forked from ajkhoury/pdbfetch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
parse_export_directory.go
124 lines (101 loc) · 3.55 KB
/
parse_export_directory.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package pe
import (
"fmt"
"log"
)
// Parse the export directory.
//
// Given the RVA of the export directory, it will process all
// its entries.
//
// The exports will be made available as a list of ExportData
// instances in the ExportDescriptors PE attribute.
func (p *PEFile) parseExportDirectory(rva, size uint32) (err error) {
exportDir := NewExportDirectory(p.getOffsetFromRva(rva))
start, _ := p.getDataBounds(rva, 0)
if err = p.parseInterface(&exportDir.ImageExportDirectory, start, exportDir.size); err != nil {
return err
}
p.ExportDirectory = exportDir
//log.Println(exportDir)
startAddrOfNames, _ := p.getDataBounds(exportDir.AddressOfNames, 0)
startAddrOfOrdinals, _ := p.getDataBounds(exportDir.AddressOfNameOrdinals, 0)
startAddrOfFuncs, _ := p.getDataBounds(exportDir.AddressOfFunctions, 0)
errMsg := "RVA %s in the export directory points to an invalid address: %x"
//maxErrors := 10
section := p.getSectionByRva(exportDir.AddressOfNames)
if section == nil {
log.Printf(errMsg, "AddressOfNames", exportDir.AddressOfNames)
return fmt.Errorf(errMsg, "AddressOfNames", exportDir.AddressOfNames)
}
safetyBoundary := section.VirtualAddress + section.SizeOfRawData - exportDir.AddressOfNames
numberOfNames := MinUInt32(safetyBoundary/4, exportDir.NumberOfNames)
// A hash set for tracking seen ordinals
ordMap := make(map[uint16]bool)
for i := uint32(0); i < numberOfNames; i++ {
sym := new(ExportData)
// Name and name offset
var symNameAddr uint32
sym.NameOffset = startAddrOfNames + (int(i) * 4)
if err = p.parseInterface(&symNameAddr, sym.NameOffset, 4); err != nil {
return err
}
sym.Name = p.getStringAtRva(symNameAddr)
//log.Printf("%s\n", sym.Name)
if !validFuncName(sym.Name) {
break
}
sym.NameOffset = p.getOffsetFromRva(symNameAddr)
// Ordinal
sym.OrdinalOffset = startAddrOfOrdinals + (int(i) * 2)
if err = p.parseInterface(&sym.Ordinal, sym.OrdinalOffset, 2); err != nil {
return err
}
// Address
sym.AddressOffset = startAddrOfFuncs + (int(sym.Ordinal) * 4)
if err = p.parseInterface(&sym.Address, sym.AddressOffset, 4); err != nil {
return err
}
if sym.Address == 0 {
continue
}
// Forwarder if applicable
if sym.Address >= rva && sym.Address < rva+size {
sym.Forwarder = p.getStringAtRva(sym.Address)
sym.ForwarderOffset = p.getOffsetFromRva(sym.Address)
}
sym.Ordinal += uint16(exportDir.Base)
ordMap[sym.Ordinal] = true
exportDir.Exports = append(exportDir.Exports, sym)
}
// Check for any missing function symbols
section = p.getSectionByRva(exportDir.AddressOfFunctions)
if section == nil {
log.Printf(errMsg, "AddressOfFunctions", exportDir.AddressOfFunctions)
return fmt.Errorf(errMsg, "AddressOfFunctions", exportDir.AddressOfFunctions)
}
safetyBoundary = section.VirtualAddress + section.SizeOfRawData - exportDir.AddressOfFunctions
numberOfNames = MinUInt32(safetyBoundary/4, exportDir.NumberOfFunctions)
for i := uint32(0); i < numberOfNames; i++ {
if _, ok := ordMap[uint16(i+exportDir.Base)]; ok {
continue
}
sym := new(ExportData)
// Address
sym.AddressOffset = startAddrOfFuncs + (int(sym.Ordinal) * 4)
if err = p.parseInterface(&sym.Address, sym.AddressOffset, 4); err != nil {
return err
}
if sym.Address == 0 {
continue
}
// Forwarder if applicable
if sym.Address >= rva && sym.Address < rva+size {
sym.Forwarder = p.getStringAtRva(sym.Address)
sym.ForwarderOffset = p.getOffsetFromRva(sym.Address)
}
sym.Ordinal = uint16(exportDir.Base + i)
exportDir.Exports = append(exportDir.Exports, sym)
}
return nil
}