github.com/saferwall/pe@v1.5.2/delayimports.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 // ImageDelayImportDescriptor represents the _IMAGE_DELAYLOAD_DESCRIPTOR structure. 12 type ImageDelayImportDescriptor struct { 13 // As yet, no attribute flags are defined. The linker sets this field to zero 14 // in the image. This field can be used to extend the record by indicating 15 // the presence of new fields, or it can be used to indicate behaviors to 16 // the delay or unload helper functions. 17 Attributes uint32 `json:"attributes"` 18 19 // The name of the DLL to be delay-loaded resides in the read-only data 20 // section of the image. It is referenced through the szName field. 21 Name uint32 `json:"name"` 22 23 // The handle of the DLL to be delay-loaded is in the data section of the 24 // image. The phmod field points to the handle. The supplied delay-load 25 // helper uses this location to store the handle to the loaded DLL. 26 ModuleHandleRVA uint32 `json:"module_handle_rva"` 27 28 // The delay import address table (IAT) is referenced by the delay import 29 // descriptor through the pIAT field. The delay-load helper updates these 30 // pointers with the real entry points so that the thunks are no longer in 31 // the calling loop 32 ImportAddressTableRVA uint32 `json:"import_address_table_rva"` 33 34 // The delay import name table (INT) contains the names of the imports that 35 // might require loading. They are ordered in the same fashion as the 36 // function pointers in the IAT. 37 ImportNameTableRVA uint32 `json:"import_name_table_rva"` 38 39 // The delay bound import address table (BIAT) is an optional table of 40 // IMAGE_THUNK_DATA items that is used along with the timestamp field 41 // of the delay-load directory table by a post-process binding phase. 42 BoundImportAddressTableRVA uint32 `json:"bound_import_address_table_rva"` 43 44 // The delay unload import address table (UIAT) is an optional table of 45 // IMAGE_THUNK_DATA items that the unload code uses to handle an explicit 46 // unload request. It consists of initialized data in the read-only section 47 // that is an exact copy of the original IAT that referred the code to the 48 // delay-load thunks. On the unload request, the library can be freed, 49 // the *phmod cleared, and the UIAT written over the IAT to restore 50 // everything to its preload state. 51 UnloadInformationTableRVA uint32 `json:"unload_information_table_rva"` 52 53 // 0 if not bound, otherwise, date/time of the target DLL. 54 TimeDateStamp uint32 `json:"time_date_stamp"` 55 } 56 57 // DelayImport represents an entry in the delay import table. 58 type DelayImport struct { 59 Offset uint32 `json:"offset"` 60 Name string `json:"name"` 61 Functions []ImportFunction `json:"functions"` 62 Descriptor ImageDelayImportDescriptor `json:"descriptor"` 63 } 64 65 // Delay-Load Import Tables tables were added to the image to support a uniform 66 // mechanism for applications to delay the loading of a DLL until the first call 67 // into that DLL. The delay-load directory table is the counterpart to the 68 // import directory table. 69 func (pe *File) parseDelayImportDirectory(rva, size uint32) error { 70 for { 71 importDelayDesc := ImageDelayImportDescriptor{} 72 fileOffset := pe.GetOffsetFromRva(rva) 73 importDescSize := uint32(binary.Size(importDelayDesc)) 74 err := pe.structUnpack(&importDelayDesc, fileOffset, importDescSize) 75 76 // If the RVA is invalid all would blow up. Some EXEs seem to be 77 // specially nasty and have an invalid RVA. 78 if err != nil { 79 return err 80 } 81 82 // If the structure is all zeros, we reached the end of the list. 83 if importDelayDesc == (ImageDelayImportDescriptor{}) { 84 break 85 } 86 87 rva += importDescSize 88 89 // If the array of thunks is somewhere earlier than the import 90 // descriptor we can set a maximum length for the array. Otherwise 91 // just set a maximum length of the size of the file 92 maxLen := uint32(len(pe.data)) - fileOffset 93 if rva > importDelayDesc.ImportNameTableRVA || 94 rva > importDelayDesc.ImportAddressTableRVA { 95 if rva < importDelayDesc.ImportNameTableRVA { 96 maxLen = rva - importDelayDesc.ImportAddressTableRVA 97 } else if rva < importDelayDesc.ImportAddressTableRVA { 98 maxLen = rva - importDelayDesc.ImportNameTableRVA 99 } else { 100 maxLen = Max(rva-importDelayDesc.ImportNameTableRVA, 101 rva-importDelayDesc.ImportAddressTableRVA) 102 } 103 } 104 105 var importedFunctions []ImportFunction 106 if pe.Is64 { 107 importedFunctions, err = pe.parseImports64(&importDelayDesc, maxLen) 108 } else { 109 importedFunctions, err = pe.parseImports32(&importDelayDesc, maxLen) 110 } 111 if err != nil { 112 return err 113 } 114 115 nameRVA := uint32(0) 116 if importDelayDesc.Attributes == 0 { 117 nameRVA = importDelayDesc.Name - 118 pe.NtHeader.OptionalHeader.(ImageOptionalHeader32).ImageBase 119 } else { 120 nameRVA = importDelayDesc.Name 121 } 122 dllName := pe.getStringAtRVA(nameRVA, maxLen) 123 if !IsValidDosFilename(dllName) { 124 dllName = "*invalid*" 125 continue 126 } 127 128 pe.DelayImports = append(pe.DelayImports, DelayImport{ 129 Offset: fileOffset, 130 Name: string(dllName), 131 Functions: importedFunctions, 132 Descriptor: importDelayDesc, 133 }) 134 } 135 136 if len(pe.DelayImports) > 0 { 137 pe.HasDelayImp = true 138 } 139 140 return nil 141 } 142 143 // GetDelayImportEntryInfoByRVA return an import function + index of the entry given 144 // an RVA. 145 func (pe *File) GetDelayImportEntryInfoByRVA(rva uint32) (DelayImport, int) { 146 for _, imp := range pe.DelayImports { 147 for i, entry := range imp.Functions { 148 if entry.ThunkRVA == rva { 149 return imp, i 150 } 151 } 152 } 153 154 return DelayImport{}, 0 155 }