4 * Copyright 1998 Patrik Stridvall
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /* INCLUDES ******************************************************************/
28 /* DATA **********************************************************************/
30 BOOLEAN DllListInitialized
;
31 LIST_ENTRY ImageLoadListHead
;
33 /* FUNCTIONS *****************************************************************/
37 ImageDirectoryEntryToData32(PVOID Base
,
38 BOOLEAN MappedAsImage
,
39 USHORT DirectoryEntry
,
41 PIMAGE_SECTION_HEADER
*FoundHeader OPTIONAL
,
42 PIMAGE_FILE_HEADER FileHeader
,
43 PIMAGE_OPTIONAL_HEADER OptionalHeader
)
46 PIMAGE_SECTION_HEADER CurrentSection
;
47 ULONG DirectoryEntryVA
;
49 /* Check if this entry is invalid */
50 if (DirectoryEntry
>= OptionalHeader
->NumberOfRvaAndSizes
)
57 /* Get the VA of the Directory Requested */
58 DirectoryEntryVA
= OptionalHeader
->DataDirectory
[DirectoryEntry
].VirtualAddress
;
59 if (!DirectoryEntryVA
)
61 /* It doesn't exist */
66 /* Get the size of the Directory Requested */
67 *Size
= OptionalHeader
->DataDirectory
[DirectoryEntry
].Size
;
69 /* Check if it was mapped as an image or if the entry is within the headers */
70 if ((MappedAsImage
) || (DirectoryEntryVA
< OptionalHeader
->SizeOfHeaders
))
73 if (FoundHeader
) *FoundHeader
= NULL
;
75 /* And simply return the VA */
76 return (PVOID
)((ULONG_PTR
)Base
+ DirectoryEntryVA
);
79 /* Read the first Section */
80 CurrentSection
= (PIMAGE_SECTION_HEADER
)((ULONG_PTR
)OptionalHeader
+
81 FileHeader
->SizeOfOptionalHeader
);
83 /* Loop through every section*/
84 for (i
= 0; i
< FileHeader
->NumberOfSections
; i
++)
86 /* If the Directory VA is located inside this section's VA, then this section belongs to this Directory */
87 if ((DirectoryEntryVA
>= CurrentSection
->VirtualAddress
) &&
88 (DirectoryEntryVA
< (CurrentSection
->VirtualAddress
+
89 CurrentSection
->SizeOfRawData
)))
91 /* Return the section header */
92 if (FoundHeader
) *FoundHeader
= CurrentSection
;
93 return ((PVOID
)((ULONG_PTR
)Base
+
94 (DirectoryEntryVA
- CurrentSection
->VirtualAddress
) +
95 CurrentSection
->PointerToRawData
));
98 /* Move to the next section */
102 /* If we got here, then we didn't find anything */
111 GetTimestampForLoadedLibrary(HMODULE Module
)
114 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
123 GetImageConfigInformation(PLOADED_IMAGE LoadedImage
,
124 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigInformation
)
127 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
136 GetImageUnusedHeaderBytes(PLOADED_IMAGE LoadedImage
,
137 LPDWORD SizeUnusedHeaderBytes
)
139 SIZE_T FirstFreeByte
;
140 PIMAGE_OPTIONAL_HEADER OptionalHeader
= NULL
;
141 PIMAGE_NT_HEADERS NtHeaders
;
144 /* Read the NT Headers */
145 NtHeaders
= LoadedImage
->FileHeader
;
147 /* Find the first free byte, which is after all the headers and sections */
148 FirstFreeByte
= (ULONG_PTR
)NtHeaders
-
149 (ULONG_PTR
)LoadedImage
->MappedAddress
+
150 FIELD_OFFSET(IMAGE_NT_HEADERS
, OptionalHeader
) +
151 NtHeaders
->FileHeader
.SizeOfOptionalHeader
+
152 NtHeaders
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
154 /* Get the Optional Header */
155 OptionalHeader
= &LoadedImage
->FileHeader
->OptionalHeader
;
158 * There is the possibilty that one of the Data Directories is in the PE Header
159 * itself, so we'll need to find such a case and add it to our PE used space
161 for (i
= 0; i
< OptionalHeader
->NumberOfRvaAndSizes
; i
++)
163 /* If the VA is less then the size of headers, then the data is inside the PE header */
164 if (OptionalHeader
->DataDirectory
[i
].VirtualAddress
<
165 OptionalHeader
->SizeOfHeaders
)
167 /* However, make sure it's not 0, which means it doesnt actually exist */
168 if (OptionalHeader
->DataDirectory
[i
].VirtualAddress
>=
171 /* Our first empty byte is after this Directory Data then */
172 FirstFreeByte
= OptionalHeader
->DataDirectory
[i
].VirtualAddress
+
173 OptionalHeader
->DataDirectory
[i
].Size
;
178 /* Return the unused Header Bytes */
179 *SizeUnusedHeaderBytes
= OptionalHeader
->SizeOfHeaders
- (DWORD
)FirstFreeByte
;
181 /* And return the first free byte*/
182 return (DWORD
)FirstFreeByte
;
190 ImageDirectoryEntryToData(PVOID Base
,
191 BOOLEAN MappedAsImage
,
192 USHORT DirectoryEntry
,
195 /* Let the extended function handle it */
196 return ImageDirectoryEntryToDataEx(Base
,
208 ImageDirectoryEntryToDataEx(IN PVOID Base
,
209 IN BOOLEAN MappedAsImage
,
210 IN USHORT DirectoryEntry
,
212 OUT PIMAGE_SECTION_HEADER
*FoundSection OPTIONAL
)
214 PIMAGE_NT_HEADERS NtHeader
;
215 PIMAGE_FILE_HEADER FileHeader
;
216 PIMAGE_OPTIONAL_HEADER OptionalHeader
;
218 /* Get the optional header ourselves */
219 NtHeader
= ImageNtHeader(Base
);
220 FileHeader
= &NtHeader
->FileHeader
;
221 OptionalHeader
= &NtHeader
->OptionalHeader
;
223 /* FIXME: Read image type and call appropriate function (32, 64, ROM) */
224 return ImageDirectoryEntryToData32(Base
,
238 ImageLoad(LPSTR DllName
,
241 PLIST_ENTRY Head
, Next
;
242 PLOADED_IMAGE LoadedImage
;
243 CHAR Drive
[_MAX_DRIVE
], Dir
[_MAX_DIR
], Filename
[_MAX_FNAME
], Ext
[_MAX_EXT
];
244 BOOL CompleteName
= TRUE
;
245 CHAR FullName
[MAX_PATH
];
247 /* Initialize the List Head */
248 if (!DllListInitialized
)
250 InitializeListHead(&ImageLoadListHead
);
251 DllListInitialized
= TRUE
;
254 /* Move to the Next DLL */
255 Head
= &ImageLoadListHead
;
257 DPRINT("Trying to find library: %s in current ListHead \n", DllName
);
260 _splitpath(DllName
, Drive
, Dir
, Filename
, Ext
);
262 /* Check if we only got a name */
263 if (!strlen(Drive
) && !strlen(Dir
)) CompleteName
= FALSE
;
265 /* Check if we already Loaded it */
268 /* Get the Loaded Image Structure */
269 LoadedImage
= CONTAINING_RECORD(Next
, LOADED_IMAGE
, Links
);
270 DPRINT("Found: %s in current ListHead \n", LoadedImage
->ModuleName
);
272 /* Check if we didn't have a complete name */
275 /* Split this module's name */
276 _splitpath(LoadedImage
->ModuleName
, NULL
, NULL
, Filename
, Ext
);
278 /* Use only the name and extension */
279 strcpy(FullName
, Filename
);
280 strcat(FullName
, Ext
);
284 /* Use the full untouched name */
285 strcpy(FullName
, LoadedImage
->ModuleName
);
288 /* Check if the Names Match */
289 if (!_stricmp(DllName
, FullName
))
291 DPRINT("Found it, returning it\n");
295 /* Move to next Entry */
299 /* Allocate memory for the Structure, and write the Module Name under */
300 DPRINT("Didn't find it...allocating it for you now\n");
301 LoadedImage
= HeapAlloc(IMAGEHLP_hHeap
,
303 sizeof(*LoadedImage
) + strlen(DllName
) + 1);
306 /* Module Name will be after structure */
307 LoadedImage
->ModuleName
= (LPSTR
)(LoadedImage
+ 1);
309 /* Copy the Module Name */
310 strcpy(LoadedImage
->ModuleName
, DllName
);
313 if (MapAndLoad(DllName
, DllPath
, LoadedImage
, TRUE
, TRUE
))
315 /* Add it to our list and return it */
316 InsertTailList(&ImageLoadListHead
, &LoadedImage
->Links
);
320 /* If we're here...there's been a failure */
321 HeapFree(IMAGEHLP_hHeap
, 0, LoadedImage
);
330 PIMAGE_SECTION_HEADER
332 ImageRvaToSection(IN PIMAGE_NT_HEADERS NtHeaders
,
336 PIMAGE_SECTION_HEADER Section
;
339 /* Get the First Section */
340 Section
= IMAGE_FIRST_SECTION(NtHeaders
);
342 /* Look through each section */
343 for (i
= 0; i
< NtHeaders
->FileHeader
.NumberOfSections
; i
++)
345 /* Check if the RVA is in between */
346 if ((Rva
>= Section
->VirtualAddress
) &&
347 (Rva
< (Section
->VirtualAddress
+ Section
->SizeOfRawData
)))
349 /* Return this section */
353 /* Move to the next section */
366 ImageNtHeader(PVOID Base
)
369 return RtlImageNtHeader(Base
);
377 ImageRvaToVa(IN PIMAGE_NT_HEADERS NtHeaders
,
380 IN OUT PIMAGE_SECTION_HEADER
*LastRvaSection OPTIONAL
)
382 PIMAGE_SECTION_HEADER Section
;
384 /* Get the Section Associated */
385 Section
= ImageRvaToSection(NtHeaders
, Base
, Rva
);
387 /* Return it, if specified */
388 if (LastRvaSection
) *LastRvaSection
= Section
;
391 return (PVOID
)((ULONG_PTR
)Base
+ (Rva
- Section
->VirtualAddress
) +
392 Section
->PointerToRawData
);
400 ImageUnload(PLOADED_IMAGE LoadedImage
)
402 /* If the image list isn't empty, remove this entry */
403 if (!IsListEmpty(&LoadedImage
->Links
)) RemoveEntryList(&LoadedImage
->Links
);
405 /* Unmap and unload it */
406 UnMapAndLoad(LoadedImage
);
408 /* Free the structure */
409 HeapFree(IMAGEHLP_hHeap
, 0, LoadedImage
);
420 MapAndLoad(LPSTR ImageName
,
422 PLOADED_IMAGE LoadedImage
,
429 UCHAR Buffer
[MAX_PATH
];
432 PIMAGE_NT_HEADERS NtHeader
;
434 /* So we can add the DLL Path later */
435 FileToOpen
= ImageName
;
438 LoadedImage
->hFile
= INVALID_HANDLE_VALUE
;
440 /* Start open loop */
443 /* Get a handle to the file */
444 hFile
= CreateFileA(FileToOpen
,
445 ReadOnly
? GENERIC_READ
:
446 GENERIC_READ
| GENERIC_WRITE
,
447 ReadOnly
? FILE_SHARE_READ
:
448 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
454 if (hFile
== INVALID_HANDLE_VALUE
)
456 /* Check if we already tried this once */
459 /* We didn't do do a path search now */
460 Tried
= SearchPath(DllPath
,
462 DotDll
? ".dll" : ".exe",
467 /* Check if it was successful */
468 if (Tried
&& (Tried
< MAX_PATH
))
470 /* Change the filename to use, and try again */
480 /* Success, break out */
484 /* Create the File Mapping */
485 hFileMapping
= CreateFileMappingA(hFile
,
487 ReadOnly
? PAGE_READONLY
:
495 SetLastError(GetLastError());
500 /* Get a pointer to the file */
501 LoadedImage
->MappedAddress
= MapViewOfFile(hFileMapping
,
502 ReadOnly
? FILE_MAP_READ
:
508 /* Close the handle to the map, we don't need it anymore */
509 CloseHandle(hFileMapping
);
511 /* Write the image size */
512 LoadedImage
->SizeOfImage
= GetFileSize(hFile
, NULL
);
514 /* Get the Nt Header */
515 NtHeader
= ImageNtHeader(LoadedImage
->MappedAddress
);
517 /* Allocate memory for the name and save it */
518 LoadedImage
->ModuleName
= HeapAlloc(IMAGEHLP_hHeap
,
520 strlen(FileToOpen
) + 16);
521 strcpy(LoadedImage
->ModuleName
, FileToOpen
);
523 /* Save the NT Header */
524 LoadedImage
->FileHeader
= NtHeader
;
526 /* Save the section data */
527 LoadedImage
->Sections
= IMAGE_FIRST_SECTION(NtHeader
);
528 LoadedImage
->NumberOfSections
= NtHeader
->FileHeader
.NumberOfSections
;
530 /* Setup other data */
531 LoadedImage
->SizeOfImage
= NtHeader
->OptionalHeader
.SizeOfImage
;
532 LoadedImage
->Characteristics
= NtHeader
->FileHeader
.Characteristics
;
533 LoadedImage
->LastRvaSection
= LoadedImage
->Sections
;
534 LoadedImage
->fSystemImage
= FALSE
; /* FIXME */
535 LoadedImage
->fDOSImage
= FALSE
; /* FIXME */
536 InitializeListHead(&LoadedImage
->Links
);
538 /* Check if it was read-only */
541 /* It was, so close our handle and write it as invalid */
543 LoadedImage
->hFile
= INVALID_HANDLE_VALUE
;
547 /* Write our file handle */
548 LoadedImage
->hFile
= hFile
;
560 SetImageConfigInformation(PLOADED_IMAGE LoadedImage
,
561 PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigInformation
)
564 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
573 UnMapAndLoad(PLOADED_IMAGE Image
)
575 PIMAGE_NT_HEADERS NtHeader
;
576 DWORD HeaderCheckSum
, CheckSum
;
578 /* Check if the image was read-only */
579 if (Image
->hFile
== INVALID_HANDLE_VALUE
)
581 /* We'll only unmap the view */
582 UnmapViewOfFile(Image
->MappedAddress
);
586 /* Calculate the checksum */
587 CheckSumMappedFile(Image
->MappedAddress
,
592 /* Get the NT Header */
593 NtHeader
= Image
->FileHeader
;
595 /* Write the new checksum to it */
596 NtHeader
->OptionalHeader
.CheckSum
= CheckSum
;
598 /* Now flush and unmap the image */
599 FlushViewOfFile(Image
->MappedAddress
, Image
->SizeOfImage
);
600 UnmapViewOfFile(Image
->MappedAddress
);
602 /* Check if the size changed */
603 if (Image
->SizeOfImage
!= GetFileSize(Image
->hFile
, NULL
))
605 /* Update the file pointer */
606 SetFilePointer(Image
->hFile
, Image
->SizeOfImage
, NULL
, FILE_BEGIN
);
607 SetEndOfFile(Image
->hFile
);
611 /* Check if the image had a valid handle, and close it */
612 if (Image
->hFile
!= INVALID_HANDLE_VALUE
) CloseHandle(Image
->hFile
);
620 UnloadAllImages(VOID
)
622 PLIST_ENTRY Head
, Entry
;
623 PLOADED_IMAGE CurrentImage
;
625 /* Make sure we're initialized */
626 if (!DllListInitialized
) return TRUE
;
628 /* Get the list pointers and loop */
629 Head
= &ImageLoadListHead
;
631 while (Entry
!= Head
)
634 CurrentImage
= CONTAINING_RECORD(Entry
, LOADED_IMAGE
, Links
);
636 /* Move to the next entry */
637 Entry
= Entry
->Flink
;
640 ImageUnload(CurrentImage
);
643 /* We are not initialized anymore */
644 DllListInitialized
= FALSE
;