1
Fork 0

section parsing

This commit is contained in:
Jan-Erik Rediger 2023-12-08 17:28:36 +01:00
parent 3ede0398eb
commit 489afcc88b
4 changed files with 189 additions and 17 deletions

View file

@ -1,19 +1,18 @@
use std::{ use std::{fs::File, io::Read};
fs::File,
io::Read,
};
use goblin::mach::Mach; use goblin::mach::Mach;
use pyo3::{prelude::*, exceptions::PyTypeError}; use pyo3::{exceptions::PyTypeError, prelude::*};
mod exports; mod exports;
mod header; mod header;
mod imports; mod imports;
mod sections;
mod symbols; mod symbols;
use exports::Export; use exports::Export;
use header::Header; use header::Header;
use imports::Import; use imports::Import;
use sections::{Sections, Section};
use symbols::Symbols; use symbols::Symbols;
#[pyclass] #[pyclass]
@ -74,6 +73,23 @@ impl Object {
} }
} }
fn sections(&self) -> Sections {
match self.inner.as_ref().unwrap() {
goblin::Object::Mach(Mach::Binary(macho)) => {
let mut sections = vec![];
for sect_iter in macho.segments.sections() {
sections.extend(sect_iter.map(|section| {
let (sect, _data) = section.unwrap();
Section::from(sect)
}));
}
Sections { sections }
},
_ => unimplemented!(),
}
}
#[getter] #[getter]
fn libs(&self) -> Vec<&str> { fn libs(&self) -> Vec<&str> {
match self.inner.as_ref().unwrap() { match self.inner.as_ref().unwrap() {
@ -93,9 +109,11 @@ impl Object {
fn exports(&self) -> Result<Vec<Export>, PyErr> { fn exports(&self) -> Result<Vec<Export>, PyErr> {
match self.inner.as_ref().unwrap() { match self.inner.as_ref().unwrap() {
goblin::Object::Mach(Mach::Binary(macho)) => { goblin::Object::Mach(Mach::Binary(macho)) => {
let exports = macho.exports().map_err(|_| PyErr::new::<PyTypeError, _>("failed"))?; let exports = macho
.exports()
.map_err(|_| PyErr::new::<PyTypeError, _>("failed"))?;
Ok(exports.into_iter().map(|exp| exp.into()).collect()) Ok(exports.into_iter().map(|exp| exp.into()).collect())
}, }
_ => unimplemented!(), _ => unimplemented!(),
} }
} }
@ -103,9 +121,11 @@ impl Object {
fn imports(&self) -> Result<Vec<Import>, PyErr> { fn imports(&self) -> Result<Vec<Import>, PyErr> {
match self.inner.as_ref().unwrap() { match self.inner.as_ref().unwrap() {
goblin::Object::Mach(Mach::Binary(macho)) => { goblin::Object::Mach(Mach::Binary(macho)) => {
let imports = macho.imports().map_err(|_| PyErr::new::<PyTypeError, _>("failed"))?; let imports = macho
.imports()
.map_err(|_| PyErr::new::<PyTypeError, _>("failed"))?;
Ok(imports.into_iter().map(|exp| exp.into()).collect()) Ok(imports.into_iter().map(|exp| exp.into()).collect())
}, }
_ => unimplemented!(), _ => unimplemented!(),
} }
} }

View file

@ -0,0 +1,79 @@
use pyo3::prelude::*;
#[derive(Debug, Clone)]
#[pyclass]
pub struct Section {
#[pyo3(get)]
name: Option<String>,
#[pyo3(get)]
segment: Option<String>,
#[pyo3(get)]
addr: u64,
#[pyo3(get)]
size: u64,
#[pyo3(get)]
offset: u32,
#[pyo3(get)]
align: u32,
#[pyo3(get)]
reloff: u32,
#[pyo3(get)]
nreloc: u32,
#[pyo3(get)]
flags: u32,
}
#[pymethods]
impl Section {
fn __repr__(&self) -> String {
format!("{:?}", self)
}
}
impl From<goblin::mach::segment::Section> for Section {
fn from(section: goblin::mach::segment::Section) -> Self {
Section {
name: section.name().ok().map(|s| s.to_string()),
segment: section.segname().ok().map(|s| s.to_string()),
addr: section.addr,
size: section.size,
offset: section.offset,
align: section.align,
reloff: section.reloff,
nreloc: section.nreloc,
flags: section.flags,
}
}
}
#[derive(Clone)]
#[pyclass]
pub struct Sections {
pub(crate) sections: Vec<Section>,
}
#[pymethods]
impl Sections {
fn __iter__(slf: PyRef<'_, Self>) -> PyResult<Py<SectionIter>> {
let iter = SectionIter {
inner: slf.sections.clone().into_iter(),
};
Py::new(slf.py(), iter)
}
}
#[pyclass]
struct SectionIter {
inner: std::vec::IntoIter<Section>,
}
#[pymethods]
impl SectionIter {
fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
slf
}
fn __next__(mut slf: PyRefMut<'_, Self>) -> Option<Section> {
slf.inner.next()
}
}

View file

@ -1,12 +1,74 @@
use goblin::mach::symbols::Nlist; use goblin::mach::symbols::{N_TYPE, n_type_to_str, N_EXT, N_WEAK_REF, N_WEAK_DEF, N_UNDF, N_STAB};
use pyo3::prelude::*; use pyo3::prelude::*;
#[derive(Debug, Clone)]
#[pyclass]
struct Nlist {
#[pyo3(get)]
n_strx: usize,
#[pyo3(get)]
n_type: u8,
#[pyo3(get)]
n_sect: usize,
#[pyo3(get)]
n_desc: u16,
#[pyo3(get)]
n_value: u64,
}
#[pymethods]
impl Nlist {
fn __repr__(&self) -> String {
format!("{:?}", self)
}
}
impl Nlist {
/// Gets this symbol's type in bits 0xe
pub fn get_type(&self) -> u8 {
self.n_type & N_TYPE
}
/// Gets the str representation of the type of this symbol
pub fn type_str(&self) -> &'static str {
n_type_to_str(self.get_type())
}
/// Whether this symbol is global or not
pub fn is_global(&self) -> bool {
self.n_type & N_EXT != 0
}
/// Whether this symbol is weak or not
pub fn is_weak(&self) -> bool {
self.n_desc & (N_WEAK_REF | N_WEAK_DEF) != 0
}
/// Whether this symbol is undefined or not
pub fn is_undefined(&self) -> bool {
self.n_sect == 0 && self.n_type & N_TYPE == N_UNDF
}
/// Whether this symbol is a symbolic debugging entry
pub fn is_stab(&self) -> bool {
self.n_type & N_STAB != 0
}
}
impl From<goblin::mach::symbols::Nlist> for Nlist {
fn from(list: goblin::mach::symbols::Nlist) -> Self {
Self {
n_strx: list.n_strx,
n_type: list.n_type,
n_sect: list.n_sect,
n_desc: list.n_desc,
n_value: list.n_value,
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[pyclass] #[pyclass]
struct Symbol { struct Symbol {
#[pyo3(get)] #[pyo3(get)]
name: String, name: String,
#[pyo3(get)]
meta: Nlist, meta: Nlist,
} }
@ -37,14 +99,21 @@ impl Symbol {
self.meta.is_stab() self.meta.is_stab()
} }
#[getter]
fn section(&self) -> usize {
self.meta.n_sect
}
fn __repr__(&self) -> String { fn __repr__(&self) -> String {
format!( format!(
"Symbol {{ name: {}, global: {}, weak: {}, undefined: {}, stab: {} }}", "Symbol {{ name: {}, type: {}, global: {}, weak: {}, undefined: {}, stab: {}, meta: {:?} }}",
self.name, self.name,
self.typ(),
self.global(), self.global(),
self.weak(), self.weak(),
self.undefined(), self.undefined(),
self.stab() self.stab(),
self.meta,
) )
} }
} }
@ -71,7 +140,7 @@ impl From<goblin::mach::symbols::SymbolIterator<'_>> for Symbols {
let (symname, meta) = sym.unwrap(); let (symname, meta) = sym.unwrap();
Symbol { Symbol {
name: symname.to_string(), name: symname.to_string(),
meta, meta: meta.into(),
} }
}) })
.collect(); .collect();
@ -95,5 +164,3 @@ impl SymbolIter {
slf.inner.next() slf.inner.next()
} }
} }

View file

@ -6,8 +6,9 @@ print(g.name)
print("symbols") print("symbols")
for sym in g.symbols(): for sym in g.symbols():
print(sym) if not sym.undefined:
break print(sym)
break
print("libs") print("libs")
print(g.libs) print(g.libs)
@ -20,3 +21,8 @@ print(len(g.exports()))
print("imports") print("imports")
print(len(g.imports())) print(len(g.imports()))
print("sections")
sections = iter(g.sections())
print(next(sections))
print(next(sections))