github.com/saferwall/pe@v1.5.2/boundimports.go (about) 1 // Copyright 2018 Saferwall. All rights reserved. 2 // Use of this source code is governed by Apache v2 license 3 // license that can be found in the LICENSE file. 4 5 package pe 6 7 import ( 8 "encoding/binary" 9 ) 10 11 const ( 12 // MaxStringLength represents the maximum length of a string to be retrieved 13 // from the file. It's there to prevent loading massive amounts of data from 14 // memory mapped files. Strings longer than 0x100B should be rather rare. 15 MaxStringLength = uint32(0x100) 16 ) 17 18 // ImageBoundImportDescriptor represents the IMAGE_BOUND_IMPORT_DESCRIPTOR. 19 type ImageBoundImportDescriptor struct { 20 // TimeDateStamp is just the value from the Exports information of the DLL 21 // which is being imported from. 22 TimeDateStamp uint32 `json:"time_date_stamp"` 23 // Offset of the DLL name counted from the beginning of the BOUND_IMPORT table. 24 OffsetModuleName uint16 `json:"offset_module_name"` 25 // Number of forwards, 26 NumberOfModuleForwarderRefs uint16 `json:"number_of_module_forwarder_refs"` 27 // Array of zero or more IMAGE_BOUND_FORWARDER_REF follows. 28 } 29 30 // ImageBoundForwardedRef represents the IMAGE_BOUND_FORWARDER_REF. 31 type ImageBoundForwardedRef struct { 32 TimeDateStamp uint32 `json:"time_date_stamp"` 33 OffsetModuleName uint16 `json:"offset_module_name"` 34 Reserved uint16 `json:"reserved"` 35 } 36 37 // BoundImportDescriptorData represents the descriptor in addition to forwarded refs. 38 type BoundImportDescriptorData struct { 39 Struct ImageBoundImportDescriptor `json:"struct"` 40 Name string `json:"name"` 41 ForwardedRefs []BoundForwardedRefData `json:"forwarded_refs"` 42 } 43 44 // BoundForwardedRefData represents the struct in addition to the dll name. 45 type BoundForwardedRefData struct { 46 Struct ImageBoundForwardedRef `json:"struct"` 47 Name string `json:"name"` 48 } 49 50 // This table is an array of bound import descriptors, each of which describes 51 // a DLL this image was bound up with at the time of the image creation. 52 // The descriptors also carry the time stamps of the bindings, and if the 53 // bindings are up-to-date, the OS loader uses these bindings as a “shortcut” 54 // for API import. Otherwise, the loader ignores the bindings and resolves the 55 // imported APIs through the Import tables. 56 func (pe *File) parseBoundImportDirectory(rva, size uint32) (err error) { 57 var sectionsAfterOffset []uint32 58 var safetyBoundary uint32 59 var start = rva 60 61 for { 62 bndDesc := ImageBoundImportDescriptor{} 63 bndDescSize := uint32(binary.Size(bndDesc)) 64 err = pe.structUnpack(&bndDesc, rva, bndDescSize) 65 // If the RVA is invalid all would blow up. Some EXEs seem to be 66 // specially nasty and have an invalid RVA. 67 if err != nil { 68 return err 69 } 70 71 // If the structure is all zeros, we reached the end of the list. 72 if bndDesc == (ImageBoundImportDescriptor{}) { 73 break 74 } 75 76 rva += bndDescSize 77 sectionsAfterOffset = nil 78 79 fileOffset := pe.GetOffsetFromRva(rva) 80 section := pe.getSectionByRva(rva) 81 if section == nil { 82 safetyBoundary = pe.size - fileOffset 83 for _, section := range pe.Sections { 84 if section.Header.PointerToRawData > fileOffset { 85 sectionsAfterOffset = append( 86 sectionsAfterOffset, section.Header.PointerToRawData) 87 } 88 } 89 if len(sectionsAfterOffset) > 0 { 90 // Find the first section starting at a later offset than that 91 // specified by 'rva' 92 firstSectionAfterOffset := Min(sectionsAfterOffset) 93 section = pe.getSectionByOffset(firstSectionAfterOffset) 94 if section != nil { 95 safetyBoundary = section.Header.PointerToRawData - fileOffset 96 } 97 } 98 } else { 99 sectionLen := uint32(len(section.Data(0, 0, pe))) 100 safetyBoundary = (section.Header.PointerToRawData + sectionLen) - fileOffset 101 } 102 103 if section == nil { 104 pe.logger.Warnf("RVA of IMAGE_BOUND_IMPORT_DESCRIPTOR points to an invalid address: 0x%x", rva) 105 return nil 106 } 107 108 bndFrwdRef := ImageBoundForwardedRef{} 109 bndFrwdRefSize := uint32(binary.Size(bndFrwdRef)) 110 count := min(uint32(bndDesc.NumberOfModuleForwarderRefs), safetyBoundary/bndFrwdRefSize) 111 112 forwarderRefs := make([]BoundForwardedRefData, 0) 113 for i := uint32(0); i < count; i++ { 114 err = pe.structUnpack(&bndFrwdRef, rva, bndFrwdRefSize) 115 if err != nil { 116 return err 117 } 118 119 rva += bndFrwdRefSize 120 121 offset := start + uint32(bndFrwdRef.OffsetModuleName) 122 DllNameBuff := string(pe.GetStringFromData(0, pe.data[offset:offset+MaxStringLength])) 123 DllName := string(DllNameBuff) 124 125 // OffsetModuleName points to a DLL name. These shouldn't be too long. 126 // Anything longer than a safety length of 128 will be taken to indicate 127 // a corrupt entry and abort the processing of these entries. 128 // Names shorter than 4 characters will be taken as invalid as well. 129 if DllName != "" && (len(DllName) > 256 || !IsPrintable(DllName)) { 130 break 131 } 132 133 forwarderRefs = append(forwarderRefs, BoundForwardedRefData{ 134 Struct: bndFrwdRef, Name: DllName}) 135 } 136 137 offset := start + uint32(bndDesc.OffsetModuleName) 138 DllNameBuff := pe.GetStringFromData(0, pe.data[offset:offset+MaxStringLength]) 139 DllName := string(DllNameBuff) 140 if DllName != "" && (len(DllName) > 256 || !IsPrintable(DllName)) { 141 break 142 } 143 144 pe.BoundImports = append(pe.BoundImports, BoundImportDescriptorData{ 145 Struct: bndDesc, 146 Name: DllName, 147 ForwardedRefs: forwarderRefs}) 148 } 149 150 if len(pe.BoundImports) > 0 { 151 pe.HasBoundImp = true 152 } 153 return nil 154 }