1 use scroll
::ctx
::{self, SizeWith}
;
2 use scroll
::{Pread, Pwrite}
;
4 use log
::{debug, warn}
;
9 use core
::ops
::{Deref, DerefMut}
;
14 use crate::mach
::constants
::{SECTION_TYPE, S_GB_ZEROFILL, S_THREAD_LOCAL_ZEROFILL, S_ZEROFILL}
;
15 use crate::mach
::load_command
::{
16 Section32
, Section64
, SegmentCommand32
, SegmentCommand64
, LC_SEGMENT
, LC_SEGMENT_64
,
17 SIZEOF_SECTION_32
, SIZEOF_SECTION_64
, SIZEOF_SEGMENT_COMMAND_32
, SIZEOF_SEGMENT_COMMAND_64
,
19 use crate::mach
::relocation
::RelocationInfo
;
21 pub struct RelocationIterator
<'a
> {
29 impl<'a
> Iterator
for RelocationIterator
<'a
> {
30 type Item
= error
::Result
<RelocationInfo
>;
31 fn next(&mut self) -> Option
<Self::Item
> {
32 if self.count
>= self.nrelocs
{
36 match self.data
.gread_with(&mut self.offset
, self.ctx
) {
37 Ok(res
) => Some(Ok(res
)),
38 Err(e
) => Some(Err(e
.into())),
44 /// Generalized 32/64 bit Section
47 /// name of this section
48 pub sectname
: [u8; 16],
49 /// segment this section goes in
50 pub segname
: [u8; 16],
51 /// memory address of this section
53 /// size in bytes of this section
55 /// file offset of this section
57 /// section alignment (power of 2)
59 /// file offset of relocation entries
61 /// number of relocation entries
63 /// flags (section type and attributes
68 /// The name of this section
69 pub fn name(&self) -> error
::Result
<&str> {
70 Ok(self.sectname
.pread
::<&str>(0)?
)
72 /// The containing segment's name
73 pub fn segname(&self) -> error
::Result
<&str> {
74 Ok(self.segname
.pread
::<&str>(0)?
)
76 /// Iterate this sections relocations given `data`; `data` must be the original binary
77 pub fn iter_relocations
<'b
>(
81 ) -> RelocationIterator
<'b
> {
82 let offset
= self.reloff
as usize;
84 "Relocations for {} starting at offset: {:#x}",
85 self.name().unwrap_or("BAD_SECTION_NAME"),
90 nrelocs
: self.nreloc
as usize,
98 impl From
<Section
> for Section64
{
99 fn from(section
: Section
) -> Self {
101 sectname
: section
.sectname
,
102 segname
: section
.segname
,
103 addr
: section
.addr
as u64,
104 size
: section
.size
as u64,
105 offset
: section
.offset
,
106 align
: section
.align
,
107 reloff
: section
.reloff
,
108 nreloc
: section
.nreloc
,
109 flags
: section
.flags
,
117 impl From
<Section
> for Section32
{
118 fn from(section
: Section
) -> Self {
120 sectname
: section
.sectname
,
121 segname
: section
.segname
,
122 addr
: section
.addr
as u32,
123 size
: section
.size
as u32,
124 offset
: section
.offset
,
125 align
: section
.align
,
126 reloff
: section
.reloff
,
127 nreloc
: section
.nreloc
,
128 flags
: section
.flags
,
135 impl fmt
::Debug
for Section
{
136 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
137 fmt
.debug_struct("Section")
138 .field("sectname", &self.name().unwrap())
139 .field("segname", &self.segname().unwrap())
140 .field("addr", &self.addr
)
141 .field("size", &self.size
)
142 .field("offset", &self.offset
)
143 .field("align", &self.align
)
144 .field("reloff", &self.reloff
)
145 .field("nreloc", &self.nreloc
)
146 .field("flags", &self.flags
)
151 impl From
<Section32
> for Section
{
152 fn from(section
: Section32
) -> Self {
154 sectname
: section
.sectname
,
155 segname
: section
.segname
,
156 addr
: u64::from(section
.addr
),
157 size
: u64::from(section
.size
),
158 offset
: section
.offset
,
159 align
: section
.align
,
160 reloff
: section
.reloff
,
161 nreloc
: section
.nreloc
,
162 flags
: section
.flags
,
167 impl From
<Section64
> for Section
{
168 fn from(section
: Section64
) -> Self {
170 sectname
: section
.sectname
,
171 segname
: section
.segname
,
174 offset
: section
.offset
,
175 align
: section
.align
,
176 reloff
: section
.reloff
,
177 nreloc
: section
.nreloc
,
178 flags
: section
.flags
,
183 impl<'a
> ctx
::TryFromCtx
<'a
, container
::Ctx
> for Section
{
184 type Error
= crate::error
::Error
;
185 fn try_from_ctx(bytes
: &'a
[u8], ctx
: container
::Ctx
) -> Result
<(Self, usize), Self::Error
> {
186 match ctx
.container
{
187 container
::Container
::Little
=> {
188 let section
= Section
::from(bytes
.pread_with
::<Section32
>(0, ctx
.le
)?
);
189 Ok((section
, SIZEOF_SECTION_32
))
191 container
::Container
::Big
=> {
192 let section
= Section
::from(bytes
.pread_with
::<Section64
>(0, ctx
.le
)?
);
193 Ok((section
, SIZEOF_SECTION_64
))
199 impl ctx
::SizeWith
<container
::Ctx
> for Section
{
200 fn size_with(ctx
: &container
::Ctx
) -> usize {
201 match ctx
.container
{
202 container
::Container
::Little
=> SIZEOF_SECTION_32
,
203 container
::Container
::Big
=> SIZEOF_SECTION_64
,
208 impl ctx
::TryIntoCtx
<container
::Ctx
> for Section
{
209 type Error
= crate::error
::Error
;
210 fn try_into_ctx(self, bytes
: &mut [u8], ctx
: container
::Ctx
) -> Result
<usize, Self::Error
> {
212 bytes
.pwrite_with
::<Section64
>(self.into(), 0, ctx
.le
)?
;
214 bytes
.pwrite_with
::<Section32
>(self.into(), 0, ctx
.le
)?
;
216 Ok(Self::size_with(&ctx
))
220 impl ctx
::IntoCtx
<container
::Ctx
> for Section
{
221 fn into_ctx(self, bytes
: &mut [u8], ctx
: container
::Ctx
) {
222 bytes
.pwrite_with(self, 0, ctx
).unwrap();
226 pub struct SectionIterator
<'a
> {
234 pub type SectionData
<'a
> = &'a
[u8];
236 impl<'a
> ::core
::iter
::ExactSizeIterator
for SectionIterator
<'a
> {
237 fn len(&self) -> usize {
242 impl<'a
> Iterator
for SectionIterator
<'a
> {
243 type Item
= error
::Result
<(Section
, SectionData
<'a
>)>;
244 fn next(&mut self) -> Option
<Self::Item
> {
245 if self.idx
>= self.count
{
249 match self.data
.gread_with
::<Section
>(&mut self.offset
, self.ctx
) {
251 let section_type
= section
.flags
& SECTION_TYPE
;
252 let data
= if section_type
== S_ZEROFILL
253 || section_type
== S_GB_ZEROFILL
254 || section_type
== S_THREAD_LOCAL_ZEROFILL
258 // it's not uncommon to encounter macho files where files are
259 // truncated but the sections are still remaining in the header.
260 // Because of this we want to not panic here but instead just
261 // slice down to a empty data slice. This way only if code
262 // actually needs to access those sections it will fall over.
264 .get(section
.offset
as usize..)
267 "section #{} offset {} out of bounds",
268 self.idx
, section
.offset
272 .get(..section
.size
as usize)
274 warn
!("section #{} size {} out of bounds", self.idx
, section
.size
);
278 Some(Ok((section
, data
)))
280 Err(e
) => Some(Err(e
)),
286 impl<'a
, 'b
> IntoIterator
for &'b Segment
<'a
> {
287 type Item
= error
::Result
<(Section
, SectionData
<'a
>)>;
288 type IntoIter
= SectionIterator
<'a
>;
289 fn into_iter(self) -> Self::IntoIter
{
292 count
: self.nsects
as usize,
293 offset
: self.offset
+ Segment
::size_with(&self.ctx
),
300 /// Generalized 32/64 bit Segment Command
301 pub struct Segment
<'a
> {
304 pub segname
: [u8; 16],
319 impl<'a
> From
<Segment
<'a
>> for SegmentCommand64
{
320 fn from(segment
: Segment
<'a
>) -> Self {
323 cmdsize
: segment
.cmdsize
,
324 segname
: segment
.segname
,
325 vmaddr
: segment
.vmaddr
as u64,
326 vmsize
: segment
.vmsize
as u64,
327 fileoff
: segment
.fileoff
as u64,
328 filesize
: segment
.filesize
as u64,
329 maxprot
: segment
.maxprot
,
330 initprot
: segment
.initprot
,
331 nsects
: segment
.nsects
,
332 flags
: segment
.flags
,
337 impl<'a
> From
<Segment
<'a
>> for SegmentCommand32
{
338 fn from(segment
: Segment
<'a
>) -> Self {
341 cmdsize
: segment
.cmdsize
,
342 segname
: segment
.segname
,
343 vmaddr
: segment
.vmaddr
as u32,
344 vmsize
: segment
.vmsize
as u32,
345 fileoff
: segment
.fileoff
as u32,
346 filesize
: segment
.filesize
as u32,
347 maxprot
: segment
.maxprot
,
348 initprot
: segment
.initprot
,
349 nsects
: segment
.nsects
,
350 flags
: segment
.flags
,
355 impl<'a
> fmt
::Debug
for Segment
<'a
> {
356 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
357 fmt
.debug_struct("Segment")
358 .field("cmd", &self.cmd
)
359 .field("cmdsize", &self.cmdsize
)
360 .field("segname", &self.segname
.pread
::<&str>(0).unwrap())
361 .field("vmaddr", &self.vmaddr
)
362 .field("vmsize", &self.vmsize
)
363 .field("fileoff", &self.fileoff
)
364 .field("filesize", &self.filesize
)
365 .field("maxprot", &self.maxprot
)
366 .field("initprot", &self.initprot
)
367 .field("nsects", &self.nsects
)
368 .field("flags", &self.flags
)
369 .field("data", &self.data
.len())
372 &self.sections().map(|sections
| {
375 .map(|(section
, _
)| section
)
383 impl<'a
> ctx
::SizeWith
<container
::Ctx
> for Segment
<'a
> {
384 fn size_with(ctx
: &container
::Ctx
) -> usize {
385 match ctx
.container
{
386 container
::Container
::Little
=> SIZEOF_SEGMENT_COMMAND_32
,
387 container
::Container
::Big
=> SIZEOF_SEGMENT_COMMAND_64
,
392 impl<'a
> ctx
::TryIntoCtx
<container
::Ctx
> for Segment
<'a
> {
393 type Error
= crate::error
::Error
;
394 fn try_into_ctx(self, bytes
: &mut [u8], ctx
: container
::Ctx
) -> Result
<usize, Self::Error
> {
395 let segment_size
= Self::size_with(&ctx
);
396 // should be able to write the section data inline after this, but not working at the moment
397 //let section_size = bytes.pwrite(data, segment_size)?;
398 //debug!("Segment size: {} raw section data size: {}", segment_size, data.len());
400 bytes
.pwrite_with
::<SegmentCommand64
>(self.into(), 0, ctx
.le
)?
;
402 bytes
.pwrite_with
::<SegmentCommand32
>(self.into(), 0, ctx
.le
)?
;
404 //debug!("Section size: {}", section_size);
409 impl<'a
> ctx
::IntoCtx
<container
::Ctx
> for Segment
<'a
> {
410 fn into_ctx(self, bytes
: &mut [u8], ctx
: container
::Ctx
) {
411 bytes
.pwrite_with(self, 0, ctx
).unwrap();
415 /// Read data that belongs to a segment if the offset is within the boundaries of bytes.
416 fn segment_data(bytes
: &[u8], fileoff
: u64, filesize
: u64) -> Result
<&[u8], error
::Error
> {
417 let data
: &[u8] = if filesize
!= 0 {
418 bytes
.pread_with(fileoff
as usize, filesize
as usize)?
425 impl<'a
> Segment
<'a
> {
426 /// Create a new, blank segment, with cmd either `LC_SEGMENT_64`, or `LC_SEGMENT`, depending on `ctx`.
427 /// **NB** You are responsible for providing a correctly marshalled byte array as the sections. You should not use this for anything other than writing.
428 pub fn new(ctx
: container
::Ctx
, sections
: &'a
[u8]) -> Self {
430 cmd
: if ctx
.is_big() {
435 cmdsize
: (Self::size_with(&ctx
) + sections
.len()) as u32,
451 /// Get the name of this segment
452 pub fn name(&self) -> error
::Result
<&str> {
453 Ok(self.segname
.pread
::<&str>(0)?
)
455 /// Get the sections from this segment, erroring if any section couldn't be retrieved
456 pub fn sections(&self) -> error
::Result
<Vec
<(Section
, SectionData
<'a
>)>> {
457 let mut sections
= Vec
::new();
458 for section
in self.into_iter() {
459 sections
.push(section?
);
463 /// Convert the raw C 32-bit segment command to a generalized version
466 segment
: &SegmentCommand32
,
469 ) -> Result
<Self, error
::Error
> {
472 cmdsize
: segment
.cmdsize
,
473 segname
: segment
.segname
,
474 vmaddr
: u64::from(segment
.vmaddr
),
475 vmsize
: u64::from(segment
.vmsize
),
476 fileoff
: u64::from(segment
.fileoff
),
477 filesize
: u64::from(segment
.filesize
),
478 maxprot
: segment
.maxprot
,
479 initprot
: segment
.initprot
,
480 nsects
: segment
.nsects
,
481 flags
: segment
.flags
,
484 u64::from(segment
.fileoff
),
485 u64::from(segment
.filesize
),
492 /// Convert the raw C 64-bit segment command to a generalized version
495 segment
: &SegmentCommand64
,
498 ) -> Result
<Self, error
::Error
> {
501 cmdsize
: segment
.cmdsize
,
502 segname
: segment
.segname
,
503 vmaddr
: segment
.vmaddr
,
504 vmsize
: segment
.vmsize
,
505 fileoff
: segment
.fileoff
,
506 filesize
: segment
.filesize
,
507 maxprot
: segment
.maxprot
,
508 initprot
: segment
.initprot
,
509 nsects
: segment
.nsects
,
510 flags
: segment
.flags
,
511 data
: segment_data(bytes
, segment
.fileoff
, segment
.filesize
)?
,
519 #[derive(Debug, Default)]
520 /// An opaque 32/64-bit container for Mach-o segments
521 pub struct Segments
<'a
> {
522 segments
: Vec
<Segment
<'a
>>,
526 impl<'a
> Deref
for Segments
<'a
> {
527 type Target
= Vec
<Segment
<'a
>>;
528 fn deref(&self) -> &Self::Target
{
533 impl<'a
> DerefMut
for Segments
<'a
> {
534 fn deref_mut(&mut self) -> &mut Self::Target
{
539 impl<'a
, 'b
> IntoIterator
for &'b Segments
<'a
> {
540 type Item
= &'b Segment
<'a
>;
541 type IntoIter
= ::core
::slice
::Iter
<'b
, Segment
<'a
>>;
542 fn into_iter(self) -> Self::IntoIter
{
547 impl<'a
> Segments
<'a
> {
548 /// Construct a new generalized segment container from this `ctx`
549 pub fn new(ctx
: container
::Ctx
) -> Self {
551 segments
: Vec
::new(),
555 /// Get every section from every segment
556 // thanks to SpaceManic for figuring out the 'b lifetimes here :)
557 pub fn sections
<'b
>(&'b
self) -> Box
<dyn Iterator
<Item
= SectionIterator
<'a
>> + 'b
> {
558 Box
::new(self.segments
.iter().map(|segment
| segment
.into_iter()))