Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 31 additions & 80 deletions firmware_config.json
Original file line number Diff line number Diff line change
@@ -1,113 +1,64 @@
{
"fuzz": true,
"fuzz": false,
"fuzz_target_address": "0xc04f1b88",
"fuzz_target_return_address": "0xc04f2094",
"qemu_args": [
"",
"-monitor",
"unix:qemu-monitor-socket,server,nowait",
"-kernel",
"./qdsp6sw.mbn",
"../modems/srlabs_qdsp6sw.mbn",
"-serial",
"null",
"-nographic",
"-snapshot",
"-S",
"-s"
"-d",
"in_asm",
"-D",
"log_sr_labs.txt"
],
"sections": [
{
"name" : "clade1",
"section_type" : "clade",
"file" : "../patching/sr_labs_dec",
"format" : "raw",
"address" : "0xd8000000"
}
],
"broker_port": "61337",
"timeout_seconds": "1",
"cores": "3",
"breakpoints": [
{
"name": "qurt_println",
"address": "0xfe10f2b0",
"handler": "HandlePrintln"
},
{
"name": "another_println",
"address": "0xc03c96cc",
"handler": "HandlePrintln"
},
{
"name": "other_println",
"address": "0xc08460e4",
"handler": "HandlePrintln"
},
{
"name": "diag_println",
"address": "0xbfe8a1f4",
"handler": "HandlePrintln"
"name": "clade_loading",
"address": "0xfe10a3ec",
"handler": "HandleCladeLoading"
},
{
"name": "kernel_started",
"address": "0xfe10c028",
"name": "loop_1",
"address": "0xd8199fcc",
"handler": "HandleNextPc"
},
{
"name": "kernel_init",
"address": "0xfe10c0a8",
"name": "loop_2_1",
"address": "0xd8199fd0",
"handler": "HandleNextPc"
},
{
"name": "first_clade",
"address": "0xfe10a3ec",
"handler": "HandleJumpOver"
},
{
"name": "second_clade",
"address": "0xfe10a744",
"handler": "HandleSecondClade"
},
{
"name": "zeroeing",
"address": "0xc083b9f0",
"handler": "HandleJumpOver"
},
{
"name": "app_init_done",
"address": "0xc0100064",
"handler": "HandlerEmpty"
},
{
"name": "zeroing_yetanother",
"address": "0xfe1012b4",
"handler": "HandleZeroingYetAnother"
},
{
"name": "fatal_error",
"address": "0xfe10ad10",
"handler": "HandleFatalError"
},
{
"name": "read_loop_hardware",
"address": "0xfe115db0",
"handler": "HandleJumpOver"
},
{
"name": "calling_fatal_error",
"address": "0xfe1021b4",
"handler": "HandleFatalError"
},
{
"name": "time_ipc_task_started",
"address": "0xc04f1b96",
"handler": "HandlerEmpty"
},
{
"name": "time_ipc_task_initialized",
"address": "0xc04f1bf4",
"handler": "HandlerEmpty"
"name": "loop_2_2",
"address": "0xd8199fd4",
"handler": "HandleNextPc"
},
{
"name": "time_ipc_connecting_to_service",
"address": "0xc04f1c64",
"handler": "HandlerEmpty"
"name": "loop_2_3",
"address": "0xd8199fd8",
"handler": "HandleNextPc"
},
{
"name": "time_ipc_qmi_client_initialized",
"address": "0xc04f1c70",
"handler": "HandlerEmpty"
"name": "skip_bad_calls",
"address" : "0xc0102044",
"handler": "HandleSkipCall"
}
]
}
130 changes: 128 additions & 2 deletions src/breakpoints.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
use crate::config::Config;
use crate::config::Section;
use crate::config::SectionFormat;
use crate::config::SectionType;
use crate::utils::decode_hex;
use libafl_qemu::ArchExtras;
use libafl_qemu::CallingConvention;
use libafl_qemu::Emulator;
use libafl_qemu::Regs;
use log::{debug, error, info};
use serde::Deserialize;
use std::fs;
use std::path::Path;
use std::process;

#[derive(Debug, Clone, Deserialize)]
Expand All @@ -16,11 +22,14 @@ pub enum HandlerFunction {
HandleFatalError,
HandleZeroingYetAnother,
HandlerEmpty, // Add other handlers here
HandleNextTwo,
HandleCladeLoading,
HandleSkipCall,
}

// Implement a method to call the actual handler function
impl HandlerFunction {
pub fn call(&self, emu: &Emulator) {
pub fn call(&self, emu: &Emulator, sections: Vec<Section>) {
debug!("Executing handler function: {:?}", self);
match self {
HandlerFunction::HandlePrintln => handle_println(emu),
Expand All @@ -30,6 +39,9 @@ impl HandlerFunction {
HandlerFunction::HandleFatalError => handle_fatal_error(emu),
HandlerFunction::HandleZeroingYetAnother => handle_zeroing_yet_another(emu),
HandlerFunction::HandlerEmpty => handler_empty(emu),
HandlerFunction::HandleNextTwo => handle_next_two(emu),
HandlerFunction::HandleCladeLoading => handle_clade_loading(emu, sections),
HandlerFunction::HandleSkipCall => handle_skip_call(emu),
// Add cases for other handlers
}
}
Expand Down Expand Up @@ -99,7 +111,7 @@ pub fn handle_breakpoint(emu: &Emulator, config: Config) -> Result<String, Strin
if pc.clone().unwrap() == bp.address {
debug!("Breakpoint reached: {} at 0x{:x}", bp.name, bp.address);
debug!("Calling handler: {:?}", bp.handler);
bp.handler.call(emu);
bp.handler.call(emu, config.sections);
return Ok(bp.name.clone());
}
}
Expand Down Expand Up @@ -138,8 +150,10 @@ fn handler_empty(emu: &Emulator) {
fn handle_println(emu: &Emulator) {
debug!("Handle printf: introspecting printf call");
let format_ptr = emu.current_cpu().unwrap().read_reg(Regs::R0).unwrap();
let return_address: u32 = emu.current_cpu().unwrap().read_return_address().unwrap();
let format_string = read_cstring_from_ptr(emu, format_ptr);

debug!("println ret address: 0x{:x}", return_address);
let a: u32 = emu
.read_function_argument(CallingConvention::Cdecl, 0)
.unwrap();
Expand Down Expand Up @@ -219,6 +233,19 @@ fn handle_jump_over(emu: &Emulator) {
debug!("jumping over to: {return_address:#x}");
}

fn handle_next_two(emu: &Emulator) {
let current_pc: u32 = emu.current_cpu().unwrap().read_reg(Regs::Pc).unwrap();
debug!(
"next to over handler: current PC 0x{:x} -> jumping to 0x{:x}",
current_pc,
current_pc + 8
);
emu.current_cpu()
.unwrap()
.write_reg(Regs::Pc, current_pc + 8)
.unwrap();
}

fn handle_second_clade(emu: &Emulator) {
let current_pc: u32 = emu.current_cpu().unwrap().read_reg(Regs::Pc).unwrap();
let old_r3: u32 = emu.current_cpu().unwrap().read_reg(Regs::R3).unwrap();
Expand Down Expand Up @@ -265,6 +292,105 @@ fn handle_zeroing_yet_another(emu: &Emulator) {
.write_reg(Regs::Pc, 0xfe1012c0u32)
.unwrap();
}

fn handle_clade_loading(emu: &Emulator, sections: Vec<Section>) {
for section in sections {
info!("Loading section {:?}", section.name);
// only load clade sections
if section.section_type == SectionType::Clade {
let file_path = Path::new(&section.file);

let raw_bytes: Vec<u8> = fs::read(file_path).expect(&format!(
"FATAL: Failed to load section '{}', unable to read file",
section.name
));

let data: Vec<u8>;
// if format is hex covert to raw bytes
match section.format {
SectionFormat::Hex => {
let hex_string = std::str::from_utf8(&raw_bytes)
.expect(&format!("FATAL: Failed to load section '{}', file contains non-UTF-8 characters for hex decoding", section.name))
.trim();

data = decode_hex(hex_string).expect(&format!(
"FATAL: Failed to load section '{}', unable to convert from hex",
section.name
));
}
SectionFormat::Raw => data = raw_bytes,
}
debug!("Bytes: {:?}", &data[..10]);

unsafe {
emu.write_mem(section.address, &data);
}
info!("Section {:?} loaded at {:?}", section.name, section.address)
}
}
let current_pc: u32 = emu.current_cpu().unwrap().read_reg(Regs::Pc).unwrap();
let return_address: u32 = emu.current_cpu().unwrap().read_return_address().unwrap();
debug!(
"Jump over handler: current PC 0x{:x} -> jumping to 0x{:x}",
current_pc, return_address
);
emu.current_cpu()
.unwrap()
.write_reg(Regs::Pc, return_address)
.unwrap();
debug!("jumping over to: {return_address:#x}");
}

fn handle_skip_call(emu: &Emulator) {
let call_pointer: u32 = emu.current_cpu().unwrap().read_reg(Regs::R26).unwrap();
debug!("call pointer {:x}", call_pointer);
let mut call_address: [u8; 4] = [0; 4];
unsafe { emu.read_mem(call_pointer, &mut call_address) }
let call_address_int: u32 = u32::from_le_bytes(call_address);
debug!("call address {:x}", call_address_int);
if (call_address_int >= 0xdc000000 && call_address_int <= 0xdd000000)
|| call_address_int == 0xd8ce2518
{
let mut distance = 4;
let mut new_call_address_int: u32;
loop {
unsafe { emu.read_mem(call_pointer + distance, &mut call_address) }
new_call_address_int = u32::from_le_bytes(call_address);

if !((new_call_address_int >= 0xdc000000 && new_call_address_int <= 0xdd000000)
|| new_call_address_int == 0xd8ce2518)
{
break;
}

distance += 4;
}
emu.current_cpu()
.unwrap()
.write_reg(Regs::R0, new_call_address_int)
.unwrap();
emu.current_cpu()
.unwrap()
.write_reg(Regs::R26, call_pointer + distance)
.unwrap();
debug!(
"changing bad call {:x} -> {:x}, dist: {:?}",
call_address_int, new_call_address_int, distance
);
} else {
emu.current_cpu()
.unwrap()
.write_reg(Regs::R0, call_address_int)
.unwrap();
debug!("allowed good call {:x}", call_address_int);
}
let current_pc: u32 = emu.current_cpu().unwrap().read_reg(Regs::Pc).unwrap();
emu.current_cpu()
.unwrap()
.write_reg(Regs::Pc, current_pc + 4)
.unwrap();
}

/*
fn handle_skipping_hardware_init(emu: &Emulator) {
unsafe {
Expand Down
Loading