- Merge from trunk up to r45543
[reactos.git] / dll / win32 / imagehlp / modify.c
1 /*
2 * IMAGEHLP library
3 *
4 * Copyright 1998 Patrik Stridvall
5 * Copyright 2005 Alex Ionescu
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "precomp.h"
23
24 #define _WINNT_H
25 #include "wine/debug.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(imagehlp);
28
29 /* DATA **********************************************************************/
30
31 CHAR BoundLibraries[4096];
32 LPSTR BoundLibrariesPointer;
33
34 /***********************************************************************
35 * BindImage (IMAGEHLP.@)
36 */
37 BOOL WINAPI BindImage(
38 LPSTR ImageName, LPSTR DllPath, LPSTR SymbolPath)
39 {
40 return BindImageEx(0, ImageName, DllPath, SymbolPath, NULL);
41 }
42
43 static LPSTR
44 IMAGEAPI
45 BindpCaptureImportModuleName(LPSTR ModuleName)
46 {
47 LPSTR Name = BoundLibraries;
48
49 /* Check if it hasn't been initialized yet */
50 if (!BoundLibrariesPointer)
51 {
52 /* Start with a null char and set the pointer */
53 *Name = ANSI_NULL;
54 BoundLibrariesPointer = Name;
55 }
56
57 /* Loop the current buffer */
58 while (*Name)
59 {
60 /* Try to match this DLL's name and return it */
61 if (!_stricmp(Name, ModuleName)) return Name;
62
63 /* Move on to the next DLL Name */
64 Name += strlen(Name) + sizeof(CHAR);
65 }
66
67 /* If we got here, we didn't find one, so add this one to our buffer */
68 strcpy(Name, ModuleName);
69
70 /* Set the new position of the buffer, and null-terminate it */
71 BoundLibrariesPointer = Name + strlen(Name) + sizeof(CHAR);
72 *BoundLibrariesPointer = ANSI_NULL;
73
74 /* Return the pointer to the name */
75 return Name;
76 }
77
78
79 static PIMPORT_DESCRIPTOR
80 IMAGEAPI
81 BindpAddImportDescriptor(PIMPORT_DESCRIPTOR *BoundImportDescriptor,
82 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor,
83 LPSTR DllName,
84 PLOADED_IMAGE Image)
85 {
86 PIMPORT_DESCRIPTOR Descriptor, *NextDescriptor;
87
88 /* Loop descriptors and check if this library has already been bound */
89 NextDescriptor = BoundImportDescriptor;
90 while ((Descriptor = *NextDescriptor))
91 {
92 /* Compare the names and return the descriptor if found */
93 if (!_stricmp(Descriptor->ModuleName, DllName)) return Descriptor;
94
95 /* Move to the next one */
96 NextDescriptor = &Descriptor->Next;
97 }
98
99 /* Allocate a new descriptor */
100 Descriptor = HeapAlloc(IMAGEHLP_hHeap,
101 HEAP_ZERO_MEMORY,
102 sizeof(IMPORT_DESCRIPTOR));
103
104 /* Set its Data and check if we have a valid loaded image */
105 Descriptor->ModuleName = BindpCaptureImportModuleName(DllName);
106 *NextDescriptor = Descriptor;
107 if (Image)
108 {
109 /* Save the time stamp */
110 Descriptor->TimeDateStamp = Image->FileHeader->FileHeader.TimeDateStamp;
111 }
112
113 /* Return the descriptor */
114 return Descriptor;
115 }
116
117 static PCHAR
118 IMAGEAPI
119 BindpAddForwarderReference(LPSTR ModuleName,
120 LPSTR ImportName,
121 PIMPORT_DESCRIPTOR BoundImportDescriptor,
122 LPSTR DllPath,
123 PCHAR ForwarderString,
124 PBOOL ForwarderBound)
125 {
126 CHAR DllName[256];
127 PCHAR TempDllName, FunctionName;
128 PLOADED_IMAGE Library;
129 SIZE_T DllNameSize;
130 USHORT OrdinalNumber;
131 USHORT HintIndex;
132 ULONG ExportSize;
133 PIMAGE_EXPORT_DIRECTORY Exports;
134 ULONG_PTR ExportsBase;
135 PULONG AddressOfNames;
136 PUSHORT AddressOfOrdinals;
137 PULONG AddressOfPointers;
138 LPSTR ExportName;
139 ULONG_PTR ForwardedAddress;
140 PBOUND_FORWARDER_REFS Forwarder, *NextForwarder;
141 PIMAGE_OPTIONAL_HEADER OptionalHeader = NULL;
142
143 NextForwarder:
144
145 /* Get the DLL Name */
146 TempDllName = ForwarderString;
147 while (*TempDllName && *TempDllName != '.') TempDllName++;
148 if (*TempDllName != '.') return ForwarderString;
149
150 /* Get the size */
151 DllNameSize = (SIZE_T)(TempDllName - ForwarderString);
152 if (DllNameSize >= MAX_PATH) return ForwarderString;
153
154 /* Now copy the name and append the extension */
155 strncpy(DllName, ForwarderString, DllNameSize);
156 DllName[DllNameSize] = ANSI_NULL;
157 strcat(DllName, ".DLL");
158
159 /* Load it */
160 TRACE("Loading the Thunk Library: %s \n", DllName);
161 Library = ImageLoad(DllName, DllPath);
162 if (!Library) return ForwarderString;
163
164 /* Move past the name */
165 TRACE("It Loaded at: %p \n", Library->MappedAddress);
166 FunctionName = TempDllName += 1;
167
168 /* Load Exports */
169 Exports = ImageDirectoryEntryToData(Library->MappedAddress,
170 FALSE,
171 IMAGE_DIRECTORY_ENTRY_EXPORT,
172 &ExportSize);
173 if (!Exports) return ForwarderString;
174
175 /* Get the Optional Header */
176 OptionalHeader = &Library->FileHeader->OptionalHeader;
177
178 /* Check if we're binding by ordinal */
179 if (*FunctionName == '#')
180 {
181 /* We are, get the number and validate it */
182 OrdinalNumber = atoi(FunctionName + 1) - (USHORT)Exports->Base;
183 if (OrdinalNumber >= Exports->NumberOfFunctions) return ForwarderString;
184 }
185 else
186 {
187 /* Binding by name... */
188 OrdinalNumber = -1;
189 }
190
191 /* Get the Pointers to the Tables */
192 AddressOfNames = ImageRvaToVa(Library->FileHeader,
193 Library->MappedAddress,
194 Exports->AddressOfNames,
195 &Library->LastRvaSection);
196 AddressOfOrdinals = ImageRvaToVa(Library->FileHeader,
197 Library->MappedAddress,
198 Exports->AddressOfNameOrdinals,
199 &Library->LastRvaSection);
200 AddressOfPointers = ImageRvaToVa(Library->FileHeader,
201 Library->MappedAddress,
202 Exports->AddressOfFunctions,
203 &Library->LastRvaSection);
204
205 /* Check if we're binding by name... */
206 if (OrdinalNumber == 0xffff)
207 {
208 /* Do a full search for the ordinal */
209 for (HintIndex = 0; HintIndex < Exports->NumberOfNames; HintIndex++)
210 {
211 /* Get the Export Name */
212 ExportName = ImageRvaToVa(Library->FileHeader,
213 Library->MappedAddress,
214 (ULONG)AddressOfNames[HintIndex],
215 &Library->LastRvaSection);
216
217 /* Check if it's the one we want */
218 if (!strcmp(FunctionName, ExportName))
219 {
220 OrdinalNumber = AddressOfOrdinals[HintIndex];
221 break;
222 }
223 }
224
225 /* Make sure it's valid */
226 if (HintIndex >= Exports->NumberOfNames) return ForwarderString;
227 }
228
229 /* Get the Forwarded Address */
230 ForwardedAddress = AddressOfPointers[OrdinalNumber] +
231 OptionalHeader->ImageBase;
232
233 /* Loop the forwarders to see if this DLL was already processed */
234 NextForwarder = &BoundImportDescriptor->Forwarders;
235 while ((Forwarder = *NextForwarder))
236 {
237 /* Check for a name match */
238 if (!_stricmp(DllName, Forwarder->ModuleName)) break;
239
240 /* Move to the next one */
241 NextForwarder = &Forwarder->Next;
242 }
243
244 /* Check if we've went through them all without luck */
245 if (!Forwarder)
246 {
247 /* Allocate a forwarder structure */
248 Forwarder = HeapAlloc(IMAGEHLP_hHeap,
249 HEAP_ZERO_MEMORY,
250 sizeof(BOUND_FORWARDER_REFS));
251
252 /* Set the name */
253 Forwarder->ModuleName = BindpCaptureImportModuleName(DllName);
254
255 /* Increase the number of forwarders */
256 BoundImportDescriptor->ForwaderReferences++;
257
258 /* Link it */
259 *NextForwarder = Forwarder;
260 }
261
262 /* Set the timestamp */
263 Forwarder->TimeDateStamp = Library->FileHeader->FileHeader.TimeDateStamp;
264
265 /* Load DLL's Exports */
266 ExportsBase = (ULONG_PTR)ImageDirectoryEntryToData(Library->MappedAddress,
267 TRUE,
268 IMAGE_DIRECTORY_ENTRY_EXPORT,
269 &ExportSize) -
270 (ULONG_PTR)Library->MappedAddress;
271
272 /* Convert to VA */
273 ExportsBase += OptionalHeader->ImageBase;
274
275 /* Is this yet another Forward? */
276 TRACE("I've thunked it\n");
277 if ((ForwardedAddress > ExportsBase) &&
278 (ForwardedAddress < (ExportsBase + ExportSize)))
279 {
280 /* Update the string pointer */
281 ForwarderString = ImageRvaToVa(Library->FileHeader,
282 Library->MappedAddress,
283 AddressOfPointers[OrdinalNumber],
284 &Library->LastRvaSection);
285 goto NextForwarder;
286 }
287 else
288 {
289 /* Update the pointer and return success */
290 ForwarderString = (PCHAR)ForwardedAddress;
291 *ForwarderBound = TRUE;
292 }
293
294 /* Return the pointer */
295 return ForwarderString;
296 }
297
298 static BOOL
299 IMAGEAPI
300 BindpLookupThunk(PIMAGE_THUNK_DATA Thunk,
301 PLOADED_IMAGE Image,
302 PIMAGE_THUNK_DATA BoundThunk,
303 PIMAGE_THUNK_DATA ThunkFunction,
304 PLOADED_IMAGE Library,
305 PIMAGE_EXPORT_DIRECTORY Exports,
306 PIMPORT_DESCRIPTOR BoundImportDescriptor,
307 LPSTR DllPath,
308 PULONG *Forwarders)
309 {
310 PULONG AddressOfNames;
311 PUSHORT AddressOfOrdinals;
312 PULONG AddressOfPointers;
313 PIMAGE_IMPORT_BY_NAME ImportName;
314 ULONG OrdinalNumber = 0;
315 USHORT HintIndex;
316 LPSTR ExportName;
317 ULONG_PTR ExportsBase;
318 ULONG ExportSize;
319 UCHAR NameBuffer[32];
320 PIMAGE_OPTIONAL_HEADER OptionalHeader = NULL;
321 PIMAGE_OPTIONAL_HEADER LibraryOptionalHeader = NULL;
322 BOOL ForwarderBound = FALSE;
323 PUCHAR ForwarderName;
324 TRACE("Binding a Thunk\n");
325
326 /* Get the Pointers to the Tables */
327 AddressOfNames = ImageRvaToVa(Library->FileHeader,
328 Library->MappedAddress,
329 Exports->AddressOfNames,
330 &Library->LastRvaSection);
331 AddressOfOrdinals = ImageRvaToVa(Library->FileHeader,
332 Library->MappedAddress,
333 Exports->AddressOfNameOrdinals,
334 &Library->LastRvaSection);
335 AddressOfPointers = ImageRvaToVa(Library->FileHeader,
336 Library->MappedAddress,
337 Exports->AddressOfFunctions,
338 &Library->LastRvaSection);
339
340 /* Get the Optional Headers */
341 OptionalHeader = &Image->FileHeader->OptionalHeader;
342 LibraryOptionalHeader = &Library->FileHeader->OptionalHeader;
343
344 /* Import by Ordinal */
345 if (IMAGE_SNAP_BY_ORDINAL(Thunk->u1.Ordinal) == TRUE)
346 {
347 /* Get the ordinal number and pointer to the name */
348 OrdinalNumber = (IMAGE_ORDINAL(Thunk->u1.Ordinal) - Exports->Base);
349 ImportName = (PIMAGE_IMPORT_BY_NAME)NameBuffer;
350
351 /* Setup the name for this ordinal */
352 sprintf((PCHAR)ImportName->Name, "Ordinal%lx\n", OrdinalNumber);
353 }
354 else
355 {
356 /* Import by Name, get the data */
357 ImportName = ImageRvaToVa(Image->FileHeader,
358 Image->MappedAddress,
359 (ULONG)Thunk->u1.AddressOfData,
360 &Image->LastRvaSection);
361
362 /* Get the hint and see if we can use it */
363 OrdinalNumber = (USHORT)(Exports->NumberOfFunctions + 1);
364 HintIndex = ImportName->Hint;
365 if (HintIndex < Exports->NumberOfNames)
366 {
367 /* Hint seems valid, get the export name */
368 ExportName = ImageRvaToVa(Library->FileHeader,
369 Library->MappedAddress,
370 (ULONG)AddressOfNames[HintIndex],
371 &Library->LastRvaSection);
372 /* Check if it's the one we want */
373 if (!strcmp((PCHAR)ImportName->Name, ExportName))
374 {
375 OrdinalNumber = AddressOfOrdinals[HintIndex];
376 }
377 }
378
379 /* If the ordinal isn't valid, we'll have to do a long loop */
380 if (OrdinalNumber >= Exports->NumberOfFunctions)
381 {
382 for (HintIndex = 0; HintIndex < Exports->NumberOfNames; HintIndex++)
383 {
384 /* Get the Export Name */
385 ExportName = ImageRvaToVa(Library->FileHeader,
386 Library->MappedAddress,
387 (ULONG)AddressOfNames[HintIndex],
388 &Library->LastRvaSection);
389
390 /* Check if it's the one we want */
391 if (!strcmp((PCHAR)ImportName->Name, ExportName))
392 {
393 OrdinalNumber = AddressOfOrdinals[HintIndex];
394 break;
395 }
396 }
397
398 /* Make sure it's valid now */
399 if (OrdinalNumber >= Exports->NumberOfFunctions) return FALSE;
400 }
401 }
402
403 /* Write the Pointer */
404 ThunkFunction->u1.Function = AddressOfPointers[OrdinalNumber] +
405 LibraryOptionalHeader->ImageBase;
406
407 /* Load DLL's Exports */
408 ExportsBase = (ULONG_PTR)ImageDirectoryEntryToData(Library->MappedAddress,
409 TRUE,
410 IMAGE_DIRECTORY_ENTRY_EXPORT,
411 &ExportSize) -
412 (ULONG_PTR)Library->MappedAddress;
413
414 /* RVA to VA */
415 ExportsBase += LibraryOptionalHeader->ImageBase;
416
417 /* Check if the Export is forwarded (meaning that it's pointer is inside the Export Table) */
418 if ((ThunkFunction->u1.Function > ExportsBase) &&
419 (ThunkFunction->u1.Function < ExportsBase + ExportSize))
420 {
421 /* Make sure we have a descriptor */
422 if (BoundImportDescriptor)
423 {
424 TRACE("This Thunk is a forward...calling forward thunk bounder\n");
425
426 /* Get the VA of the pointer containg the name */
427 ForwarderName = ImageRvaToVa(Library->FileHeader,
428 Library->MappedAddress,
429 AddressOfPointers[OrdinalNumber],
430 &Library->LastRvaSection);
431
432 /* Replace the Forwarder String by the actual name */
433 ThunkFunction->u1.ForwarderString =
434 PtrToUlong(BindpAddForwarderReference(Image->ModuleName,
435 (PCHAR)ImportName->Name,
436 BoundImportDescriptor,
437 DllPath,
438 (PCHAR)ForwarderName,
439 &ForwarderBound));
440 }
441
442 /* Check if it wasn't bound */
443 if (!ForwarderBound)
444 {
445 /* Set the chain to the ordinal to reflect this */
446 **Forwarders = (ULONG)(ThunkFunction - BoundThunk);
447 *Forwarders = (PULONG)&ThunkFunction->u1.Ordinal;
448 }
449 }
450
451 /* Return Success */
452 return TRUE;
453 }
454
455 static PIMAGE_BOUND_IMPORT_DESCRIPTOR
456 IMAGEAPI
457 BindpCreateNewImportSection(PIMPORT_DESCRIPTOR *BoundImportDescriptor,
458 PULONG BoundImportsSize)
459 {
460 ULONG BoundLibraryNamesSize = 0, BoundImportTableSize = 0;
461 PBOUND_FORWARDER_REFS Forwarder, *NextForwarder;
462 PIMPORT_DESCRIPTOR Descriptor, *NextDescriptor;
463 LPSTR BoundLibraryNames;
464 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundTableEntry, BoundTable;
465 PIMAGE_BOUND_FORWARDER_REF BoundForwarder;
466
467 /* Zero the outoging size */
468 *BoundImportsSize = 0;
469
470 /* Loop the descriptors and forwarders to get the size */
471 NextDescriptor = BoundImportDescriptor;
472 while ((Descriptor = *NextDescriptor))
473 {
474 /* Add to the size of the Bound Import Table */
475 BoundImportTableSize += sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR);
476
477 /* Check Forwarders */
478 NextForwarder = &Descriptor->Forwarders;
479 while ((Forwarder = *NextForwarder))
480 {
481 /* Add to size of Bound Import Table */
482 BoundImportTableSize += sizeof(IMAGE_BOUND_FORWARDER_REF);
483
484 /* Next Forwarder */
485 NextForwarder = &Forwarder->Next;
486 }
487
488 /* Read Next Internal Descriptor */
489 NextDescriptor = &Descriptor->Next;
490 }
491
492 /* Add Terminator for PE Loader*/
493 BoundImportTableSize += sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR);
494 TRACE("Table size: %lx\n", BoundImportTableSize);
495
496 /* Name of Libraries Bound in Bound Import Table */
497 BoundLibraryNamesSize = (ULONG)((ULONG_PTR)BoundLibrariesPointer -
498 (ULONG_PTR)BoundLibraries);
499 BoundLibrariesPointer = NULL;
500
501 /* Size of the whole table, dword aligned */
502 *BoundImportsSize = BoundImportTableSize +
503 ((BoundLibraryNamesSize + sizeof(ULONG) - 1) &
504 ~(sizeof(ULONG) - 1));
505
506 /* Allocate it */
507 BoundTable = HeapAlloc(IMAGEHLP_hHeap, HEAP_ZERO_MEMORY, *BoundImportsSize);
508
509 /* Pointer Library Names inside the Bound Import Table */
510 BoundLibraryNames = (LPSTR)BoundTable + BoundImportTableSize;
511
512 /* Copy the Library Names */
513 RtlCopyMemory(BoundLibraryNames, BoundLibraries, BoundLibraryNamesSize);
514
515 /* Now loop both tables */
516 BoundTableEntry = BoundTable;
517 NextDescriptor = BoundImportDescriptor;
518 while ((Descriptor = *NextDescriptor))
519 {
520 /* Copy the data */
521 BoundTableEntry->TimeDateStamp = Descriptor->TimeDateStamp;
522 BoundTableEntry->OffsetModuleName = (USHORT)(ULONG_PTR)(BoundImportTableSize +
523 (Descriptor->ModuleName -
524 (ULONG_PTR)BoundLibraries));
525 BoundTableEntry->NumberOfModuleForwarderRefs = Descriptor->ForwaderReferences;
526
527 /* Now loop the forwarders */
528 BoundForwarder = (PIMAGE_BOUND_FORWARDER_REF)BoundTableEntry + 1;
529 NextForwarder = &Descriptor->Forwarders;
530 while ((Forwarder = *NextForwarder))
531 {
532 /* Copy the data */
533 BoundForwarder->TimeDateStamp = Forwarder->TimeDateStamp;
534 BoundForwarder->OffsetModuleName = (USHORT)(ULONG_PTR)(BoundImportTableSize +
535 (Forwarder->ModuleName -
536 (ULONG_PTR)BoundLibraries));
537
538 /* Move to the next new forwarder, and move to the next entry */
539 BoundForwarder++;
540 NextForwarder = &Forwarder->Next;
541 }
542
543 /* Move to next Bound Import Table Entry */
544 BoundTableEntry = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)BoundForwarder;
545
546 /* Move to the next descriptor */
547 NextDescriptor = &Descriptor->Next;
548 }
549
550 /* Loop the descriptors and forwarders to free them */
551 NextDescriptor = BoundImportDescriptor;
552 while ((Descriptor = *NextDescriptor))
553 {
554 /* Read next internal descriptor */
555 *NextDescriptor = Descriptor->Next;
556
557 /* Loop its forwarders */
558 NextForwarder = &Descriptor->Forwarders;
559 while ((Forwarder = *NextForwarder))
560 {
561 /* Next Forwarder */
562 *NextForwarder = Forwarder->Next;
563
564 /* Free it */
565 HeapFree(IMAGEHLP_hHeap, 0, Forwarder);
566 }
567
568 /* Free it */
569 HeapFree(IMAGEHLP_hHeap, 0, Descriptor);
570 }
571
572 /* Return the Bound Import Table */
573 return BoundTable;
574 }
575
576 static VOID
577 IMAGEAPI
578 BindpWalkAndProcessImports(PLOADED_IMAGE File,
579 LPSTR DllPath,
580 PBOOLEAN UpdateImage)
581 {
582 PIMAGE_IMPORT_DESCRIPTOR Imports;
583 PIMAGE_EXPORT_DIRECTORY Exports;
584 ULONG SizeOfImports;
585 ULONG SizeOfExports;
586 ULONG SizeOfThunks;
587 PIMAGE_OPTIONAL_HEADER OptionalHeader;
588 PIMAGE_FILE_HEADER FileHeader;
589 LPSTR ImportedLibrary;
590 PLOADED_IMAGE LoadedLibrary;
591 ULONG TopForwarderChain;
592 PULONG ForwarderChain;
593 PIMPORT_DESCRIPTOR TopBoundDescriptor = NULL, BoundImportDescriptor;
594 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportTable, OldBoundImportTable;
595 PIMAGE_THUNK_DATA Thunks, TempThunk;
596 PIMAGE_THUNK_DATA BoundThunks, TempBoundThunk;
597 ULONG ThunkCount = 0;
598 ULONG Thunk;
599 ULONG BoundImportTableSize, OldBoundImportTableSize;
600 ULONG VirtBytesFree, HeaderBytesFree, FirstFreeByte, PhysBytesFree;
601 BOOL ThunkStatus;
602 TRACE("BindpWalkAndBindImports Called\n");
603
604 /* Assume untouched image */
605 *UpdateImage = FALSE;
606
607 /* Load the Import Descriptor */
608 Imports = ImageDirectoryEntryToData(File->MappedAddress,
609 FALSE,
610 IMAGE_DIRECTORY_ENTRY_IMPORT,
611 &SizeOfImports);
612 if (!Imports) return;
613
614 /* Read the File Header */
615 FileHeader = &File->FileHeader->FileHeader;
616 OptionalHeader = &File->FileHeader->OptionalHeader;
617
618 /* Get the old Bound Import Table, if any */
619 OldBoundImportTable = ImageDirectoryEntryToData(File->MappedAddress,
620 FALSE,
621 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
622 &OldBoundImportTableSize);
623
624 /* For each Import */
625 while(Imports)
626 {
627 /* Make sure we have a name */
628 if (!Imports->Name) break;
629
630 /* Which DLL is being Imported */
631 ImportedLibrary = ImageRvaToVa(File->FileHeader,
632 File->MappedAddress,
633 Imports->Name,
634 &File->LastRvaSection);
635 if (ImportedLibrary)
636 {
637 TRACE("Loading Imported DLL: %s \n", ImportedLibrary);
638
639 /* Load the DLL */
640 LoadedLibrary = ImageLoad(ImportedLibrary, DllPath);
641 if (!LoadedLibrary)
642 {
643 /* Create the descriptor, even if we failed */
644 BindpAddImportDescriptor(&TopBoundDescriptor,
645 Imports,
646 ImportedLibrary,
647 LoadedLibrary);
648
649 /* Move on the next file */
650 Imports++;
651 continue;
652 }
653
654 /* Now load the Exports */
655 TRACE("DLL Loaded at: %p \n", LoadedLibrary->MappedAddress);
656 Exports = ImageDirectoryEntryToData(LoadedLibrary->MappedAddress,
657 FALSE,
658 IMAGE_DIRECTORY_ENTRY_EXPORT,
659 &SizeOfExports);
660
661 /* Move on, if we don't have exports */
662 if (!Exports) continue;
663
664 /* And load the Thunks */
665 Thunks = ImageRvaToVa(File->FileHeader,
666 File->MappedAddress,
667 (ULONG)Imports->OriginalFirstThunk,
668 &File->LastRvaSection);
669
670 /* No actual Exports (UPX Packer can do this */
671 if (!(Thunks) || !(Thunks->u1.Function)) continue;
672
673 /* Create Bound Import Descriptor */
674 TRACE("Creating Bound Descriptor for this DLL\n");
675 BoundImportDescriptor = BindpAddImportDescriptor(&TopBoundDescriptor,
676 Imports,
677 ImportedLibrary,
678 LoadedLibrary);
679
680 /* Count how many Thunks we have */
681 ThunkCount = 0;
682 TempThunk = Thunks;
683 while (TempThunk->u1.AddressOfData)
684 {
685 ThunkCount++;
686 TempThunk++;
687 }
688
689 /* Allocate Memory for the Thunks we will Bind */
690 SizeOfThunks = ThunkCount * sizeof(*TempBoundThunk);
691 BoundThunks = HeapAlloc(IMAGEHLP_hHeap,
692 HEAP_ZERO_MEMORY,
693 SizeOfThunks);
694
695 /* Setup the initial data pointers */
696 TRACE("Binding Thunks\n");
697 TempThunk = Thunks;
698 TempBoundThunk = BoundThunks;
699 TopForwarderChain = -1;
700 ForwarderChain = &TopForwarderChain;
701
702 /* Loop for every thunk */
703 for (Thunk = 0; Thunk < ThunkCount; Thunk++)
704 {
705 /* Bind it */
706 ThunkStatus = BindpLookupThunk(TempThunk,
707 File,
708 BoundThunks,
709 TempBoundThunk,
710 LoadedLibrary,
711 Exports,
712 BoundImportDescriptor,
713 DllPath,
714 &ForwarderChain);
715 /* Check if binding failed */
716 if (!ThunkStatus)
717 {
718 /* If we have a descriptor */
719 if (BoundImportDescriptor)
720 {
721 /* Zero the timestamp */
722 BoundImportDescriptor->TimeDateStamp = 0;
723 }
724
725 /* Quit the loop */
726 break;
727 }
728
729 /* Move on */
730 TempThunk++;
731 TempBoundThunk++;
732 }
733
734 /* Load the Second Thunk Array */
735 TempThunk = ImageRvaToVa(File->FileHeader,
736 File->MappedAddress,
737 (ULONG)Imports->FirstThunk,
738 &File->LastRvaSection);
739 if (TempThunk)
740 {
741 /* Check if the forwarder chain changed */
742 if (TopForwarderChain != -1)
743 {
744 /* It did. Update the chain and let caller know */
745 *ForwarderChain = -1;
746 *UpdateImage = TRUE;
747 }
748
749 /* Check if we're not pointing at the new top chain */
750 if (Imports->ForwarderChain != TopForwarderChain)
751 {
752 /* Update it, and let the caller know */
753 Imports->ForwarderChain = TopForwarderChain;
754 *UpdateImage = TRUE;
755 }
756
757 /* Check if thunks have changed */
758 if (memcmp(TempThunk, BoundThunks, SizeOfThunks))
759 {
760 /* Copy the Pointers and let caller know */
761 TRACE("Copying Bound Thunks\n");
762 RtlCopyMemory(TempThunk, BoundThunks, SizeOfThunks);
763 *UpdateImage = TRUE;
764 }
765
766 /* Check if we have no bound entries */
767 if (!TopBoundDescriptor)
768 {
769 /* Check if the timestamp is different */
770 if (Imports->TimeDateStamp != FileHeader->TimeDateStamp)
771 {
772 /* Update it, and let the caller knmow */
773 Imports->TimeDateStamp = FileHeader->TimeDateStamp;
774 *UpdateImage = TRUE;
775 }
776 }
777 else if ((Imports->TimeDateStamp != 0xFFFFFFFF))
778 {
779 /* Invalidate the timedate stamp */
780 Imports->TimeDateStamp = 0xFFFFFFFF;
781 }
782 }
783
784 /* Free the Allocated Memory */
785 HeapFree(IMAGEHLP_hHeap, 0, BoundThunks);
786
787 TRACE("Moving to next File\n");
788 Imports++;
789 }
790 }
791
792 /* Create the Bound Import Table */
793 TRACE("Creating Bound Import Section\n");
794 BoundImportTable = BindpCreateNewImportSection(&TopBoundDescriptor,
795 &BoundImportTableSize);
796
797 /* Check if the import table changed */
798 if (OldBoundImportTableSize != BoundImportTableSize)
799 {
800 /* Let the caller know */
801 *UpdateImage = TRUE;
802 }
803
804 /*
805 * At this point, check if anything that we've done until now has resulted
806 * in the image being touched. If not, then we'll simply return to caller.
807 */
808 if (!(*UpdateImage)) return;
809
810 /* Check if we have a new table */
811 if (BoundImportTable)
812 {
813 /* Zero it out */
814 OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
815 OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
816
817 /* Check if we have enough space */
818 TRACE("Calculating Space\n");
819 FirstFreeByte = GetImageUnusedHeaderBytes(File, &VirtBytesFree);
820 HeaderBytesFree = File->Sections->VirtualAddress -
821 OptionalHeader->SizeOfHeaders + VirtBytesFree;
822 PhysBytesFree = File->Sections->PointerToRawData -
823 OptionalHeader->SizeOfHeaders + VirtBytesFree;
824
825 /* Check if we overflowed */
826 if (BoundImportTableSize > VirtBytesFree)
827 {
828 /* Check if we have no space a tall */
829 if (BoundImportTableSize > HeaderBytesFree)
830 {
831 ERR("Not enough Space\n");
832 return; /* Fail...not enough space */
833 }
834
835 /* Check if we have space on disk to enlarge it */
836 if (BoundImportTableSize <= PhysBytesFree)
837 {
838 /* We have enough NULLs to add it, simply enlarge header data */
839 TRACE("Header Recalculation\n");
840 OptionalHeader->SizeOfHeaders = OptionalHeader->SizeOfHeaders -
841 VirtBytesFree +
842 BoundImportTableSize +
843 ((OptionalHeader->FileAlignment - 1) &
844 ~(OptionalHeader->FileAlignment - 1));
845 }
846 else
847 {
848 /* Resize the Headers */
849 FIXME("UNIMPLEMENTED: Header Resizing\n");
850
851 /* Recalculate Headers */
852 FileHeader = &File->FileHeader->FileHeader;
853 OptionalHeader = &File->FileHeader->OptionalHeader;
854 }
855 }
856
857 /* Set Bound Import Table Data */
858 OptionalHeader->DataDirectory
859 [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = FirstFreeByte;
860 OptionalHeader->DataDirectory
861 [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = BoundImportTableSize;
862
863 /* Copy the Bound Import Table */
864 TRACE("Copying Bound Import Table\n");
865 RtlCopyMemory(File->MappedAddress + FirstFreeByte,
866 BoundImportTable,
867 BoundImportTableSize);
868
869 /* Free the data */
870 HeapFree(IMAGEHLP_hHeap, 0, BoundImportTable);
871 }
872
873 }
874
875 /***********************************************************************
876 * BindImageEx (IMAGEHLP.@)
877 */
878 BOOL IMAGEAPI BindImageEx(
879 DWORD Flags, LPSTR ImageName, LPSTR DllPath, LPSTR SymbolPath,
880 PIMAGEHLP_STATUS_ROUTINE StatusRoutine)
881 {
882 LOADED_IMAGE FileData;
883 PLOADED_IMAGE File;
884 PIMAGE_FILE_HEADER FileHeader;
885 PIMAGE_OPTIONAL_HEADER OptionalHeader;
886 ULONG CheckSum, HeaderCheckSum, OldChecksum;
887 SYSTEMTIME SystemTime;
888 FILETIME LastWriteTime;
889 BOOLEAN UpdateImage;
890 DWORD DataSize;
891 TRACE("BindImageEx Called for: %s \n", ImageName);
892
893 /* Set and Clear Buffer */
894 File = &FileData;
895 RtlZeroMemory(File, sizeof(*File));
896
897 /* Request Image Data */
898 if (MapAndLoad(ImageName, DllPath, File, TRUE, FALSE))
899 {
900 /* Write the image's name */
901 TRACE("Image Mapped and Loaded\n");
902 File->ModuleName = ImageName;
903
904 /* Check if the image is valid and if it should be bound */
905 if ((File->FileHeader) &&
906 ((Flags & BIND_ALL_IMAGES) || (!File->fSystemImage)))
907 {
908 /* Get the optional header */
909 FileHeader = &File->FileHeader->FileHeader;
910 OptionalHeader = &File->FileHeader->OptionalHeader;
911
912 /* Check if this image should be bound */
913 if (OptionalHeader->DllCharacteristics &
914 IMAGE_DLLCHARACTERISTICS_NO_BIND)
915 {
916 /* Don't bind it */
917 goto Skip;
918 }
919
920 /* Check if the image has security data */
921 if ((ImageDirectoryEntryToData(File->MappedAddress,
922 FALSE,
923 IMAGE_DIRECTORY_ENTRY_SECURITY,
924 &DataSize)) || DataSize)
925 {
926 /* It does, skip it */
927 goto Skip;
928 }
929
930 /* Read Import Table */
931 BindpWalkAndProcessImports(File, DllPath, &UpdateImage);
932
933 /* Check if we need to update the image */
934 if ((UpdateImage) && (File->hFile != INVALID_HANDLE_VALUE))
935 {
936 /* FIXME: Update symbols */
937
938 /* Update Checksum */
939 TRACE("Binding Completed, getting Checksum\n");
940 OldChecksum = File->FileHeader->OptionalHeader.CheckSum;
941 CheckSumMappedFile(File->MappedAddress,
942 GetFileSize(File->hFile, NULL),
943 &HeaderCheckSum,
944 &CheckSum);
945 File->FileHeader->OptionalHeader.CheckSum = CheckSum;
946
947 /* Save Changes */
948 TRACE("Saving Changes to file\n");
949 FlushViewOfFile(File->MappedAddress, File->SizeOfImage);
950
951 /* Save new Modified Time */
952 TRACE("Setting time\n");
953 GetSystemTime(&SystemTime);
954 SystemTimeToFileTime(&SystemTime, &LastWriteTime);
955 SetFileTime(File->hFile, NULL, NULL, &LastWriteTime);
956 }
957 }
958 }
959
960 Skip:
961
962 /* Unmap the image */
963 UnmapViewOfFile(File->MappedAddress);
964
965 /* Close the handle if it's valid */
966 if (File->hFile != INVALID_HANDLE_VALUE) CloseHandle(File->hFile);
967
968 /* Unload all the images if we're not supposed to cache them */
969 if (!(Flags & BIND_CACHE_IMPORT_DLLS)) UnloadAllImages();
970
971 /* Return success */
972 TRACE("Done\n");
973 return TRUE;
974 }
975
976 /* FUNCTIONS *****************************************************************/
977
978 /*
979 * @implemented
980 */
981 BOOL
982 IMAGEAPI
983 TouchFileTimes(HANDLE FileHandle,
984 LPSYSTEMTIME lpSystemTime)
985 {
986 FILETIME FileTime;
987 SYSTEMTIME SystemTime;
988
989 if(lpSystemTime == NULL)
990 {
991 GetSystemTime(&SystemTime);
992 lpSystemTime = &SystemTime;
993 }
994
995 return (SystemTimeToFileTime(lpSystemTime,
996 &FileTime) &&
997 SetFileTime(FileHandle,
998 NULL,
999 NULL,
1000 &FileTime));
1001 }
1002
1003 /***********************************************************************
1004 * MapFileAndCheckSumA (IMAGEHLP.@)
1005 */
1006 DWORD IMAGEAPI MapFileAndCheckSumA(
1007 LPSTR Filename, LPDWORD HeaderSum, LPDWORD CheckSum)
1008 {
1009 HANDLE hFile;
1010 HANDLE hMapping;
1011 LPVOID BaseAddress;
1012 DWORD FileLength;
1013
1014 TRACE("(%s, %p, %p): stub\n",
1015 debugstr_a(Filename), HeaderSum, CheckSum
1016 );
1017
1018 hFile = CreateFileA(Filename,
1019 GENERIC_READ,
1020 FILE_SHARE_READ | FILE_SHARE_WRITE,
1021 NULL,
1022 OPEN_EXISTING,
1023 FILE_ATTRIBUTE_NORMAL,
1024 0);
1025 if (hFile == INVALID_HANDLE_VALUE)
1026 {
1027 return CHECKSUM_OPEN_FAILURE;
1028 }
1029
1030 hMapping = CreateFileMappingW(hFile,
1031 NULL,
1032 PAGE_READONLY,
1033 0,
1034 0,
1035 NULL);
1036 if (hMapping == 0)
1037 {
1038 CloseHandle(hFile);
1039 return CHECKSUM_MAP_FAILURE;
1040 }
1041
1042 BaseAddress = MapViewOfFile(hMapping,
1043 FILE_MAP_READ,
1044 0,
1045 0,
1046 0);
1047 if (BaseAddress == NULL)
1048 {
1049 CloseHandle(hMapping);
1050 CloseHandle(hFile);
1051 return CHECKSUM_MAPVIEW_FAILURE;
1052 }
1053
1054 FileLength = GetFileSize(hFile,
1055 NULL);
1056
1057 CheckSumMappedFile(BaseAddress,
1058 FileLength,
1059 HeaderSum,
1060 CheckSum);
1061
1062 UnmapViewOfFile(BaseAddress);
1063 CloseHandle(hMapping);
1064 CloseHandle(hFile);
1065
1066 return 0;
1067 }
1068
1069 /***********************************************************************
1070 * MapFileAndCheckSumW (IMAGEHLP.@)
1071 */
1072 DWORD IMAGEAPI MapFileAndCheckSumW(
1073 LPWSTR Filename, LPDWORD HeaderSum, LPDWORD CheckSum)
1074 {
1075 HANDLE hFile;
1076 HANDLE hMapping;
1077 LPVOID BaseAddress;
1078 DWORD FileLength;
1079
1080 TRACE("(%s, %p, %p): stub\n",
1081 debugstr_w(Filename), HeaderSum, CheckSum
1082 );
1083
1084 hFile = CreateFileW(Filename,
1085 GENERIC_READ,
1086 FILE_SHARE_READ | FILE_SHARE_WRITE,
1087 NULL,
1088 OPEN_EXISTING,
1089 FILE_ATTRIBUTE_NORMAL,
1090 0);
1091 if (hFile == INVALID_HANDLE_VALUE)
1092 {
1093 return CHECKSUM_OPEN_FAILURE;
1094 }
1095
1096 hMapping = CreateFileMappingW(hFile,
1097 NULL,
1098 PAGE_READONLY,
1099 0,
1100 0,
1101 NULL);
1102 if (hMapping == 0)
1103 {
1104 CloseHandle(hFile);
1105 return CHECKSUM_MAP_FAILURE;
1106 }
1107
1108 BaseAddress = MapViewOfFile(hMapping,
1109 FILE_MAP_READ,
1110 0,
1111 0,
1112 0);
1113 if (BaseAddress == NULL)
1114 {
1115 CloseHandle(hMapping);
1116 CloseHandle(hFile);
1117 return CHECKSUM_MAPVIEW_FAILURE;
1118 }
1119
1120 FileLength = GetFileSize(hFile,
1121 NULL);
1122
1123 CheckSumMappedFile(BaseAddress,
1124 FileLength,
1125 HeaderSum,
1126 CheckSum);
1127
1128 UnmapViewOfFile(BaseAddress);
1129 CloseHandle(hMapping);
1130 CloseHandle(hFile);
1131
1132 return 0;
1133 }
1134
1135 /***********************************************************************
1136 * ReBaseImage (IMAGEHLP.@)
1137 */
1138 BOOL IMAGEAPI ReBaseImage(
1139 LPSTR CurrentImageName, LPSTR SymbolPath, BOOL fReBase,
1140 BOOL fRebaseSysfileOk, BOOL fGoingDown, ULONG CheckImageSize,
1141 ULONG *OldImageSize, ULONG *OldImageBase, ULONG *NewImageSize,
1142 ULONG *NewImageBase, ULONG TimeStamp)
1143 {
1144 FIXME(
1145 "(%s, %s, %d, %d, %d, %ld, %p, %p, %p, %p, %ld): stub\n",
1146 debugstr_a(CurrentImageName),debugstr_a(SymbolPath), fReBase,
1147 fRebaseSysfileOk, fGoingDown, CheckImageSize, OldImageSize,
1148 OldImageBase, NewImageSize, NewImageBase, TimeStamp
1149 );
1150 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1151 return FALSE;
1152 }
1153
1154 /***********************************************************************
1155 * RemovePrivateCvSymbolic (IMAGEHLP.@)
1156 */
1157 BOOL IMAGEAPI RemovePrivateCvSymbolic(
1158 PCHAR DebugData, PCHAR *NewDebugData, ULONG *NewDebugSize)
1159 {
1160 FIXME("(%p, %p, %p): stub\n",
1161 DebugData, NewDebugData, NewDebugSize
1162 );
1163 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1164 return FALSE;
1165 }
1166
1167 /***********************************************************************
1168 * RemoveRelocations (IMAGEHLP.@)
1169 */
1170 VOID IMAGEAPI RemoveRelocations(PCHAR ImageName)
1171 {
1172 FIXME("(%p): stub\n", ImageName);
1173 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1174 }
1175
1176 /***********************************************************************
1177 * SplitSymbols (IMAGEHLP.@)
1178 */
1179 BOOL IMAGEAPI SplitSymbols(
1180 LPSTR ImageName, LPSTR SymbolsPath,
1181 LPSTR SymbolFilePath, DWORD Flags)
1182 {
1183 FIXME("(%s, %s, %s, %ld): stub\n",
1184 debugstr_a(ImageName), debugstr_a(SymbolsPath),
1185 debugstr_a(SymbolFilePath), Flags
1186 );
1187 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1188 return FALSE;
1189 }
1190
1191 /***********************************************************************
1192 * UpdateDebugInfoFile (IMAGEHLP.@)
1193 */
1194 BOOL IMAGEAPI UpdateDebugInfoFile(
1195 LPSTR ImageFileName, LPSTR SymbolPath,
1196 LPSTR DebugFilePath, PIMAGE_NT_HEADERS NtHeaders)
1197 {
1198 FIXME("(%s, %s, %s, %p): stub\n",
1199 debugstr_a(ImageFileName), debugstr_a(SymbolPath),
1200 debugstr_a(DebugFilePath), NtHeaders
1201 );
1202 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1203 return FALSE;
1204 }
1205
1206 /***********************************************************************
1207 * UpdateDebugInfoFileEx (IMAGEHLP.@)
1208 */
1209 BOOL IMAGEAPI UpdateDebugInfoFileEx(
1210 LPSTR ImageFileName, LPSTR SymbolPath, LPSTR DebugFilePath,
1211 PIMAGE_NT_HEADERS NtHeaders, DWORD OldChecksum)
1212 {
1213 FIXME("(%s, %s, %s, %p, %ld): stub\n",
1214 debugstr_a(ImageFileName), debugstr_a(SymbolPath),
1215 debugstr_a(DebugFilePath), NtHeaders, OldChecksum
1216 );
1217 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1218 return FALSE;
1219 }