retdec
DelayImportDirectory.h
Go to the documentation of this file.
1 
7 #ifndef RETDEC_PELIB_DELAY_IMPORT_DIRECTORY_H
8 #define RETDEC_PELIB_DELAY_IMPORT_DIRECTORY_H
9 
10 #include "retdec/pelib/PeLibInc.h"
12 
13 namespace PeLib
14 {
20  {
21  typedef typename std::vector<PELIB_IMAGE_DELAY_IMPORT_DIRECTORY_RECORD >::const_iterator DelayImportDirectoryIterator;
22 
23  private:
24  std::vector<PELIB_IMAGE_DELAY_IMPORT_DIRECTORY_RECORD> records;
25 
26  void init()
27  {
28  records.clear();
29  }
30 
31  public:
33  {
34  init();
35  }
36 
38  {
39 
40  }
41 
42  // Delay-import descriptors made by MS Visual C++ 6.0 have old format
43  // of delay import directory, where all entries are VAs (as opposite to RVAs from newer MS compilers).
44  // We convert the delay-import directory entries to RVAs by checking the lowest bit in the delay-import descriptor's Attributes value
45  std::uint64_t normalizeDelayImportValue(std::uint64_t imageBase, std::uint64_t virtualAddress)
46  {
47  // Ignore zero items
48  if (virtualAddress != 0)
49  {
50  // Sample: 0fc4cb0620f95bdd624f2c78eea4d2b59594244c6671cf249526adf2f2cb71ec
51  // Contains artificially created delay import directory with incorrect values:
52  //
53  // Attributes 0x00000000 <-- Old MS delay import record, contains VAs
54  // NameRva 0x004010e6
55  // ModuleHandleRva 0x00000000
56  // DelayImportAddressTableRva 0x00001140 <-- WRONG! This is an RVA
57  // DelayImportNameTableRva 0x004010c0
58  // BoundDelayImportTableRva 0x00000000
59  // ...
60 
61  if (virtualAddress > imageBase)
62  {
63  virtualAddress = virtualAddress - imageBase;
64  }
65  }
66 
67  return virtualAddress;
68  }
69 
70  void normalize32BitDelayImport(PELIB_IMAGE_DELAY_LOAD_DESCRIPTOR & rec, std::uint64_t imageBase)
71  {
72  rec.NameRva = (std::uint32_t)normalizeDelayImportValue(imageBase, rec.NameRva);
73  rec.ModuleHandleRva = (std::uint32_t)normalizeDelayImportValue(imageBase, rec.ModuleHandleRva);
78  }
79 
81  {
82  return (importDescriptor.Attributes == 0 &&
83  importDescriptor.NameRva == 0 &&
84  importDescriptor.ModuleHandleRva == 0 &&
85  importDescriptor.DelayImportAddressTableRva == 0 &&
86  importDescriptor.DelayImportNameTableRva == 0 &&
87  importDescriptor.BoundDelayImportTableRva == 0 &&
88  importDescriptor.UnloadDelayImportTableRva == 0 &&
89  importDescriptor.TimeStamp == 0);
90  }
91 
92  int read(ImageLoader & imageLoader)
93  {
94  std::uint32_t rva = imageLoader.getDataDirRva(PELIB_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
95  std::uint32_t size = imageLoader.getDataDirSize(PELIB_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
96  std::uint32_t sizeOfImage = imageLoader.getSizeOfImage();
97  std::uint32_t pointerSize = imageLoader.getPointerSize();
98  std::uint64_t imageBase = imageLoader.getImageBase();
99  std::uint64_t ordinalMask = imageLoader.getOrdinalMask();
100 
101  if(rva >= sizeOfImage)
102  return ERROR_INVALID_FILE;
103  init();
104 
105  // Keep loading until we encounter an entry filles with zeros
106  for(std::uint32_t i = 0;; i += sizeof(PELIB_IMAGE_DELAY_LOAD_DESCRIPTOR))
107  {
109 
110  // Read the n-th import directory entry
111  if((rva + i) >= sizeOfImage)
112  break;
113  if(!imageLoader.readImage(&rec.delayedImport, rva + i, sizeof(PELIB_IMAGE_DELAY_LOAD_DESCRIPTOR)))
114  break;
115 
116  // Valid delayed import entry starts either with 0 or 0x01
117  if(rec.delayedImport.Attributes & 0xFFFF0000)
118  break;
119 
120  // Check for the termination entry
122  break;
123 
124  // Convert older (MS Visual C++ 6.0) delay-import descriptor to newer one.
125  // These delay-import descriptors are distinguishable by lowest bit in rec.Attributes to be zero.
126  // Sample: 2775d97f8bdb3311ace960a42eee35dbec84b9d71a6abbacb26c14e83f5897e4
127  if(imageLoader.getImageBitability() == 32 && (rec.delayedImport.Attributes & PELIB_DELAY_ATTRIBUTE_V2) == 0)
128  normalize32BitDelayImport(rec.delayedImport, (std::uint32_t)imageBase);
129 
130  // Stop on blatantly invalid delay import entries (old PELIB behavior)
131  if(rec.delayedImport.DelayImportNameTableRva >= sizeOfImage || rec.delayedImport.DelayImportAddressTableRva >= sizeOfImage)
132  return ERROR_INVALID_FILE;
133 
134  // Get name of library
136 
137  //
138  // LOADING NAME ADDRESSES/NAME ORDINALS
139  //
140 
141  std::vector<uint64_t> nameAddresses;
142  std::uint32_t rva2 = rec.delayedImport.DelayImportNameTableRva;
143 
144  for(;;)
145  {
146  std::uint64_t nameAddress;
147 
148  // Read single name address. Also stop processing if the RVA gets out of image
149  if(imageLoader.readPointer(rva2, nameAddress) != pointerSize)
150  return ERROR_INVALID_FILE;
151  rva2 += pointerSize;
152 
153  // Value of zero means that this is the end of the bound import name table
154  if(nameAddress == 0)
155  break;
156  nameAddresses.push_back(nameAddress);
157  }
158 
159  //
160  // LOADING FUNCTION POINTERS
161  //
162 
163  std::vector<uint64_t> funcAddresses;
165 
166  // Read all (VAs) of import names
167  for (std::size_t i = 0; i < nameAddresses.size(); i++)
168  {
169  std::uint64_t funcAddress;
170 
171  // Read single name address. Also stop processing if the RVA gets out of image
172  if(imageLoader.readPointer(rva2, funcAddress) != pointerSize)
173  return ERROR_INVALID_FILE;
174  rva2 += pointerSize;
175 
176  // Value of zero means that this is the end of the bound import name table
177  if(funcAddress == 0)
178  break;
179  funcAddresses.push_back(funcAddress);
180  }
181 
182  //
183  // MERGE BOTH TOGETHER
184  //
185 
186  std::size_t numberOfFunctions = std::min(nameAddresses.size(), funcAddresses.size());
187  for (std::size_t i = 0; i < numberOfFunctions; i++)
188  {
189  PELIB_DELAY_IMPORT function;
190  std::uint64_t nameAddress = nameAddresses[i];
191  std::uint64_t funcAddress = funcAddresses[i];
192 
193  // Check name address. It could be ordinal, VA or RVA
194  if (!(nameAddress & ordinalMask))
195  {
196  // Convert name address to RVA, if needed
198  nameAddress = normalizeDelayImportValue(imageBase, nameAddress);
199 
200  // Read the function hint
201  if(imageLoader.readImage(&function.hint, nameAddress, sizeof(function.hint)) != sizeof(function.hint))
202  break;
203 
204  // Read the function name
205  imageLoader.readString(function.fname, nameAddress + sizeof(function.hint), IMPORT_SYMBOL_MAX_LENGTH);
206  }
207  else
208  {
209  function.hint = (std::uint16_t)(nameAddress & 0xFFFF);
210  }
211 
212  // Convert function address to RVA, if needed
213  if(imageBase <= funcAddress && funcAddress < imageBase + sizeOfImage)
214  funcAddress -= imageBase;
215  function.address = funcAddress;
216 
217  // Insert the function to the list
218  rec.addFunction(function);
219  }
220 
221  records.push_back(rec);
222  }
223  return ERROR_NONE;
224  }
225 
226  std::size_t getNumberOfFiles() const
227  {
228  return records.size();
229  }
230 
231  const PELIB_IMAGE_DELAY_IMPORT_DIRECTORY_RECORD *getFile(std::size_t index) const
232  {
233  return index < getNumberOfFiles() ? &records[index] : nullptr;
234  }
235 
237  {
238  return records.begin();
239  }
240 
242  {
243  return records.end();
244  }
245  };
246 }
247 
248 #endif
Definition: DelayImportDirectory.h:20
std::uint64_t normalizeDelayImportValue(std::uint64_t imageBase, std::uint64_t virtualAddress)
Definition: DelayImportDirectory.h:45
void normalize32BitDelayImport(PELIB_IMAGE_DELAY_LOAD_DESCRIPTOR &rec, std::uint64_t imageBase)
Definition: DelayImportDirectory.h:70
DelayImportDirectoryIterator end() const
Definition: DelayImportDirectory.h:241
std::vector< PELIB_IMAGE_DELAY_IMPORT_DIRECTORY_RECORD > records
Definition: DelayImportDirectory.h:24
std::vector< PELIB_IMAGE_DELAY_IMPORT_DIRECTORY_RECORD >::const_iterator DelayImportDirectoryIterator
Definition: DelayImportDirectory.h:21
int read(ImageLoader &imageLoader)
Definition: DelayImportDirectory.h:92
const PELIB_IMAGE_DELAY_IMPORT_DIRECTORY_RECORD * getFile(std::size_t index) const
Definition: DelayImportDirectory.h:231
~DelayImportDirectory()
Definition: DelayImportDirectory.h:37
void init()
Definition: DelayImportDirectory.h:26
std::size_t getNumberOfFiles() const
Definition: DelayImportDirectory.h:226
DelayImportDirectoryIterator begin() const
Definition: DelayImportDirectory.h:236
bool isTerminationEntry(PELIB_IMAGE_DELAY_LOAD_DESCRIPTOR &importDescriptor)
Definition: DelayImportDirectory.h:80
DelayImportDirectory()
Definition: DelayImportDirectory.h:32
Definition: ImageLoader.h:138
std::uint32_t readPointer(std::uint32_t rva, std::uint64_t &pointerValue)
Definition: ImageLoader.cpp:291
std::uint32_t getDataDirSize(std::size_t dataDirIndex) const
Definition: ImageLoader.h:321
std::uint32_t getDataDirRva(std::size_t dataDirIndex) const
Definition: ImageLoader.h:315
std::uint32_t readString(std::string &str, std::uint32_t rva, std::uint32_t maxLength=65535)
Definition: ImageLoader.cpp:275
std::uint64_t getOrdinalMask() const
Definition: ImageLoader.h:210
std::uint32_t getImageBitability() const
Definition: ImageLoader.cpp:432
std::uint64_t getImageBase() const
Definition: ImageLoader.h:265
std::uint32_t readImage(void *buffer, std::uint32_t rva, std::uint32_t bytesToRead)
Definition: ImageLoader.cpp:171
std::uint32_t getSizeOfImage() const
Definition: ImageLoader.h:280
std::uint32_t getPointerSize() const
Definition: ImageLoader.cpp:322
Definition: BoundImportDirectory.h:21
@ PELIB_IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT
Definition: PeLibAux.h:182
const std::size_t IMPORT_LIBRARY_MAX_LENGTH
Definition: PeLibAux.h:1130
const std::size_t IMPORT_SYMBOL_MAX_LENGTH
Definition: PeLibAux.h:1131
const std::uint32_t PELIB_DELAY_ATTRIBUTE_V2
Definition: PeLibAux.h:1399
@ ERROR_NONE
Definition: PeLibAux.h:33
@ ERROR_INVALID_FILE
Definition: PeLibAux.h:35
Definition: PeLibAux.h:1091
std::string Name
Definition: PeLibAux.h:1410
void addFunction(const PELIB_DELAY_IMPORT &function)
Definition: PeLibAux.h:1430
PELIB_IMAGE_DELAY_LOAD_DESCRIPTOR delayedImport
Definition: PeLibAux.h:1409
Definition: PeLibAux.h:1388
std::uint32_t BoundDelayImportTableRva
Definition: PeLibAux.h:1394
std::uint32_t DelayImportAddressTableRva
Definition: PeLibAux.h:1392
std::uint32_t ModuleHandleRva
Definition: PeLibAux.h:1391
std::uint32_t TimeStamp
Definition: PeLibAux.h:1396
std::uint32_t Attributes
Definition: PeLibAux.h:1389
std::uint32_t NameRva
Definition: PeLibAux.h:1390
std::uint32_t UnloadDelayImportTableRva
Definition: PeLibAux.h:1395
std::uint32_t DelayImportNameTableRva
Definition: PeLibAux.h:1393