1 use scroll::{Pread, Pwrite};
2 use scroll::ctx::{self, SizeWith};
3 
4 use log::{debug, warn};
5 
6 use core::fmt;
7 use core::ops::{Deref, DerefMut};
8 use crate::alloc::boxed::Box;
9 use crate::alloc::vec::Vec;
10 
11 use crate::container;
12 use crate::error;
13 
14 use crate::mach::relocation::RelocationInfo;
15 use crate::mach::load_command::{Section32, Section64, SegmentCommand32, SegmentCommand64, SIZEOF_SECTION_32, SIZEOF_SECTION_64, SIZEOF_SEGMENT_COMMAND_32, SIZEOF_SEGMENT_COMMAND_64, LC_SEGMENT, LC_SEGMENT_64};
16 
17 pub struct RelocationIterator<'a> {
18     data: &'a [u8],
19     nrelocs: usize,
20     offset: usize,
21     count: usize,
22     ctx: scroll::Endian,
23 }
24 
25 impl<'a> Iterator for RelocationIterator<'a> {
26     type Item = error::Result<RelocationInfo>;
next(&mut self) -> Option<Self::Item>27     fn next(&mut self) -> Option<Self::Item> {
28         if self.count >= self.nrelocs {
29             None
30         } else {
31             self.count += 1;
32             match self.data.gread_with(&mut self.offset, self.ctx) {
33                 Ok(res) => Some(Ok(res)),
34                 Err(e) => Some(Err(e.into()))
35             }
36         }
37     }
38 }
39 
40 /// Generalized 32/64 bit Section
41 #[derive(Default)]
42 pub struct Section {
43     /// name of this section
44     pub sectname:  [u8; 16],
45     /// segment this section goes in
46     pub segname:   [u8; 16],
47     /// memory address of this section
48     pub addr:      u64,
49     /// size in bytes of this section
50     pub size:      u64,
51     /// file offset of this section
52     pub offset:    u32,
53     /// section alignment (power of 2)
54     pub align:     u32,
55     /// file offset of relocation entries
56     pub reloff:    u32,
57     /// number of relocation entries
58     pub nreloc:    u32,
59     /// flags (section type and attributes
60     pub flags:     u32,
61 }
62 
63 impl Section {
64     /// The name of this section
name(&self) -> error::Result<&str>65     pub fn name(&self) -> error::Result<&str> {
66         Ok(self.sectname.pread::<&str>(0)?)
67     }
68     /// The containing segment's name
segname(&self) -> error::Result<&str>69     pub fn segname(&self) -> error::Result<&str> {
70         Ok(self.segname.pread::<&str>(0)?)
71     }
72     /// Iterate this sections relocations given `data`; `data` must be the original binary
iter_relocations<'b>(&self, data: &'b [u8], ctx: container::Ctx) -> RelocationIterator<'b>73     pub fn iter_relocations<'b>(&self, data: &'b [u8], ctx: container::Ctx) -> RelocationIterator<'b> {
74         let offset = self.reloff as usize;
75         debug!("Relocations for {} starting at offset: {:#x}", self.name().unwrap_or("BAD_SECTION_NAME"), offset);
76         RelocationIterator {
77             offset,
78             nrelocs: self.nreloc as usize,
79             count: 0,
80             data,
81             ctx: ctx.le,
82         }
83     }
84 }
85 
86 impl From<Section> for Section64 {
from(section: Section) -> Self87     fn from(section: Section) -> Self {
88         Section64 {
89             sectname: section.sectname,
90             segname:  section.segname,
91             addr:     section.addr as u64,
92             size:     section.size as u64,
93             offset:   section.offset,
94             align:    section.align,
95             reloff:   section.reloff,
96             nreloc:   section.nreloc,
97             flags:    section.flags,
98             reserved1: 0,
99             reserved2: 0,
100             reserved3: 0,
101         }
102     }
103 }
104 
105 impl From<Section> for Section32 {
from(section: Section) -> Self106     fn from(section: Section) -> Self {
107         Section32 {
108             sectname: section.sectname,
109             segname:  section.segname,
110             addr:     section.addr as u32,
111             size:     section.size as u32,
112             offset:   section.offset,
113             align:    section.align,
114             reloff:   section.reloff,
115             nreloc:   section.nreloc,
116             flags:    section.flags,
117             reserved1: 0,
118             reserved2: 0,
119         }
120     }
121 }
122 
123 impl fmt::Debug for Section {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result124     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
125         fmt.debug_struct("Section")
126             .field("sectname", &self.name().unwrap())
127             .field("segname",  &self.segname().unwrap())
128             .field("addr",     &self.addr)
129             .field("size",     &self.size)
130             .field("offset",   &self.offset)
131             .field("align",    &self.align)
132             .field("reloff",   &self.reloff)
133             .field("nreloc",   &self.nreloc)
134             .field("flags",    &self.flags)
135             .finish()
136     }
137 }
138 
139 impl From<Section32> for Section {
from(section: Section32) -> Self140     fn from(section: Section32) -> Self {
141         Section {
142             sectname: section.sectname,
143             segname:  section.segname,
144             addr:     u64::from(section.addr),
145             size:     u64::from(section.size),
146             offset:   section.offset,
147             align:    section.align,
148             reloff:   section.reloff,
149             nreloc:   section.nreloc,
150             flags:    section.flags,
151         }
152     }
153 }
154 
155 impl From<Section64> for Section {
from(section: Section64) -> Self156     fn from(section: Section64) -> Self {
157         Section {
158             sectname: section.sectname,
159             segname:  section.segname,
160             addr:     section.addr,
161             size:     section.size,
162             offset:   section.offset,
163             align:    section.align,
164             reloff:   section.reloff,
165             nreloc:   section.nreloc,
166             flags:    section.flags,
167         }
168     }
169 }
170 
171 impl<'a> ctx::TryFromCtx<'a, container::Ctx> for Section {
172     type Error = crate::error::Error;
173     type Size = usize;
try_from_ctx(bytes: &'a [u8], ctx: container::Ctx) -> Result<(Self, Self::Size), Self::Error>174     fn try_from_ctx(bytes: &'a [u8], ctx: container::Ctx) -> Result<(Self, Self::Size), Self::Error> {
175         match ctx.container {
176             container::Container::Little => {
177                 let section = Section::from(bytes.pread_with::<Section32>(0, ctx.le)?);
178                 Ok((section, SIZEOF_SECTION_32))
179             },
180             container::Container::Big    => {
181                 let section = Section::from(bytes.pread_with::<Section64>(0, ctx.le)?);
182                 Ok((section, SIZEOF_SECTION_64))
183             },
184         }
185     }
186 }
187 
188 impl ctx::SizeWith<container::Ctx> for Section {
189     type Units = usize;
size_with(ctx: &container::Ctx) -> usize190     fn size_with(ctx: &container::Ctx) -> usize {
191         match ctx.container {
192             container::Container::Little => SIZEOF_SECTION_32,
193             container::Container::Big    => SIZEOF_SECTION_64,
194         }
195     }
196 }
197 
198 impl ctx::TryIntoCtx<container::Ctx> for Section {
199     type Error = crate::error::Error;
200     type Size = usize;
try_into_ctx(self, bytes: &mut [u8], ctx: container::Ctx) -> Result<Self::Size, Self::Error>201     fn try_into_ctx(self, bytes: &mut [u8], ctx: container::Ctx) -> Result<Self::Size, Self::Error> {
202         if ctx.is_big () {
203             bytes.pwrite_with::<Section64>(self.into(), 0, ctx.le)?;
204         } else {
205             bytes.pwrite_with::<Section32>(self.into(), 0, ctx.le)?;
206         }
207         Ok(Self::size_with(&ctx))
208     }
209 }
210 
211 impl ctx::IntoCtx<container::Ctx> for Section {
into_ctx(self, bytes: &mut [u8], ctx: container::Ctx)212     fn into_ctx(self, bytes: &mut [u8], ctx: container::Ctx) {
213         bytes.pwrite_with(self, 0, ctx).unwrap();
214     }
215 }
216 
217 pub struct SectionIterator<'a> {
218     data: &'a [u8],
219     count: usize,
220     offset: usize,
221     idx: usize,
222     ctx: container::Ctx,
223 }
224 
225 pub type SectionData<'a> = &'a [u8];
226 
227 impl<'a> ::core::iter::ExactSizeIterator for SectionIterator<'a> {
len(&self) -> usize228     fn len(&self) -> usize {
229         self.count
230     }
231 }
232 
233 impl<'a> Iterator for SectionIterator<'a> {
234     type Item = error::Result<(Section, SectionData<'a>)>;
next(&mut self) -> Option<Self::Item>235     fn next(&mut self) -> Option<Self::Item> {
236         if self.idx >= self.count {
237             None
238         } else {
239             self.idx += 1;
240             match self.data.gread_with::<Section>(&mut self.offset, self.ctx) {
241                 Ok(section) => {
242                     // it's not uncommon to encounter macho files where files are
243                     // truncated but the sections are still remaining in the header.
244                     // Because of this we want to not panic here but instead just
245                     // slice down to a empty data slice.  This way only if code
246                     // actually needs to access those sections it will fall over.
247                     let data = self.data
248                         .get(section.offset as usize..)
249                         .unwrap_or_else(|| {
250                             warn!("section #{} offset {} out of bounds", self.idx, section.offset);
251                             &[]
252                         })
253                         .get(..section.size as usize)
254                         .unwrap_or_else(|| {
255                             warn!("section #{} size {} out of bounds", self.idx, section.size);
256                             &[]
257                         });
258                     Some(Ok((section, data)))
259                 },
260                 Err(e) => Some(Err(e))
261             }
262         }
263     }
264 }
265 
266 impl<'a, 'b> IntoIterator for &'b Segment<'a> {
267     type Item = error::Result<(Section, SectionData<'a>)>;
268     type IntoIter = SectionIterator<'a>;
into_iter(self) -> Self::IntoIter269     fn into_iter(self) -> Self::IntoIter {
270         SectionIterator {
271             data: self.raw_data,
272             count: self.nsects as usize,
273             offset: self.offset + Segment::size_with(&self.ctx),
274             idx: 0,
275             ctx: self.ctx,
276         }
277     }
278 }
279 
280 /// Generalized 32/64 bit Segment Command
281 pub struct Segment<'a> {
282     pub cmd:      u32,
283     pub cmdsize:  u32,
284     pub segname:  [u8; 16],
285     pub vmaddr:   u64,
286     pub vmsize:   u64,
287     pub fileoff:  u64,
288     pub filesize: u64,
289     pub maxprot:  u32,
290     pub initprot: u32,
291     pub nsects:   u32,
292     pub flags:    u32,
293     pub data:     &'a [u8],
294     offset:       usize,
295     raw_data:     &'a [u8],
296     ctx:          container::Ctx,
297 }
298 
299 impl<'a> From<Segment<'a>> for SegmentCommand64 {
from(segment: Segment<'a>) -> Self300     fn from(segment: Segment<'a>) -> Self {
301         SegmentCommand64 {
302             cmd:      segment.cmd,
303             cmdsize:  segment.cmdsize,
304             segname:  segment.segname,
305             vmaddr:   segment.vmaddr   as u64,
306             vmsize:   segment.vmsize   as u64,
307             fileoff:  segment.fileoff  as u64,
308             filesize: segment.filesize as u64,
309             maxprot:  segment.maxprot,
310             initprot: segment.initprot,
311             nsects:   segment.nsects,
312             flags:    segment.flags,
313         }
314     }
315 }
316 
317 impl<'a> From<Segment<'a>> for SegmentCommand32 {
from(segment: Segment<'a>) -> Self318     fn from(segment: Segment<'a>) -> Self {
319         SegmentCommand32 {
320             cmd:      segment.cmd,
321             cmdsize:  segment.cmdsize,
322             segname:  segment.segname,
323             vmaddr:   segment.vmaddr   as u32,
324             vmsize:   segment.vmsize   as u32,
325             fileoff:  segment.fileoff  as u32,
326             filesize: segment.filesize as u32,
327             maxprot:  segment.maxprot,
328             initprot: segment.initprot,
329             nsects:   segment.nsects,
330             flags:    segment.flags,
331         }
332     }
333 }
334 
335 impl<'a> fmt::Debug for Segment<'a> {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result336     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
337         fmt.debug_struct("Segment")
338             .field("cmd", &self.cmd)
339             .field("cmdsize", &self.cmdsize)
340             .field("segname", &self.segname.pread::<&str>(0).unwrap())
341             .field("vmaddr",  &self.vmaddr)
342             .field("vmsize",  &self.vmsize)
343             .field("fileoff", &self.fileoff)
344             .field("filesize", &self.filesize)
345             .field("maxprot", &self.maxprot)
346             .field("initprot", &self.initprot)
347             .field("nsects", &self.nsects)
348             .field("flags", &self.flags)
349             .field("data", &self.data.len())
350             .field("sections()", &self.sections().map(|sections|
351                 sections.into_iter().map(|(section,_)| section).collect::<Vec<_>>())
352             )
353             .finish()
354     }
355 }
356 
357 impl<'a> ctx::SizeWith<container::Ctx> for Segment<'a> {
358     type Units = usize;
size_with(ctx: &container::Ctx) -> usize359     fn size_with(ctx: &container::Ctx) -> usize {
360         match ctx.container {
361             container::Container::Little => SIZEOF_SEGMENT_COMMAND_32,
362             container::Container::Big    => SIZEOF_SEGMENT_COMMAND_64,
363         }
364     }
365 }
366 
367 impl<'a> ctx::TryIntoCtx<container::Ctx> for Segment<'a> {
368     type Error = crate::error::Error;
369     type Size = usize;
try_into_ctx(self, bytes: &mut [u8], ctx: container::Ctx) -> Result<Self::Size, Self::Error>370     fn try_into_ctx(self, bytes: &mut [u8], ctx: container::Ctx) -> Result<Self::Size, Self::Error> {
371         let segment_size = Self::size_with(&ctx);
372         // should be able to write the section data inline after this, but not working at the moment
373         //let section_size = bytes.pwrite(data, segment_size)?;
374         //debug!("Segment size: {} raw section data size: {}", segment_size, data.len());
375         if ctx.is_big () {
376             bytes.pwrite_with::<SegmentCommand64>(self.into(), 0, ctx.le)?;
377         } else {
378             bytes.pwrite_with::<SegmentCommand32>(self.into(), 0, ctx.le)?;
379         }
380         //debug!("Section size: {}", section_size);
381         Ok(segment_size)
382     }
383 }
384 
385 impl<'a> ctx::IntoCtx<container::Ctx> for Segment<'a> {
into_ctx(self, bytes: &mut [u8], ctx: container::Ctx)386     fn into_ctx(self, bytes: &mut [u8], ctx: container::Ctx) {
387         bytes.pwrite_with(self, 0, ctx).unwrap();
388     }
389 }
390 
391 /// Read data that belongs to a segment if the offset is within the boundaries of bytes.
segment_data(bytes: &[u8], fileoff :u64, filesize :u64) -> Result<&[u8], error::Error>392 fn segment_data(bytes: &[u8], fileoff :u64, filesize :u64) -> Result<&[u8], error::Error> {
393     let data :&[u8] = if filesize != 0 {
394         bytes.pread_with(fileoff as usize, filesize as usize)?
395     } else {
396         &[]
397     };
398     Ok(data)
399 }
400 
401 impl<'a> Segment<'a> {
402     /// Create a new, blank segment, with cmd either `LC_SEGMENT_64`, or `LC_SEGMENT`, depending on `ctx`.
403     /// **NB** You are responsible for providing a correctly marshalled byte array as the sections. You should not use this for anything other than writing.
new(ctx: container::Ctx, sections: &'a [u8]) -> Self404     pub fn new(ctx: container::Ctx, sections: &'a [u8]) -> Self {
405         Segment {
406             cmd:      if ctx.is_big() { LC_SEGMENT_64 } else { LC_SEGMENT },
407             cmdsize:  (Self::size_with(&ctx) + sections.len()) as u32,
408             segname:  [0; 16],
409             vmaddr:   0,
410             vmsize:   0,
411             fileoff:  0,
412             filesize: 0,
413             maxprot:  0,
414             initprot: 0,
415             nsects:   0,
416             flags:    0,
417             data:     sections,
418             offset:   0,
419             raw_data: &[],
420             ctx,
421         }
422     }
423     /// Get the name of this segment
name(&self) -> error::Result<&str>424     pub fn name(&self) -> error::Result<&str> {
425         Ok(self.segname.pread::<&str>(0)?)
426     }
427     /// Get the sections from this segment, erroring if any section couldn't be retrieved
sections(&self) -> error::Result<Vec<(Section, SectionData<'a>)>>428     pub fn sections(&self) -> error::Result<Vec<(Section, SectionData<'a>)>> {
429         let mut sections = Vec::new();
430         for section in self.into_iter() {
431             sections.push(section?);
432         }
433         Ok(sections)
434     }
435     /// Convert the raw C 32-bit segment command to a generalized version
from_32(bytes: &'a[u8], segment: &SegmentCommand32, offset: usize, ctx: container::Ctx) -> Result<Self, error::Error>436     pub fn from_32(bytes: &'a[u8], segment: &SegmentCommand32, offset: usize, ctx: container::Ctx) -> Result<Self, error::Error> {
437         Ok(Segment {
438             cmd:      segment.cmd,
439             cmdsize:  segment.cmdsize,
440             segname:  segment.segname,
441             vmaddr:   u64::from(segment.vmaddr),
442             vmsize:   u64::from(segment.vmsize),
443             fileoff:  u64::from(segment.fileoff),
444             filesize: u64::from(segment.filesize),
445             maxprot:  segment.maxprot,
446             initprot: segment.initprot,
447             nsects:   segment.nsects,
448             flags:    segment.flags,
449             data: segment_data(bytes, segment.fileoff as u64, segment.filesize as u64)?,
450             offset,
451             raw_data: bytes,
452             ctx,
453         })
454     }
455     /// Convert the raw C 64-bit segment command to a generalized version
from_64(bytes: &'a [u8], segment: &SegmentCommand64, offset: usize, ctx: container::Ctx) -> Result<Self, error::Error>456     pub fn from_64(bytes: &'a [u8], segment: &SegmentCommand64, offset: usize, ctx: container::Ctx) -> Result<Self, error::Error> {
457         Ok(Segment {
458             cmd:      segment.cmd,
459             cmdsize:  segment.cmdsize,
460             segname:  segment.segname,
461             vmaddr:   segment.vmaddr,
462             vmsize:   segment.vmsize,
463             fileoff:  segment.fileoff,
464             filesize: segment.filesize,
465             maxprot:  segment.maxprot,
466             initprot: segment.initprot,
467             nsects:   segment.nsects,
468             flags:    segment.flags,
469             data: segment_data(bytes, segment.fileoff, segment.filesize)?,
470             offset,
471             raw_data: bytes,
472             ctx,
473         })
474     }
475 }
476 
477 #[derive(Debug, Default)]
478 /// An opaque 32/64-bit container for Mach-o segments
479 pub struct Segments<'a> {
480     segments: Vec<Segment<'a>>,
481     ctx: container::Ctx,
482 }
483 
484 impl<'a> Deref for Segments<'a> {
485     type Target = Vec<Segment<'a>>;
deref(&self) -> &Self::Target486     fn deref(&self) -> &Self::Target {
487         &self.segments
488     }
489 }
490 
491 impl<'a> DerefMut for Segments<'a> {
deref_mut(&mut self) -> &mut Self::Target492     fn deref_mut(&mut self) -> &mut Self::Target {
493         &mut self.segments
494     }
495 }
496 
497 impl<'a, 'b> IntoIterator for &'b Segments<'a> {
498     type Item = &'b Segment<'a>;
499     type IntoIter = ::core::slice::Iter<'b, Segment<'a>>;
into_iter(self) -> Self::IntoIter500     fn into_iter(self) -> Self::IntoIter {
501         self.segments.iter()
502     }
503 }
504 
505 impl<'a> Segments<'a> {
506     /// Construct a new generalized segment container from this `ctx`
new(ctx: container::Ctx) -> Self507     pub fn new(ctx: container::Ctx) -> Self {
508         Segments {
509             segments: Vec::new(),
510             ctx,
511         }
512     }
513     /// Get every section from every segment
514     // thanks to SpaceManic for figuring out the 'b lifetimes here :)
sections<'b>(&'b self) -> Box<Iterator<Item=SectionIterator<'a>> + 'b>515     pub fn sections<'b>(&'b self) -> Box<Iterator<Item=SectionIterator<'a>> + 'b> {
516         Box::new(self.segments.iter().map(|segment| segment.into_iter()))
517     }
518 }
519