Skip to content

Instantly share code, notes, and snippets.

@djanatyn
Created December 28, 2023 08:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save djanatyn/684ebeb618cb58aa96d3ab7487a6cfd5 to your computer and use it in GitHub Desktop.
Save djanatyn/684ebeb618cb58aa96d3ab7487a6cfd5 to your computer and use it in GitHub Desktop.
disassembling melee with radare2 from rust
use r2pipe::{R2Pipe, R2PipeSpawnOptions};
/// Filename of GALE01 v1.02 GCM disk image.
const SSBM_ISO: &str = "ssbm.iso";
/// Filename of converted main.dol -> main.elf, converted with doltool.
const MAIN_DOL: &str = "main.elf";
/// Offset of get_rand_int in main.elf and in memory.
///
/// Taken from SSBM datasheet.
const MEMORY_GET_RAND_INT_OFFSET: u64 = 0x80380580;
/// Taken from melee community symbol map.
const MEMORY_PEACH_DOWNB_GEN_TURNIP: u64 = 0x8011d018;
struct MeleeAnalyzer {
r2p: R2Pipe,
}
impl MeleeAnalyzer {
fn new<S: AsRef<str>>(filename: S) -> Result<Self, String> {
let mut r2p = R2Pipe::spawn(
MAIN_DOL,
Some(R2PipeSpawnOptions {
exepath: "r2".to_string(),
args: vec!["-a", "ppc"],
}),
)
.expect("failed to spawn r2");
eprintln!("spawned r2, running analysis...");
r2p.cmd("aaa").or(Err("failed analysis"))?;
Ok(MeleeAnalyzer { r2p })
}
fn disasm_function(&mut self, offset: u64) -> Result<String, String> {
self.r2p
.cmd(format!("s {}", offset).as_str())
.or(Err("failed to seek to subroutine"))?;
let disasm = self
.r2p
.cmd("pdf")
.or(Err("failed to disassemble subroutine"))?;
Ok(disasm)
}
fn disasm_instructions(&mut self, offset: u64, instructions: u64) -> Result<String, String> {
self.r2p
.cmd(format!("s {}", offset).as_str())
.or(Err("failed to seek to subroutine"))?;
let disasm = self
.r2p
.cmd(format!("pd {}", instructions).as_str())
.or(Err("failed to disassemble subroutine"))?;
Ok(disasm)
}
}
fn main() -> Result<(), String> {
let mut analyzer = MeleeAnalyzer::new(MAIN_DOL)?;
{
let disasm = analyzer.disasm_function(MEMORY_GET_RAND_INT_OFFSET)?;
println!("get_rand_int:\n{disasm}");
}
{
let disasm = analyzer.disasm_instructions(0x8011d088, 3)?;
println!("peach_turnip_rng:\n{disasm}");
}
Ok(())
}
get_rand_int:
; XREFS(736)
┌ 60: fcn.80380580 ();
│ 0x80380580 80ada8f4 lwz r5, -0x570c(r13)
│ 0x80380584 3c800003 lis r4, 3
│ 0x80380588 380443fd addi r0, r4, 0x43fd
│ 0x8038058c 80850000 lwz r4, 0(r5)
│ 0x80380590 7c8401d6 mullw r4, r4, r0
│ 0x80380594 3c840027 addis r4, r4, 0x27
│ 0x80380598 38049ec3 addi r0, r4, 0x9ec3
│ 0x8038059c 90050000 stw r0, 0(r5)
│ 0x803805a0 808da8f4 lwz r4, -0x570c(r13)
│ 0x803805a4 80040000 lwz r0, 0(r4)
│ 0x803805a8 5400843e srwi r0, r0, 0x10
│ 0x803805ac 7c0301d6 mullw r0, r3, r0
│ 0x803805b0 7c038670 srawi r3, r0, 0x10
│ 0x803805b4 7c630194 addze r3, r3
└ 0x803805b8 4e800020 blr
peach_turnip_rng:
0x8011d088 482634f9 bl fcn.80380580
0x8011d08c 2c030000 cmpwi r3, 0
┌─< 0x8011d090 40820010 bne 0x8011d0a0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment