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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 /* INCLUDES ******************************************************************/
29 /* DATA **********************************************************************/
31 CHAR BoundLibraries
[4096];
32 LPSTR BoundLibrariesPointer
;
34 /* FUNCTIONS *****************************************************************/
38 BindpCaptureImportModuleName(LPSTR ModuleName
)
40 LPSTR Name
= BoundLibraries
;
42 /* Check if it hasn't been initialized yet */
43 if (!BoundLibrariesPointer
)
45 /* Start with a null char and set the pointer */
47 BoundLibrariesPointer
= Name
;
50 /* Loop the current buffer */
53 /* Try to match this DLL's name and return it */
54 if (!_stricmp(Name
, ModuleName
)) return Name
;
56 /* Move on to the next DLL Name */
57 Name
+= strlen(Name
) + sizeof(CHAR
);
60 /* If we got here, we didn't find one, so add this one to our buffer */
61 strcpy(Name
, ModuleName
);
63 /* Set the new position of the buffer, and null-terminate it */
64 BoundLibrariesPointer
= Name
+ strlen(Name
) + sizeof(CHAR
);
65 *BoundLibrariesPointer
= ANSI_NULL
;
67 /* Return the pointer to the name */
71 PIMAGE_BOUND_IMPORT_DESCRIPTOR
73 BindpCreateNewImportSection(PIMPORT_DESCRIPTOR
*BoundImportDescriptor
,
74 PULONG BoundImportsSize
)
76 ULONG BoundLibraryNamesSize
= 0, BoundImportTableSize
= 0;
77 PBOUND_FORWARDER_REFS Forwarder
, *NextForwarder
;
78 PIMPORT_DESCRIPTOR Descriptor
, *NextDescriptor
;
79 LPSTR BoundLibraryNames
;
80 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundTableEntry
, BoundTable
;
81 PIMAGE_BOUND_FORWARDER_REF BoundForwarder
;
83 /* Zero the outoging size */
84 *BoundImportsSize
= 0;
86 /* Loop the descriptors and forwarders to get the size */
87 NextDescriptor
= BoundImportDescriptor
;
88 while ((Descriptor
= *NextDescriptor
))
90 /* Add to the size of the Bound Import Table */
91 BoundImportTableSize
+= sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR
);
93 /* Check Forwarders */
94 NextForwarder
= &Descriptor
->Forwarders
;
95 while ((Forwarder
= *NextForwarder
))
97 /* Add to size of Bound Import Table */
98 BoundImportTableSize
+= sizeof(IMAGE_BOUND_FORWARDER_REF
);
101 NextForwarder
= &Forwarder
->Next
;
104 /* Read Next Internal Descriptor */
105 NextDescriptor
= &Descriptor
->Next
;
108 /* Add Terminator for PE Loader*/
109 BoundImportTableSize
+= sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR
);
110 DPRINT("Table size: %lx\n", BoundImportTableSize
);
112 /* Name of Libraries Bound in Bound Import Table */
113 BoundLibraryNamesSize
= (ULONG
)((ULONG_PTR
)BoundLibrariesPointer
-
114 (ULONG_PTR
)BoundLibraries
);
115 BoundLibrariesPointer
= NULL
;
117 /* Size of the whole table, dword aligned */
118 *BoundImportsSize
= BoundImportTableSize
+
119 ((BoundLibraryNamesSize
+ sizeof(ULONG
) - 1) &
120 ~(sizeof(ULONG
) - 1));
123 BoundTable
= HeapAlloc(IMAGEHLP_hHeap
, HEAP_ZERO_MEMORY
, *BoundImportsSize
);
125 /* Pointer Library Names inside the Bound Import Table */
126 BoundLibraryNames
= (LPSTR
)BoundTable
+ BoundImportTableSize
;
128 /* Copy the Library Names */
129 RtlCopyMemory(BoundLibraryNames
, BoundLibraries
, BoundLibraryNamesSize
);
131 /* Now loop both tables */
132 BoundTableEntry
= BoundTable
;
133 NextDescriptor
= BoundImportDescriptor
;
134 while ((Descriptor
= *NextDescriptor
))
137 BoundTableEntry
->TimeDateStamp
= Descriptor
->TimeDateStamp
;
138 BoundTableEntry
->OffsetModuleName
= (USHORT
)(BoundImportTableSize
+
139 (Descriptor
->ModuleName
-
140 (ULONG_PTR
)BoundLibraries
));
141 BoundTableEntry
->NumberOfModuleForwarderRefs
= Descriptor
->ForwaderReferences
;
143 /* Now loop the forwarders */
144 BoundForwarder
= (PIMAGE_BOUND_FORWARDER_REF
)BoundTableEntry
+ 1;
145 NextForwarder
= &Descriptor
->Forwarders
;
146 while ((Forwarder
= *NextForwarder
))
149 BoundForwarder
->TimeDateStamp
= Forwarder
->TimeDateStamp
;
150 BoundForwarder
->OffsetModuleName
= (USHORT
)(BoundImportTableSize
+
151 (Forwarder
->ModuleName
-
152 (ULONG_PTR
)BoundLibraries
));
154 /* Move to the next new forwarder, and move to the next entry */
156 NextForwarder
= &Forwarder
->Next
;
159 /* Move to next Bound Import Table Entry */
160 BoundTableEntry
= (PIMAGE_BOUND_IMPORT_DESCRIPTOR
)BoundForwarder
;
162 /* Move to the next descriptor */
163 NextDescriptor
= &Descriptor
->Next
;
166 /* Loop the descriptors and forwarders to free them */
167 NextDescriptor
= BoundImportDescriptor
;
168 while ((Descriptor
= *NextDescriptor
))
170 /* Read next internal descriptor */
171 *NextDescriptor
= Descriptor
->Next
;
173 /* Loop its forwarders */
174 NextForwarder
= &Descriptor
->Forwarders
;
175 while ((Forwarder
= *NextForwarder
))
178 *NextForwarder
= Forwarder
->Next
;
181 HeapFree(IMAGEHLP_hHeap
, 0, Forwarder
);
185 HeapFree(IMAGEHLP_hHeap
, 0, Descriptor
);
188 /* Return the Bound Import Table */
194 BindpAddForwarderReference(LPSTR ModuleName
,
196 PIMPORT_DESCRIPTOR BoundImportDescriptor
,
198 PCHAR ForwarderString
,
199 PBOOL ForwarderBound
)
202 PCHAR TempDllName
, FunctionName
;
203 PLOADED_IMAGE Library
;
205 USHORT OrdinalNumber
;
208 PIMAGE_EXPORT_DIRECTORY Exports
;
209 ULONG_PTR ExportsBase
;
210 PULONG AddressOfNames
;
211 PUSHORT AddressOfOrdinals
;
212 PULONG AddressOfPointers
;
214 ULONG_PTR ForwardedAddress
;
215 PBOUND_FORWARDER_REFS Forwarder
, *NextForwarder
;
216 PIMAGE_OPTIONAL_HEADER OptionalHeader
= NULL
;
220 /* Get the DLL Name */
221 TempDllName
= ForwarderString
;
222 while (*TempDllName
&& *TempDllName
!= '.') TempDllName
++;
223 if (*TempDllName
!= '.') return ForwarderString
;
226 DllNameSize
= (SIZE_T
)(TempDllName
- ForwarderString
);
227 if (DllNameSize
>= MAX_PATH
) return ForwarderString
;
229 /* Now copy the name and append the extension */
230 strncpy(DllName
, ForwarderString
, DllNameSize
);
231 DllName
[DllNameSize
] = ANSI_NULL
;
232 strcat(DllName
, ".DLL");
235 DPRINT("Loading the Thunk Library: %s \n", DllName
);
236 Library
= ImageLoad(DllName
, DllPath
);
237 if (!Library
) return ForwarderString
;
239 /* Move past the name */
240 DPRINT("It Loaded at: %p \n", Library
->MappedAddress
);
241 FunctionName
= TempDllName
+= 1;
244 Exports
= ImageDirectoryEntryToData(Library
->MappedAddress
,
246 IMAGE_DIRECTORY_ENTRY_EXPORT
,
248 if (!Exports
) return ForwarderString
;
250 /* Get the Optional Header */
251 OptionalHeader
= &Library
->FileHeader
->OptionalHeader
;
253 /* Check if we're binding by ordinal */
254 if (*FunctionName
== '#')
256 /* We are, get the number and validate it */
257 OrdinalNumber
= atoi(FunctionName
+ 1) - (USHORT
)Exports
->Base
;
258 if (OrdinalNumber
>= Exports
->NumberOfFunctions
) return ForwarderString
;
262 /* Binding by name... */
266 /* Get the Pointers to the Tables */
267 AddressOfNames
= ImageRvaToVa(Library
->FileHeader
,
268 Library
->MappedAddress
,
269 Exports
->AddressOfNames
,
270 &Library
->LastRvaSection
);
271 AddressOfOrdinals
= ImageRvaToVa(Library
->FileHeader
,
272 Library
->MappedAddress
,
273 Exports
->AddressOfNameOrdinals
,
274 &Library
->LastRvaSection
);
275 AddressOfPointers
= ImageRvaToVa(Library
->FileHeader
,
276 Library
->MappedAddress
,
277 Exports
->AddressOfFunctions
,
278 &Library
->LastRvaSection
);
280 /* Check if we're binding by name... */
281 if (OrdinalNumber
== 0xffff)
283 /* Do a full search for the ordinal */
284 for (HintIndex
= 0; HintIndex
< Exports
->NumberOfNames
; HintIndex
++)
286 /* Get the Export Name */
287 ExportName
= ImageRvaToVa(Library
->FileHeader
,
288 Library
->MappedAddress
,
289 (ULONG
)AddressOfNames
[HintIndex
],
290 &Library
->LastRvaSection
);
292 /* Check if it's the one we want */
293 if (!strcmp(FunctionName
, ExportName
))
295 OrdinalNumber
= AddressOfOrdinals
[HintIndex
];
300 /* Make sure it's valid */
301 if (HintIndex
>= Exports
->NumberOfNames
) return ForwarderString
;
304 /* Get the Forwarded Address */
305 ForwardedAddress
= AddressOfPointers
[OrdinalNumber
] +
306 OptionalHeader
->ImageBase
;
308 /* Loop the forwarders to see if this DLL was already processed */
309 NextForwarder
= &BoundImportDescriptor
->Forwarders
;
310 while ((Forwarder
= *NextForwarder
))
312 /* Check for a name match */
313 if (!_stricmp(DllName
, Forwarder
->ModuleName
)) break;
315 /* Move to the next one */
316 NextForwarder
= &Forwarder
->Next
;
319 /* Check if we've went through them all without luck */
322 /* Allocate a forwarder structure */
323 Forwarder
= HeapAlloc(IMAGEHLP_hHeap
,
325 sizeof(BOUND_FORWARDER_REFS
));
328 Forwarder
->ModuleName
= BindpCaptureImportModuleName(DllName
);
330 /* Increase the number of forwarders */
331 BoundImportDescriptor
->ForwaderReferences
++;
334 *NextForwarder
= Forwarder
;
337 /* Set the timestamp */
338 Forwarder
->TimeDateStamp
= Library
->FileHeader
->FileHeader
.TimeDateStamp
;
340 /* Load DLL's Exports */
341 ExportsBase
= (ULONG_PTR
)ImageDirectoryEntryToData(Library
->MappedAddress
,
343 IMAGE_DIRECTORY_ENTRY_EXPORT
,
345 (ULONG_PTR
)Library
->MappedAddress
;
348 ExportsBase
+= OptionalHeader
->ImageBase
;
350 /* Is this yet another Forward? */
351 DPRINT("I've thunked it\n");
352 if ((ForwardedAddress
> ExportsBase
) &&
353 (ForwardedAddress
< (ExportsBase
+ ExportSize
)))
355 /* Update the string pointer */
356 ForwarderString
= ImageRvaToVa(Library
->FileHeader
,
357 Library
->MappedAddress
,
358 AddressOfPointers
[OrdinalNumber
],
359 &Library
->LastRvaSection
);
364 /* Update the pointer and return success */
365 ForwarderString
= (PUCHAR
)ForwardedAddress
;
366 *ForwarderBound
= TRUE
;
369 /* Return the pointer */
370 return ForwarderString
;
375 BindpLookupThunk(PIMAGE_THUNK_DATA Thunk
,
377 PIMAGE_THUNK_DATA BoundThunk
,
378 PIMAGE_THUNK_DATA ThunkFunction
,
379 PLOADED_IMAGE Library
,
380 PIMAGE_EXPORT_DIRECTORY Exports
,
381 PIMPORT_DESCRIPTOR BoundImportDescriptor
,
385 PULONG AddressOfNames
;
386 PUSHORT AddressOfOrdinals
;
387 PULONG AddressOfPointers
;
388 PIMAGE_IMPORT_BY_NAME ImportName
;
389 ULONG OrdinalNumber
= 0;
392 ULONG_PTR ExportsBase
;
394 UCHAR NameBuffer
[32];
395 PIMAGE_OPTIONAL_HEADER OptionalHeader
= NULL
;
396 PIMAGE_OPTIONAL_HEADER LibraryOptionalHeader
= NULL
;
397 BOOL ForwarderBound
= FALSE
;
398 PUCHAR ForwarderName
;
399 DPRINT("Binding a Thunk\n");
401 /* Get the Pointers to the Tables */
402 AddressOfNames
= ImageRvaToVa(Library
->FileHeader
,
403 Library
->MappedAddress
,
404 Exports
->AddressOfNames
,
405 &Library
->LastRvaSection
);
406 AddressOfOrdinals
= ImageRvaToVa(Library
->FileHeader
,
407 Library
->MappedAddress
,
408 Exports
->AddressOfNameOrdinals
,
409 &Library
->LastRvaSection
);
410 AddressOfPointers
= ImageRvaToVa(Library
->FileHeader
,
411 Library
->MappedAddress
,
412 Exports
->AddressOfFunctions
,
413 &Library
->LastRvaSection
);
415 /* Get the Optional Headers */
416 OptionalHeader
= &Image
->FileHeader
->OptionalHeader
;
417 LibraryOptionalHeader
= &Library
->FileHeader
->OptionalHeader
;
419 /* Import by Ordinal */
420 if (IMAGE_SNAP_BY_ORDINAL(Thunk
->u1
.Ordinal
) == TRUE
)
422 /* Get the ordinal number and pointer to the name */
423 OrdinalNumber
= (IMAGE_ORDINAL(Thunk
->u1
.Ordinal
) - Exports
->Base
);
424 ImportName
= (PIMAGE_IMPORT_BY_NAME
)NameBuffer
;
426 /* Setup the name for this ordinal */
427 sprintf(ImportName
->Name
, "Ordinal%lx\n", OrdinalNumber
);
431 /* Import by Name, get the data */
432 ImportName
= ImageRvaToVa(Image
->FileHeader
,
433 Image
->MappedAddress
,
434 (ULONG
)Thunk
->u1
.AddressOfData
,
435 &Image
->LastRvaSection
);
437 /* Get the hint and see if we can use it */
438 OrdinalNumber
= (USHORT
)(Exports
->NumberOfFunctions
+ 1);
439 HintIndex
= ImportName
->Hint
;
440 if (HintIndex
< Exports
->NumberOfNames
)
442 /* Hint seems valid, get the export name */
443 ExportName
= ImageRvaToVa(Library
->FileHeader
,
444 Library
->MappedAddress
,
445 (ULONG
)AddressOfNames
[HintIndex
],
446 &Library
->LastRvaSection
);
447 /* Check if it's the one we want */
448 if (!strcmp(ImportName
->Name
, ExportName
))
450 OrdinalNumber
= AddressOfOrdinals
[HintIndex
];
454 /* If the ordinal isn't valid, we'll have to do a long loop */
455 if (OrdinalNumber
>= Exports
->NumberOfFunctions
)
457 for (HintIndex
= 0; HintIndex
< Exports
->NumberOfNames
; HintIndex
++)
459 /* Get the Export Name */
460 ExportName
= ImageRvaToVa(Library
->FileHeader
,
461 Library
->MappedAddress
,
462 (ULONG
)AddressOfNames
[HintIndex
],
463 &Library
->LastRvaSection
);
465 /* Check if it's the one we want */
466 if (!strcmp(ImportName
->Name
, ExportName
))
468 OrdinalNumber
= AddressOfOrdinals
[HintIndex
];
473 /* Make sure it's valid now */
474 if (OrdinalNumber
>= Exports
->NumberOfFunctions
) return FALSE
;
478 /* Write the Pointer */
479 ThunkFunction
->u1
.Function
= AddressOfPointers
[OrdinalNumber
] +
480 LibraryOptionalHeader
->ImageBase
;
482 /* Load DLL's Exports */
483 ExportsBase
= (ULONG_PTR
)ImageDirectoryEntryToData(Library
->MappedAddress
,
485 IMAGE_DIRECTORY_ENTRY_EXPORT
,
487 (ULONG_PTR
)Library
->MappedAddress
;
490 ExportsBase
+= LibraryOptionalHeader
->ImageBase
;
492 /* Check if the Export is forwarded (meaning that it's pointer is inside the Export Table) */
493 if ((ThunkFunction
->u1
.Function
> ExportsBase
) &&
494 (ThunkFunction
->u1
.Function
< ExportsBase
+ ExportSize
))
496 /* Make sure we have a descriptor */
497 if (BoundImportDescriptor
)
499 DPRINT("This Thunk is a forward...calling forward thunk bounder\n");
501 /* Get the VA of the pointer containg the name */
502 ForwarderName
= ImageRvaToVa(Library
->FileHeader
,
503 Library
->MappedAddress
,
504 AddressOfPointers
[OrdinalNumber
],
505 &Library
->LastRvaSection
);
507 /* Replace the Forwarder String by the actual name */
508 ThunkFunction
->u1
.ForwarderString
=
509 PtrToUlong(BindpAddForwarderReference(Image
->ModuleName
,
511 BoundImportDescriptor
,
517 /* Check if it wasn't bound */
520 /* Set the chain to the ordinal to reflect this */
521 **Forwarders
= (ULONG
)(ThunkFunction
- BoundThunk
);
522 *Forwarders
= (PULONG
)&ThunkFunction
->u1
.Ordinal
;
532 BindpAddImportDescriptor(PIMPORT_DESCRIPTOR
*BoundImportDescriptor
,
533 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor
,
537 PIMPORT_DESCRIPTOR Descriptor
, *NextDescriptor
;
539 /* Loop descriptors and check if this library has already been bound */
540 NextDescriptor
= BoundImportDescriptor
;
541 while ((Descriptor
= *NextDescriptor
))
543 /* Compare the names and return the descriptor if found */
544 if (!_stricmp(Descriptor
->ModuleName
, DllName
)) return Descriptor
;
546 /* Move to the next one */
547 NextDescriptor
= &Descriptor
->Next
;
550 /* Allocate a new descriptor */
551 Descriptor
= HeapAlloc(IMAGEHLP_hHeap
,
553 sizeof(IMPORT_DESCRIPTOR
));
555 /* Set its Data and check if we have a valid loaded image */
556 Descriptor
->ModuleName
= BindpCaptureImportModuleName(DllName
);
557 *NextDescriptor
= Descriptor
;
560 /* Save the time stamp */
561 Descriptor
->TimeDateStamp
= Image
->FileHeader
->FileHeader
.TimeDateStamp
;
564 /* Return the descriptor */
570 BindpWalkAndProcessImports(PLOADED_IMAGE File
,
572 PBOOLEAN UpdateImage
)
574 PIMAGE_IMPORT_DESCRIPTOR Imports
;
575 PIMAGE_EXPORT_DIRECTORY Exports
;
579 PIMAGE_OPTIONAL_HEADER OptionalHeader
;
580 PIMAGE_FILE_HEADER FileHeader
;
581 LPSTR ImportedLibrary
;
582 PLOADED_IMAGE LoadedLibrary
;
583 ULONG TopForwarderChain
;
584 PULONG ForwarderChain
;
585 PIMPORT_DESCRIPTOR TopBoundDescriptor
= NULL
, BoundImportDescriptor
;
586 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportTable
, OldBoundImportTable
;
587 PIMAGE_THUNK_DATA Thunks
, TempThunk
;
588 PIMAGE_THUNK_DATA BoundThunks
, TempBoundThunk
;
589 ULONG ThunkCount
= 0;
591 ULONG BoundImportTableSize
, OldBoundImportTableSize
;
592 ULONG VirtBytesFree
, HeaderBytesFree
, FirstFreeByte
, PhysBytesFree
;
594 DPRINT("BindpWalkAndBindImports Called\n");
596 /* Assume untouched image */
597 *UpdateImage
= FALSE
;
599 /* Load the Import Descriptor */
600 Imports
= ImageDirectoryEntryToData(File
->MappedAddress
,
602 IMAGE_DIRECTORY_ENTRY_IMPORT
,
604 if (!Imports
) return;
606 /* Read the File Header */
607 FileHeader
= &File
->FileHeader
->FileHeader
;
608 OptionalHeader
= &File
->FileHeader
->OptionalHeader
;
610 /* Get the old Bound Import Table, if any */
611 OldBoundImportTable
= ImageDirectoryEntryToData(File
->MappedAddress
,
613 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
,
614 &OldBoundImportTableSize
);
616 /* For each Import */
619 /* Make sure we have a name */
620 if (!Imports
->Name
) break;
622 /* Which DLL is being Imported */
623 ImportedLibrary
= ImageRvaToVa(File
->FileHeader
,
626 &File
->LastRvaSection
);
629 DPRINT("Loading Imported DLL: %s \n", ImportedLibrary
);
632 LoadedLibrary
= ImageLoad(ImportedLibrary
, DllPath
);
635 /* Create the descriptor, even if we failed */
636 BindpAddImportDescriptor(&TopBoundDescriptor
,
641 /* Move on the next file */
646 /* Now load the Exports */
647 DPRINT("DLL Loaded at: %p \n", LoadedLibrary
->MappedAddress
);
648 Exports
= ImageDirectoryEntryToData(LoadedLibrary
->MappedAddress
,
650 IMAGE_DIRECTORY_ENTRY_EXPORT
,
653 /* Move on, if we don't have exports */
654 if (!Exports
) continue;
656 /* And load the Thunks */
657 Thunks
= ImageRvaToVa(File
->FileHeader
,
659 (ULONG
)Imports
->OriginalFirstThunk
,
660 &File
->LastRvaSection
);
662 /* No actual Exports (UPX Packer can do this */
663 if (!(Thunks
) || !(Thunks
->u1
.Function
)) continue;
665 /* Create Bound Import Descriptor */
666 DPRINT("Creating Bound Descriptor for this DLL\n");
667 BoundImportDescriptor
= BindpAddImportDescriptor(&TopBoundDescriptor
,
672 /* Count how many Thunks we have */
675 while (TempThunk
->u1
.AddressOfData
)
681 /* Allocate Memory for the Thunks we will Bind */
682 SizeOfThunks
= ThunkCount
* sizeof(*TempBoundThunk
);
683 BoundThunks
= HeapAlloc(IMAGEHLP_hHeap
,
687 /* Setup the initial data pointers */
688 DPRINT("Binding Thunks\n");
690 TempBoundThunk
= BoundThunks
;
691 TopForwarderChain
= -1;
692 ForwarderChain
= &TopForwarderChain
;
694 /* Loop for every thunk */
695 for (Thunk
= 0; Thunk
< ThunkCount
; Thunk
++)
698 ThunkStatus
= BindpLookupThunk(TempThunk
,
704 BoundImportDescriptor
,
707 /* Check if binding failed */
710 /* If we have a descriptor */
711 if (BoundImportDescriptor
)
713 /* Zero the timestamp */
714 BoundImportDescriptor
->TimeDateStamp
= 0;
726 /* Load the Second Thunk Array */
727 TempThunk
= ImageRvaToVa(File
->FileHeader
,
729 (ULONG
)Imports
->FirstThunk
,
730 &File
->LastRvaSection
);
733 /* Check if the forwarder chain changed */
734 if (TopForwarderChain
!= -1)
736 /* It did. Update the chain and let caller know */
737 *ForwarderChain
= -1;
741 /* Check if we're not pointing at the new top chain */
742 if (Imports
->ForwarderChain
!= TopForwarderChain
)
744 /* Update it, and let the caller know */
745 Imports
->ForwarderChain
= TopForwarderChain
;
749 /* Check if thunks have changed */
750 if (memcmp(TempThunk
, BoundThunks
, SizeOfThunks
))
752 /* Copy the Pointers and let caller know */
753 DPRINT("Copying Bound Thunks\n");
754 RtlCopyMemory(TempThunk
, BoundThunks
, SizeOfThunks
);
758 /* Check if we have no bound entries */
759 if (!TopBoundDescriptor
)
761 /* Check if the timestamp is different */
762 if (Imports
->TimeDateStamp
!= FileHeader
->TimeDateStamp
)
764 /* Update it, and let the caller knmow */
765 Imports
->TimeDateStamp
= FileHeader
->TimeDateStamp
;
769 else if ((Imports
->TimeDateStamp
!= 0xFFFFFFFF))
771 /* Invalidate the timedate stamp */
772 Imports
->TimeDateStamp
= 0xFFFFFFFF;
776 /* Free the Allocated Memory */
777 HeapFree(IMAGEHLP_hHeap
, 0, BoundThunks
);
779 DPRINT("Moving to next File\n");
784 /* Create the Bound Import Table */
785 DPRINT("Creating Bound Import Section\n");
786 BoundImportTable
= BindpCreateNewImportSection(&TopBoundDescriptor
,
787 &BoundImportTableSize
);
789 /* Check if the import table changed */
790 if (OldBoundImportTableSize
!= BoundImportTableSize
)
792 /* Let the caller know */
797 * At this point, check if anything that we've done until now has resulted
798 * in the image being touched. If not, then we'll simply return to caller.
800 if (!(*UpdateImage
)) return;
802 /* Check if we have a new table */
803 if (BoundImportTable
)
806 OptionalHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
].VirtualAddress
= 0;
807 OptionalHeader
->DataDirectory
[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
].Size
= 0;
809 /* Check if we have enough space */
810 DPRINT("Calculating Space\n");
811 FirstFreeByte
= GetImageUnusedHeaderBytes(File
, &VirtBytesFree
);
812 HeaderBytesFree
= File
->Sections
->VirtualAddress
-
813 OptionalHeader
->SizeOfHeaders
+ VirtBytesFree
;
814 PhysBytesFree
= File
->Sections
->PointerToRawData
-
815 OptionalHeader
->SizeOfHeaders
+ VirtBytesFree
;
817 /* Check if we overflowed */
818 if (BoundImportTableSize
> VirtBytesFree
)
820 /* Check if we have no space a tall */
821 if (BoundImportTableSize
> HeaderBytesFree
)
823 DPRINT1("Not enough Space\n");
824 return; /* Fail...not enough space */
827 /* Check if we have space on disk to enlarge it */
828 if (BoundImportTableSize
<= PhysBytesFree
)
830 /* We have enough NULLs to add it, simply enlarge header data */
831 DPRINT("Header Recalculation\n");
832 OptionalHeader
->SizeOfHeaders
= OptionalHeader
->SizeOfHeaders
-
834 BoundImportTableSize
+
835 ((OptionalHeader
->FileAlignment
- 1) &
836 ~(OptionalHeader
->FileAlignment
- 1));
840 /* Resize the Headers */
841 DPRINT1("UNIMPLEMENTED: Header Resizing\n");
843 /* Recalculate Headers */
844 FileHeader
= &File
->FileHeader
->FileHeader
;
845 OptionalHeader
= &File
->FileHeader
->OptionalHeader
;
849 /* Set Bound Import Table Data */
850 OptionalHeader
->DataDirectory
851 [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
].VirtualAddress
= FirstFreeByte
;
852 OptionalHeader
->DataDirectory
853 [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
].Size
= BoundImportTableSize
;
855 /* Copy the Bound Import Table */
856 DPRINT("Copying Bound Import Table\n");
857 RtlCopyMemory(File
->MappedAddress
+ FirstFreeByte
,
859 BoundImportTableSize
);
862 HeapFree(IMAGEHLP_hHeap
, 0, BoundImportTable
);
872 BindImageEx(IN DWORD Flags
,
876 IN PIMAGEHLP_STATUS_ROUTINE StatusRoutine
)
878 LOADED_IMAGE FileData
;
880 PIMAGE_FILE_HEADER FileHeader
;
881 PIMAGE_OPTIONAL_HEADER32 OptionalHeader
;
882 ULONG CheckSum
, HeaderCheckSum
, OldChecksum
;
883 SYSTEMTIME SystemTime
;
884 FILETIME LastWriteTime
;
887 DPRINT("BindImageEx Called for: %s \n", ImageName
);
889 /* Set and Clear Buffer */
891 RtlZeroMemory(File
, sizeof(*File
));
893 /* Request Image Data */
894 if (MapAndLoad(ImageName
, DllPath
, File
, TRUE
, FALSE
))
896 /* Write the image's name */
897 DPRINT("Image Mapped and Loaded\n");
898 File
->ModuleName
= ImageName
;
900 /* Check if the image is valid and if it should be bound */
901 if ((File
->FileHeader
) &&
902 ((Flags
& BIND_ALL_IMAGES
) || (!File
->fSystemImage
)))
904 /* Get the optional header */
905 FileHeader
= &File
->FileHeader
->FileHeader
;
906 OptionalHeader
= &File
->FileHeader
->OptionalHeader
;
908 /* Check if this image should be bound */
909 if (OptionalHeader
->DllCharacteristics
&
910 IMAGE_DLLCHARACTERISTICS_NO_BIND
)
916 /* Check if the image has security data */
917 if ((ImageDirectoryEntryToData(File
->MappedAddress
,
919 IMAGE_DIRECTORY_ENTRY_SECURITY
,
920 &DataSize
)) || DataSize
)
922 /* It does, skip it */
926 /* Read Import Table */
927 BindpWalkAndProcessImports(File
, DllPath
, &UpdateImage
);
929 /* Check if we need to update the image */
930 if ((UpdateImage
) && (File
->hFile
!= INVALID_HANDLE_VALUE
))
932 /* FIXME: Update symbols */
934 /* Update Checksum */
935 DPRINT("Binding Completed, getting Checksum\n");
936 OldChecksum
= File
->FileHeader
->OptionalHeader
.CheckSum
;
937 CheckSumMappedFile(File
->MappedAddress
,
938 GetFileSize(File
->hFile
, NULL
),
941 File
->FileHeader
->OptionalHeader
.CheckSum
= CheckSum
;
944 DPRINT("Saving Changes to file\n");
945 FlushViewOfFile(File
->MappedAddress
, File
->SizeOfImage
);
947 /* Save new Modified Time */
948 DPRINT("Setting time\n");
949 GetSystemTime(&SystemTime
);
950 SystemTimeToFileTime(&SystemTime
, &LastWriteTime
);
951 SetFileTime(File
->hFile
, NULL
, NULL
, &LastWriteTime
);
958 /* Unmap the image */
959 UnmapViewOfFile(File
->MappedAddress
);
961 /* Close the handle if it's valid */
962 if (File
->hFile
!= INVALID_HANDLE_VALUE
) CloseHandle(File
->hFile
);
964 /* Unload all the images if we're not supposed to cache them */
965 if (!(Flags
& BIND_CACHE_IMPORT_DLLS
)) UnloadAllImages();
977 BindImage(LPSTR ImageName
,
981 /* Call the newer API */
982 return BindImageEx(0,
994 ReBaseImage(LPSTR CurrentImageName
,
997 BOOL fRebaseSysfileOk
,
999 ULONG CheckImageSize
,
1000 ULONG
*OldImageSize
,
1001 ULONG
*OldImageBase
,
1002 ULONG
*NewImageSize
,
1003 ULONG
*NewImageBase
,
1007 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1016 RemoveRelocations(PCHAR ImageName
)
1019 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1027 SplitSymbols(LPSTR ImageName
,
1029 LPSTR SymbolFilePath
,
1033 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1042 TouchFileTimes(HANDLE FileHandle
,
1043 LPSYSTEMTIME lpSystemTime
)
1046 SYSTEMTIME SystemTime
;
1048 if(lpSystemTime
== NULL
)
1050 GetSystemTime(&SystemTime
);
1051 lpSystemTime
= &SystemTime
;
1054 return (SystemTimeToFileTime(lpSystemTime
,
1056 SetFileTime(FileHandle
,