diff --git a/.gitignore b/.gitignore index 19712ce..4df18b2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ # Generated by Cargo # will have compiled files and executables /target/ - +sample_elf # These are backup files generated by rustfmt **/*.rs.bk diff --git a/README.md b/README.md index e2f00a5..e187f07 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,11 @@ Rust Cli - Rust command line util +ELF +* https://fasterthanli.me/series/making-our-own-executable-packer/part-1 + + +ELF format: +![](https://playsecurity.org/getdoc/3969_4D1E689A0A238F3244FA46D98AF1C404/elf64-file-header.a08515d63bdb6e35.safe.svg) + + diff --git a/src/cmd_elf.rs b/src/cmd_elf.rs new file mode 100644 index 0000000..ef0d592 --- /dev/null +++ b/src/cmd_elf.rs @@ -0,0 +1,89 @@ +use std::io::Read; +use std::fs::File; +use clap::{ ArgMatches, SubCommand, App, Arg }; +use crate::cmd::{ Command, CommandError }; + +pub struct CommandElf; + +// https://fasterthanli.me/series/making-our-own-executable-packer/part-1 +impl Command for CommandElf { + + fn name(&self) -> &str { "elf" } + + fn subcommand<'a>(&self) -> App<'a, 'a> { + SubCommand::with_name(self.name()).about("ELF subcommand") + .arg(Arg::with_name("FILE").required(true).index(1).help("ELF file")) + } + + fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError { + let file_name = sub_arg_matches.value_of("FILE").unwrap(); + let mut file = File::open(file_name)?; + let mut buf = vec![]; + let len = file.read_to_end(&mut buf)?; + + information!("File: {}, length: {}", file_name, len); + + let elf_magic_number = buf.drain(0..4).collect::>(); + if vec![0x7f, 0x45/*'E'*/, 0x4c/*'L'*/, 0x46/*'F'*/] != elf_magic_number { + failure!("File not ELF file: {}", file_name); + return Ok(()); + } + let class = buf.remove(0); + if class == 0x01 || class == 0x02 { + information!("File class is: {}", iff!(class == 0x01, "x86", "x64")); + } else { + failure!("File is not x86 or x64: {}", file_name); + return Ok(()); + } + let endian = buf.remove(0); + if endian == 0x01 || endian == 0x02 { + information!("File endian is: {}", iff!(class == 0x01, "LittleEndian", "BigEndian")); + } else { + failure!("File is not Little or Big Endian: {}", file_name); + return Ok(()); + } + let version = buf.remove(0); + information!("File version: {}", version); + let abi = buf.remove(0); + information!("File ABI: {}", abi); + let padding = buf.drain(0..8).collect::>(); + information!("File padding: {:?}", padding); + let ty = u16::from_le_bytes([buf.remove(0), buf.remove(0)]); + information!("File type: {}", match ty { + 0x0 => "NONE".into(), + 0x1 => "REL".into(), + 0x2 => "EXEC".into(), + 0x3 => "DYN".into(), + 0x4 => "CORE".into(), + _ => format!("unknown: {}", ty), + }); + let machine = u16::from_le_bytes([buf.remove(0), buf.remove(0)]); + information!("File machine: {}", match machine { + 0x03 => "x86".into(), + 0x3e => "x86-64".into(), + _ => format!("unknown: {}", machine), + }); + let encore_version = u32::from_le_bytes([buf.remove(0), buf.remove(0), buf.remove(0), buf.remove(0)]); + information!("File encore version: {}", encore_version); + let entry_point = u64::from_le_bytes([buf.remove(0), buf.remove(0), buf.remove(0), buf.remove(0), + buf.remove(0), buf.remove(0), buf.remove(0), buf.remove(0)]); + information!("File entry point: {}", entry_point); + let table_offset_first_program_header_entry = u64::from_le_bytes([buf.remove(0), buf.remove(0), buf.remove(0), buf.remove(0), + buf.remove(0), buf.remove(0), buf.remove(0), buf.remove(0)]); + information!("File table offset fist program header entry: {}", table_offset_first_program_header_entry); + let table_offset_first_section_header_entry = u64::from_le_bytes([buf.remove(0), buf.remove(0), buf.remove(0), buf.remove(0), + buf.remove(0), buf.remove(0), buf.remove(0), buf.remove(0)]); + information!("File table offset fist section header entry: {}", table_offset_first_section_header_entry); + let flags = u32::from_le_bytes([buf.remove(0), buf.remove(0), buf.remove(0), buf.remove(0)]); + information!("File flags: {}", flags); + let header_size = u16::from_le_bytes([buf.remove(0), buf.remove(0)]); + information!("File header size: {}", header_size); + let entry_size = u16::from_le_bytes([buf.remove(0), buf.remove(0)]); + information!("File entry size: {}", entry_size); + let number_of_entries = u16::from_le_bytes([buf.remove(0), buf.remove(0)]); + information!("File number of entries: {}", number_of_entries); + + + Ok(()) + } +} diff --git a/src/main.rs b/src/main.rs index ff9ceb0..d3ecde4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,19 @@ +#[macro_use] extern crate rust_util; + use clap::App; mod cmd; +mod cmd_elf; mod cmd_show; mod cmd_default; -use cmd::{ Command, CommandError, }; -use cmd_show::CommandShow; +use cmd::{ Command, CommandError }; use cmd_default::CommandDefault; fn main() -> CommandError { let commands: Vec> = vec![ - Box::new(CommandShow), + Box::new(cmd_elf::CommandElf), + Box::new(cmd_show::CommandShow), ]; let mut app = App::new(env!("CARGO_PKG_NAME")) .version(env!("CARGO_PKG_VERSION"))