reshuffling of dlls
[reactos.git] / reactos / 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 /* INCLUDES ******************************************************************/
23
24 #include "precomp.h"
25
26 //#define NDEBUG
27 #include <debug.h>
28
29 /* DATA **********************************************************************/
30
31 CHAR BoundLibraries[4096];
32 LPSTR BoundLibrariesPointer;
33
34 /* FUNCTIONS *****************************************************************/
35
36 LPSTR
37 IMAGEAPI
38 BindpCaptureImportModuleName(LPSTR ModuleName)
39 {
40 LPSTR Name = BoundLibraries;
41
42 /* Check if it hasn't been initialized yet */
43 if (!BoundLibrariesPointer)
44 {
45 /* Start with a null char and set the pointer */
46 *Name = ANSI_NULL;
47 BoundLibrariesPointer = Name;
48 }
49
50 /* Loop the current buffer */
51 while (*Name)
52 {
53 /* Try to match this DLL's name and return it */
54 if (!_stricmp(Name, ModuleName)) return Name;
55
56 /* Move on to the next DLL Name */
57 Name += strlen(Name) + sizeof(CHAR);
58 }
59
60 /* If we got here, we didn't find one, so add this one to our buffer */
61 strcpy(Name, ModuleName);
62
63 /* Set the new position of the buffer, and null-terminate it */
64 BoundLibrariesPointer = Name + strlen(Name) + sizeof(CHAR);
65 *BoundLibrariesPointer = ANSI_NULL;
66
67 /* Return the pointer to the name */
68 return Name;
69 }
70
71 PIMAGE_BOUND_IMPORT_DESCRIPTOR
72 IMAGEAPI
73 BindpCreateNewImportSection(PIMPORT_DESCRIPTOR *BoundImportDescriptor,
74 PULONG BoundImportsSize)
75 {
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;
82
83 /* Zero the outoging size */
84 *BoundImportsSize = 0;
85
86 /* Loop the descriptors and forwarders to get the size */
87 NextDescriptor = BoundImportDescriptor;
88 while ((Descriptor = *NextDescriptor))
89 {
90 /* Add to the size of the Bound Import Table */
91 BoundImportTableSize += sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR);
92
93 /* Check Forwarders */
94 NextForwarder = &Descriptor->Forwarders;
95 while ((Forwarder = *NextForwarder))
96 {
97 /* Add to size of Bound Import Table */
98 BoundImportTableSize += sizeof(IMAGE_BOUND_FORWARDER_REF);
99
100 /* Next Forwarder */
101 NextForwarder = &Forwarder->Next;
102 }
103
104 /* Read Next Internal Descriptor */
105 NextDescriptor = &Descriptor->Next;
106 }
107
108 /* Add Terminator for PE Loader*/
109 BoundImportTableSize += sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR);
110 DPRINT("Table size: %lx\n", BoundImportTableSize);
111
112 /* Name of Libraries Bound in Bound Import Table */
113 BoundLibraryNamesSize = (ULONG)((ULONG_PTR)BoundLibrariesPointer -
114 (ULONG_PTR)BoundLibraries);
115 BoundLibrariesPointer = NULL;
116
117 /* Size of the whole table, dword aligned */
118 *BoundImportsSize = BoundImportTableSize +
119 ((BoundLibraryNamesSize + sizeof(ULONG) - 1) &
120 ~(sizeof(ULONG) - 1));
121
122 /* Allocate it */
123 BoundTable = HeapAlloc(IMAGEHLP_hHeap, HEAP_ZERO_MEMORY, *BoundImportsSize);
124
125 /* Pointer Library Names inside the Bound Import Table */
126 BoundLibraryNames = (LPSTR)BoundTable + BoundImportTableSize;
127
128 /* Copy the Library Names */
129 RtlCopyMemory(BoundLibraryNames, BoundLibraries, BoundLibraryNamesSize);
130
131 /* Now loop both tables */
132 BoundTableEntry = BoundTable;
133 NextDescriptor = BoundImportDescriptor;
134 while ((Descriptor = *NextDescriptor))
135 {
136 /* Copy the data */
137 BoundTableEntry->TimeDateStamp = Descriptor->TimeDateStamp;
138 BoundTableEntry->OffsetModuleName = (USHORT)(BoundImportTableSize +
139 (Descriptor->ModuleName -
140 (ULONG_PTR)BoundLibraries));
141 BoundTableEntry->NumberOfModuleForwarderRefs = Descriptor->ForwaderReferences;
142
143 /* Now loop the forwarders */
144 BoundForwarder = (PIMAGE_BOUND_FORWARDER_REF)BoundTableEntry + 1;
145 NextForwarder = &Descriptor->Forwarders;
146 while ((Forwarder = *NextForwarder))
147 {
148 /* Copy the data */
149 BoundForwarder->TimeDateStamp = Forwarder->TimeDateStamp;
150 BoundForwarder->OffsetModuleName = (USHORT)(BoundImportTableSize +
151 (Forwarder->ModuleName -
152 (ULONG_PTR)BoundLibraries));
153
154 /* Move to the next new forwarder, and move to the next entry */
155 BoundForwarder++;
156 NextForwarder = &Forwarder->Next;
157 }
158
159 /* Move to next Bound Import Table Entry */
160 BoundTableEntry = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)BoundForwarder;
161
162 /* Move to the next descriptor */
163 NextDescriptor = &Descriptor->Next;
164 }
165
166 /* Loop the descriptors and forwarders to free them */
167 NextDescriptor = BoundImportDescriptor;
168 while ((Descriptor = *NextDescriptor))
169 {
170 /* Read next internal descriptor */
171 *NextDescriptor = Descriptor->Next;
172
173 /* Loop its forwarders */
174 NextForwarder = &Descriptor->Forwarders;
175 while ((Forwarder = *NextForwarder))
176 {
177 /* Next Forwarder */
178 *NextForwarder = Forwarder->Next;
179
180 /* Free it */
181 HeapFree(IMAGEHLP_hHeap, 0, Forwarder);
182 }
183
184 /* Free it */
185 HeapFree(IMAGEHLP_hHeap, 0, Descriptor);
186 }
187
188 /* Return the Bound Import Table */
189 return BoundTable;
190 }
191
192 PCHAR
193 IMAGEAPI
194 BindpAddForwarderReference(LPSTR ModuleName,
195 LPSTR ImportName,
196 PIMPORT_DESCRIPTOR BoundImportDescriptor,
197 LPSTR DllPath,
198 PCHAR ForwarderString,
199 PBOOL ForwarderBound)
200 {
201 CHAR DllName[256];
202 PCHAR TempDllName, FunctionName;
203 PLOADED_IMAGE Library;
204 SIZE_T DllNameSize;
205 USHORT OrdinalNumber;
206 USHORT HintIndex;
207 ULONG ExportSize;
208 PIMAGE_EXPORT_DIRECTORY Exports;
209 ULONG_PTR ExportsBase;
210 PULONG AddressOfNames;
211 PUSHORT AddressOfOrdinals;
212 PULONG AddressOfPointers;
213 LPSTR ExportName;
214 ULONG_PTR ForwardedAddress;
215 PBOUND_FORWARDER_REFS Forwarder, *NextForwarder;
216 PIMAGE_OPTIONAL_HEADER OptionalHeader = NULL;
217
218 NextForwarder:
219
220 /* Get the DLL Name */
221 TempDllName = ForwarderString;
222 while (*TempDllName && *TempDllName != '.') TempDllName++;
223 if (*TempDllName != '.') return ForwarderString;
224
225 /* Get the size */
226 DllNameSize = (SIZE_T)(TempDllName - ForwarderString);
227 if (DllNameSize >= MAX_PATH) return ForwarderString;
228
229 /* Now copy the name and append the extension */
230 strncpy(DllName, ForwarderString, DllNameSize);
231 DllName[DllNameSize] = ANSI_NULL;
232 strcat(DllName, ".DLL");
233
234 /* Load it */
235 DPRINT("Loading the Thunk Library: %s \n", DllName);
236 Library = ImageLoad(DllName, DllPath);
237 if (!Library) return ForwarderString;
238
239 /* Move past the name */
240 DPRINT("It Loaded at: %p \n", Library->MappedAddress);
241 FunctionName = TempDllName += 1;
242
243 /* Load Exports */
244 Exports = ImageDirectoryEntryToData(Library->MappedAddress,
245 FALSE,
246 IMAGE_DIRECTORY_ENTRY_EXPORT,
247 &ExportSize);
248 if (!Exports) return ForwarderString;
249
250 /* Get the Optional Header */
251 OptionalHeader = &Library->FileHeader->OptionalHeader;
252
253 /* Check if we're binding by ordinal */
254 if (*FunctionName == '#')
255 {
256 /* We are, get the number and validate it */
257 OrdinalNumber = atoi(FunctionName + 1) - (USHORT)Exports->Base;
258 if (OrdinalNumber >= Exports->NumberOfFunctions) return ForwarderString;
259 }
260 else
261 {
262 /* Binding by name... */
263 OrdinalNumber = -1;
264 }
265
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);
279
280 /* Check if we're binding by name... */
281 if (OrdinalNumber == 0xffff)
282 {
283 /* Do a full search for the ordinal */
284 for (HintIndex = 0; HintIndex < Exports->NumberOfNames; HintIndex++)
285 {
286 /* Get the Export Name */
287 ExportName = ImageRvaToVa(Library->FileHeader,
288 Library->MappedAddress,
289 (ULONG)AddressOfNames[HintIndex],
290 &Library->LastRvaSection);
291
292 /* Check if it's the one we want */
293 if (!strcmp(FunctionName, ExportName))
294 {
295 OrdinalNumber = AddressOfOrdinals[HintIndex];
296 break;
297 }
298 }
299
300 /* Make sure it's valid */
301 if (HintIndex >= Exports->NumberOfNames) return ForwarderString;
302 }
303
304 /* Get the Forwarded Address */
305 ForwardedAddress = AddressOfPointers[OrdinalNumber] +
306 OptionalHeader->ImageBase;
307
308 /* Loop the forwarders to see if this DLL was already processed */
309 NextForwarder = &BoundImportDescriptor->Forwarders;
310 while ((Forwarder = *NextForwarder))
311 {
312 /* Check for a name match */
313 if (!_stricmp(DllName, Forwarder->ModuleName)) break;
314
315 /* Move to the next one */
316 NextForwarder = &Forwarder->Next;
317 }
318
319 /* Check if we've went through them all without luck */
320 if (!Forwarder)
321 {
322 /* Allocate a forwarder structure */
323 Forwarder = HeapAlloc(IMAGEHLP_hHeap,
324 HEAP_ZERO_MEMORY,
325 sizeof(BOUND_FORWARDER_REFS));
326
327 /* Set the name */
328 Forwarder->ModuleName = BindpCaptureImportModuleName(DllName);
329
330 /* Increase the number of forwarders */
331 BoundImportDescriptor->ForwaderReferences++;
332
333 /* Link it */
334 *NextForwarder = Forwarder;
335 }
336
337 /* Set the timestamp */
338 Forwarder->TimeDateStamp = Library->FileHeader->FileHeader.TimeDateStamp;
339
340 /* Load DLL's Exports */
341 ExportsBase = (ULONG_PTR)ImageDirectoryEntryToData(Library->MappedAddress,
342 TRUE,
343 IMAGE_DIRECTORY_ENTRY_EXPORT,
344 &ExportSize) -
345 (ULONG_PTR)Library->MappedAddress;
346
347 /* Convert to VA */
348 ExportsBase += OptionalHeader->ImageBase;
349
350 /* Is this yet another Forward? */
351 DPRINT("I've thunked it\n");
352 if ((ForwardedAddress > ExportsBase) &&
353 (ForwardedAddress < (ExportsBase + ExportSize)))
354 {
355 /* Update the string pointer */
356 ForwarderString = ImageRvaToVa(Library->FileHeader,
357 Library->MappedAddress,
358 AddressOfPointers[OrdinalNumber],
359 &Library->LastRvaSection);
360 goto NextForwarder;
361 }
362 else
363 {
364 /* Update the pointer and return success */
365 ForwarderString = (PUCHAR)ForwardedAddress;
366 *ForwarderBound = TRUE;
367 }
368
369 /* Return the pointer */
370 return ForwarderString;
371 }
372
373 BOOL
374 IMAGEAPI
375 BindpLookupThunk(PIMAGE_THUNK_DATA Thunk,
376 PLOADED_IMAGE Image,
377 PIMAGE_THUNK_DATA BoundThunk,
378 PIMAGE_THUNK_DATA ThunkFunction,
379 PLOADED_IMAGE Library,
380 PIMAGE_EXPORT_DIRECTORY Exports,
381 PIMPORT_DESCRIPTOR BoundImportDescriptor,
382 LPSTR DllPath,
383 PULONG *Forwarders)
384 {
385 PULONG AddressOfNames;
386 PUSHORT AddressOfOrdinals;
387 PULONG AddressOfPointers;
388 PIMAGE_IMPORT_BY_NAME ImportName;
389 ULONG OrdinalNumber = 0;
390 USHORT HintIndex;
391 LPSTR ExportName;
392 ULONG_PTR ExportsBase;
393 ULONG ExportSize;
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");
400
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);
414
415 /* Get the Optional Headers */
416 OptionalHeader = &Image->FileHeader->OptionalHeader;
417 LibraryOptionalHeader = &Library->FileHeader->OptionalHeader;
418
419 /* Import by Ordinal */
420 if (IMAGE_SNAP_BY_ORDINAL(Thunk->u1.Ordinal) == TRUE)
421 {
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;
425
426 /* Setup the name for this ordinal */
427 sprintf(ImportName->Name, "Ordinal%lx\n", OrdinalNumber);
428 }
429 else
430 {
431 /* Import by Name, get the data */
432 ImportName = ImageRvaToVa(Image->FileHeader,
433 Image->MappedAddress,
434 (ULONG)Thunk->u1.AddressOfData,
435 &Image->LastRvaSection);
436
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)
441 {
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))
449 {
450 OrdinalNumber = AddressOfOrdinals[HintIndex];
451 }
452 }
453
454 /* If the ordinal isn't valid, we'll have to do a long loop */
455 if (OrdinalNumber >= Exports->NumberOfFunctions)
456 {
457 for (HintIndex = 0; HintIndex < Exports->NumberOfNames; HintIndex++)
458 {
459 /* Get the Export Name */
460 ExportName = ImageRvaToVa(Library->FileHeader,
461 Library->MappedAddress,
462 (ULONG)AddressOfNames[HintIndex],
463 &Library->LastRvaSection);
464
465 /* Check if it's the one we want */
466 if (!strcmp(ImportName->Name, ExportName))
467 {
468 OrdinalNumber = AddressOfOrdinals[HintIndex];
469 break;
470 }
471 }
472
473 /* Make sure it's valid now */
474 if (OrdinalNumber >= Exports->NumberOfFunctions) return FALSE;
475 }
476 }
477
478 /* Write the Pointer */
479 ThunkFunction->u1.Function = AddressOfPointers[OrdinalNumber] +
480 LibraryOptionalHeader->ImageBase;
481
482 /* Load DLL's Exports */
483 ExportsBase = (ULONG_PTR)ImageDirectoryEntryToData(Library->MappedAddress,
484 TRUE,
485 IMAGE_DIRECTORY_ENTRY_EXPORT,
486 &ExportSize) -
487 (ULONG_PTR)Library->MappedAddress;
488
489 /* RVA to VA */
490 ExportsBase += LibraryOptionalHeader->ImageBase;
491
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))
495 {
496 /* Make sure we have a descriptor */
497 if (BoundImportDescriptor)
498 {
499 DPRINT("This Thunk is a forward...calling forward thunk bounder\n");
500
501 /* Get the VA of the pointer containg the name */
502 ForwarderName = ImageRvaToVa(Library->FileHeader,
503 Library->MappedAddress,
504 AddressOfPointers[OrdinalNumber],
505 &Library->LastRvaSection);
506
507 /* Replace the Forwarder String by the actual name */
508 ThunkFunction->u1.ForwarderString =
509 PtrToUlong(BindpAddForwarderReference(Image->ModuleName,
510 ImportName->Name,
511 BoundImportDescriptor,
512 DllPath,
513 ForwarderName,
514 &ForwarderBound));
515 }
516
517 /* Check if it wasn't bound */
518 if (!ForwarderBound)
519 {
520 /* Set the chain to the ordinal to reflect this */
521 **Forwarders = (ULONG)(ThunkFunction - BoundThunk);
522 *Forwarders = (PULONG)&ThunkFunction->u1.Ordinal;
523 }
524 }
525
526 /* Return Success */
527 return TRUE;
528 }
529
530 PIMPORT_DESCRIPTOR
531 IMAGEAPI
532 BindpAddImportDescriptor(PIMPORT_DESCRIPTOR *BoundImportDescriptor,
533 PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor,
534 LPSTR DllName,
535 PLOADED_IMAGE Image)
536 {
537 PIMPORT_DESCRIPTOR Descriptor, *NextDescriptor;
538
539 /* Loop descriptors and check if this library has already been bound */
540 NextDescriptor = BoundImportDescriptor;
541 while ((Descriptor = *NextDescriptor))
542 {
543 /* Compare the names and return the descriptor if found */
544 if (!_stricmp(Descriptor->ModuleName, DllName)) return Descriptor;
545
546 /* Move to the next one */
547 NextDescriptor = &Descriptor->Next;
548 }
549
550 /* Allocate a new descriptor */
551 Descriptor = HeapAlloc(IMAGEHLP_hHeap,
552 HEAP_ZERO_MEMORY,
553 sizeof(IMPORT_DESCRIPTOR));
554
555 /* Set its Data and check if we have a valid loaded image */
556 Descriptor->ModuleName = BindpCaptureImportModuleName(DllName);
557 *NextDescriptor = Descriptor;
558 if (Image)
559 {
560 /* Save the time stamp */
561 Descriptor->TimeDateStamp = Image->FileHeader->FileHeader.TimeDateStamp;
562 }
563
564 /* Return the descriptor */
565 return Descriptor;
566 }
567
568 VOID
569 IMAGEAPI
570 BindpWalkAndProcessImports(PLOADED_IMAGE File,
571 LPSTR DllPath,
572 PBOOLEAN UpdateImage)
573 {
574 PIMAGE_IMPORT_DESCRIPTOR Imports;
575 PIMAGE_EXPORT_DIRECTORY Exports;
576 ULONG SizeOfImports;
577 ULONG SizeOfExports;
578 ULONG SizeOfThunks;
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;
590 ULONG Thunk;
591 ULONG BoundImportTableSize, OldBoundImportTableSize;
592 ULONG VirtBytesFree, HeaderBytesFree, FirstFreeByte, PhysBytesFree;
593 BOOL ThunkStatus;
594 DPRINT("BindpWalkAndBindImports Called\n");
595
596 /* Assume untouched image */
597 *UpdateImage = FALSE;
598
599 /* Load the Import Descriptor */
600 Imports = ImageDirectoryEntryToData(File->MappedAddress,
601 FALSE,
602 IMAGE_DIRECTORY_ENTRY_IMPORT,
603 &SizeOfImports);
604 if (!Imports) return;
605
606 /* Read the File Header */
607 FileHeader = &File->FileHeader->FileHeader;
608 OptionalHeader = &File->FileHeader->OptionalHeader;
609
610 /* Get the old Bound Import Table, if any */
611 OldBoundImportTable = ImageDirectoryEntryToData(File->MappedAddress,
612 FALSE,
613 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
614 &OldBoundImportTableSize);
615
616 /* For each Import */
617 while(Imports)
618 {
619 /* Make sure we have a name */
620 if (!Imports->Name) break;
621
622 /* Which DLL is being Imported */
623 ImportedLibrary = ImageRvaToVa(File->FileHeader,
624 File->MappedAddress,
625 Imports->Name,
626 &File->LastRvaSection);
627 if (ImportedLibrary)
628 {
629 DPRINT("Loading Imported DLL: %s \n", ImportedLibrary);
630
631 /* Load the DLL */
632 LoadedLibrary = ImageLoad(ImportedLibrary, DllPath);
633 if (!LoadedLibrary)
634 {
635 /* Create the descriptor, even if we failed */
636 BindpAddImportDescriptor(&TopBoundDescriptor,
637 Imports,
638 ImportedLibrary,
639 LoadedLibrary);
640
641 /* Move on the next file */
642 Imports++;
643 continue;
644 }
645
646 /* Now load the Exports */
647 DPRINT("DLL Loaded at: %p \n", LoadedLibrary->MappedAddress);
648 Exports = ImageDirectoryEntryToData(LoadedLibrary->MappedAddress,
649 FALSE,
650 IMAGE_DIRECTORY_ENTRY_EXPORT,
651 &SizeOfExports);
652
653 /* Move on, if we don't have exports */
654 if (!Exports) continue;
655
656 /* And load the Thunks */
657 Thunks = ImageRvaToVa(File->FileHeader,
658 File->MappedAddress,
659 (ULONG)Imports->OriginalFirstThunk,
660 &File->LastRvaSection);
661
662 /* No actual Exports (UPX Packer can do this */
663 if (!(Thunks) || !(Thunks->u1.Function)) continue;
664
665 /* Create Bound Import Descriptor */
666 DPRINT("Creating Bound Descriptor for this DLL\n");
667 BoundImportDescriptor = BindpAddImportDescriptor(&TopBoundDescriptor,
668 Imports,
669 ImportedLibrary,
670 LoadedLibrary);
671
672 /* Count how many Thunks we have */
673 ThunkCount = 0;
674 TempThunk = Thunks;
675 while (TempThunk->u1.AddressOfData)
676 {
677 ThunkCount++;
678 TempThunk++;
679 }
680
681 /* Allocate Memory for the Thunks we will Bind */
682 SizeOfThunks = ThunkCount * sizeof(*TempBoundThunk);
683 BoundThunks = HeapAlloc(IMAGEHLP_hHeap,
684 HEAP_ZERO_MEMORY,
685 SizeOfThunks);
686
687 /* Setup the initial data pointers */
688 DPRINT("Binding Thunks\n");
689 TempThunk = Thunks;
690 TempBoundThunk = BoundThunks;
691 TopForwarderChain = -1;
692 ForwarderChain = &TopForwarderChain;
693
694 /* Loop for every thunk */
695 for (Thunk = 0; Thunk < ThunkCount; Thunk++)
696 {
697 /* Bind it */
698 ThunkStatus = BindpLookupThunk(TempThunk,
699 File,
700 BoundThunks,
701 TempBoundThunk,
702 LoadedLibrary,
703 Exports,
704 BoundImportDescriptor,
705 DllPath,
706 &ForwarderChain);
707 /* Check if binding failed */
708 if (!ThunkStatus)
709 {
710 /* If we have a descriptor */
711 if (BoundImportDescriptor)
712 {
713 /* Zero the timestamp */
714 BoundImportDescriptor->TimeDateStamp = 0;
715 }
716
717 /* Quit the loop */
718 break;
719 }
720
721 /* Move on */
722 TempThunk++;
723 TempBoundThunk++;
724 }
725
726 /* Load the Second Thunk Array */
727 TempThunk = ImageRvaToVa(File->FileHeader,
728 File->MappedAddress,
729 (ULONG)Imports->FirstThunk,
730 &File->LastRvaSection);
731 if (TempThunk)
732 {
733 /* Check if the forwarder chain changed */
734 if (TopForwarderChain != -1)
735 {
736 /* It did. Update the chain and let caller know */
737 *ForwarderChain = -1;
738 *UpdateImage = TRUE;
739 }
740
741 /* Check if we're not pointing at the new top chain */
742 if (Imports->ForwarderChain != TopForwarderChain)
743 {
744 /* Update it, and let the caller know */
745 Imports->ForwarderChain = TopForwarderChain;
746 *UpdateImage = TRUE;
747 }
748
749 /* Check if thunks have changed */
750 if (memcmp(TempThunk, BoundThunks, SizeOfThunks))
751 {
752 /* Copy the Pointers and let caller know */
753 DPRINT("Copying Bound Thunks\n");
754 RtlCopyMemory(TempThunk, BoundThunks, SizeOfThunks);
755 *UpdateImage = TRUE;
756 }
757
758 /* Check if we have no bound entries */
759 if (!TopBoundDescriptor)
760 {
761 /* Check if the timestamp is different */
762 if (Imports->TimeDateStamp != FileHeader->TimeDateStamp)
763 {
764 /* Update it, and let the caller knmow */
765 Imports->TimeDateStamp = FileHeader->TimeDateStamp;
766 *UpdateImage = TRUE;
767 }
768 }
769 else if ((Imports->TimeDateStamp != 0xFFFFFFFF))
770 {
771 /* Invalidate the timedate stamp */
772 Imports->TimeDateStamp = 0xFFFFFFFF;
773 }
774 }
775
776 /* Free the Allocated Memory */
777 HeapFree(IMAGEHLP_hHeap, 0, BoundThunks);
778
779 DPRINT("Moving to next File\n");
780 Imports++;
781 }
782 }
783
784 /* Create the Bound Import Table */
785 DPRINT("Creating Bound Import Section\n");
786 BoundImportTable = BindpCreateNewImportSection(&TopBoundDescriptor,
787 &BoundImportTableSize);
788
789 /* Check if the import table changed */
790 if (OldBoundImportTableSize != BoundImportTableSize)
791 {
792 /* Let the caller know */
793 *UpdateImage = TRUE;
794 }
795
796 /*
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.
799 */
800 if (!(*UpdateImage)) return;
801
802 /* Check if we have a new table */
803 if (BoundImportTable)
804 {
805 /* Zero it out */
806 OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
807 OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
808
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;
816
817 /* Check if we overflowed */
818 if (BoundImportTableSize > VirtBytesFree)
819 {
820 /* Check if we have no space a tall */
821 if (BoundImportTableSize > HeaderBytesFree)
822 {
823 DPRINT1("Not enough Space\n");
824 return; /* Fail...not enough space */
825 }
826
827 /* Check if we have space on disk to enlarge it */
828 if (BoundImportTableSize <= PhysBytesFree)
829 {
830 /* We have enough NULLs to add it, simply enlarge header data */
831 DPRINT("Header Recalculation\n");
832 OptionalHeader->SizeOfHeaders = OptionalHeader->SizeOfHeaders -
833 VirtBytesFree +
834 BoundImportTableSize +
835 ((OptionalHeader->FileAlignment - 1) &
836 ~(OptionalHeader->FileAlignment - 1));
837 }
838 else
839 {
840 /* Resize the Headers */
841 DPRINT1("UNIMPLEMENTED: Header Resizing\n");
842
843 /* Recalculate Headers */
844 FileHeader = &File->FileHeader->FileHeader;
845 OptionalHeader = &File->FileHeader->OptionalHeader;
846 }
847 }
848
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;
854
855 /* Copy the Bound Import Table */
856 DPRINT("Copying Bound Import Table\n");
857 RtlCopyMemory(File->MappedAddress + FirstFreeByte,
858 BoundImportTable,
859 BoundImportTableSize);
860
861 /* Free the data */
862 HeapFree(IMAGEHLP_hHeap, 0, BoundImportTable);
863 }
864
865 }
866
867 /*
868 * @implemented
869 */
870 BOOL
871 IMAGEAPI
872 BindImageEx(IN DWORD Flags,
873 IN LPSTR ImageName,
874 IN LPSTR DllPath,
875 IN LPSTR SymbolPath,
876 IN PIMAGEHLP_STATUS_ROUTINE StatusRoutine)
877 {
878 LOADED_IMAGE FileData;
879 PLOADED_IMAGE File;
880 PIMAGE_FILE_HEADER FileHeader;
881 PIMAGE_OPTIONAL_HEADER32 OptionalHeader;
882 ULONG CheckSum, HeaderCheckSum, OldChecksum;
883 SYSTEMTIME SystemTime;
884 FILETIME LastWriteTime;
885 BOOLEAN UpdateImage;
886 DWORD DataSize;
887 DPRINT("BindImageEx Called for: %s \n", ImageName);
888
889 /* Set and Clear Buffer */
890 File = &FileData;
891 RtlZeroMemory(File, sizeof(*File));
892
893 /* Request Image Data */
894 if (MapAndLoad(ImageName, DllPath, File, TRUE, FALSE))
895 {
896 /* Write the image's name */
897 DPRINT("Image Mapped and Loaded\n");
898 File->ModuleName = ImageName;
899
900 /* Check if the image is valid and if it should be bound */
901 if ((File->FileHeader) &&
902 ((Flags & BIND_ALL_IMAGES) || (!File->fSystemImage)))
903 {
904 /* Get the optional header */
905 FileHeader = &File->FileHeader->FileHeader;
906 OptionalHeader = &File->FileHeader->OptionalHeader;
907
908 /* Check if this image should be bound */
909 if (OptionalHeader->DllCharacteristics &
910 IMAGE_DLLCHARACTERISTICS_NO_BIND)
911 {
912 /* Don't bind it */
913 goto Skip;
914 }
915
916 /* Check if the image has security data */
917 if ((ImageDirectoryEntryToData(File->MappedAddress,
918 FALSE,
919 IMAGE_DIRECTORY_ENTRY_SECURITY,
920 &DataSize)) || DataSize)
921 {
922 /* It does, skip it */
923 goto Skip;
924 }
925
926 /* Read Import Table */
927 BindpWalkAndProcessImports(File, DllPath, &UpdateImage);
928
929 /* Check if we need to update the image */
930 if ((UpdateImage) && (File->hFile != INVALID_HANDLE_VALUE))
931 {
932 /* FIXME: Update symbols */
933
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),
939 &HeaderCheckSum,
940 &CheckSum);
941 File->FileHeader->OptionalHeader.CheckSum = CheckSum;
942
943 /* Save Changes */
944 DPRINT("Saving Changes to file\n");
945 FlushViewOfFile(File->MappedAddress, File->SizeOfImage);
946
947 /* Save new Modified Time */
948 DPRINT("Setting time\n");
949 GetSystemTime(&SystemTime);
950 SystemTimeToFileTime(&SystemTime, &LastWriteTime);
951 SetFileTime(File->hFile, NULL, NULL, &LastWriteTime);
952 }
953 }
954 }
955
956 Skip:
957
958 /* Unmap the image */
959 UnmapViewOfFile(File->MappedAddress);
960
961 /* Close the handle if it's valid */
962 if (File->hFile != INVALID_HANDLE_VALUE) CloseHandle(File->hFile);
963
964 /* Unload all the images if we're not supposed to cache them */
965 if (!(Flags & BIND_CACHE_IMPORT_DLLS)) UnloadAllImages();
966
967 /* Return success */
968 DPRINT("Done\n");
969 return TRUE;
970 }
971
972 /*
973 * @implemented
974 */
975 BOOL
976 IMAGEAPI
977 BindImage(LPSTR ImageName,
978 LPSTR DllPath,
979 LPSTR SymbolPath)
980 {
981 /* Call the newer API */
982 return BindImageEx(0,
983 ImageName,
984 DllPath,
985 SymbolPath,
986 NULL);
987 }
988
989 /*
990 * @unimplemented
991 */
992 BOOL
993 IMAGEAPI
994 ReBaseImage(LPSTR CurrentImageName,
995 LPSTR SymbolPath,
996 BOOL fReBase,
997 BOOL fRebaseSysfileOk,
998 BOOL fGoingDown,
999 ULONG CheckImageSize,
1000 ULONG *OldImageSize,
1001 ULONG *OldImageBase,
1002 ULONG *NewImageSize,
1003 ULONG *NewImageBase,
1004 ULONG TimeStamp)
1005 {
1006 UNIMPLEMENTED;
1007 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1008 return FALSE;
1009 }
1010
1011 /*
1012 * @unimplemented
1013 */
1014 VOID
1015 IMAGEAPI
1016 RemoveRelocations(PCHAR ImageName)
1017 {
1018 UNIMPLEMENTED;
1019 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1020 }
1021
1022 /*
1023 * @unimplemented
1024 */
1025 BOOL
1026 IMAGEAPI
1027 SplitSymbols(LPSTR ImageName,
1028 LPSTR SymbolsPath,
1029 LPSTR SymbolFilePath,
1030 DWORD Flags)
1031 {
1032 UNIMPLEMENTED;
1033 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1034 return FALSE;
1035 }
1036
1037 /*
1038 * @implemented
1039 */
1040 BOOL
1041 IMAGEAPI
1042 TouchFileTimes(HANDLE FileHandle,
1043 LPSYSTEMTIME lpSystemTime)
1044 {
1045 FILETIME FileTime;
1046 SYSTEMTIME SystemTime;
1047
1048 if(lpSystemTime == NULL)
1049 {
1050 GetSystemTime(&SystemTime);
1051 lpSystemTime = &SystemTime;
1052 }
1053
1054 return (SystemTimeToFileTime(lpSystemTime,
1055 &FileTime) &&
1056 SetFileTime(FileHandle,
1057 NULL,
1058 NULL,
1059 &FileTime));
1060 }