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 : #include "syzygy/pe/pe_file.h"
15 :
16 : #include "base/file_util.h"
17 : #include "base/logging.h"
18 :
19 : namespace pe {
20 :
21 : using core::AbsoluteAddress;
22 : using core::FileOffsetAddress;
23 : using core::RelativeAddress;
24 :
25 : PEFile::PEFile()
26 : : dos_header_(NULL),
27 E : nt_headers_(NULL) {
28 E : }
29 :
30 E : PEFile::~PEFile() {
31 E : }
32 :
33 E : bool PEFile::Init(const base::FilePath& path) {
34 E : PECoffFile::Init(path);
35 :
36 E : FILE* file = file_util::OpenFile(path, "rb");
37 E : if (file == NULL) {
38 E : LOG(ERROR) << "Failed to open file " << path.value() << ".";
39 E : return false;
40 : }
41 :
42 E : bool success = ReadHeaders(file);
43 E : if (success)
44 E : success = ReadSections(file);
45 :
46 E : file_util::CloseFile(file);
47 :
48 E : return success;
49 E : }
50 :
51 E : void PEFile::GetSignature(Signature* signature) const {
52 E : DCHECK(signature != NULL);
53 E : DCHECK(nt_headers_ != NULL);
54 :
55 : // TODO(chrisha): Make GetSignature return a bool, and update all calling
56 : // sites.
57 E : base::FilePath abs_path(base::MakeAbsoluteFilePath(path_));
58 E : CHECK(!abs_path.empty());
59 :
60 E : signature->path = abs_path.value();
61 : signature->base_address =
62 E : AbsoluteAddress(nt_headers_->OptionalHeader.ImageBase);
63 E : signature->module_size = nt_headers_->OptionalHeader.SizeOfImage;
64 E : signature->module_time_date_stamp = nt_headers_->FileHeader.TimeDateStamp;
65 E : signature->module_checksum = nt_headers_->OptionalHeader.CheckSum;
66 E : }
67 :
68 E : bool PEFile::Contains(AbsoluteAddress abs, size_t len) const {
69 E : RelativeAddress rel;
70 E : return Translate(abs, &rel) && Contains(rel, len);
71 E : }
72 :
73 E : size_t PEFile::GetSectionIndex(AbsoluteAddress abs, size_t len) const {
74 E : RelativeAddress rel;
75 E : if (!Translate(abs, &rel))
76 E : return kInvalidSection;
77 E : return GetSectionIndex(rel, len);
78 E : }
79 :
80 : const IMAGE_SECTION_HEADER* PEFile::GetSectionHeader(
81 E : AbsoluteAddress abs, size_t len) const {
82 E : RelativeAddress rel;
83 E : if (!Translate(abs, &rel))
84 i : return NULL;
85 E : return GetSectionHeader(rel, len);
86 E : }
87 :
88 E : size_t PEFile::GetSectionIndex(const char* name) const {
89 E : size_t section_count = file_header_->NumberOfSections;
90 E : for (size_t i = 0; i < section_count; ++i) {
91 E : const IMAGE_SECTION_HEADER* header = section_headers_ + i;
92 : if (strncmp(reinterpret_cast<const char*>(header->Name), name,
93 E : IMAGE_SIZEOF_SHORT_NAME) == 0)
94 E : return i;
95 E : }
96 E : return kInvalidSection;
97 E : }
98 :
99 E : const IMAGE_SECTION_HEADER* PEFile::GetSectionHeader(const char* name) const {
100 E : size_t id = GetSectionIndex(name);
101 E : if (id == kInvalidSection)
102 E : return NULL;
103 E : return section_headers_ + id;
104 E : }
105 :
106 E : bool PEFile::ReadHeaders(FILE* file) {
107 : // Read the DOS header.
108 E : IMAGE_DOS_HEADER dos_header = {};
109 E : if (!ReadAt(file, 0, &dos_header, sizeof(dos_header))) {
110 i : LOG(ERROR) << "Unable to read DOS header.";
111 i : return false;
112 : }
113 :
114 : // And the NT headers.
115 E : IMAGE_NT_HEADERS nt_headers = {};
116 E : size_t pos = dos_header.e_lfanew;
117 E : if (!ReadAt(file, pos, &nt_headers, sizeof(nt_headers))) {
118 i : LOG(ERROR) << "Unable to read NT headers.";
119 i : return false;
120 : }
121 :
122 : FileOffsetAddress file_header_start(
123 E : pos + offsetof(IMAGE_NT_HEADERS, FileHeader));
124 E : if (!ReadCommonHeaders(file, file_header_start)) {
125 i : return false;
126 : }
127 :
128 E : ImageAddressSpace::RangeMap::iterator it = image_data_.begin();
129 E : DCHECK(it != image_data_.end());
130 E : SectionBuffer& header = it->second.buffer;
131 :
132 : // TODO(siggi): Validate these pointers!
133 E : dos_header_ = reinterpret_cast<IMAGE_DOS_HEADER*>(&header.at(0));
134 : nt_headers_ =
135 E : reinterpret_cast<IMAGE_NT_HEADERS*>(&header.at(dos_header_->e_lfanew));
136 :
137 E : return true;
138 E : }
139 :
140 E : bool PEFile::Translate(RelativeAddress rel, AbsoluteAddress* abs) const {
141 E : DCHECK(abs != NULL);
142 E : if (rel.value() >= nt_headers_->OptionalHeader.SizeOfImage)
143 E : return false;
144 E : abs->set_value(rel.value() + nt_headers_->OptionalHeader.ImageBase);
145 E : return true;
146 E : }
147 :
148 E : bool PEFile::Translate(AbsoluteAddress abs, RelativeAddress* rel) const {
149 E : DCHECK(rel != NULL);
150 E : uint32 rel_addr = AbsToRelDisplacement(abs.value());
151 E : if (rel_addr >= nt_headers_->OptionalHeader.SizeOfImage)
152 E : return false;
153 E : rel->set_value(rel_addr);
154 E : return true;
155 E : }
156 :
157 E : bool PEFile::Translate(FileOffsetAddress offs, RelativeAddress* rel) const {
158 E : DCHECK(rel != NULL);
159 :
160 : // The first "previous section" is the headers.
161 E : RelativeAddress previous_section_start(0);
162 E : FileOffsetAddress previous_section_file_start(0);
163 E : const IMAGE_SECTION_HEADER* previous_section = NULL;
164 E : for (size_t i = 0; i < nt_headers_->FileHeader.NumberOfSections; ++i) {
165 E : if (offs.value() < section_headers_[i].PointerToRawData)
166 E : break;
167 :
168 E : previous_section_start.set_value(section_headers_[i].VirtualAddress);
169 E : previous_section_file_start.set_value(section_headers_[i].PointerToRawData);
170 E : previous_section = section_headers_ + i;
171 E : }
172 :
173 E : size_t section_offset = offs - previous_section_file_start;
174 : if (previous_section != NULL &&
175 E : section_offset >= previous_section->SizeOfRawData) {
176 E : return false;
177 : }
178 :
179 E : *rel = previous_section_start + section_offset;
180 :
181 E : return true;
182 E : }
183 :
184 E : bool PEFile::Translate(RelativeAddress rel, FileOffsetAddress* offs) const {
185 E : DCHECK(offs != NULL);
186 :
187 : // In the headers?
188 E : if (rel.value() < section_header(0)->VirtualAddress) {
189 E : offs->set_value(rel.value());
190 E : return true;
191 : }
192 :
193 : // Find the section in which this address lies.
194 E : const IMAGE_SECTION_HEADER* section = GetSectionHeader(rel, 1);
195 E : if (section == NULL)
196 E : return false;
197 :
198 : // Calculate the offset of this address and ensure it can be expressed as
199 : // a file offset (lies in the explicit data part of the section, not the
200 : // implicit virtual data at the end).
201 E : size_t section_offset = rel.value() - section->VirtualAddress;
202 E : if (section_offset >= section->SizeOfRawData)
203 E : return false;
204 :
205 E : offs->set_value(section->PointerToRawData + section_offset);
206 :
207 E : return true;
208 E : }
209 :
210 E : const uint8* PEFile::GetImageData(AbsoluteAddress abs, size_t len) const {
211 E : RelativeAddress rel;
212 E : if (Translate(abs, &rel))
213 E : return GetImageData(rel, len);
214 :
215 i : return NULL;
216 E : }
217 :
218 E : uint8* PEFile::GetImageData(AbsoluteAddress abs, size_t len) {
219 : return const_cast<uint8*>(
220 E : static_cast<const PEFile*>(this)->GetImageData(abs, len));
221 E : }
222 :
223 E : bool PEFile::ReadImage(AbsoluteAddress abs, void* data, size_t len) const {
224 E : RelativeAddress rel;
225 E : if (!Translate(abs, &rel))
226 i : return false;
227 :
228 E : return ReadImage(rel, data, len);
229 E : }
230 :
231 E : bool PEFile::ReadImageString(AbsoluteAddress abs, std::string* str) const {
232 E : RelativeAddress rel;
233 E : if (!Translate(abs, &rel))
234 i : return false;
235 :
236 E : return ReadImageString(rel, str);
237 E : }
238 :
239 E : bool PEFile::DecodeRelocs(RelocSet* relocs) const {
240 E : DCHECK(nt_headers_ != NULL);
241 E : DCHECK(relocs != NULL);
242 :
243 : // Walk the relocs.
244 : IMAGE_DATA_DIRECTORY dir =
245 : nt_headers_->OptionalHeader.DataDirectory[
246 E : IMAGE_DIRECTORY_ENTRY_BASERELOC];
247 E : RelativeAddress offs(dir.VirtualAddress);
248 E : RelativeAddress end(offs + dir.Size);
249 :
250 E : const IMAGE_BASE_RELOCATION* hdr = NULL;
251 E : for (; offs < end; offs += hdr->SizeOfBlock) {
252 : // Read the next header.
253 E : if (!GetImageData(offs, sizeof(hdr), &hdr)) {
254 i : LOG(ERROR) << "Failed to read relocation block header.";
255 i : return false;
256 : }
257 :
258 : // Read the entries.
259 E : size_t num_relocs = (hdr->SizeOfBlock - sizeof(*hdr)) / sizeof(WORD);
260 E : const WORD* reloc_block = NULL;
261 : if (!GetImageData(offs + sizeof(*hdr), sizeof(*reloc_block) * num_relocs,
262 E : &reloc_block)) {
263 i : LOG(ERROR) << "Failed to read relocation entries.";
264 i : return false;
265 : }
266 :
267 : // Walk the entries.
268 E : for (size_t i = 0; i < num_relocs; ++i) {
269 E : uint8 type = reloc_block[i] >> 12;
270 E : uint16 offs = reloc_block[i] & 0xFFF;
271 : DCHECK(type == IMAGE_REL_BASED_HIGHLOW ||
272 E : type == IMAGE_REL_BASED_ABSOLUTE);
273 :
274 E : if (type == IMAGE_REL_BASED_HIGHLOW) {
275 : // Record the entry.
276 E : relocs->insert(RelativeAddress(hdr->VirtualAddress) + offs);
277 : }
278 E : }
279 E : }
280 :
281 E : DCHECK(offs == end);
282 E : return true;
283 E : }
284 :
285 E : bool PEFile::ReadRelocs(const RelocSet& relocs, RelocMap* reloc_values) const {
286 E : RelocSet::const_iterator it(relocs.begin());
287 E : for (; it != relocs.end(); ++it) {
288 E : const AbsoluteAddress* abs = NULL;
289 E : if (!GetImageData(*it, sizeof(*abs), &abs)) {
290 i : LOG(ERROR) << "Failed to read reloc at " << it->value() << ".";
291 i : return false;
292 : }
293 :
294 E : reloc_values->insert(std::make_pair(*it, *abs));
295 E : }
296 :
297 E : return true;
298 E : }
299 :
300 E : bool PEFile::DecodeExports(ExportInfoVector* exports) const {
301 E : DCHECK(exports != NULL);
302 :
303 : IMAGE_DATA_DIRECTORY dir = nt_headers_->OptionalHeader.
304 E : DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
305 E : RelativeAddress addr(dir.VirtualAddress);
306 E : RelativeAddress end(addr + dir.Size);
307 :
308 E : if (addr.value() == 0)
309 i : return true;
310 :
311 E : const IMAGE_EXPORT_DIRECTORY* export_dir = NULL;
312 E : if (!GetImageData(addr, sizeof(export_dir), &export_dir)) {
313 i : LOG(ERROR) << "Unable to read export directory.";
314 i : return false;
315 : }
316 :
317 E : const RelativeAddress* functions = NULL;
318 : if (!GetImageData(RelativeAddress(export_dir->AddressOfFunctions),
319 : sizeof(*functions) * export_dir->NumberOfFunctions,
320 E : &functions)) {
321 i : LOG(ERROR) << "Unable to read export functions.";
322 i : return false;
323 : }
324 :
325 E : const RelativeAddress* names = NULL;
326 : if (!GetImageData(RelativeAddress(export_dir->AddressOfNames),
327 : sizeof(*functions) * export_dir->NumberOfNames,
328 E : &names)) {
329 i : LOG(ERROR) << "Unable to read export names.";
330 i : return false;
331 : }
332 :
333 E : const WORD* name_ordinals = NULL;
334 : if (!GetImageData(RelativeAddress(export_dir->AddressOfNameOrdinals),
335 : sizeof(*functions) * export_dir->NumberOfNames,
336 E : &name_ordinals)) {
337 i : LOG(ERROR) << "Unable to read name ordinals.";
338 i : return false;
339 : }
340 :
341 E : for (size_t index = 0; index < export_dir->NumberOfFunctions; ++index) {
342 : // Is it a blank entry?
343 E : if (functions[index] != RelativeAddress(0)) {
344 E : ExportInfo info;
345 E : info.ordinal = index + 1;
346 :
347 E : RelativeAddress function = functions[index];
348 : // Is it a forward?
349 E : if (function >= addr && function < end) {
350 E : if (!ReadImageString(function, &info.forward)) {
351 i : LOG(ERROR) << "Unable to read export forward string.";
352 i : return false;
353 : }
354 E : } else {
355 E : info.function = function;
356 : }
357 :
358 : // Does it have a name?
359 E : for (size_t i = 0; i < export_dir->NumberOfNames; ++i) {
360 E : if (name_ordinals[i] == index) {
361 E : if (!ReadImageString(names[i], &info.name)) {
362 i : LOG(ERROR) << "Unable to read export name.";
363 i : return false;
364 : }
365 E : break;
366 : }
367 E : }
368 :
369 E : exports->push_back(info);
370 E : }
371 E : }
372 :
373 E : return true;
374 E : }
375 :
376 E : bool PEFile::DecodeImports(ImportDllVector* imports) const {
377 E : DCHECK(imports != NULL);
378 :
379 : // Walk the import thunks.
380 : IMAGE_DATA_DIRECTORY dir = nt_headers_->OptionalHeader.
381 E : DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
382 E : RelativeAddress offs(dir.VirtualAddress);
383 E : RelativeAddress end(offs + dir.Size);
384 :
385 E : const IMAGE_IMPORT_DESCRIPTOR* import_desc = NULL;
386 E : for (; offs < end; offs += sizeof(*import_desc)) {
387 E : if (!GetImageData(offs, sizeof(*import_desc), &import_desc)) {
388 i : LOG(ERROR) << "Unable to read import descriptor.";
389 i : return false;
390 : }
391 :
392 E : if (import_desc->Characteristics == 0 && import_desc->FirstThunk == 0) {
393 : // This is the last chunk, bail the loop.
394 E : break;
395 : }
396 :
397 E : std::string dll_name;
398 E : if (!ReadImageString(RelativeAddress(import_desc->Name), &dll_name)) {
399 i : LOG(ERROR) << "Unable to read import descriptor name.";
400 i : return false;
401 : }
402 :
403 : // Iterate the Import Name Table and the Import Address Table
404 : // concurrently. They will yield, respectively, the name of the
405 : // function and the address of the entry.
406 E : RelativeAddress int_offs(import_desc->OriginalFirstThunk);
407 E : RelativeAddress iat_offs(import_desc->FirstThunk);
408 :
409 E : imports->push_back(ImportDll());
410 E : ImportDll& dll = imports->back();
411 E : dll.name = dll_name;
412 E : dll.desc = *import_desc;
413 :
414 E : while (true) {
415 E : IMAGE_THUNK_DATA int_thunk = {};
416 E : IMAGE_THUNK_DATA iat_thunk = {};
417 :
418 : if (!ReadImage(int_offs, &int_thunk, sizeof(int_thunk)) ||
419 E : !ReadImage(iat_offs, &iat_thunk, sizeof(iat_thunk))) {
420 i : LOG(ERROR) << "Unable to read import name or address table thunk.";
421 i : return false;
422 : }
423 :
424 : // Are we at the end of the table?
425 E : if (int_thunk.u1.Function == 0) {
426 E : DCHECK_EQ(0U, iat_thunk.u1.Function);
427 E : break;
428 : }
429 :
430 E : uint16 hint = 0;
431 E : uint16 ordinal = 0;
432 E : std::string function_name;
433 E : if (int_thunk.u1.AddressOfData & IMAGE_ORDINAL_FLAG32) {
434 : // It's an ordinal.
435 E : ordinal = IMAGE_ORDINAL32(int_thunk.u1.Ordinal);
436 E : } else {
437 : // Read the hint word, followed by the function name.
438 E : RelativeAddress import_name(int_thunk.u1.AddressOfData);
439 : if (!ReadImage(import_name, &hint, sizeof(hint)) ||
440 E : !ReadImageString(import_name + sizeof(hint), &function_name)) {
441 i : LOG(ERROR) << "Unable to read import function hint or name.";
442 i : return false;
443 : }
444 : }
445 :
446 E : dll.functions.push_back(ImportInfo());
447 E : ImportInfo& info = dll.functions.back();
448 E : info.function = function_name;
449 E : info.ordinal = ordinal;
450 E : info.hint = hint;
451 :
452 E : int_offs += sizeof(int_thunk);
453 E : iat_offs += sizeof(iat_thunk);
454 E : }
455 E : }
456 :
457 E : return true;
458 E : }
459 :
460 E : bool PEFile::Signature::IsConsistent(const Signature& signature) const {
461 : return IsConsistentExceptForChecksum(signature) &&
462 E : module_checksum == signature.module_checksum;
463 E : }
464 :
465 : bool PEFile::Signature::IsConsistentExceptForChecksum(
466 E : const Signature& signature) const {
467 : return base_address == signature.base_address &&
468 : module_size == signature.module_size &&
469 E : module_time_date_stamp == signature.module_time_date_stamp;
470 E : }
471 :
472 E : bool PEFile::Signature::Save(core::OutArchive* out_archive) const {
473 : return out_archive->Save(path) &&
474 : out_archive->Save(base_address) &&
475 : out_archive->Save(module_size) &&
476 : out_archive->Save(module_time_date_stamp) &&
477 E : out_archive->Save(module_checksum);
478 E : }
479 :
480 E : bool PEFile::Signature::Load(core::InArchive* in_archive) {
481 : return in_archive->Load(&path) &&
482 : in_archive->Load(&base_address) &&
483 : in_archive->Load(&module_size) &&
484 : in_archive->Load(&module_time_date_stamp) &&
485 E : in_archive->Load(&module_checksum);
486 E : }
487 :
488 : } // namespace pe
|