reloc_win32_unittest.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  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. #include "components/zucchini/reloc_win32.h"
  5. #include <stdint.h>
  6. #include <algorithm>
  7. #include <memory>
  8. #include <string>
  9. #include <utility>
  10. #include <vector>
  11. #include "base/numerics/safe_conversions.h"
  12. #include "base/test/gtest_util.h"
  13. #include "components/zucchini/address_translator.h"
  14. #include "components/zucchini/algorithm.h"
  15. #include "components/zucchini/image_utils.h"
  16. #include "components/zucchini/test_utils.h"
  17. #include "testing/gtest/include/gtest/gtest.h"
  18. namespace zucchini {
  19. class RelocUtilsWin32Test : public testing::Test {
  20. protected:
  21. using Units = std::vector<RelocUnitWin32>;
  22. RelocUtilsWin32Test() {}
  23. // Resets all tester data, calls RelocRvaReaderWin32::FindRelocBlocks(), and
  24. // returns its results.
  25. bool Initialize(const std::vector<uint8_t>& image_raw,
  26. BufferRegion reloc_region) {
  27. image_ = BufferSource(image_raw.data(), image_raw.size());
  28. reloc_region_ = reloc_region;
  29. return RelocRvaReaderWin32::FindRelocBlocks(image_, reloc_region_,
  30. &reloc_block_offsets_);
  31. }
  32. // Uses RelocRvaReaderWin32 to get all relocs, returned as Units.
  33. Units EmitAll(offset_t lo, offset_t hi) {
  34. RelocRvaReaderWin32 reader(image_, reloc_region_, reloc_block_offsets_, lo,
  35. hi);
  36. Units units;
  37. for (auto unit = reader.GetNext(); unit.has_value();
  38. unit = reader.GetNext()) {
  39. units.push_back(unit.value());
  40. }
  41. return units;
  42. }
  43. ConstBufferView image_;
  44. BufferRegion reloc_region_;
  45. std::vector<uint32_t> reloc_block_offsets_;
  46. };
  47. TEST_F(RelocUtilsWin32Test, RvaReaderEmpty) {
  48. {
  49. std::vector<uint8_t> image_raw = ParseHexString("");
  50. EXPECT_TRUE(Initialize(image_raw, {0U, 0U}));
  51. EXPECT_EQ(std::vector<uint32_t>(), reloc_block_offsets_); // Nothing.
  52. EXPECT_EQ(Units(), EmitAll(0U, 0U));
  53. }
  54. {
  55. std::vector<uint8_t> image_raw = ParseHexString("AA BB CC DD EE FF");
  56. EXPECT_TRUE(Initialize(image_raw, {2U, 0U}));
  57. EXPECT_EQ(std::vector<uint32_t>(), reloc_block_offsets_); // Nothing.
  58. EXPECT_EQ(Units(), EmitAll(2U, 2U));
  59. }
  60. {
  61. std::vector<uint8_t> image_raw = ParseHexString("00 C0 00 00 08 00 00 00");
  62. EXPECT_TRUE(Initialize(image_raw, {0U, image_raw.size()}));
  63. EXPECT_EQ(std::vector<uint32_t>({0U}),
  64. reloc_block_offsets_); // Empty block.
  65. EXPECT_EQ(Units(), EmitAll(0U, 8U));
  66. }
  67. }
  68. TEST_F(RelocUtilsWin32Test, RvaReaderBad) {
  69. std::string test_cases[] = {
  70. "00 C0 00 00 07 00 00", // Header too small.
  71. "00 C0 00 00 08 00 00", // Header too small, lies about size.
  72. "00 C0 00 00 0A 00 00 00 66 31", // Odd number of units.
  73. "00 C0 00 00 0C 00 00 00 66 31 88 31 FF", // Trailing data.
  74. };
  75. for (const std::string& test_case : test_cases) {
  76. std::vector<uint8_t> image_raw = ParseHexString(test_case);
  77. EXPECT_FALSE(Initialize(image_raw, {0U, image_raw.size()}));
  78. }
  79. }
  80. TEST_F(RelocUtilsWin32Test, RvaReaderSingle) {
  81. // Block 0: All type 0x3: {0xC166, 0xC288, 0xC342, (padding) 0xCFFF}.
  82. std::vector<uint8_t> image_raw = ParseHexString(
  83. "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF "
  84. "00 C0 00 00 10 00 00 00 66 31 88 32 42 33 FF 0F "
  85. "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF");
  86. constexpr offset_t kBlock0 = 16U;
  87. Units exp0 = {{3, kBlock0 + 8U, 0xC166U},
  88. {3, kBlock0 + 10U, 0xC288U},
  89. {3, kBlock0 + 12U, 0xC342U},
  90. {0, kBlock0 + 14U, 0xCFFFU}};
  91. EXPECT_TRUE(Initialize(image_raw, {16U, 16U}));
  92. EXPECT_EQ(exp0, EmitAll(kBlock0, kBlock0 + 16U));
  93. EXPECT_EQ(Units(), EmitAll(kBlock0, kBlock0));
  94. EXPECT_EQ(Units(), EmitAll(kBlock0, kBlock0 + 8U));
  95. EXPECT_EQ(Units(), EmitAll(kBlock0, kBlock0 + 9U));
  96. EXPECT_EQ(Sub(exp0, 0, 1), EmitAll(kBlock0, kBlock0 + 10U));
  97. EXPECT_EQ(Sub(exp0, 0, 1), EmitAll(kBlock0 + 8U, kBlock0 + 10U));
  98. EXPECT_EQ(Units(), EmitAll(kBlock0 + 9U, kBlock0 + 10U));
  99. EXPECT_EQ(Sub(exp0, 0, 3), EmitAll(kBlock0, kBlock0 + 15U));
  100. EXPECT_EQ(Sub(exp0, 2, 3), EmitAll(kBlock0 + 11U, kBlock0 + 15U));
  101. }
  102. TEST_F(RelocUtilsWin32Test, RvaReaderMulti) {
  103. // The sample image encodes 3 reloc blocks:
  104. // Block 0: All type 0x3: {0xC166, 0xC288, 0xC344, (padding) 0xCFFF}.
  105. // Block 1: All type 0x3: {0x12166, 0x12288}.
  106. // Block 2: All type 0xA: {0x24000, 0x24010, 0x24020, 0x24028, 0x24A3C,
  107. // 0x24170}.
  108. std::vector<uint8_t> image_raw = ParseHexString(
  109. "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF "
  110. "00 C0 00 00 10 00 00 00 66 31 88 32 42 33 FF 0F "
  111. "00 20 01 00 0C 00 00 00 66 31 88 32 "
  112. "00 40 02 00 14 00 00 00 00 A0 10 A0 20 A0 28 A0 3C A0 70 A1 "
  113. "FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF");
  114. offset_t image_size = base::checked_cast<offset_t>(image_raw.size());
  115. constexpr offset_t kBlock0 = 16U;
  116. constexpr offset_t kBlock1 = kBlock0 + 16U;
  117. constexpr offset_t kBlock2 = kBlock1 + 12U;
  118. constexpr offset_t kBlockEnd = kBlock2 + 20U;
  119. Units exp0 = {{3, kBlock0 + 8U, 0xC166U},
  120. {3, kBlock0 + 10U, 0xC288U},
  121. {3, kBlock0 + 12U, 0xC342U},
  122. {0, kBlock0 + 14U, 0xCFFFU}};
  123. Units exp1 = {{3, kBlock0 + 24U, 0x12166U}, {3, kBlock0 + 26U, 0x12288U}};
  124. Units exp2 = {{10, kBlock0 + 36U, 0x24000U}, {10, kBlock0 + 38U, 0x24010U},
  125. {10, kBlock0 + 40U, 0x24020U}, {10, kBlock0 + 42U, 0x24028U},
  126. {10, kBlock0 + 44U, 0x2403CU}, {10, kBlock0 + 46U, 0x24170U}};
  127. EXPECT_TRUE(Initialize(image_raw, {kBlock0, kBlockEnd - kBlock0}));
  128. EXPECT_EQ(std::vector<uint32_t>({kBlock0, kBlock1, kBlock2}),
  129. reloc_block_offsets_);
  130. // Everything.
  131. EXPECT_EQ(Cat(Cat(exp0, exp1), exp2), EmitAll(kBlock0, kBlockEnd));
  132. EXPECT_EQ(Cat(Cat(exp0, exp1), exp2), EmitAll(0, image_size));
  133. // Entire blocks.
  134. EXPECT_EQ(exp0, EmitAll(kBlock0, kBlock1));
  135. EXPECT_EQ(exp1, EmitAll(kBlock1, kBlock2));
  136. EXPECT_EQ(exp2, EmitAll(kBlock2, kBlockEnd));
  137. EXPECT_EQ(Units(), EmitAll(0, kBlock0));
  138. EXPECT_EQ(Units(), EmitAll(kBlockEnd, image_size));
  139. // Within blocks, clipped at boundaries.
  140. EXPECT_EQ(exp0, EmitAll(kBlock0 + 5U, kBlock1));
  141. EXPECT_EQ(exp0, EmitAll(kBlock0 + 8U, kBlock1));
  142. EXPECT_EQ(Sub(exp0, 1, 4), EmitAll(kBlock0 + 9U, kBlock1));
  143. EXPECT_EQ(Sub(exp0, 0, 3), EmitAll(kBlock0, kBlock0 + 15U));
  144. EXPECT_EQ(Sub(exp0, 0, 3), EmitAll(kBlock0, kBlock0 + 14U));
  145. EXPECT_EQ(Sub(exp0, 0, 1), EmitAll(kBlock0 + 8U, kBlock0 + 10U));
  146. EXPECT_EQ(Sub(exp1, 1, 2), EmitAll(kBlock1 + 10U, kBlock1 + 12U));
  147. EXPECT_EQ(Sub(exp2, 2, 4), EmitAll(kBlock2 + 12U, kBlock2 + 16U));
  148. EXPECT_EQ(Units(), EmitAll(kBlock0, kBlock0));
  149. EXPECT_EQ(Units(), EmitAll(kBlock0, kBlock0 + 8U));
  150. EXPECT_EQ(Units(), EmitAll(kBlock2 + 10U, kBlock2 + 11U));
  151. EXPECT_EQ(Units(), EmitAll(kBlock2 + 11U, kBlock2 + 12U));
  152. // Across blocks.
  153. EXPECT_EQ(Cat(Cat(exp0, exp1), exp2), EmitAll(kBlock0 - 5U, kBlockEnd));
  154. EXPECT_EQ(Cat(Cat(exp0, exp1), exp2), EmitAll(kBlock0 + 6U, kBlockEnd));
  155. EXPECT_EQ(Cat(Cat(exp0, exp1), Sub(exp2, 0, 5)),
  156. EmitAll(kBlock0 + 6U, kBlock2 + 18U));
  157. EXPECT_EQ(Cat(Sub(exp0, 2, 4), Sub(exp1, 0, 1)),
  158. EmitAll(kBlock0 + 12U, kBlock1 + 10U));
  159. EXPECT_EQ(Cat(Sub(exp0, 2, 4), Sub(exp1, 0, 1)),
  160. EmitAll(kBlock0 + 11U, kBlock1 + 10U));
  161. EXPECT_EQ(Cat(Sub(exp0, 2, 4), Sub(exp1, 0, 1)),
  162. EmitAll(kBlock0 + 12U, kBlock1 + 11U));
  163. EXPECT_EQ(Sub(exp1, 1, 2), EmitAll(kBlock1 + 10U, kBlock2 + 5U));
  164. EXPECT_EQ(Cat(Sub(exp1, 1, 2), exp2), EmitAll(kBlock1 + 10U, kBlockEnd + 5));
  165. EXPECT_EQ(Units(), EmitAll(kBlock0 + 15, kBlock1 + 9));
  166. }
  167. TEST_F(RelocUtilsWin32Test, ReadWrite) {
  168. // Set up mock image: Size = 0x3000, .reloc at 0x600. RVA is 0x40000 + offset.
  169. constexpr rva_t kBaseRva = 0x40000;
  170. std::vector<uint8_t> image_data(0x3000, 0xFF);
  171. // 4 x86 relocs (xx 3x), 3 x64 relocs (xx Ax), 1 padding (xx 0X).
  172. std::vector<uint8_t> reloc_data = ParseHexString(
  173. "00 10 04 00 10 00 00 00 C0 32 18 A3 F8 A7 FF 0F "
  174. "00 20 04 00 10 00 00 00 80 A0 65 31 F8 37 BC 3A");
  175. reloc_region_ = {0x600, reloc_data.size()};
  176. std::copy(reloc_data.begin(), reloc_data.end(),
  177. image_data.begin() + reloc_region_.lo());
  178. image_ = {image_data.data(), image_data.size()};
  179. offset_t image_size = base::checked_cast<offset_t>(image_.size());
  180. AddressTranslator translator;
  181. translator.Initialize({{0, image_size, kBaseRva, image_size}});
  182. // Precompute |reloc_block_offsets_|.
  183. EXPECT_TRUE(RelocRvaReaderWin32::FindRelocBlocks(image_, reloc_region_,
  184. &reloc_block_offsets_));
  185. EXPECT_EQ(std::vector<uint32_t>({0x600U, 0x610U}), reloc_block_offsets_);
  186. // Focus on x86.
  187. constexpr uint16_t kRelocTypeX86 = 3;
  188. constexpr offset_t kVAWidthX86 = 4;
  189. // Make RelocRvaReaderWin32.
  190. RelocRvaReaderWin32 reloc_rva_reader(image_, reloc_region_,
  191. reloc_block_offsets_, 0, image_size);
  192. offset_t offset_bound = image_size - kVAWidthX86 + 1;
  193. // Make RelocReaderWin32 that wraps |reloc_rva_reader|.
  194. auto reader = std::make_unique<RelocReaderWin32>(
  195. std::move(reloc_rva_reader), kRelocTypeX86, offset_bound, translator);
  196. // Read all references and check.
  197. std::vector<Reference> refs;
  198. for (absl::optional<Reference> ref = reader->GetNext(); ref.has_value();
  199. ref = reader->GetNext()) {
  200. refs.push_back(ref.value());
  201. }
  202. std::vector<Reference> exp_refs{
  203. {0x608, 0x12C0}, {0x61A, 0x2165}, {0x61C, 0x27F8}, {0x61E, 0x2ABC}};
  204. EXPECT_EQ(exp_refs, refs);
  205. // Write reference, extract bytes and check.
  206. MutableBufferView mutable_image(&image_data[0], image_data.size());
  207. auto writer = std::make_unique<RelocWriterWin32>(
  208. kRelocTypeX86, mutable_image, reloc_region_, reloc_block_offsets_,
  209. translator);
  210. writer->PutNext({0x608, 0x1F83});
  211. std::vector<uint8_t> exp_reloc_data1 = ParseHexString(
  212. "00 10 04 00 10 00 00 00 83 3F 18 A3 F8 A7 FF 0F "
  213. "00 20 04 00 10 00 00 00 80 A0 65 31 F8 37 BC 3A");
  214. EXPECT_EQ(exp_reloc_data1,
  215. Sub(image_data, reloc_region_.lo(), reloc_region_.hi()));
  216. writer->PutNext({0x61C, 0x2950});
  217. std::vector<uint8_t> exp_reloc_data2 = ParseHexString(
  218. "00 10 04 00 10 00 00 00 83 3F 18 A3 F8 A7 FF 0F "
  219. "00 20 04 00 10 00 00 00 80 A0 65 31 50 39 BC 3A");
  220. EXPECT_EQ(exp_reloc_data2,
  221. Sub(image_data, reloc_region_.lo(), reloc_region_.hi()));
  222. }
  223. } // namespace zucchini