Working COFF dump

This commit is contained in:
Seth Morabito 2019-01-14 14:17:25 -08:00
parent a3bb5bc81b
commit fc57b4ef80
6 changed files with 626 additions and 115 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
imgread
.DS_Store
target

180
Cargo.lock generated Normal file
View File

@ -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"

6
Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[workspace]
members = [
"we32dis",
"we32as",
]

View File

@ -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)

41
we32dis/src/errors.rs Normal file
View File

@ -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
}
}

View File

@ -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() {