rel32_finder.h 9.7 KB

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