1 /*
2  * PROJECT:         ReactOS api tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Test for LdrEnumResources
5  * PROGRAMMER:      Timo Kreuzer
6  */
7 
8 #include "precomp.h"
9 
10 #include <pseh/pseh2.h>
11 
12 typedef struct _TEST_RESOURCES
13 {
14     IMAGE_RESOURCE_DIRECTORY TypeDirectory;
15     IMAGE_RESOURCE_DIRECTORY_ENTRY TypeEntries[2];
16     IMAGE_RESOURCE_DIRECTORY Name1Directory;
17     IMAGE_RESOURCE_DIRECTORY_ENTRY Name1Entries[2];
18     IMAGE_RESOURCE_DIRECTORY Name2Directory;
19     IMAGE_RESOURCE_DIRECTORY_ENTRY Name2Entries[2];
20     IMAGE_RESOURCE_DIRECTORY Lang1Directory;
21     IMAGE_RESOURCE_DIRECTORY_ENTRY Lang1Entries[2];
22     IMAGE_RESOURCE_DIRECTORY Lang2Directory;
23     IMAGE_RESOURCE_DIRECTORY_ENTRY Lang2Entries[2];
24     IMAGE_RESOURCE_DIRECTORY Lang3Directory;
25     IMAGE_RESOURCE_DIRECTORY_ENTRY Lang3Entries[2];
26     IMAGE_RESOURCE_DIRECTORY Lang4Directory;
27     IMAGE_RESOURCE_DIRECTORY_ENTRY Lang4Entries[2];
28     IMAGE_RESOURCE_DATA_ENTRY DataEntries[8];
29     IMAGE_RESOURCE_DIRECTORY_STRING Name1String;
30     ULONG StringIndex;
31     WCHAR StringBuffer[20];
32 } TEST_RESOURCES, *PTEST_RESOURCES;
33 
34 typedef struct _TEST_IMAGE
35 {
36     IMAGE_DOS_HEADER DosHeader;
37     IMAGE_NT_HEADERS NtHeaders;
38     IMAGE_SECTION_HEADER SectionHeaders[1];
39     TEST_RESOURCES Resources;
40 } TEST_IMAGE, *PTEST_IMAGE;
41 
42 static
43 VOID
InitializeResourceDirectory(PIMAGE_RESOURCE_DIRECTORY ResourceDirectory,USHORT NumberOfNamedEntries,USHORT NumberOfIdEntries)44 InitializeResourceDirectory(
45     PIMAGE_RESOURCE_DIRECTORY ResourceDirectory,
46     USHORT NumberOfNamedEntries,
47     USHORT NumberOfIdEntries)
48 {
49     ResourceDirectory->Characteristics = 0;
50     ResourceDirectory->TimeDateStamp = 0;
51     ResourceDirectory->MajorVersion = 0;
52     ResourceDirectory->MinorVersion = 0;
53     ResourceDirectory->NumberOfNamedEntries = NumberOfNamedEntries;
54     ResourceDirectory->NumberOfIdEntries = NumberOfIdEntries;
55 }
56 
57 static
58 VOID
InitializeNamedEntry(PTEST_RESOURCES Resource,PIMAGE_RESOURCE_DIRECTORY_ENTRY DirEntry,PWCHAR Name,PVOID Data)59 InitializeNamedEntry(
60     PTEST_RESOURCES Resource,
61     PIMAGE_RESOURCE_DIRECTORY_ENTRY DirEntry,
62     PWCHAR Name,
63     PVOID Data)
64 {
65     DirEntry->Name = Resource->StringIndex * 2 + FIELD_OFFSET(TEST_RESOURCES, StringBuffer);
66     DirEntry->NameIsString = 1;
67     DirEntry->OffsetToData = (PUCHAR)Data - (PUCHAR)Resource;
68     if (DirEntry < Resource->Lang1Entries)
69         DirEntry->DataIsDirectory = 1;
70     Resource->StringBuffer[Resource->StringIndex] = (USHORT)wcslen(Name);
71     wcscpy(&Resource->StringBuffer[Resource->StringIndex + 1], Name);
72     Resource->StringIndex += Resource->StringBuffer[Resource->StringIndex] * 2 + 1;
73 }
74 
75 static
76 VOID
InitializeIdEntry(PTEST_RESOURCES Resource,PIMAGE_RESOURCE_DIRECTORY_ENTRY DirEntry,USHORT Id,PVOID Data)77 InitializeIdEntry(
78     PTEST_RESOURCES Resource,
79     PIMAGE_RESOURCE_DIRECTORY_ENTRY DirEntry,
80     USHORT Id,
81     PVOID Data)
82 {
83     DirEntry->Name = Id;
84     DirEntry->NameIsString = 0;
85     DirEntry->OffsetToData = (PUCHAR)Data - (PUCHAR)Resource;
86     if (DirEntry < Resource->Lang1Entries)
87         DirEntry->DataIsDirectory = 1;
88 }
89 
90 static
91 VOID
InitializeDataEntry(PVOID ImageBase,PIMAGE_RESOURCE_DATA_ENTRY DataEntry,PVOID Data,ULONG Size)92 InitializeDataEntry(
93     PVOID ImageBase,
94     PIMAGE_RESOURCE_DATA_ENTRY DataEntry,
95     PVOID Data,
96     ULONG Size)
97 {
98 
99     DataEntry->OffsetToData = (PUCHAR)Data - (PUCHAR)ImageBase;
100     DataEntry->Size = Size;
101     DataEntry->CodePage = 0;
102     DataEntry->Reserved = 0;
103 }
104 
105 static
106 VOID
InitializeTestResource(PVOID ImageBase,PTEST_RESOURCES Resource)107 InitializeTestResource(
108     PVOID ImageBase,
109     PTEST_RESOURCES Resource)
110 {
111 
112     memset(Resource->StringBuffer, 0, sizeof(Resource->StringBuffer));
113     Resource->StringIndex = 0;
114 
115     InitializeResourceDirectory(&Resource->TypeDirectory, 0, 2);
116     InitializeIdEntry(Resource, &Resource->TypeEntries[0], 1, &Resource->Name1Directory);
117     InitializeIdEntry(Resource, &Resource->TypeEntries[1], 2, &Resource->Name2Directory);
118 
119     InitializeResourceDirectory(&Resource->Name1Directory, 1, 1);
120     InitializeNamedEntry(Resource, &Resource->Name1Entries[0], L"TEST", &Resource->Lang1Directory);
121     InitializeIdEntry(Resource, &Resource->Name1Entries[1], 7, &Resource->Lang2Directory);
122 
123     InitializeResourceDirectory(&Resource->Name2Directory, 2, 0);
124     InitializeNamedEntry(Resource, &Resource->Name2Entries[0], L"LOL", &Resource->Lang3Directory);
125     InitializeNamedEntry(Resource, &Resource->Name2Entries[1], L"xD", &Resource->Lang4Directory);
126 
127     InitializeResourceDirectory(&Resource->Lang1Directory, 0, 2);
128     InitializeIdEntry(Resource, &Resource->Lang1Entries[0], 0x409, &Resource->DataEntries[0]);
129     InitializeIdEntry(Resource, &Resource->Lang1Entries[1], 0x407, &Resource->DataEntries[1]);
130 
131     InitializeResourceDirectory(&Resource->Lang2Directory, 0, 2);
132     InitializeIdEntry(Resource, &Resource->Lang2Entries[0], 0x408, &Resource->DataEntries[2]);
133     InitializeIdEntry(Resource, &Resource->Lang2Entries[1], 0x406, &Resource->DataEntries[3]);
134 
135     InitializeResourceDirectory(&Resource->Lang3Directory, 0, 2);
136     InitializeIdEntry(Resource, &Resource->Lang3Entries[0], 0x405, &Resource->DataEntries[4]);
137     InitializeIdEntry(Resource, &Resource->Lang3Entries[1], 0x403, &Resource->DataEntries[5]);
138 
139     InitializeResourceDirectory(&Resource->Lang4Directory, 0, 2);
140     InitializeIdEntry(Resource, &Resource->Lang4Entries[0], 0x402, &Resource->DataEntries[6]);
141     InitializeIdEntry(Resource, &Resource->Lang4Entries[1], 0x404, &Resource->DataEntries[7]);
142 
143     InitializeDataEntry(ImageBase, &Resource->DataEntries[0], Resource->StringBuffer + 0, 2);
144     InitializeDataEntry(ImageBase, &Resource->DataEntries[1], Resource->StringBuffer + 2, 4);
145     InitializeDataEntry(ImageBase, &Resource->DataEntries[2], Resource->StringBuffer + 4, 6);
146     InitializeDataEntry(ImageBase, &Resource->DataEntries[3], Resource->StringBuffer + 6, 8);
147     InitializeDataEntry(ImageBase, &Resource->DataEntries[4], Resource->StringBuffer + 8, 10);
148     InitializeDataEntry(ImageBase, &Resource->DataEntries[5], Resource->StringBuffer + 10, 12);
149     InitializeDataEntry(ImageBase, &Resource->DataEntries[6], Resource->StringBuffer + 12, 14);
150     InitializeDataEntry(ImageBase, &Resource->DataEntries[7], Resource->StringBuffer + 14, 16);
151 
152 }
153 
154 VOID
InitializeTestImage(PTEST_IMAGE TestImage)155 InitializeTestImage(
156     PTEST_IMAGE TestImage)
157 {
158     PIMAGE_DATA_DIRECTORY ResourceDirectory;
159 
160     TestImage->DosHeader.e_magic = IMAGE_DOS_SIGNATURE;
161     TestImage->DosHeader.e_lfanew = sizeof(IMAGE_DOS_HEADER);
162 
163     TestImage->NtHeaders.Signature = IMAGE_NT_SIGNATURE;
164 
165     TestImage->NtHeaders.FileHeader.Machine = IMAGE_FILE_MACHINE_NATIVE;
166     TestImage->NtHeaders.FileHeader.NumberOfSections = 1;
167     TestImage->NtHeaders.FileHeader.TimeDateStamp = 0;
168     TestImage->NtHeaders.FileHeader.PointerToSymbolTable = 0;
169     TestImage->NtHeaders.FileHeader.NumberOfSymbols = 0;
170     TestImage->NtHeaders.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
171     TestImage->NtHeaders.FileHeader.Characteristics = 0;
172 
173 #ifdef _WIN64
174     TestImage->NtHeaders.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
175 #else
176     TestImage->NtHeaders.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
177 #endif
178     TestImage->NtHeaders.OptionalHeader.ImageBase = (DWORD_PTR)TestImage;
179     TestImage->NtHeaders.OptionalHeader.SizeOfImage = sizeof(TEST_IMAGE);
180     TestImage->NtHeaders.OptionalHeader.SizeOfHeaders = sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS);
181     TestImage->NtHeaders.OptionalHeader.NumberOfRvaAndSizes = ARRAYSIZE(TestImage->NtHeaders.OptionalHeader.DataDirectory);
182 
183     ResourceDirectory = &TestImage->NtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
184     ResourceDirectory->VirtualAddress = FIELD_OFFSET(TEST_IMAGE, Resources);
185     ResourceDirectory->Size = sizeof(TEST_RESOURCES);
186 
187     strcpy((char*)TestImage->SectionHeaders[0].Name, ".rsrc");
188     TestImage->SectionHeaders[0].Misc.VirtualSize = sizeof(TEST_IMAGE);
189     TestImage->SectionHeaders[0].VirtualAddress = FIELD_OFFSET(TEST_IMAGE, Resources);
190     TestImage->SectionHeaders[0].SizeOfRawData = sizeof(TEST_IMAGE);
191     TestImage->SectionHeaders[0].PointerToRawData = FIELD_OFFSET(TEST_IMAGE, Resources);
192     TestImage->SectionHeaders[0].PointerToRelocations = 0;
193     TestImage->SectionHeaders[0].PointerToLinenumbers = 0;
194     TestImage->SectionHeaders[0].NumberOfRelocations = 0;
195     TestImage->SectionHeaders[0].NumberOfLinenumbers = 0;
196     TestImage->SectionHeaders[0].Characteristics = 0;
197 
198     InitializeTestResource(TestImage, &TestImage->Resources);
199 }
200 
201 #define ok_nwstr(str1, str2, count) \
202     ok(wcsncmp((PWCHAR)str1, (PWCHAR)str2, count) == 0, \
203        "string is wrong, expected: '%S', got '%S'\n", str1, str2); \
204 
205 #define ok_enumres(_Res, _Type, _Name, _Lang, _Data, _Size) \
206     ok_dec((_Res)->Type, _Type); \
207     if ((ULONG_PTR)(_Name) > 0xFFFF) \
208     { \
209         ok_size_t(*(WORD*)((_Res)->Name), wcslen((PWCHAR)(_Name))); \
210         ok_nwstr((PWCHAR)((_Res)->Name + 2), (PWCHAR)_Name, *(WORD*)((_Res)->Name)); \
211     } \
212     else \
213     { \
214         ok_dec((_Res)->Name, (ULONG_PTR)_Name); \
215     } \
216     ok_hex((_Res)->Language, _Lang); \
217     ok_ptr((PVOID)(_Res)->Data, _Data); \
218     ok_dec((_Res)->Size, _Size); \
219     ok_dec((_Res)->Reserved, 0);
220 
221 static
222 void
Test_Data(PTEST_IMAGE TestImage)223 Test_Data(PTEST_IMAGE TestImage)
224 {
225     LDR_RESOURCE_INFO ResourceInfo;
226     LDR_ENUM_RESOURCE_INFO EnumRes[8];
227     ULONG ResourceCount;
228     NTSTATUS Status;
229 
230     InitializeTestImage(TestImage);
231 
232     memset(EnumRes, 0xcc, sizeof(EnumRes));
233 
234     ResourceInfo.Type = 1;
235     ResourceInfo.Name = 1;
236     ResourceInfo.Language = 0x408;
237     ResourceCount = 8;
238     Status = LdrEnumResources(TestImage, &ResourceInfo, 0, &ResourceCount, EnumRes);
239     ok_hex(Status, STATUS_SUCCESS);
240     ok_dec(ResourceCount, 8);
241 
242     ok_ptr((PVOID)EnumRes[0].Data, TestImage->Resources.StringBuffer);
243     ok_dec(EnumRes[0].Size, 2);
244 
245     ok_enumres(&EnumRes[0], 1, L"TEST", 0x409, TestImage->Resources.StringBuffer, 2)
246     ok_enumres(&EnumRes[1], 1, L"TEST", 0x407, TestImage->Resources.StringBuffer + 2, 4)
247     ok_enumres(&EnumRes[2], 1, 7, 0x408, TestImage->Resources.StringBuffer + 4, 6)
248     ok_enumres(&EnumRes[3], 1, 7, 0x406, TestImage->Resources.StringBuffer + 6, 8)
249     ok_enumres(&EnumRes[4], 2, L"LOL", 0x405, TestImage->Resources.StringBuffer + 8, 10)
250     ok_enumres(&EnumRes[5], 2, L"LOL", 0x403, TestImage->Resources.StringBuffer + 10, 12)
251     ok_enumres(&EnumRes[6], 2, L"xD", 0x402, TestImage->Resources.StringBuffer + 12, 14)
252     ok_enumres(&EnumRes[7], 2, L"xD", 0x404, TestImage->Resources.StringBuffer + 14, 16)
253 
254     Status = LdrEnumResources(TestImage, &ResourceInfo, 1, &ResourceCount, EnumRes);
255     ok_hex(Status, STATUS_SUCCESS);
256     ok_dec(ResourceCount, 4);
257 
258 }
259 
260 
261 static
262 void
Test_Parameters(PTEST_IMAGE TestImage)263 Test_Parameters(PTEST_IMAGE TestImage)
264 {
265     LDR_RESOURCE_INFO ResourceInfo;
266     LDR_ENUM_RESOURCE_INFO Resources[8];
267     ULONG ResourceCount;
268     NTSTATUS Status;
269 
270     InitializeTestImage(TestImage);
271 
272     ResourceInfo.Type = 6;
273     ResourceInfo.Name = 1;
274     ResourceInfo.Language = 0x409;
275 
276     ResourceCount = 8;
277     Status = LdrEnumResources(TestImage, &ResourceInfo, 3, &ResourceCount, Resources);
278     ok_hex(Status, STATUS_SUCCESS);
279     ok_dec(ResourceCount, 0);
280 
281     ResourceInfo.Type = 1;
282     ResourceInfo.Name = 7;
283     ResourceInfo.Language = 0x406;
284     ResourceCount = 8;
285     Status = LdrEnumResources(TestImage, &ResourceInfo, 0, &ResourceCount, Resources);
286     ok_hex(Status,  STATUS_SUCCESS);
287     ok_dec(ResourceCount, 8);
288 
289     ResourceCount = 8;
290     Status = LdrEnumResources(TestImage, &ResourceInfo, 1, &ResourceCount, Resources);
291     ok_hex(Status, STATUS_SUCCESS);
292     ok_dec(ResourceCount, 4);
293 
294     ResourceCount = 8;
295     Status = LdrEnumResources(TestImage, &ResourceInfo, 2, &ResourceCount, Resources);
296     ok_hex(Status, STATUS_SUCCESS);
297     ok_dec(ResourceCount, 2);
298 
299     ResourceCount = 8;
300     Status = LdrEnumResources(TestImage, &ResourceInfo, 3, &ResourceCount, Resources);
301     ok_hex(Status, STATUS_SUCCESS);
302     ok_dec(ResourceCount, 1);
303 
304     ResourceCount = 8;
305     Status = LdrEnumResources(TestImage, &ResourceInfo, 99, &ResourceCount, Resources);
306     ok_hex(Status, STATUS_SUCCESS);
307     ok_dec(ResourceCount, 1);
308 
309     ResourceCount = 0;
310     Status = LdrEnumResources(TestImage, &ResourceInfo, 0, &ResourceCount, Resources);
311     ok_hex(Status,  STATUS_INFO_LENGTH_MISMATCH);
312     ok_dec(ResourceCount, 8);
313 
314     ResourceCount = 7;
315     Status = LdrEnumResources(TestImage, &ResourceInfo, 0, &ResourceCount, Resources);
316     ok_hex(Status,  STATUS_INFO_LENGTH_MISMATCH);
317     ok_dec(ResourceCount, 8);
318 
319     ResourceCount = 8;
320     Status = LdrEnumResources(NULL, &ResourceInfo, 1, &ResourceCount, Resources);
321     ok_hex(Status, STATUS_RESOURCE_DATA_NOT_FOUND);
322     ok_dec(ResourceCount, 0);
323 
324     ResourceCount = 8;
325     Status = LdrEnumResources(TestImage, &ResourceInfo, 1, &ResourceCount, NULL);
326     ok_hex(Status, STATUS_INFO_LENGTH_MISMATCH);
327     ok_dec(ResourceCount, 4);
328 
329     ResourceCount = 8;
330     _SEH2_TRY
331     {
332         Status = LdrEnumResources(NULL, NULL, 0, NULL, NULL);
333     }
334     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
335     {
336         Status = 0xDeadC0de;
337     }
338     _SEH2_END
339     ok_hex(Status, 0xDeadC0de);
340 
341     ResourceCount = 42;
342     _SEH2_TRY
343     {
344         Status = LdrEnumResources(TestImage, &ResourceInfo, 1, NULL, Resources);
345     }
346     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
347     {
348         Status = 0xDeadC0de;
349     }
350     _SEH2_END
351     ok_hex(Status, 0xDeadC0de);
352     ok_dec(ResourceCount, 42);
353 
354     ResourceCount = 8;
355     Status = LdrEnumResources(TestImage + 2, &ResourceInfo, 1, &ResourceCount, NULL);
356     ok_hex(Status,  STATUS_RESOURCE_DATA_NOT_FOUND);
357     ok_dec(ResourceCount, 0);
358 
359     TestImage->Resources.TypeEntries[0].DataIsDirectory = 0;
360     Status = LdrEnumResources(TestImage, &ResourceInfo, 1, &ResourceCount, NULL);
361     ok_hex(Status,  STATUS_INVALID_IMAGE_FORMAT);
362     ok_dec(ResourceCount, 0);
363 
364 }
365 
START_TEST(LdrEnumResources)366 START_TEST(LdrEnumResources)
367 {
368     TEST_IMAGE TestImage;
369     RtlZeroMemory(&TestImage, sizeof(TestImage));
370 
371     Test_Parameters(&TestImage);
372     Test_Data(&TestImage);
373 
374 }
375