Skip to content

Commit a87fbec

Browse files
authored
Update to goblin 0.6.0 (#30)
Goblin added support for archives in Mach fat binaries, see [1]. Tested against the binaries from that commit. [1]: m4b/goblin@e2b5207
1 parent 40bf077 commit a87fbec

File tree

4 files changed

+145
-86
lines changed

4 files changed

+145
-86
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ panic = 'abort' # Abort on panic
2828
clap = {version = "4.0.14", features = ["cargo"]}
2929
colored = {version = "2.0.0", optional = true}
3030
colored_json = {version = "3.0.1", optional = true}
31-
goblin = "0.5.4"
31+
goblin = "0.6.0"
3232
ignore = "0.4.18"
3333
memmap2 = "0.5.7"
3434
scroll = "0.11.0"

examples/macho_print_checksec_results.rs

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ extern crate checksec;
22
extern crate goblin;
33

44
use checksec::macho::CheckSecResults;
5-
use goblin::mach::{Mach, MachO};
5+
use goblin::mach::cputype::get_arch_name_from_types;
6+
use goblin::mach::Mach;
7+
use goblin::mach::SingleArch::Archive;
8+
use goblin::mach::SingleArch::MachO;
69
use goblin::Object;
710
use std::{env, fs};
811

@@ -12,32 +15,60 @@ fn main() {
1215
2 => {
1316
if fs::File::open(&argv[1]).is_ok() {
1417
if let Ok(buf) = fs::read(&argv[1]) {
15-
match Object::parse(&buf).unwrap() {
16-
Object::Mach(mach) => match mach {
17-
Mach::Binary(macho) => {
18-
println!(
19-
"{:#?}",
20-
CheckSecResults::parse(&macho)
21-
);
22-
}
23-
Mach::Fat(fatmach) => {
24-
for (idx, _) in
25-
fatmach.iter_arches().enumerate()
26-
{
27-
let container: MachO =
28-
fatmach.get(idx).unwrap();
29-
println!(
30-
"{:#?}",
31-
CheckSecResults::parse(&container)
32-
);
18+
parse(&buf);
19+
}
20+
}
21+
}
22+
_ => eprintln!("Usage: macho_print_checksec_results <binary>"),
23+
}
24+
}
25+
26+
fn parse(bytes: &[u8]) {
27+
match Object::parse(&bytes).unwrap() {
28+
Object::Mach(mach) => match mach {
29+
Mach::Binary(macho) => {
30+
println!("{:#?}", CheckSecResults::parse(&macho));
31+
}
32+
Mach::Fat(fatmach) => {
33+
for (idx, fatarch) in fatmach.iter_arches().enumerate() {
34+
match fatmach.get(idx).unwrap() {
35+
MachO(mach) => {
36+
let machine = get_arch_name_from_types(
37+
mach.header.cputype(),
38+
mach.header.cpusubtype(),
39+
)
40+
.unwrap_or("UNKNOWN");
41+
println!("# Machine type {}:", machine);
42+
println!("{:#?}", CheckSecResults::parse(&mach))
43+
}
44+
Archive(archive) => {
45+
let fatarch = fatarch.unwrap();
46+
47+
let archive_bytes = &bytes[fatarch.offset as usize
48+
..(fatarch.offset + fatarch.size) as usize];
49+
50+
for member in archive.members() {
51+
match archive.extract(member, archive_bytes) {
52+
Ok(ext_bytes) => {
53+
println!(
54+
"# Archive member {}:",
55+
member
56+
);
57+
parse(ext_bytes);
58+
}
59+
Err(err) => {
60+
eprintln!(
61+
"Failed to extract member {}: {}",
62+
member, err
63+
);
64+
}
3365
}
3466
}
35-
},
36-
_ => eprintln!("not a mach binary"),
67+
}
3768
}
3869
}
3970
}
40-
}
41-
_ => eprintln!("Usage: macho_print_checksec_results <binary>"),
71+
},
72+
_ => eprintln!("not a mach binary"),
4273
}
4374
}

src/main.rs

Lines changed: 88 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use clap::{
1414
};
1515
use goblin::error::Error;
1616
#[cfg(feature = "macho")]
17-
use goblin::mach::Mach;
17+
use goblin::mach::{Mach, SingleArch::Archive, SingleArch::MachO};
1818
use goblin::Object;
1919
use ignore::Walk;
2020
use memmap2::Mmap;
@@ -193,80 +193,108 @@ fn parse_bytes(bytes: &[u8], file: &Path) -> Result<Vec<Binary>, ParseError> {
193193
)])
194194
}
195195
#[cfg(feature = "macho")]
196-
Object::Mach(mach) => match mach {
197-
Mach::Binary(macho) => {
198-
let results = macho::CheckSecResults::parse(&macho);
199-
let bin_type = if macho.is_64 {
200-
BinType::MachO64
201-
} else {
202-
BinType::MachO32
203-
};
204-
Ok(vec![Binary::new(
205-
bin_type,
206-
file.to_path_buf(),
207-
BinSpecificProperties::MachO(results),
208-
)])
209-
}
210-
Mach::Fat(fatmach) => {
211-
let mut fat_bins: Vec<Binary> = Vec::new();
212-
for (idx, _) in fatmach.arches()?.iter().enumerate() {
213-
if let Ok(container) = fatmach.get(idx) {
214-
let results =
215-
macho::CheckSecResults::parse(&container);
216-
let bin_type = if container.is_64 {
217-
BinType::MachO64
218-
} else {
219-
BinType::MachO32
220-
};
221-
fat_bins.push(Binary::new(
222-
bin_type,
223-
file.to_path_buf(),
224-
BinSpecificProperties::MachO(results),
225-
));
196+
Object::Mach(mach) => {
197+
match mach {
198+
Mach::Binary(macho) => {
199+
let results = macho::CheckSecResults::parse(&macho);
200+
let bin_type = if macho.is_64 {
201+
BinType::MachO64
202+
} else {
203+
BinType::MachO32
204+
};
205+
Ok(vec![Binary::new(
206+
bin_type,
207+
file.to_path_buf(),
208+
BinSpecificProperties::MachO(results),
209+
)])
210+
}
211+
Mach::Fat(fatmach) => {
212+
let mut fat_bins: Vec<Binary> = Vec::new();
213+
for (idx, fatarch) in fatmach.iter_arches().enumerate() {
214+
if let Ok(container) = fatmach.get(idx) {
215+
match container {
216+
MachO(mach) => {
217+
let results =
218+
macho::CheckSecResults::parse(&mach);
219+
let bin_type = if mach.is_64 {
220+
BinType::MachO64
221+
} else {
222+
BinType::MachO32
223+
};
224+
fat_bins.push(Binary::new(
225+
bin_type,
226+
file.to_path_buf(),
227+
BinSpecificProperties::MachO(results),
228+
));
229+
}
230+
Archive(archive) => {
231+
let fatarch = fatarch?;
232+
if let Some(archive_bytes) = bytes.get(
233+
fatarch.offset as usize
234+
..(fatarch.offset + fatarch.size)
235+
as usize,
236+
) {
237+
fat_bins.append(&mut parse_archive(
238+
&archive,
239+
file,
240+
archive_bytes,
241+
));
242+
} else {
243+
Err(goblin::error::Error::Malformed("Archive refers to invalid position".to_string()))?;
244+
}
245+
}
246+
}
247+
}
226248
}
249+
Ok(fat_bins)
227250
}
228-
Ok(fat_bins)
229251
}
230-
},
252+
}
231253
#[cfg(not(feature = "elf"))]
232254
Object::Elf(_) => Err(ParseError::Unimplemented("ELF")),
233255
#[cfg(not(feature = "pe"))]
234256
Object::PE(_) => Err(ParseError::Unimplemented("PE")),
235257
#[cfg(not(feature = "macho"))]
236258
Object::Mach(_) => Err(ParseError::Unimplemented("MachO")),
237-
Object::Archive(archive) => Ok(archive
238-
.members()
239-
.iter()
240-
.filter_map(|member_name| {
241-
match archive.extract(member_name, bytes) {
242-
Ok(ext_bytes) => parse_bytes(
243-
ext_bytes,
244-
Path::new(&format!(
245-
"{}\u{2794}{}",
246-
file.display(),
247-
member_name
248-
)),
249-
)
250-
.ok(),
251-
Err(err) => {
252-
eprintln!(
253-
"Failed to extract member {} of {}: {}",
254-
member_name,
255-
file.display(),
256-
err
257-
);
258-
None
259-
}
260-
}
261-
})
262-
.flatten()
263-
.collect()),
259+
Object::Archive(archive) => Ok(parse_archive(&archive, file, bytes)),
264260
Object::Unknown(magic) => {
265261
Err(ParseError::Goblin(Error::BadMagic(magic)))
266262
}
267263
}
268264
}
269265

266+
fn parse_archive(
267+
archive: &goblin::archive::Archive,
268+
file: &Path,
269+
bytes: &[u8],
270+
) -> Vec<Binary> {
271+
archive
272+
.members()
273+
.iter()
274+
.filter_map(|member_name| match archive.extract(member_name, bytes) {
275+
Ok(ext_bytes) => parse_bytes(
276+
ext_bytes,
277+
Path::new(&format!(
278+
"{}\u{2794}{}",
279+
file.display(),
280+
member_name
281+
)),
282+
)
283+
.ok(),
284+
Err(err) => {
285+
eprintln!(
286+
"Failed to extract member {} of {}: {}",
287+
member_name,
288+
file.display(),
289+
err
290+
);
291+
None
292+
}
293+
})
294+
.flatten()
295+
.collect()
296+
}
297+
270298
fn walk(basepath: &Path, settings: &output::Settings) {
271299
let mut bins: Vec<Binary> = Vec::new();
272300
for result in Walk::new(basepath).flatten() {

0 commit comments

Comments
 (0)