4 * Copyright 1998 Patrik Stridvall
5 * Copyright 2005 Alex Ionescu
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.
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.
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
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(imagehlp
);
29 /* DATA **********************************************************************/
31 CHAR BoundLibraries
[4096];
32 LPSTR BoundLibrariesPointer
;
34 /***********************************************************************
35 * BindImage (IMAGEHLP.@)
37 BOOL WINAPI
BindImage(
38 LPSTR ImageName
, LPSTR DllPath
, LPSTR SymbolPath
)
40 return BindImageEx(0, ImageName
, DllPath
, SymbolPath
, NULL
);
45 BindpCaptureImportModuleName(LPSTR ModuleName
)
47 LPSTR Name
= BoundLibraries
;
49 /* Check if it hasn't been initialized yet */
50 if (!BoundLibrariesPointer
)
52 /* Start with a null char and set the pointer */
54 BoundLibrariesPointer
= Name
;
57 /* Loop the current buffer */
60 /* Try to match this DLL's name and return it */
61 if (!_stricmp(Name
, ModuleName
)) return Name
;
63 /* Move on to the next DLL Name */
64 Name
+= strlen(Name
) + sizeof(CHAR
);
67 /* If we got here, we didn't find one, so add this one to our buffer */
68 strcpy(Name
, ModuleName
);
70 /* Set the new position of the buffer, and null-terminate it */
71 BoundLibrariesPointer
= Name
+ strlen(Name
) + sizeof(CHAR
);
72 *BoundLibrariesPointer
= ANSI_NULL
;
74 /* Return the pointer to the name */
79 static PIMPORT_DESCRIPTOR
81 BindpAddImportDescriptor(PIMPORT_DESCRIPTOR
*BoundImportDescriptor
,
82 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
,
86 PIMPORT_DESCRIPTOR Descriptor
, *NextDescriptor
;
88 /* Loop descriptors and check if this library has already been bound */
89 NextDescriptor
= BoundImportDescriptor
;
90 while ((Descriptor
= *NextDescriptor
))
92 /* Compare the names and return the descriptor if found */
93 if (!_stricmp(Descriptor
->ModuleName
, DllName
)) return Descriptor
;
95 /* Move to the next one */
96 NextDescriptor
= &Descriptor
->Next
;
99 /* Allocate a new descriptor */
100 Descriptor
= HeapAlloc(IMAGEHLP_hHeap
,
102 sizeof(IMPORT_DESCRIPTOR
));
104 /* Set its Data and check if we have a valid loaded image */
105 Descriptor
->ModuleName
= BindpCaptureImportModuleName(DllName
);
106 *NextDescriptor
= Descriptor
;
109 /* Save the time stamp */
110 Descriptor
->TimeDateStamp
= Image
->FileHeader
->FileHeader
.TimeDateStamp
;
113 /* Return the descriptor */
119 BindpAddForwarderReference(LPSTR ModuleName
,
121 PIMPORT_DESCRIPTOR BoundImportDescriptor
,
123 PCHAR ForwarderString
,
124 PBOOL ForwarderBound
)
127 PCHAR TempDllName
, FunctionName
;
128 PLOADED_IMAGE Library
;
130 USHORT OrdinalNumber
;
133 PIMAGE_EXPORT_DIRECTORY Exports
;
134 ULONG_PTR ExportsBase
;
135 PULONG AddressOfNames
;
136 PUSHORT AddressOfOrdinals
;
137 PULONG AddressOfPointers
;
139 ULONG_PTR ForwardedAddress
;
140 PBOUND_FORWARDER_REFS Forwarder
, *NextForwarder
;
141 PIMAGE_OPTIONAL_HEADER OptionalHeader
= NULL
;
145 /* Get the DLL Name */
146 TempDllName
= ForwarderString
;
147 while (*TempDllName
&& *TempDllName
!= '.') TempDllName
++;
148 if (*TempDllName
!= '.') return ForwarderString
;
151 DllNameSize
= (SIZE_T
)(TempDllName
- ForwarderString
);
152 if (DllNameSize
>= MAX_PATH
) return ForwarderString
;
154 /* Now copy the name and append the extension */
155 strncpy(DllName
, ForwarderString
, DllNameSize
);
156 DllName
[DllNameSize
] = ANSI_NULL
;
157 strcat(DllName
, ".DLL");
160 TRACE("Loading the Thunk Library: %s \n", DllName
);
161 Library
= ImageLoad(DllName
, DllPath
);
162 if (!Library
) return ForwarderString
;
164 /* Move past the name */
165 TRACE("It Loaded at: %p \n", Library
->MappedAddress
);
166 FunctionName
= TempDllName
+= 1;
169 Exports
= ImageDirectoryEntryToData(Library
->MappedAddress
,
171 IMAGE_DIRECTORY_ENTRY_EXPORT
,
173 if (!Exports
) return ForwarderString
;
175 /* Get the Optional Header */
176 OptionalHeader
= &Library
->FileHeader
->OptionalHeader
;
178 /* Check if we're binding by ordinal */
179 if (*FunctionName
== '#')
181 /* We are, get the number and validate it */
182 OrdinalNumber
= atoi(FunctionName
+ 1) - (USHORT
)Exports
->Base
;
183 if (OrdinalNumber
>= Exports
->NumberOfFunctions
) return ForwarderString
;
187 /* Binding by name... */
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
);
205 /* Check if we're binding by name... */
206 if (OrdinalNumber
== 0xffff)
208 /* Do a full search for the ordinal */
209 for (HintIndex
= 0; HintIndex
< Exports
->NumberOfNames
; HintIndex
++)
211 /* Get the Export Name */
212 ExportName
= ImageRvaToVa(Library
->FileHeader
,
213 Library
->MappedAddress
,
214 (ULONG
)AddressOfNames
[HintIndex
],
215 &Library
->LastRvaSection
);
217 /* Check if it's the one we want */
218 if (!strcmp(FunctionName
, ExportName
))
220 OrdinalNumber
= AddressOfOrdinals
[HintIndex
];
225 /* Make sure it's valid */
226 if (HintIndex
>= Exports
->NumberOfNames
) return ForwarderString
;
229 /* Get the Forwarded Address */
230 ForwardedAddress
= AddressOfPointers
[OrdinalNumber
] +
231 OptionalHeader
->ImageBase
;
233 /* Loop the forwarders to see if this DLL was already processed */
234 NextForwarder
= &BoundImportDescriptor
->Forwarders
;
235 while ((Forwarder
= *NextForwarder
))
237 /* Check for a name match */
238 if (!_stricmp(DllName
, Forwarder
->ModuleName
)) break;
240 /* Move to the next one */
241 NextForwarder
= &Forwarder
->Next
;
244 /* Check if we've went through them all without luck */
247 /* Allocate a forwarder structure */
248 Forwarder
= HeapAlloc(IMAGEHLP_hHeap
,
250 sizeof(BOUND_FORWARDER_REFS
));
253 Forwarder
->ModuleName
= BindpCaptureImportModuleName(DllName
);
255 /* Increase the number of forwarders */
256 BoundImportDescriptor
->ForwaderReferences
++;
259 *NextForwarder
= Forwarder
;
262 /* Set the timestamp */
263 Forwarder
->TimeDateStamp
= Library
->FileHeader
->FileHeader
.TimeDateStamp
;
265 /* Load DLL's Exports */
266 ExportsBase
= (ULONG_PTR
)ImageDirectoryEntryToData(Library
->MappedAddress
,
268 IMAGE_DIRECTORY_ENTRY_EXPORT
,
270 (ULONG_PTR
)Library
->MappedAddress
;
273 ExportsBase
+= OptionalHeader
->ImageBase
;
275 /* Is this yet another Forward? */
276 TRACE("I've thunked it\n");
277 if ((ForwardedAddress
> ExportsBase
) &&
278 (ForwardedAddress
< (ExportsBase
+ ExportSize
)))
280 /* Update the string pointer */
281 ForwarderString
= ImageRvaToVa(Library
->FileHeader
,
282 Library
->MappedAddress
,
283 AddressOfPointers
[OrdinalNumber
],
284 &Library
->LastRvaSection
);
289 /* Update the pointer and return success */
290 ForwarderString
= (PCHAR
)ForwardedAddress
;
291 *ForwarderBound
= TRUE
;
294 /* Return the pointer */
295 return ForwarderString
;
300 BindpLookupThunk(PIMAGE_THUNK_DATA Thunk
,
302 PIMAGE_THUNK_DATA BoundThunk
,
303 PIMAGE_THUNK_DATA ThunkFunction
,
304 PLOADED_IMAGE Library
,
305 PIMAGE_EXPORT_DIRECTORY Exports
,
306 PIMPORT_DESCRIPTOR BoundImportDescriptor
,
310 PULONG AddressOfNames
;
311 PUSHORT AddressOfOrdinals
;
312 PULONG AddressOfPointers
;
313 PIMAGE_IMPORT_BY_NAME ImportName
;
314 ULONG OrdinalNumber
= 0;
317 ULONG_PTR ExportsBase
;
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");
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
);
340 /* Get the Optional Headers */
341 OptionalHeader
= &Image
->FileHeader
->OptionalHeader
;
342 LibraryOptionalHeader
= &Library
->FileHeader
->OptionalHeader
;
344 /* Import by Ordinal */
345 if (IMAGE_SNAP_BY_ORDINAL(Thunk
->u1
.Ordinal
) == TRUE
)
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
;
351 /* Setup the name for this ordinal */
352 sprintf((PCHAR
)ImportName
->Name
, "Ordinal%lx\n", OrdinalNumber
);
356 /* Import by Name, get the data */
357 ImportName
= ImageRvaToVa(Image
->FileHeader
,
358 Image
->MappedAddress
,
359 (ULONG
)Thunk
->u1
.AddressOfData
,
360 &Image
->LastRvaSection
);
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
)
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
))
375 OrdinalNumber
= AddressOfOrdinals
[HintIndex
];
379 /* If the ordinal isn't valid, we'll have to do a long loop */
380 if (OrdinalNumber
>= Exports
->NumberOfFunctions
)
382 for (HintIndex
= 0; HintIndex
< Exports
->NumberOfNames
; HintIndex
++)
384 /* Get the Export Name */
385 ExportName
= ImageRvaToVa(Library
->FileHeader
,
386 Library
->MappedAddress
,
387 (ULONG
)AddressOfNames
[HintIndex
],
388 &Library
->LastRvaSection
);
390 /* Check if it's the one we want */
391 if (!strcmp((PCHAR
)ImportName
->Name
, ExportName
))
393 OrdinalNumber
= AddressOfOrdinals
[HintIndex
];
398 /* Make sure it's valid now */
399 if (OrdinalNumber
>= Exports
->NumberOfFunctions
) return FALSE
;
403 /* Write the Pointer */
404 ThunkFunction
->u1
.Function
= AddressOfPointers
[OrdinalNumber
] +
405 LibraryOptionalHeader
->ImageBase
;
407 /* Load DLL's Exports */
408 ExportsBase
= (ULONG_PTR
)ImageDirectoryEntryToData(Library
->MappedAddress
,
410 IMAGE_DIRECTORY_ENTRY_EXPORT
,
412 (ULONG_PTR
)Library
->MappedAddress
;
415 ExportsBase
+= LibraryOptionalHeader
->ImageBase
;
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
))
421 /* Make sure we have a descriptor */
422 if (BoundImportDescriptor
)
424 TRACE("This Thunk is a forward...calling forward thunk bounder\n");
426 /* Get the VA of the pointer containg the name */
427 ForwarderName
= ImageRvaToVa(Library
->FileHeader
,
428 Library
->MappedAddress
,
429 AddressOfPointers
[OrdinalNumber
],
430 &Library
->LastRvaSection
);
432 /* Replace the Forwarder String by the actual name */
433 ThunkFunction
->u1
.ForwarderString
=
434 PtrToUlong(BindpAddForwarderReference(Image
->ModuleName
,
435 (PCHAR
)ImportName
->Name
,
436 BoundImportDescriptor
,
438 (PCHAR
)ForwarderName
,
442 /* Check if it wasn't bound */
445 /* Set the chain to the ordinal to reflect this */
446 **Forwarders
= (ULONG
)(ThunkFunction
- BoundThunk
);
447 *Forwarders
= (PULONG
)&ThunkFunction
->u1
.Ordinal
;
455 static PIMAGE_BOUND_IMPORT_DESCRIPTOR
457 BindpCreateNewImportSection(PIMPORT_DESCRIPTOR
*BoundImportDescriptor
,
458 PULONG BoundImportsSize
)
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
;
467 /* Zero the outoging size */
468 *BoundImportsSize
= 0;
470 /* Loop the descriptors and forwarders to get the size */
471 NextDescriptor
= BoundImportDescriptor
;
472 while ((Descriptor
= *NextDescriptor
))
474 /* Add to the size of the Bound Import Table */
475 BoundImportTableSize
+= sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR
);
477 /* Check Forwarders */
478 NextForwarder
= &Descriptor
->Forwarders
;
479 while ((Forwarder
= *NextForwarder
))
481 /* Add to size of Bound Import Table */
482 BoundImportTableSize
+= sizeof(IMAGE_BOUND_FORWARDER_REF
);
485 NextForwarder
= &Forwarder
->Next
;
488 /* Read Next Internal Descriptor */
489 NextDescriptor
= &Descriptor
->Next
;
492 /* Add Terminator for PE Loader*/
493 BoundImportTableSize
+= sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR
);
494 TRACE("Table size: %lx\n", BoundImportTableSize
);
496 /* Name of Libraries Bound in Bound Import Table */
497 BoundLibraryNamesSize
= (ULONG
)((ULONG_PTR
)BoundLibrariesPointer
-
498 (ULONG_PTR
)BoundLibraries
);
499 BoundLibrariesPointer
= NULL
;
501 /* Size of the whole table, dword aligned */
502 *BoundImportsSize
= BoundImportTableSize
+
503 ((BoundLibraryNamesSize
+ sizeof(ULONG
) - 1) &
504 ~(sizeof(ULONG
) - 1));
507 BoundTable
= HeapAlloc(IMAGEHLP_hHeap
, HEAP_ZERO_MEMORY
, *BoundImportsSize
);
509 /* Pointer Library Names inside the Bound Import Table */
510 BoundLibraryNames
= (LPSTR
)BoundTable
+ BoundImportTableSize
;
512 /* Copy the Library Names */
513 RtlCopyMemory(BoundLibraryNames
, BoundLibraries
, BoundLibraryNamesSize
);
515 /* Now loop both tables */
516 BoundTableEntry
= BoundTable
;
517 NextDescriptor
= BoundImportDescriptor
;
518 while ((Descriptor
= *NextDescriptor
))
521 BoundTableEntry
->TimeDateStamp
= Descriptor
->TimeDateStamp
;
522 BoundTableEntry
->OffsetModuleName
= (USHORT
)(ULONG_PTR
)(BoundImportTableSize
+
523 (Descriptor
->ModuleName
-
524 (ULONG_PTR
)BoundLibraries
));
525 BoundTableEntry
->NumberOfModuleForwarderRefs
= Descriptor
->ForwaderReferences
;
527 /* Now loop the forwarders */
528 BoundForwarder
= (PIMAGE_BOUND_FORWARDER_REF
)BoundTableEntry
+ 1;
529 NextForwarder
= &Descriptor
->Forwarders
;
530 while ((Forwarder
= *NextForwarder
))
533 BoundForwarder
->TimeDateStamp
= Forwarder
->TimeDateStamp
;
534 BoundForwarder
->OffsetModuleName
= (USHORT
)(ULONG_PTR
)(BoundImportTableSize
+
535 (Forwarder
->ModuleName
-
536 (ULONG_PTR
)BoundLibraries
));
538 /* Move to the next new forwarder, and move to the next entry */
540 NextForwarder
= &Forwarder
->Next
;
543 /* Move to next Bound Import Table Entry */
544 BoundTableEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)BoundForwarder
;
546 /* Move to the next descriptor */
547 NextDescriptor
= &Descriptor
->Next
;
550 /* Loop the descriptors and forwarders to free them */
551 NextDescriptor
= BoundImportDescriptor
;
552 while ((Descriptor
= *NextDescriptor
))
554 /* Read next internal descriptor */
555 *NextDescriptor
= Descriptor
->Next
;
557 /* Loop its forwarders */
558 NextForwarder
= &Descriptor
->Forwarders
;
559 while ((Forwarder
= *NextForwarder
))
562 *NextForwarder
= Forwarder
->Next
;
565 HeapFree(IMAGEHLP_hHeap
, 0, Forwarder
);
569 HeapFree(IMAGEHLP_hHeap
, 0, Descriptor
);
572 /* Return the Bound Import Table */
578 BindpWalkAndProcessImports(PLOADED_IMAGE File
,
580 PBOOLEAN UpdateImage
)
582 PIMAGE_IMPORT_DESCRIPTOR Imports
;
583 PIMAGE_EXPORT_DIRECTORY Exports
;
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;
599 ULONG BoundImportTableSize
, OldBoundImportTableSize
;
600 ULONG VirtBytesFree
, HeaderBytesFree
, FirstFreeByte
, PhysBytesFree
;
602 TRACE("BindpWalkAndBindImports Called\n");
604 /* Assume untouched image */
605 *UpdateImage
= FALSE
;
607 /* Load the Import Descriptor */
608 Imports
= ImageDirectoryEntryToData(File
->MappedAddress
,
610 IMAGE_DIRECTORY_ENTRY_IMPORT
,
612 if (!Imports
) return;
614 /* Read the File Header */
615 FileHeader
= &File
->FileHeader
->FileHeader
;
616 OptionalHeader
= &File
->FileHeader
->OptionalHeader
;
618 /* Get the old Bound Import Table, if any */
619 OldBoundImportTable
= ImageDirectoryEntryToData(File
->MappedAddress
,
621 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
622 &OldBoundImportTableSize
);
624 /* For each Import */
627 /* Make sure we have a name */
628 if (!Imports
->Name
) break;
630 /* Which DLL is being Imported */
631 ImportedLibrary
= ImageRvaToVa(File
->FileHeader
,
634 &File
->LastRvaSection
);
637 TRACE("Loading Imported DLL: %s \n", ImportedLibrary
);
640 LoadedLibrary
= ImageLoad(ImportedLibrary
, DllPath
);
643 /* Create the descriptor, even if we failed */
644 BindpAddImportDescriptor(&TopBoundDescriptor
,
649 /* Move on the next file */
654 /* Now load the Exports */
655 TRACE("DLL Loaded at: %p \n", LoadedLibrary
->MappedAddress
);
656 Exports
= ImageDirectoryEntryToData(LoadedLibrary
->MappedAddress
,
658 IMAGE_DIRECTORY_ENTRY_EXPORT
,
661 /* Move on, if we don't have exports */
662 if (!Exports
) continue;
664 /* And load the Thunks */
665 Thunks
= ImageRvaToVa(File
->FileHeader
,
667 (ULONG
)Imports
->OriginalFirstThunk
,
668 &File
->LastRvaSection
);
670 /* No actual Exports (UPX Packer can do this */
671 if (!(Thunks
) || !(Thunks
->u1
.Function
)) continue;
673 /* Create Bound Import Descriptor */
674 TRACE("Creating Bound Descriptor for this DLL\n");
675 BoundImportDescriptor
= BindpAddImportDescriptor(&TopBoundDescriptor
,
680 /* Count how many Thunks we have */
683 while (TempThunk
->u1
.AddressOfData
)
689 /* Allocate Memory for the Thunks we will Bind */
690 SizeOfThunks
= ThunkCount
* sizeof(*TempBoundThunk
);
691 BoundThunks
= HeapAlloc(IMAGEHLP_hHeap
,
695 /* Setup the initial data pointers */
696 TRACE("Binding Thunks\n");
698 TempBoundThunk
= BoundThunks
;
699 TopForwarderChain
= -1;
700 ForwarderChain
= &TopForwarderChain
;
702 /* Loop for every thunk */
703 for (Thunk
= 0; Thunk
< ThunkCount
; Thunk
++)
706 ThunkStatus
= BindpLookupThunk(TempThunk
,
712 BoundImportDescriptor
,
715 /* Check if binding failed */
718 /* If we have a descriptor */
719 if (BoundImportDescriptor
)
721 /* Zero the timestamp */
722 BoundImportDescriptor
->TimeDateStamp
= 0;
734 /* Load the Second Thunk Array */
735 TempThunk
= ImageRvaToVa(File
->FileHeader
,
737 (ULONG
)Imports
->FirstThunk
,
738 &File
->LastRvaSection
);
741 /* Check if the forwarder chain changed */
742 if (TopForwarderChain
!= -1)
744 /* It did. Update the chain and let caller know */
745 *ForwarderChain
= -1;
749 /* Check if we're not pointing at the new top chain */
750 if (Imports
->ForwarderChain
!= TopForwarderChain
)
752 /* Update it, and let the caller know */
753 Imports
->ForwarderChain
= TopForwarderChain
;
757 /* Check if thunks have changed */
758 if (memcmp(TempThunk
, BoundThunks
, SizeOfThunks
))
760 /* Copy the Pointers and let caller know */
761 TRACE("Copying Bound Thunks\n");
762 RtlCopyMemory(TempThunk
, BoundThunks
, SizeOfThunks
);
766 /* Check if we have no bound entries */
767 if (!TopBoundDescriptor
)
769 /* Check if the timestamp is different */
770 if (Imports
->TimeDateStamp
!= FileHeader
->TimeDateStamp
)
772 /* Update it, and let the caller knmow */
773 Imports
->TimeDateStamp
= FileHeader
->TimeDateStamp
;
777 else if ((Imports
->TimeDateStamp
!= 0xFFFFFFFF))
779 /* Invalidate the timedate stamp */
780 Imports
->TimeDateStamp
= 0xFFFFFFFF;
784 /* Free the Allocated Memory */
785 HeapFree(IMAGEHLP_hHeap
, 0, BoundThunks
);
787 TRACE("Moving to next File\n");
792 /* Create the Bound Import Table */
793 TRACE("Creating Bound Import Section\n");
794 BoundImportTable
= BindpCreateNewImportSection(&TopBoundDescriptor
,
795 &BoundImportTableSize
);
797 /* Check if the import table changed */
798 if (OldBoundImportTableSize
!= BoundImportTableSize
)
800 /* Let the caller know */
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.
808 if (!(*UpdateImage
)) return;
810 /* Check if we have a new table */
811 if (BoundImportTable
)
814 OptionalHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
].VirtualAddress
= 0;
815 OptionalHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
].Size
= 0;
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
;
825 /* Check if we overflowed */
826 if (BoundImportTableSize
> VirtBytesFree
)
828 /* Check if we have no space a tall */
829 if (BoundImportTableSize
> HeaderBytesFree
)
831 ERR("Not enough Space\n");
832 return; /* Fail...not enough space */
835 /* Check if we have space on disk to enlarge it */
836 if (BoundImportTableSize
<= PhysBytesFree
)
838 /* We have enough NULLs to add it, simply enlarge header data */
839 TRACE("Header Recalculation\n");
840 OptionalHeader
->SizeOfHeaders
= OptionalHeader
->SizeOfHeaders
-
842 BoundImportTableSize
+
843 ((OptionalHeader
->FileAlignment
- 1) &
844 ~(OptionalHeader
->FileAlignment
- 1));
848 /* Resize the Headers */
849 FIXME("UNIMPLEMENTED: Header Resizing\n");
851 /* Recalculate Headers */
852 FileHeader
= &File
->FileHeader
->FileHeader
;
853 OptionalHeader
= &File
->FileHeader
->OptionalHeader
;
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
;
863 /* Copy the Bound Import Table */
864 TRACE("Copying Bound Import Table\n");
865 RtlCopyMemory(File
->MappedAddress
+ FirstFreeByte
,
867 BoundImportTableSize
);
870 HeapFree(IMAGEHLP_hHeap
, 0, BoundImportTable
);
875 /***********************************************************************
876 * BindImageEx (IMAGEHLP.@)
878 BOOL IMAGEAPI
BindImageEx(
879 DWORD Flags
, LPSTR ImageName
, LPSTR DllPath
, LPSTR SymbolPath
,
880 PIMAGEHLP_STATUS_ROUTINE StatusRoutine
)
882 LOADED_IMAGE FileData
;
884 PIMAGE_FILE_HEADER FileHeader
;
885 PIMAGE_OPTIONAL_HEADER OptionalHeader
;
886 ULONG CheckSum
, HeaderCheckSum
, OldChecksum
;
887 SYSTEMTIME SystemTime
;
888 FILETIME LastWriteTime
;
891 TRACE("BindImageEx Called for: %s \n", ImageName
);
893 /* Set and Clear Buffer */
895 RtlZeroMemory(File
, sizeof(*File
));
897 /* Request Image Data */
898 if (MapAndLoad(ImageName
, DllPath
, File
, TRUE
, FALSE
))
900 /* Write the image's name */
901 TRACE("Image Mapped and Loaded\n");
902 File
->ModuleName
= ImageName
;
904 /* Check if the image is valid and if it should be bound */
905 if ((File
->FileHeader
) &&
906 ((Flags
& BIND_ALL_IMAGES
) || (!File
->fSystemImage
)))
908 /* Get the optional header */
909 FileHeader
= &File
->FileHeader
->FileHeader
;
910 OptionalHeader
= &File
->FileHeader
->OptionalHeader
;
912 /* Check if this image should be bound */
913 if (OptionalHeader
->DllCharacteristics
&
914 IMAGE_DLLCHARACTERISTICS_NO_BIND
)
920 /* Check if the image has security data */
921 if ((ImageDirectoryEntryToData(File
->MappedAddress
,
923 IMAGE_DIRECTORY_ENTRY_SECURITY
,
924 &DataSize
)) || DataSize
)
926 /* It does, skip it */
930 /* Read Import Table */
931 BindpWalkAndProcessImports(File
, DllPath
, &UpdateImage
);
933 /* Check if we need to update the image */
934 if ((UpdateImage
) && (File
->hFile
!= INVALID_HANDLE_VALUE
))
936 /* FIXME: Update symbols */
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
),
945 File
->FileHeader
->OptionalHeader
.CheckSum
= CheckSum
;
948 TRACE("Saving Changes to file\n");
949 FlushViewOfFile(File
->MappedAddress
, File
->SizeOfImage
);
951 /* Save new Modified Time */
952 TRACE("Setting time\n");
953 GetSystemTime(&SystemTime
);
954 SystemTimeToFileTime(&SystemTime
, &LastWriteTime
);
955 SetFileTime(File
->hFile
, NULL
, NULL
, &LastWriteTime
);
962 /* Unmap the image */
963 UnmapViewOfFile(File
->MappedAddress
);
965 /* Close the handle if it's valid */
966 if (File
->hFile
!= INVALID_HANDLE_VALUE
) CloseHandle(File
->hFile
);
968 /* Unload all the images if we're not supposed to cache them */
969 if (!(Flags
& BIND_CACHE_IMPORT_DLLS
)) UnloadAllImages();
976 /* FUNCTIONS *****************************************************************/
983 TouchFileTimes(HANDLE FileHandle
,
984 LPSYSTEMTIME lpSystemTime
)
987 SYSTEMTIME SystemTime
;
989 if(lpSystemTime
== NULL
)
991 GetSystemTime(&SystemTime
);
992 lpSystemTime
= &SystemTime
;
995 return (SystemTimeToFileTime(lpSystemTime
,
997 SetFileTime(FileHandle
,
1003 /***********************************************************************
1004 * MapFileAndCheckSumA (IMAGEHLP.@)
1006 DWORD IMAGEAPI
MapFileAndCheckSumA(
1007 LPSTR Filename
, LPDWORD HeaderSum
, LPDWORD CheckSum
)
1014 TRACE("(%s, %p, %p): stub\n",
1015 debugstr_a(Filename
), HeaderSum
, CheckSum
1018 hFile
= CreateFileA(Filename
,
1020 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1023 FILE_ATTRIBUTE_NORMAL
,
1025 if (hFile
== INVALID_HANDLE_VALUE
)
1027 return CHECKSUM_OPEN_FAILURE
;
1030 hMapping
= CreateFileMappingW(hFile
,
1039 return CHECKSUM_MAP_FAILURE
;
1042 BaseAddress
= MapViewOfFile(hMapping
,
1047 if (BaseAddress
== NULL
)
1049 CloseHandle(hMapping
);
1051 return CHECKSUM_MAPVIEW_FAILURE
;
1054 FileLength
= GetFileSize(hFile
,
1057 CheckSumMappedFile(BaseAddress
,
1062 UnmapViewOfFile(BaseAddress
);
1063 CloseHandle(hMapping
);
1069 /***********************************************************************
1070 * MapFileAndCheckSumW (IMAGEHLP.@)
1072 DWORD IMAGEAPI
MapFileAndCheckSumW(
1073 LPWSTR Filename
, LPDWORD HeaderSum
, LPDWORD CheckSum
)
1080 TRACE("(%s, %p, %p): stub\n",
1081 debugstr_w(Filename
), HeaderSum
, CheckSum
1084 hFile
= CreateFileW(Filename
,
1086 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1089 FILE_ATTRIBUTE_NORMAL
,
1091 if (hFile
== INVALID_HANDLE_VALUE
)
1093 return CHECKSUM_OPEN_FAILURE
;
1096 hMapping
= CreateFileMappingW(hFile
,
1105 return CHECKSUM_MAP_FAILURE
;
1108 BaseAddress
= MapViewOfFile(hMapping
,
1113 if (BaseAddress
== NULL
)
1115 CloseHandle(hMapping
);
1117 return CHECKSUM_MAPVIEW_FAILURE
;
1120 FileLength
= GetFileSize(hFile
,
1123 CheckSumMappedFile(BaseAddress
,
1128 UnmapViewOfFile(BaseAddress
);
1129 CloseHandle(hMapping
);
1135 /***********************************************************************
1136 * ReBaseImage (IMAGEHLP.@)
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
)
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
1150 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1154 /***********************************************************************
1155 * RemovePrivateCvSymbolic (IMAGEHLP.@)
1157 BOOL IMAGEAPI
RemovePrivateCvSymbolic(
1158 PCHAR DebugData
, PCHAR
*NewDebugData
, ULONG
*NewDebugSize
)
1160 FIXME("(%p, %p, %p): stub\n",
1161 DebugData
, NewDebugData
, NewDebugSize
1163 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1167 /***********************************************************************
1168 * RemoveRelocations (IMAGEHLP.@)
1170 VOID IMAGEAPI
RemoveRelocations(PCHAR ImageName
)
1172 FIXME("(%p): stub\n", ImageName
);
1173 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1176 /***********************************************************************
1177 * SplitSymbols (IMAGEHLP.@)
1179 BOOL IMAGEAPI
SplitSymbols(
1180 LPSTR ImageName
, LPSTR SymbolsPath
,
1181 LPSTR SymbolFilePath
, DWORD Flags
)
1183 FIXME("(%s, %s, %s, %ld): stub\n",
1184 debugstr_a(ImageName
), debugstr_a(SymbolsPath
),
1185 debugstr_a(SymbolFilePath
), Flags
1187 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1191 /***********************************************************************
1192 * UpdateDebugInfoFile (IMAGEHLP.@)
1194 BOOL IMAGEAPI
UpdateDebugInfoFile(
1195 LPSTR ImageFileName
, LPSTR SymbolPath
,
1196 LPSTR DebugFilePath
, PIMAGE_NT_HEADERS NtHeaders
)
1198 FIXME("(%s, %s, %s, %p): stub\n",
1199 debugstr_a(ImageFileName
), debugstr_a(SymbolPath
),
1200 debugstr_a(DebugFilePath
), NtHeaders
1202 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1206 /***********************************************************************
1207 * UpdateDebugInfoFileEx (IMAGEHLP.@)
1209 BOOL IMAGEAPI
UpdateDebugInfoFileEx(
1210 LPSTR ImageFileName
, LPSTR SymbolPath
, LPSTR DebugFilePath
,
1211 PIMAGE_NT_HEADERS NtHeaders
, DWORD OldChecksum
)
1213 FIXME("(%s, %s, %s, %p, %ld): stub\n",
1214 debugstr_a(ImageFileName
), debugstr_a(SymbolPath
),
1215 debugstr_a(DebugFilePath
), NtHeaders
, OldChecksum
1217 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);