Skip to main content

goblin/pe/
export.rs

1use alloc::vec::Vec;
2use scroll::{Pread, Pwrite};
3
4use log::debug;
5
6use crate::error;
7
8use crate::pe::data_directories;
9use crate::pe::options;
10use crate::pe::section_table;
11use crate::pe::utils;
12
13#[repr(C)]
14#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite)]
15pub struct ExportDirectoryTable {
16    pub export_flags: u32,
17    pub time_date_stamp: u32,
18    pub major_version: u16,
19    pub minor_version: u16,
20    pub name_rva: u32,
21    pub ordinal_base: u32,
22    pub address_table_entries: u32,
23    pub number_of_name_pointers: u32,
24    pub export_address_table_rva: u32,
25    pub name_pointer_rva: u32,
26    pub ordinal_table_rva: u32,
27}
28
29pub const SIZEOF_EXPORT_DIRECTORY_TABLE: usize = 40;
30
31impl ExportDirectoryTable {
32    pub fn parse(bytes: &[u8], offset: usize) -> error::Result<Self> {
33        let res = bytes.pread_with(offset, scroll::LE)?;
34        Ok(res)
35    }
36}
37
38#[derive(Debug)]
39pub enum ExportAddressTableEntry {
40    ExportRVA(u32),
41    ForwarderRVA(u32),
42}
43
44pub const SIZEOF_EXPORT_ADDRESS_TABLE_ENTRY: usize = 4;
45
46pub type ExportAddressTable = Vec<ExportAddressTableEntry>;
47
48/// Array of rvas into the export name table
49///
50/// Export name is defined iff pointer table has pointer to the name
51pub type ExportNamePointerTable = Vec<u32>;
52
53/// Array of indexes into the export address table.
54///
55/// Should obey the formula `idx = ordinal - ordinalbase`
56pub type ExportOrdinalTable = Vec<u16>;
57
58#[derive(Debug, Default)]
59/// Export data contains the `dll` name which other libraries can import symbols by (two-level namespace), as well as other important indexing data allowing symbol lookups
60pub struct ExportData<'a> {
61    pub name: Option<&'a str>,
62    pub export_directory_table: ExportDirectoryTable,
63    pub export_name_pointer_table: ExportNamePointerTable,
64    pub export_ordinal_table: ExportOrdinalTable,
65    pub export_address_table: ExportAddressTable,
66}
67
68impl<'a> ExportData<'a> {
69    pub fn parse(
70        bytes: &'a [u8],
71        dd: data_directories::DataDirectory,
72        sections: &[section_table::SectionTable],
73        file_alignment: u32,
74    ) -> error::Result<ExportData<'a>> {
75        Self::parse_with_opts(
76            bytes,
77            dd,
78            sections,
79            file_alignment,
80            &options::ParseOptions::default(),
81        )
82    }
83
84    pub fn parse_with_opts(
85        bytes: &'a [u8],
86        dd: data_directories::DataDirectory,
87        sections: &[section_table::SectionTable],
88        file_alignment: u32,
89        opts: &options::ParseOptions,
90    ) -> error::Result<ExportData<'a>> {
91        let export_rva = dd.virtual_address as usize;
92        let size = dd.size as usize;
93        debug!("export_rva {:#x} size {:#}", export_rva, size);
94        let export_offset = utils::find_offset_or(
95            export_rva,
96            sections,
97            file_alignment,
98            opts,
99            &format!("cannot map export_rva ({:#x}) into offset", export_rva),
100        )?;
101        let export_directory_table =
102            ExportDirectoryTable::parse(bytes, export_offset).map_err(|_| {
103                error::Error::Malformed(format!(
104                    "cannot parse export_directory_table (offset {:#x})",
105                    export_offset
106                ))
107            })?;
108        let number_of_name_pointers = export_directory_table.number_of_name_pointers as usize;
109        let address_table_entries = export_directory_table.address_table_entries as usize;
110
111        if number_of_name_pointers > bytes.len() {
112            return Err(error::Error::BufferTooShort(
113                number_of_name_pointers,
114                "name pointers",
115            ));
116        }
117        if address_table_entries > bytes.len() {
118            return Err(error::Error::BufferTooShort(
119                address_table_entries,
120                "address table entries",
121            ));
122        }
123
124        let export_name_pointer_table = utils::find_offset(
125            export_directory_table.name_pointer_rva as usize,
126            sections,
127            file_alignment,
128            opts,
129        )
130        .map_or(vec![], |table_offset| {
131            let mut offset = table_offset;
132            let mut table: ExportNamePointerTable = Vec::with_capacity(number_of_name_pointers);
133
134            for _ in 0..number_of_name_pointers {
135                if let Ok(name_rva) = bytes.gread_with(&mut offset, scroll::LE) {
136                    table.push(name_rva);
137                } else {
138                    break;
139                }
140            }
141
142            table
143        });
144
145        let export_ordinal_table = utils::find_offset(
146            export_directory_table.ordinal_table_rva as usize,
147            sections,
148            file_alignment,
149            opts,
150        )
151        .map_or(vec![], |table_offset| {
152            let mut offset = table_offset;
153            let mut table: ExportOrdinalTable = Vec::with_capacity(number_of_name_pointers);
154
155            for _ in 0..number_of_name_pointers {
156                if let Ok(name_ordinal) = bytes.gread_with(&mut offset, scroll::LE) {
157                    table.push(name_ordinal);
158                } else {
159                    break;
160                }
161            }
162
163            table
164        });
165
166        let export_address_table = utils::find_offset(
167            export_directory_table.export_address_table_rva as usize,
168            sections,
169            file_alignment,
170            opts,
171        )
172        .map_or(vec![], |table_offset| {
173            let mut offset = table_offset;
174            let mut table: ExportAddressTable = Vec::with_capacity(address_table_entries);
175            let export_end = export_rva + size;
176
177            for _ in 0..address_table_entries {
178                if let Ok(func_rva) = bytes.gread_with::<u32>(&mut offset, scroll::LE) {
179                    if utils::is_in_range(func_rva as usize, export_rva, export_end) {
180                        table.push(ExportAddressTableEntry::ForwarderRVA(func_rva));
181                    } else {
182                        table.push(ExportAddressTableEntry::ExportRVA(func_rva));
183                    }
184                } else {
185                    break;
186                }
187            }
188
189            table
190        });
191
192        let name = utils::find_offset(
193            export_directory_table.name_rva as usize,
194            sections,
195            file_alignment,
196            opts,
197        )
198        .and_then(|offset| bytes.pread(offset).ok());
199
200        Ok(ExportData {
201            name,
202            export_directory_table,
203            export_name_pointer_table,
204            export_ordinal_table,
205            export_address_table,
206        })
207    }
208}
209
210#[derive(Debug)]
211/// PE binaries have two kinds of reexports, either specifying the dll's name, or the ordinal value of the dll
212pub enum Reexport<'a> {
213    DLLName { export: &'a str, lib: &'a str },
214    DLLOrdinal { ordinal: usize, lib: &'a str },
215}
216
217impl<'a> scroll::ctx::TryFromCtx<'a, scroll::Endian> for Reexport<'a> {
218    type Error = crate::error::Error;
219    #[inline]
220    fn try_from_ctx(bytes: &'a [u8], _ctx: scroll::Endian) -> Result<(Self, usize), Self::Error> {
221        let reexport = bytes.pread::<&str>(0)?;
222        let reexport_len = reexport.len();
223        debug!("reexport: {}", &reexport);
224        for o in 0..reexport_len {
225            let c: u8 = bytes.pread(o)?;
226            debug!("reexport offset: {:#x} char: {:#x}", o, c);
227            if c == b'.' {
228                let dll: &'a str = bytes.pread_with(0, scroll::ctx::StrCtx::Length(o))?;
229                debug!("dll: {:?}", &dll);
230                if o + 1 == reexport_len {
231                    break;
232                }
233                let len = reexport_len - o - 1;
234                let rest: &'a [u8] = bytes.pread_with(o + 1, len)?;
235                debug!("rest: {:?}", &rest);
236                if rest[0] == b'#' {
237                    let ordinal =
238                        rest.pread_with::<&str>(1, scroll::ctx::StrCtx::Length(len - 1))?;
239                    let ordinal = ordinal.parse::<u32>().map_err(|_e| {
240                        error::Error::Malformed(format!(
241                            "Cannot parse reexport ordinal from {} bytes",
242                            bytes.len()
243                        ))
244                    })?;
245                    return Ok((
246                        Reexport::DLLOrdinal {
247                            ordinal: ordinal as usize,
248                            lib: dll,
249                        },
250                        reexport_len + 1,
251                    ));
252                } else {
253                    let export = rest.pread_with::<&str>(0, scroll::ctx::StrCtx::Length(len))?;
254                    return Ok((Reexport::DLLName { export, lib: dll }, reexport_len + 1));
255                }
256            }
257        }
258        Err(error::Error::Malformed(format!(
259            "Reexport {:#} is malformed",
260            reexport
261        )))
262    }
263}
264
265impl<'a> Reexport<'a> {
266    pub fn parse(bytes: &'a [u8], offset: usize) -> crate::error::Result<Reexport<'a>> {
267        bytes.pread(offset)
268    }
269}
270
271#[derive(Debug, Default)]
272/// An exported symbol in this binary, contains synthetic data (name offset, etc., are computed)
273pub struct Export<'a> {
274    pub name: Option<&'a str>,
275    pub offset: Option<usize>,
276    pub rva: usize,
277    pub size: usize,
278    pub reexport: Option<Reexport<'a>>,
279}
280
281#[derive(Debug, Copy, Clone)]
282struct ExportCtx<'a> {
283    pub ptr: u32,
284    pub idx: usize,
285    pub sections: &'a [section_table::SectionTable],
286    pub file_alignment: u32,
287    pub addresses: &'a ExportAddressTable,
288    pub ordinals: &'a ExportOrdinalTable,
289    pub opts: options::ParseOptions,
290}
291
292impl<'a, 'b> scroll::ctx::TryFromCtx<'a, ExportCtx<'b>> for Export<'a> {
293    type Error = error::Error;
294    #[inline]
295    fn try_from_ctx(
296        bytes: &'a [u8],
297        ExportCtx {
298            ptr,
299            idx,
300            sections,
301            file_alignment,
302            addresses,
303            ordinals,
304            opts,
305        }: ExportCtx<'b>,
306    ) -> Result<(Self, usize), Self::Error> {
307        use self::ExportAddressTableEntry::*;
308
309        let name = utils::find_offset(ptr as usize, sections, file_alignment, &opts)
310            .and_then(|offset| bytes.pread::<&str>(offset).ok());
311
312        if let Some(ordinal) = ordinals.get(idx) {
313            if let Some(rva) = addresses.get(*ordinal as usize) {
314                match *rva {
315                    ExportRVA(rva) => {
316                        let rva = rva as usize;
317                        let offset = utils::find_offset(rva, sections, file_alignment, &opts);
318                        Ok((
319                            Export {
320                                name,
321                                offset,
322                                rva,
323                                reexport: None,
324                                size: 0,
325                            },
326                            0,
327                        ))
328                    }
329
330                    ForwarderRVA(rva) => {
331                        let rva = rva as usize;
332                        let offset = utils::find_offset_or(
333                            rva,
334                            sections,
335                            file_alignment,
336                            &opts,
337                            &format!(
338                                "cannot map RVA ({:#x}) of export ordinal {} into offset",
339                                rva, ordinal
340                            ),
341                        )?;
342                        let reexport = Reexport::parse(bytes, offset)?;
343                        Ok((
344                            Export {
345                                name,
346                                offset: Some(offset),
347                                rva,
348                                reexport: Some(reexport),
349                                size: 0,
350                            },
351                            0,
352                        ))
353                    }
354                }
355            } else {
356                Err(error::Error::Malformed(format!(
357                    "cannot get RVA of export ordinal {}",
358                    ordinal
359                )))
360            }
361        } else {
362            Err(error::Error::Malformed(format!(
363                "cannot get ordinal of export name entry {}",
364                idx
365            )))
366        }
367    }
368}
369
370impl<'a> Export<'a> {
371    pub fn parse(
372        bytes: &'a [u8],
373        export_data: &ExportData,
374        sections: &[section_table::SectionTable],
375        file_alignment: u32,
376    ) -> error::Result<Vec<Export<'a>>> {
377        Self::parse_with_opts(
378            bytes,
379            export_data,
380            sections,
381            file_alignment,
382            &options::ParseOptions::default(),
383        )
384    }
385
386    pub fn parse_with_opts(
387        bytes: &'a [u8],
388        export_data: &ExportData,
389        sections: &[section_table::SectionTable],
390        file_alignment: u32,
391        opts: &options::ParseOptions,
392    ) -> error::Result<Vec<Export<'a>>> {
393        let pointers = &export_data.export_name_pointer_table;
394        let addresses = &export_data.export_address_table;
395        let ordinals = &export_data.export_ordinal_table;
396
397        let mut exports = Vec::with_capacity(pointers.len());
398        for (idx, &ptr) in pointers.iter().enumerate() {
399            if let Ok(export) = bytes.pread_with(
400                0,
401                ExportCtx {
402                    ptr,
403                    idx,
404                    sections,
405                    file_alignment,
406                    addresses,
407                    ordinals,
408                    opts: *opts,
409                },
410            ) {
411                exports.push(export);
412            }
413        }
414
415        // TODO: sort + compute size
416        Ok(exports)
417    }
418}
419
420#[cfg(test)]
421mod tests {
422    use self::data_directories::*;
423    use super::*;
424
425    static CORKAMI_POCS_PE_EXPORTSDATA_EXE: [u8; 0x400] = [
426        0x4d, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
427        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
428        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
429        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430        0x40, 0x00, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, 0x4c, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
431        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x02, 0x01, 0x0b, 0x01,
432        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433        0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
434        0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
435        0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x60, 0x01,
436        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
437        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
438        0x10, 0x00, 0x00, 0x00, 0xb0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x10, 0x00,
439        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
440        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
441        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
442        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
443        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
444        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
445        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
446        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
447        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02,
448        0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
449        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
450        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
451        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
452        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
453        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
454        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
455        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
456        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
457        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
458        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
459        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
460        0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x80, 0x03,
461        0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x20, 0x2a, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20,
462        0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x66, 0x61, 0x6b, 0x65, 0x20,
463        0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x0a, 0x00, 0x00,
464        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84,
465        0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x10, 0x00, 0x00,
466        0x40, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
467        0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
468        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c,
469        0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66,
470        0x00, 0x6d, 0x73, 0x76, 0x63, 0x72, 0x74, 0x2e, 0x64, 0x6c, 0x6c, 0x00, 0x65, 0x78, 0x70,
471        0x6f, 0x72, 0x74, 0x73, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x65, 0x78, 0x65, 0x00, 0x00, 0x00,
472        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
473        0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x10, 0x00, 0x00,
474        0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
475        0x00, 0x68, 0x14, 0x10, 0xf0, 0x10, 0xff, 0x15, 0x30, 0x10, 0x00, 0x10, 0x73, 0xc4, 0x04,
476        0xc3, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
477        0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
478        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
479        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
480        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
481        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
482        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
483        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
484        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
485        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
486        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
487        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
488        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
489        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
491        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
492        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
493        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
494        0x00, 0x00, 0x00, 0x00,
495    ];
496
497    #[test]
498    fn size_export_directory_table() {
499        assert_eq!(
500            ::std::mem::size_of::<ExportDirectoryTable>(),
501            SIZEOF_EXPORT_DIRECTORY_TABLE
502        );
503    }
504
505    #[test]
506    fn parse_export_table() {
507        let data_dirs =
508            DataDirectories::parse(&CORKAMI_POCS_PE_EXPORTSDATA_EXE[..], 16, &mut 0xb8).unwrap();
509        let export_table = data_dirs.get_export_table().unwrap();
510
511        assert_eq!(export_table.virtual_address, 0x10b0);
512        assert_eq!(export_table.size, 0x0);
513    }
514
515    #[test]
516    fn parse_export_directory() {
517        let data_dir = ExportDirectoryTable::parse(&CORKAMI_POCS_PE_EXPORTSDATA_EXE[..], 0x2b0);
518        assert!(data_dir.is_ok());
519
520        let data_dir = data_dir.unwrap();
521        assert_eq!(data_dir.export_flags, 0x0);
522        assert_eq!(data_dir.time_date_stamp, 0x0);
523        assert_eq!(data_dir.major_version, 0x0);
524        assert_eq!(data_dir.minor_version, 0x0);
525        assert_eq!(data_dir.name_rva, 0x0);
526        assert_eq!(data_dir.ordinal_base, 0x0);
527        assert_eq!(data_dir.address_table_entries, 0x4);
528        assert_eq!(data_dir.number_of_name_pointers, 0x0);
529        assert_eq!(data_dir.export_address_table_rva, 0x10e0);
530        assert_eq!(data_dir.name_pointer_rva, 0x0);
531        assert_eq!(data_dir.ordinal_table_rva, 0x1100);
532    }
533}