Working COFF dump
This commit is contained in:
parent
a3bb5bc81b
commit
fc57b4ef80
|
@ -1,2 +1,3 @@
|
|||
imgread
|
||||
.DS_Store
|
||||
target
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "redox_termios"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "termion"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "we32as"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "we32dis"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
|
||||
"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
|
||||
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
||||
"checksum libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)" = "023a4cd09b2ff695f9734c1934145a315594b7986398496841c7031a5a1bbdbd"
|
||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||
"checksum redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)" = "52ee9a534dc1301776eff45b4fa92d2c39b1d8c3d3357e6eb593e0d795506fc2"
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
||||
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
||||
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
||||
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
@ -0,0 +1,6 @@
|
|||
[workspace]
|
||||
|
||||
members = [
|
||||
"we32dis",
|
||||
"we32as",
|
||||
]
|
|
@ -2,10 +2,14 @@
|
|||
/// WE32000 COFF File Parsing and Utilities
|
||||
///
|
||||
|
||||
use std::str;
|
||||
use std::str::Utf8Error;
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
use std::io;
|
||||
use std::io::{Read, Seek, SeekFrom};
|
||||
use std::marker::PhantomData;
|
||||
use crate::errors::{CoffError, Result};
|
||||
|
||||
use chrono::prelude::*;
|
||||
use chrono::TimeZone;
|
||||
|
@ -18,8 +22,11 @@ const MAGIC_WE32K: u16 = 0x170;
|
|||
// WE32000 with transfer vector
|
||||
const MAGIC_WE32K_TV: u16 = 0x171;
|
||||
|
||||
// The optional header (if present) is 28 bytes long
|
||||
const OPT_HEADER_SIZE: u16 = 0x1c;
|
||||
// Size of the file header
|
||||
const FILE_HEADER_SIZE: u16 = 20;
|
||||
|
||||
// Length of old COFF version symbol names
|
||||
const SYM_NAME_LEN: usize = 8;
|
||||
|
||||
bitflags! {
|
||||
pub struct Flags: u16 {
|
||||
|
@ -50,8 +57,6 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub struct FileHeader {
|
||||
pub magic: u16,
|
||||
pub section_count: u16,
|
||||
|
@ -62,6 +67,27 @@ pub struct FileHeader {
|
|||
pub flags: Flags,
|
||||
}
|
||||
|
||||
impl FileHeader {
|
||||
|
||||
///
|
||||
/// Read a FileHeader from the current cursor position.
|
||||
///
|
||||
|
||||
pub fn read(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
|
||||
let header = FileHeader {
|
||||
magic: cursor.read_u16::<BigEndian>()?,
|
||||
section_count: cursor.read_u16::<BigEndian>()?,
|
||||
timestamp: cursor.read_u32::<BigEndian>()?,
|
||||
symbols_pointer: cursor.read_u32::<BigEndian>()?,
|
||||
symbol_count: cursor.read_u32::<BigEndian>()?,
|
||||
opt_header: cursor.read_u16::<BigEndian>()?,
|
||||
flags: Flags::from_bits_truncate(cursor.read_u16::<BigEndian>()?),
|
||||
};
|
||||
|
||||
Ok(header)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for FileHeader {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut desc = String::new();
|
||||
|
@ -90,7 +116,6 @@ impl fmt::Debug for FileHeader {
|
|||
desc.push_str(", with relocation info");
|
||||
}
|
||||
|
||||
|
||||
write!(f, "{}", desc)
|
||||
}
|
||||
}
|
||||
|
@ -107,6 +132,23 @@ pub struct OptionalHeader {
|
|||
pub data_start: u32,
|
||||
}
|
||||
|
||||
impl OptionalHeader {
|
||||
pub fn read(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
|
||||
let header = OptionalHeader {
|
||||
magic: cursor.read_u16::<BigEndian>()?,
|
||||
version_stamp: cursor.read_u16::<BigEndian>()?,
|
||||
text_size: cursor.read_u32::<BigEndian>()?,
|
||||
dsize: cursor.read_u32::<BigEndian>()?,
|
||||
bsize: cursor.read_u32::<BigEndian>()?,
|
||||
entry_point: cursor.read_u32::<BigEndian>()?,
|
||||
text_start: cursor.read_u32::<BigEndian>()?,
|
||||
data_start: cursor.read_u32::<BigEndian>()?
|
||||
};
|
||||
|
||||
Ok(header)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SectionHeader {
|
||||
pub name: [u8; 8],
|
||||
pub paddr: u32,
|
||||
|
@ -120,92 +162,145 @@ pub struct SectionHeader {
|
|||
pub flags: u32,
|
||||
}
|
||||
|
||||
impl SectionHeader {
|
||||
pub fn read(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
|
||||
let mut name: [u8; 8] = [0; 8];
|
||||
cursor.read_exact(&mut name)?;
|
||||
|
||||
let header = SectionHeader {
|
||||
name: name,
|
||||
paddr: cursor.read_u32::<BigEndian>()?,
|
||||
vaddr: cursor.read_u32::<BigEndian>()?,
|
||||
size: cursor.read_u32::<BigEndian>()?,
|
||||
scnptr: cursor.read_u32::<BigEndian>()?,
|
||||
relptr: cursor.read_u32::<BigEndian>()?,
|
||||
lnnoptr: cursor.read_u32::<BigEndian>()?,
|
||||
nreloc: cursor.read_u16::<BigEndian>()?,
|
||||
nlnno: cursor.read_u16::<BigEndian>()?,
|
||||
flags: cursor.read_u32::<BigEndian>()?,
|
||||
};
|
||||
|
||||
Ok(header)
|
||||
}
|
||||
}
|
||||
|
||||
/// Representation of a Relocation Table Entry
|
||||
pub struct RelocationEntry {
|
||||
pub vaddr: u32,
|
||||
pub symndx: u32,
|
||||
pub rtype: u16,
|
||||
}
|
||||
|
||||
pub struct Section {
|
||||
pub header: SectionHeader,
|
||||
pub relocation_entries: Vec<RelocationEntry>,
|
||||
/// Representation of a Symbol Table Entry
|
||||
pub struct SymbolEntry {
|
||||
pub n_name: [u8; SYM_NAME_LEN],
|
||||
pub n_zeroes: u32,
|
||||
pub n_offset: u32,
|
||||
pub n_value: u32,
|
||||
pub n_scnum: i16,
|
||||
pub n_type: u16,
|
||||
pub n_sclass: u8,
|
||||
pub n_numaux: u8,
|
||||
pub is_aux: bool,
|
||||
}
|
||||
|
||||
pub struct MetaData {
|
||||
pub struct StringTable<'s> {
|
||||
pub data: Vec<u8>,
|
||||
pub data_size: u32,
|
||||
pub string_count: u32,
|
||||
phantom: PhantomData<&'s str>,
|
||||
}
|
||||
|
||||
impl<'s> StringTable<'s> {
|
||||
pub fn read(cursor: &mut Cursor<&[u8]>) -> io::Result<Self> {
|
||||
let mut data: Vec<u8> = vec!();
|
||||
// The first four bytes of data are ALWAYS zeroed.
|
||||
let mut pad: Vec<u8> = vec!(0, 0, 0, 0);
|
||||
data.append(&mut pad);
|
||||
// ... and therefore, the index is always initialized to 4.
|
||||
let mut index: u32 = 4;
|
||||
let mut string_count: u32 = 0;
|
||||
let data_size = cursor.read_u32::<BigEndian>()?;
|
||||
|
||||
while index < data_size {
|
||||
let c = cursor.read_u8()?;
|
||||
data.push(c);
|
||||
if c == 0 {
|
||||
string_count += 1;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
|
||||
let table = StringTable {
|
||||
data,
|
||||
data_size,
|
||||
string_count,
|
||||
phantom: PhantomData,
|
||||
};
|
||||
|
||||
Ok(table)
|
||||
}
|
||||
|
||||
pub fn string_at(&'s self, index: u32) -> std::result::Result<&'s str, Utf8Error> {
|
||||
let start = index as usize;
|
||||
|
||||
// Index into the vector at the appropriate location, and then
|
||||
// find the first nul.
|
||||
let nul = self.data[start.. ].iter()
|
||||
.position( |&c| c == b'\0')
|
||||
.unwrap_or(self.data.len() - start);
|
||||
|
||||
let end = start + nul;
|
||||
|
||||
let s = &self.data[start..end];
|
||||
|
||||
str::from_utf8(&s)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Section {
|
||||
pub header: SectionHeader,
|
||||
pub relocations: Vec<RelocationEntry>,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
pub struct MetaData<'s> {
|
||||
pub header: FileHeader,
|
||||
pub timestamp: DateTime<Utc>,
|
||||
pub opt_header: Option<OptionalHeader>,
|
||||
pub sections: Vec<Section>,
|
||||
pub symbols: Vec<SymbolEntry>,
|
||||
pub strings: StringTable<'s>,
|
||||
}
|
||||
|
||||
impl MetaData {
|
||||
pub fn read(cursor: &mut Cursor<&[u8]>) -> io::Result<MetaData> {
|
||||
// FIRST PASS: Pull out File Header, Optional Header (if any),
|
||||
// and Section Headers
|
||||
impl<'s> MetaData<'s> {
|
||||
|
||||
cursor.seek(SeekFrom::Start(0))?;
|
||||
///
|
||||
/// Read in and destructure a WE32100 COFF file.
|
||||
///
|
||||
|
||||
let header = FileHeader {
|
||||
magic: cursor.read_u16::<BigEndian>()?,
|
||||
section_count: cursor.read_u16::<BigEndian>()?,
|
||||
timestamp: cursor.read_u32::<BigEndian>()?,
|
||||
symbols_pointer: cursor.read_u32::<BigEndian>()?,
|
||||
symbol_count: cursor.read_u32::<BigEndian>()?,
|
||||
opt_header: cursor.read_u16::<BigEndian>()?,
|
||||
flags: Flags::from_bits_truncate(cursor.read_u16::<BigEndian>()?),
|
||||
};
|
||||
|
||||
let opt_header = if header.opt_header == OPT_HEADER_SIZE {
|
||||
Some(
|
||||
OptionalHeader {
|
||||
magic: cursor.read_u16::<BigEndian>()?,
|
||||
version_stamp: cursor.read_u16::<BigEndian>()?,
|
||||
text_size: cursor.read_u32::<BigEndian>()?,
|
||||
dsize: cursor.read_u32::<BigEndian>()?,
|
||||
bsize: cursor.read_u32::<BigEndian>()?,
|
||||
entry_point: cursor.read_u32::<BigEndian>()?,
|
||||
text_start: cursor.read_u32::<BigEndian>()?,
|
||||
data_start: cursor.read_u32::<BigEndian>()?
|
||||
}
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
fn bad_metadata(header: &FileHeader) -> bool {
|
||||
!(header.magic == MAGIC_WE32K || header.magic == MAGIC_WE32K_TV)
|
||||
}
|
||||
|
||||
fn read_sections(file_header: &FileHeader, cursor: &mut Cursor<&[u8]>) -> io::Result<Vec<Section>> {
|
||||
let mut section_headers: Vec<SectionHeader> = vec!();
|
||||
|
||||
for _ in 0..header.section_count {
|
||||
let mut name: [u8; 8] = [0; 8];
|
||||
cursor.read_exact(&mut name)?;
|
||||
|
||||
let sec_header = SectionHeader {
|
||||
name: name,
|
||||
paddr: cursor.read_u32::<BigEndian>()?,
|
||||
vaddr: cursor.read_u32::<BigEndian>()?,
|
||||
size: cursor.read_u32::<BigEndian>()?,
|
||||
scnptr: cursor.read_u32::<BigEndian>()?,
|
||||
relptr: cursor.read_u32::<BigEndian>()?,
|
||||
lnnoptr: cursor.read_u32::<BigEndian>()?,
|
||||
nreloc: cursor.read_u16::<BigEndian>()?,
|
||||
nlnno: cursor.read_u16::<BigEndian>()?,
|
||||
flags: cursor.read_u32::<BigEndian>()?,
|
||||
};
|
||||
|
||||
section_headers.push(sec_header);
|
||||
// Read the section headers
|
||||
for _ in 0..file_header.section_count {
|
||||
section_headers.push(SectionHeader::read(cursor)?);
|
||||
}
|
||||
|
||||
// SECOND PASS: Now that we have decoded the section headers,
|
||||
// let's decode the section relocation tables.
|
||||
|
||||
// Build up the section structures
|
||||
let mut sections: Vec<Section> = vec!();
|
||||
|
||||
for header in section_headers {
|
||||
let mut relocation_entries: Vec<RelocationEntry> = vec!();
|
||||
let mut relocations: Vec<RelocationEntry> = vec!();
|
||||
let mut data: Vec<u8> = vec!();
|
||||
|
||||
// Get relocation information
|
||||
if header.nreloc > 0 {
|
||||
let offset = header.relptr;
|
||||
|
||||
cursor.seek(SeekFrom::Start(u64::from(offset)))?;
|
||||
cursor.seek(SeekFrom::Start(u64::from(header.relptr)))?;
|
||||
|
||||
for _ in 0..header.nreloc {
|
||||
let entry = RelocationEntry {
|
||||
|
@ -213,21 +308,142 @@ impl MetaData {
|
|||
symndx: cursor.read_u32::<BigEndian>()?,
|
||||
rtype: cursor.read_u16::<BigEndian>()?,
|
||||
};
|
||||
|
||||
relocation_entries.push(entry);
|
||||
relocations.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
// Get data
|
||||
if header.size > 0 {
|
||||
cursor.seek(SeekFrom::Start(u64::from(header.scnptr)))?;
|
||||
|
||||
for _ in 0..header.size {
|
||||
data.push(cursor.read_u8()?);
|
||||
}
|
||||
}
|
||||
|
||||
// Done with this section.
|
||||
let section = Section {
|
||||
header,
|
||||
relocation_entries,
|
||||
relocations,
|
||||
data,
|
||||
};
|
||||
|
||||
sections.push(section);
|
||||
}
|
||||
|
||||
// FINAL TOUCHUPS
|
||||
Ok(sections)
|
||||
}
|
||||
|
||||
fn read_symbol_table(header: &FileHeader, cursor: &mut Cursor<&[u8]>) -> io::Result<Vec<SymbolEntry>> {
|
||||
let mut symbols: Vec<SymbolEntry> = vec!();
|
||||
|
||||
if header.symbol_count > 0 {
|
||||
cursor.seek(SeekFrom::Start(u64::from(header.symbols_pointer)))?;
|
||||
|
||||
// Keep track of which symbols are aux symbols, and which
|
||||
// are not, by tagging them with metadata.
|
||||
let mut is_aux = false;
|
||||
let mut aux_index: u8 = 0;
|
||||
|
||||
for _ in 0..header.symbol_count {
|
||||
let mut name: [u8; SYM_NAME_LEN] = [0; SYM_NAME_LEN];
|
||||
|
||||
cursor.read_exact(&mut name)?;
|
||||
|
||||
let mut zeroes_array: [u8; 4] = [0; 4];
|
||||
let mut offset_array: [u8; 4] = [0; 4];
|
||||
|
||||
zeroes_array.clone_from_slice(&name[0..4]);
|
||||
offset_array.clone_from_slice(&name[4..]);
|
||||
|
||||
let symbol_entry = SymbolEntry {
|
||||
n_name: name,
|
||||
n_zeroes: unsafe { std::mem::transmute::<[u8; 4], u32>(zeroes_array) }.to_be().into(),
|
||||
n_offset: unsafe { std::mem::transmute::<[u8; 4], u32>(offset_array) }.to_be().into(),
|
||||
n_value: cursor.read_u32::<BigEndian>()?,
|
||||
n_scnum: cursor.read_i16::<BigEndian>()?,
|
||||
n_type: cursor.read_u16::<BigEndian>()?,
|
||||
n_sclass: cursor.read_u8()?,
|
||||
n_numaux: cursor.read_u8()?,
|
||||
is_aux: is_aux,
|
||||
};
|
||||
|
||||
// If we just read a numaux > 0, then the next symbol
|
||||
// we read will be an aux symbol, down to the last
|
||||
// one.
|
||||
|
||||
if is_aux {
|
||||
aux_index -= 1;
|
||||
if aux_index == 0 {
|
||||
is_aux = false;
|
||||
}
|
||||
}
|
||||
|
||||
if symbol_entry.n_numaux > 0 {
|
||||
is_aux = true;
|
||||
aux_index = symbol_entry.n_numaux;
|
||||
}
|
||||
|
||||
symbols.push(symbol_entry);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(symbols)
|
||||
}
|
||||
|
||||
pub fn read(buf: &[u8]) -> Result<Self> {
|
||||
let mut cursor = Cursor::new(buf);
|
||||
|
||||
// Determine if we're parsing a linked executable
|
||||
// or an object file.
|
||||
|
||||
// Read the file header.
|
||||
let header = match FileHeader::read(&mut cursor) {
|
||||
Ok(h) => {
|
||||
if MetaData::bad_metadata(&h) {
|
||||
return Err(CoffError::BadFileHeader)
|
||||
} else {
|
||||
h
|
||||
}
|
||||
},
|
||||
Err(_) => return Err(CoffError::BadFileHeader)
|
||||
};
|
||||
|
||||
// If an optional header is indicated in the file header, read
|
||||
// it.
|
||||
let opt_header = if header.opt_header > 0 {
|
||||
match OptionalHeader::read(&mut cursor) {
|
||||
Ok(h) => Some(h),
|
||||
Err(_) => return Err(CoffError::BadOptionalHeader)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Now we have to seek to the sections area.
|
||||
if let Err(_) = cursor.seek(SeekFrom::Start(u64::from(FILE_HEADER_SIZE + header.opt_header))) {
|
||||
return Err(CoffError::BadSections)
|
||||
}
|
||||
|
||||
// Read sections
|
||||
let sections = match MetaData::read_sections(&header, &mut cursor) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err(CoffError::BadSections)
|
||||
};
|
||||
|
||||
// Load symbols
|
||||
let symbols = match MetaData::read_symbol_table(&header, &mut cursor) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err(CoffError::BadSymbols)
|
||||
};
|
||||
|
||||
// The cursor is now at the correct position to read string entries.
|
||||
let strings = match StringTable::read(&mut cursor) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err(CoffError::BadStrings)
|
||||
};
|
||||
|
||||
// Finally, destructure the timestamp
|
||||
let timestamp = Utc.timestamp(i64::from(header.timestamp), 0);
|
||||
|
||||
let metadata = MetaData {
|
||||
|
@ -235,6 +451,8 @@ impl MetaData {
|
|||
timestamp,
|
||||
opt_header,
|
||||
sections,
|
||||
symbols,
|
||||
strings,
|
||||
};
|
||||
|
||||
Ok(metadata)
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
use std::error;
|
||||
use std::fmt;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, CoffError>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CoffError {
|
||||
BadFileHeader,
|
||||
BadOptionalHeader,
|
||||
BadSections,
|
||||
BadSymbols,
|
||||
BadStrings,
|
||||
}
|
||||
|
||||
impl fmt::Display for CoffError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
CoffError::BadFileHeader => write!(f, "bad file header"),
|
||||
CoffError::BadOptionalHeader => write!(f, "bad optional header"),
|
||||
CoffError::BadSections => write!(f, "bad section headers"),
|
||||
CoffError::BadSymbols => write!(f, "bad symbols table"),
|
||||
CoffError::BadStrings => write!(f, "bad strings table"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for CoffError {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
CoffError::BadFileHeader => "bad file header",
|
||||
CoffError::BadOptionalHeader => "bad file header",
|
||||
CoffError::BadSections => "bad section headers",
|
||||
CoffError::BadSymbols => "bad symbols table",
|
||||
CoffError::BadStrings => "bad strings table",
|
||||
}
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
None
|
||||
}
|
||||
}
|
|
@ -6,13 +6,13 @@ use std::fs::File;
|
|||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
use std::vec::Vec;
|
||||
use std::io::Cursor;
|
||||
use std::str;
|
||||
|
||||
use clap::{Arg, App};
|
||||
|
||||
use crate::coff::*;
|
||||
use crate::coff::{MetaData, SectionHeader};
|
||||
|
||||
mod errors;
|
||||
mod coff;
|
||||
|
||||
fn name(buf: &[u8]) -> Result<&str, std::str::Utf8Error> {
|
||||
|
@ -21,61 +21,126 @@ fn name(buf: &[u8]) -> Result<&str, std::str::Utf8Error> {
|
|||
}
|
||||
|
||||
fn disassemble(buf: &[u8]) {
|
||||
let mut cursor = Cursor::new(buf);
|
||||
match MetaData::read(buf) {
|
||||
Ok(metadata) => {
|
||||
println!("File Header:");
|
||||
println!(" {:?}", metadata.header);
|
||||
println!(" Magic Number: 0x{:04x}", metadata.header.magic);
|
||||
println!(" # Sections: {}", metadata.header.section_count);
|
||||
println!(" Date: {}", metadata.timestamp.to_rfc2822());
|
||||
println!(" Symbols Ptr: 0x{:x}", metadata.header.symbols_pointer);
|
||||
println!(" Symbol Count: {}", metadata.header.symbol_count);
|
||||
println!(" Opt Hdr: {:?}", metadata.header.opt_header == 0x1c);
|
||||
println!(" Flags: 0x{:04x}", metadata.header.flags);
|
||||
|
||||
if let Ok(metadata) = MetaData::read(&mut cursor) {
|
||||
println!("File Header:");
|
||||
println!(" {:?}", metadata.header);
|
||||
println!(" Magic Number: 0x{:04x}", metadata.header.magic);
|
||||
println!(" # Sections: {}", metadata.header.section_count);
|
||||
println!(" Date: {}", metadata.timestamp.to_rfc2822());
|
||||
println!(" Symbols Ptr: 0x{:x}", metadata.header.symbols_pointer);
|
||||
println!(" Symbol Count: {}", metadata.header.symbol_count);
|
||||
println!(" Opt Hdr: {:?}", metadata.header.opt_header == 0x1c);
|
||||
println!(" Flags: 0x{:04x}", metadata.header.flags);
|
||||
if let Some(opt_header) = metadata.opt_header {
|
||||
println!();
|
||||
println!("Optional Header:");
|
||||
println!(" Magic Number: 0x{:04x}", opt_header.magic);
|
||||
println!(" Version Stamp: 0x{:04x}", opt_header.version_stamp);
|
||||
println!(" Text Size: 0x{:x}", opt_header.text_size);
|
||||
println!(" dsize: 0x{:x}", opt_header.dsize);
|
||||
println!(" bsize: 0x{:x}", opt_header.bsize);
|
||||
println!(" Entry Point: 0x{:x}", opt_header.entry_point);
|
||||
println!(" Text Start: 0x{:x}", opt_header.text_start);
|
||||
println!(" Data Start: 0x{:x}", opt_header.data_start);
|
||||
}
|
||||
|
||||
if let Some(opt_header) = metadata.opt_header {
|
||||
println!();
|
||||
println!("Optional Header:");
|
||||
println!(" Magic Number: 0x{:04x}", opt_header.magic);
|
||||
println!(" Version Stamp: 0x{:04x}", opt_header.version_stamp);
|
||||
println!(" Text Size: 0x{:x}", opt_header.text_size);
|
||||
println!(" dsize: 0x{:x}", opt_header.dsize);
|
||||
println!(" bsize: 0x{:x}", opt_header.bsize);
|
||||
println!(" Entry Point: 0x{:x}", opt_header.entry_point);
|
||||
println!(" Text Start: 0x{:x}", opt_header.text_start);
|
||||
println!(" Data Start: 0x{:x}", opt_header.data_start);
|
||||
}
|
||||
for section in metadata.sections {
|
||||
let header: SectionHeader = section.header;
|
||||
|
||||
for section in metadata.sections {
|
||||
println!();
|
||||
println!("Section Header:");
|
||||
println!(" Name: {}", name(&header.name).unwrap());
|
||||
println!(" Phys. Addr: 0x{:x}", header.paddr);
|
||||
println!(" Virtual Addr: 0x{:x}", header.vaddr);
|
||||
println!(" Sec. Size: 0x{:x}", header.size);
|
||||
println!(" Data Offset: 0x{:x}", header.scnptr);
|
||||
println!(" Rel. Tab. Offset: 0x{:x}", header.relptr);
|
||||
println!(" Line Num. Offset: 0x{:x}", header.lnnoptr);
|
||||
println!(" Rel. Tab. Entries: {}", header.nreloc);
|
||||
println!(" Line Num. Entries: {}", header.nlnno);
|
||||
println!(" Flags: 0x{:08x}", header.flags);
|
||||
|
||||
let header = section.header;
|
||||
// If there is relocation data, let's dump that too.
|
||||
if section.relocations.len() > 0 {
|
||||
println!(" Relocation Table:");
|
||||
|
||||
println!();
|
||||
println!("Section Header:");
|
||||
println!(" Name: {}", name(&header.name).unwrap());
|
||||
println!(" Phys. Addr: 0x{:x}", header.paddr);
|
||||
println!(" Virtual Addr: 0x{:x}", header.vaddr);
|
||||
println!(" Sec. Size: 0x{:x}", header.size);
|
||||
println!(" Data Offset: 0x{:x}", header.scnptr);
|
||||
println!(" Rel. Tab. Offset: 0x{:x}", header.relptr);
|
||||
println!(" Line Num. Offset: 0x{:x}", header.lnnoptr);
|
||||
println!(" Rel. Tab. Entries: {}", header.nreloc);
|
||||
println!(" Line Num. Entries: {}", header.nlnno);
|
||||
println!(" Flags: 0x{:08x}", header.flags);
|
||||
println!(" Num Vaddr Symndx Type");
|
||||
println!(" ----- ---------- ------ ----");
|
||||
|
||||
// If there is relocation data, let's dump that too.
|
||||
for (i, entry) in section.relocations.iter().enumerate() {
|
||||
println!(" [{:03}] 0x{:08x} {:6} {:3}",
|
||||
i, entry.vaddr, entry.symndx, entry.rtype);
|
||||
}
|
||||
}
|
||||
|
||||
if header.nreloc > 0 {
|
||||
println!(" Relocation Table:");
|
||||
// If there is data, dump it.
|
||||
if section.data.len() > 0 {
|
||||
println!(" Section Data");
|
||||
|
||||
for (i, entry) in section.relocation_entries.iter().enumerate() {
|
||||
println!(" [{:03}] vaddr=0x{:08x}, symndx={}, type={}",
|
||||
i, entry.vaddr, entry.symndx, entry.rtype);
|
||||
for (i, b) in section.data.iter().enumerate() {
|
||||
if i % 16 == 0 {
|
||||
let vaddr = header.vaddr + i as u32;
|
||||
print!(" {:08x}: ", vaddr);
|
||||
}
|
||||
|
||||
print!("{:02x} ", b);
|
||||
|
||||
if (i + 1) % 8 == 0 && (i + 1) % 16 != 0 {
|
||||
print!(" ");
|
||||
}
|
||||
|
||||
if (i + 1) % 16 == 0 || i == (header.size - 1) as usize {
|
||||
println!();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dump the symbols table
|
||||
let strings = metadata.strings;
|
||||
|
||||
if !metadata.symbols.is_empty() {
|
||||
println!();
|
||||
println!("Symbol Table:");
|
||||
|
||||
println!(" Num Name Offset Value Scnum Type Class Numaux");
|
||||
println!(" ------ ---------------- ---------- ---------- ----- ---- ----- ------");
|
||||
|
||||
for (i, e) in metadata.symbols.iter().enumerate() {
|
||||
let stype = match e.is_aux {
|
||||
true => "a",
|
||||
false => "m"
|
||||
};
|
||||
|
||||
let name = match e.n_zeroes {
|
||||
0 => {
|
||||
match e.is_aux {
|
||||
true => "",
|
||||
false => strings.string_at(e.n_offset).unwrap(),
|
||||
}
|
||||
}
|
||||
_ => name(&e.n_name).unwrap(),
|
||||
};
|
||||
|
||||
println!(" [{:4}] {:2} {:16} 0x{:08x} 0x{:08x} {:5} {:04x} {:02x} {:2}",
|
||||
i, stype, name, e.n_offset, e.n_value, e.n_scnum, e.n_type,
|
||||
e.n_sclass, e.n_numaux);
|
||||
}
|
||||
}
|
||||
|
||||
if strings.string_count > 0 {
|
||||
println!();
|
||||
println!("Strings Table:");
|
||||
println!(" data_size: {}", strings.data_size);
|
||||
println!(" string_count: {}", strings.string_count);
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
println!("Could not parse file: {}", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
Loading…
Reference in New Issue