#![cfg(test)]
const EHDR: usize = 64;
const PHDR: usize = 56;
const SHDR: usize = 64;
const P_DYNSTR: u64 = 0x00e8;
const P_DYNSYM: u64 = 0x00f0;
const P_RELA: u64 = 0x0120;
const P_DYNAMIC: u64 = 0x0138;
const P_PLT: u64 = 0x01c0;
const P_TEXT: u64 = 0x01d0;
const P_GOT: u64 = 0x01e0;
const P_SHSTR: u64 = 0x01e8;
const P_SHDRS: u64 = 0x0208;
const FILE_END: u64 = P_SHDRS + 5 * SHDR as u64;
const DYNSTR: &[u8] = b"\0strcpy\0";
const SHSTR: &[u8] = b"\0.plt\0.text\0.got.plt\0.shstrtab\0";
pub fn elf_with_plt_call() -> Vec<u8> {
let mut f = vec![0u8; FILE_END as usize];
f[0..4].copy_from_slice(b"\x7fELF");
f[4] = 2; f[5] = 1; f[6] = 1; put16(&mut f, 16, 2); put16(&mut f, 18, 62); put32(&mut f, 20, 1); put64(&mut f, 24, P_TEXT); put64(&mut f, 32, EHDR as u64); put64(&mut f, 40, P_SHDRS); put16(&mut f, 52, EHDR as u16); put16(&mut f, 54, PHDR as u16); put16(&mut f, 56, 3); put16(&mut f, 58, SHDR as u16); put16(&mut f, 60, 5); put16(&mut f, 62, 4);
let ph = EHDR;
phdr(&mut f, ph, 1, 7, 0, 0, FILE_END, 0x1000); phdr(&mut f, ph + PHDR, 2, 6, P_DYNAMIC, P_DYNAMIC, 128, 8); phdr(&mut f, ph + 2 * PHDR, 0x6474_e551, 6, 0, 0, 0, 16);
let o = P_DYNSTR as usize;
f[o..o + DYNSTR.len()].copy_from_slice(DYNSTR);
let s = P_DYNSYM as usize + 24;
put32(&mut f, s, 1); f[s + 4] = 0x12; put16(&mut f, s + 6, 0);
let r = P_RELA as usize;
put64(&mut f, r, P_GOT); put64(&mut f, r + 8, (1u64 << 32) | 7);
let dyn_entries: [(u64, u64); 8] = [
(5, P_DYNSTR), (10, 8), (6, P_DYNSYM), (11, 24), (23, P_RELA), (2, 24), (20, 7), (0, 0), ];
for (i, (tag, val)) in dyn_entries.iter().enumerate() {
let d = P_DYNAMIC as usize + i * 16;
put64(&mut f, d, *tag);
put64(&mut f, d + 8, *val);
}
let p = P_PLT as usize;
f[p] = 0xff;
f[p + 1] = 0x25;
let disp = (P_GOT as i64 - (P_PLT as i64 + 6)) as i32;
f[p + 2..p + 6].copy_from_slice(&disp.to_le_bytes());
let t = P_TEXT as usize;
f[t] = 0xe8;
let rel = (P_PLT as i64 - (P_TEXT as i64 + 5)) as i32;
f[t + 1..t + 5].copy_from_slice(&rel.to_le_bytes());
f[t + 5] = 0xc3;
let sh = P_SHSTR as usize;
f[sh..sh + SHSTR.len()].copy_from_slice(SHSTR);
const PROGBITS: u32 = 1;
const STRTAB: u32 = 3;
const ALLOC_EXEC: u64 = 0x2 | 0x4;
const ALLOC_WRITE: u64 = 0x2 | 0x1;
let sd = P_SHDRS as usize;
shdr(&mut f, sd + SHDR, 1, PROGBITS, ALLOC_EXEC, P_PLT, 16); shdr(&mut f, sd + 2 * SHDR, 6, PROGBITS, ALLOC_EXEC, P_TEXT, 16); shdr(&mut f, sd + 3 * SHDR, 12, PROGBITS, ALLOC_WRITE, P_GOT, 8); shdr(&mut f, sd + 4 * SHDR, 21, STRTAB, 0, 0, SHSTR.len() as u64); put64(&mut f, sd + 4 * SHDR + 24, P_SHSTR);
f
}
fn put16(f: &mut [u8], at: usize, v: u16) {
f[at..at + 2].copy_from_slice(&v.to_le_bytes());
}
fn put32(f: &mut [u8], at: usize, v: u32) {
f[at..at + 4].copy_from_slice(&v.to_le_bytes());
}
fn put64(f: &mut [u8], at: usize, v: u64) {
f[at..at + 8].copy_from_slice(&v.to_le_bytes());
}
#[allow(clippy::too_many_arguments)]
fn phdr(f: &mut [u8], at: usize, ty: u32, flags: u32, off: u64, va: u64, sz: u64, align: u64) {
put32(f, at, ty);
put32(f, at + 4, flags);
put64(f, at + 8, off);
put64(f, at + 16, va);
put64(f, at + 24, va); put64(f, at + 32, sz); put64(f, at + 40, sz); put64(f, at + 48, align);
}
fn shdr(f: &mut [u8], at: usize, name: u32, ty: u32, flags: u64, addr: u64, size: u64) {
put32(f, at, name);
put32(f, at + 4, ty);
put64(f, at + 8, flags);
put64(f, at + 16, addr);
put64(f, at + 24, addr); put64(f, at + 32, size);
put64(f, at + 48, 1); }
#[cfg(test)]
mod tests {
use super::*;
use crate::model::{Format, SymKind};
#[test]
fn the_fixture_parses_as_an_elf() {
let bytes = elf_with_plt_call();
let bin = crate::formats::analyze("fixture.elf", &bytes).expect("parses");
assert_eq!(bin.format, Format::Elf);
assert_eq!(bin.bits, 64);
assert_eq!(bin.entry, P_TEXT);
assert!(bin.sections.iter().any(|s| s.name == ".plt" && s.exec));
}
#[test]
fn the_relocation_names_the_got_slot() {
let bytes = elf_with_plt_call();
let bin = crate::formats::analyze("fixture.elf", &bytes).unwrap();
let slot = bin
.symbols
.iter()
.find(|s| s.kind == SymKind::Import)
.expect("an import symbol from .rela.plt");
assert_eq!(slot.addr, P_GOT);
assert_eq!(slot.name, "strcpy");
}
}