You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
350 lines
7.9 KiB
Rust
350 lines
7.9 KiB
Rust
use core::fmt;
|
|
use std::{char, env, fs};
|
|
|
|
fn main() {
|
|
let mut args = env::args().skip(1);
|
|
let path = args.next().unwrap();
|
|
|
|
let bytes = fs::read(path).unwrap();
|
|
|
|
let elf = Elf::parse(&bytes).unwrap();
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
struct InputBytes<'a> {
|
|
bytes: &'a [u8],
|
|
}
|
|
|
|
impl<'a> InputBytes<'a> {
|
|
fn new(bytes: &'a [u8]) -> Self {
|
|
Self { bytes }
|
|
}
|
|
|
|
fn new_offset(bytes: &'a [u8], offset: usize) -> Self {
|
|
Self::new(bytes).advanced(offset)
|
|
}
|
|
|
|
fn prefix_len(&self, n: usize) -> usize {
|
|
self.bytes.len().min(n)
|
|
}
|
|
|
|
fn advanced(&self, n: usize) -> Self {
|
|
Self {
|
|
bytes: &self.bytes[self.prefix_len(n)..],
|
|
}
|
|
}
|
|
|
|
fn advance(&mut self, n: usize) -> &mut Self {
|
|
self.bytes = &self.bytes[self.prefix_len(n)..];
|
|
self
|
|
}
|
|
|
|
fn peek(&self, n: usize) -> Result<&'a [u8], ParseError> {
|
|
self.bytes.get(..n).ok_or(ParseError::UnexpectedEof)
|
|
}
|
|
|
|
fn pop(&mut self, n: usize) -> Result<&'a [u8], ParseError> {
|
|
let res = self.peek(n);
|
|
if res.is_ok() {
|
|
self.advance(n);
|
|
}
|
|
res
|
|
}
|
|
|
|
fn pop_arr<const N: usize>(&mut self) -> Result<[u8; N], ParseError> {
|
|
self.pop(N).map(|bs| <[u8; N]>::try_from(bs).unwrap())
|
|
}
|
|
|
|
fn pop_u8(&mut self) -> Result<u8, ParseError> {
|
|
self.pop_arr::<1>().map(|[x]| x)
|
|
}
|
|
|
|
fn pop_u16(&mut self, endianness: Endianness) -> Result<u16, ParseError> {
|
|
let bytes = self.pop_arr::<2>()?;
|
|
Ok(endianness.read_u16(bytes))
|
|
}
|
|
|
|
fn pop_u32(&mut self, endianness: Endianness) -> Result<u32, ParseError> {
|
|
let bytes = self.pop_arr::<4>()?;
|
|
Ok(endianness.read_u32(bytes))
|
|
}
|
|
|
|
fn pop_u64(&mut self, endianness: Endianness) -> Result<u64, ParseError> {
|
|
let bytes = self.pop_arr::<8>()?;
|
|
Ok(endianness.read_u64(bytes))
|
|
}
|
|
|
|
fn pop_word(&mut self, endianness: Endianness, width: Width) -> Result<u64, ParseError> {
|
|
match width {
|
|
Width::Bits32 => self.pop_u32(endianness).map(u64::from),
|
|
Width::Bits64 => self.pop_u64(endianness),
|
|
}
|
|
}
|
|
|
|
fn pop_word_usize(&mut self, endianness: Endianness, width: Width) -> Result<usize, ParseError> {
|
|
self.pop_word(endianness, width)
|
|
.and_then(|x| usize::try_from(x).map_err(|_| ParseError::OffsetOutOfBounds))
|
|
}
|
|
|
|
fn hexdump(&self, n: usize) {
|
|
print!("{: <8}", "");
|
|
for i in 0..16 {
|
|
print!(" {:x}", i);
|
|
}
|
|
println!();
|
|
for (i, chunk) in self.bytes[.. n.min(self.bytes.len())].chunks(16).enumerate() {
|
|
print!("{:08x}", i * 16);
|
|
for b in chunk {
|
|
print!(" {:02x}", b);
|
|
}
|
|
print!("{: <1$}", "", 4 + 3 * (16 - chunk.len()));
|
|
for b in chunk {
|
|
let c = match char::from(*b) {
|
|
c if c.is_ascii_graphic() => c,
|
|
_ => '.',
|
|
};
|
|
print!("{}", c);
|
|
}
|
|
println!();
|
|
}
|
|
}
|
|
}
|
|
|
|
struct Elf<'a> {
|
|
elf_bytes: &'a [u8],
|
|
bl: ByteLayout,
|
|
header_version: u8,
|
|
abi: u8,
|
|
ty: ElfType,
|
|
instruction_set: Option<InstructionSet>,
|
|
elf_version: u32,
|
|
}
|
|
|
|
impl<'a> Elf<'a> {
|
|
fn parse(bytes: &'a [u8]) -> Result<Self, ElfError> {
|
|
let mut hdr = InputBytes::new(bytes);
|
|
|
|
hdr.hexdump(64);
|
|
|
|
let magic = hdr.pop(4)?;
|
|
if magic != &[0x7f, b'E', b'L', b'F'] {
|
|
return Err(ElfError::BadMagic);
|
|
}
|
|
|
|
let width = match hdr.pop_u8()? {
|
|
1 => Width::Bits32,
|
|
2 => Width::Bits64,
|
|
_ => return Err(ElfError::UnsupportedValue),
|
|
};
|
|
|
|
let endianness = match hdr.pop_u8()? {
|
|
1 => Endianness::Little,
|
|
2 => Endianness::Big,
|
|
_ => return Err(ElfError::UnsupportedValue),
|
|
};
|
|
|
|
let bl = ByteLayout {
|
|
endianness,
|
|
width,
|
|
};
|
|
|
|
let header_version = hdr.pop_u8()?;
|
|
|
|
let abi = hdr.pop_u8()?;
|
|
|
|
hdr.pop(8)?;
|
|
|
|
let ty = match hdr.pop_u16(endianness)? {
|
|
1 => ElfType::Relocatable,
|
|
2 => ElfType::Executable,
|
|
3 => ElfType::Shared,
|
|
4 => ElfType::Core,
|
|
_ => return Err(ElfError::UnsupportedValue),
|
|
};
|
|
|
|
let instruction_set = match hdr.pop_u16(endianness)? {
|
|
0 => None,
|
|
0x02 => Some(InstructionSet::Sparc),
|
|
0x03 => Some(InstructionSet::I386),
|
|
0x08 => Some(InstructionSet::Mips),
|
|
0x14 => Some(InstructionSet::PowerPc),
|
|
0x28 => Some(InstructionSet::Arm),
|
|
0x2a => Some(InstructionSet::SuperH),
|
|
0x32 => Some(InstructionSet::Ia64),
|
|
0x3e => Some(InstructionSet::Amd64),
|
|
0xb7 => Some(InstructionSet::Aarch64),
|
|
0xf3 => Some(InstructionSet::RiscV),
|
|
_ => return Err(ElfError::UnsupportedValue),
|
|
};
|
|
|
|
let elf_version = hdr.pop_u32(endianness)?;
|
|
let entry_offset = hdr.pop_word(endianness, width)?;
|
|
let pht_offset = hdr.pop_word_usize(endianness, width)?;
|
|
let sht_offset = hdr.pop_word_usize(endianness, width)?;
|
|
let flags = hdr.pop_u32(endianness)?;
|
|
let header_size = hdr.pop_u16(endianness)?;
|
|
let pht_entry_size = hdr.pop_u16(endianness)?;
|
|
let pht_len = hdr.pop_u16(endianness)?;
|
|
let sht_entry_size = hdr.pop_u16(endianness)?;
|
|
let sht_len = hdr.pop_u16(endianness)?;
|
|
let shstr_idx = hdr.pop_u16(endianness)?;
|
|
|
|
dbg!(entry_offset);
|
|
dbg!(pht_offset);
|
|
dbg!(sht_offset);
|
|
dbg!(flags);
|
|
dbg!(header_size);
|
|
dbg!(pht_entry_size);
|
|
dbg!(pht_len);
|
|
dbg!(sht_entry_size);
|
|
dbg!(sht_len);
|
|
dbg!(shstr_idx);
|
|
|
|
// TODO
|
|
|
|
let shstr = SectionHeader::parse(bl,
|
|
InputBytes::new_offset(bytes, sht_offset + usize::from(sht_entry_size * shstr_idx)))?;
|
|
|
|
let str_table = InputBytes::new_offset(bytes, shstr.offset);
|
|
str_table.hexdump(shstr.size);
|
|
|
|
Ok(Self {
|
|
elf_bytes: bytes,
|
|
bl,
|
|
header_version,
|
|
abi,
|
|
ty,
|
|
instruction_set,
|
|
elf_version,
|
|
})
|
|
}
|
|
}
|
|
|
|
struct SectionHeader {
|
|
name: u32,
|
|
// FIXME: parse type
|
|
ty: u32,
|
|
flags: u64,
|
|
addr: u64,
|
|
offset: usize,
|
|
size: usize,
|
|
link: u32,
|
|
info: u32,
|
|
align: u64,
|
|
ent_size: usize,
|
|
}
|
|
|
|
impl SectionHeader {
|
|
fn parse(bl: ByteLayout, mut bytes: InputBytes) -> Result<Self, ElfError> {
|
|
let name = bytes.pop_u32(bl.endianness)?;
|
|
let ty = bytes.pop_u32(bl.endianness)?;
|
|
let flags = bytes.pop_word(bl.endianness, bl.width)?;
|
|
let addr = bytes.pop_word(bl.endianness, bl.width)?;
|
|
let offset = bytes.pop_word_usize(bl.endianness, bl.width)?;
|
|
let size = bytes.pop_word_usize(bl.endianness, bl.width)?;
|
|
let link = bytes.pop_u32(bl.endianness)?;
|
|
let info = bytes.pop_u32(bl.endianness)?;
|
|
let align = bytes.pop_word(bl.endianness, bl.width)?;
|
|
let ent_size = bytes.pop_word_usize(bl.endianness, bl.width)?;
|
|
|
|
Ok(Self {
|
|
name,
|
|
ty,
|
|
flags,
|
|
addr,
|
|
offset,
|
|
size,
|
|
link,
|
|
info,
|
|
align,
|
|
ent_size,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
struct ByteLayout {
|
|
endianness: Endianness,
|
|
width: Width,
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
enum Width {
|
|
Bits32,
|
|
Bits64,
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
enum Endianness {
|
|
Little,
|
|
Big,
|
|
}
|
|
|
|
impl Endianness {
|
|
fn read_u16(self, bytes: [u8; 2]) -> u16 {
|
|
match self {
|
|
Self::Little => u16::from_le_bytes(bytes),
|
|
Self::Big => u16::from_be_bytes(bytes),
|
|
}
|
|
}
|
|
|
|
fn read_u32(self, bytes: [u8; 4]) -> u32 {
|
|
match self {
|
|
Self::Little => u32::from_le_bytes(bytes),
|
|
Self::Big => u32::from_be_bytes(bytes),
|
|
}
|
|
}
|
|
|
|
fn read_u64(self, bytes: [u8; 8]) -> u64 {
|
|
match self {
|
|
Self::Little => u64::from_le_bytes(bytes),
|
|
Self::Big => u64::from_be_bytes(bytes),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
enum ElfType {
|
|
Relocatable,
|
|
Executable,
|
|
Shared,
|
|
Core,
|
|
}
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
enum InstructionSet {
|
|
Sparc,
|
|
I386,
|
|
Mips,
|
|
PowerPc,
|
|
Arm,
|
|
SuperH,
|
|
Ia64,
|
|
Amd64,
|
|
Aarch64,
|
|
RiscV,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
enum ElfError {
|
|
BadMagic,
|
|
UnexpectedEof,
|
|
OffsetOutOfBounds,
|
|
UnsupportedValue,
|
|
}
|
|
|
|
impl From<ParseError> for ElfError {
|
|
fn from(value: ParseError) -> Self {
|
|
match value {
|
|
ParseError::UnexpectedEof => Self::UnexpectedEof,
|
|
ParseError::OffsetOutOfBounds => Self::OffsetOutOfBounds,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
enum ParseError {
|
|
UnexpectedEof,
|
|
OffsetOutOfBounds,
|
|
}
|