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