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