yaxpeax_core/memory/repr/
process.rs

1use goblin;
2use goblin::Object;
3
4use arch::ISA;
5
6use yaxpeax_arch::{Arch, Address, AddressBase, AddressDisplay};
7use memory::repr::FlatMemoryRepr;
8use memory::repr::ReadCursor;
9use memory::{LayoutError, MemoryRange, MemoryRepr, Named, PatchyMemoryRepr};
10use std::ops::Range;
11
12#[derive(Debug)]
13pub struct PESymbol {
14    pub name: String,
15    pub va: u64
16}
17#[derive(Debug)]
18pub struct PEReloc {}
19#[derive(Debug)]
20pub struct PEImport {
21    pub name: String,
22    pub dll: String,
23    ordinal: u16,
24    pub offset: usize,
25    pub rva: usize,
26    size: usize
27}
28impl <'a, 'b> From<&'b goblin::pe::import::Import<'a>> for PEImport {
29    fn from(imp: &'b goblin::pe::import::Import<'a>) -> PEImport {
30        match imp {
31            goblin::pe::import::Import {
32                name,
33                dll,
34                ordinal,
35                offset,
36                rva,
37                size
38            } => {
39                PEImport {
40                    name: name.to_string(),
41                    dll: dll.to_string(),
42                    ordinal: *ordinal,
43                    offset: *offset,
44                    rva: *rva,
45                    size: *size
46                }
47            }
48        }
49    }
50}
51#[derive(Debug)]
52pub enum Reexport {
53    DLLName(String, String),
54    DLLOrdinal(String, usize)
55}
56impl <'a, 'b> From<&'b goblin::pe::export::Reexport<'a>> for Reexport {
57    fn from(reexp: &'b goblin::pe::export::Reexport<'a>) -> Reexport {
58        match reexp {
59            goblin::pe::export::Reexport::DLLName {
60                export,
61                lib
62            } => { Reexport::DLLName(lib.to_string(), export.to_string()) },
63            goblin::pe::export::Reexport::DLLOrdinal {
64                // TODO: goblin claims that dllordinal reexports specify the ordinal is for the dll
65                // name or something? need to look into this..
66                export,
67                ordinal
68            } => { Reexport::DLLOrdinal(export.to_string(), *ordinal) }
69        }
70    }
71}
72#[derive(Debug)]
73pub struct PEExport {
74    pub name: Option<String>,
75    pub offset: usize,
76    pub rva: usize,
77    size: usize,
78    reexport: Option<Reexport>
79}
80impl <'a, 'b> From<&'b goblin::pe::export::Export<'a>> for PEExport {
81    fn from(exp: &'b goblin::pe::export::Export<'a>) -> PEExport {
82        match exp {
83            goblin::pe::export::Export {
84                name,
85                offset,
86                rva,
87                size,
88                reexport
89            } => {
90                PEExport {
91                    name: name.map(|x| x.to_string()),
92                    offset: *offset,
93                    rva: *rva,
94                    size: *size,
95                    reexport: reexport.as_ref().map(|x| x.into())
96                }
97            }
98        }
99    }
100}
101#[derive(Debug)]
102pub struct ELFSymbol {
103    pub name: String,
104    pub section_index: usize,
105    pub addr: u64
106}
107#[derive(Debug)]
108pub struct ELFReloc {}
109#[derive(Debug)]
110pub struct ELFImport {
111    pub name: String,
112    pub section_index: usize,
113    pub value: u64
114}
115#[derive(Clone, Debug)]
116pub struct ELFExport {
117    pub name: String,
118    pub section_index: usize,
119    pub addr: u64,
120}
121
122#[derive(Debug)]
123pub struct Segment {
124    pub start: usize,
125    pub data: Vec<u8>,
126    pub name: String
127}
128
129impl Segment {
130    pub fn contains<A: Address>(&self, addr: A) -> bool {
131        let linear = addr.to_linear();
132        if linear < self.start {
133            false
134        } else if linear - self.start >= self.data.len() {
135            false
136        } else {
137            true
138        }
139    }
140    pub fn start(&self) -> usize {
141        self.start
142    }
143    pub fn end(&self) -> usize {
144        self.start + self.data.len()
145    }
146}
147
148impl Named for Segment {
149    fn name(&self) -> &str {
150        &self.name
151    }
152}
153
154impl <A: Arch> MemoryRepr<A> for Segment {
155    fn read(&self, addr: A::Address) -> Option<u8> {
156        if self.contains(addr) {
157            Some(self.data[addr.to_linear() - self.start])
158        } else {
159            None
160        }
161    }
162    fn as_flat(&self) -> Option<FlatMemoryRepr> {
163        None
164    }
165    fn module_info(&self) -> Option<&ModuleInfo> { None }
166    fn module_for(&self, addr: A::Address) -> Option<&dyn MemoryRepr<A>> {
167        if self.contains(addr) {
168            Some(self)
169        } else {
170            None
171        }
172    }
173    fn size(&self) -> Option<u64> {
174        Some(self.data.len() as u64)
175    }
176    fn start(&self) -> Option<u64> {
177        Some(self.start as u64)
178    }
179}
180
181#[derive(Debug)]
182pub enum ISAHint {
183    Hint(crate::arch::ISA),
184    Unknown(String)
185}
186
187#[derive(Debug)]
188pub struct ELFSection {
189    pub name: String,
190    pub start: u64,
191    pub size: u64,
192}
193
194#[derive(Debug)]
195pub enum ModuleInfo {
196    PE(ISAHint, goblin::pe::header::Header, Vec<goblin::pe::section_table::SectionTable>, u64, Vec<PEReloc>, Vec<PEImport>, Vec<PEExport>, Vec<PESymbol>),
197    ELF(ISAHint, goblin::elf::header::Header, Vec<goblin::elf::program_header::ProgramHeader>, Vec<ELFSection>, u64, Vec<ELFReloc>, Vec<ELFImport>, Vec<ELFExport>, Vec<ELFSymbol>)
198    /*
199     * One day, also MachO, .a, .o, .class, .jar, ...
200     */
201}
202
203impl ModuleInfo {
204    pub fn isa_hint(&self) -> &ISAHint {
205        match self {
206            ModuleInfo::PE(hint, _, _, _, _, _, _, _) |
207            ModuleInfo::ELF(hint, _, _, _, _, _, _, _, _) => {
208                hint
209            }
210        }
211    }
212}
213
214mod elf {
215    pub(crate) mod program_header {
216        pub(crate) fn type_to_str(machine: u16, tpe: u32) -> String {
217            match tpe {
218                goblin::elf::program_header::PT_NULL => "NULL".to_string(),
219                goblin::elf::program_header::PT_LOAD => "LOAD".to_string(),
220                goblin::elf::program_header::PT_DYNAMIC => "DYNAMIC".to_string(),
221                goblin::elf::program_header::PT_INTERP => "INTERP".to_string(),
222                goblin::elf::program_header::PT_NOTE => "NOTE".to_string(),
223                goblin::elf::program_header::PT_SHLIB => "SHLIB".to_string(),
224                goblin::elf::program_header::PT_PHDR => "PHDR".to_string(),
225                goblin::elf::program_header::PT_TLS => "TLS".to_string(),
226                other => {
227                    if other >= goblin::elf::program_header::PT_LOOS && other <= goblin::elf::program_header::PT_HIOS {
228                        // best-effort, try to match any number
229                        match other {
230                            goblin::elf::program_header::PT_GNU_EH_FRAME => {
231                                "GNU_EH_FRAME".to_string()
232                            }
233                            // not in goblin
234                            // goblin::elf::program_header::PT_SUNW_UNWIND => {
235                            0x6464e550 => {
236                                "SUNW_UNWIND".to_string()
237                            }
238                            goblin::elf::program_header::PT_GNU_STACK => {
239                                "GNU_STACK".to_string()
240                            }
241                            goblin::elf::program_header::PT_GNU_RELRO => {
242                                "GNU_RELRO".to_string()
243                            }
244                            // not in goblin
245                            // goblin::elf::program_header::PT_OPENBSD_RANDOMIZE => {
246                            0x65a3dbe6 => {
247                                "OPENBSD_RANDOMIZE".to_string()
248                            }
249                            // goblin::elf::program_header::PT_OPENBSD_WXNEEDED => {
250                            0x65a3dbe7 => {
251                                "OPENBSD_WXNEEDED".to_string()
252                            }
253                            // goblin::elf::program_header::PT_OPENBSD_BOOTDATA => {
254                            0x65a41be6 => {
255                                "OPENBSD_BOOTDATA".to_string()
256                            }
257                            _ => {
258                                format!("unknown OS section type: {:#x}", other)
259                            }
260                        }
261                    } else if other >= goblin::elf::program_header::PT_LOPROC && other <= goblin::elf::program_header::PT_HIPROC {
262                        match (machine, other) {
263                            (goblin::elf::header::EM_ARM, 0x70000000) => {
264                                "ARM_ARCHEXT".to_string()
265                            }
266                            (goblin::elf::header::EM_ARM, 0x70000001) => {
267                                // These contain stack unwind tables.
268                                "ARM_UNWIND".to_string()
269                            }
270                            (goblin::elf::header::EM_MIPS, 0x70000000) => {
271                                // Register usage information.
272                                "MIPS_REGINFO".to_string()
273                            }
274                            (goblin::elf::header::EM_MIPS, 0x70000001) => {
275                                // Runtime procedure table.
276                                "MIPS_RTPROC".to_string()
277                            }
278                            (goblin::elf::header::EM_MIPS, 0x70000002) => {
279                                // Options segment.
280                                "MIPS_OPTIONS".to_string()
281                            }
282                            (goblin::elf::header::EM_MIPS, 0x70000003) => {
283                                // Abiflags segment.
284                                "MIPS_ABIFLAGS".to_string()
285                            }
286                            (machine, other) => {
287                                format!("unknown machine-dependent section type, machine: {:#x} p_type: {:#x}", machine, other)
288                            }
289                        }
290                    } else {
291                        format!("unknown elf section type: {:#x}", other)
292                    }
293                }
294            }
295        }
296    }
297}
298
299fn map_elf_machine(machine: u16) -> ISAHint {
300    match machine {
301        3 => {
302            // IMAGE_FILE_MACHINE_I386
303            ISAHint::Hint(ISA::x86)
304        },
305        20 => {
306            ISAHint::Hint(ISA::PowerPC)
307        },
308        40 => {
309            // ELF doesn't hint at *what kind* of ARM..
310            ISAHint::Hint(ISA::ARM)
311        }
312        41 => {
313            // IMAGE_FILE_MACHINE_ALPHA
314            ISAHint::Hint(ISA::Alpha)
315        },
316        /*
317         * The SuperH chips are interesting because ELF only hints SH, not what revision...
318        42 => {
319            // IMAGE_FILE_MACHINE_SH3
320            ISAHint::Hint(ISA::SH3)
321        },
322        0x01a3 => {
323            // IMAGE_FILE_MACHINE_SH3DSP
324            ISAHint::Hint(ISA::SH3DSP)
325        },
326        0x01a4 => {
327            // IMAGE_FILE_MACHINE_SH3E
328            ISAHint::Hint(ISA::SH3E)
329        },
330        0x01a6 => {
331            // IMAGE_FILE_MACHINE_SH4
332            ISAHint::Hint(ISA::SH4)
333        },
334        0x01a8 => {
335            // IMAGE_FILE_MACHINE_SH5
336            ISAHint::Unknown("SuperH-5 never had shipping hardware...".to_string())
337        },
338        */
339        44 => {
340            // IMAGE_FILE_MACHINE_TRICORE
341            ISAHint::Hint(ISA::Tricore)
342        },
343        50 => {
344            // IMAGE_FILE_MACHINE_IA64
345            ISAHint::Hint(ISA::IA64)
346        },
347        62 => {
348            // IMAGE_FILE_MACHINE_AMD64
349            ISAHint::Hint(ISA::x86_64)
350        },
351        /*
352        0x0162 => {
353            // IMAGE_FILE_MACHINE_R3000
354            // this is specifically MIPS-1?
355            ISAHint::Hint(ISA::MIPS)
356        },
357        0x0166 => {
358            // IMAGE_FILE_MACHINE_R4000
359            // specifically, MIPS-3?
360            ISAHint::Hint(ISA::MIPS)
361        },
362        0x0168 => {
363            // IMAGE_FILE_MACHINE_R10000
364            // specifically, MIPS-4?
365            ISAHint::Hint(ISA::MIPS)
366        },
367        0x0169 => {
368            // IMAGE_FILE_MACHINE_WCEMIPSV2
369            // ???
370            ISAHint::Hint(ISA::MIPS)
371        },
372        */
373        183 => { // this is from osdev.org, because i can't find the actual header!
374            ISAHint::Hint(ISA::AArch64)
375        },
376        magic @ _ => {
377            ISAHint::Unknown(format!("Unknown machine magic: {:#x}", magic))
378        }
379    }
380}
381fn map_pe_machine(machine: u16) -> ISAHint {
382    match machine {
383        0x0000 => {
384            // IMAGE_FILE_MACHINE_UNKNOWN
385            ISAHint::Unknown("PE machine field is 0".to_string())
386        },
387        0x014d => {
388            // IMAGE_FILE_MACHINE_I860
389            ISAHint::Unknown("Okay, I know this is an Intel I860, but I don't know what to do with that.".to_string())
390        },
391        0x014c => {
392            // IMAGE_FILE_MACHINE_I386
393            ISAHint::Hint(ISA::x86)
394        },
395        0x0162 => {
396            // IMAGE_FILE_MACHINE_R3000
397            // this is specifically MIPS-1?
398            ISAHint::Hint(ISA::MIPS)
399        },
400        0x0166 => {
401            // IMAGE_FILE_MACHINE_R4000
402            // specifically, MIPS-3?
403            ISAHint::Hint(ISA::MIPS)
404        },
405        0x0168 => {
406            // IMAGE_FILE_MACHINE_R10000
407            // specifically, MIPS-4?
408            ISAHint::Hint(ISA::MIPS)
409        },
410        0x0169 => {
411            // IMAGE_FILE_MACHINE_WCEMIPSV2
412            // ???
413            ISAHint::Hint(ISA::MIPS)
414        },
415        0x0184 => {
416            // IMAGE_FILE_MACHINE_ALPHA
417            ISAHint::Hint(ISA::Alpha)
418        },
419        0x01a2 => {
420            // IMAGE_FILE_MACHINE_SH3
421            ISAHint::Hint(ISA::SH3)
422        },
423        0x01a3 => {
424            // IMAGE_FILE_MACHINE_SH3DSP
425            ISAHint::Hint(ISA::SH3DSP)
426        },
427        0x01a4 => {
428            // IMAGE_FILE_MACHINE_SH3E
429            ISAHint::Hint(ISA::SH3E)
430        },
431        0x01a6 => {
432            // IMAGE_FILE_MACHINE_SH4
433            ISAHint::Hint(ISA::SH4)
434        },
435        0x01a8 => {
436            // IMAGE_FILE_MACHINE_SH5
437            ISAHint::Unknown("SuperH-5 never had shipping hardware...".to_string())
438        },
439        0x01c0 => {
440            // IMAGE_FILE_MACHINE_ARM
441            ISAHint::Hint(ISA::ARM)
442        },
443        0x01c2 => {
444            // IMAGE_FILE_MACHINE_THUMB
445            ISAHint::Hint(ISA::ARM)
446        },
447        0x01c4 => {
448            // IMAGE_FILE_MACHINE_ARMNT -- windows for ARM Thumb-2 Little-Endian
449            ISAHint::Hint(ISA::ARM)
450        },
451        0x01d3 => {
452            // IMAGE_FILE_MACHINE_AM33
453            ISAHint::Unknown("AM33?".to_string())
454        },
455        0x01f0 => {
456            // IMAGE_FILE_MACHINE_POWERPC
457            ISAHint::Hint(ISA::PowerPC)
458        },
459        0x01f1 => {
460            // IMAGE_FILE_MACHINE_POWERPCFP
461            ISAHint::Hint(ISA::PowerPC)
462        },
463        0x0200 => {
464            // IMAGE_FILE_MACHINE_IA64
465            ISAHint::Hint(ISA::IA64)
466        },
467        0x0266 => {
468            // IMAGE_FILE_MACHINE_MIPS16
469            ISAHint::Hint(ISA::MIPS)
470        },
471        0x0284 => {
472            // IMAGE_FILE_MACHINE_ALPHA64 // aka: AXP64
473            ISAHint::Hint(ISA::Alpha64)
474        },
475        0x0366 => {
476            // IMAGE_FILE_MACHINE_MIPSFPU
477            ISAHint::Hint(ISA::MIPS)
478        },
479        0x0466 => {
480            // IMAGE_FILE_MACHINE_MIPSFPU16
481            ISAHint::Hint(ISA::MIPS)
482        },
483        0x0520 => {
484            // IMAGE_FILE_MACHINE_TRICORE
485            ISAHint::Hint(ISA::Tricore)
486        },
487        0x0cef => {
488            // IMAGE_FILE_MACHINE_CEF
489            // https://blogs.msdn.microsoft.com/mikehall/2004/11/28/remember-cef-common-executable-format/
490            ISAHint::Unknown("Common Executable Format? Sounds fake".to_string())
491        },
492        0x0ebc => {
493            // IMAGE_FILE_MACHINE_EBC
494            ISAHint::Unknown("EBC is unknown".to_string())
495        },
496        0x8664 => {
497            // IMAGE_FILE_MACHINE_AMD64
498            ISAHint::Hint(ISA::x86_64)
499        },
500        0x9041 => {
501            // IMAGE_FILE_MACHINE_M32R
502            ISAHint::Unknown("M32R is unknown".to_string())
503        },
504        0xc0ee => {
505            // IMAGE_FILE_MACHINE_CEE
506            ISAHint::Unknown("CEE is unknown".to_string())
507        },
508        0x01c5 => {
509            // IMAGE_FILE_MACHINE_ARM64 // WINE ONLY
510            ISAHint::Hint(ISA::AArch64)
511        },
512        0xaa64 => {
513            // IMAGE_FILE_MACHINE_ARM64 // Windows 8.1+
514            ISAHint::Hint(ISA::AArch64)
515        },
516        magic @ _ => {
517            ISAHint::Unknown(format!("Unknown machine magic: {:#x}", magic))
518        }
519    }
520}
521
522impl ModuleInfo {
523    pub fn from_goblin(obj: &goblin::Object, _data: &[u8]) -> Option<ModuleInfo> {
524        match obj {
525            Object::PE(pe) => {
526                // From "winnt.h" .. kind of.
527                // https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-tools/widl/include/winnt.h
528                // also
529                // https://docs.microsoft.com/en-us/windows/desktop/sysinfo/image-file-machine-constants
530                // note they disagree on AArch64..
531                let isa = map_pe_machine(pe.header.coff_header.machine);
532
533    // PE(ISAHint, goblin::pe::header::Header, Vec<goblin::pe::section_table::SectionTable>, Vec<PEReloc>, Vec<PEImport>, Vec<PEExport>),
534                Some(ModuleInfo::PE(
535                    isa,
536                    pe.header,
537                    vec![],
538                    pe.header.optional_header.map(|x| x.windows_fields.image_base as usize).unwrap_or(0x400000) as u64,
539                    vec![],
540                    pe.imports.iter().map(|x| x.into()).collect(),
541                    pe.exports.iter().map(|x| x.into()).collect(),
542                    vec![]
543                ))
544            }
545            Object::Elf(elf) => {
546                let imports: Vec<ELFImport> = Vec::new();
547                let mut exports: Vec<ELFExport> = Vec::new();
548                let mut syms: Vec<ELFSymbol> = Vec::new();
549                let mut sections: Vec<ELFSection> = Vec::new();
550                for section in elf.section_headers.iter() {
551                    if section.sh_name == 0 {
552                        continue;
553                    }
554                    sections.push(ELFSection {
555                        name: elf.shdr_strtab.get(section.sh_name).unwrap().unwrap().to_string(),
556                        start: section.sh_addr,
557                        size: section.sh_size,
558                    });
559                }
560                for sym in elf.syms.iter() {
561                    syms.push(ELFSymbol {
562                        name: elf.strtab.get(sym.st_name).unwrap().unwrap().to_string(),
563                        section_index: sym.st_shndx,
564                        addr: sym.st_value
565                    })
566                }
567
568                for dynsym in elf.dynsyms.iter() {
569                    // these are dynamically resolved symbols.
570                    // this is what i'll call an 'import'
571                    //
572                    // if sy_value == 0 it's probably (not necessarily?) a symbol to be referenced
573                    // by a reloc for a .got entry
574                    if dynsym.st_bind() == 1 /* global */ && dynsym.st_type() == 2 /* func */ && dynsym.st_value != 0 /* bad check for "is it a rexport or actually local" */ {
575                        // we have ourselves a bona fide export symbol, maybe? try it on for size.
576                        syms.push(ELFSymbol {
577                            name: elf.dynstrtab.get(dynsym.st_name).unwrap().unwrap().to_string(),
578                            section_index: dynsym.st_shndx,
579                            addr: dynsym.st_value
580                        });
581                        exports.push(ELFExport {
582                            name: elf.dynstrtab.get(dynsym.st_name).unwrap().unwrap().to_string(),
583                            section_index: dynsym.st_shndx,
584                            addr: dynsym.st_value
585                        });
586                    } else {
587                        // got entry, figure this out.
588                    }
589                }
590
591                let isa = map_elf_machine(elf.header.e_machine);
592
593    // PE(ISAHint, goblin::pe::header::Header, Vec<goblin::pe::section_table::SectionTable>, Vec<PEReloc>, Vec<PEImport>, Vec<PEExport>),
594                Some(ModuleInfo::ELF(
595                    isa,
596                    elf.header,
597                    vec![],
598                    sections,
599                    elf.entry,
600                    vec![],
601                    imports,
602                    exports,
603                    //elf.exports.iter().map(|x| x.into()).collect()
604                    syms
605                ))
606            }
607            _ => {
608                None
609            }
610        }
611    }
612}
613
614#[derive(Debug)]
615pub struct ModuleData {
616    pub segments: Vec<Segment>,
617    pub module_info: ModuleInfo,
618    pub name: String
619//    pub headers: Option<goblin::Object<'a>>
620}
621
622impl ModuleData {
623    pub fn load_from(data: &[u8], name: String) -> Option<ModuleData> {
624        match Object::parse(data) {
625            Ok(obj @ Object::Elf(_)) => {
626                let mut module = ModuleData {
627                    segments: vec![],
628                    module_info: ModuleInfo::from_goblin(&obj, data).unwrap(),
629                    name
630                };
631
632                let elf = match obj {
633                    Object::Elf(elf) => elf,
634                    _ => panic!()
635                };
636/*
637                println!("Parsed ELF: {:?}", elf);
638
639                for sym in elf.dynsyms.iter() {
640                    println!("dynsym: {:?}", sym);
641                    println!("Name: {}", elf.dynstrtab.get(sym.st_name).unwrap().unwrap());
642                }
643                for sym in elf.syms.iter() {
644                    println!("sym: {:?}", sym);
645                    println!("Name: {}", elf.strtab.get(sym.st_name).unwrap().unwrap());
646                }
647*/
648                for (i, section) in elf.program_headers.iter().enumerate() {
649                    // TODO: look into cow handles into the actual data
650                    // TODO: actually respect ELF loader behavior w.r.t overlays
651                    // TODO: does this do stuff with alignment or what
652                    let mut section_data = vec![0; section.p_memsz as usize];
653                    tracing::trace!("virtual size: {:#x}, size of raw data: {:#x}", section.p_memsz, section.p_filesz);
654                    tracing::trace!("{:?}", section);
655                    let physical_copy_end = (section.p_offset as usize) + std::cmp::min(section.p_filesz as usize, section.p_memsz as usize);
656                    let copy_size = if physical_copy_end > data.len() {
657                        if (section.p_offset as usize) < data.len() {
658                            data.len() - section.p_offset as usize
659                        } else {
660                            0
661                        }
662                    } else {
663                        std::cmp::min(section.p_filesz as usize, section.p_memsz as usize)
664                    };
665
666                    tracing::trace!("mapping section {} by copying {:#x} bytes starting from {:#x}", i, copy_size, section.p_offset);
667                    tracing::trace!("virtual size is {:#x}", section_data.len());
668                    for i in 0..copy_size {
669                        section_data[i] = data[(section.p_offset as usize) + i];
670                    }
671
672                    let new_section = Segment {
673                        start: section.p_vaddr as usize,
674                        data: section_data,
675                        name: elf::program_header::type_to_str(elf.header.e_machine, section.p_type),
676                    };
677                    tracing::trace!("mapped section {} to [{}, {})",
678                        i,
679                        new_section.start.show(),
680                        (new_section.start as u64 + new_section.data.len() as u64).show()
681                    );
682                    module.segments.push(new_section);
683                }
684                Some(module)
685            },
686            Ok(obj @ Object::PE(_)) => {
687                let mut module = ModuleData {
688                    segments: vec![],
689                    module_info: ModuleInfo::from_goblin(&obj, data).unwrap(),
690                    name
691                };
692
693                let pe = match obj {
694                    Object::PE(pe) => pe,
695                    _ => { unreachable!(); }
696                };
697//                println!("Parsed PE: {:?}", pe);
698
699                for section in pe.sections.iter() {
700                    // TODO: look into cow handles into the actual data
701                    // TODO: actually respect PE loader behavior w.r.t overlays
702                    // TODO: does this do stuff with alignment or what
703                    let mut section_data = vec![0; section.virtual_size as usize];
704//                    println!("virtual size: {:#x}, size of raw data: {:#x}", section.virtual_size, section.size_of_raw_data);
705//                    println!("{:?}", section);
706                    let physical_copy_end = (section.pointer_to_raw_data as usize) + std::cmp::min(section.size_of_raw_data as usize, section.virtual_size as usize);
707                    let copy_size = if physical_copy_end > data.len() {
708                        if (section.pointer_to_raw_data as usize) < data.len() {
709                            data.len() - section.pointer_to_raw_data as usize
710                        } else {
711                            0
712                        }
713                    } else {
714                        std::cmp::min(section.size_of_raw_data as usize, section.virtual_size as usize)
715                    };
716
717                    println!("mapping section \"{}\" by copying {:#x} bytes starting from {:#x}", std::str::from_utf8(&section.name[..]).unwrap(), copy_size, section.pointer_to_raw_data);
718                    println!("virtual size is {:#x}", section_data.len());
719                    for i in 0..copy_size {
720                        section_data[i] = data[(section.pointer_to_raw_data as usize) + i];
721                    }
722
723                    let new_section = Segment {
724                        start: section.virtual_address as usize + pe.header.optional_header.map(|x| x.windows_fields.image_base as usize).unwrap_or(0x400000),
725                        data: section_data,
726                        name: std::str::from_utf8(&section.name[..]).unwrap().to_string()
727                    };
728                    tracing::trace!("mapped {} to [{}, {})",
729                        std::str::from_utf8(&section.name[..]).unwrap(),
730                        new_section.start.show(),
731                        (new_section.start as u64 + new_section.data.len() as u64).show()
732                    );
733                    module.segments.push(new_section);
734                }
735                match &module.module_info {
736                    ModuleInfo::PE(_, _, _, _, _, ref imports, ref _exports, _) => {
737                        for _i in imports.iter() {
738//                            println!("import: {:?}", i);
739                        }
740                    }
741                    _ => { }
742                }
743                Some(module)
744            },
745            Ok(Object::Mach(mach)) => {
746                panic!("Mach objects are not yet supported: {:?}", mach);
747            },
748            Ok(Object::Archive(archive)) => {
749                panic!("AR archives are not yet supported: {:?}", archive);
750            },
751            Ok(Object::Unknown(magic)) => {
752                tracing::warn!("goblin found unknown magic: {:#x}", magic);
753                None
754            },
755            Err(e) => {
756                tracing::error!("goblin error: {:?}", e);
757                None
758            }
759        }
760    }
761    fn segment_for<A: Address>(&self, addr: A) -> Option<&Segment> {
762        for segment in self.segments.iter() {
763            if segment.contains(addr) {
764                return Some(segment);
765            }
766        }
767        None
768    }
769    #[allow(dead_code)]
770    fn segment_after(&self, _segment: &Segment) -> Option<&Segment> {
771        unreachable!()
772    }
773}
774
775impl <A: Arch> MemoryRepr<A> for ModuleData where Segment: MemoryRepr<A> {
776    fn read(&self, addr: A::Address) -> Option<u8> {
777        self.segment_for(addr).and_then(|segment| segment.read(addr))
778    }
779    fn as_flat(&self) -> Option<FlatMemoryRepr> {
780        None
781    }
782    fn module_info(&self) -> Option<&ModuleInfo> { Some(&self.module_info) }
783    fn module_for(&self, addr: A::Address) -> Option<&dyn MemoryRepr<A>> {
784        if self.segment_for(addr).is_some() {
785            Some(self)
786        } else {
787            None
788        }
789    }
790    fn size(&self) -> Option<u64> {
791        match ((self as &dyn MemoryRepr<A>).end(), (self as &dyn MemoryRepr<A>).start()) {
792            (Some(end), Some(start)) => {
793                Some(end - start)
794            }
795            _ => None
796        }
797    }
798    fn end(&self) -> Option<u64> {
799        self.segments.iter().map(|s| s.end()).max().map(|x| x as u64)
800    }
801    fn start(&self) -> Option<u64> {
802        self.segments.iter().map(|s| s.start()).min().map(|x| x as u64)
803    }
804}
805
806impl Named for ModuleData {
807    fn name(&self) -> &str {
808        &self.name
809    }
810}
811
812impl <A: Arch> MemoryRange<A> for Segment {
813    fn range<'a>(&'a self, range: Range<A::Address>) -> Option<ReadCursor<'a, A, Self>> {
814        if self.contains(range.start) && self.contains(range.end) {
815            // TODO: return the section itself to avoid double lookups
816            Some(ReadCursor::from(self, range.start, Some(range.end)))
817        } else {
818            // TODO: this range may intersect with multiple sections
819            None
820        }
821    }
822    fn range_from<'a>(&'a self, start: A::Address) -> Option<ReadCursor<'a, A, Self>> {
823        Some(ReadCursor::from(self, start, None))
824    }
825}
826
827impl <A: Arch> MemoryRange<A> for ModuleData {
828    fn range<'a>(&'a self, range: Range<A::Address>) -> Option<ReadCursor<'a, A, Self>> {
829        self.segment_for(range.start).and_then(|section| {
830            if section.contains(range.end) {
831                // TODO: return the section itself to avoid double lookups
832                Some(ReadCursor::from(self, range.start, Some(range.end)))
833            } else {
834                // TODO: this range may intersect with multiple sections
835                None
836            }
837        })
838    }
839    fn range_from<'a>(&'a self, start: A::Address) -> Option<ReadCursor<'a, A, Self>> {
840        self.segment_for(start).map(|_segment| ReadCursor::from(self, start, None))
841    }
842}
843
844#[derive(Debug)]
845pub struct ProcessMemoryRepr {
846    pub modules: Vec<ModuleData>
847}
848
849impl <A: Arch> MemoryRepr<A> for ProcessMemoryRepr where ModuleData: MemoryRepr<A> {
850    fn read(&self, addr: A::Address) -> Option<u8> {
851        // TODO: Overlap is not considered correctly here.
852        for module in self.modules.iter() {
853            match module.read(addr) {
854                Some(data) => { return Some(data); },
855                None => ()
856            }
857        }
858        return None
859    }
860    fn as_flat(&self) -> Option<FlatMemoryRepr> {
861        None
862    }
863    fn module_info(&self) -> Option<&ModuleInfo> { /* TODO: how to get one specific moduleinfo? or should all of them get merged? */ None }
864    fn module_for(&self, addr: A::Address) -> Option<&dyn MemoryRepr<A>> {
865        for module in self.modules.iter() {
866            if module.segment_for(addr).is_some() {
867                return Some(module)
868            }
869        }
870        None
871    }
872    fn size(&self) -> Option<u64> {
873        Some(self.modules.iter().map(|m| <ModuleData as MemoryRepr<A>>::size(m).unwrap()).sum())
874    }
875}
876
877impl Named for ProcessMemoryRepr {
878    fn name(&self) -> &str {
879        "process"
880    }
881}
882
883impl <A: Arch> PatchyMemoryRepr<A> for ProcessMemoryRepr {
884    fn add(&mut self, _data: Vec<u8>, _addr: A::Address) -> Result<(), LayoutError> {
885        Err(LayoutError::Unsupported)
886    }
887}
888
889impl <A: Arch> MemoryRange<A> for ProcessMemoryRepr {
890    // TODO:
891    fn range<'a>(&'a self, range: Range<A::Address>) -> Option<ReadCursor<'a, A, Self>> {
892//        if range.start.to_linear() < self.data.len() && range.end.to_linear() < self.data.len() && range.start < range.end {
893            Some(ReadCursor::from(self, range.start, Some(range.end)))
894                /*
895            Some(ReadCursor {
896                data: self,
897                start: range.start,
898                end: range.end
899            })
900            */
901//        } else {
902//            None
903//        }
904    }
905    // TODO:
906    fn range_from<'a>(&'a self, start: A::Address) -> Option<ReadCursor<'a, A, Self>> {
907//        if range.start.to_linear() < self.data.len() && range.end.to_linear() < self.data.len() && range.start < range.end {
908            Some(ReadCursor::from(self, start, None))
909//        } else {
910//            None
911//        }
912    }
913}
914