1 : // Copyright 2012 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/pe/pe_file_parser.h"
16 :
17 : #include <memory>
18 :
19 : #include "base/bind.h"
20 : #include "base/native_library.h"
21 : #include "base/path_service.h"
22 : #include "base/files/file_path.h"
23 : #include "base/strings/string_util.h"
24 : #include "base/win/pe_image.h"
25 : #include "gmock/gmock.h"
26 : #include "gtest/gtest.h"
27 : #include "syzygy/core/unittest_util.h"
28 : #include "syzygy/pe/pe_structs.h"
29 : #include "syzygy/pe/unittest_util.h"
30 :
31 : namespace pe {
32 :
33 : using block_graph::BlockGraph;
34 : using core::RelativeAddress;
35 : using testing::ContainerEq;
36 : using testing::Contains;
37 :
38 : namespace {
39 :
40 : // Path to a sample DLL containing an ILTCG debug info data directory.
41 : const wchar_t kTestDllILTCG[] = L"syzygy\\pe\\test_data\\test_dll_iltcg.dll";
42 :
43 : // Exposes the protected methods for testing.
44 : class TestPEFileParser: public PEFileParser {
45 : public:
46 E : TestPEFileParser(const PEFile& image_file,
47 : BlockGraph::AddressSpace* address_space,
48 : AddReferenceCallback add_reference)
49 E : : PEFileParser(image_file, address_space, add_reference) {
50 E : }
51 :
52 : // Expose as public for testing.
53 : using PEFileParser::ParseDelayImportDir;
54 : using PEFileParser::ParseDebugDir;
55 : using PEFileParser::ParseExportDir;
56 : using PEFileParser::ParseImageHeader;
57 : using PEFileParser::ParseImportDir;
58 : using PEFileParser::ParseLoadConfigDir;
59 : };
60 :
61 : class PEFileParserTest: public testing::PELibUnitTest {
62 : typedef testing::PELibUnitTest Super;
63 :
64 : public:
65 E : PEFileParserTest() : address_space_(&image_), loaded_image_(NULL) {
66 E : }
67 :
68 E : virtual void SetUp() {
69 E : Super::SetUp();
70 :
71 E : add_reference_ = base::Bind(&PEFileParserTest::AddReference,
72 : base::Unretained(this));
73 E : on_import_thunk_ = base::Bind(&PEFileParserTest::OnImportThunk,
74 : base::Unretained(this));
75 :
76 E : ASSERT_TRUE(image_file_.Init(testing::GetExeRelativePath(
77 : testing::kTestDllName)));
78 E : }
79 :
80 E : virtual void TearDown() {
81 E : if (loaded_image_ != NULL)
82 E : base::UnloadNativeLibrary(loaded_image_);
83 E : loaded_image_ = NULL;
84 :
85 E : Super::TearDown();
86 E : }
87 :
88 : bool AddReference(RelativeAddress src,
89 : BlockGraph::ReferenceType type,
90 : BlockGraph::Size size,
91 E : RelativeAddress dst) {
92 E : Reference ref = { type, size, dst };
93 E : bool inserted = references_.insert(std::make_pair(src, ref)).second;
94 E : EXPECT_TRUE(inserted);
95 E : return inserted;
96 E : }
97 :
98 : bool OnImportThunk(const char* module_name,
99 : const char* symbol_name,
100 E : BlockGraph::Block* thunk) {
101 E : EXPECT_TRUE(module_name != NULL);
102 E : EXPECT_TRUE(symbol_name != NULL);
103 E : EXPECT_TRUE(thunk != NULL);
104 E : import_map_[module_name]++;
105 E : EXPECT_TRUE(import_set_.insert(
106 : std::make_pair(std::string(module_name),
107 : std::string(symbol_name))).second);
108 E : return true;
109 E : }
110 :
111 : // Assert that an exported function in the test_dll is referenced
112 : // in the image.
113 E : bool ExportIsReferenced(const char* function_name_or_ordinal) {
114 E : if (loaded_image_ == NULL) {
115 i : base::NativeLibraryLoadError error;
116 i : loaded_image_ = base::LoadNativeLibrary(
117 : testing::GetExeRelativePath(testing::kTestDllName), &error);
118 : }
119 :
120 E : EXPECT_TRUE(loaded_image_ != NULL);
121 E : if (loaded_image_ == NULL)
122 i : return false;
123 :
124 E : void* function = base::GetFunctionPointerFromNativeLibrary(
125 : loaded_image_, function_name_or_ordinal);
126 :
127 E : RelativeAddress addr(reinterpret_cast<const char*>(function) -
128 : reinterpret_cast<const char*>(loaded_image_));
129 :
130 E : ReferenceMap::const_iterator it(references_.begin());
131 E : for (; it != references_.end(); ++it) {
132 E : if (it->second.dst == addr)
133 E : return true;
134 E : }
135 :
136 i : return false;
137 E : }
138 :
139 E : void AssertDataDirectoryEntryValid(BlockGraph::Block* block) {
140 E : ASSERT_TRUE(block != NULL);
141 E : ASSERT_NE(0u, block->size());
142 E : ASSERT_EQ(block->size(), block->data_size());
143 E : ASSERT_TRUE(block->data() != NULL);
144 E : }
145 :
146 : // Locate block pointed to by the reference at @p offset into @p block.
147 : // @returns the block in question, or NULL if no such block.
148 : BlockGraph::Block* FindReferencedBlock(BlockGraph::Block* block,
149 E : BlockGraph::Offset offset) {
150 E : ReferenceMap::const_iterator it(references_.find(block->addr() + offset));
151 E : if (it == references_.end())
152 i : return NULL;
153 :
154 E : return address_space_.GetBlockByAddress(it->second.dst);
155 E : }
156 :
157 : protected:
158 : struct Reference {
159 : BlockGraph::ReferenceType type;
160 : BlockGraph::Size size;
161 : RelativeAddress dst;
162 : };
163 :
164 : typedef std::map<RelativeAddress, Reference> ReferenceMap;
165 : ReferenceMap references_;
166 :
167 : // This is used to count the number of imported symbols per imported module,
168 : // and is populated by the OnImportThunk callback.
169 : typedef std::map<std::string, size_t> ImportMap;
170 : typedef std::set<std::pair<std::string, std::string>> ImportSet;
171 : ImportMap import_map_;
172 : ImportSet import_set_;
173 :
174 : PEFileParser::AddReferenceCallback add_reference_;
175 : PEFileParser::OnImportThunkCallback on_import_thunk_;
176 : PEFile image_file_;
177 : BlockGraph image_;
178 : BlockGraph::AddressSpace address_space_;
179 :
180 : base::NativeLibrary loaded_image_;
181 : };
182 :
183 : } // namespace
184 :
185 E : TEST_F(PEFileParserTest, ParseImageHeader) {
186 E : TestPEFileParser parser(image_file_, &address_space_, add_reference_);
187 :
188 E : PEFileParser::PEHeader header;
189 E : EXPECT_TRUE(parser.ParseImageHeader(&header));
190 :
191 : // Check that the DOS header was read successfully.
192 E : ASSERT_TRUE(header.dos_header != NULL);
193 E : ASSERT_GE(header.dos_header->size(), sizeof(IMAGE_DOS_HEADER));
194 E : ASSERT_EQ(BlockGraph::DATA_BLOCK, header.dos_header->type());
195 : // Check the underlying data.
196 E : ASSERT_GE(header.dos_header->data_size(), sizeof(IMAGE_DOS_HEADER));
197 : const IMAGE_DOS_HEADER* dos_header =
198 E : reinterpret_cast<const IMAGE_DOS_HEADER*>(header.dos_header->data());
199 E : ASSERT_TRUE(dos_header != NULL);
200 E : ASSERT_EQ(IMAGE_DOS_SIGNATURE, dos_header->e_magic);
201 :
202 : // Check that the DOS header references the NT headers.
203 E : ASSERT_EQ(header.nt_headers,
204 : FindReferencedBlock(header.dos_header,
205 E : offsetof(IMAGE_DOS_HEADER, e_lfanew)));
206 :
207 : // Check the NT headers.
208 E : ASSERT_TRUE(header.nt_headers != NULL);
209 E : ASSERT_GT(header.nt_headers->size(), sizeof(IMAGE_NT_HEADERS));
210 E : ASSERT_EQ(header.nt_headers->data_size(), header.nt_headers->size());
211 E : ASSERT_EQ(BlockGraph::DATA_BLOCK, header.nt_headers->type());
212 : const IMAGE_NT_HEADERS* nt_headers =
213 E : reinterpret_cast<const IMAGE_NT_HEADERS*>(header.nt_headers->data());
214 E : ASSERT_TRUE(nt_headers != NULL);
215 E : ASSERT_EQ(IMAGE_NT_OPTIONAL_HDR32_MAGIC, nt_headers->OptionalHeader.Magic);
216 :
217 : // Check that the data accounts for the image section headers.
218 E : ASSERT_EQ(
219 : nt_headers->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
220 : sizeof(*nt_headers),
221 E : header.nt_headers->data_size());
222 E : }
223 :
224 E : TEST_F(PEFileParserTest, ParseExportDir) {
225 E : TestPEFileParser parser(image_file_, &address_space_, add_reference_);
226 :
227 E : PEFileParser::PEHeader header;
228 E : EXPECT_TRUE(parser.ParseImageHeader(&header));
229 :
230 : const IMAGE_NT_HEADERS* nt_headers =
231 E : reinterpret_cast<const IMAGE_NT_HEADERS*>(header.nt_headers->data());
232 :
233 E : const IMAGE_DATA_DIRECTORY& dir =
234 : nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
235 E : EXPECT_TRUE(parser.ParseExportDir(dir) != NULL);
236 :
237 E : base::NativeLibraryLoadError error;
238 E : loaded_image_ = base::LoadNativeLibrary(
239 : testing::GetExeRelativePath(testing::kTestDllName), &error);
240 E : ASSERT_TRUE(loaded_image_ != NULL);
241 :
242 E : ASSERT_TRUE(ExportIsReferenced("function1"));
243 : // function2 is exported by ordinal only.
244 E : ASSERT_TRUE(ExportIsReferenced(reinterpret_cast<const char*>(7)));
245 E : ASSERT_TRUE(ExportIsReferenced("function3"));
246 E : }
247 :
248 E : TEST_F(PEFileParserTest, ParseEmptyExportDir) {
249 E : base::FilePath no_exports_dll_path = testing::GetOutputRelativePath(
250 : testing::kNoExportsDllName);
251 E : pe::PEFile no_exports_dll_image;
252 E : ASSERT_TRUE(no_exports_dll_image.Init(no_exports_dll_path));
253 E : TestPEFileParser parser(no_exports_dll_image,
254 : &address_space_, add_reference_);
255 :
256 E : PEFileParser::PEHeader header;
257 E : EXPECT_TRUE(parser.ParseImageHeader(&header));
258 :
259 : const IMAGE_NT_HEADERS* nt_headers =
260 E : reinterpret_cast<const IMAGE_NT_HEADERS*>(header.nt_headers->data());
261 :
262 E : const IMAGE_DATA_DIRECTORY& dir =
263 : nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
264 E : EXPECT_TRUE(parser.ParseExportDir(dir) != NULL);
265 E : }
266 :
267 E : TEST_F(PEFileParserTest, ParseImportDir) {
268 E : TestPEFileParser parser(image_file_, &address_space_, add_reference_);
269 E : parser.set_on_import_thunk(on_import_thunk_);
270 :
271 E : PEFileParser::PEHeader header;
272 E : EXPECT_TRUE(parser.ParseImageHeader(&header));
273 :
274 : const IMAGE_NT_HEADERS* nt_headers =
275 E : reinterpret_cast<const IMAGE_NT_HEADERS*>(header.nt_headers->data());
276 :
277 E : const IMAGE_DATA_DIRECTORY& dir =
278 : nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
279 E : BlockGraph::Block* block = parser.ParseImportDir(dir);
280 E : ASSERT_TRUE(block != NULL);
281 :
282 : // Test that we have the two import descriptors we expect, plus the sentinel.
283 E : size_t num_descriptors = block->size() / sizeof(IMAGE_IMPORT_DESCRIPTOR);
284 E : ASSERT_EQ(4, num_descriptors);
285 E : ASSERT_TRUE(block->data() != NULL);
286 E : ASSERT_EQ(block->size(), block->data_size());
287 :
288 E : std::set<std::string> import_names;
289 E : for (size_t i = 0; i < num_descriptors - 1; ++i) {
290 E : size_t element_offset = sizeof(IMAGE_IMPORT_DESCRIPTOR) * i;
291 : BlockGraph::Block* name_block =
292 E : FindReferencedBlock(block, element_offset +
293 : offsetof(IMAGE_IMPORT_DESCRIPTOR, Name));
294 E : ASSERT_TRUE(name_block != NULL);
295 :
296 : const char* name =
297 E : reinterpret_cast<const char*>(name_block->data());
298 E : EXPECT_TRUE(import_names.insert(name).second);
299 :
300 : // Now retrieve the IAT and INT blocks.
301 : BlockGraph::Block* iat_block =
302 E : FindReferencedBlock(block, element_offset +
303 : offsetof(IMAGE_IMPORT_DESCRIPTOR, FirstThunk));
304 : BlockGraph::Block* int_block =
305 E : FindReferencedBlock(block, element_offset +
306 : offsetof(IMAGE_IMPORT_DESCRIPTOR, OriginalFirstThunk));
307 :
308 E : ASSERT_TRUE(iat_block != NULL);
309 E : ASSERT_TRUE(int_block != NULL);
310 E : ASSERT_EQ(iat_block->size(), int_block->size());
311 E : ASSERT_EQ(iat_block->data_size(), int_block->data_size());
312 E : ASSERT_EQ(0,
313 E : memcmp(iat_block->data(), int_block->data(), iat_block->data_size()));
314 :
315 : // Now check that each slot, save for the last one, in the IAT/INT
316 : // points to a name block or else is an ordinal.
317 E : size_t num_thunks = iat_block->data_size() / sizeof(IMAGE_THUNK_DATA) - 1;
318 : const IMAGE_THUNK_DATA* iat =
319 E : reinterpret_cast<const IMAGE_THUNK_DATA*>(iat_block->data());
320 E : for (size_t i = 0; i < num_thunks; ++i) {
321 E : if (!IMAGE_ORDINAL(iat[i].u1.Ordinal)) {
322 i : size_t thunk_offset = sizeof(IMAGE_THUNK_DATA) * i;
323 i : ASSERT_TRUE(FindReferencedBlock(iat_block, thunk_offset) != NULL);
324 i : ASSERT_TRUE(FindReferencedBlock(int_block, thunk_offset) != NULL);
325 : }
326 E : }
327 E : }
328 :
329 : // Check that the sentinel is all zero.
330 E : IMAGE_IMPORT_DESCRIPTOR zero = {};
331 : const IMAGE_IMPORT_DESCRIPTOR* sentinel =
332 : reinterpret_cast<const IMAGE_IMPORT_DESCRIPTOR*>(block->data()) +
333 E : num_descriptors - 1;
334 E : EXPECT_EQ(0, memcmp(sentinel, &zero, sizeof(zero)));
335 :
336 E : std::set<std::string> expected;
337 E : expected.insert("ADVAPI32.dll");
338 E : expected.insert("KERNEL32.dll");
339 E : expected.insert("export_dll.dll");
340 E : EXPECT_THAT(import_names, ContainerEq(expected));
341 :
342 : // The number of expected symbols imported from kernel32.dll.
343 : static size_t kNumAdvApiSymbols = 1;
344 : static size_t kNumKernel32Symbols = 70;
345 : // The number of expected symbols imported from export_dll.dll.
346 : static const size_t kNumExportDllSymbols = 3;
347 :
348 E : ImportMap expected_import_map;
349 E : expected_import_map["ADVAPI32.dll"] = kNumAdvApiSymbols;
350 E : expected_import_map["KERNEL32.dll"] = kNumKernel32Symbols;
351 E : expected_import_map["export_dll.dll"] = kNumExportDllSymbols;
352 E : EXPECT_THAT(import_map_, ContainerEq(expected_import_map));
353 E : EXPECT_EQ(kNumKernel32Symbols + kNumExportDllSymbols + kNumAdvApiSymbols,
354 E : import_set_.size());
355 :
356 : std::pair<std::string, std::string> exit_process_entry =
357 E : std::make_pair(std::string("KERNEL32.dll"), std::string("ExitProcess"));
358 E : EXPECT_THAT(import_set_, Contains(exit_process_entry));
359 : std::pair<std::string, std::string> function1_entry =
360 E : std::make_pair(std::string("export_dll.dll"), std::string("function1"));
361 E : EXPECT_THAT(import_set_, Contains(function1_entry));
362 E : }
363 :
364 E : TEST_F(PEFileParserTest, ParseDelayImportDir) {
365 E : TestPEFileParser parser(image_file_, &address_space_, add_reference_);
366 :
367 E : PEFileParser::PEHeader header;
368 E : EXPECT_TRUE(parser.ParseImageHeader(&header));
369 :
370 : const IMAGE_NT_HEADERS* nt_headers =
371 E : reinterpret_cast<const IMAGE_NT_HEADERS*>(header.nt_headers->data());
372 :
373 E : const IMAGE_DATA_DIRECTORY& dir =
374 : nt_headers->OptionalHeader.DataDirectory[
375 : IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT];
376 E : BlockGraph::Block* block = parser.ParseDelayImportDir(dir);
377 E : ASSERT_TRUE(block != NULL);
378 :
379 : // Test that we have the import descriptors we expect - we expect
380 : // the one delay import, plus the sentinel import descriptor to be
381 : // chunked out.
382 E : size_t num_descriptors = block->size() / sizeof(ImgDelayDescr);
383 E : ASSERT_EQ(2, num_descriptors);
384 E : ASSERT_TRUE(block->data() != NULL);
385 E : ASSERT_EQ(block->size(), block->data_size());
386 :
387 E : std::set<std::string> import_names;
388 E : for (size_t i = 0; i < num_descriptors - 1; ++i) {
389 E : size_t element_offset = sizeof(ImgDelayDescr) * i;
390 : BlockGraph::Block* name_block =
391 E : FindReferencedBlock(block, element_offset +
392 : offsetof(ImgDelayDescr, rvaDLLName));
393 E : ASSERT_TRUE(name_block != NULL);
394 :
395 : const char* name =
396 E : reinterpret_cast<const char*>(name_block->data());
397 E : EXPECT_TRUE(import_names.insert(name).second);
398 :
399 : // Now retrieve the IAT, INT and BoundIAT blocks.
400 : BlockGraph::Block* iat_block =
401 E : FindReferencedBlock(block, element_offset +
402 : offsetof(ImgDelayDescr, rvaIAT));
403 : BlockGraph::Block* int_block =
404 E : FindReferencedBlock(block, element_offset +
405 : offsetof(ImgDelayDescr, rvaINT));
406 : BlockGraph::Block* bound_iat_block =
407 E : FindReferencedBlock(block, element_offset +
408 : offsetof(ImgDelayDescr, rvaBoundIAT));
409 :
410 E : ASSERT_TRUE(iat_block != NULL);
411 E : ASSERT_TRUE(int_block != NULL);
412 E : ASSERT_TRUE(bound_iat_block != NULL);
413 :
414 E : ASSERT_EQ(iat_block->size(), int_block->size());
415 E : ASSERT_EQ(iat_block->size(), bound_iat_block->size());
416 E : ASSERT_EQ(iat_block->data_size(), int_block->data_size());
417 E : ASSERT_EQ(iat_block->data_size(), bound_iat_block->data_size());
418 :
419 : // Now check that each slot, save for the last one, in the INT
420 : // points to a name block or else is an ordinal.
421 E : size_t num_thunks = iat_block->data_size() / sizeof(IMAGE_THUNK_DATA) - 1;
422 : const IMAGE_THUNK_DATA* iat =
423 E : reinterpret_cast<const IMAGE_THUNK_DATA*>(int_block->data());
424 E : for (size_t i = 0; i < num_thunks; ++i) {
425 E : if (!IMAGE_ORDINAL(iat[i].u1.Ordinal)) {
426 i : size_t thunk_offset = sizeof(IMAGE_THUNK_DATA) * i;
427 i : ASSERT_TRUE(FindReferencedBlock(int_block, thunk_offset) != NULL);
428 : }
429 E : }
430 E : }
431 :
432 : // Check that the sentinel is all zero.
433 E : ImgDelayDescr zero = {};
434 : const ImgDelayDescr* sentinel =
435 : reinterpret_cast<const ImgDelayDescr*>(block->data()) +
436 E : num_descriptors - 1;
437 E : EXPECT_EQ(0, memcmp(sentinel, &zero, sizeof(zero)));
438 :
439 E : std::set<std::string> expected;
440 E : expected.insert("ole32.dll");
441 E : EXPECT_THAT(import_names, ContainerEq(expected));
442 E : }
443 :
444 E : TEST_F(PEFileParserTest, ParseImage) {
445 E : TestPEFileParser parser(image_file_, &address_space_, add_reference_);
446 :
447 E : PEFileParser::PEHeader header;
448 E : EXPECT_TRUE(parser.ParseImage(&header));
449 :
450 : // Check that the DOS header was read successfully.
451 E : ASSERT_TRUE(header.dos_header != NULL);
452 E : ASSERT_GE(header.dos_header->size(), sizeof(IMAGE_DOS_HEADER));
453 E : ASSERT_EQ(BlockGraph::DATA_BLOCK, header.dos_header->type());
454 : // Check the underlying data.
455 E : ASSERT_GE(header.dos_header->data_size(), sizeof(IMAGE_DOS_HEADER));
456 : const IMAGE_DOS_HEADER* dos_header =
457 E : reinterpret_cast<const IMAGE_DOS_HEADER*>(header.dos_header->data());
458 E : ASSERT_TRUE(dos_header != NULL);
459 E : ASSERT_EQ(IMAGE_DOS_SIGNATURE, dos_header->e_magic);
460 :
461 : // Check the NT headers.
462 E : ASSERT_TRUE(header.nt_headers != NULL);
463 E : ASSERT_GT(header.nt_headers->size(), sizeof(IMAGE_NT_HEADERS));
464 E : ASSERT_EQ(header.nt_headers->data_size(), header.nt_headers->size());
465 E : ASSERT_EQ(BlockGraph::DATA_BLOCK, header.nt_headers->type());
466 : const IMAGE_NT_HEADERS* nt_headers =
467 E : reinterpret_cast<const IMAGE_NT_HEADERS*>(header.nt_headers->data());
468 E : ASSERT_TRUE(nt_headers != NULL);
469 E : ASSERT_EQ(IMAGE_NT_OPTIONAL_HDR32_MAGIC, nt_headers->OptionalHeader.Magic);
470 :
471 E : const IMAGE_SECTION_HEADER* section_headers = NULL;
472 : // Check that the data accounts for the image section headers.
473 E : ASSERT_EQ(nt_headers->FileHeader.NumberOfSections * sizeof(*section_headers) +
474 E : sizeof(*nt_headers), header.nt_headers->data_size());
475 :
476 E : section_headers =
477 : reinterpret_cast<const IMAGE_SECTION_HEADER*>(nt_headers + 1);
478 :
479 : // Now check the various data directory sections we expect to be non NULL.
480 : // We know the test dll has exports.
481 E : EXPECT_NO_FATAL_FAILURE(AssertDataDirectoryEntryValid(
482 E : header.data_directory[IMAGE_DIRECTORY_ENTRY_EXPORT]));
483 : // And imports.
484 E : EXPECT_NO_FATAL_FAILURE(AssertDataDirectoryEntryValid(
485 E : header.data_directory[IMAGE_DIRECTORY_ENTRY_IMPORT]));
486 : // And resources.
487 E : EXPECT_NO_FATAL_FAILURE(AssertDataDirectoryEntryValid(
488 E : header.data_directory[IMAGE_DIRECTORY_ENTRY_RESOURCE]));
489 : // And relocs.
490 E : EXPECT_NO_FATAL_FAILURE(AssertDataDirectoryEntryValid(
491 E : header.data_directory[IMAGE_DIRECTORY_ENTRY_BASERELOC]));
492 : // And a debug directory.
493 E : EXPECT_NO_FATAL_FAILURE(AssertDataDirectoryEntryValid(
494 E : header.data_directory[IMAGE_DIRECTORY_ENTRY_DEBUG]));
495 : // And a tls directory?
496 : // TODO(siggi): add some TLS data to the test DLL.
497 : // EXPECT_NO_FATAL_FAILURE(AssertDataDirectoryEntryValid(
498 : // header.data_directory[IMAGE_DIRECTORY_ENTRY_TLS]));
499 : // And a load configuration directory.
500 E : EXPECT_NO_FATAL_FAILURE(AssertDataDirectoryEntryValid(
501 E : header.data_directory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG]));
502 : // And a delay import directory.
503 E : EXPECT_NO_FATAL_FAILURE(AssertDataDirectoryEntryValid(
504 E : header.data_directory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT]));
505 E : }
506 :
507 E : TEST_F(PEFileParserTest, ParseEmptyDebugDir) {
508 E : base::FilePath dll_path = testing::GetSrcRelativePath(kTestDllILTCG);
509 E : pe::PEFile image_file;
510 E : pe::BlockGraph image;
511 E : BlockGraph::AddressSpace address_space(&image);
512 E : ASSERT_TRUE(image_file.Init(dll_path));
513 E : TestPEFileParser parser(image_file, &address_space, add_reference_);
514 :
515 E : PEFileParser::PEHeader header;
516 E : EXPECT_TRUE(parser.ParseImageHeader(&header));
517 E : ASSERT_EQ(2u, image.blocks().size()); // DOS + NT headers.
518 :
519 : const IMAGE_NT_HEADERS* nt_headers =
520 E : reinterpret_cast<const IMAGE_NT_HEADERS*>(header.nt_headers->data());
521 :
522 E : const IMAGE_DATA_DIRECTORY& dir =
523 : nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
524 E : ASSERT_EQ(sizeof(IMAGE_DEBUG_DIRECTORY) * 3, dir.Size);
525 E : EXPECT_TRUE(parser.ParseDebugDir(dir) != NULL);
526 :
527 : // This should create 3 new blocks: the debug directory itself, a codeview
528 : // entry and a coff group entry. There should not be a third block created
529 : // for the ILTCG entry, despite their being 3 debug directory entries.
530 E : EXPECT_EQ(5u, image.blocks().size());
531 E : }
532 :
533 E : TEST_F(PEFileParserTest, ParseImageHeadersFromDifferentWindowsSDKs) {
534 : struct TestData {
535 : const wchar_t* filename;
536 : size_t expected_load_config_dir_size;
537 : size_t expected_number_of_references;
538 : };
539 :
540 : TestData test_data[] = {
541 E : { L"syzygy\\pe\\test_data\\test_dll_winsdk80.dll",
542 E : pe::kLoadConfigDirectorySize80,
543 E : 5
544 : },
545 E : { L"syzygy\\pe\\test_data\\test_dll_winsdk81.dll",
546 E : pe::kLoadConfigDirectorySize81,
547 E : 7
548 : },
549 : };
550 E : for (size_t i = 0; i < arraysize(test_data); ++i) {
551 E : base::FilePath dll_path = testing::GetSrcRelativePath(
552 : test_data[i].filename);
553 E : pe::PEFile image_file;
554 E : pe::BlockGraph image;
555 E : BlockGraph::AddressSpace address_space(&image);
556 :
557 E : ASSERT_TRUE(image_file.Init(dll_path));
558 E : TestPEFileParser parser(image_file, &address_space, add_reference_);
559 :
560 E : PEFileParser::PEHeader header;
561 E : EXPECT_TRUE(parser.ParseImageHeader(&header));
562 :
563 : const IMAGE_NT_HEADERS* nt_headers =
564 E : reinterpret_cast<const IMAGE_NT_HEADERS*>(header.nt_headers->data());
565 E : ASSERT_NE(static_cast<const IMAGE_NT_HEADERS*>(nullptr), nt_headers);
566 :
567 E : const IMAGE_DATA_DIRECTORY& dir = nt_headers->OptionalHeader.DataDirectory[
568 : IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG];
569 :
570 E : references_.clear();
571 E : BlockGraph::Block* data_dir_block = parser.ParseLoadConfigDir(dir);
572 E : EXPECT_NE(static_cast<BlockGraph::Block*>(nullptr), data_dir_block);
573 E : EXPECT_EQ(test_data[i].expected_load_config_dir_size,
574 E : data_dir_block->size());
575 E : EXPECT_EQ(test_data[i].expected_number_of_references,
576 E : references_.size());
577 :
578 E : references_.clear();
579 E : }
580 E : }
581 :
582 E : TEST_F(PEFileParserTest, ParseSignedImage) {
583 E : base::FilePath signed_test_dll = testing::GetExeTestDataRelativePath(
584 : testing::kSignedTestDllName);
585 E : pe::PEFile image_file;
586 E : ASSERT_TRUE(image_file.Init(signed_test_dll));
587 :
588 : // Expect the security directory to be non-empty in the source file.
589 : auto data_dir = image_file.nt_headers()->OptionalHeader.DataDirectory[
590 E : IMAGE_DIRECTORY_ENTRY_SECURITY];
591 E : EXPECT_NE(0u, data_dir.Size);
592 E : EXPECT_NE(0u, data_dir.VirtualAddress);
593 :
594 E : TestPEFileParser parser(image_file, &address_space_, add_reference_);
595 E : PEFileParser::PEHeader header;
596 E : EXPECT_TRUE(parser.ParseImage(&header));
597 :
598 : // Expect it to be empty in the parsed file.
599 : const IMAGE_NT_HEADERS* nt_headers =
600 E : reinterpret_cast<const IMAGE_NT_HEADERS*>(header.nt_headers->data());
601 E : EXPECT_FALSE(header.data_directory[IMAGE_DIRECTORY_ENTRY_SECURITY]);
602 E : data_dir = nt_headers->OptionalHeader.DataDirectory[
603 : IMAGE_DIRECTORY_ENTRY_SECURITY];
604 E : EXPECT_EQ(0u, data_dir.Size);
605 E : EXPECT_EQ(0u, data_dir.VirtualAddress);
606 E : }
607 :
608 : } // namespace pe
|