/
api.go
118 lines (92 loc) · 2.88 KB
/
api.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
package pe
import (
"errors"
"io"
)
// Exported API
type Section struct {
Perm string `json:"Perm"`
Name string `json:"Name"`
FileOffset int64 `json:"FileOffset"`
VMA int64 `json:"VMA"`
Size int64 `json:"Size"`
}
type PEFile struct {
nt_header *IMAGE_NT_HEADERS
// Used to resolve RVA to file offsets.
rva_resolver *RVAResolver
// The file offset to the resource section.
resource_base int64
Machine string `json:"Machine"`
TimeDateStamp string `json:"TimeDateStamp"`
GUIDAge string `json:"GUIDAge"`
PDB string `json:"PDB"`
Sections []*Section `json:"Sections"`
VersionInformation map[string]string `json:"VersionInformation"`
Imports []string `json:"Imports"`
}
func GetVersionInformation(
nt_header *IMAGE_NT_HEADERS,
rva_resolver *RVAResolver,
resource_base int64) map[string]string {
result := make(map[string]string)
// Find the RT_VERSION resource.
for _, entry := range nt_header.
ResourceDirectory(rva_resolver).Entries() {
if entry.NameString(resource_base) == "RT_VERSION" {
for _, child := range entry.Traverse(resource_base) {
vs_info := child.Profile.VS_VERSIONINFO(
child.Reader,
int64(rva_resolver.GetFileAddress(
child.OffsetToData())))
for _, child := range vs_info.Children() {
for _, string_table := range child.StringTable() {
for _, resource_string := range string_table.
ResourceStrings() {
result[resource_string.Key()] = resource_string.Value()
}
}
}
}
}
}
return result
}
func NewPEFile(reader io.ReaderAt) (*PEFile, error) {
profile := NewPeProfile()
dos_header := profile.IMAGE_DOS_HEADER(reader, 0)
if dos_header.E_magic() != 0x5a4d {
return nil, errors.New("Invalid IMAGE_DOS_HEADER")
}
nt_header := dos_header.NTHeader()
if nt_header.Signature() != 0x4550 {
return nil, errors.New("Invalid IMAGE_NT_HEADERS")
}
rva_resolver := NewRVAResolver(nt_header)
// Get the base address of the resource section.
resource_section := nt_header.SectionByName(".rsrc")
resource_base := int64(resource_section.PointerToRawData())
file_header := nt_header.FileHeader()
rsds := nt_header.RSDS(rva_resolver)
result := &PEFile{
nt_header: nt_header,
rva_resolver: rva_resolver,
resource_base: resource_base,
Machine: file_header.Machine().Name,
TimeDateStamp: file_header.TimeDateStamp().String(),
GUIDAge: rsds.GUIDAge(),
PDB: rsds.Filename(),
VersionInformation: GetVersionInformation(
nt_header, rva_resolver, resource_base),
Imports: GetImports(nt_header, rva_resolver),
}
for _, section := range nt_header.Sections() {
result.Sections = append(result.Sections, &Section{
Perm: section.Permissions(),
Name: section.Name(),
FileOffset: int64(section.PointerToRawData()),
VMA: int64(section.VirtualAddress()),
})
}
return result, nil
}