-
-
Save kitlith/a26a1021c268b34bef60d57cfc6cc19f to your computer and use it in GitHub Desktop.
Memory Dump for Microcorruption
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Memory Dump for Microcorruption | |
// @namespace Kitlith | |
// @match https://*.microcorruption.com/cpu/debugger | |
// @grant none | |
// @version 1.0 | |
// @author Kitlith | |
// @require http://localhost:8000/microcorruption_wasm.js | |
// @description Adds a command (dump) to the debugger that performs a memory dump and downloads it as "mcorrupt_dump.bin" | |
// ==/UserScript== | |
var wasm; | |
// TODO: embed the final wasm file? | |
wasm_bindgen('http://localhost:8000/microcorruption_wasm_bg.wasm').then(o => console.log(wasm_bindgen.example())); | |
window.cpu._dump = (function () { | |
// File download code from: https://stackoverflow.com/a/19328891 | |
var a = document.createElement("a"); | |
a.style = "display: none"; | |
document.body.appendChild(a); | |
return function (e) { | |
// cpu.memory is a sparse js 'array', let's convert it to a full 64KiB array before downloading | |
var memory = new Uint8Array(0x10000); | |
for (key in cpu.memory) { | |
memory[key] = cpu.memory[key]; | |
} | |
var symbols = {}; | |
// for (elem of document.getElementsByClassName("insnlabel")) { | |
// let addr = parseInt(elem.innerText.slice(0, 4), 16); // first four characters are address in hex | |
// let name = elem.textContent.slice(7, -2); // skip the addr, skip ' <', and leave out '>' | |
// symbols[name] = addr; | |
// } | |
console.log(symbols); | |
// By querying whoami, we can get the current level name. woo! | |
cpu.get('/whoami', function(e) { | |
let elf = wasm_bindgen.gen_elf(e.level, memory, symbols); | |
var url = window.URL.createObjectURL(new Blob([elf], {type: "application/octet-stream"})); | |
a.href = url; | |
a.download = e.level + ".elf"; | |
a.click(); | |
window.URL.revokeObjectURL(url); | |
}); | |
}; | |
}()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mod utils; | |
use wasm_bindgen::prelude::*; | |
use faerie::{ArtifactBuilder, Data, DataType, Decl, artifact::DefinedDecl, SectionKind}; | |
use goblin::{elf, container::{Ctx, Endian, Container}}; | |
use scroll::{Pread, Pwrite}; | |
use target_lexicon::{Architecture, BinaryFormat, Environment, OperatingSystem, Triple, Vendor}; | |
use std::collections::BTreeMap; | |
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global | |
// allocator. | |
#[cfg(feature = "wee_alloc")] | |
#[global_allocator] | |
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; | |
// #[wasm_bindgen] | |
// extern { | |
// fn alert(s: &str); | |
// } | |
#[wasm_bindgen] | |
pub fn gen_elf(name: &str, memory: Box<[u8]>, symbols: &JsValue) -> Result<Box<[u8]>, JsValue> { | |
let symbols: BTreeMap<String, u64> = symbols.into_serde().map_err(|_| "Bad symbol input")?; | |
let target = Triple { | |
architecture: Architecture::Msp430, | |
vendor: Vendor::Unknown, | |
operating_system: OperatingSystem::None_, | |
environment: Environment::Unknown, | |
binary_format: BinaryFormat::Elf | |
}; | |
let mut artifact = ArtifactBuilder::new(target) | |
.name(name.to_string()) | |
.library(false) | |
.finish(); | |
let section = Decl::section(SectionKind::Text) | |
.with_datatype(DataType::Bytes) | |
.with_writable(true) | |
.with_executable(true) | |
.with_loaded(true); | |
artifact.declare("flash", Decl::Defined(DefinedDecl::Section(section))).map_err(|e| e.to_string())?; | |
artifact.define_with_symbols("flash", Data::Blob(memory.into_vec()), symbols).map_err(|e| e.to_string())?; | |
let mut bin = artifact.emit().map_err(|e| e.to_string())?; | |
// Now let's modify the output of that to create a real executable. | |
// read header | |
let ctx = Ctx::new(Container::Little, Endian::Little); | |
let mut header: elf::Header = bin.pread_with(0, ctx.le).map_err(|e: goblin::error::Error| e.to_string())?; | |
// make it an executable | |
header.e_type = elf::header::ET_EXEC; | |
header.e_entry = 0x4400; | |
header.e_flags = 0x00000112; // EXEC_P, HAS_SYMS, D_PAGED | |
// read section header | |
let sheader: elf::SectionHeader = bin.pread_with((header.e_shoff + (header.e_shentsize as u64 * 3)) as usize, ctx).map_err(|e: goblin::error::Error| e.to_string())?; | |
// build a ProgramHeader | |
let mut pheader: elf::ProgramHeader = elf::ProgramHeader::new(); | |
pheader.read(); pheader.write(); pheader.executable(); // rwx | |
pheader.p_offset = sheader.sh_offset; | |
pheader.p_vaddr = 0; | |
pheader.p_paddr = 0; | |
pheader.p_filesz = sheader.sh_size; | |
pheader.p_memsz = sheader.sh_size; | |
// locate the ProgramHeader | |
header.e_phoff = bin.len() as u64; // end of file. TODO: alignment? | |
header.e_phentsize = elf::ProgramHeader::size(ctx) as u16; | |
header.e_phnum = 1; | |
// write ProgramHeader | |
let mut phbin = vec![0; header.e_phentsize as usize]; | |
phbin.pwrite_with(pheader, 0, ctx).map_err(|e| e.to_string())?; | |
bin.extend(phbin); | |
// write the updated header | |
bin.pwrite_with(header, 0, ctx.le).map_err(|e| e.to_string())?; | |
Ok(bin.into_boxed_slice()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment