123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- // 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_REL32_FINDER_H_
- #define COMPONENTS_ZUCCHINI_REL32_FINDER_H_
- #include <stddef.h>
- #include <deque>
- #include "components/zucchini/address_translator.h"
- #include "components/zucchini/arm_utils.h"
- #include "components/zucchini/buffer_view.h"
- #include "components/zucchini/image_utils.h"
- namespace zucchini {
- // See README.md for definitions on abs32 and rel32 references. The following
- // are assumed:
- // * Abs32 reference bodies have fixed widths.
- // * Rel32 locations can be identified by heuristically disassembling machine
- // code, and errors are tolerated.
- // * The collection all abs32 and rel32 reference bodies do not overlap.
- // A class to visit non-empty contiguous gaps in |region| that lie outside of
- // |abs32_locations| elements, each with a body that spans |abs32_width_| bytes.
- // For example, given:
- // region = [base_ + 4, base_ + 26),
- // abs32_locations = {2, 6, 15, 20, 27},
- // abs32_width_ = 4,
- // the following is obtained:
- // 111111111122222222223 -> offsets
- // 0123456789012345678901234567890
- // ....**********************..... -> region = *
- // ^ ^ ^ ^ ^ -> abs32 locations
- // aaaaaaaa aaaa aaaa aaaa -> abs32 bodies
- // ....------*****----*----**..... -> regions excluding abs32 -> 3 gaps
- // The resulting gaps (non-empty, so [6, 6) is excluded) are:
- // [10, 15), [19, 20), [24, 26).
- // These gaps can then be passed to Rel32Finder (below) to find rel32 references
- // with bodies that are guaranteed to not overlap with any abs32 bodies.
- class Abs32GapFinder {
- public:
- // |abs32_locations| is a sorted list of non-overlapping abs32 locations in
- // |image|, each spanning |abs32_width| bytes. Gaps are searched in |region|,
- // which must be part of |image|.
- Abs32GapFinder(ConstBufferView image,
- ConstBufferView region,
- const std::deque<offset_t>& abs32_locations,
- size_t abs32_width);
- Abs32GapFinder(const Abs32GapFinder&) = delete;
- const Abs32GapFinder& operator=(const Abs32GapFinder&) = delete;
- ~Abs32GapFinder();
- // Searches for the next available gap, and returns successfulness.
- bool FindNext();
- // Returns the cached result from the last successful FindNext().
- ConstBufferView GetGap() const { return gap_; }
- private:
- const ConstBufferView::const_iterator base_;
- const ConstBufferView::const_iterator region_end_;
- ConstBufferView::const_iterator cur_lo_;
- const std::deque<offset_t>::const_iterator abs32_end_;
- std::deque<offset_t>::const_iterator abs32_cur_;
- const size_t abs32_width_;
- ConstBufferView gap_;
- };
- // A class to scan regions within an image to find successive rel32 references.
- // Architecture-specific parsing and result extraction are delegated to
- // inherited classes (say, Rel32Finder_Impl). Sample extraction loop, combined
- // with Abs32GapFinder usage:
- //
- // Abs32GapFinder gap_finder(...);
- // Rel32Finder_Impl finder(...);
- // while (gap_finder.FindNext()) {
- // rel_finder.SetRegion(gap_finder.GetGap());
- // while (rel_finder.FindNext()) {
- // auto rel32 = rel_finder.GetRel32(); // In Rel32Finder_Impl.
- // if (architecture_specific_validation(rel32)) {
- // rel_finder.Accept();
- // // Store rel32.
- // }
- // }
- // }
- class Rel32Finder {
- public:
- Rel32Finder(ConstBufferView image, const AddressTranslator& translator);
- Rel32Finder(const Rel32Finder&) = delete;
- const Rel32Finder& operator=(const Rel32Finder&) = delete;
- virtual ~Rel32Finder();
- // Assigns the scan |region| for rel32 references to enable FindNext() use.
- void SetRegion(ConstBufferView region);
- // Scans for the next rel32 reference, and returns whether any is found, so a
- // "while" loop can be used for iterative rel32 extraction. The results are
- // cached in Rel32Finder_Impl and obtained by Rel32Finder_Impl::GetRel32().
- bool FindNext();
- // When a rel32 reference is found, the caller needs to decide whether to keep
- // the result (perhaps following more validation). If it decides to keep the
- // result, then it must call Accept(), so the next call to FindNext() can skip
- // the accepted rel32 reference.
- void Accept();
- // Accessors for unittest.
- ConstBufferView::const_iterator accept_it() const { return accept_it_; }
- ConstBufferView region() const { return region_; }
- protected:
- // Alternatives for where to continue the next scan when a rel32 reference is
- // found. nulls indicate that no rel32 references remain.
- struct NextIterators {
- // The next iterator if the caller does not call Accept().
- ConstBufferView::const_iterator reject;
- // The next iterator if the caller calls Accept().
- ConstBufferView::const_iterator accept;
- };
- // Detects and extracts architecture-specific rel32 reference. For each one
- // found, the implementation should cache the necessary data to be retrieved
- // via accessors. Returns a NextIterators that stores alternatives for where
- // to continue the scan. If no rel32 reference is found then the returned
- // NextIterators are nulls.
- virtual NextIterators Scan(ConstBufferView region) = 0;
- const ConstBufferView image_;
- AddressTranslator::OffsetToRvaCache offset_to_rva_;
- private:
- ConstBufferView region_;
- ConstBufferView::const_iterator accept_it_ = nullptr;
- };
- // Parsing for X86 or X64: we perform naive scan for opcodes that have rel32 as
- // an argument, and disregard instruction alignment.
- class Rel32FinderIntel : public Rel32Finder {
- public:
- Rel32FinderIntel(const Rel32FinderIntel&) = delete;
- const Rel32FinderIntel& operator=(const Rel32FinderIntel&) = delete;
- // Struct to store GetRel32() results.
- struct Result {
- offset_t location;
- rva_t target_rva;
- // Some references must have their target in the same section as location,
- // which we use this to heuristically reject rel32 reference candidates.
- // When true, this constraint is relaxed.
- bool can_point_outside_section;
- };
- using Rel32Finder::Rel32Finder;
- // Returns the cached result from the last successful FindNext().
- const Result& GetRel32() { return rel32_; }
- protected:
- // Helper for Scan() that also assigns |rel32_|.
- Rel32Finder::NextIterators SetResult(ConstBufferView::const_iterator cursor,
- uint32_t code_size,
- bool can_point_outside_section);
- // Cached results.
- Result rel32_;
- // Rel32Finder:
- NextIterators Scan(ConstBufferView region) override = 0;
- };
- // X86 instructions.
- class Rel32FinderX86 : public Rel32FinderIntel {
- public:
- using Rel32FinderIntel::Rel32FinderIntel;
- Rel32FinderX86(const Rel32FinderX86&) = delete;
- const Rel32FinderX86& operator=(const Rel32FinderX86&) = delete;
- private:
- // Rel32Finder:
- NextIterators Scan(ConstBufferView region) override;
- };
- // X64 instructions.
- class Rel32FinderX64 : public Rel32FinderIntel {
- public:
- using Rel32FinderIntel::Rel32FinderIntel;
- Rel32FinderX64(const Rel32FinderX64&) = delete;
- const Rel32FinderX64& operator=(const Rel32FinderX64&) = delete;
- private:
- // Rel32Finder:
- NextIterators Scan(ConstBufferView region) override;
- };
- // Base class for ARM (AArch32 and AArch64) instructions.
- template <typename ADDR_TYPE>
- class Rel32FinderArm : public Rel32Finder {
- public:
- struct Result {
- offset_t location;
- rva_t target_rva;
- ADDR_TYPE type;
- // For testing.
- bool operator==(const Result& other) const {
- return location == other.location && target_rva == other.target_rva &&
- type == other.type;
- }
- };
- Rel32FinderArm(ConstBufferView image, const AddressTranslator& translator);
- Rel32FinderArm(const Rel32FinderArm&) = delete;
- const Rel32FinderArm& operator=(const Rel32FinderArm&) = delete;
- ~Rel32FinderArm() override;
- // Helper for Scan*() that also assigns |rel32_|.
- NextIterators SetResult(Result&& result,
- ConstBufferView::const_iterator cursor,
- int instr_size);
- // SetResult() for end of scan.
- NextIterators SetEmptyResult();
- protected:
- // Cached results.
- Result rel32_;
- };
- // AArch32 instructions.
- class Rel32FinderAArch32
- : public Rel32FinderArm<AArch32Rel32Translator::AddrType> {
- public:
- Rel32FinderAArch32(ConstBufferView image,
- const AddressTranslator& translator,
- bool is_thumb2);
- Rel32FinderAArch32(const Rel32FinderAArch32&) = delete;
- const Rel32FinderAArch32& operator=(const Rel32FinderAArch32&) = delete;
- ~Rel32FinderAArch32() override;
- const Result& GetRel32() const { return rel32_; }
- private:
- // Rel32 extraction, assuming segment is in ARM mode.
- NextIterators ScanA32(ConstBufferView region);
- // Rel32 extraction, assuming segment is in THUMB2 mode.
- NextIterators ScanT32(ConstBufferView region);
- // Rel32Finder:
- NextIterators Scan(ConstBufferView region) override;
- // Indicates whether segment is in THUMB2 or ARM mod. In general this can
- // change throughout a section. However, currently we assume that this is
- // constant for an entire section.
- const bool is_thumb2_;
- };
- // AArch64 instructions.
- class Rel32FinderAArch64
- : public Rel32FinderArm<AArch64Rel32Translator::AddrType> {
- public:
- Rel32FinderAArch64(ConstBufferView image,
- const AddressTranslator& translator);
- Rel32FinderAArch64(const Rel32FinderAArch64&) = delete;
- const Rel32FinderAArch64& operator=(const Rel32FinderAArch64&) = delete;
- ~Rel32FinderAArch64() override;
- const Result& GetRel32() const { return rel32_; }
- private:
- // Rel32Finder:
- NextIterators Scan(ConstBufferView region) override;
- };
- } // namespace zucchini
- #endif // COMPONENTS_ZUCCHINI_REL32_FINDER_H_
|