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.h"
16 : #include "base/native_library.h"
17 : #include "base/path_service.h"
18 : #include "base/string_util.h"
19 : #include "base/files/file_path.h"
20 : #include "gmock/gmock.h"
21 : #include "gtest/gtest.h"
22 : #include "syzygy/core/unittest_util.h"
23 : #include "syzygy/pe/unittest_util.h"
24 :
25 : namespace pe {
26 :
27 : namespace {
28 :
29 : using core::AbsoluteAddress;
30 : using core::FileOffsetAddress;
31 : using core::RelativeAddress;
32 :
33 : class PEFileTest: public testing::PELibUnitTest {
34 : typedef testing::PELibUnitTest Super;
35 :
36 : public:
37 E : PEFileTest() : test_dll_(NULL) {
38 E : }
39 :
40 E : virtual void SetUp() OVERRIDE {
41 E : Super::SetUp();
42 :
43 : base::FilePath test_dll =
44 E : testing::GetExeRelativePath(testing::kTestDllName);
45 E : std::string error;
46 E : test_dll_ = base::LoadNativeLibrary(test_dll, &error);
47 :
48 E : ASSERT_TRUE(image_file_.Init(test_dll));
49 E : }
50 :
51 E : virtual void TearDown() OVERRIDE {
52 E : base::UnloadNativeLibrary(test_dll_);
53 E : Super::TearDown();
54 E : }
55 :
56 : void TestAddressesAreConsistent(RelativeAddress rel,
57 : AbsoluteAddress abs,
58 E : FileOffsetAddress off) {
59 E : AbsoluteAddress abs2;
60 E : RelativeAddress rel2;
61 E : FileOffsetAddress off2;
62 :
63 E : ASSERT_TRUE(image_file_.Translate(rel, &abs2));
64 E : ASSERT_EQ(abs, abs2);
65 :
66 E : ASSERT_TRUE(image_file_.Translate(abs, &rel2));
67 E : ASSERT_EQ(rel, rel2);
68 :
69 E : ASSERT_TRUE(image_file_.Translate(off, &rel2));
70 E : ASSERT_EQ(rel, rel2);
71 :
72 E : ASSERT_TRUE(image_file_.Translate(rel, &off2));
73 E : ASSERT_EQ(off, off2);
74 E : }
75 :
76 : protected:
77 : pe::PEFile image_file_;
78 : base::NativeLibrary test_dll_;
79 : };
80 :
81 : // Functor for comparing import infos.
82 : struct CompareImportInfo {
83 : bool operator()(const PEFile::ImportInfo& ii1,
84 E : const PEFile::ImportInfo& ii2) {
85 E : if (ii1.hint < ii2.hint)
86 E : return true;
87 E : if (ii1.hint > ii2.hint)
88 E : return false;
89 E : if (ii1.ordinal < ii2.ordinal)
90 i : return true;
91 E : if (ii1.ordinal > ii2.ordinal)
92 E : return false;
93 i : return ii1.function < ii2.function;
94 E : }
95 : };
96 :
97 : } // namespace
98 :
99 E : TEST_F(PEFileTest, Create) {
100 E : PEFile image_file;
101 :
102 E : ASSERT_EQ(NULL, image_file.dos_header());
103 E : ASSERT_EQ(NULL, image_file.nt_headers());
104 E : ASSERT_EQ(NULL, image_file.section_headers());
105 E : }
106 :
107 E : TEST_F(PEFileTest, Init) {
108 E : EXPECT_TRUE(image_file_.dos_header() != NULL);
109 E : EXPECT_TRUE(image_file_.nt_headers() != NULL);
110 E : EXPECT_TRUE(image_file_.section_headers() != NULL);
111 E : }
112 :
113 E : TEST_F(PEFileTest, GetImageData) {
114 E : const IMAGE_NT_HEADERS* nt_headers = image_file_.nt_headers();
115 E : ASSERT_TRUE(nt_headers != NULL);
116 : const IMAGE_DATA_DIRECTORY* exports =
117 E : &nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
118 :
119 : // We should be able to read the export directory.
120 : ASSERT_TRUE(image_file_.GetImageData(RelativeAddress(exports->VirtualAddress),
121 E : exports->Size) != NULL);
122 :
123 : // We should be able to read it using an absolute address as well.
124 E : AbsoluteAddress abs_addr;
125 : ASSERT_TRUE(image_file_.Translate(RelativeAddress(exports->VirtualAddress),
126 E : &abs_addr));
127 E : ASSERT_TRUE(image_file_.GetImageData(abs_addr, exports->Size) != NULL);
128 :
129 : // But there ought to be a gap in the image data past the header size.
130 : ASSERT_TRUE(image_file_.GetImageData(
131 E : RelativeAddress(nt_headers->OptionalHeader.SizeOfHeaders), 1) == NULL);
132 E : }
133 :
134 E : TEST_F(PEFileTest, ReadImage) {
135 E : const IMAGE_NT_HEADERS* nt_headers = image_file_.nt_headers();
136 E : ASSERT_TRUE(nt_headers != NULL);
137 : const IMAGE_DATA_DIRECTORY* exports =
138 E : &nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
139 :
140 : // We should be able to read the export directory.
141 E : IMAGE_EXPORT_DIRECTORY export_dir = {};
142 : ASSERT_TRUE(image_file_.ReadImage(RelativeAddress(exports->VirtualAddress),
143 : &export_dir,
144 E : sizeof(export_dir)));
145 :
146 : // Check that we actually read something.
147 E : IMAGE_EXPORT_DIRECTORY zero_export_dir = {};
148 E : ASSERT_NE(0, memcmp(&export_dir, &zero_export_dir, sizeof(export_dir)));
149 :
150 : // Now test the ReadImageString function.
151 E : std::vector<RelativeAddress> names(export_dir.NumberOfNames);
152 : ASSERT_TRUE(image_file_.ReadImage(RelativeAddress(export_dir.AddressOfNames),
153 : &names.at(0),
154 E : sizeof(names[0]) * names.size()));
155 :
156 : // Test the same thing using an absolute address.
157 E : AbsoluteAddress abs_names_addr;
158 : ASSERT_TRUE(image_file_.Translate(RelativeAddress(export_dir.AddressOfNames),
159 E : &abs_names_addr));
160 E : std::vector<RelativeAddress> names2(export_dir.NumberOfNames);
161 : ASSERT_TRUE(image_file_.ReadImage(abs_names_addr, &names2.at(0),
162 E : sizeof(names2[0]) * names2.size()));
163 E : ASSERT_EQ(names, names2);
164 :
165 : // Read all the export name strings.
166 E : for (size_t i = 0; i < names.size(); ++i) {
167 E : std::string name1;
168 E : ASSERT_TRUE(image_file_.ReadImageString(names[i], &name1));
169 : ASSERT_TRUE(name1 == "function1" ||
170 : name1 == "function3" ||
171 : name1 == "DllMain" ||
172 : name1 == "CreateFileW" ||
173 : name1 == "TestUnusedFuncs" ||
174 : name1 == "TestExport" ||
175 : name1 == "LabelTestFunc" ||
176 : name1 == "BringInOle32DelayLib" ||
177 : name1 == "TestFunctionWithNoPrivateSymbols" ||
178 : name1 == "FuncWithOffsetOutOfImage" ||
179 E : name1 == "EndToEndTest");
180 :
181 E : std::string name2;
182 E : AbsoluteAddress abs_addr;
183 E : ASSERT_TRUE(image_file_.Translate(names[i], &abs_addr));
184 E : ASSERT_TRUE(image_file_.ReadImageString(abs_addr, &name2));
185 E : ASSERT_EQ(name1, name2);
186 E : }
187 E : }
188 :
189 E : TEST_F(PEFileTest, Contains) {
190 E : RelativeAddress relative_base(0);
191 E : AbsoluteAddress absolute_base;
192 E : size_t image_size = image_file_.nt_headers()->OptionalHeader.SizeOfImage;
193 E : RelativeAddress relative_end(image_size);
194 : AbsoluteAddress absolute_end(
195 E : image_file_.nt_headers()->OptionalHeader.ImageBase + image_size);
196 :
197 E : ASSERT_TRUE(image_file_.Translate(relative_base, &absolute_base));
198 E : ASSERT_TRUE(image_file_.Contains(relative_base, 1));
199 E : ASSERT_TRUE(image_file_.Contains(absolute_base, 1));
200 E : ASSERT_FALSE(image_file_.Contains(absolute_base - 1, 1));
201 E : ASSERT_FALSE(image_file_.Contains(absolute_end, 1));
202 E : ASSERT_FALSE(image_file_.Contains(relative_end, 1));
203 :
204 : // TODO(rogerm): test for inclusion at the end of the address space
205 : // The way the address space is built only captures the ranges
206 : // specified as sections in the headers, not the overall image size.
207 : // Either the test needs to be more invasive or the data structure
208 : // needs to be more broadly representative. Note sure which, but
209 : // it's not critical.
210 :
211 : // ASSERT_TRUE(image_file_.Contains(absolute_end - 1, 1));
212 E : }
213 :
214 E : TEST_F(PEFileTest, Translate) {
215 : // Try an address inside the headers (outside of any section).
216 E : AbsoluteAddress abs(image_file_.nt_headers()->OptionalHeader.ImageBase + 3);
217 E : RelativeAddress rel(3);
218 E : FileOffsetAddress off(3);
219 E : ASSERT_NO_FATAL_FAILURE(TestAddressesAreConsistent(rel, abs, off));
220 :
221 : // Now try an address in each of the sections.
222 E : size_t i = 0;
223 E : for (; i < image_file_.nt_headers()->FileHeader.NumberOfSections; ++i) {
224 E : const IMAGE_SECTION_HEADER* section = image_file_.section_header(i);
225 :
226 : AbsoluteAddress abs(section->VirtualAddress +
227 E : image_file_.nt_headers()->OptionalHeader.ImageBase + i);
228 E : RelativeAddress rel(section->VirtualAddress + i);
229 E : FileOffsetAddress off(section->PointerToRawData + i);
230 :
231 E : ASSERT_NO_FATAL_FAILURE(TestAddressesAreConsistent(rel, abs, off));
232 E : }
233 E : }
234 :
235 E : TEST_F(PEFileTest, TranslateOffImageFails) {
236 : const IMAGE_SECTION_HEADER* section = image_file_.section_header(
237 E : image_file_.nt_headers()->FileHeader.NumberOfSections - 1);
238 :
239 : AbsoluteAddress abs_end(image_file_.nt_headers()->OptionalHeader.ImageBase +
240 E : image_file_.nt_headers()->OptionalHeader.SizeOfImage);
241 E : RelativeAddress rel_end(image_file_.nt_headers()->OptionalHeader.SizeOfImage);
242 E : FileOffsetAddress off_end(section->PointerToRawData + section->SizeOfRawData);
243 :
244 E : AbsoluteAddress abs;
245 E : RelativeAddress rel;
246 E : FileOffsetAddress off;
247 E : ASSERT_FALSE(image_file_.Translate(rel_end, &abs));
248 E : ASSERT_FALSE(image_file_.Translate(abs_end, &rel));
249 E : ASSERT_FALSE(image_file_.Translate(off_end, &rel));
250 E : ASSERT_FALSE(image_file_.Translate(rel_end, &off));
251 E : }
252 :
253 E : TEST_F(PEFileTest, TranslateFileOffsetSpaceNotContiguous) {
254 E : size_t data_index = image_file_.GetSectionIndex(".data");
255 E : ASSERT_NE(kInvalidSection, data_index);
256 :
257 : const IMAGE_SECTION_HEADER* data =
258 E : image_file_.section_header(data_index);
259 E : ASSERT_TRUE(data != NULL);
260 :
261 E : RelativeAddress rel1, rel2;
262 E : rel1.set_value(data->VirtualAddress + data->SizeOfRawData - 1);
263 E : rel2.set_value(data->VirtualAddress + data->SizeOfRawData);
264 :
265 E : FileOffsetAddress off1, off2;
266 E : ASSERT_TRUE(image_file_.Translate(rel1, &off1));
267 E : ASSERT_FALSE(image_file_.Translate(rel2, &off2));
268 :
269 E : RelativeAddress rel3;
270 E : off2 = off1 + 1;
271 E : ASSERT_TRUE(image_file_.Translate(off2, &rel3));
272 E : ASSERT_LT(1, rel3 - rel2);
273 E : }
274 :
275 E : TEST_F(PEFileTest, DecodeRelocs) {
276 E : PEFile::RelocSet relocs;
277 E : ASSERT_TRUE(image_file_.DecodeRelocs(&relocs));
278 :
279 E : PEFile::RelocMap reloc_values;
280 E : ASSERT_TRUE(image_file_.ReadRelocs(relocs, &reloc_values));
281 :
282 : // We expect to have some relocs to validate and we expect that
283 : // all relocation table entries and their corresponding values
284 : // fall within the image's address space
285 E : ASSERT_TRUE(!reloc_values.empty());
286 E : PEFile::RelocMap::const_iterator i = reloc_values.begin();
287 E : for (;i != reloc_values.end(); ++i) {
288 : // Note:
289 : // i->first is a relative pointer yielded by the relocation table
290 : // i->second is the absolute value of that pointer (i.e., the relocation)
291 :
292 E : const RelativeAddress &pointer_location(i->first);
293 E : const AbsoluteAddress &pointer_value(i->second);
294 :
295 E : ASSERT_TRUE(image_file_.Contains(pointer_location, sizeof(pointer_value)));
296 E : }
297 E : }
298 :
299 E : TEST_F(PEFileTest, DecodeExports) {
300 E : PEFile::ExportInfoVector exports;
301 E : ASSERT_TRUE(image_file_.DecodeExports(&exports));
302 :
303 : // This must match the information in the test_dll.def file.
304 : PEFile::ExportInfo expected[] = {
305 E : { RelativeAddress(0), "", "", 1 },
306 E : { RelativeAddress(0), "BringInOle32DelayLib", "", 2 },
307 E : { RelativeAddress(0), "TestExport", "", 3 },
308 E : { RelativeAddress(0), "TestUnusedFuncs", "", 4 },
309 E : { RelativeAddress(0), "LabelTestFunc", "", 5 },
310 E : { RelativeAddress(0), "TestFunctionWithNoPrivateSymbols", "", 6 },
311 E : { RelativeAddress(0), "DllMain", "", 7 },
312 E : { RelativeAddress(0), "function3", "", 9 },
313 E : { RelativeAddress(0), "CreateFileW", "kernel32.CreateFileW", 13 },
314 E : { RelativeAddress(0), "function1", "", 17 },
315 E : { RelativeAddress(0), "FuncWithOffsetOutOfImage", "", 18 },
316 E : { RelativeAddress(0), "EndToEndTest", "", 20 },
317 : };
318 :
319 E : ASSERT_EQ(ARRAYSIZE(expected), exports.size());
320 :
321 E : const uint8* module_base = reinterpret_cast<const uint8*>(test_dll_);
322 :
323 : // Resolve the exports and compare.
324 E : for (size_t i = 0; i < arraysize(expected); ++i) {
325 E : if (expected[i].forward.empty()) {
326 : // Look up the functions by ordinal.
327 : const uint8* function = reinterpret_cast<const uint8*>(
328 : base::GetFunctionPointerFromNativeLibrary(
329 E : test_dll_, reinterpret_cast<const char*>(expected[i].ordinal)));
330 E : EXPECT_TRUE(function != NULL);
331 :
332 E : expected[i].function = RelativeAddress(function - module_base);
333 : }
334 E : EXPECT_EQ(expected[i].function, exports.at(i).function);
335 E : EXPECT_EQ(expected[i].name, exports.at(i).name);
336 E : EXPECT_EQ(expected[i].forward, exports.at(i).forward);
337 E : EXPECT_EQ(expected[i].ordinal, exports.at(i).ordinal);
338 E : }
339 E : }
340 :
341 E : TEST_F(PEFileTest, DecodeImports) {
342 E : PEFile::ImportDllVector imports;
343 E : ASSERT_TRUE(image_file_.DecodeImports(&imports));
344 :
345 : // Validation the read imports section.
346 : // The test image imports at least kernel32 and the export_dll.
347 E : ASSERT_LE(2U, imports.size());
348 :
349 E : for (size_t i = 0; i < imports.size(); ++i) {
350 E : PEFile::ImportDll& dll = imports[i];
351 E : if (0 == base::strcasecmp("export_dll.dll", dll.name.c_str())) {
352 E : ASSERT_EQ(4, dll.functions.size());
353 E : for (size_t i = 0; i < dll.functions.size(); ++i) {
354 E : LOG(ERROR) << dll.functions[i].hint << ":"
355 : << dll.functions[i].ordinal << ":"
356 : << dll.functions[i].function;
357 E : }
358 : // Depending on the optimization settings the order of these elements can
359 : // actually be different.
360 : ASSERT_THAT(dll.functions, testing::WhenSortedBy(
361 : CompareImportInfo(),
362 : testing::ElementsAre(
363 : PEFile::ImportInfo(0, 0, "function1"),
364 : PEFile::ImportInfo(0, 7, ""),
365 : PEFile::ImportInfo(1, 0, "function3"),
366 E : PEFile::ImportInfo(2, 0, "kExportedData"))));
367 : }
368 E : }
369 E : }
370 :
371 E : TEST_F(PEFileTest, GetSectionIndexByRelativeAddress) {
372 E : size_t num_sections = image_file_.nt_headers()->FileHeader.NumberOfSections;
373 E : for (size_t i = 0; i < num_sections; ++i) {
374 : RelativeAddress section_start(
375 E : image_file_.section_header(i)->VirtualAddress);
376 E : EXPECT_EQ(i, image_file_.GetSectionIndex(section_start, 1));
377 E : }
378 :
379 : RelativeAddress off_end(image_file_.nt_headers()->OptionalHeader.SizeOfImage +
380 E : 0x10000);
381 E : EXPECT_EQ(kInvalidSection, image_file_.GetSectionIndex(off_end, 1));
382 E : }
383 :
384 E : TEST_F(PEFileTest, GetSectionIndexByAbsoluteAddress) {
385 E : size_t image_base = image_file_.nt_headers()->OptionalHeader.ImageBase;
386 E : size_t num_sections = image_file_.nt_headers()->FileHeader.NumberOfSections;
387 E : for (size_t i = 0; i < num_sections; ++i) {
388 : AbsoluteAddress section_start(
389 E : image_file_.section_header(i)->VirtualAddress + image_base);
390 E : EXPECT_EQ(i, image_file_.GetSectionIndex(section_start, 1));
391 E : }
392 :
393 : AbsoluteAddress off_end(image_file_.nt_headers()->OptionalHeader.SizeOfImage +
394 E : 0x10000 + image_base);
395 E : EXPECT_EQ(kInvalidSection, image_file_.GetSectionIndex(off_end, 1));
396 E : }
397 :
398 E : TEST_F(PEFileTest, GetSectionIndexByName) {
399 E : size_t num_sections = image_file_.nt_headers()->FileHeader.NumberOfSections;
400 E : for (size_t i = 0; i < num_sections; ++i) {
401 E : std::string name = image_file_.GetSectionName(i);
402 E : EXPECT_EQ(i, image_file_.GetSectionIndex(name.c_str()));
403 E : }
404 :
405 E : EXPECT_EQ(kInvalidSection, image_file_.GetSectionIndex(".foobar"));
406 E : }
407 :
408 E : TEST_F(PEFileTest, GetSectionHeaderByRelativeAddress) {
409 E : size_t num_sections = image_file_.nt_headers()->FileHeader.NumberOfSections;
410 E : for (size_t i = 0; i < num_sections; ++i) {
411 : RelativeAddress section_start(
412 E : image_file_.section_header(i)->VirtualAddress);
413 : EXPECT_EQ(image_file_.section_header(i),
414 E : image_file_.GetSectionHeader(section_start, 1));
415 E : }
416 :
417 : RelativeAddress off_end(image_file_.nt_headers()->OptionalHeader.SizeOfImage +
418 E : 0x10000);
419 E : EXPECT_EQ(kInvalidSection, image_file_.GetSectionIndex(off_end, 1));
420 E : }
421 :
422 E : TEST_F(PEFileTest, GetSectionHeaderByAbsoluteAddress) {
423 E : size_t image_base = image_file_.nt_headers()->OptionalHeader.ImageBase;
424 E : size_t num_sections = image_file_.nt_headers()->FileHeader.NumberOfSections;
425 E : for (size_t i = 0; i < num_sections; ++i) {
426 : AbsoluteAddress section_start(
427 E : image_file_.section_header(i)->VirtualAddress + image_base);
428 : EXPECT_EQ(image_file_.section_header(i),
429 E : image_file_.GetSectionHeader(section_start, 1));
430 E : }
431 :
432 : AbsoluteAddress off_end(image_file_.nt_headers()->OptionalHeader.SizeOfImage +
433 E : 0x10000 + image_base);
434 E : EXPECT_EQ(kInvalidSection, image_file_.GetSectionIndex(off_end, 1));
435 E : }
436 :
437 E : TEST_F(PEFileTest, GetSectionHeaderByName) {
438 E : size_t num_sections = image_file_.nt_headers()->FileHeader.NumberOfSections;
439 E : for (size_t i = 0; i < num_sections; ++i) {
440 E : std::string name = image_file_.GetSectionName(i);
441 : EXPECT_EQ(image_file_.section_header(i),
442 E : image_file_.GetSectionHeader(name.c_str()));
443 E : }
444 :
445 E : EXPECT_EQ(NULL, image_file_.GetSectionHeader(".foobar"));
446 E : }
447 :
448 E : TEST(PEFileSignatureTest, Serialization) {
449 E : PEFile::Signature sig;
450 E : sig.path = L"C:\foo\bar.dll";
451 E : sig.base_address = AbsoluteAddress(0x1000000);
452 E : sig.module_size = 12345;
453 E : sig.module_time_date_stamp = 9999999;
454 E : sig.module_checksum = 0xbaadf00d;
455 :
456 E : EXPECT_TRUE(testing::TestSerialization(sig));
457 E : }
458 :
459 E : TEST(PEFileSignatureTest, Consistency) {
460 E : PEFile::Signature sig1;
461 E : sig1.path = L"C:\\foo\\bar.dll";
462 E : sig1.base_address = AbsoluteAddress(0x1000000);
463 E : sig1.module_size = 12345;
464 E : sig1.module_time_date_stamp = 9999999;
465 E : sig1.module_checksum = 0xbaadf00d;
466 :
467 : // sig2 is the same, but with a different module path.
468 E : PEFile::Signature sig2(sig1);
469 E : sig2.path = L"C:\\foo\\bar.exe";
470 :
471 E : EXPECT_FALSE(sig1 == sig2);
472 E : EXPECT_TRUE(sig1.IsConsistent(sig2));
473 E : EXPECT_TRUE(sig1.IsConsistentExceptForChecksum(sig2));
474 :
475 E : sig2.module_checksum = sig1.module_checksum + 100;
476 E : EXPECT_FALSE(sig1.IsConsistent(sig2));
477 E : EXPECT_TRUE(sig1.IsConsistentExceptForChecksum(sig2));
478 E : sig2.module_checksum = sig1.module_checksum;
479 :
480 E : sig2.base_address = sig1.base_address + 0x1000;
481 E : EXPECT_FALSE(sig1.IsConsistent(sig2));
482 E : EXPECT_FALSE(sig1.IsConsistentExceptForChecksum(sig2));
483 E : sig2.base_address = sig1.base_address;
484 :
485 E : sig2.module_size = sig2.module_size + 0x1000;
486 E : EXPECT_FALSE(sig1.IsConsistent(sig2));
487 E : EXPECT_FALSE(sig1.IsConsistentExceptForChecksum(sig2));
488 E : }
489 :
490 : } // namespace pe
|