use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub enum ElfType {
None,
Relocatable,
Executable,
SharedObject,
Core,
}
impl fmt::Display for ElfType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ElfType::None => write!(f, "无类型文件"),
ElfType::Relocatable => write!(f, "可重定位文件"),
ElfType::Executable => write!(f, "可执行文件"),
ElfType::SharedObject => write!(f, "共享目标文件"),
ElfType::Core => write!(f, "核心转储文件"),
}
}
}
impl From<u16> for ElfType {
fn from(value: u16) -> Self {
match value {
0 => ElfType::None,
1 => ElfType::Relocatable,
2 => ElfType::Executable,
3 => ElfType::SharedObject,
4 => ElfType::Core,
_ => ElfType::None,
}
}
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub enum ElfMachine {
None,
I386,
X86_64,
Arm,
AArch64,
RiscV,
}
impl From<u16> for ElfMachine {
fn from(value: u16) -> Self {
match value {
0 => ElfMachine::None,
3 => ElfMachine::I386,
62 => ElfMachine::X86_64,
40 => ElfMachine::Arm,
183 => ElfMachine::AArch64,
243 => ElfMachine::RiscV,
_ => ElfMachine::None,
}
}
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct ElfHeader64 {
pub e_ident: [u8; 16],
pub e_type: u16,
pub e_machine: u16,
pub e_version: u32,
pub e_entry: u64,
pub e_phoff: u64,
pub e_shoff: u64,
pub e_flags: u32,
pub e_ehsize: u16,
pub e_phentsize: u16,
pub e_phnum: u16,
pub e_shentsize: u16,
pub e_shnum: u16,
pub e_shstrndx: u16,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct ProgramHeader64 {
pub p_type: u32,
pub p_flags: u32,
pub p_offset: u64,
pub p_vaddr: u64,
pub p_paddr: u64,
pub p_filesz: u64,
pub p_memsz: u64,
pub p_align: u64,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct SectionHeader64 {
pub sh_name: u32,
pub sh_type: u32,
pub sh_flags: u64,
pub sh_addr: u64,
pub sh_offset: u64,
pub sh_size: u64,
pub sh_link: u32,
pub sh_info: u32,
pub sh_addralign: u64,
pub sh_entsize: u64,
}
pub mod segment_type {
pub const PT_NULL: u32 = 0;
pub const PT_LOAD: u32 = 1;
pub const PT_DYNAMIC: u32 = 2;
pub const PT_INTERP: u32 = 3;
pub const PT_NOTE: u32 = 4;
pub const PT_SHLIB: u32 = 5;
pub const PT_PHDR: u32 = 6;
pub const PT_TLS: u32 = 7;
}
pub mod section_type {
pub const SHT_NULL: u32 = 0;
pub const SHT_PROGBITS: u32 = 1;
pub const SHT_SYMTAB: u32 = 2;
pub const SHT_STRTAB: u32 = 3;
pub const SHT_RELA: u32 = 4;
pub const SHT_HASH: u32 = 5;
pub const SHT_DYNAMIC: u32 = 6;
pub const SHT_NOTE: u32 = 7;
pub const SHT_NOBITS: u32 = 8;
pub const SHT_REL: u32 = 9;
pub const SHT_SHLIB: u32 = 10;
pub const SHT_DYNSYM: u32 = 11;
}
pub mod segment_flags {
pub const PF_X: u32 = 1;
pub const PF_W: u32 = 2;
pub const PF_R: u32 = 4;
}
pub mod section_flags {
pub const SHF_WRITE: u64 = 1;
pub const SHF_ALLOC: u64 = 2;
pub const SHF_EXECINSTR: u64 = 4;
}
impl ElfHeader64 {
pub fn new() -> Self {
let mut e_ident = [0u8; 16];
e_ident[0] = 0x7f;
e_ident[1] = b'E';
e_ident[2] = b'L';
e_ident[3] = b'F';
e_ident[4] = 2;
e_ident[5] = 1;
e_ident[6] = 1;
e_ident[7] = 0;
Self {
e_ident,
e_type: 2, e_machine: 62, e_version: 1,
e_entry: 0x401000, e_phoff: 64, e_shoff: 0, e_flags: 0,
e_ehsize: 64, e_phentsize: 56, e_phnum: 1, e_shentsize: 64, e_shnum: 0, e_shstrndx: 0, }
}
}
impl Default for ElfHeader64 {
fn default() -> Self {
Self::new()
}
}
impl ProgramHeader64 {
pub fn new_load_segment(offset: u64, vaddr: u64, size: u64) -> Self {
Self {
p_type: segment_type::PT_LOAD,
p_flags: segment_flags::PF_R | segment_flags::PF_X, p_offset: offset,
p_vaddr: vaddr,
p_paddr: vaddr,
p_filesz: size,
p_memsz: size,
p_align: 0x1000, }
}
}
#[derive(Debug, Clone)]
pub struct ElfFile {
pub header: ElfHeader64,
pub program_headers: Vec<ProgramHeader64>,
pub section_headers: Vec<SectionHeader64>,
pub data: Vec<u8>,
}
impl ElfFile {
pub fn new() -> Self {
Self { header: ElfHeader64::new(), program_headers: Vec::new(), section_headers: Vec::new(), data: Vec::new() }
}
pub fn add_program_header(&mut self, header: ProgramHeader64) {
self.program_headers.push(header);
self.header.e_phnum = self.program_headers.len() as u16;
}
pub fn set_entry_point(&mut self, entry: u64) {
self.header.e_entry = entry;
}
pub fn create_executable(machine_code: Vec<u8>) -> Self {
let mut elf = Self::new();
let base_vaddr = 0x400000;
let header_size = 64 + 56; let code_offset = 0x1000;
elf.header.e_entry = base_vaddr + code_offset;
elf.header.e_phoff = 64;
elf.header.e_phnum = 1;
elf.data = vec![0u8; code_offset as usize];
elf.data.extend_from_slice(&machine_code);
let ph = ProgramHeader64::new_load_segment(0, base_vaddr, elf.data.len() as u64);
elf.add_program_header(ph);
elf
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.extend_from_slice(&self.header_to_bytes());
for ph in &self.program_headers {
bytes.extend_from_slice(&self.program_header_to_bytes(ph));
}
while bytes.len() % 0x1000 != 0 {
bytes.push(0);
}
bytes.extend_from_slice(&self.data);
bytes
}
fn header_to_bytes(&self) -> [u8; 64] {
let mut bytes = [0u8; 64];
let h = &self.header;
bytes[0..16].copy_from_slice(&h.e_ident);
bytes[16..18].copy_from_slice(&h.e_type.to_le_bytes());
bytes[18..20].copy_from_slice(&h.e_machine.to_le_bytes());
bytes[20..24].copy_from_slice(&h.e_version.to_le_bytes());
bytes[24..32].copy_from_slice(&h.e_entry.to_le_bytes());
bytes[32..40].copy_from_slice(&h.e_phoff.to_le_bytes());
bytes[40..48].copy_from_slice(&h.e_shoff.to_le_bytes());
bytes[48..52].copy_from_slice(&h.e_flags.to_le_bytes());
bytes[52..54].copy_from_slice(&h.e_ehsize.to_le_bytes());
bytes[54..56].copy_from_slice(&h.e_phentsize.to_le_bytes());
bytes[56..58].copy_from_slice(&h.e_phnum.to_le_bytes());
bytes[58..60].copy_from_slice(&h.e_shentsize.to_le_bytes());
bytes[60..62].copy_from_slice(&h.e_shnum.to_le_bytes());
bytes[62..64].copy_from_slice(&h.e_shstrndx.to_le_bytes());
bytes
}
fn program_header_to_bytes(&self, ph: &ProgramHeader64) -> [u8; 56] {
let mut bytes = [0u8; 56];
bytes[0..4].copy_from_slice(&ph.p_type.to_le_bytes());
bytes[4..8].copy_from_slice(&ph.p_flags.to_le_bytes());
bytes[8..16].copy_from_slice(&ph.p_offset.to_le_bytes());
bytes[16..24].copy_from_slice(&ph.p_vaddr.to_le_bytes());
bytes[24..32].copy_from_slice(&ph.p_paddr.to_le_bytes());
bytes[32..40].copy_from_slice(&ph.p_filesz.to_le_bytes());
bytes[40..48].copy_from_slice(&ph.p_memsz.to_le_bytes());
bytes[48..56].copy_from_slice(&ph.p_align.to_le_bytes());
bytes
}
}
impl Default for ElfFile {
fn default() -> Self {
Self::new()
}
}