extern crate colored;
extern crate elfkit;
use std::env;
use std::fs::File;
use elfkit::{types, DynamicContent, Elf, SectionContent};
use elfkit::relocation::RelocationType;
use elfkit::symbol::SymbolSectionIndex;
use colored::*;
fn hextab<S>(align: usize, s: S) -> String
where
S: std::fmt::LowerHex,
{
let s = format!("{:.align$x}", s, align = align);
let pad: String = vec!['0'; align - s.len()].into_iter().collect();
format!("\x1b[90m{}\x1b[0;m{}", pad, s)
}
fn main() {
let filename = env::args().nth(1).unwrap();
let mut file = File::open(filename).unwrap();
let mut elf = Elf::from_reader(&mut file).unwrap();
elf.load_all(&mut file).unwrap();
println!("{}", "ELF Header:".bold());
println!(
" Magic: {:?}",
elf.header.ident_magic
);
println!(
" Class: {:?}",
elf.header.ident_class
);
println!(
" Data: {:?}",
elf.header.ident_endianness
);
println!(
" Version: {}",
elf.header.ident_version
);
println!(
" OS/ABI: {:?}",
elf.header.ident_abi
);
println!(
" ABI Version: {:?}",
elf.header.ident_abiversion
);
println!(
" Type: {:?}",
elf.header.etype
);
println!(
" Machine: {:?}",
elf.header.machine
);
println!(
" Version: {:?}",
elf.header.version
);
println!(
" Entry point address: 0x{:x}",
elf.header.entry
);
println!(
" Start of program headers: {} (bytes into file)",
elf.header.phoff
);
println!(
" Start of section headers: {} (bytes into file)",
elf.header.shoff
);
println!(
" Flags: 0x{:x} {:?}",
elf.header.flags,
elf.header.flags
);
println!(
" Size of this header: {} (bytes)",
elf.header.ehsize
);
println!(
" Size of program headers: {} (bytes)",
elf.header.phentsize
);
println!(" Number of program headers: {}", elf.header.phnum);
println!(
" Size of section headers: {} (bytes)",
elf.header.shentsize
);
println!(" Number of section headers: {}", elf.header.shnum);
println!(
" Section header string table index: {}",
elf.header.shstrndx
);
println!("");
println!(
"{} at offset 0x{:x}:",
"Section Headers".bold(),
elf.header.shoff
);
println!(
" [Nr] Name Type Address Offset Size EntS \
Flg Lnk Inf Al"
);
for (i, section) in elf.sections.iter().enumerate() {
println!(
" [{:>2}] {:<16.16} {} {} {} {} {} {:<3} {:<3.3} {:<3} {:<2.2}",
i,
String::from_utf8_lossy(§ion.name).bold(),
match section.header.shtype.typename(&elf.header) {
Some(s) => format!("{:<14.14}", s),
None => hextab(14, section.header.shtype.to_u32()),
},
hextab(16, section.header.addr),
hextab(8, section.header.offset),
hextab(8, section.header.size),
hextab(4, section.header.entsize),
section.header.flags,
section.header.link,
section.header.info,
section.header.addralign
);
}
println!("",);
println!("{}", "Legend for Flags:".bold());
println!(
" {}: write, {}: alloc, {}: execute, {}: merge, {}: strings, {}: info,
{}: link order, {}: extra OS processing required, {}: group, {}: TLS,
{}: compressed, {}: OS specific, {}: exclude, {}: large,
{}: mips: global data area",
"W".bold(),
"A".bold(),
"X".bold(),
"M".bold(),
"S".bold(),
"I".bold(),
"L".bold(),
"O".bold(),
"G".bold(),
"T".bold(),
"C".bold(),
"o".bold(),
"E".bold(),
"l".bold(),
"g".bold()
);
if elf.segments.len() > 0 {
println!("");
println!(
"{} at offset 0x{:x}:",
"Program Headers (Segments)".bold(),
elf.header.phoff
);
println!(" Type Offset VirtAddr PhysAddr");
println!(" FileSiz MemSiz Flags Align");
for ph in &elf.segments {
println!(
" {:<14.14} 0x{} 0x{} 0x{}",
format!("{:?}", ph.phtype),
hextab(16, ph.offset),
hextab(16, ph.vaddr),
hextab(16, ph.paddr)
);
println!(
" 0x{} 0x{} {:<6} 0x{:x}",
hextab(16, ph.filesz),
hextab(16, ph.memsz),
ph.flags,
ph.align
);
}
}
println!("");
println!("{}:", "Segment Layout".bold());
let mut fls = vec![
];
if elf.header.phoff > 0 {
fls.push((
String::from("segment headers"),
elf.header.phoff,
(elf.header.phentsize * elf.header.phnum) as u64,
));
}
for section in elf.sections.iter() {
if section.header.size < 1 {
continue;
}
fls.push((
String::from_utf8_lossy(§ion.name).into_owned(),
section.header.addr,
section.header.size,
));
}
fls.sort_by(|&(_, a, _), &(_, b, _)| a.cmp(&b));
println!(
"{}",
" addr size segment".bold()
);
if elf.segments.len() > 0 {
for n in 0..12 {
let n = n;
print!(" ");
for segment in elf.segments.iter() {
let name = format!("{:?}", segment.phtype);
print!(" {} |", if name.len() > n { &name[n..n + 1] } else { " " });
}
println!("");
}
print!(" ");
for _ in elf.segments.iter() {
print!("---|")
}
println!("");
}
let mut cfileoff = 0;
let fls_intermediate = fls.drain(..).collect::<Vec<(String, u64, u64)>>();
for (name, off, size) in fls_intermediate {
if cfileoff < off {
fls.push((String::default(), cfileoff, off - cfileoff));
}
fls.push((name, off, size));
cfileoff = off + size;
}
if let Some(&(_, off, size)) = fls.last() {
let filelen = file.metadata().unwrap().len();
if off + size < filelen {
fls.push((String::default(), off + size, filelen - (off + size)));
}
}
for (name, off, size) in fls {
print!(
" {} 0x{:<6.6x} 0x{:<6.6x} ",
format!("{:<16.16}", name).bold(),
off,
size
);
for segment in elf.segments.iter() {
if off >= segment.vaddr && (off + size) <= (segment.vaddr + segment.memsz) {
if segment.flags.contains(types::SegmentFlags::WRITABLE) {
print!("{:^3}|", format!("{}", segment.flags).red())
} else if segment.flags.contains(types::SegmentFlags::EXECUTABLE) {
print!("{:^3}|", format!("{}", segment.flags).green())
} else {
print!("{:^3}|", format!("{}", segment.flags));
}
} else {
print!(" |");
}
}
println!("");
}
for section in &elf.sections {
match section.content {
SectionContent::Relocations(ref relocs) => {
println!("");
println!(
"{} relocation section at offset 0x{:x}:",
String::from_utf8_lossy(§ion.name).bold(),
section.header.offset
);
println!(" Offset Type Symbol Addend");
for reloc in relocs {
print!(
" {} {:<15.15} ",
hextab(16, reloc.addr),
&format!("{:?}", reloc.rtype)[2..]
);
elf.sections
.get(section.header.link as usize)
.and_then(|sec| sec.content.as_symbols())
.and_then(|symbols| symbols.get(reloc.sym as usize))
.and_then(|symbol| if symbol.name.len() > 0 {
print!("{: <20.20} ", String::from_utf8_lossy(&symbol.name));
Some(())
} else {
None
})
.unwrap_or_else(|| {
print!("{: <20.20} ", reloc.sym);
});
match reloc.rtype {
RelocationType::R_X86_64_RELATIVE => {
println!("0x{:<16.16x}", reloc.addend);
}
_ => {
println!("{: <18.18}", reloc.addend);
}
}
}
}
SectionContent::Symbols(ref symbols) => {
println!("");
println!(
"{} symbols section at offset 0x{:x}:",
String::from_utf8_lossy(§ion.name).bold(),
section.header.offset
);
println!(" Num: Value Size Type Bind Vis Ndx Name");
for (i, symbol) in symbols.iter().enumerate() {
println!(
" {:>3}: {} {:>5.5} {:<7.7} {:<6.6} {:<8.8} {:<3.3} {} ",
i,
hextab(16, symbol.value),
symbol.size,
format!("{:?}", symbol.stype),
format!("{:?}", symbol.bind),
format!("{:?}", symbol.vis),
match symbol.shndx {
SymbolSectionIndex::Undefined => String::from("UND"),
SymbolSectionIndex::Absolute => String::from("ABS"),
SymbolSectionIndex::Common => String::from("COM"),
SymbolSectionIndex::Section(i) => format!("{}", i),
},
String::from_utf8_lossy(&symbol.name)
);
}
}
SectionContent::Dynamic(ref dynamics) => {
println!("");
println!(
"{} dynamic linker section at offset 0x{:x}:",
String::from_utf8_lossy(§ion.name).bold(),
section.header.offset
);
println!(" Tag Value");
for dyn in dynamics {
println!(
" {:<12} {}",
format!("{:?}", dyn.dhtype),
match dyn.content {
DynamicContent::None => String::default(),
DynamicContent::String(ref s) => String::from_utf8_lossy(&s.0).into_owned(),
DynamicContent::Address(u) => hextab(16, u),
DynamicContent::Flags1(v) => format!("{:?}", v),
}
);
}
}
SectionContent::Raw(ref s) => match section.name.as_slice() {
b".interp" => {
println!("");
println!(
"{} program interpreter section at offset 0x{:x}:",
String::from_utf8_lossy(§ion.name).bold(),
section.header.offset
);
println!(" {}", String::from_utf8_lossy(s));
}
_ => {}
},
_ => {}
}
}
}