Rework ELF data into structs, break up main.rs
This commit is contained in:
parent
e446d06c82
commit
0b6fc85612
13
notes/jan31.md
Normal file
13
notes/jan31.md
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Lecture notes 1/31/2023
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
- Load file into byte array
|
||||||
|
- check if ELF
|
||||||
|
- parse file header
|
||||||
|
- get offset and length of text section
|
||||||
|
- virtual addresses and size
|
||||||
|
- get function addresses
|
||||||
|
|
||||||
|
## Disassembly
|
||||||
|
- Use something like [Capstone]()
|
||||||
|
- feed address and offset in linear sweep to find instruction
|
||||||
88
src/elf.rs
Normal file
88
src/elf.rs
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
|
||||||
|
// Generic ELF information offsets.
|
||||||
|
|
||||||
|
pub const MAGIC_NUMBER: &[u8] = &[0x7F,0x45,0x4C,0x46];
|
||||||
|
pub const ARCH_OFFSET: u8 = 0x04; // x86 or x64 indiicator; 1 byte
|
||||||
|
pub const ENDIAN_OFFSET: u8 = 0x05; // Endian offset (1 - little, 2 - big); 1 byte
|
||||||
|
pub const ABI_OFFSET: u8 = 0x07; // ABI identifier; 1 byte
|
||||||
|
pub const TYPE_OFFSET: u8 = 0x10; // Object type identifier; 2 bytes
|
||||||
|
pub const MACHINE_OFFSET: u8 = 0x12; // Instruction set type; 2 bytes
|
||||||
|
|
||||||
|
|
||||||
|
// Offsets for file header entry points and table inforamtion.
|
||||||
|
// Arrayed offset are split by architecture:
|
||||||
|
// 0 : x86
|
||||||
|
// 1 : x86_64
|
||||||
|
|
||||||
|
pub const ENTRYPOINT_OFFSET: u8 = 0x18;
|
||||||
|
pub const PHOFF_OFFSET: [u8; 2] = [0x1C, 0x20]; // Program header table pointer; 2 bytes
|
||||||
|
pub const SHOFF_OFFSET: [u8; 2] = [0x20, 0x28]; // Section table pointer; 2 bytes
|
||||||
|
pub const EHSIZE_OFFSET: [u8; 2] = [0x28, 0x34]; // Program header table entry size pointer; 2 bytes
|
||||||
|
pub const PHENTSIZE_OFFSET: [u8; 2] = [0x28, 0x34]; // Section table pointer; 2 bytes
|
||||||
|
pub const PHNUM_OFFSET: [u8; 2] = [0x2C, 0x38]; // Program header table number of entries pointer; 2 bytes
|
||||||
|
pub const SHENTSIZE_OFFSET: [u8; 2] = [0x2E, 0x3A]; // Size of section header table; 2 bytes
|
||||||
|
pub const SHNUM_OFFSET: [u8; 2] = [0x30, 0x3C]; // Number of entries in section table pointer; 2 bytes
|
||||||
|
pub const SHSTRNDX_OFFSET: [u8; 2] = [0x32, 0x3E]; // Index of section header that contains names; 2 bytes
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ArchitecureType {
|
||||||
|
X86,
|
||||||
|
X86_64,
|
||||||
|
Unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum EndianType {
|
||||||
|
Big,
|
||||||
|
Little,
|
||||||
|
Unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FileHeader {
|
||||||
|
pub arch: ArchitecureType,
|
||||||
|
pub is_x86_64: bool,
|
||||||
|
pub endian: EndianType,
|
||||||
|
pub abi: u8,
|
||||||
|
pub elf_type: u8,
|
||||||
|
pub isa: u8,
|
||||||
|
pub entryoff: u8,
|
||||||
|
pub phoff: u8,
|
||||||
|
pub shoff: u8,
|
||||||
|
pub ehsize: u8,
|
||||||
|
pub phentsize: u8,
|
||||||
|
pub phnum: u8,
|
||||||
|
pub shentsize: u8,
|
||||||
|
pub shnum: u8,
|
||||||
|
pub shstrndx: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ProgramHeader {
|
||||||
|
pub program_type: u8,
|
||||||
|
pub flags: u8,
|
||||||
|
pub offset: u8,
|
||||||
|
pub vaddr: u8,
|
||||||
|
pub paddr: u8,
|
||||||
|
pub filesz: u8,
|
||||||
|
pub align: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SectionHeader {
|
||||||
|
pub name: u8,
|
||||||
|
pub section_type: u8,
|
||||||
|
pub flags: u8,
|
||||||
|
pub addr: u8,
|
||||||
|
pub offset: u8,
|
||||||
|
pub size: u8,
|
||||||
|
pub link: u8,
|
||||||
|
pub info: u8,
|
||||||
|
pub addralign: u8,
|
||||||
|
pub entsize: u8
|
||||||
|
}
|
||||||
101
src/main.rs
101
src/main.rs
|
|
@ -8,38 +8,10 @@ use std::path;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
|
// Import modules
|
||||||
// ELF Header Sizes
|
mod elf;
|
||||||
|
mod util;
|
||||||
const ELF_FILE_HEADER_LENGTH: [u8; 2] = [0x34, 0x40];
|
|
||||||
|
|
||||||
|
|
||||||
// Generic ELF information offsets.
|
|
||||||
|
|
||||||
const ELF_MAGIC_NUMBER: &[u8] = &[0x7F,0x45,0x4C,0x46];
|
|
||||||
const ELF_ARCH_OFFSET: u8 = 0x04; // x86 or x64 indiicator; 1 byte
|
|
||||||
const ELF_ENDIAN_OFFSET: u8 = 0x05; // Endian offset (1 - little, 2 - big); 1 byte
|
|
||||||
const ELF_ABI_OFFSET: u8 = 0x07; // ABI identifier; 1 byte
|
|
||||||
const ELF_TYPE_OFFSET: u8 = 0x10; // Object type identifier; 2 bytes
|
|
||||||
const ELF_MACHINE_OFFSET: u8 = 0x12; // Instruction set type; 2 bytes
|
|
||||||
|
|
||||||
|
|
||||||
// Offsets for file header entry points and table inforamtion.
|
|
||||||
// Arrayed offset are split by architecture:
|
|
||||||
// 0 : x86
|
|
||||||
// 1 : x86_64
|
|
||||||
|
|
||||||
const ELF_ENTRYPOINT_OFFSET: u8 = 0x18;
|
|
||||||
const ELF_PHOFF_OFFSET: [u8; 2] = [0x1C, 0x20]; // Program header table pointer; 2 bytes
|
|
||||||
const ELF_SHOFF_OFFSET: [u8; 2] = [0x20, 0x28]; // Section table pointer; 2 bytes
|
|
||||||
const ELF_EHSIZE_OFFSET: [u8; 2] = [0x28, 0x34]; // Program header table entry size pointer; 2 bytes
|
|
||||||
const ELF_PHENTSIZE_OFFSET: [u8; 2] = [0x28, 0x34]; // Section table pointer; 2 bytes
|
|
||||||
const ELF_PHNUM_OFFSET: [u8; 2] = [0x2C, 0x38]; // Program header table number of entries pointer; 2 bytes
|
|
||||||
const ELF_SHENTSIZE_OFFSET: [u8; 2] = [0x2E, 0x3A]; // Size of section header table; 2 bytes
|
|
||||||
const ELF_SHNUM_OFFSET: [u8; 2] = [0x30, 0x3C]; // Number of entries in section table pointer; 2 bytes
|
|
||||||
const ELF_SHSTRNDX_OFFSET: [u8; 2] = [0x32, 0x3E]; // Index of section header that contains names; 2 bytes
|
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
@ -49,14 +21,14 @@ fn main() {
|
||||||
// Grab our filepath from our options
|
// Grab our filepath from our options
|
||||||
if &args.len() < &2 {
|
if &args.len() < &2 {
|
||||||
// No file given, terminate
|
// No file given, terminate
|
||||||
println!("[Error] Please provied a file to open...");
|
println!("[Error] Please provide a filepath to open");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let file_path: &String = &args[1];
|
let file_path: &String = &args[1];
|
||||||
|
|
||||||
if path::Path::new(file_path).exists() {
|
if path::Path::new(file_path).exists() {
|
||||||
println!("File exists, reading '{}'", file_path);
|
println!("File exists, reading '{}'...", file_path);
|
||||||
|
|
||||||
let contents: Result<Vec<u8>, std::io::Error> = fs::read(file_path);
|
let contents: Result<Vec<u8>, std::io::Error> = fs::read(file_path);
|
||||||
|
|
||||||
|
|
@ -64,16 +36,18 @@ fn main() {
|
||||||
let bytes: &Vec<u8> = &contents.expect("");
|
let bytes: &Vec<u8> = &contents.expect("");
|
||||||
let magic_num: &[u8] = &bytes[0..4];
|
let magic_num: &[u8] = &bytes[0..4];
|
||||||
|
|
||||||
if magic_num == ELF_MAGIC_NUMBER {
|
if magic_num == elf::MAGIC_NUMBER {
|
||||||
println!("Found ELF Magic Number...");
|
println!("Found ELF Magic Number...");
|
||||||
println!("Parsing File Header...");
|
println!("Parsing File Header...");
|
||||||
|
|
||||||
// Build the File Header data structure
|
// Build the File Header data structure
|
||||||
let file_header_map = build_fild_header(bytes);
|
let file_header: elf::FileHeader = build_file_header(bytes);
|
||||||
|
|
||||||
for (key, value) in &file_header_map {
|
// Build Program Header data structure
|
||||||
println!("{}: {}", key, value);
|
//let program_header: elf::ProgramHeader = build_program_header(bytes, file_header.is_x86_64);
|
||||||
}
|
|
||||||
|
println!("{:?}", file_header);
|
||||||
|
//println!("{:?}", program_header);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
println!("[Error] Could not find magic number, is this an ELF executable?")
|
println!("[Error] Could not find magic number, is this an ELF executable?")
|
||||||
|
|
@ -88,29 +62,44 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn build_fild_header(data: &Vec<u8>) -> HashMap<String, u8>{
|
fn build_file_header(data: &Vec<u8>) -> elf::FileHeader {
|
||||||
let mut file_header: HashMap<String, u8> = HashMap::new();
|
|
||||||
|
|
||||||
// Determine x86 or x64 architecture
|
// Determine x86 or x64 architecture
|
||||||
// 0 : x86
|
// 0 : x86
|
||||||
// 1 : x64
|
// 1 : x64
|
||||||
let arch: u8 = (data[ELF_ARCH_OFFSET as usize] - 1).into();
|
let arch: usize = (data[elf::ARCH_OFFSET as usize] - 1).into();
|
||||||
|
|
||||||
file_header.insert("e_arch".to_string(), data[ELF_ARCH_OFFSET as usize]);
|
let file_header: elf::FileHeader = elf::FileHeader {
|
||||||
file_header.insert("e_endian".to_string(), data[ELF_ENDIAN_OFFSET as usize]);
|
arch: util::parse_architecture(data[elf::ARCH_OFFSET as usize]),
|
||||||
file_header.insert("e_abi".to_string(), data[ELF_ABI_OFFSET as usize]);
|
is_x86_64: arch != 0,
|
||||||
file_header.insert("e_type".to_string(), data[ELF_TYPE_OFFSET as usize]);
|
endian: util::parse_endian(data[elf::ENDIAN_OFFSET as usize]),
|
||||||
file_header.insert("e_machine".to_string(), data[ELF_MACHINE_OFFSET as usize]);
|
abi: data[elf::ABI_OFFSET as usize],
|
||||||
|
elf_type: data[elf::TYPE_OFFSET as usize],
|
||||||
file_header.insert("e_entry".to_string(), data[ELF_ENTRYPOINT_OFFSET as usize]);
|
isa: data[elf::MACHINE_OFFSET as usize],
|
||||||
file_header.insert("e_phoff".to_string(), data[ELF_PHOFF_OFFSET[arch as usize] as usize]);
|
entryoff: data[elf::ENTRYPOINT_OFFSET as usize],
|
||||||
file_header.insert("e_shoff".to_string(), data[ELF_SHOFF_OFFSET[arch as usize] as usize]);
|
phoff: data[elf::PHOFF_OFFSET[arch] as usize],
|
||||||
file_header.insert("e_ehsize".to_string(), data[ELF_EHSIZE_OFFSET[arch as usize] as usize]);
|
shoff: data[elf::SHOFF_OFFSET[arch] as usize],
|
||||||
file_header.insert("e_phentsize".to_string(), data[ELF_PHENTSIZE_OFFSET[arch as usize] as usize]);
|
ehsize: data[elf::EHSIZE_OFFSET[arch] as usize],
|
||||||
file_header.insert("e_phnum".to_string(), data[ELF_PHNUM_OFFSET[arch as usize] as usize]);
|
phentsize: data[elf::PHENTSIZE_OFFSET[arch] as usize],
|
||||||
file_header.insert("e_shentsize".to_string(), data[ELF_SHENTSIZE_OFFSET[arch as usize] as usize]);
|
phnum: data[elf::PHNUM_OFFSET[arch] as usize],
|
||||||
file_header.insert("e_shnum".to_string(), data[ELF_SHNUM_OFFSET[arch as usize] as usize]);
|
shentsize: data[elf::SHENTSIZE_OFFSET[arch] as usize],
|
||||||
file_header.insert("e_shstrndx".to_string(), data[ELF_SHSTRNDX_OFFSET[arch as usize] as usize]);
|
shnum: data[elf::SHNUM_OFFSET[arch] as usize],
|
||||||
|
shstrndx: data[elf::SHSTRNDX_OFFSET[arch] as usize],
|
||||||
|
};
|
||||||
|
|
||||||
return file_header;
|
return file_header;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// fn build_program_header(data: &Vec<u8>, is_x86_64: bool) -> elf::ProgramHeader {
|
||||||
|
|
||||||
|
// let arch: i8 = if is_x86_64 { 1 } else { 0 };
|
||||||
|
|
||||||
|
// let mut program_header: elf::ProgramHeader;
|
||||||
|
|
||||||
|
// // let mut program_header: elf::ProgramHeader = elf::ProgramHeader {
|
||||||
|
// // arch: util::parse_architecture(data[elf::ARCH_OFFSET as usize])
|
||||||
|
// // };
|
||||||
|
|
||||||
|
// return program_header;
|
||||||
|
// }
|
||||||
58
src/util.rs
Normal file
58
src/util.rs
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
use crate::elf::{self, EndianType, ArchitecureType};
|
||||||
|
|
||||||
|
|
||||||
|
pub fn parse_endian(endian: u8) -> elf::EndianType {
|
||||||
|
match endian {
|
||||||
|
0x00 => return EndianType::Big,
|
||||||
|
0x01 => return EndianType::Little,
|
||||||
|
_ => return EndianType::Unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn parse_architecture(arch: u8) -> elf::ArchitecureType {
|
||||||
|
match arch {
|
||||||
|
0x01 => return ArchitecureType::X86,
|
||||||
|
0x02 => return ArchitecureType::X86_64,
|
||||||
|
_ => return ArchitecureType::Unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn parse_abi(abi: u8) -> String {
|
||||||
|
match abi {
|
||||||
|
0x00 => "SystemV".to_string(),
|
||||||
|
0x01 => "HP-UX".to_string(),
|
||||||
|
0x02 => "NetBSD".to_string(),
|
||||||
|
0x03 => "Linux".to_string(),
|
||||||
|
0x04 => "GNU Hurd".to_string(),
|
||||||
|
0x06 => "Solaris".to_string(),
|
||||||
|
0x07 => "AIX".to_string(),
|
||||||
|
0x08 => "IRIX".to_string(),
|
||||||
|
0x09 => "FreeBSD".to_string(),
|
||||||
|
0x0C => "OpenBSD".to_string(),
|
||||||
|
0x0D => "OpenVMS".to_string(),
|
||||||
|
|
||||||
|
// Match unknown ABI
|
||||||
|
_ => "Unknown".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn parse_isa(isa: u8) -> String {
|
||||||
|
match isa {
|
||||||
|
0x03 => "Intel x86".to_string(),
|
||||||
|
0x3E => "AMD x86-64".to_string(),
|
||||||
|
|
||||||
|
// Matching just for fun, maybe future functionality? o.O
|
||||||
|
0x14 => "PowerPC".to_string(),
|
||||||
|
0x15 => "PowerPC 64-bit".to_string(),
|
||||||
|
0x32 => "IA_64".to_string(),
|
||||||
|
0x28 => "Arm".to_string(),
|
||||||
|
0xB7 => "Arm 64-bit".to_string(),
|
||||||
|
|
||||||
|
// Match unknown ISA
|
||||||
|
_ => "Unknown".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BIN
testing/hello.o
Normal file
BIN
testing/hello.o
Normal file
Binary file not shown.
BIN
testing/hello.stripped
Executable file
BIN
testing/hello.stripped
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user