├── .gitignore ├── Cargo.toml ├── LICENSE └── src ├── bin ├── elffile.rs ├── loader.rs └── read_header.rs ├── file ├── elf_file.rs └── mod.rs ├── header ├── elf_type.rs ├── header.rs ├── ident.rs ├── machine.rs ├── mod.rs ├── prog_header │ ├── flag.rs │ ├── mod.rs │ └── prog_header_type.rs └── sect_header │ ├── flag.rs │ ├── mod.rs │ └── sect_header_type.rs ├── lib.rs ├── loader ├── loader.rs └── mod.rs └── util └── mod.rs /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | busybox 6 | ls 7 | libc.so.6 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "elf-loader" 3 | version = "0.1.0" 4 | authors = ["Hajime Fukuda "] 5 | 6 | [dependencies] 7 | aligned_alloc = "0.1" 8 | bitflags = "1.0" 9 | cenums = {version = "0.1", git = "https://github.com/hajifkd/cenums"} 10 | 11 | [target.'cfg(unix)'.dependencies] 12 | libc = { version = "0.2"} 13 | 14 | [target.'cfg(windows)'.dependencies] 15 | winapi = { version = "0.3", features = [ "memoryapi", "sysinfoapi" ]} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Hajime Fukuda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/bin/elffile.rs: -------------------------------------------------------------------------------- 1 | extern crate elf_loader; 2 | 3 | use elf_loader::file::elf_file::ElfFile; 4 | use std::env; 5 | 6 | fn main() -> std::io::Result<()> { 7 | let args: Vec<_> = env::args().collect(); 8 | let file = ElfFile::new(&args[1])?; 9 | println!("{:?}", file.prog_headers); 10 | println!("{:?}", file.sect_headers); 11 | println!("{:?}", file.sect_header_names); 12 | Ok(()) 13 | } 14 | -------------------------------------------------------------------------------- /src/bin/loader.rs: -------------------------------------------------------------------------------- 1 | extern crate elf_loader; 2 | 3 | use elf_loader::loader::ElfLoader; 4 | use std::env; 5 | 6 | fn main() -> std::io::Result<()> { 7 | let args: Vec<_> = env::args().collect(); 8 | let mut loader = ElfLoader::new(&args[1])?; 9 | loader.load_memory(); 10 | unsafe { 11 | use std::mem::transmute; 12 | let entry: fn() = transmute(loader.get_entry_addr()); 13 | entry(); 14 | } 15 | Ok(()) 16 | } 17 | -------------------------------------------------------------------------------- /src/bin/read_header.rs: -------------------------------------------------------------------------------- 1 | extern crate elf_loader; 2 | 3 | use std::env; 4 | use std::fs::File; 5 | use std::io::BufReader; 6 | use std::io::prelude::*; 7 | 8 | use std::mem; 9 | use std::slice; 10 | 11 | use elf_loader::header::ElfHeader; 12 | 13 | fn main() -> std::io::Result<()> { 14 | let args: Vec<_> = env::args().collect(); 15 | let bin_file = File::open(&args[1])?; 16 | let mut reader = BufReader::new(bin_file); 17 | 18 | let mut header: ElfHeader = unsafe { mem::zeroed() }; 19 | let header_size = mem::size_of::(); 20 | unsafe { 21 | let header_slice = slice::from_raw_parts_mut(&mut header as *mut _ as *mut u8, header_size); 22 | reader.read_exact(header_slice)?; 23 | } 24 | 25 | println!("{:?}", header); 26 | 27 | Ok(()) 28 | } 29 | -------------------------------------------------------------------------------- /src/file/elf_file.rs: -------------------------------------------------------------------------------- 1 | use header::header::*; 2 | use header::prog_header::*; 3 | use header::sect_header::*; 4 | use std; 5 | use std::ffi::CStr; 6 | use std::fs::File; 7 | use std::mem; 8 | use util::read_into_ptr; 9 | 10 | #[derive(Debug)] 11 | pub struct ElfFile { 12 | pub header: ElfHeader, 13 | pub file: File, 14 | pub prog_headers: ProgramHeaders, 15 | pub sect_headers: SectionHeaders, 16 | pub sect_header_names: Vec, 17 | } 18 | 19 | macro_rules! read_header { 20 | ($fn_name:ident, $sum_type:ident, $entry_size:ident, $entry_num:ident, $offset:ident) => { 21 | fn $fn_name(header: &ElfHeader, file: &mut File) -> Result<$sum_type, std::io::Error> { 22 | let is_32 = header.is_32()?; 23 | let total_size = header.$entry_size as usize * header.$entry_num as usize; 24 | let offset = header.$offset as _; 25 | 26 | unsafe { 27 | if is_32 { 28 | let mut v = vec![mem::zeroed(); header.$entry_num as _]; 29 | read_into_ptr(file, v.as_mut_ptr() as _, total_size, offset)?; 30 | Ok($sum_type::Header32(v)) 31 | } else { 32 | let mut v = vec![mem::zeroed(); header.$entry_num as _]; 33 | read_into_ptr(file, v.as_mut_ptr() as _, total_size, offset)?; 34 | Ok($sum_type::Header64(v)) 35 | } 36 | } 37 | } 38 | }; 39 | } 40 | 41 | read_header! { 42 | read_prog_headers, 43 | ProgramHeaders, 44 | prog_header_entry_size, 45 | prog_header_entry_num, 46 | prog_header_offset 47 | } 48 | 49 | read_header! { 50 | read_sect_headers, 51 | SectionHeaders, 52 | sect_header_entry_size, 53 | sect_header_entry_num, 54 | sect_header_offset 55 | } 56 | 57 | impl ElfFile { 58 | pub fn new(path: &str) -> Result { 59 | ElfFile::new_from_file(File::open(path)?) 60 | } 61 | 62 | pub fn new_from_file(mut file: File) -> Result { 63 | let mut header: ElfHeader = unsafe { mem::zeroed() }; 64 | let header_size = mem::size_of::(); 65 | unsafe { 66 | read_into_ptr(&mut file, &mut header as *mut _ as _, header_size, 0)?; 67 | } 68 | 69 | let sect_headers = read_sect_headers(&header, &mut file)?; 70 | 71 | macro_rules! read_names { 72 | ($shdrs:expr) => {{ 73 | let strtab = $shdrs[header.sect_header_name_tbl_index as usize]; 74 | let mut buf = vec![0u8; strtab.size as usize]; 75 | unsafe { 76 | read_into_ptr( 77 | &mut file, 78 | buf.as_mut_ptr() as _, 79 | strtab.size as usize, 80 | strtab.offset as u64, 81 | )?; 82 | } 83 | let buf = buf; 84 | 85 | let mut res = $shdrs 86 | .iter() 87 | .map(|&shdr| { 88 | if shdr.sect_type == SectionHeaderType::NULL { 89 | Ok("".to_owned()) 90 | } else { 91 | unsafe { 92 | Ok( 93 | CStr::from_ptr(&buf[shdr.name_index as usize] as *const u8 as _) 94 | .to_str()? 95 | .to_owned(), 96 | ) 97 | } 98 | } 99 | }) 100 | .collect::>(); 101 | 102 | if res.iter() 103 | .any(|r: &Result<_, std::str::Utf8Error>| r.is_err()) 104 | { 105 | return Err(std::io::Error::new( 106 | std::io::ErrorKind::InvalidData, 107 | "Cannot decode section header name.", 108 | )); 109 | } 110 | 111 | res.into_iter().map(|r| r.unwrap()).collect() 112 | }}; 113 | } 114 | 115 | let sect_header_names = match sect_headers { 116 | SectionHeaders::Header32(ref shdrs) => read_names!(shdrs), 117 | SectionHeaders::Header64(ref shdrs) => read_names!(shdrs), 118 | }; 119 | 120 | Ok(ElfFile { 121 | header, 122 | prog_headers: read_prog_headers(&header, &mut file)?, 123 | sect_headers, 124 | sect_header_names, 125 | file, 126 | }) 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/file/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod elf_file; 2 | pub use self::elf_file::ElfFile; 3 | -------------------------------------------------------------------------------- /src/header/elf_type.rs: -------------------------------------------------------------------------------- 1 | cenums! { 2 | #[repr(C)] 3 | pub struct ElfType: u16 { 4 | const NONE = 0; 5 | const RELOCATABLE = 1; 6 | const EXECUTABLE = 2; 7 | const SHARED_OBJECT = 3; 8 | const CORE = 4; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/header/header.rs: -------------------------------------------------------------------------------- 1 | use super::elf_type; 2 | use super::ident; 3 | use super::machine; 4 | use std; 5 | 6 | #[repr(C)] 7 | #[derive(Debug, Copy, Clone)] 8 | pub struct ElfHeader { 9 | pub magics: [ident::ElfMagic; 4], 10 | pub file_class: ident::ElfFileClass, 11 | pub data_encoding: ident::ElfDataEncoding, 12 | pub elf_version: ident::ElfVersion, 13 | pub os_abi: ident::ElfOsAbi, 14 | pub abi_version: u8, 15 | pub pad: [u8; 7], // ident 16 | pub elf_type: elf_type::ElfType, 17 | pub machine: machine::ElfMachine, 18 | pub version: u32, 19 | pub entry: usize, 20 | pub prog_header_offset: usize, 21 | pub sect_header_offset: usize, 22 | pub flags: u32, // not used 23 | pub elf_header_size: u16, 24 | pub prog_header_entry_size: u16, 25 | pub prog_header_entry_num: u16, 26 | pub sect_header_entry_size: u16, 27 | pub sect_header_entry_num: u16, 28 | pub sect_header_name_tbl_index: u16, 29 | } 30 | 31 | impl ElfHeader { 32 | pub fn is_32(&self) -> Result { 33 | match self.file_class { 34 | ident::ElfFileClass::CLASS32 => Ok(true), 35 | ident::ElfFileClass::CLASS64 => Ok(false), 36 | _ => { 37 | return Err(std::io::Error::new( 38 | std::io::ErrorKind::InvalidData, 39 | "Unknown file class", 40 | )) 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/header/ident.rs: -------------------------------------------------------------------------------- 1 | cenums! { 2 | #[repr(C)] 3 | pub struct ElfMagic: u8 { 4 | const MAGIC0 = 0x7f; 5 | const MAGIC1 = 'E' as _; 6 | const MAGIC2 = 'L' as _; 7 | const MAGIC3 = 'F' as _; 8 | } 9 | } 10 | 11 | cenums! { 12 | #[repr(C)] 13 | pub struct ElfFileClass: u8 { 14 | const NONE = 0; 15 | const CLASS32 = 1; 16 | const CLASS64 = 2; 17 | } 18 | } 19 | 20 | cenums! { 21 | #[repr(C)] 22 | pub struct ElfDataEncoding: u8 { 23 | const NONE = 0; 24 | const LITTLE_ENDIAN = 1; 25 | const BIG_ENDIAN = 2; 26 | } 27 | } 28 | 29 | cenums! { 30 | #[repr(C)] 31 | pub struct ElfVersion: u8 { 32 | const NONE = 0; 33 | const CURRENT = 1; 34 | } 35 | } 36 | 37 | cenums! { 38 | #[repr(C)] 39 | pub struct ElfOsAbi: u8 { 40 | const SYSV = 0; 41 | const HPUX = 1; 42 | const NETBSD = 2; 43 | const LINUX = 3; 44 | const HURD = 4; 45 | const _86OPEN = 5; 46 | const SOLARIS = 6; 47 | const MONTEREY = 7; 48 | const IRIX = 8; 49 | const FREEBSD = 9; 50 | const TRU64 = 10; 51 | const MODESTO = 11; 52 | const OPENBSD = 12; 53 | const ARM = 97; 54 | const STANDALONE = 255; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/header/machine.rs: -------------------------------------------------------------------------------- 1 | cenums! { 2 | /// copied from http://llvm.org/doxygen/Support_2ELF_8h_source.html 3 | #[repr(C)] 4 | pub struct ElfMachine: u16 { 5 | const NONE = 0; // No machine 6 | const M32 = 1; // AT&T WE 32100 7 | const SPARC = 2; // SPARC 8 | const I386 = 3; // Intel 386 9 | const M68K = 4; // Motorola 68000 10 | const M88K = 5; // Motorola 88000 11 | const IAMCU = 6; // Intel MCU 12 | const I860 = 7; // Intel 80860 13 | const MIPS = 8; // MIPS R3000 14 | const S370 = 9; // IBM System/370 15 | const MIPS_RS3_LE = 10; // MIPS RS3000 Little-endian 16 | const PARISC = 15; // Hewlett-Packard PA-RISC 17 | const VPP500 = 17; // Fujitsu VPP500 18 | const SPARC32PLUS = 18; // Enhanced instruction set SPARC 19 | const I960 = 19; // Intel 80960 20 | const PPC = 20; // PowerPC 21 | const PPC64 = 21; // PowerPC64 22 | const S390 = 22; // IBM System/390 23 | const SPU = 23; // IBM SPU/SPC 24 | const V800 = 36; // NEC V800 25 | const FR20 = 37; // Fujitsu FR20 26 | const RH32 = 38; // TRW RH-32 27 | const RCE = 39; // Motorola RCE 28 | const ARM = 40; // ARM 29 | const ALPHA = 41; // DEC Alpha 30 | const SH = 42; // Hitachi SH 31 | const SPARCV9 = 43; // SPARC V9 32 | const TRICORE = 44; // Siemens TriCore 33 | const ARC = 45; // Argonaut RISC Core 34 | const H8_300 = 46; // Hitachi H8/300 35 | const H8_300H = 47; // Hitachi H8/300H 36 | const H8S = 48; // Hitachi H8S 37 | const H8_500 = 49; // Hitachi H8/500 38 | const IA_64 = 50; // Intel IA-64 processor architecture 39 | const MIPS_X = 51; // Stanford MIPS-X 40 | const COLDFIRE = 52; // Motorola ColdFire 41 | const M68HC12 = 53; // Motorola M68HC12 42 | const MMA = 54; // Fujitsu MMA Multimedia Accelerator 43 | const PCP = 55; // Siemens PCP 44 | const NCPU = 56; // Sony nCPU embedded RISC processor 45 | const NDR1 = 57; // Denso NDR1 microprocessor 46 | const STARCORE = 58; // Motorola Star*Core processor 47 | const ME16 = 59; // Toyota ME16 processor 48 | const ST100 = 60; // STMicroelectronics ST100 processor 49 | const TINYJ = 61; // Advanced Logic Corp. TinyJ embedded processor family 50 | const X86_64 = 62; // AMD x86-64 architecture 51 | const PDSP = 63; // Sony DSP Processor 52 | const PDP10 = 64; // Digital Equipment Corp. PDP-10 53 | const PDP11 = 65; // Digital Equipment Corp. PDP-11 54 | const FX66 = 66; // Siemens FX66 microcontroller 55 | const ST9PLUS = 67; // STMicroelectronics ST9+ 8/16 bit microcontroller 56 | const ST7 = 68; // STMicroelectronics ST7 8-bit microcontroller 57 | const M68HC16 = 69; // Motorola MC68HC16 Microcontroller 58 | const M68HC11 = 70; // Motorola MC68HC11 Microcontroller 59 | const M68HC08 = 71; // Motorola MC68HC08 Microcontroller 60 | const M68HC05 = 72; // Motorola MC68HC05 Microcontroller 61 | const SVX = 73; // Silicon Graphics SVx 62 | const ST19 = 74; // STMicroelectronics ST19 8-bit microcontroller 63 | const VAX = 75; // Digital VAX 64 | const CRIS = 76; // Axis Communications 32-bit embedded processor 65 | const JAVELIN = 77; // Infineon Technologies 32-bit embedded processor 66 | const FIREPATH = 78; // Element 14 64-bit DSP Processor 67 | const ZSP = 79; // LSI Logic 16-bit DSP Processor 68 | const MMIX = 80; // Donald Knuth's educational 64-bit processor 69 | const HUANY = 81; // Harvard University machine-independent object files 70 | const PRISM = 82; // SiTera Prism 71 | const AVR = 83; // Atmel AVR 8-bit microcontroller 72 | const FR30 = 84; // Fujitsu FR30 73 | const D10V = 85; // Mitsubishi D10V 74 | const D30V = 86; // Mitsubishi D30V 75 | const V850 = 87; // NEC v850 76 | const M32R = 88; // Mitsubishi M32R 77 | const MN10300 = 89; // Matsushita MN10300 78 | const MN10200 = 90; // Matsushita MN10200 79 | const PJ = 91; // picoJava 80 | const OPENRISC = 92; // OpenRISC 32-bit embedded processor 81 | const ARC_COMPACT = 93; // ARC International ARCompact processor (old 82 | // spelling/synonym: EM_ARC_A5) 83 | const XTENSA = 94; // Tensilica Xtensa Architecture 84 | const VIDEOCORE = 95; // Alphamosaic VideoCore processor 85 | const TMM_GPP = 96; // Thompson Multimedia General Purpose Processor 86 | const NS32K = 97; // National Semiconductor 32000 series 87 | const TPC = 98; // Tenor Network TPC processor 88 | const SNP1K = 99; // Trebia SNP 1000 processor 89 | const ST200 = 100; // STMicroelectronics (www.st.com) ST200 90 | const IP2K = 101; // Ubicom IP2xxx microcontroller family 91 | const MAX = 102; // MAX Processor 92 | const CR = 103; // National Semiconductor CompactRISC microprocessor 93 | const F2MC16 = 104; // Fujitsu F2MC16 94 | const MSP430 = 105; // Texas Instruments embedded microcontroller msp430 95 | const BLACKFIN = 106; // Analog Devices Blackfin (DSP) processor 96 | const SE_C33 = 107; // S1C33 Family of Seiko Epson processors 97 | const SEP = 108; // Sharp embedded microprocessor 98 | const ARCA = 109; // Arca RISC Microprocessor 99 | const UNICORE = 110; // Microprocessor series from PKU-Unity Ltd. and MPRC 100 | // of Peking University 101 | const EXCESS = 111; // eXcess: 16/32/64-bit configurable embedded CPU 102 | const DXP = 112; // Icera Semiconductor Inc. Deep Execution Processor 103 | const ALTERA_NIOS2 = 113; // Altera Nios II soft-core processor 104 | const CRX = 114; // National Semiconductor CompactRISC CRX 105 | const XGATE = 115; // Motorola XGATE embedded processor 106 | const C166 = 116; // Infineon C16x/XC16x processor 107 | const M16C = 117; // Renesas M16C series microprocessors 108 | const DSPIC30F = 118; // Microchip Technology dsPIC30F Digital Signal 109 | // Controller 110 | const CE = 119; // Freescale Communication Engine RISC core 111 | const M32C = 120; // Renesas M32C series microprocessors 112 | const TSK3000 = 131; // Altium TSK3000 core 113 | const RS08 = 132; // Freescale RS08 embedded processor 114 | const SHARC = 133; // Analog Devices SHARC family of 32-bit DSP 115 | // processors 116 | const ECOG2 = 134; // Cyan Technology eCOG2 microprocessor 117 | const SCORE7 = 135; // Sunplus S+core7 RISC processor 118 | const DSP24 = 136; // New Japan Radio (NJR) 24-bit DSP Processor 119 | const VIDEOCORE3 = 137; // Broadcom VideoCore III processor 120 | const LATTICEMICO32 = 138; // RISC processor for Lattice FPGA architecture 121 | const SE_C17 = 139; // Seiko Epson C17 family 122 | const TI_C6000 = 140; // The Texas Instruments TMS320C6000 DSP family 123 | const TI_C2000 = 141; // The Texas Instruments TMS320C2000 DSP family 124 | const TI_C5500 = 142; // The Texas Instruments TMS320C55x DSP family 125 | const MMDSP_PLUS = 160; // STMicroelectronics 64bit VLIW Data Signal Processor 126 | const CYPRESS_M8C = 161; // Cypress M8C microprocessor 127 | const R32C = 162; // Renesas R32C series microprocessors 128 | const TRIMEDIA = 163; // NXP Semiconductors TriMedia architecture family 129 | const HEXAGON = 164; // Qualcomm Hexagon processor 130 | const I8051 = 165; // Intel 8051 and variants 131 | const STXP7X = 166; // STMicroelectronics STxP7x family of configurable 132 | // and extensible RISC processors 133 | const NDS32 = 167; // Andes Technology compact code size embedded RISC 134 | // processor family 135 | const ECOG1 = 168; // Cyan Technology eCOG1X family 136 | const ECOG1X = 168; // Cyan Technology eCOG1X family 137 | const MAXQ30 = 169; // Dallas Semiconductor MAXQ30 Core Micro-controllers 138 | const XIMO16 = 170; // New Japan Radio (NJR) 16-bit DSP Processor 139 | const MANIK = 171; // M2000 Reconfigurable RISC Microprocessor 140 | const CRAYNV2 = 172; // Cray Inc. NV2 vector architecture 141 | const RX = 173; // Renesas RX family 142 | const METAG = 174; // Imagination Technologies META processor 143 | // architecture 144 | const MCST_ELBRUS = 175; // MCST Elbrus general purpose hardware architecture 145 | const ECOG16 = 176; // Cyan Technology eCOG16 family 146 | const CR16 = 177; // National Semiconductor CompactRISC CR16 16-bit 147 | // microprocessor 148 | const ETPU = 178; // Freescale Extended Time Processing Unit 149 | const SLE9X = 179; // Infineon Technologies SLE9X core 150 | const L10M = 180; // Intel L10M 151 | const K10M = 181; // Intel K10M 152 | const AARCH64 = 183; // ARM AArch64 153 | const AVR32 = 185; // Atmel Corporation 32-bit microprocessor family 154 | const STM8 = 186; // STMicroeletronics STM8 8-bit microcontroller 155 | const TILE64 = 187; // Tilera TILE64 multicore architecture family 156 | const TILEPRO = 188; // Tilera TILEPro multicore architecture family 157 | const CUDA = 190; // NVIDIA CUDA architecture 158 | const TILEGX = 191; // Tilera TILE-Gx multicore architecture family 159 | const CLOUDSHIELD = 192; // CloudShield architecture family 160 | const COREA_1ST = 193; // KIPO-KAIST Core-A 1st generation processor family 161 | const COREA_2ND = 194; // KIPO-KAIST Core-A 2nd generation processor family 162 | const ARC_COMPACT2 = 195; // Synopsys ARCompact V2 163 | const OPEN8 = 196; // Open8 8-bit RISC soft processor core 164 | const RL78 = 197; // Renesas RL78 family 165 | const VIDEOCORE5 = 198; // Broadcom VideoCore V processor 166 | const R78KOR = 199; // Renesas 78KOR family 167 | const DSC56800EX = 200; // Freescale 56800EX Digital Signal Controller (DSC) 168 | const BA1 = 201; // Beyond BA1 CPU architecture 169 | const BA2 = 202; // Beyond BA2 CPU architecture 170 | const XCORE = 203; // XMOS xCORE processor family 171 | const MCHP_PIC = 204; // Microchip 8-bit PIC(r) family 172 | const INTEL205 = 205; // Reserved by Intel 173 | const INTEL206 = 206; // Reserved by Intel 174 | const INTEL207 = 207; // Reserved by Intel 175 | const INTEL208 = 208; // Reserved by Intel 176 | const INTEL209 = 209; // Reserved by Intel 177 | const KM32 = 210; // KM211 KM32 32-bit processor 178 | const KMX32 = 211; // KM211 KMX32 32-bit processor 179 | const KMX16 = 212; // KM211 KMX16 16-bit processor 180 | const KMX8 = 213; // KM211 KMX8 8-bit processor 181 | const KVARC = 214; // KM211 KVARC processor 182 | const CDP = 215; // Paneve CDP architecture family 183 | const COGE = 216; // Cognitive Smart Memory Processor 184 | const COOL = 217; // iCelero CoolEngine 185 | const NORC = 218; // Nanoradio Optimized RISC 186 | const CSR_KALIMBA = 219; // CSR Kalimba architecture family 187 | const AMDGPU = 224; // AMD GPU architecture 188 | const RISCV = 243; // RISC-V 189 | const LANAI = 244; // Lanai 32-bit processor 190 | const BPF = 247; // Linux kernel bpf virtual machine 191 | 192 | // A request has been made to the maintainer of the official registry for 193 | // such numbers for an official value for WebAssembly. As soon as one is 194 | // allocated; this enum will be updated to use it. 195 | const WEBASSEMBLY = 0x4157; // WebAssembly architecture 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /src/header/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod elf_type; 2 | pub mod header; 3 | pub mod ident; 4 | pub mod machine; 5 | pub mod prog_header; 6 | pub mod sect_header; 7 | 8 | pub use self::elf_type::*; 9 | pub use self::header::ElfHeader; 10 | pub use self::ident::*; 11 | pub use self::machine::*; 12 | pub use self::prog_header::*; 13 | pub use self::sect_header::*; 14 | -------------------------------------------------------------------------------- /src/header/prog_header/flag.rs: -------------------------------------------------------------------------------- 1 | bitflags! { 2 | #[repr(C)] 3 | pub struct SegmentFlag: u32 { 4 | const X = 1; 5 | const W = 2; 6 | const R = 4; 7 | } 8 | } 9 | 10 | impl SegmentFlag { 11 | pub(crate) fn to_mprotect_flags(&self) -> ::util::Prot::Ty { 12 | use util::Prot::*; 13 | 14 | let table = &[ 15 | (SegmentFlag::X, Execute), 16 | #[cfg(unix)] 17 | (SegmentFlag::W, WriteOnly), 18 | (SegmentFlag::R, ReadOnly), 19 | (SegmentFlag::X | SegmentFlag::R, ReadExec), 20 | #[cfg(unix)] 21 | (SegmentFlag::X | SegmentFlag::W, WriteExec), 22 | (SegmentFlag::W | SegmentFlag::R, ReadWrite), 23 | ( 24 | SegmentFlag::X | SegmentFlag::R | SegmentFlag::W, 25 | ReadWriteExec, 26 | ), 27 | ]; 28 | 29 | table 30 | .iter() 31 | .filter_map(|&(f, v)| if *self == f { Some(v) } else { None }) 32 | .next() 33 | .unwrap_or(NoAccess) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/header/prog_header/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod flag; 2 | pub mod prog_header_type; 3 | 4 | #[derive(Debug, Clone)] 5 | pub enum ProgramHeaders { 6 | Header32(Vec), 7 | Header64(Vec), 8 | } 9 | 10 | #[repr(C)] 11 | #[derive(Debug, Copy, Clone)] 12 | pub struct ProgramHeader32 { 13 | pub prog_header_type: prog_header_type::ProgramHeaderType, 14 | pub offset: u32, 15 | pub vert_addr: u32, 16 | pub phys_addr: u32, 17 | pub file_size: u32, 18 | pub mem_size: u32, 19 | pub flags: flag::SegmentFlag, 20 | pub align: u32, 21 | } 22 | 23 | #[repr(C)] 24 | #[derive(Debug, Copy, Clone)] 25 | pub struct ProgramHeader64 { 26 | pub prog_header_type: prog_header_type::ProgramHeaderType, 27 | pub flags: flag::SegmentFlag, 28 | pub offset: u64, 29 | pub vert_addr: u64, 30 | pub phys_addr: u64, 31 | pub file_size: u64, 32 | pub mem_size: u64, 33 | pub align: u64, 34 | } 35 | -------------------------------------------------------------------------------- /src/header/prog_header/prog_header_type.rs: -------------------------------------------------------------------------------- 1 | cenums! { 2 | #[repr(C)] 3 | pub struct ProgramHeaderType: u32 { 4 | const NULL = 0; 5 | const LOADABLE = 1; 6 | const DYNAMIC_LINKING = 2; 7 | const INTERPRETER = 3; 8 | const NOTE = 4; 9 | const SHLIB = 5; 10 | const PROGRAM_HEADER = 6; 11 | const THREAD_LOCAL_STORAGE = 7; 12 | 13 | const GNU_EH_FRAME = 0x6474e550; 14 | const GNU_STACK = 0x6474e551; 15 | const GNU_RELRO = 0x6474e552; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/header/sect_header/flag.rs: -------------------------------------------------------------------------------- 1 | bitflags! { 2 | #[repr(C)] 3 | pub struct SectionFlag32: u32 { 4 | const WRITE = 0x1; 5 | const ALLOC = 0x2; 6 | const EXECINSTR = 0x4; 7 | } 8 | } 9 | 10 | bitflags! { 11 | #[repr(C)] 12 | pub struct SectionFlag64: u32 { 13 | const WRITE = 0x1; 14 | const ALLOC = 0x2; 15 | const EXECINSTR = 0x4; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/header/sect_header/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod flag; 2 | pub mod sect_header_type; 3 | 4 | pub use self::flag::SectionFlag32; 5 | pub use self::flag::SectionFlag64; 6 | pub use self::sect_header_type::SectionHeaderType; 7 | 8 | #[derive(Debug, Clone)] 9 | pub enum SectionHeaders { 10 | Header32(Vec), 11 | Header64(Vec), 12 | } 13 | 14 | #[repr(C)] 15 | #[derive(Debug, Copy, Clone)] 16 | pub struct SectionHeader32 { 17 | pub name_index: u32, 18 | pub sect_type: sect_header_type::SectionHeaderType, 19 | pub flags: flag::SectionFlag32, 20 | pub addr: u32, 21 | pub offset: u32, 22 | pub size: u32, 23 | pub link: u32, 24 | pub info: u32, 25 | pub addr_aligh: u32, 26 | pub entry_size: u32, 27 | } 28 | 29 | #[repr(C)] 30 | #[derive(Debug, Copy, Clone)] 31 | pub struct SectionHeader64 { 32 | pub name_index: u32, 33 | pub sect_type: sect_header_type::SectionHeaderType, 34 | pub flags: flag::SectionFlag64, 35 | pub addr: u64, 36 | pub offset: u64, 37 | pub size: u64, 38 | pub link: u32, 39 | pub info: u32, 40 | pub addr_aligh: u64, 41 | pub entry_size: u64, 42 | } 43 | -------------------------------------------------------------------------------- /src/header/sect_header/sect_header_type.rs: -------------------------------------------------------------------------------- 1 | cenums! { 2 | #[repr(C)] 3 | pub struct SectionHeaderType: u32 { 4 | const NULL = 0; // No associated section (inactive entry). 5 | const PROGBITS = 1; // Program-defined contents. 6 | const SYMBOL_TABLE = 2; // Symbol table. 7 | const STRING_TABLE = 3; // String table. 8 | const RELA = 4; // Relocation entries; explicit addends. 9 | const HASH = 5; // Symbol hash table. 10 | const DYNAMIC_LINKING = 6; // Information for dynamic linking. 11 | const NOTE = 7; // Information about the file. 12 | const NOBITS = 8; // Data occupies no space in the file. 13 | const REL = 9; // Relocation entries; no explicit addends. 14 | const SHLIB = 10; // Reserved. 15 | const DYNSYM = 11; // Symbol table. 16 | const INIT_ARRAY = 14; // Pointers to initialization functions. 17 | const FINI_ARRAY = 15; // Pointers to termination functions. 18 | const PREINIT_ARRAY = 16; // Pointers to pre-init functions. 19 | const GROUP = 17; // Section group. 20 | const SYMTAB_SHNDX = 18; // Indices for SHN_XINDEX entries. 21 | // Experimental support for SHT_RELR sections. For details, see proposal 22 | // at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg 23 | const RELR = 19; // Relocation entries; only offsets. 24 | const LOOS = 0x60000000; // Lowest operating system-specific type. 25 | // Android packed relocation section types. 26 | // https://android.googlesource.com/platform/bionic/+/6f12bfece5dcc01325e0abba56a46b1bcf991c69/tools/relocation_packer/src/elf_file.cc#37 27 | const ANDROID_REL = 0x60000001; 28 | const ANDROID_RELA = 0x60000002; 29 | const LLVM_ODRTAB = 0x6fff4c00; // LLVM ODR table. 30 | const LLVM_LINKER_OPTIONS = 0x6fff4c01; // LLVM Linker Options. 31 | const LLVM_CALL_GRAPH_PROFILE = 0x6fff4c02; // LLVM Call Graph Profile. 32 | 33 | // Android's experimental support for SHT_RELR sections. 34 | // https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#512 35 | const ANDROID_RELR = 0x6fffff00; // Relocation entries; only offsets. 36 | const GNU_ATTRIBUTES = 0x6ffffff5; // Object attributes. 37 | const GNU_HASH = 0x6ffffff6; // GNU-style hash table. 38 | const GNU_VERDEF = 0x6ffffffd; // GNU version definitions. 39 | const GNU_VERNEED = 0x6ffffffe; // GNU version references. 40 | const GNU_VERSYM = 0x6fffffff; // GNU symbol versions table. 41 | const HIOS = 0x6fffffff; // Highest operating system-specific type. 42 | const LOPROC = 0x70000000; // Lowest processor arch-specific type. 43 | 44 | // Fixme: All this is duplicated in MCSectionELF. Why?? 45 | // Exception Index table 46 | const ARM_EXIDX = 0x70000001; 47 | // BPABI DLL dynamic linking pre-emption map 48 | const ARM_PREEMPTMAP = 0x70000002; 49 | // Object file compatibility attributes 50 | const ARM_ATTRIBUTES = 0x70000003; 51 | const ARM_DEBUGOVERLAY = 0x70000004; 52 | const ARM_OVERLAYSECTION = 0x70000005; 53 | const HEX_ORDERED = 0x70000000; // Link editor is to sort the entries in 54 | // this section based on their sizes 55 | const X86_64_UNWIND = 0x70000001; // Unwind information 56 | const MIPS_REGINFO = 0x70000006; // Register usage information 57 | const MIPS_OPTIONS = 0x7000000d; // General options 58 | const MIPS_DWARF = 0x7000001e; // DWARF debugging section. 59 | const MIPS_ABIFLAGS = 0x7000002a; // ABI information. 60 | const HIPROC = 0x7fffffff; // Highest processor arch-specific type. 61 | const LOUSER = 0x80000000; // Lowest type reserved for applications. 62 | const HIUSER = 0xffffffff; // Highest type reserved for applications. 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate bitflags; 3 | 4 | #[macro_use] 5 | extern crate cenums; 6 | 7 | extern crate aligned_alloc; 8 | 9 | #[cfg(unix)] 10 | extern crate libc; 11 | 12 | #[cfg(windows)] 13 | extern crate winapi; 14 | 15 | pub mod file; 16 | pub mod header; 17 | pub mod loader; 18 | mod util; 19 | 20 | #[cfg(test)] 21 | mod tests { 22 | #[test] 23 | fn it_works() { 24 | assert_eq!(2 + 2, 4); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/loader/loader.rs: -------------------------------------------------------------------------------- 1 | use aligned_alloc; 2 | use file::ElfFile; 3 | use header::{ElfMagic, ElfType, ElfVersion, ProgramHeaders}; 4 | use std; 5 | use util::read_into_ptr; 6 | 7 | pub struct ElfLoader { 8 | elf_file: ElfFile, 9 | memory: Option<*mut u8>, 10 | } 11 | 12 | impl Drop for ElfLoader { 13 | fn drop(&mut self) { 14 | if let Some(ptr) = self.memory { 15 | unsafe { 16 | aligned_alloc::aligned_free(ptr as _); 17 | } 18 | } 19 | 20 | self.memory = None; 21 | } 22 | } 23 | 24 | impl ElfLoader { 25 | pub fn new(path: &str) -> Result { 26 | let res = ElfLoader { 27 | elf_file: ElfFile::new(path)?, 28 | memory: None, 29 | }; 30 | 31 | res.sanity_check(); 32 | 33 | Ok(res) 34 | } 35 | 36 | // TODO probably use failure? 37 | fn sanity_check(&self) { 38 | if self.elf_file.header.magics 39 | != [ 40 | ElfMagic::MAGIC0, 41 | ElfMagic::MAGIC1, 42 | ElfMagic::MAGIC2, 43 | ElfMagic::MAGIC3, 44 | ] || self.elf_file.header.elf_version != ElfVersion::CURRENT 45 | { 46 | panic!("Invalid Elf File"); 47 | } 48 | 49 | if self.elf_file.header.elf_type != ElfType::SHARED_OBJECT { 50 | panic!("Only PIE binaries are supported."); 51 | } 52 | } 53 | 54 | fn allocate_memory(&mut self) { 55 | if self.memory.is_some() { 56 | return; 57 | } 58 | 59 | macro_rules! max_addr { 60 | ($phdrs:expr) => { 61 | $phdrs 62 | .iter() 63 | .map(|&h| h.vert_addr + h.mem_size) 64 | .max() 65 | .unwrap() as usize 66 | }; 67 | } 68 | 69 | let max_addr = match self.elf_file.prog_headers { 70 | ProgramHeaders::Header32(ref phdrs) => max_addr!(phdrs), 71 | ProgramHeaders::Header64(ref phdrs) => max_addr!(phdrs), 72 | }; 73 | 74 | const PAGE_SIZE: usize = 0x1000; 75 | 76 | // No virtual address... 77 | let memory = aligned_alloc::aligned_alloc(max_addr, PAGE_SIZE) as *mut u8; 78 | 79 | self.memory = Some(memory); 80 | } 81 | 82 | fn apply_mprotect(&mut self) { 83 | self.allocate_memory(); 84 | 85 | macro_rules! mprotect { 86 | ($phdrs:expr) => { 87 | for phdr in $phdrs { 88 | unsafe { 89 | ::util::mprotect( 90 | self.memory.unwrap().add(phdr.offset as usize), 91 | phdr.mem_size as usize, 92 | phdr.flags.to_mprotect_flags(), 93 | ); 94 | } 95 | } 96 | }; 97 | } 98 | 99 | match self.elf_file.prog_headers { 100 | ProgramHeaders::Header64(ref phdrs) => mprotect!(phdrs), 101 | ProgramHeaders::Header32(ref phdrs) => mprotect!(phdrs), 102 | } 103 | } 104 | 105 | pub fn get_entry_addr(&self) -> *mut u8 { 106 | unsafe { 107 | self.memory.unwrap().add(self.elf_file.header.entry) 108 | } 109 | } 110 | 111 | pub fn load_memory(&mut self) { 112 | self.allocate_memory(); 113 | 114 | macro_rules! load_memory { 115 | ($phdrs:expr) => { 116 | for phdr in $phdrs { 117 | unsafe { 118 | read_into_ptr( 119 | &mut self.elf_file.file, 120 | self.memory.unwrap().add(phdr.vert_addr as usize), 121 | phdr.file_size as usize, 122 | phdr.offset as u64, 123 | ).unwrap(); 124 | } 125 | } 126 | }; 127 | } 128 | 129 | match self.elf_file.prog_headers { 130 | ProgramHeaders::Header64(ref phdrs) => load_memory!(phdrs), 131 | ProgramHeaders::Header32(ref phdrs) => load_memory!(phdrs), 132 | } 133 | 134 | self.apply_mprotect(); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/loader/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod loader; 2 | pub use self::loader::*; 3 | -------------------------------------------------------------------------------- /src/util/mod.rs: -------------------------------------------------------------------------------- 1 | use std; 2 | use std::fs::File; 3 | use std::io::{Read, Seek, SeekFrom}; 4 | use std::mem; 5 | 6 | /// Copied from https://github.com/quininer/memsec 7 | /// Prot enum. 8 | #[cfg(unix)] 9 | #[allow(non_snake_case, non_upper_case_globals, unused)] 10 | pub mod Prot { 11 | pub use libc::c_int as Ty; 12 | 13 | pub const NoAccess: Ty = ::libc::PROT_NONE; 14 | pub const ReadOnly: Ty = ::libc::PROT_READ; 15 | pub const WriteOnly: Ty = ::libc::PROT_WRITE; 16 | pub const ReadWrite: Ty = (::libc::PROT_READ | ::libc::PROT_WRITE); 17 | pub const Execute: Ty = ::libc::PROT_EXEC; 18 | pub const ReadExec: Ty = (::libc::PROT_READ | ::libc::PROT_EXEC); 19 | pub const WriteExec: Ty = (::libc::PROT_WRITE | ::libc::PROT_EXEC); 20 | pub const ReadWriteExec: Ty = (::libc::PROT_READ | ::libc::PROT_WRITE | ::libc::PROT_EXEC); 21 | } 22 | 23 | /// Copied from https://github.com/quininer/memsec 24 | /// Prot enum. 25 | #[cfg(windows)] 26 | #[allow(non_snake_case, non_upper_case_globals, unused)] 27 | pub mod Prot { 28 | pub use winapi::shared::minwindef::DWORD as Ty; 29 | 30 | pub const NoAccess: Ty = ::winapi::um::winnt::PAGE_NOACCESS; 31 | pub const ReadOnly: Ty = ::winapi::um::winnt::PAGE_READONLY; 32 | pub const ReadWrite: Ty = ::winapi::um::winnt::PAGE_READWRITE; 33 | pub const WriteCopy: Ty = ::winapi::um::winnt::PAGE_WRITECOPY; 34 | pub const Execute: Ty = ::winapi::um::winnt::PAGE_EXECUTE; 35 | pub const ReadExec: Ty = ::winapi::um::winnt::PAGE_EXECUTE_READ; 36 | pub const ReadWriteExec: Ty = ::winapi::um::winnt::PAGE_EXECUTE_READWRITE; 37 | pub const WriteCopyExec: Ty = ::winapi::um::winnt::PAGE_EXECUTE_WRITECOPY; 38 | pub const Guard: Ty = ::winapi::um::winnt::PAGE_GUARD; 39 | pub const NoCache: Ty = ::winapi::um::winnt::PAGE_NOCACHE; 40 | pub const WriteCombine: Ty = ::winapi::um::winnt::PAGE_WRITECOMBINE; 41 | pub const RevertToFileMap: Ty = ::winapi::um::winnt::PAGE_REVERT_TO_FILE_MAP; 42 | pub const TargetsInvalid: Ty = ::winapi::um::winnt::PAGE_TARGETS_INVALID; 43 | pub const TargetsNoUpdate: Ty = ::winapi::um::winnt::PAGE_TARGETS_NO_UPDATE; 44 | } 45 | 46 | /// Unix `mprotect`. 47 | /// Copied from https://github.com/quininer/memsec 48 | #[cfg(unix)] 49 | #[inline] 50 | pub unsafe fn mprotect(ptr: *mut u8, len: usize, prot: Prot::Ty) -> bool { 51 | ::libc::mprotect(ptr as *mut ::libc::c_void, len, prot as ::libc::c_int) == 0 52 | } 53 | 54 | /// Windows `VirtualProtect`. 55 | /// Copied from https://github.com/quininer/memsec 56 | #[cfg(windows)] 57 | #[inline] 58 | pub unsafe fn mprotect(ptr: *mut u8, len: usize, prot: Prot::Ty) -> bool { 59 | let mut old = mem::uninitialized(); 60 | ::winapi::um::memoryapi::VirtualProtect( 61 | ptr as ::winapi::shared::minwindef::LPVOID, 62 | len as ::winapi::shared::basetsd::SIZE_T, 63 | prot as ::winapi::shared::minwindef::DWORD, 64 | &mut old as ::winapi::shared::minwindef::PDWORD, 65 | ) != 0 66 | } 67 | 68 | pub unsafe fn read_into_ptr( 69 | file: &mut File, 70 | ptr: *mut u8, 71 | size: usize, 72 | offset: u64, 73 | ) -> Result<(), std::io::Error> { 74 | let slice = std::slice::from_raw_parts_mut(ptr, size); 75 | file.seek(SeekFrom::Start(offset))?; 76 | file.read_exact(slice)?; 77 | 78 | Ok(()) 79 | } 80 | --------------------------------------------------------------------------------