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