summaryrefslogtreecommitdiffstats
path: root/private/ntos/rtl/ldrrsrc.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/rtl/ldrrsrc.c')
-rw-r--r--private/ntos/rtl/ldrrsrc.c930
1 files changed, 930 insertions, 0 deletions
diff --git a/private/ntos/rtl/ldrrsrc.c b/private/ntos/rtl/ldrrsrc.c
new file mode 100644
index 000000000..95e664f2b
--- /dev/null
+++ b/private/ntos/rtl/ldrrsrc.c
@@ -0,0 +1,930 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ldrrsrc.c
+
+Abstract:
+
+ Loader API calls for accessing resource sections.
+
+Author:
+
+ Steve Wood (stevewo) 16-Sep-1991
+
+Revision History:
+
+--*/
+
+#include "ntrtlp.h"
+
+#if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
+#pragma alloc_text(PAGE,LdrAccessResource)
+#pragma alloc_text(PAGE,LdrpAccessResourceData)
+#pragma alloc_text(PAGE,LdrFindEntryForAddress)
+#pragma alloc_text(PAGE,LdrFindResource_U)
+#pragma alloc_text(PAGE,LdrFindResourceDirectory_U)
+#pragma alloc_text(PAGE,LdrpCompareResourceNames_U)
+#pragma alloc_text(PAGE,LdrpSearchResourceSection_U)
+#pragma alloc_text(PAGE,LdrEnumResources)
+#endif
+
+NTSTATUS
+LdrAccessResource(
+ IN PVOID DllHandle,
+ IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,
+ OUT PVOID *Address OPTIONAL,
+ OUT PULONG Size OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This function locates the address of the specified resource in the
+ specified DLL and returns its address.
+
+Arguments:
+
+ DllHandle - Supplies a handle to the image file that the resource is
+ contained in.
+
+ ResourceDataEntry - Supplies a pointer to the resource data entry in
+ the resource data section of the image file specified by the
+ DllHandle parameter. This pointer should have been one returned
+ by the LdrFindResource function.
+
+ Address - Optional pointer to a variable that will receive the
+ address of the resource specified by the first two parameters.
+
+ Size - Optional pointer to a variable that will receive the size of
+ the resource specified by the first two parameters.
+
+Return Value:
+
+ TBD
+
+--*/
+
+{
+ RTL_PAGED_CODE();
+
+ return LdrpAccessResourceData(
+ DllHandle,
+ ResourceDataEntry,
+ Address,
+ Size
+ );
+}
+
+
+NTSTATUS
+LdrpAccessResourceData(
+ IN PVOID DllHandle,
+ IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,
+ OUT PVOID *Address OPTIONAL,
+ OUT PULONG Size OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the data necessary to actually examine the
+ contents of a particular resource.
+
+Arguments:
+
+ DllHandle - Supplies a handle to the image file that the resource is
+ contained in.
+
+ ResourceDataEntry - Supplies a pointer to the resource data entry in
+ the resource data directory of the image file specified by the
+ DllHandle parameter. This pointer should have been one returned
+ by the LdrFindResource function.
+
+ Address - Optional pointer to a variable that will receive the
+ address of the resource specified by the first two parameters.
+
+ Size - Optional pointer to a variable that will receive the size of
+ the resource specified by the first two parameters.
+
+
+Return Value:
+
+ TBD
+
+--*/
+
+{
+ PIMAGE_RESOURCE_DIRECTORY ResourceDirectory;
+ ULONG ResourceSize;
+ PIMAGE_NT_HEADERS NtHeaders;
+ ULONG VirtualAddressOffset;
+ PIMAGE_SECTION_HEADER NtSection;
+
+ RTL_PAGED_CODE();
+
+ ResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY)
+ RtlImageDirectoryEntryToData(DllHandle,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_RESOURCE,
+ &ResourceSize
+ );
+ if (!ResourceDirectory) {
+ return( STATUS_RESOURCE_DATA_NOT_FOUND );
+ }
+
+ if ((ULONG)DllHandle & 0x00000001) {
+ DllHandle = (PVOID)((ULONG)DllHandle & ~0x00000001);
+ NtHeaders = RtlImageNtHeader( DllHandle );
+ VirtualAddressOffset =
+ (ULONG)DllHandle +
+ NtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_RESOURCE ].VirtualAddress -
+ (ULONG)ResourceDirectory;
+
+ //
+ // Now, we must check to see if the resource is not in the
+ // same section as the resource table. If it's in .rsrc1,
+ // we've got to adjust the RVA in the ResourceDataEntry
+ // to point to the correct place in the non-VA data file.
+ //
+ NtSection= RtlSectionTableFromVirtualAddress( NtHeaders, DllHandle,
+ (PVOID)NtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_RESOURCE ].VirtualAddress );
+ if (!NtSection) {
+ return( STATUS_RESOURCE_DATA_NOT_FOUND );
+ }
+ if ( ResourceDataEntry->OffsetToData > NtSection->Misc.VirtualSize ) {
+ ULONG rva;
+
+ rva = NtSection->VirtualAddress;
+ NtSection= RtlSectionTableFromVirtualAddress
+ (
+ NtHeaders,
+ DllHandle,
+ (PVOID)ResourceDataEntry->OffsetToData
+ );
+ VirtualAddressOffset +=
+ ((ULONG)NtSection->VirtualAddress - rva) -
+ ((ULONG)RtlAddressInSectionTable ( NtHeaders, DllHandle, (PVOID)NtSection->VirtualAddress ) - (ULONG)ResourceDirectory);
+ }
+ }
+ else {
+ VirtualAddressOffset = 0;
+ }
+
+ try {
+ if (ARGUMENT_PRESENT( Address )) {
+ *Address = (PVOID)( (ULONG)DllHandle +
+ (ResourceDataEntry->OffsetToData - VirtualAddressOffset)
+ );
+ }
+
+ if (ARGUMENT_PRESENT( Size )) {
+ *Size = ResourceDataEntry->Size;
+ }
+ }
+ except (EXCEPTION_EXECUTE_HANDLER) {
+ return GetExceptionCode();
+ }
+
+ return( STATUS_SUCCESS );
+}
+
+
+NTSTATUS
+LdrFindEntryForAddress(
+ IN PVOID Address,
+ OUT PLDR_DATA_TABLE_ENTRY *TableEntry
+ )
+/*++
+
+Routine Description:
+
+ This function returns the load data table entry that describes the virtual
+ address range that contains the passed virtual address.
+
+Arguments:
+
+ Address - Supplies a 32-bit virtual address.
+
+ TableEntry - Supplies a pointer to the variable that will receive the
+ address of the loader data table entry.
+
+
+Return Value:
+
+ Status
+
+--*/
+{
+ PPEB_LDR_DATA Ldr;
+ PLIST_ENTRY Head, Next;
+ PLDR_DATA_TABLE_ENTRY Entry;
+ PIMAGE_NT_HEADERS NtHeaders;
+ PVOID ImageBase;
+ PVOID EndOfImage;
+
+ Ldr = NtCurrentPeb()->Ldr;
+ if (Ldr == NULL) {
+ return( STATUS_NO_MORE_ENTRIES );
+ }
+
+ Head = &Ldr->InMemoryOrderModuleList;
+ Next = Head->Flink;
+ while ( Next != Head ) {
+ Entry = CONTAINING_RECORD( Next, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks );
+
+ NtHeaders = RtlImageNtHeader( Entry->DllBase );
+ if (NtHeaders != NULL) {
+ ImageBase = (PVOID)Entry->DllBase;
+
+ EndOfImage = (PVOID)
+ ((ULONG)ImageBase + NtHeaders->OptionalHeader.SizeOfImage);
+
+ if ((ULONG)Address >= (ULONG)ImageBase && (ULONG)Address < (ULONG)EndOfImage) {
+ *TableEntry = Entry;
+ return( STATUS_SUCCESS );
+ }
+ }
+
+ Next = Next->Flink;
+ }
+
+ return( STATUS_NO_MORE_ENTRIES );
+}
+
+
+NTSTATUS
+LdrFindResource_U(
+ IN PVOID DllHandle,
+ IN PULONG ResourceIdPath,
+ IN ULONG ResourceIdPathLength,
+ OUT PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry
+ )
+
+/*++
+
+Routine Description:
+
+ This function locates the address of the specified resource in the
+ specified DLL and returns its address.
+
+Arguments:
+
+ DllHandle - Supplies a handle to the image file that the resource is
+ contained in.
+
+ ResourceIdPath - Supplies a pointer to an array of 32-bit resource
+ identifiers. Each identifier is either an integer or a pointer
+ to a STRING structure that specifies a resource name. The array
+ is used to traverse the directory structure contained in the
+ resource section in the image file specified by the DllHandle
+ parameter.
+
+ ResourceIdPathLength - Supplies the number of elements in the
+ ResourceIdPath array.
+
+ ResourceDataEntry - Supplies a pointer to a variable that will
+ receive the address of the resource data entry in the resource
+ data section of the image file specified by the DllHandle
+ parameter.
+
+Return Value:
+
+ TBD
+
+--*/
+
+{
+ RTL_PAGED_CODE();
+
+ return LdrpSearchResourceSection_U(
+ DllHandle,
+ ResourceIdPath,
+ ResourceIdPathLength,
+ FALSE, // Look for a leaf node
+ (PVOID *)ResourceDataEntry
+ );
+}
+
+
+NTSTATUS
+LdrFindResourceDirectory_U(
+ IN PVOID DllHandle,
+ IN PULONG ResourceIdPath,
+ IN ULONG ResourceIdPathLength,
+ OUT PIMAGE_RESOURCE_DIRECTORY *ResourceDirectory
+ )
+
+/*++
+
+Routine Description:
+
+ This function locates the address of the specified resource directory in
+ specified DLL and returns its address.
+
+Arguments:
+
+ DllHandle - Supplies a handle to the image file that the resource
+ directory is contained in.
+
+ ResourceIdPath - Supplies a pointer to an array of 32-bit resource
+ identifiers. Each identifier is either an integer or a pointer
+ to a STRING structure that specifies a resource name. The array
+ is used to traverse the directory structure contained in the
+ resource section in the image file specified by the DllHandle
+ parameter.
+
+ ResourceIdPathLength - Supplies the number of elements in the
+ ResourceIdPath array.
+
+ ResourceDirectory - Supplies a pointer to a variable that will
+ receive the address of the resource directory specified by
+ ResourceIdPath in the resource data section of the image file
+ the DllHandle parameter.
+
+Return Value:
+
+ TBD
+
+--*/
+
+{
+ RTL_PAGED_CODE();
+
+ return LdrpSearchResourceSection_U(
+ DllHandle,
+ ResourceIdPath,
+ ResourceIdPathLength,
+ TRUE, // Look for a directory node
+ (PVOID *)ResourceDirectory
+ );
+}
+
+
+LONG
+LdrpCompareResourceNames_U(
+ IN ULONG ResourceName,
+ IN PIMAGE_RESOURCE_DIRECTORY ResourceDirectory,
+ IN PIMAGE_RESOURCE_DIRECTORY_ENTRY ResourceDirectoryEntry
+ )
+{
+ LONG li;
+ PIMAGE_RESOURCE_DIR_STRING_U ResourceNameString;
+
+ if (ResourceName & LDR_RESOURCE_ID_NAME_MASK) {
+ if (!ResourceDirectoryEntry->NameIsString) {
+ return( -1 );
+ }
+
+ ResourceNameString = (PIMAGE_RESOURCE_DIR_STRING_U)
+ ((PCHAR)ResourceDirectory + ResourceDirectoryEntry->NameOffset);
+
+ li = wcsncmp( (LPWSTR)ResourceName,
+ ResourceNameString->NameString,
+ ResourceNameString->Length
+ );
+
+ if (!li && wcslen((PWSTR)ResourceName) != ResourceNameString->Length) {
+ return( 1 );
+ }
+
+ return(li);
+ }
+ else {
+ if (ResourceDirectoryEntry->NameIsString) {
+ return( 1 );
+ }
+
+ return( ResourceName - ResourceDirectoryEntry->Name );
+ }
+}
+
+
+#define USE_FIRSTAVAILABLE_LANGID (0xFFFFFFFF & ~LDR_RESOURCE_ID_NAME_MASK)
+
+NTSTATUS
+LdrpSearchResourceSection_U(
+ IN PVOID DllHandle,
+ IN PULONG ResourceIdPath,
+ IN ULONG ResourceIdPathLength,
+ IN BOOLEAN FindDirectoryEntry,
+ OUT PVOID *ResourceDirectoryOrData
+ )
+
+/*++
+
+Routine Description:
+
+ This function locates the address of the specified resource in the
+ specified DLL and returns its address.
+
+Arguments:
+
+ DllHandle - Supplies a handle to the image file that the resource is
+ contained in.
+
+ ResourceIdPath - Supplies a pointer to an array of 32-bit resource
+ identifiers. Each identifier is either an integer or a pointer
+ to a null terminated string (PSZ) that specifies a resource
+ name. The array is used to traverse the directory structure
+ contained in the resource section in the image file specified by
+ the DllHandle parameter.
+
+ ResourceIdPathLength - Supplies the number of elements in the
+ ResourceIdPath array.
+
+ FindDirectoryEntry - Supplies a boolean that is TRUE if caller is
+ searching for a resource directory, otherwise the caller is
+ searching for a resource data entry.
+
+ ResourceDirectoryOrData - Supplies a pointer to a variable that will
+ receive the address of the resource directory or data entry in
+ the resource data section of the image file specified by the
+ DllHandle parameter.
+
+Return Value:
+
+ TBD
+
+--*/
+
+{
+ NTSTATUS Status;
+ PIMAGE_RESOURCE_DIRECTORY LanguageResourceDirectory, ResourceDirectory, TopResourceDirectory;
+ PIMAGE_RESOURCE_DIRECTORY_ENTRY ResourceDirEntLow;
+ PIMAGE_RESOURCE_DIRECTORY_ENTRY ResourceDirEntMiddle;
+ PIMAGE_RESOURCE_DIRECTORY_ENTRY ResourceDirEntHigh;
+ PIMAGE_RESOURCE_DATA_ENTRY ResourceEntry;
+ USHORT n, half;
+ LONG dir;
+ ULONG size;
+ ULONG ResourceIdRetry, RetryCount;
+ LCID DefaultThreadLocale, DefaultSystemLocale;
+ LANGID NewLangId;
+ PULONG IdPath = ResourceIdPath;
+ ULONG IdPathLength = ResourceIdPathLength;
+ BOOLEAN fIsNeutral = FALSE;
+ LANGID GivenLanguage;
+
+ RTL_PAGED_CODE();
+
+ TopResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY)
+ RtlImageDirectoryEntryToData(DllHandle,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_RESOURCE,
+ &size
+ );
+ if (!TopResourceDirectory) {
+ return( STATUS_RESOURCE_DATA_NOT_FOUND );
+ }
+
+ try {
+ ResourceDirectory = TopResourceDirectory;
+ ResourceIdRetry = USE_FIRSTAVAILABLE_LANGID;
+ RetryCount = 0;
+ ResourceEntry = NULL;
+ LanguageResourceDirectory = NULL;
+ while (ResourceDirectory != NULL && ResourceIdPathLength--) {
+ //
+ // If search path includes a language id, then attempt to
+ // match the following language ids in this order:
+ //
+ // (0) use given language id
+ // (1) use primary language of given language id
+ // (2) use id 0 (neutral resource)
+ //
+ // If the PRIMARY language id is ZERO, then ALSO attempt to
+ // match the following language ids in this order:
+ //
+ // (3) use lang id from locale in TEB
+ // (4) use lang id from user's locale id
+ // (5) use primary language of user's locale id
+ // (6) use lang id from system default locale id
+ // (7) use primary language of system default locale id
+ // (8) use US English lang id
+ // (9) use any lang id that matches requested info
+ //
+ if (ResourceIdPathLength == 0 && IdPathLength == 3) {
+ LanguageResourceDirectory = ResourceDirectory;
+ }
+
+ if (LanguageResourceDirectory != NULL) {
+ GivenLanguage = (LANGID)IdPath[ 2 ];
+ fIsNeutral = (PRIMARYLANGID( GivenLanguage ) == LANG_NEUTRAL);
+TryNextLangId:
+ switch( RetryCount++ ) {
+ case 0: // Use given language id
+ NewLangId = GivenLanguage;
+ break;
+
+ case 1: // Use primary language of given language id
+ NewLangId = PRIMARYLANGID( GivenLanguage );
+ break;
+
+ case 2: // Use id 0 (neutral resource)
+ NewLangId = LANG_USER_DEFAULT;
+ NewLangId = LANG_SYSTEM_DEFAULT;
+ NewLangId = 0;
+ break;
+
+ case 3: // Use lang id from locale in TEB
+ if ( !fIsNeutral ) {
+ // Stop looking - Not in the neutral case
+ goto ReturnFailure;
+ break;
+ }
+
+ if (SUBLANGID( GivenLanguage ) == SUBLANG_SYS_DEFAULT) {
+ // Skip over all USER locale options
+ DefaultThreadLocale = 0;
+ RetryCount += 2;
+ break;
+ }
+
+ if (NtCurrentTeb() != NULL) {
+ NewLangId = LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale);
+ }
+ break;
+
+ case 4: // Use User's default locale
+ Status = NtQueryDefaultLocale( TRUE, &DefaultThreadLocale );
+ if (NT_SUCCESS( Status )) {
+ NewLangId = LANGIDFROMLCID(DefaultThreadLocale);
+ break;
+ }
+
+ RetryCount++;
+ break;
+
+ case 5: // Use primary language of User's default locale
+ NewLangId = PRIMARYLANGID( (LANGID)ResourceIdRetry );
+ break;
+
+ case 6: // Use System default locale
+ Status = NtQueryDefaultLocale( FALSE, &DefaultSystemLocale );
+ if (!NT_SUCCESS( Status )) {
+ RetryCount++;
+ break;
+ }
+
+ if (DefaultSystemLocale != DefaultThreadLocale) {
+ NewLangId = LANGIDFROMLCID(DefaultSystemLocale);
+ break;
+ }
+
+ RetryCount += 2;
+ // fall through
+
+ case 8: // Use US English language
+ NewLangId = MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US );
+ break;
+
+ case 7: // Use primary language of System default locale
+ NewLangId = PRIMARYLANGID( (LANGID)ResourceIdRetry );
+ break;
+
+ case 9: // Take any lang id that matches
+ NewLangId = USE_FIRSTAVAILABLE_LANGID;
+ break;
+
+ default: // No lang ids to match
+ goto ReturnFailure;
+ break;
+ }
+
+ //
+ // If looking for a specific language id and same as the
+ // one we just looked up, then skip it.
+ //
+ if (NewLangId != USE_FIRSTAVAILABLE_LANGID &&
+ NewLangId == ResourceIdRetry
+ ) {
+ goto TryNextLangId;
+ }
+
+ //
+ // Try this new language Id
+ //
+ ResourceIdRetry = (ULONG)NewLangId;
+ ResourceIdPath = &ResourceIdRetry;
+ ResourceDirectory = LanguageResourceDirectory;
+ }
+
+ n = ResourceDirectory->NumberOfNamedEntries;
+ ResourceDirEntLow = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResourceDirectory+1);
+ if (!(*ResourceIdPath & LDR_RESOURCE_ID_NAME_MASK)) {
+ ResourceDirEntLow += n;
+ n = ResourceDirectory->NumberOfIdEntries;
+ }
+
+ if (!n) {
+ ResourceDirectory = NULL;
+ goto NotFound;
+ }
+
+ if (LanguageResourceDirectory != NULL &&
+ *ResourceIdPath == USE_FIRSTAVAILABLE_LANGID
+ ) {
+ ResourceDirectory = NULL;
+ ResourceIdRetry = ResourceDirEntLow->Name;
+ ResourceEntry = (PIMAGE_RESOURCE_DATA_ENTRY)
+ ((PCHAR)TopResourceDirectory +
+ ResourceDirEntLow->OffsetToData
+ );
+
+ break;
+ }
+
+ ResourceDirectory = NULL;
+ ResourceDirEntHigh = ResourceDirEntLow + n - 1;
+ while (ResourceDirEntLow <= ResourceDirEntHigh) {
+ if ((half = (n >> 1)) != 0) {
+ ResourceDirEntMiddle = ResourceDirEntLow;
+ if (*(PUCHAR)&n & 1) {
+ ResourceDirEntMiddle += half;
+ }
+ else {
+ ResourceDirEntMiddle += half - 1;
+ }
+ dir = LdrpCompareResourceNames_U( *ResourceIdPath,
+ TopResourceDirectory,
+ ResourceDirEntMiddle
+ );
+ if (!dir) {
+ if (ResourceDirEntMiddle->DataIsDirectory) {
+ ResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY)
+ ((PCHAR)TopResourceDirectory +
+ ResourceDirEntMiddle->OffsetToDirectory
+ );
+ }
+ else {
+ ResourceDirectory = NULL;
+ ResourceEntry = (PIMAGE_RESOURCE_DATA_ENTRY)
+ ((PCHAR)TopResourceDirectory +
+ ResourceDirEntMiddle->OffsetToData
+ );
+ }
+
+ break;
+ }
+ else {
+ if (dir < 0) {
+ ResourceDirEntHigh = ResourceDirEntMiddle - 1;
+ if (*(PUCHAR)&n & 1) {
+ n = half;
+ }
+ else {
+ n = half - 1;
+ }
+ }
+ else {
+ ResourceDirEntLow = ResourceDirEntMiddle + 1;
+ n = half;
+ }
+ }
+ }
+ else {
+ if (n != 0) {
+ dir = LdrpCompareResourceNames_U( *ResourceIdPath,
+ TopResourceDirectory,
+ ResourceDirEntLow
+ );
+ if (!dir) {
+ if (ResourceDirEntLow->DataIsDirectory) {
+ ResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY)
+ ((PCHAR)TopResourceDirectory +
+ ResourceDirEntLow->OffsetToDirectory
+ );
+ }
+ else {
+ ResourceEntry = (PIMAGE_RESOURCE_DATA_ENTRY)
+ ((PCHAR)TopResourceDirectory +
+ ResourceDirEntLow->OffsetToData
+ );
+ }
+ }
+ }
+
+ break;
+ }
+ }
+
+ ResourceIdPath++;
+ }
+
+ if (ResourceEntry != NULL && !FindDirectoryEntry) {
+ *ResourceDirectoryOrData = (PVOID)ResourceEntry;
+ Status = STATUS_SUCCESS;
+ }
+ else
+ if (ResourceDirectory != NULL && FindDirectoryEntry) {
+ *ResourceDirectoryOrData = (PVOID)ResourceDirectory;
+ Status = STATUS_SUCCESS;
+ }
+ else {
+NotFound:
+ switch( IdPathLength - ResourceIdPathLength) {
+ case 3: Status = STATUS_RESOURCE_LANG_NOT_FOUND; break;
+ case 2: Status = STATUS_RESOURCE_NAME_NOT_FOUND; break;
+ case 1: Status = STATUS_RESOURCE_TYPE_NOT_FOUND; break;
+ default: Status = STATUS_INVALID_PARAMETER; break;
+ }
+ }
+
+ if (Status == STATUS_RESOURCE_LANG_NOT_FOUND &&
+ LanguageResourceDirectory != NULL
+ ) {
+ ResourceEntry = NULL;
+ goto TryNextLangId;
+ReturnFailure: ;
+ }
+ }
+ except (EXCEPTION_EXECUTE_HANDLER) {
+ Status = GetExceptionCode();
+ }
+
+ return Status;
+}
+
+NTSTATUS
+LdrEnumResources(
+ IN PVOID DllHandle,
+ IN PULONG ResourceIdPath,
+ IN ULONG ResourceIdPathLength,
+ IN OUT PULONG NumberOfResources,
+ OUT PLDR_ENUM_RESOURCE_ENTRY Resources OPTIONAL
+ )
+{
+ NTSTATUS Status;
+ PIMAGE_RESOURCE_DIRECTORY TopResourceDirectory;
+ PIMAGE_RESOURCE_DIRECTORY TypeResourceDirectory;
+ PIMAGE_RESOURCE_DIRECTORY NameResourceDirectory;
+ PIMAGE_RESOURCE_DIRECTORY LangResourceDirectory;
+ PIMAGE_RESOURCE_DIRECTORY_ENTRY TypeResourceDirectoryEntry;
+ PIMAGE_RESOURCE_DIRECTORY_ENTRY NameResourceDirectoryEntry;
+ PIMAGE_RESOURCE_DIRECTORY_ENTRY LangResourceDirectoryEntry;
+ ULONG TypeDirectoryIndex, NumberOfTypeDirectoryEntries;
+ ULONG NameDirectoryIndex, NumberOfNameDirectoryEntries;
+ ULONG LangDirectoryIndex, NumberOfLangDirectoryEntries;
+ BOOLEAN ScanTypeDirectory;
+ BOOLEAN ScanNameDirectory;
+ BOOLEAN ReturnThisResource;
+ PIMAGE_RESOURCE_DIR_STRING_U ResourceNameString;
+ ULONG TypeResourceNameOrId;
+ ULONG NameResourceNameOrId;
+ ULONG LangResourceNameOrId;
+ PLDR_ENUM_RESOURCE_ENTRY ResourceInfo;
+ PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
+ ULONG ResourceIndex, MaxResourceIndex;
+ ULONG Size;
+
+ ResourceIndex = 0;
+ if (!ARGUMENT_PRESENT( Resources )) {
+ MaxResourceIndex = 0;
+ }
+ else {
+ MaxResourceIndex = *NumberOfResources;
+ }
+ *NumberOfResources = 0;
+
+ TopResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY)
+ RtlImageDirectoryEntryToData( DllHandle,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_RESOURCE,
+ &Size
+ );
+ if (!TopResourceDirectory) {
+ return STATUS_RESOURCE_DATA_NOT_FOUND;
+ }
+
+ TypeResourceDirectory = TopResourceDirectory;
+ TypeResourceDirectoryEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(TypeResourceDirectory+1);
+ NumberOfTypeDirectoryEntries = TypeResourceDirectory->NumberOfNamedEntries +
+ TypeResourceDirectory->NumberOfIdEntries;
+ TypeDirectoryIndex = 0;
+ Status = STATUS_SUCCESS;
+ for (TypeDirectoryIndex=0;
+ TypeDirectoryIndex<NumberOfTypeDirectoryEntries;
+ TypeDirectoryIndex++, TypeResourceDirectoryEntry++
+ ) {
+ if (ResourceIdPathLength > 0) {
+ ScanTypeDirectory = LdrpCompareResourceNames_U( ResourceIdPath[ 0 ],
+ TopResourceDirectory,
+ TypeResourceDirectoryEntry
+ ) == 0;
+ }
+ else {
+ ScanTypeDirectory = TRUE;
+ }
+ if (ScanTypeDirectory) {
+ if (!TypeResourceDirectoryEntry->DataIsDirectory) {
+ return STATUS_INVALID_IMAGE_FORMAT;
+ }
+ if (TypeResourceDirectoryEntry->NameIsString) {
+ ResourceNameString = (PIMAGE_RESOURCE_DIR_STRING_U)
+ ((PCHAR)TopResourceDirectory + TypeResourceDirectoryEntry->NameOffset);
+
+ TypeResourceNameOrId = (ULONG)ResourceNameString;
+ }
+ else {
+ TypeResourceNameOrId = (ULONG)TypeResourceDirectoryEntry->Id;
+ }
+
+ NameResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY)
+ ((PCHAR)TopResourceDirectory + TypeResourceDirectoryEntry->OffsetToDirectory);
+ NameResourceDirectoryEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(NameResourceDirectory+1);
+ NumberOfNameDirectoryEntries = NameResourceDirectory->NumberOfNamedEntries +
+ NameResourceDirectory->NumberOfIdEntries;
+ NameDirectoryIndex = 0;
+ for (NameDirectoryIndex=0;
+ NameDirectoryIndex<NumberOfNameDirectoryEntries;
+ NameDirectoryIndex++, NameResourceDirectoryEntry++
+ ) {
+ if (ResourceIdPathLength > 1) {
+ ScanNameDirectory = LdrpCompareResourceNames_U( ResourceIdPath[ 1 ],
+ TopResourceDirectory,
+ NameResourceDirectoryEntry
+ ) == 0;
+ }
+ else {
+ ScanNameDirectory = TRUE;
+ }
+ if (ScanNameDirectory) {
+ if (!NameResourceDirectoryEntry->DataIsDirectory) {
+ return STATUS_INVALID_IMAGE_FORMAT;
+ }
+
+ if (NameResourceDirectoryEntry->NameIsString) {
+ ResourceNameString = (PIMAGE_RESOURCE_DIR_STRING_U)
+ ((PCHAR)TopResourceDirectory + NameResourceDirectoryEntry->NameOffset);
+
+ NameResourceNameOrId = (ULONG)ResourceNameString;
+ }
+ else {
+ NameResourceNameOrId = (ULONG)NameResourceDirectoryEntry->Id;
+ }
+
+ LangResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY)
+ ((PCHAR)TopResourceDirectory + NameResourceDirectoryEntry->OffsetToDirectory);
+
+ LangResourceDirectoryEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(LangResourceDirectory+1);
+ NumberOfLangDirectoryEntries = LangResourceDirectory->NumberOfNamedEntries +
+ LangResourceDirectory->NumberOfIdEntries;
+ LangDirectoryIndex = 0;
+ for (LangDirectoryIndex=0;
+ LangDirectoryIndex<NumberOfLangDirectoryEntries;
+ LangDirectoryIndex++, LangResourceDirectoryEntry++
+ ) {
+ if (ResourceIdPathLength > 2) {
+ ReturnThisResource = LdrpCompareResourceNames_U( ResourceIdPath[ 2 ],
+ TopResourceDirectory,
+ LangResourceDirectoryEntry
+ ) == 0;
+ }
+ else {
+ ReturnThisResource = TRUE;
+ }
+ if (ReturnThisResource) {
+ if (LangResourceDirectoryEntry->DataIsDirectory) {
+ return STATUS_INVALID_IMAGE_FORMAT;
+ }
+
+ if (LangResourceDirectoryEntry->NameIsString) {
+ ResourceNameString = (PIMAGE_RESOURCE_DIR_STRING_U)
+ ((PCHAR)TopResourceDirectory + LangResourceDirectoryEntry->NameOffset);
+
+ LangResourceNameOrId = (ULONG)ResourceNameString;
+ }
+ else {
+ LangResourceNameOrId = (ULONG)LangResourceDirectoryEntry->Id;
+ }
+
+ ResourceDataEntry = (PIMAGE_RESOURCE_DATA_ENTRY)
+ ((PCHAR)TopResourceDirectory + LangResourceDirectoryEntry->OffsetToData);
+
+ ResourceInfo = &Resources[ ResourceIndex++ ];
+ if (ResourceIndex <= MaxResourceIndex) {
+ ResourceInfo->Path[ 0 ].NameOrId = TypeResourceNameOrId;
+ ResourceInfo->Path[ 1 ].NameOrId = NameResourceNameOrId;
+ ResourceInfo->Path[ 2 ].NameOrId = LangResourceNameOrId;
+ ResourceInfo->Data = (PVOID)((ULONG)DllHandle + ResourceDataEntry->OffsetToData);
+ ResourceInfo->Size = ResourceDataEntry->Size;
+ ResourceInfo->Reserved = 0;
+ }
+ else {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ *NumberOfResources = ResourceIndex;
+ return Status;
+}