aboutsummaryrefslogtreecommitdiff
path: root/disassembler_win32.h
blob: dfb2533304b88b9431c502422fe6bc30ec570278 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_ZUCCHINI_DISASSEMBLER_WIN32_H_
#define COMPONENTS_ZUCCHINI_DISASSEMBLER_WIN32_H_

#include <stddef.h>
#include <stdint.h>

#include <deque>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "components/zucchini/address_translator.h"
#include "components/zucchini/buffer_view.h"
#include "components/zucchini/disassembler.h"
#include "components/zucchini/image_utils.h"
#include "components/zucchini/type_win_pe.h"

namespace zucchini {

class Rel32FinderX86;
class Rel32FinderX64;

struct Win32X86Traits {
  static constexpr uint16_t kVersion = 1;
  static constexpr Bitness kBitness = kBit32;
  static constexpr ExecutableType kExeType = kExeTypeWin32X86;
  enum : uint16_t { kMagic = 0x10B };
  enum : uint16_t { kRelocType = 3 };
  enum : uint32_t { kVAWidth = 4 };
  static const char kExeTypeString[];

  using ImageOptionalHeader = pe::ImageOptionalHeader;
  using RelFinder = Rel32FinderX86;
  using Address = uint32_t;
};

struct Win32X64Traits {
  static constexpr uint16_t kVersion = 1;
  static constexpr Bitness kBitness = kBit64;
  static constexpr ExecutableType kExeType = kExeTypeWin32X64;
  enum : uint16_t { kMagic = 0x20B };
  enum : uint16_t { kRelocType = 10 };
  enum : uint32_t { kVAWidth = 8 };
  static const char kExeTypeString[];

  using ImageOptionalHeader = pe::ImageOptionalHeader64;
  using RelFinder = Rel32FinderX64;
  using Address = uint64_t;
};

template <class TRAITS>
class DisassemblerWin32 : public Disassembler {
 public:
  using Traits = TRAITS;
  static constexpr uint16_t kVersion = Traits::kVersion;
  enum ReferenceType : uint8_t { kReloc, kAbs32, kRel32, kTypeCount };

  // Applies quick checks to determine whether |image| *may* point to the start
  // of an executable. Returns true iff the check passes.
  static bool QuickDetect(ConstBufferView image);

  DisassemblerWin32();
  DisassemblerWin32(const DisassemblerWin32&) = delete;
  const DisassemblerWin32& operator=(const DisassemblerWin32&) = delete;
  ~DisassemblerWin32() override;

  // Disassembler:
  ExecutableType GetExeType() const override;
  std::string GetExeTypeString() const override;
  std::vector<ReferenceGroup> MakeReferenceGroups() const override;

  // Functions that return reader / writer for references.
  std::unique_ptr<ReferenceReader> MakeReadRelocs(offset_t lo, offset_t hi);
  std::unique_ptr<ReferenceReader> MakeReadAbs32(offset_t lo, offset_t hi);
  std::unique_ptr<ReferenceReader> MakeReadRel32(offset_t lo, offset_t hi);
  std::unique_ptr<ReferenceWriter> MakeWriteRelocs(MutableBufferView image);
  std::unique_ptr<ReferenceWriter> MakeWriteAbs32(MutableBufferView image);
  std::unique_ptr<ReferenceWriter> MakeWriteRel32(MutableBufferView image);

 private:
  friend Disassembler;

  // Disassembler:
  bool Parse(ConstBufferView image) override;

  // Parses the file header. Returns true iff successful.
  bool ParseHeader();

  // Parsers to extract references. These are lazily called, and return whether
  // parsing was successful (failures are non-fatal).
  bool ParseAndStoreRelocBlocks();
  bool ParseAndStoreAbs32();
  bool ParseAndStoreRel32();

  // In-memory copy of sections.
  std::vector<pe::ImageSectionHeader> sections_;

  // Image base address to translate between RVA and VA.
  typename Traits::Address image_base_ = 0;

  // Pointer to data Directory entry of the relocation table.
  const pe::ImageDataDirectory* base_relocation_table_ = nullptr;

  // Translator between offsets and RVAs.
  AddressTranslator translator_;

  // Reference storage.
  BufferRegion reloc_region_ = {kInvalidOffset, 0U};
  std::vector<offset_t> reloc_block_offsets_;
  offset_t reloc_end_ = 0;
  std::vector<offset_t> abs32_locations_;
  // Using std::deque to reduce peak memory footprint.
  std::deque<offset_t> rel32_locations_;

  // Initialization states of reference storage, used for lazy initialization.
  // TODO(huangs): Investigate whether lazy initialization is useful for memory
  // reduction. This is a carryover from Courgette. To be sure we should run
  // experiment after Zucchini is able to do ensemble patching.
  bool has_parsed_relocs_ = false;
  bool has_parsed_abs32_ = false;
  bool has_parsed_rel32_ = false;
};

using DisassemblerWin32X86 = DisassemblerWin32<Win32X86Traits>;
using DisassemblerWin32X64 = DisassemblerWin32<Win32X64Traits>;

}  // namespace zucchini

#endif  // COMPONENTS_ZUCCHINI_DISASSEMBLER_WIN32_H_