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