1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "courgette/disassembler_win32_x86.h" 6 7 #include <algorithm> 8 #include <string> 9 #include <vector> 10 11 #include "base/basictypes.h" 12 #include "base/logging.h" 13 14 #include "courgette/assembly_program.h" 15 #include "courgette/courgette.h" 16 #include "courgette/encoded_program.h" 17 18 namespace courgette { 19 20 DisassemblerWin32X86::DisassemblerWin32X86(const void* start, size_t length) 21 : Disassembler(start, length), 22 incomplete_disassembly_(false), 23 is_PE32_plus_(false), 24 optional_header_(NULL), 25 size_of_optional_header_(0), 26 offset_of_data_directories_(0), 27 machine_type_(0), 28 number_of_sections_(0), 29 sections_(NULL), 30 has_text_section_(false), 31 size_of_code_(0), 32 size_of_initialized_data_(0), 33 size_of_uninitialized_data_(0), 34 base_of_code_(0), 35 base_of_data_(0), 36 image_base_(0), 37 size_of_image_(0), 38 number_of_data_directories_(0) { 39 } 40 41 // ParseHeader attempts to match up the buffer with the Windows data 42 // structures that exist within a Windows 'Portable Executable' format file. 43 // Returns 'true' if the buffer matches, and 'false' if the data looks 44 // suspicious. Rather than try to 'map' the buffer to the numerous windows 45 // structures, we extract the information we need into the courgette::PEInfo 46 // structure. 47 // 48 bool DisassemblerWin32X86::ParseHeader() { 49 if (length() < kOffsetOfFileAddressOfNewExeHeader + 4 /*size*/) 50 return Bad("Too small"); 51 52 // Have 'MZ' magic for a DOS header? 53 if (start()[0] != 'M' || start()[1] != 'Z') 54 return Bad("Not MZ"); 55 56 // offset from DOS header to PE header is stored in DOS header. 57 uint32 offset = ReadU32(start(), 58 kOffsetOfFileAddressOfNewExeHeader); 59 60 if (offset >= length()) 61 return Bad("Bad offset to PE header"); 62 63 const uint8* const pe_header = OffsetToPointer(offset); 64 const size_t kMinPEHeaderSize = 4 /*signature*/ + kSizeOfCoffHeader; 65 if (pe_header <= start() || 66 pe_header >= end() - kMinPEHeaderSize) 67 return Bad("Bad offset to PE header"); 68 69 if (offset % 8 != 0) 70 return Bad("Misaligned PE header"); 71 72 // The 'PE' header is an IMAGE_NT_HEADERS structure as defined in WINNT.H. 73 // See http://msdn.microsoft.com/en-us/library/ms680336(VS.85).aspx 74 // 75 // The first field of the IMAGE_NT_HEADERS is the signature. 76 if (!(pe_header[0] == 'P' && 77 pe_header[1] == 'E' && 78 pe_header[2] == 0 && 79 pe_header[3] == 0)) 80 return Bad("no PE signature"); 81 82 // The second field of the IMAGE_NT_HEADERS is the COFF header. 83 // The COFF header is also called an IMAGE_FILE_HEADER 84 // http://msdn.microsoft.com/en-us/library/ms680313(VS.85).aspx 85 const uint8* const coff_header = pe_header + 4; 86 machine_type_ = ReadU16(coff_header, 0); 87 number_of_sections_ = ReadU16(coff_header, 2); 88 size_of_optional_header_ = ReadU16(coff_header, 16); 89 90 // The rest of the IMAGE_NT_HEADERS is the IMAGE_OPTIONAL_HEADER(32|64) 91 const uint8* const optional_header = coff_header + kSizeOfCoffHeader; 92 optional_header_ = optional_header; 93 94 if (optional_header + size_of_optional_header_ >= end()) 95 return Bad("optional header past end of file"); 96 97 // Check we can read the magic. 98 if (size_of_optional_header_ < 2) 99 return Bad("optional header no magic"); 100 101 uint16 magic = ReadU16(optional_header, 0); 102 103 if (magic == kImageNtOptionalHdr32Magic) { 104 is_PE32_plus_ = false; 105 offset_of_data_directories_ = 106 kOffsetOfDataDirectoryFromImageOptionalHeader32; 107 } else if (magic == kImageNtOptionalHdr64Magic) { 108 is_PE32_plus_ = true; 109 offset_of_data_directories_ = 110 kOffsetOfDataDirectoryFromImageOptionalHeader64; 111 } else { 112 return Bad("unrecognized magic"); 113 } 114 115 // Check that we can read the rest of the the fixed fields. Data directories 116 // directly follow the fixed fields of the IMAGE_OPTIONAL_HEADER. 117 if (size_of_optional_header_ < offset_of_data_directories_) 118 return Bad("optional header too short"); 119 120 // The optional header is either an IMAGE_OPTIONAL_HEADER32 or 121 // IMAGE_OPTIONAL_HEADER64 122 // http://msdn.microsoft.com/en-us/library/ms680339(VS.85).aspx 123 // 124 // Copy the fields we care about. 125 size_of_code_ = ReadU32(optional_header, 4); 126 size_of_initialized_data_ = ReadU32(optional_header, 8); 127 size_of_uninitialized_data_ = ReadU32(optional_header, 12); 128 base_of_code_ = ReadU32(optional_header, 20); 129 if (is_PE32_plus_) { 130 base_of_data_ = 0; 131 image_base_ = ReadU64(optional_header, 24); 132 } else { 133 base_of_data_ = ReadU32(optional_header, 24); 134 image_base_ = ReadU32(optional_header, 28); 135 } 136 size_of_image_ = ReadU32(optional_header, 56); 137 number_of_data_directories_ = 138 ReadU32(optional_header, (is_PE32_plus_ ? 108 : 92)); 139 140 if (size_of_code_ >= length() || 141 size_of_initialized_data_ >= length() || 142 size_of_code_ + size_of_initialized_data_ >= length()) { 143 // This validation fires on some perfectly fine executables. 144 // return Bad("code or initialized data too big"); 145 } 146 147 // TODO(sra): we can probably get rid of most of the data directories. 148 bool b = true; 149 // 'b &= ...' could be short circuit 'b = b && ...' but it is not necessary 150 // for correctness and it compiles smaller this way. 151 b &= ReadDataDirectory(0, &export_table_); 152 b &= ReadDataDirectory(1, &import_table_); 153 b &= ReadDataDirectory(2, &resource_table_); 154 b &= ReadDataDirectory(3, &exception_table_); 155 b &= ReadDataDirectory(5, &base_relocation_table_); 156 b &= ReadDataDirectory(11, &bound_import_table_); 157 b &= ReadDataDirectory(12, &import_address_table_); 158 b &= ReadDataDirectory(13, &delay_import_descriptor_); 159 b &= ReadDataDirectory(14, &clr_runtime_header_); 160 if (!b) { 161 return Bad("malformed data directory"); 162 } 163 164 // Sections follow the optional header. 165 sections_ = 166 reinterpret_cast<const Section*>(optional_header + 167 size_of_optional_header_); 168 size_t detected_length = 0; 169 170 for (int i = 0; i < number_of_sections_; ++i) { 171 const Section* section = §ions_[i]; 172 173 // TODO(sra): consider using the 'characteristics' field of the section 174 // header to see if the section contains instructions. 175 if (memcmp(section->name, ".text", 6) == 0) 176 has_text_section_ = true; 177 178 uint32 section_end = 179 section->file_offset_of_raw_data + section->size_of_raw_data; 180 if (section_end > detected_length) 181 detected_length = section_end; 182 } 183 184 // Pretend our in-memory copy is only as long as our detected length. 185 ReduceLength(detected_length); 186 187 if (!is_32bit()) { 188 return Bad("64 bit executables are not supported by this disassembler"); 189 } 190 191 if (!has_text_section()) { 192 return Bad("Resource-only executables are not yet supported"); 193 } 194 195 return Good(); 196 } 197 198 bool DisassemblerWin32X86::Disassemble(AssemblyProgram* target) { 199 if (!ok()) 200 return false; 201 202 target->set_image_base(image_base()); 203 204 if (!ParseAbs32Relocs()) 205 return false; 206 207 ParseRel32RelocsFromSections(); 208 209 if (!ParseFile(target)) 210 return false; 211 212 target->DefaultAssignIndexes(); 213 214 return true; 215 } 216 217 //////////////////////////////////////////////////////////////////////////////// 218 219 bool DisassemblerWin32X86::ParseRelocs(std::vector<RVA> *relocs) { 220 relocs->clear(); 221 222 size_t relocs_size = base_relocation_table_.size_; 223 if (relocs_size == 0) 224 return true; 225 226 // The format of the base relocation table is a sequence of variable sized 227 // IMAGE_BASE_RELOCATION blocks. Search for 228 // "The format of the base relocation data is somewhat quirky" 229 // at http://msdn.microsoft.com/en-us/library/ms809762.aspx 230 231 const uint8* relocs_start = RVAToPointer(base_relocation_table_.address_); 232 const uint8* relocs_end = relocs_start + relocs_size; 233 234 // Make sure entire base relocation table is within the buffer. 235 if (relocs_start < start() || 236 relocs_start >= end() || 237 relocs_end <= start() || 238 relocs_end > end()) { 239 return Bad(".relocs outside image"); 240 } 241 242 const uint8* block = relocs_start; 243 244 // Walk the variable sized blocks. 245 while (block + 8 < relocs_end) { 246 RVA page_rva = ReadU32(block, 0); 247 uint32 size = ReadU32(block, 4); 248 if (size < 8 || // Size includes header ... 249 size % 4 != 0) // ... and is word aligned. 250 return Bad("unreasonable relocs block"); 251 252 const uint8* end_entries = block + size; 253 254 if (end_entries <= block || 255 end_entries <= start() || 256 end_entries > end()) 257 return Bad(".relocs block outside image"); 258 259 // Walk through the two-byte entries. 260 for (const uint8* p = block + 8; p < end_entries; p += 2) { 261 uint16 entry = ReadU16(p, 0); 262 int type = entry >> 12; 263 int offset = entry & 0xFFF; 264 265 RVA rva = page_rva + offset; 266 if (type == 3) { // IMAGE_REL_BASED_HIGHLOW 267 relocs->push_back(rva); 268 } else if (type == 0) { // IMAGE_REL_BASED_ABSOLUTE 269 // Ignore, used as padding. 270 } else { 271 // Does not occur in Windows x86 executables. 272 return Bad("unknown type of reloc"); 273 } 274 } 275 276 block += size; 277 } 278 279 std::sort(relocs->begin(), relocs->end()); 280 281 return true; 282 } 283 284 const Section* DisassemblerWin32X86::RVAToSection(RVA rva) const { 285 for (int i = 0; i < number_of_sections_; i++) { 286 const Section* section = §ions_[i]; 287 uint32 offset = rva - section->virtual_address; 288 if (offset < section->virtual_size) { 289 return section; 290 } 291 } 292 return NULL; 293 } 294 295 int DisassemblerWin32X86::RVAToFileOffset(RVA rva) const { 296 const Section* section = RVAToSection(rva); 297 if (section) { 298 uint32 offset = rva - section->virtual_address; 299 if (offset < section->size_of_raw_data) { 300 return section->file_offset_of_raw_data + offset; 301 } else { 302 return kNoOffset; // In section but not in file (e.g. uninit data). 303 } 304 } 305 306 // Small RVA values point into the file header in the loaded image. 307 // RVA 0 is the module load address which Windows uses as the module handle. 308 // RVA 2 sometimes occurs, I'm not sure what it is, but it would map into the 309 // DOS header. 310 if (rva == 0 || rva == 2) 311 return rva; 312 313 NOTREACHED(); 314 return kNoOffset; 315 } 316 317 const uint8* DisassemblerWin32X86::RVAToPointer(RVA rva) const { 318 int file_offset = RVAToFileOffset(rva); 319 if (file_offset == kNoOffset) 320 return NULL; 321 else 322 return OffsetToPointer(file_offset); 323 } 324 325 std::string DisassemblerWin32X86::SectionName(const Section* section) { 326 if (section == NULL) 327 return "<none>"; 328 char name[9]; 329 memcpy(name, section->name, 8); 330 name[8] = '\0'; // Ensure termination. 331 return name; 332 } 333 334 CheckBool DisassemblerWin32X86::ParseFile(AssemblyProgram* program) { 335 // Walk all the bytes in the file, whether or not in a section. 336 uint32 file_offset = 0; 337 while (file_offset < length()) { 338 const Section* section = FindNextSection(file_offset); 339 if (section == NULL) { 340 // No more sections. There should not be extra stuff following last 341 // section. 342 // ParseNonSectionFileRegion(file_offset, pe_info().length(), program); 343 break; 344 } 345 if (file_offset < section->file_offset_of_raw_data) { 346 uint32 section_start_offset = section->file_offset_of_raw_data; 347 if(!ParseNonSectionFileRegion(file_offset, section_start_offset, 348 program)) 349 return false; 350 351 file_offset = section_start_offset; 352 } 353 uint32 end = file_offset + section->size_of_raw_data; 354 if (!ParseFileRegion(section, file_offset, end, program)) 355 return false; 356 file_offset = end; 357 } 358 359 #if COURGETTE_HISTOGRAM_TARGETS 360 HistogramTargets("abs32 relocs", abs32_target_rvas_); 361 HistogramTargets("rel32 relocs", rel32_target_rvas_); 362 #endif 363 364 return true; 365 } 366 367 bool DisassemblerWin32X86::ParseAbs32Relocs() { 368 abs32_locations_.clear(); 369 if (!ParseRelocs(&abs32_locations_)) 370 return false; 371 372 std::sort(abs32_locations_.begin(), abs32_locations_.end()); 373 374 #if COURGETTE_HISTOGRAM_TARGETS 375 for (size_t i = 0; i < abs32_locations_.size(); ++i) { 376 RVA rva = abs32_locations_[i]; 377 // The 4 bytes at the relocation are a reference to some address. 378 uint32 target_address = Read32LittleEndian(RVAToPointer(rva)); 379 ++abs32_target_rvas_[target_address - image_base()]; 380 } 381 #endif 382 return true; 383 } 384 385 void DisassemblerWin32X86::ParseRel32RelocsFromSections() { 386 uint32 file_offset = 0; 387 while (file_offset < length()) { 388 const Section* section = FindNextSection(file_offset); 389 if (section == NULL) 390 break; 391 if (file_offset < section->file_offset_of_raw_data) 392 file_offset = section->file_offset_of_raw_data; 393 ParseRel32RelocsFromSection(section); 394 file_offset += section->size_of_raw_data; 395 } 396 std::sort(rel32_locations_.begin(), rel32_locations_.end()); 397 398 #if COURGETTE_HISTOGRAM_TARGETS 399 VLOG(1) << "abs32_locations_ " << abs32_locations_.size() 400 << "\nrel32_locations_ " << rel32_locations_.size() 401 << "\nabs32_target_rvas_ " << abs32_target_rvas_.size() 402 << "\nrel32_target_rvas_ " << rel32_target_rvas_.size(); 403 404 int common = 0; 405 std::map<RVA, int>::iterator abs32_iter = abs32_target_rvas_.begin(); 406 std::map<RVA, int>::iterator rel32_iter = rel32_target_rvas_.begin(); 407 while (abs32_iter != abs32_target_rvas_.end() && 408 rel32_iter != rel32_target_rvas_.end()) { 409 if (abs32_iter->first < rel32_iter->first) 410 ++abs32_iter; 411 else if (rel32_iter->first < abs32_iter->first) 412 ++rel32_iter; 413 else { 414 ++common; 415 ++abs32_iter; 416 ++rel32_iter; 417 } 418 } 419 VLOG(1) << "common " << common; 420 #endif 421 } 422 423 void DisassemblerWin32X86::ParseRel32RelocsFromSection(const Section* section) { 424 // TODO(sra): use characteristic. 425 bool isCode = strcmp(section->name, ".text") == 0; 426 if (!isCode) 427 return; 428 429 uint32 start_file_offset = section->file_offset_of_raw_data; 430 uint32 end_file_offset = start_file_offset + section->size_of_raw_data; 431 RVA relocs_start_rva = base_relocation_table().address_; 432 433 const uint8* start_pointer = OffsetToPointer(start_file_offset); 434 const uint8* end_pointer = OffsetToPointer(end_file_offset); 435 436 RVA start_rva = FileOffsetToRVA(start_file_offset); 437 RVA end_rva = start_rva + section->virtual_size; 438 439 // Quick way to convert from Pointer to RVA within a single Section is to 440 // subtract 'pointer_to_rva'. 441 const uint8* const adjust_pointer_to_rva = start_pointer - start_rva; 442 443 std::vector<RVA>::iterator abs32_pos = abs32_locations_.begin(); 444 445 // Find the rel32 relocations. 446 const uint8* p = start_pointer; 447 while (p < end_pointer) { 448 RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva); 449 if (current_rva == relocs_start_rva) { 450 uint32 relocs_size = base_relocation_table().size_; 451 if (relocs_size) { 452 p += relocs_size; 453 continue; 454 } 455 } 456 457 //while (abs32_pos != abs32_locations_.end() && *abs32_pos < current_rva) 458 // ++abs32_pos; 459 460 // Heuristic discovery of rel32 locations in instruction stream: are the 461 // next few bytes the start of an instruction containing a rel32 462 // addressing mode? 463 const uint8* rel32 = NULL; 464 465 if (p + 5 <= end_pointer) { 466 if (*p == 0xE8 || *p == 0xE9) { // jmp rel32 and call rel32 467 rel32 = p + 1; 468 } 469 } 470 if (p + 6 <= end_pointer) { 471 if (*p == 0x0F && (*(p+1) & 0xF0) == 0x80) { // Jcc long form 472 if (p[1] != 0x8A && p[1] != 0x8B) // JPE/JPO unlikely 473 rel32 = p + 2; 474 } 475 } 476 if (rel32) { 477 RVA rel32_rva = static_cast<RVA>(rel32 - adjust_pointer_to_rva); 478 479 // Is there an abs32 reloc overlapping the candidate? 480 while (abs32_pos != abs32_locations_.end() && *abs32_pos < rel32_rva - 3) 481 ++abs32_pos; 482 // Now: (*abs32_pos > rel32_rva - 4) i.e. the lowest addressed 4-byte 483 // region that could overlap rel32_rva. 484 if (abs32_pos != abs32_locations_.end()) { 485 if (*abs32_pos < rel32_rva + 4) { 486 // Beginning of abs32 reloc is before end of rel32 reloc so they 487 // overlap. Skip four bytes past the abs32 reloc. 488 p += (*abs32_pos + 4) - current_rva; 489 continue; 490 } 491 } 492 493 RVA target_rva = rel32_rva + 4 + Read32LittleEndian(rel32); 494 // To be valid, rel32 target must be within image, and within this 495 // section. 496 if (IsValidRVA(target_rva) && 497 start_rva <= target_rva && target_rva < end_rva) { 498 rel32_locations_.push_back(rel32_rva); 499 #if COURGETTE_HISTOGRAM_TARGETS 500 ++rel32_target_rvas_[target_rva]; 501 #endif 502 p = rel32 + 4; 503 continue; 504 } 505 } 506 p += 1; 507 } 508 } 509 510 CheckBool DisassemblerWin32X86::ParseNonSectionFileRegion( 511 uint32 start_file_offset, 512 uint32 end_file_offset, 513 AssemblyProgram* program) { 514 if (incomplete_disassembly_) 515 return true; 516 517 const uint8* start = OffsetToPointer(start_file_offset); 518 const uint8* end = OffsetToPointer(end_file_offset); 519 520 const uint8* p = start; 521 522 while (p < end) { 523 if (!program->EmitByteInstruction(*p)) 524 return false; 525 ++p; 526 } 527 528 return true; 529 } 530 531 CheckBool DisassemblerWin32X86::ParseFileRegion( 532 const Section* section, 533 uint32 start_file_offset, uint32 end_file_offset, 534 AssemblyProgram* program) { 535 RVA relocs_start_rva = base_relocation_table().address_; 536 537 const uint8* start_pointer = OffsetToPointer(start_file_offset); 538 const uint8* end_pointer = OffsetToPointer(end_file_offset); 539 540 RVA start_rva = FileOffsetToRVA(start_file_offset); 541 RVA end_rva = start_rva + section->virtual_size; 542 543 // Quick way to convert from Pointer to RVA within a single Section is to 544 // subtract 'pointer_to_rva'. 545 const uint8* const adjust_pointer_to_rva = start_pointer - start_rva; 546 547 std::vector<RVA>::iterator rel32_pos = rel32_locations_.begin(); 548 std::vector<RVA>::iterator abs32_pos = abs32_locations_.begin(); 549 550 if (!program->EmitOriginInstruction(start_rva)) 551 return false; 552 553 const uint8* p = start_pointer; 554 555 while (p < end_pointer) { 556 RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva); 557 558 // The base relocation table is usually in the .relocs section, but it could 559 // actually be anywhere. Make sure we skip it because we will regenerate it 560 // during assembly. 561 if (current_rva == relocs_start_rva) { 562 if (!program->EmitPeRelocsInstruction()) 563 return false; 564 uint32 relocs_size = base_relocation_table().size_; 565 if (relocs_size) { 566 p += relocs_size; 567 continue; 568 } 569 } 570 571 while (abs32_pos != abs32_locations_.end() && *abs32_pos < current_rva) 572 ++abs32_pos; 573 574 if (abs32_pos != abs32_locations_.end() && *abs32_pos == current_rva) { 575 uint32 target_address = Read32LittleEndian(p); 576 RVA target_rva = target_address - image_base(); 577 // TODO(sra): target could be Label+offset. It is not clear how to guess 578 // which it might be. We assume offset==0. 579 if (!program->EmitAbs32(program->FindOrMakeAbs32Label(target_rva))) 580 return false; 581 p += 4; 582 continue; 583 } 584 585 while (rel32_pos != rel32_locations_.end() && *rel32_pos < current_rva) 586 ++rel32_pos; 587 588 if (rel32_pos != rel32_locations_.end() && *rel32_pos == current_rva) { 589 RVA target_rva = current_rva + 4 + Read32LittleEndian(p); 590 if (!program->EmitRel32(program->FindOrMakeRel32Label(target_rva))) 591 return false; 592 p += 4; 593 continue; 594 } 595 596 if (incomplete_disassembly_) { 597 if ((abs32_pos == abs32_locations_.end() || end_rva <= *abs32_pos) && 598 (rel32_pos == rel32_locations_.end() || end_rva <= *rel32_pos) && 599 (end_rva <= relocs_start_rva || current_rva >= relocs_start_rva)) { 600 // No more relocs in this section, don't bother encoding bytes. 601 break; 602 } 603 } 604 605 if (!program->EmitByteInstruction(*p)) 606 return false; 607 p += 1; 608 } 609 610 return true; 611 } 612 613 #if COURGETTE_HISTOGRAM_TARGETS 614 // Histogram is printed to std::cout. It is purely for debugging the algorithm 615 // and is only enabled manually in 'exploration' builds. I don't want to add 616 // command-line configuration for this feature because this code has to be 617 // small, which means compiled-out. 618 void DisassemblerWin32X86::HistogramTargets(const char* kind, 619 const std::map<RVA, int>& map) { 620 int total = 0; 621 std::map<int, std::vector<RVA> > h; 622 for (std::map<RVA, int>::const_iterator p = map.begin(); 623 p != map.end(); 624 ++p) { 625 h[p->second].push_back(p->first); 626 total += p->second; 627 } 628 629 std::cout << total << " " << kind << " to " 630 << map.size() << " unique targets" << std::endl; 631 632 std::cout << "indegree: #targets-with-indegree (example)" << std::endl; 633 const int kFirstN = 15; 634 bool someSkipped = false; 635 int index = 0; 636 for (std::map<int, std::vector<RVA> >::reverse_iterator p = h.rbegin(); 637 p != h.rend(); 638 ++p) { 639 ++index; 640 if (index <= kFirstN || p->first <= 3) { 641 if (someSkipped) { 642 std::cout << "..." << std::endl; 643 } 644 size_t count = p->second.size(); 645 std::cout << std::dec << p->first << ": " << count; 646 if (count <= 2) { 647 for (size_t i = 0; i < count; ++i) 648 std::cout << " " << DescribeRVA(p->second[i]); 649 } 650 std::cout << std::endl; 651 someSkipped = false; 652 } else { 653 someSkipped = true; 654 } 655 } 656 } 657 #endif // COURGETTE_HISTOGRAM_TARGETS 658 659 660 // DescribeRVA is for debugging only. I would put it under #ifdef DEBUG except 661 // that during development I'm finding I need to call it when compiled in 662 // Release mode. Hence: 663 // TODO(sra): make this compile only for debug mode. 664 std::string DisassemblerWin32X86::DescribeRVA(RVA rva) const { 665 const Section* section = RVAToSection(rva); 666 std::ostringstream s; 667 s << std::hex << rva; 668 if (section) { 669 s << " ("; 670 s << SectionName(section) << "+" 671 << std::hex << (rva - section->virtual_address) 672 << ")"; 673 } 674 return s.str(); 675 } 676 677 const Section* DisassemblerWin32X86::FindNextSection(uint32 fileOffset) const { 678 const Section* best = 0; 679 for (int i = 0; i < number_of_sections_; i++) { 680 const Section* section = §ions_[i]; 681 if (section->size_of_raw_data > 0) { // i.e. has data in file. 682 if (fileOffset <= section->file_offset_of_raw_data) { 683 if (best == 0 || 684 section->file_offset_of_raw_data < best->file_offset_of_raw_data) { 685 best = section; 686 } 687 } 688 } 689 } 690 return best; 691 } 692 693 RVA DisassemblerWin32X86::FileOffsetToRVA(uint32 file_offset) const { 694 for (int i = 0; i < number_of_sections_; i++) { 695 const Section* section = §ions_[i]; 696 uint32 offset = file_offset - section->file_offset_of_raw_data; 697 if (offset < section->size_of_raw_data) { 698 return section->virtual_address + offset; 699 } 700 } 701 return 0; 702 } 703 704 bool DisassemblerWin32X86::ReadDataDirectory( 705 int index, 706 ImageDataDirectory* directory) { 707 708 if (index < number_of_data_directories_) { 709 size_t offset = index * 8 + offset_of_data_directories_; 710 if (offset >= size_of_optional_header_) 711 return Bad("number of data directories inconsistent"); 712 const uint8* data_directory = optional_header_ + offset; 713 if (data_directory < start() || 714 data_directory + 8 >= end()) 715 return Bad("data directory outside image"); 716 RVA rva = ReadU32(data_directory, 0); 717 size_t size = ReadU32(data_directory, 4); 718 if (size > size_of_image_) 719 return Bad("data directory size too big"); 720 721 // TODO(sra): validate RVA. 722 directory->address_ = rva; 723 directory->size_ = static_cast<uint32>(size); 724 return true; 725 } else { 726 directory->address_ = 0; 727 directory->size_ = 0; 728 return true; 729 } 730 } 731 732 } // namespace courgette 733