balrog.git


balrog

~ ELF file analysis tool to be used after firmware extraction
git clone https://github.com/djnnvx/balrog.git
log | files | refs | archive | README

mips.rs (2616B)

      1 use super::{imm, mem, reg, Kind, Op, HIGH_HALF_SHIFT, IMM16_MASK};
      2 use crate::load::{dyn_val, sym_name};
      3 use capstone::arch::mips::MipsReg;
      4 use goblin::elf::Elf;
      5 use std::collections::HashMap;
      6 
      7 const DT_PLTGOT: u64 = 3;
      8 const DT_MIPS_LOCAL_GOTNO: u64 = 0x7000_000a;
      9 const DT_MIPS_SYMTABNO: u64 = 0x7000_0011;
     10 const DT_MIPS_GOTSYM: u64 = 0x7000_0013;
     11 const GP_BIAS: u64 = 0x7ff0;
     12 
     13 pub const ARG_REGS: [u16; 4] = [
     14     MipsReg::MIPS_REG_A0 as u16,
     15     MipsReg::MIPS_REG_A1 as u16,
     16     MipsReg::MIPS_REG_A2 as u16,
     17     MipsReg::MIPS_REG_A3 as u16,
     18 ];
     19 
     20 pub const SP: u16 = MipsReg::MIPS_REG_SP as u16;
     21 pub const GP: u16 = MipsReg::MIPS_REG_GP as u16;
     22 
     23 pub fn decode(mnemonic: &str, o: &[Op; 3]) -> Option<Kind> {
     24     match mnemonic {
     25         "jal" | "bal" | "jals" => Some(Kind::Call(imm(o, 0)? as u64)),
     26         "jalr" => Some(Kind::CallInd { reg: reg(o, 0)? }),
     27         "jr" => (reg(o, 0)? == MipsReg::MIPS_REG_RA as u16).then_some(Kind::Ret),
     28         "lui" => {
     29             let high_half = ((imm(o, 1)? as u64) & IMM16_MASK) << HIGH_HALF_SHIFT;
     30             Some(Kind::SetConst {
     31                 dst: reg(o, 0)?,
     32                 val: high_half,
     33             })
     34         }
     35         "lw" => {
     36             let (base, disp) = mem(o, 1)?;
     37             Some(Kind::Load {
     38                 dst: reg(o, 0)?,
     39                 base,
     40                 disp,
     41             })
     42         }
     43         "addiu" | "addi" | "ori" => Some(Kind::AddImm {
     44             dst: reg(o, 0)?,
     45             base: reg(o, 1)?,
     46             imm: imm(o, 2)?,
     47         }),
     48         "move" => Some(Kind::Mov {
     49             dst: reg(o, 0)?,
     50             src: reg(o, 1)?,
     51         }),
     52         _ => None,
     53     }
     54 }
     55 
     56 pub fn resolve_got(elf: &Elf, got2sym: &mut HashMap<u64, String>) -> Option<u64> {
     57     let got = dyn_val(elf, DT_PLTGOT)?;
     58     let gp = got.wrapping_add(GP_BIAS);
     59 
     60     let (Some(local_gotno), Some(gotsym), Some(symtabno)) = (
     61         dyn_val(elf, DT_MIPS_LOCAL_GOTNO),
     62         dyn_val(elf, DT_MIPS_GOTSYM),
     63         dyn_val(elf, DT_MIPS_SYMTABNO),
     64     ) else {
     65         return Some(gp);
     66     };
     67     let entry_size = if elf.is_64 { 8 } else { 4 };
     68     let last_dynsym = symtabno.min(elf.dynsyms.len() as u64);
     69     for sym_index in gotsym..last_dynsym {
     70         let got_entry = local_gotno
     71             .wrapping_add(sym_index - gotsym)
     72             .wrapping_mul(entry_size);
     73         let slot = got.wrapping_add(got_entry);
     74         let Some(sym) = elf.dynsyms.get(sym_index as usize) else {
     75             continue;
     76         };
     77         if let Some(name) = sym_name(&elf.dynstrtab, sym.st_name) {
     78             got2sym.entry(slot).or_insert(name);
     79         }
     80     }
     81     Some(gp)
     82 }