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_REL32_FINDER_H_
6 #define COMPONENTS_ZUCCHINI_REL32_FINDER_H_
7 
8 #include <stddef.h>
9 
10 #include <vector>
11 
12 #include "components/zucchini/address_translator.h"
13 #include "components/zucchini/arm_utils.h"
14 #include "components/zucchini/buffer_view.h"
15 #include "components/zucchini/image_utils.h"
16 
17 namespace zucchini {
18 
19 // See README.md for definitions on abs32 and rel32 references. The following
20 // are assumed:
21 // * Abs32 reference bodies have fixed widths.
22 // * Rel32 locations can be identified by heuristically disassembling machine
23 //   code, and errors are tolerated.
24 // * The collection all abs32 and rel32 reference bodies do not overlap.
25 
26 // A class to visit non-empty contiguous gaps in |region| that lie outside of
27 // |abs32_locations| elements, each with a body that spans |abs32_width_| bytes.
28 // For example, given:
29 //   region = [base_ + 4, base_ + 26),
30 //   abs32_locations = {2, 6, 15, 20, 27},
31 //   abs32_width_ = 4,
32 // the following is obtained:
33 //             111111111122222222223   -> offsets
34 //   0123456789012345678901234567890
35 //   ....**********************.....   -> region = *
36 //     ^   ^        ^    ^      ^      -> abs32 locations
37 //     aaaaaaaa     aaaa aaaa   aaaa   -> abs32 bodies
38 //   ....------*****----*----**.....   -> regions excluding abs32 -> 3 gaps
39 // The resulting gaps (non-empty, so [6, 6) is excluded) are:
40 //   [10, 15), [19, 20), [24, 26).
41 // These gaps can then be passed to Rel32Finder (below) to find rel32 references
42 // with bodies that are guaranteed to not overlap with any abs32 bodies.
43 class Abs32GapFinder {
44  public:
45   // |abs32_locations| is a sorted list of non-overlapping abs32 locations in
46   // |image|, each spanning |abs32_width| bytes. Gaps are searched in |region|,
47   // which must be part of |image|.
48   Abs32GapFinder(ConstBufferView image,
49                  ConstBufferView region,
50                  const std::vector<offset_t>& abs32_locations,
51                  size_t abs32_width);
52   Abs32GapFinder(const Abs32GapFinder&) = delete;
53   const Abs32GapFinder& operator=(const Abs32GapFinder&) = delete;
54   ~Abs32GapFinder();
55 
56   // Searches for the next available gap, and returns successfulness.
57   bool FindNext();
58 
59   // Returns the cached result from the last successful FindNext().
GetGap()60   ConstBufferView GetGap() const { return gap_; }
61 
62  private:
63   const ConstBufferView::const_iterator base_;
64   const ConstBufferView::const_iterator region_end_;
65   ConstBufferView::const_iterator cur_lo_;
66   const std::vector<offset_t>::const_iterator abs32_end_;
67   std::vector<offset_t>::const_iterator abs32_cur_;
68   const size_t abs32_width_;
69   ConstBufferView gap_;
70 };
71 
72 // A class to scan regions within an image to find successive rel32 references.
73 // Architecture-specific parsing and result extraction are delegated to
74 // inherited classes (say, Rel32Finder_Impl). Sample extraction loop, combined
75 // with Abs32GapFinder usage:
76 //
77 //   Abs32GapFinder gap_finder(...);
78 //   Rel32Finder_Impl finder(...);
79 //   while (gap_finder.FindNext()) {
80 //     rel_finder.SetRegion(gap_finder.GetGap());
81 //     while (rel_finder.FindNext()) {
82 //       auto rel32 = rel_finder.GetRel32();  // In Rel32Finder_Impl.
83 //       if (architecture_specific_validation(rel32)) {
84 //         rel_finder.Accept();
85 //         // Store rel32.
86 //       }
87 //     }
88 //   }
89 class Rel32Finder {
90  public:
91   Rel32Finder(ConstBufferView image, const AddressTranslator& translator);
92   Rel32Finder(const Rel32Finder&) = delete;
93   const Rel32Finder& operator=(const Rel32Finder&) = delete;
94   virtual ~Rel32Finder();
95 
96   // Assigns the scan |region| for rel32 references to enable FindNext() use.
97   void SetRegion(ConstBufferView region);
98 
99   // Scans for the next rel32 reference, and returns whether any is found, so a
100   // "while" loop can be used for iterative rel32 extraction. The results are
101   // cached in Rel32Finder_Impl and obtained by Rel32Finder_Impl::GetRel32().
102   bool FindNext();
103 
104   // When a rel32 reference is found, the caller needs to decide whether to keep
105   // the result (perhaps following more validation). If it decides to keep the
106   // result, then it must call Accept(), so the next call to FindNext() can skip
107   // the accepted rel32 reference.
108   void Accept();
109 
110   // Accessors for unittest.
accept_it()111   ConstBufferView::const_iterator accept_it() const { return accept_it_; }
region()112   ConstBufferView region() const { return region_; }
113 
114  protected:
115   // Alternatives for where to continue the next scan when a rel32 reference is
116   // found. nulls indicate that no rel32 references remain.
117   struct NextIterators {
118     // The next iterator if the caller does not call Accept().
119     ConstBufferView::const_iterator reject;
120 
121     // The next iterator if the caller calls Accept().
122     ConstBufferView::const_iterator accept;
123   };
124 
125   // Detects and extracts architecture-specific rel32 reference. For each one
126   // found, the implementation should cache the necessary data to be retrieved
127   // via accessors. Returns a NextIterators that stores alternatives for where
128   // to continue the scan. If no rel32 reference is found then the returned
129   // NextIterators are nulls.
130   virtual NextIterators Scan(ConstBufferView region) = 0;
131 
132   const ConstBufferView image_;
133   AddressTranslator::OffsetToRvaCache offset_to_rva_;
134 
135  private:
136   ConstBufferView region_;
137   ConstBufferView::const_iterator accept_it_ = nullptr;
138 };
139 
140 // Parsing for X86 or X64: we perform naive scan for opcodes that have rel32 as
141 // an argument, and disregard instruction alignment.
142 class Rel32FinderIntel : public Rel32Finder {
143  public:
144   Rel32FinderIntel(const Rel32FinderIntel&) = delete;
145   const Rel32FinderIntel& operator=(const Rel32FinderIntel&) = delete;
146 
147   // Struct to store GetRel32() results.
148   struct Result {
149     offset_t location;
150     rva_t target_rva;
151 
152     // Some references must have their target in the same section as location,
153     // which we use this to heuristically reject rel32 reference candidates.
154     // When true, this constraint is relaxed.
155     bool can_point_outside_section;
156   };
157 
158   using Rel32Finder::Rel32Finder;
159 
160   // Returns the cached result from the last successful FindNext().
GetRel32()161   const Result& GetRel32() { return rel32_; }
162 
163  protected:
164   // Helper for Scan() that also assigns |rel32_|.
165   Rel32Finder::NextIterators SetResult(ConstBufferView::const_iterator cursor,
166                                        uint32_t code_size,
167                                        bool can_point_outside_section);
168 
169   // Cached results.
170   Result rel32_;
171 
172   // Rel32Finder:
173   NextIterators Scan(ConstBufferView region) override = 0;
174 };
175 
176 // X86 instructions.
177 class Rel32FinderX86 : public Rel32FinderIntel {
178  public:
179   using Rel32FinderIntel::Rel32FinderIntel;
180 
181   Rel32FinderX86(const Rel32FinderX86&) = delete;
182   const Rel32FinderX86& operator=(const Rel32FinderX86&) = delete;
183 
184  private:
185   // Rel32Finder:
186   NextIterators Scan(ConstBufferView region) override;
187 };
188 
189 // X64 instructions.
190 class Rel32FinderX64 : public Rel32FinderIntel {
191  public:
192   using Rel32FinderIntel::Rel32FinderIntel;
193 
194   Rel32FinderX64(const Rel32FinderX64&) = delete;
195   const Rel32FinderX64& operator=(const Rel32FinderX64&) = delete;
196 
197  private:
198   // Rel32Finder:
199   NextIterators Scan(ConstBufferView region) override;
200 };
201 
202 // Base class for ARM (AArch32 and AArch64) instructions.
203 template <typename ADDR_TYPE>
204 class Rel32FinderArm : public Rel32Finder {
205  public:
206   struct Result {
207     offset_t location;
208     rva_t target_rva;
209     ADDR_TYPE type;
210 
211     // For testing.
212     bool operator==(const Result& other) const {
213       return location == other.location && target_rva == other.target_rva &&
214              type == other.type;
215     }
216   };
217 
218   Rel32FinderArm(ConstBufferView image, const AddressTranslator& translator);
219   Rel32FinderArm(const Rel32FinderArm&) = delete;
220   const Rel32FinderArm& operator=(const Rel32FinderArm&) = delete;
221   ~Rel32FinderArm() override;
222 
223   // Helper for Scan*() that also assigns |rel32_|.
224   NextIterators SetResult(Result&& result,
225                           ConstBufferView::const_iterator cursor,
226                           int instr_size);
227 
228   // SetResult() for end of scan.
229   NextIterators SetEmptyResult();
230 
231  protected:
232   // Cached results.
233   Result rel32_;
234 };
235 
236 // AArch32 instructions.
237 class Rel32FinderAArch32
238     : public Rel32FinderArm<AArch32Rel32Translator::AddrType> {
239  public:
240   Rel32FinderAArch32(ConstBufferView image,
241                      const AddressTranslator& translator,
242                      bool is_thumb2);
243   Rel32FinderAArch32(const Rel32FinderAArch32&) = delete;
244   const Rel32FinderAArch32& operator=(const Rel32FinderAArch32&) = delete;
245   ~Rel32FinderAArch32() override;
246 
GetRel32()247   const Result& GetRel32() const { return rel32_; }
248 
249  private:
250   // Rel32 extraction, assuming segment is in ARM mode.
251   NextIterators ScanA32(ConstBufferView region);
252 
253   // Rel32 extraction, assuming segment is in THUMB2 mode.
254   NextIterators ScanT32(ConstBufferView region);
255 
256   // Rel32Finder:
257   NextIterators Scan(ConstBufferView region) override;
258 
259   // Indicates whether segment is in THUMB2 or ARM mod. In general this can
260   // change throughout a section. However, currently we assume that this is
261   // constant for an entire section.
262   const bool is_thumb2_;
263 };
264 
265 // AArch64 instructions.
266 class Rel32FinderAArch64
267     : public Rel32FinderArm<AArch64Rel32Translator::AddrType> {
268  public:
269   Rel32FinderAArch64(ConstBufferView image,
270                      const AddressTranslator& translator);
271   Rel32FinderAArch64(const Rel32FinderAArch64&) = delete;
272   const Rel32FinderAArch64& operator=(const Rel32FinderAArch64&) = delete;
273   ~Rel32FinderAArch64() override;
274 
GetRel32()275   const Result& GetRel32() const { return rel32_; }
276 
277  private:
278   // Rel32Finder:
279   NextIterators Scan(ConstBufferView region) override;
280 };
281 
282 }  // namespace zucchini
283 
284 #endif  // COMPONENTS_ZUCCHINI_REL32_FINDER_H_
285