Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 1 | // Copyright 2017 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 | #ifndef COMPONENTS_ZUCCHINI_DISASSEMBLER_WIN32_H_ |
| 6 | #define COMPONENTS_ZUCCHINI_DISASSEMBLER_WIN32_H_ |
| 7 | |
| 8 | #include <stddef.h> |
| 9 | #include <stdint.h> |
| 10 | |
Etienne Pierre-doray | e1c6a71 | 2021-04-16 18:20:33 +0000 | [diff] [blame] | 11 | #include <deque> |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 12 | #include <memory> |
| 13 | #include <string> |
| 14 | #include <utility> |
| 15 | #include <vector> |
| 16 | |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 17 | #include "components/zucchini/address_translator.h" |
| 18 | #include "components/zucchini/buffer_view.h" |
| 19 | #include "components/zucchini/disassembler.h" |
| 20 | #include "components/zucchini/image_utils.h" |
| 21 | #include "components/zucchini/type_win_pe.h" |
| 22 | |
| 23 | namespace zucchini { |
| 24 | |
| 25 | class Rel32FinderX86; |
| 26 | class Rel32FinderX64; |
| 27 | |
| 28 | struct Win32X86Traits { |
Etienne Pierre-doray | b90a947 | 2021-10-28 21:16:04 +0000 | [diff] [blame] | 29 | static constexpr uint16_t kVersion = 1; |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 30 | static constexpr Bitness kBitness = kBit32; |
| 31 | static constexpr ExecutableType kExeType = kExeTypeWin32X86; |
| 32 | enum : uint16_t { kMagic = 0x10B }; |
| 33 | enum : uint16_t { kRelocType = 3 }; |
Samuel Huang | 607ce60 | 2018-06-13 17:47:39 +0000 | [diff] [blame] | 34 | enum : uint32_t { kVAWidth = 4 }; |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 35 | static const char kExeTypeString[]; |
| 36 | |
| 37 | using ImageOptionalHeader = pe::ImageOptionalHeader; |
| 38 | using RelFinder = Rel32FinderX86; |
| 39 | using Address = uint32_t; |
| 40 | }; |
| 41 | |
| 42 | struct Win32X64Traits { |
Etienne Pierre-doray | b90a947 | 2021-10-28 21:16:04 +0000 | [diff] [blame] | 43 | static constexpr uint16_t kVersion = 1; |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 44 | static constexpr Bitness kBitness = kBit64; |
| 45 | static constexpr ExecutableType kExeType = kExeTypeWin32X64; |
| 46 | enum : uint16_t { kMagic = 0x20B }; |
| 47 | enum : uint16_t { kRelocType = 10 }; |
Samuel Huang | 607ce60 | 2018-06-13 17:47:39 +0000 | [diff] [blame] | 48 | enum : uint32_t { kVAWidth = 8 }; |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 49 | static const char kExeTypeString[]; |
| 50 | |
| 51 | using ImageOptionalHeader = pe::ImageOptionalHeader64; |
| 52 | using RelFinder = Rel32FinderX64; |
| 53 | using Address = uint64_t; |
| 54 | }; |
| 55 | |
Samuel Huang | 3e1f64d | 2021-08-04 00:58:50 +0000 | [diff] [blame] | 56 | template <class TRAITS> |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 57 | class DisassemblerWin32 : public Disassembler { |
| 58 | public: |
Samuel Huang | 3e1f64d | 2021-08-04 00:58:50 +0000 | [diff] [blame] | 59 | using Traits = TRAITS; |
Etienne Pierre-doray | b90a947 | 2021-10-28 21:16:04 +0000 | [diff] [blame] | 60 | static constexpr uint16_t kVersion = Traits::kVersion; |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 61 | enum ReferenceType : uint8_t { kReloc, kAbs32, kRel32, kTypeCount }; |
| 62 | |
| 63 | // Applies quick checks to determine whether |image| *may* point to the start |
| 64 | // of an executable. Returns true iff the check passes. |
| 65 | static bool QuickDetect(ConstBufferView image); |
| 66 | |
| 67 | DisassemblerWin32(); |
Samuel Huang | f137bf4 | 2021-08-13 15:42:26 +0000 | [diff] [blame] | 68 | DisassemblerWin32(const DisassemblerWin32&) = delete; |
| 69 | const DisassemblerWin32& operator=(const DisassemblerWin32&) = delete; |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 70 | ~DisassemblerWin32() override; |
| 71 | |
| 72 | // Disassembler: |
| 73 | ExecutableType GetExeType() const override; |
| 74 | std::string GetExeTypeString() const override; |
| 75 | std::vector<ReferenceGroup> MakeReferenceGroups() const override; |
| 76 | |
| 77 | // Functions that return reader / writer for references. |
| 78 | std::unique_ptr<ReferenceReader> MakeReadRelocs(offset_t lo, offset_t hi); |
| 79 | std::unique_ptr<ReferenceReader> MakeReadAbs32(offset_t lo, offset_t hi); |
| 80 | std::unique_ptr<ReferenceReader> MakeReadRel32(offset_t lo, offset_t hi); |
| 81 | std::unique_ptr<ReferenceWriter> MakeWriteRelocs(MutableBufferView image); |
| 82 | std::unique_ptr<ReferenceWriter> MakeWriteAbs32(MutableBufferView image); |
| 83 | std::unique_ptr<ReferenceWriter> MakeWriteRel32(MutableBufferView image); |
| 84 | |
| 85 | private: |
| 86 | friend Disassembler; |
| 87 | |
| 88 | // Disassembler: |
| 89 | bool Parse(ConstBufferView image) override; |
| 90 | |
| 91 | // Parses the file header. Returns true iff successful. |
| 92 | bool ParseHeader(); |
| 93 | |
| 94 | // Parsers to extract references. These are lazily called, and return whether |
| 95 | // parsing was successful (failures are non-fatal). |
| 96 | bool ParseAndStoreRelocBlocks(); |
| 97 | bool ParseAndStoreAbs32(); |
| 98 | bool ParseAndStoreRel32(); |
| 99 | |
| 100 | // In-memory copy of sections. |
| 101 | std::vector<pe::ImageSectionHeader> sections_; |
| 102 | |
| 103 | // Image base address to translate between RVA and VA. |
| 104 | typename Traits::Address image_base_ = 0; |
| 105 | |
| 106 | // Pointer to data Directory entry of the relocation table. |
| 107 | const pe::ImageDataDirectory* base_relocation_table_ = nullptr; |
| 108 | |
| 109 | // Translator between offsets and RVAs. |
| 110 | AddressTranslator translator_; |
| 111 | |
| 112 | // Reference storage. |
Samuel Huang | 431d119 | 2018-12-31 19:59:22 +0000 | [diff] [blame] | 113 | BufferRegion reloc_region_ = {kInvalidOffset, 0U}; |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 114 | std::vector<offset_t> reloc_block_offsets_; |
| 115 | offset_t reloc_end_ = 0; |
| 116 | std::vector<offset_t> abs32_locations_; |
Etienne Pierre-doray | e1c6a71 | 2021-04-16 18:20:33 +0000 | [diff] [blame] | 117 | // Using std::deque to reduce peak memory footprint. |
| 118 | std::deque<offset_t> rel32_locations_; |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 119 | |
| 120 | // Initialization states of reference storage, used for lazy initialization. |
| 121 | // TODO(huangs): Investigate whether lazy initialization is useful for memory |
| 122 | // reduction. This is a carryover from Courgette. To be sure we should run |
| 123 | // experiment after Zucchini is able to do ensemble patching. |
| 124 | bool has_parsed_relocs_ = false; |
| 125 | bool has_parsed_abs32_ = false; |
| 126 | bool has_parsed_rel32_ = false; |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 127 | }; |
| 128 | |
| 129 | using DisassemblerWin32X86 = DisassemblerWin32<Win32X86Traits>; |
| 130 | using DisassemblerWin32X64 = DisassemblerWin32<Win32X64Traits>; |
| 131 | |
| 132 | } // namespace zucchini |
| 133 | |
| 134 | #endif // COMPONENTS_ZUCCHINI_DISASSEMBLER_WIN32_H_ |