1 : // Copyright 2013 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_coff_file.h"
16 :
17 : #include "base/native_library.h"
18 : #include "base/path_service.h"
19 : #include "base/files/file_path.h"
20 : #include "base/strings/string_util.h"
21 : #include "gmock/gmock.h"
22 : #include "gtest/gtest.h"
23 : #include "syzygy/core/unittest_util.h"
24 : #include "syzygy/pe/unittest_util.h"
25 :
26 : namespace pe {
27 :
28 : namespace {
29 :
30 : using core::AbsoluteAddress;
31 : using core::FileOffsetAddress;
32 : using core::RelativeAddress;
33 :
34 : template <typename AddressSpaceTraits>
35 : class TestPECoffFile : public PECoffFile<AddressSpaceTraits> {
36 : public:
37 : // Partial initialization, for common parts.
38 E : bool Init(const base::FilePath& path, bool has_pe_headers) {
39 E : PECoffFile::Init(path);
40 :
41 E : FILE* file = base::OpenFile(path, "rb");
42 E : if (file == NULL) {
43 i : LOG(ERROR) << "Failed to open file " << path.value() << ".";
44 i : return false;
45 : }
46 :
47 E : FileOffsetAddress file_header_start(0);
48 E : if (has_pe_headers) {
49 : // Read NT header position at 0x3C according to the spec.
50 E : uint32 nt_header_pos = 0;
51 E : if (!ReadAt(file, 0x3C, &nt_header_pos, sizeof(nt_header_pos))) {
52 i : LOG(ERROR) << "Unable to read NT header offset.";
53 i : return false;
54 : }
55 :
56 : file_header_start.set_value(nt_header_pos +
57 E : offsetof(IMAGE_NT_HEADERS, FileHeader));
58 : }
59 :
60 E : bool success = ReadCommonHeaders(file, file_header_start);
61 E : if (success)
62 E : success = ReadSections(file);
63 :
64 E : base::CloseFile(file);
65 :
66 E : return success;
67 E : }
68 : };
69 :
70 : template <typename AddressType, size_t shift_base, size_t header_base>
71 : struct ShiftedAddressSpaceTraits {
72 : typedef typename AddressType AddressType;
73 : typedef unsigned int SizeType;
74 :
75 : static const size_t kShiftBase = shift_base;
76 :
77 E : static const AddressType invalid_address() {
78 E : return AddressType::kInvalidAddress;
79 E : }
80 :
81 E : static const AddressType header_address() {
82 E : return AddressType(header_base);
83 E : }
84 :
85 E : static AddressType GetSectionAddress(const IMAGE_SECTION_HEADER& header) {
86 : // VirtualAddress is not necessarily 0 for object files, but it
87 : // should, and MSVC should produce 0; we use that info as
88 : // a heuristic to decide on the address.
89 E : if (header.VirtualAddress == 0) {
90 : if ((header.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0 &&
91 E : header.PointerToRawData == 0) {
92 : // Unmapped section.
93 E : return invalid_address();
94 i : } else {
95 E : return AddressType(kShiftBase + header.PointerToRawData);
96 : }
97 i : } else {
98 E : return AddressType(kShiftBase + header.VirtualAddress);
99 : }
100 E : }
101 :
102 E : static SizeType GetSectionSize(const IMAGE_SECTION_HEADER& header) {
103 E : return 1;
104 E : }
105 : };
106 :
107 : typedef ShiftedAddressSpaceTraits<AbsoluteAddress, 0x10000, 0x4>
108 : ShiftedVirtualAddressTraits;
109 : typedef ShiftedAddressSpaceTraits<FileOffsetAddress, 0x100, 0x100>
110 : ShiftedFileOffsetAddressTraits;
111 :
112 : class PECoffFileTest : public testing::PELibUnitTest {
113 : typedef testing::PELibUnitTest Super;
114 :
115 : public:
116 E : PECoffFileTest() {
117 E : }
118 :
119 E : virtual void SetUp() OVERRIDE {
120 E : Super::SetUp();
121 :
122 E : test_dll_path_ = testing::GetExeRelativePath(testing::kTestDllName);
123 : test_dll_coff_obj_path_ =
124 E : testing::GetExeTestDataRelativePath(testing::kTestDllCoffObjName);
125 : test_dll_ltcg_obj_path_ =
126 E : testing::GetExeTestDataRelativePath(testing::kTestDllLtcgObjName);
127 E : }
128 :
129 : protected:
130 E : bool InitImages() {
131 : return pe_image_file_.Init(test_dll_path_, true) &&
132 E : coff_image_file_.Init(test_dll_coff_obj_path_, false);
133 E : }
134 :
135 : base::FilePath test_dll_path_;
136 : base::FilePath test_dll_coff_obj_path_;
137 : base::FilePath test_dll_ltcg_obj_path_;
138 :
139 : TestPECoffFile<ShiftedVirtualAddressTraits> pe_image_file_;
140 : TestPECoffFile<ShiftedFileOffsetAddressTraits> coff_image_file_;
141 :
142 : private:
143 : DISALLOW_COPY_AND_ASSIGN(PECoffFileTest);
144 : };
145 :
146 : bool IsCoffSectionMapped(
147 : const TestPECoffFile<ShiftedFileOffsetAddressTraits>& image_file,
148 E : size_t i) {
149 E : const IMAGE_SECTION_HEADER* hdr = image_file.section_header(i);
150 : return hdr != NULL &&
151 : (ShiftedFileOffsetAddressTraits::GetSectionAddress(*hdr) !=
152 E : ShiftedFileOffsetAddressTraits::invalid_address());
153 E : }
154 :
155 : } // namespace
156 :
157 E : TEST_F(PECoffFileTest, Init) {
158 E : EXPECT_TRUE(pe_image_file_.file_header() == NULL);
159 E : EXPECT_TRUE(pe_image_file_.section_headers() == NULL);
160 E : EXPECT_TRUE(coff_image_file_.file_header() == NULL);
161 E : EXPECT_TRUE(coff_image_file_.section_headers() == NULL);
162 :
163 E : ASSERT_TRUE(pe_image_file_.Init(test_dll_path_, true));
164 E : ASSERT_TRUE(coff_image_file_.Init(test_dll_coff_obj_path_, false));
165 :
166 E : EXPECT_TRUE(pe_image_file_.file_header() != NULL);
167 E : EXPECT_TRUE(pe_image_file_.section_headers() != NULL);
168 E : EXPECT_TRUE(coff_image_file_.file_header() != NULL);
169 E : EXPECT_TRUE(coff_image_file_.section_headers() != NULL);
170 :
171 E : EXPECT_EQ(pe_image_file_.file_header()->Machine, IMAGE_FILE_MACHINE_I386);
172 E : EXPECT_EQ(coff_image_file_.file_header()->Machine, IMAGE_FILE_MACHINE_I386);
173 :
174 E : EXPECT_TRUE(pe_image_file_.file_header()->SizeOfOptionalHeader != 0);
175 E : EXPECT_TRUE(coff_image_file_.file_header()->PointerToSymbolTable != 0);
176 E : }
177 :
178 E : TEST_F(PECoffFileTest, FailOnAnonymousObject) {
179 E : ASSERT_FALSE(coff_image_file_.Init(test_dll_ltcg_obj_path_, false));
180 E : }
181 :
182 : // Compare header data obtained from different methods.
183 E : TEST_F(PECoffFileTest, ReadFileHeader) {
184 E : ASSERT_TRUE(InitImages());
185 E : ASSERT_TRUE(coff_image_file_.file_header() != NULL);
186 :
187 E : IMAGE_FILE_HEADER header = {};
188 : ASSERT_TRUE(coff_image_file_.ReadImage(coff_image_file_.header_address(),
189 E : &header, sizeof(header)));
190 : EXPECT_TRUE(memcmp(static_cast<void*>(&header),
191 : static_cast<const void*>(coff_image_file_.file_header()),
192 E : sizeof(header)) == 0);
193 : uint8* ptr = coff_image_file_.GetImageData(coff_image_file_.header_address(),
194 E : sizeof(header));
195 E : ASSERT_TRUE(ptr != NULL);
196 : EXPECT_TRUE(memcmp(static_cast<void*>(&header),
197 : static_cast<void*>(ptr),
198 E : sizeof(header)) == 0);
199 E : }
200 :
201 E : TEST_F(PECoffFileTest, Contains) {
202 E : ASSERT_TRUE(InitImages());
203 E : EXPECT_TRUE(pe_image_file_.Contains(pe_image_file_.header_address(), 1));
204 E : EXPECT_FALSE(pe_image_file_.Contains(pe_image_file_.header_address() - 1, 1));
205 :
206 : // Should be a gap in the address space before the big shift of
207 : // ShiftedVirtualAddressTraits::kShiftBase.
208 : EXPECT_FALSE(pe_image_file_.Contains(
209 E : AbsoluteAddress(ShiftedVirtualAddressTraits::kShiftBase - 1), 1));
210 :
211 E : EXPECT_TRUE(coff_image_file_.Contains(coff_image_file_.header_address(), 1));
212 : EXPECT_FALSE(coff_image_file_.Contains(
213 E : coff_image_file_.header_address() - 1, 1));
214 E : }
215 :
216 E : TEST_F(PECoffFileTest, GetSectionIndex) {
217 E : ASSERT_TRUE(InitImages());
218 :
219 E : size_t num_sections = pe_image_file_.file_header()->NumberOfSections;
220 E : for (size_t i = 0; i < num_sections; ++i) {
221 : AbsoluteAddress section_start(
222 : ShiftedVirtualAddressTraits::GetSectionAddress(
223 E : *pe_image_file_.section_header(i)));
224 E : EXPECT_EQ(i, pe_image_file_.GetSectionIndex(section_start, 1));
225 E : }
226 :
227 E : AbsoluteAddress off_by_one(ShiftedVirtualAddressTraits::kShiftBase - 1);
228 E : EXPECT_EQ(kInvalidSection, pe_image_file_.GetSectionIndex(off_by_one, 1));
229 :
230 E : num_sections = coff_image_file_.file_header()->NumberOfSections;
231 E : for (size_t i = 0; i < num_sections; ++i) {
232 E : if (IsCoffSectionMapped(coff_image_file_, i)) {
233 : FileOffsetAddress section_start(
234 : ShiftedFileOffsetAddressTraits::GetSectionAddress(
235 E : *coff_image_file_.section_header(i)));
236 E : EXPECT_EQ(i, coff_image_file_.GetSectionIndex(section_start, 1));
237 : }
238 E : }
239 E : }
240 :
241 E : TEST_F(PECoffFileTest, GetSectionHeader) {
242 E : ASSERT_TRUE(InitImages());
243 :
244 E : size_t num_sections = pe_image_file_.file_header()->NumberOfSections;
245 E : for (size_t i = 0; i < num_sections; ++i) {
246 : AbsoluteAddress section_start(
247 : ShiftedVirtualAddressTraits::GetSectionAddress(
248 E : *pe_image_file_.section_header(i)));
249 : EXPECT_EQ(pe_image_file_.section_header(i),
250 E : pe_image_file_.GetSectionHeader(section_start, 1));
251 E : }
252 :
253 E : num_sections = coff_image_file_.file_header()->NumberOfSections;
254 E : for (size_t i = 0; i < num_sections; ++i) {
255 E : if (IsCoffSectionMapped(coff_image_file_, i)) {
256 : FileOffsetAddress section_start(
257 : ShiftedFileOffsetAddressTraits::GetSectionAddress(
258 E : *coff_image_file_.section_header(i)));
259 : EXPECT_EQ(coff_image_file_.section_header(i),
260 E : coff_image_file_.GetSectionHeader(section_start, 1));
261 : }
262 E : }
263 E : }
264 :
265 E : TEST_F(PECoffFileTest, GetImageData) {
266 E : ASSERT_TRUE(InitImages());
267 E : ASSERT_TRUE(pe_image_file_.file_header() != NULL);
268 E : ASSERT_TRUE(coff_image_file_.file_header() != NULL);
269 :
270 E : size_t num_sections = pe_image_file_.file_header()->NumberOfSections;
271 E : for (size_t i = 0; i < num_sections; ++i) {
272 : AbsoluteAddress section_start(
273 : ShiftedVirtualAddressTraits::GetSectionAddress(
274 E : *pe_image_file_.section_header(i)));
275 E : EXPECT_TRUE(pe_image_file_.GetImageData(section_start, 1) != NULL);
276 E : }
277 :
278 E : num_sections = coff_image_file_.file_header()->NumberOfSections;
279 E : for (size_t i = 0; i < num_sections; ++i) {
280 E : if (IsCoffSectionMapped(coff_image_file_, i)) {
281 : FileOffsetAddress section_start(
282 : ShiftedFileOffsetAddressTraits::GetSectionAddress(
283 E : *coff_image_file_.section_header(i)));
284 E : EXPECT_TRUE(coff_image_file_.GetImageData(section_start, 1) != NULL);
285 : }
286 E : }
287 E : }
288 :
289 : } // namespace pe
|