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