Skip to content

Commit f937e97

Browse files
committed
Use segments
1 parent c7891e2 commit f937e97

File tree

6 files changed

+157
-5
lines changed

6 files changed

+157
-5
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ tracing = "0.1.40"
3434
colored = "2.1.0"
3535
tracing-subscriber = { version = "0.3.18", optional = true, features = ["env-filter"] }
3636
toml_edit = { version = "0.22.12", optional = true, features = ["serde"] }
37-
object = { version = "0.36.0" }
37+
object = "0.36.7"
3838
clap = { version = "4.0.32", optional = true , features = ["derive"]}
3939
rand = "0.8.5"
4040
derive_builder = "0.20.0"

src/config/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ pub enum CrackersConfigError {
1010
Gimli(#[from] object::Error),
1111
#[error("Spec objects must have a '_start' symbol")]
1212
SpecMissingStartSymbol,
13+
#[error("Unable to parse a segment from the target binary")]
14+
LibraryParse,
1315
#[error("Spec objects must have a '.text' symbol")]
1416
SpecMissingTextSection,
1517
#[error("Unable to determine the architecture of the provided object file. This is a config file limitation and not a sleigh limitation.")]

src/config/object.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,28 @@ use object::{File, Object};
1010
use crate::config::error::CrackersConfigError;
1111
use crate::config::error::CrackersConfigError::UnrecognizedArchitecture;
1212
use crate::config::sleigh::SleighConfig;
13+
use crate::gadget::library::image::SegmentFile;
1314

14-
fn load_image<T: AsRef<Path>>(path: T) -> Result<(OwnedFile, &'static str), CrackersConfigError> {
15+
fn load_image<T: AsRef<Path>>(path: T) -> Result<(SegmentFile, &'static str), CrackersConfigError> {
1516
let data = fs::read(path.as_ref())?;
1617
let file = File::parse(&*data)?;
1718
let arch = map_gimli_architecture(&file).ok_or(UnrecognizedArchitecture(format!(
1819
"{:?}",
1920
file.architecture()
2021
)))?;
21-
let img = OwnedFile::new(&file)?;
22+
let img = SegmentFile::new(&file).map_err(|_| CrackersConfigError::LibraryParse)?;
23+
Ok((img, arch))
24+
}
25+
26+
/// gross hack
27+
fn load_image_spec<T: AsRef<Path>>(path: T) -> Result<(OwnedFile, &'static str), CrackersConfigError> {
28+
let data = fs::read(path.as_ref())?;
29+
let file = File::parse(&*data)?;
30+
let arch = map_gimli_architecture(&file).ok_or(UnrecognizedArchitecture(format!(
31+
"{:?}",
32+
file.architecture()
33+
)))?;
34+
let img = OwnedFile::new(&file).map_err(|_| CrackersConfigError::LibraryParse)?;
2235
Ok((img, arch))
2336
}
2437

@@ -32,3 +45,14 @@ pub fn load_sleigh<T: AsRef<Path>>(
3245
let ctx = ctx.initialize_with_image(img)?;
3346
Ok(ctx)
3447
}
48+
49+
pub fn load_sleigh_spec<T: AsRef<Path>>(
50+
file_path: T,
51+
sleigh_config: &SleighConfig,
52+
) -> Result<LoadedSleighContext, CrackersConfigError> {
53+
let (img, arch) = load_image_spec(file_path)?;
54+
let builder = sleigh_config.context_builder()?;
55+
let ctx = builder.build(arch)?;
56+
let ctx = ctx.initialize_with_image(img)?;
57+
Ok(ctx)
58+
}

src/config/specification.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
77

88
use crate::config::error::CrackersConfigError;
99
use crate::config::error::CrackersConfigError::{SpecMissingStartSymbol, SpecMissingTextSection};
10-
use crate::config::object::load_sleigh;
10+
use crate::config::object::load_sleigh_spec;
1111
use crate::config::sleigh::SleighConfig;
1212

1313
#[derive(Clone, Debug, Deserialize, Serialize)]
@@ -21,7 +21,7 @@ impl SpecificationConfig {
2121
&self,
2222
sleigh_config: &'a SleighConfig,
2323
) -> Result<LoadedSleighContext<'a>, CrackersConfigError> {
24-
load_sleigh(&self.path, sleigh_config)
24+
load_sleigh_spec(&self.path, sleigh_config)
2525
}
2626

2727
pub fn get_spec(

src/gadget/library/image.rs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
use crate::error::CrackersError;
2+
use jingle::sleigh::context::image::{ImageProvider, ImageSection, ImageSectionIterator, Perms};
3+
use jingle::sleigh::JingleSleighError::ImageLoadError;
4+
use jingle::sleigh::VarNode;
5+
use jingle::JingleError::Sleigh;
6+
use object::elf::{PF_R, PF_W, PF_X};
7+
use object::macho::{VM_PROT_EXECUTE, VM_PROT_READ, VM_PROT_WRITE};
8+
use object::pe::{IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE};
9+
use object::{File, Object, ObjectSegment, Segment, SegmentFlags};
10+
use std::cmp::{max, min};
11+
12+
#[derive(Debug, PartialEq, Eq)]
13+
pub struct ImageSegment {
14+
data: Vec<u8>,
15+
perms: Perms,
16+
base_address: usize,
17+
}
18+
19+
impl<'a> From<&'a ImageSegment> for ImageSection<'a> {
20+
fn from(value: &'a ImageSegment) -> Self {
21+
ImageSection {
22+
data: value.data.as_slice(),
23+
perms: value.perms.clone(),
24+
base_address: value.base_address,
25+
}
26+
}
27+
}
28+
29+
impl TryFrom<Segment<'_, '_>> for ImageSegment {
30+
type Error = CrackersError;
31+
32+
fn try_from(value: Segment) -> Result<Self, Self::Error> {
33+
let data = value
34+
.data()
35+
.map_err(|_| CrackersError::Jingle(Sleigh(ImageLoadError)))?
36+
.to_vec();
37+
Ok(ImageSegment {
38+
data,
39+
perms: map_seg_flags(&value.flags())?,
40+
base_address: value.address() as usize,
41+
})
42+
}
43+
}
44+
45+
/// todo: this should go in jingle
46+
fn map_seg_flags(p0: &SegmentFlags) -> Result<Perms, CrackersError> {
47+
match p0 {
48+
SegmentFlags::None => Ok(Perms::RWX),
49+
SegmentFlags::Elf { p_flags } => Ok(Perms {
50+
read: p_flags & PF_R != 0,
51+
write: p_flags & PF_W != 0,
52+
exec: p_flags & PF_X != 0,
53+
}),
54+
SegmentFlags::MachO { maxprot, .. } => Ok(Perms {
55+
read: maxprot & VM_PROT_READ != 0,
56+
write: maxprot & VM_PROT_WRITE != 0,
57+
exec: maxprot & VM_PROT_EXECUTE != 0,
58+
}),
59+
SegmentFlags::Coff { characteristics } => Ok(Perms {
60+
read: characteristics & IMAGE_SCN_MEM_READ != 0,
61+
write: characteristics & IMAGE_SCN_MEM_WRITE != 0,
62+
exec: characteristics & IMAGE_SCN_MEM_EXECUTE != 0,
63+
}),
64+
_ => Err(CrackersError::Jingle(Sleigh(ImageLoadError))),
65+
}
66+
}
67+
68+
/// A gross hack because we want to process the entire executable segment, rather
69+
/// than the portion that is marked executable for the linker
70+
pub struct SegmentFile {
71+
segments: Vec<ImageSegment>,
72+
}
73+
74+
impl SegmentFile {
75+
pub fn new(file: &File) -> Result<Self, CrackersError> {
76+
let mut segments = vec![];
77+
for x in file
78+
.segments()
79+
.filter(|f| map_seg_flags(&f.flags()).map(|f| f.exec).unwrap_or(false))
80+
{
81+
segments.push(x.try_into()?);
82+
}
83+
Ok(Self { segments })
84+
}
85+
}
86+
87+
impl ImageProvider for SegmentFile {
88+
fn load(&self, vn: &VarNode, output: &mut [u8]) -> usize {
89+
let mut written = 0;
90+
output.fill(0);
91+
let output_start_addr = vn.offset as usize;
92+
let output_end_addr = output_start_addr + vn.size;
93+
if let Some(x) = self.get_section_info().find(|s| {
94+
output_start_addr >= s.base_address
95+
&& output_start_addr < (s.base_address + s.data.len())
96+
}) {
97+
let input_start_addr = x.base_address;
98+
let input_end_addr = input_start_addr + x.data.len();
99+
let start_addr = max(input_start_addr, output_start_addr);
100+
let end_addr = max(min(input_end_addr, output_end_addr), start_addr);
101+
if end_addr > start_addr {
102+
let i_s = start_addr - x.base_address;
103+
let i_e = end_addr - x.base_address;
104+
let o_s = start_addr - vn.offset as usize;
105+
let o_e = end_addr - vn.offset as usize;
106+
let out_slice = &mut output[o_s..o_e];
107+
let in_slice = &x.data[i_s..i_e];
108+
out_slice.copy_from_slice(in_slice);
109+
written += end_addr - start_addr;
110+
}
111+
}
112+
written
113+
}
114+
115+
fn has_full_range(&self, vn: &VarNode) -> bool {
116+
self.get_section_info().any(|s| {
117+
s.base_address <= vn.offset as usize
118+
&& (s.base_address + s.data.len()) >= (vn.offset as usize + vn.size)
119+
})
120+
}
121+
122+
fn get_section_info(&self) -> ImageSectionIterator {
123+
ImageSectionIterator::new(self.segments.iter().map(ImageSection::from))
124+
}
125+
}

src/gadget/library/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::gadget::library::builder::GadgetLibraryParams;
1414
use crate::gadget::Gadget;
1515

1616
pub mod builder;
17+
pub mod image;
1718

1819
#[derive(Clone, Debug)]
1920
pub struct GadgetLibrary {

0 commit comments

Comments
 (0)