-
-
Notifications
You must be signed in to change notification settings - Fork 50
/
Copy pathboundimports.go
154 lines (132 loc) · 5.29 KB
/
boundimports.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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright 2018 Saferwall. All rights reserved.
// Use of this source code is governed by Apache v2 license
// license that can be found in the LICENSE file.
package pe
import (
"encoding/binary"
)
const (
// MaxStringLength represents the maximum length of a string to be retrieved
// from the file. It's there to prevent loading massive amounts of data from
// memory mapped files. Strings longer than 0x100B should be rather rare.
MaxStringLength = uint32(0x100)
)
// ImageBoundImportDescriptor represents the IMAGE_BOUND_IMPORT_DESCRIPTOR.
type ImageBoundImportDescriptor struct {
// TimeDateStamp is just the value from the Exports information of the DLL
// which is being imported from.
TimeDateStamp uint32 `json:"time_date_stamp"`
// Offset of the DLL name counted from the beginning of the BOUND_IMPORT table.
OffsetModuleName uint16 `json:"offset_module_name"`
// Number of forwards,
NumberOfModuleForwarderRefs uint16 `json:"number_of_module_forwarder_refs"`
// Array of zero or more IMAGE_BOUND_FORWARDER_REF follows.
}
// ImageBoundForwardedRef represents the IMAGE_BOUND_FORWARDER_REF.
type ImageBoundForwardedRef struct {
TimeDateStamp uint32 `json:"time_date_stamp"`
OffsetModuleName uint16 `json:"offset_module_name"`
Reserved uint16 `json:"reserved"`
}
// BoundImportDescriptorData represents the descriptor in addition to forwarded refs.
type BoundImportDescriptorData struct {
Struct ImageBoundImportDescriptor `json:"struct"`
Name string `json:"name"`
ForwardedRefs []BoundForwardedRefData `json:"forwarded_refs"`
}
// BoundForwardedRefData represents the struct in addition to the dll name.
type BoundForwardedRefData struct {
Struct ImageBoundForwardedRef `json:"struct"`
Name string `json:"name"`
}
// This table is an array of bound import descriptors, each of which describes
// a DLL this image was bound up with at the time of the image creation.
// The descriptors also carry the time stamps of the bindings, and if the
// bindings are up-to-date, the OS loader uses these bindings as a “shortcut”
// for API import. Otherwise, the loader ignores the bindings and resolves the
// imported APIs through the Import tables.
func (pe *File) parseBoundImportDirectory(rva, size uint32) (err error) {
var sectionsAfterOffset []uint32
var safetyBoundary uint32
var start = rva
for {
bndDesc := ImageBoundImportDescriptor{}
bndDescSize := uint32(binary.Size(bndDesc))
err = pe.structUnpack(&bndDesc, rva, bndDescSize)
// If the RVA is invalid all would blow up. Some EXEs seem to be
// specially nasty and have an invalid RVA.
if err != nil {
return err
}
// If the structure is all zeros, we reached the end of the list.
if bndDesc == (ImageBoundImportDescriptor{}) {
break
}
rva += bndDescSize
sectionsAfterOffset = nil
fileOffset := pe.GetOffsetFromRva(rva)
section := pe.getSectionByRva(rva)
if section == nil {
safetyBoundary = pe.size - fileOffset
for _, section := range pe.Sections {
if section.Header.PointerToRawData > fileOffset {
sectionsAfterOffset = append(
sectionsAfterOffset, section.Header.PointerToRawData)
}
}
if len(sectionsAfterOffset) > 0 {
// Find the first section starting at a later offset than that
// specified by 'rva'
firstSectionAfterOffset := Min(sectionsAfterOffset)
section = pe.getSectionByOffset(firstSectionAfterOffset)
if section != nil {
safetyBoundary = section.Header.PointerToRawData - fileOffset
}
}
} else {
sectionLen := uint32(len(section.Data(0, 0, pe)))
safetyBoundary = (section.Header.PointerToRawData + sectionLen) - fileOffset
}
if section == nil {
pe.logger.Warnf("RVA of IMAGE_BOUND_IMPORT_DESCRIPTOR points to an invalid address: 0x%x", rva)
return nil
}
bndFrwdRef := ImageBoundForwardedRef{}
bndFrwdRefSize := uint32(binary.Size(bndFrwdRef))
count := min(uint32(bndDesc.NumberOfModuleForwarderRefs), safetyBoundary/bndFrwdRefSize)
forwarderRefs := make([]BoundForwardedRefData, 0)
for i := uint32(0); i < count; i++ {
err = pe.structUnpack(&bndFrwdRef, rva, bndFrwdRefSize)
if err != nil {
return err
}
rva += bndFrwdRefSize
offset := start + uint32(bndFrwdRef.OffsetModuleName)
DllNameBuff := string(pe.GetStringFromData(0, pe.data[offset:offset+MaxStringLength]))
DllName := string(DllNameBuff)
// OffsetModuleName points to a DLL name. These shouldn't be too long.
// Anything longer than a safety length of 128 will be taken to indicate
// a corrupt entry and abort the processing of these entries.
// Names shorter than 4 characters will be taken as invalid as well.
if DllName != "" && (len(DllName) > 256 || !IsPrintable(DllName)) {
break
}
forwarderRefs = append(forwarderRefs, BoundForwardedRefData{
Struct: bndFrwdRef, Name: DllName})
}
offset := start + uint32(bndDesc.OffsetModuleName)
DllNameBuff := pe.GetStringFromData(0, pe.data[offset:offset+MaxStringLength])
DllName := string(DllNameBuff)
if DllName != "" && (len(DllName) > 256 || !IsPrintable(DllName)) {
break
}
pe.BoundImports = append(pe.BoundImports, BoundImportDescriptorData{
Struct: bndDesc,
Name: DllName,
ForwardedRefs: forwarderRefs})
}
if len(pe.BoundImports) > 0 {
pe.HasBoundImp = true
}
return nil
}