diff --git a/.gitignore b/.gitignore index 63cdff3..1320f90 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1 @@ -hekate.bin.js -lockpick.bin.js -tegraexplorer.bin.js -index.html +site diff --git a/Makefile b/Makefile deleted file mode 100644 index aacc37f..0000000 --- a/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -generate_files: - @python gen_contents.py - -clean: - @rm hekate.bin.js - @rm lockpick.bin.js - @rm tegraexplorer.bin.js - @rm index.html - -.PHONY: help - -help: - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' - -.DEFAULT_GOAL := help diff --git a/README.md b/README.md index b934aed..be362d7 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,3 @@ Fusee Launcher, in a browser! # Description This is a fork of [web-fusee-launcher](https://github.com/atlas44/web-fusee-launcher), which is a port of [fusee-launcher](https://github.com/reswitched/fusee-launcher) to JavaScript using WebUSB. This has been mildly tested and appears to work on Linux, Android (unrooted), OSX and ChromeOS. Today, this only works on Chrome because only Chrome implements WebUSB. It also does NOT work on Windows because the WebUSB Windows implementation does not allow sending the required USB packet. - -# fork changes - -* Hekate latest. -* You need to gen that automatically. diff --git a/gen_contents.py b/gen_contents.py index 3e0a009..b45b50c 100644 --- a/gen_contents.py +++ b/gen_contents.py @@ -1,6 +1,7 @@ import requests import io import shutil +import os import zipfile bin_files = { @@ -98,7 +99,7 @@ def serialize_to_js(short_name: str, payload: io.BytesIO, filename: str): final_str = "".join(final_str) out_string = DEFAULT_SERIALIZED_CONTENTS.format(short_name, final_str) - with open(filename, "w") as outfile: + with open(f"site/{filename}", "w") as outfile: outfile.write(out_string) def generate_js(program: str): @@ -130,14 +131,17 @@ def generate_html(): out_string = "".join(html_data_list) - with open("index.html", "w") as indexfile: + with open("site/index.html", "w") as indexfile: indexfile.write(out_string) def main(): + os.makedirs("site", exist_ok=True) generate_js("hekate") generate_js("tegraexplorer") generate_js("lockpick") generate_html() + shutil.copy("js/main.js", "site/main.js") + shutil.copy("js/fusee.bin.js", "site/fusee.bin.js") if __name__ == "__main__": main() diff --git a/fusee.bin.js b/js/fusee.bin.js similarity index 100% rename from fusee.bin.js rename to js/fusee.bin.js diff --git a/main.js b/js/main.js similarity index 96% rename from main.js rename to js/main.js index 213f150..7d31880 100644 --- a/main.js +++ b/js/main.js @@ -1,139 +1,139 @@ -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); - }); -} - -function logOutput(...message) { - document.getElementById("output").value += message.join(" ") + "\n"; -} - -let device; - -async function launchPayload(payload) { - await device.open(); - logOutput(`Connected to ${device.manufacturerName} ${device.productName}`); - - 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 () => { - logOutput("Requesting access to device..."); - device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x0955 }] }); - - const payloadType = document.forms.mainForm.payload.value; - logOutput(`Preparing to launch ${payloadType}...`); - - let payload; - if (payloadType === "fusee.bin") { - payload = fusee; - } else if (payloadType === "hekate.bin") { - payload = hekate; - } else if (payloadType === "tegraexplorer.bin") { - payload = tegraexplorer; - } else if (payloadType === "lockpick.bin") { - payload = lockpick; - } else if (payloadType === "uploaded") { - const file = document.getElementById("payloadUpload").files[0]; - if (!file) { - alert("You need to upload a file, to use an uploaded file."); - return; - } - payload = new Uint8Array(await readFileAsArrayBuffer(file)); - } else { - console.log("how?"); - return; - } - - launchPayload(payload); -}); - -document.getElementById("payloadUpload").addEventListener("change", () => document.forms.mainForm.payload.value = "uploaded"); +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); + }); +} + +function logOutput(...message) { + document.getElementById("output").value += message.join(" ") + "\n"; +} + +let device; + +async function launchPayload(payload) { + await device.open(); + logOutput(`Connected to ${device.manufacturerName} ${device.productName}`); + + 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 () => { + logOutput("Requesting access to device..."); + device = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x0955 }] }); + + const payloadType = document.forms.mainForm.payload.value; + logOutput(`Preparing to launch ${payloadType}...`); + + let payload; + if (payloadType === "fusee.bin") { + payload = fusee; + } else if (payloadType === "hekate.bin") { + payload = hekate; + } else if (payloadType === "tegraexplorer.bin") { + payload = tegraexplorer; + } else if (payloadType === "lockpick.bin") { + payload = lockpick; + } else if (payloadType === "uploaded") { + const file = document.getElementById("payloadUpload").files[0]; + if (!file) { + alert("You need to upload a file, to use an uploaded file."); + return; + } + payload = new Uint8Array(await readFileAsArrayBuffer(file)); + } else { + console.log("how?"); + return; + } + + launchPayload(payload); +}); + +document.getElementById("payloadUpload").addEventListener("change", () => document.forms.mainForm.payload.value = "uploaded");