Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 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 | #include "components/zucchini/abs32_utils.h" |
| 6 | |
| 7 | #include <stdint.h> |
| 8 | |
| 9 | #include <algorithm> |
| 10 | #include <string> |
| 11 | #include <utility> |
| 12 | |
| 13 | #include "base/numerics/safe_conversions.h" |
Samuel Huang | 98dd017 | 2018-10-10 15:48:10 +0000 | [diff] [blame] | 14 | #include "components/zucchini/address_translator.h" |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 15 | #include "components/zucchini/image_utils.h" |
| 16 | #include "components/zucchini/test_utils.h" |
| 17 | #include "testing/gtest/include/gtest/gtest.h" |
| 18 | |
| 19 | namespace zucchini { |
| 20 | |
| 21 | namespace { |
| 22 | |
| 23 | // A trivial AddressTranslator that applies constant shift. |
| 24 | class TestAddressTranslator : public AddressTranslator { |
| 25 | public: |
| 26 | TestAddressTranslator(size_t image_size, rva_t rva_begin) { |
| 27 | DCHECK_GE(rva_begin, 0U); |
| 28 | CHECK_EQ(AddressTranslator::kSuccess, |
| 29 | Initialize({{0, base::checked_cast<offset_t>(image_size), |
| 30 | rva_begin, base::checked_cast<rva_t>(image_size)}})); |
| 31 | } |
| 32 | }; |
| 33 | |
| 34 | // Helper to translate address |value| to RVA. May return |kInvalidRva|. |
| 35 | rva_t AddrValueToRva(uint64_t value, AbsoluteAddress* addr) { |
| 36 | *addr->mutable_value() = value; |
| 37 | return addr->ToRva(); |
| 38 | } |
| 39 | |
| 40 | } // namespace |
| 41 | |
| 42 | TEST(Abs32UtilsTest, AbsoluteAddress32) { |
| 43 | std::vector<uint8_t> data32 = ParseHexString( |
| 44 | "00 00 32 00 21 43 65 4A 00 00 00 00 FF FF FF FF FF FF 31 00"); |
| 45 | ConstBufferView image32(data32.data(), data32.size()); |
| 46 | MutableBufferView mutable_image32(data32.data(), data32.size()); |
| 47 | |
| 48 | AbsoluteAddress addr32(kBit32, 0x00320000U); |
| 49 | EXPECT_TRUE(addr32.Read(0x0U, image32)); |
| 50 | EXPECT_EQ(0x00000000U, addr32.ToRva()); |
| 51 | EXPECT_TRUE(addr32.Read(0x4U, image32)); |
| 52 | EXPECT_EQ(0x4A334321U, addr32.ToRva()); |
| 53 | EXPECT_TRUE(addr32.Read(0x8U, image32)); |
| 54 | EXPECT_EQ(kInvalidRva, addr32.ToRva()); // Underflow. |
| 55 | EXPECT_TRUE(addr32.Read(0xCU, image32)); |
Samuel Huang | 98dd017 | 2018-10-10 15:48:10 +0000 | [diff] [blame] | 56 | EXPECT_EQ(kInvalidRva, addr32.ToRva()); // Translated RVA would be too large. |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 57 | EXPECT_TRUE(addr32.Read(0x10U, image32)); |
| 58 | EXPECT_EQ(kInvalidRva, addr32.ToRva()); // Underflow (boundary case). |
| 59 | |
| 60 | EXPECT_FALSE(addr32.Read(0x11U, image32)); |
| 61 | EXPECT_FALSE(addr32.Read(0x14U, image32)); |
| 62 | EXPECT_FALSE(addr32.Read(0x100000U, image32)); |
| 63 | EXPECT_FALSE(addr32.Read(0x80000000U, image32)); |
| 64 | EXPECT_FALSE(addr32.Read(0xFFFFFFFFU, image32)); |
| 65 | |
| 66 | EXPECT_TRUE(addr32.FromRva(0x11223344U)); |
| 67 | EXPECT_TRUE(addr32.Write(0x2U, &mutable_image32)); |
| 68 | EXPECT_TRUE(addr32.Write(0x10U, &mutable_image32)); |
| 69 | std::vector<uint8_t> expected_data32 = ParseHexString( |
| 70 | "00 00 44 33 54 11 65 4A 00 00 00 00 FF FF FF FF 44 33 54 11"); |
| 71 | EXPECT_EQ(expected_data32, data32); |
| 72 | EXPECT_FALSE(addr32.Write(0x11U, &mutable_image32)); |
| 73 | EXPECT_FALSE(addr32.Write(0xFFFFFFFFU, &mutable_image32)); |
| 74 | EXPECT_EQ(expected_data32, data32); |
| 75 | } |
| 76 | |
| 77 | TEST(Abs32UtilsTest, AbsoluteAddress32Overflow) { |
| 78 | AbsoluteAddress addr32(kBit32, 0xC0000000U); |
| 79 | EXPECT_TRUE(addr32.FromRva(0x00000000U)); |
| 80 | EXPECT_TRUE(addr32.FromRva(0x11223344U)); |
| 81 | EXPECT_TRUE(addr32.FromRva(0x3FFFFFFFU)); |
| 82 | EXPECT_FALSE(addr32.FromRva(0x40000000U)); |
| 83 | EXPECT_FALSE(addr32.FromRva(0x40000001U)); |
| 84 | EXPECT_FALSE(addr32.FromRva(0x80000000U)); |
| 85 | EXPECT_FALSE(addr32.FromRva(0xFFFFFFFFU)); |
| 86 | |
| 87 | EXPECT_EQ(0x00000000U, AddrValueToRva(0xC0000000U, &addr32)); |
| 88 | EXPECT_EQ(kInvalidRva, AddrValueToRva(0xBFFFFFFFU, &addr32)); |
| 89 | EXPECT_EQ(kInvalidRva, AddrValueToRva(0x00000000U, &addr32)); |
| 90 | EXPECT_EQ(0x3FFFFFFFU, AddrValueToRva(0xFFFFFFFFU, &addr32)); |
| 91 | } |
| 92 | |
| 93 | TEST(Abs32UtilsTest, AbsoluteAddress64) { |
| 94 | std::vector<uint8_t> data64 = ParseHexString( |
| 95 | "00 00 00 00 64 00 00 00 21 43 65 4A 64 00 00 00 " |
| 96 | "00 00 00 00 00 00 00 00 FF FF FF FF FF FF FF FF " |
| 97 | "00 00 00 00 64 00 00 80 FF FF FF FF 63 00 00 00"); |
| 98 | ConstBufferView image64(data64.data(), data64.size()); |
| 99 | MutableBufferView mutable_image64(data64.data(), data64.size()); |
| 100 | |
| 101 | AbsoluteAddress addr64(kBit64, 0x0000006400000000ULL); |
| 102 | EXPECT_TRUE(addr64.Read(0x0U, image64)); |
| 103 | EXPECT_EQ(0x00000000U, addr64.ToRva()); |
| 104 | EXPECT_TRUE(addr64.Read(0x8U, image64)); |
| 105 | EXPECT_EQ(0x4A654321U, addr64.ToRva()); |
| 106 | EXPECT_TRUE(addr64.Read(0x10U, image64)); // Succeeds, in spite of value. |
| 107 | EXPECT_EQ(kInvalidRva, addr64.ToRva()); // Underflow. |
| 108 | EXPECT_TRUE(addr64.Read(0x18U, image64)); |
| 109 | EXPECT_EQ(kInvalidRva, addr64.ToRva()); // Translated RVA too large. |
| 110 | EXPECT_TRUE(addr64.Read(0x20U, image64)); |
| 111 | EXPECT_EQ(kInvalidRva, addr64.ToRva()); // Translated RVA toolarge. |
| 112 | EXPECT_TRUE(addr64.Read(0x28U, image64)); |
| 113 | EXPECT_EQ(kInvalidRva, addr64.ToRva()); // Underflow. |
| 114 | |
| 115 | EXPECT_FALSE(addr64.Read(0x29U, image64)); // Extends outside. |
| 116 | EXPECT_FALSE(addr64.Read(0x30U, image64)); // Entirely outside (note: hex). |
| 117 | EXPECT_FALSE(addr64.Read(0x100000U, image64)); |
| 118 | EXPECT_FALSE(addr64.Read(0x80000000U, image64)); |
| 119 | EXPECT_FALSE(addr64.Read(0xFFFFFFFFU, image64)); |
| 120 | |
| 121 | EXPECT_TRUE(addr64.FromRva(0x11223344U)); |
| 122 | EXPECT_TRUE(addr64.Write(0x13U, &mutable_image64)); |
| 123 | EXPECT_TRUE(addr64.Write(0x20U, &mutable_image64)); |
| 124 | std::vector<uint8_t> expected_data64 = ParseHexString( |
| 125 | "00 00 00 00 64 00 00 00 21 43 65 4A 64 00 00 00 " |
| 126 | "00 00 00 44 33 22 11 64 00 00 00 FF FF FF FF FF " |
| 127 | "44 33 22 11 64 00 00 00 FF FF FF FF 63 00 00 00"); |
| 128 | EXPECT_EQ(expected_data64, data64); |
| 129 | EXPECT_FALSE(addr64.Write(0x29U, &mutable_image64)); |
| 130 | EXPECT_FALSE(addr64.Write(0x30U, &mutable_image64)); |
| 131 | EXPECT_FALSE(addr64.Write(0xFFFFFFFFU, &mutable_image64)); |
| 132 | EXPECT_EQ(expected_data64, data64); |
| 133 | |
| 134 | EXPECT_FALSE(addr64.FromRva(0xFFFFFFFFU)); |
| 135 | } |
| 136 | |
| 137 | TEST(Abs32UtilsTest, AbsoluteAddress64Overflow) { |
| 138 | { |
| 139 | // Counterpart to AbsoluteAddress632verflow test. |
| 140 | AbsoluteAddress addr64(kBit64, 0xFFFFFFFFC0000000ULL); |
| 141 | EXPECT_TRUE(addr64.FromRva(0x00000000U)); |
| 142 | EXPECT_TRUE(addr64.FromRva(0x11223344U)); |
| 143 | EXPECT_TRUE(addr64.FromRva(0x3FFFFFFFU)); |
| 144 | EXPECT_FALSE(addr64.FromRva(0x40000000U)); |
| 145 | EXPECT_FALSE(addr64.FromRva(0x40000001U)); |
| 146 | EXPECT_FALSE(addr64.FromRva(0x80000000U)); |
| 147 | EXPECT_FALSE(addr64.FromRva(0xFFFFFFFFU)); |
| 148 | |
| 149 | EXPECT_EQ(0x00000000U, AddrValueToRva(0xFFFFFFFFC0000000U, &addr64)); |
| 150 | EXPECT_EQ(kInvalidRva, AddrValueToRva(0xFFFFFFFFBFFFFFFFU, &addr64)); |
| 151 | EXPECT_EQ(kInvalidRva, AddrValueToRva(0x0000000000000000U, &addr64)); |
| 152 | EXPECT_EQ(kInvalidRva, AddrValueToRva(0xFFFFFFFF00000000U, &addr64)); |
| 153 | EXPECT_EQ(0x3FFFFFFFU, AddrValueToRva(0xFFFFFFFFFFFFFFFFU, &addr64)); |
| 154 | } |
| 155 | { |
| 156 | // Pseudo-counterpart to AbsoluteAddress632verflow test: Some now pass. |
| 157 | AbsoluteAddress addr64(kBit64, 0xC0000000U); |
| 158 | EXPECT_TRUE(addr64.FromRva(0x00000000U)); |
| 159 | EXPECT_TRUE(addr64.FromRva(0x11223344U)); |
| 160 | EXPECT_TRUE(addr64.FromRva(0x3FFFFFFFU)); |
| 161 | EXPECT_TRUE(addr64.FromRva(0x40000000U)); |
| 162 | EXPECT_TRUE(addr64.FromRva(0x40000001U)); |
| 163 | EXPECT_FALSE(addr64.FromRva(0x80000000U)); |
| 164 | EXPECT_FALSE(addr64.FromRva(0xFFFFFFFFU)); |
| 165 | |
| 166 | // ToRva() still fail though. |
| 167 | EXPECT_EQ(0x00000000U, AddrValueToRva(0xC0000000U, &addr64)); |
| 168 | EXPECT_EQ(kInvalidRva, AddrValueToRva(0xBFFFFFFFU, &addr64)); |
| 169 | EXPECT_EQ(kInvalidRva, AddrValueToRva(0x00000000U, &addr64)); |
| 170 | EXPECT_EQ(0x3FFFFFFFU, AddrValueToRva(0xFFFFFFFFU, &addr64)); |
| 171 | } |
| 172 | { |
| 173 | AbsoluteAddress addr64(kBit64, 0xC000000000000000ULL); |
| 174 | EXPECT_TRUE(addr64.FromRva(0x00000000ULL)); |
| 175 | EXPECT_TRUE(addr64.FromRva(0x11223344ULL)); |
| 176 | EXPECT_TRUE(addr64.FromRva(0x3FFFFFFFULL)); |
| 177 | EXPECT_TRUE(addr64.FromRva(0x40000000ULL)); |
| 178 | EXPECT_TRUE(addr64.FromRva(0x40000001ULL)); |
| 179 | EXPECT_FALSE(addr64.FromRva(0x80000000ULL)); |
| 180 | EXPECT_FALSE(addr64.FromRva(0xFFFFFFFFULL)); |
| 181 | |
| 182 | EXPECT_EQ(0x00000000U, AddrValueToRva(0xC000000000000000ULL, &addr64)); |
| 183 | EXPECT_EQ(kInvalidRva, AddrValueToRva(0xBFFFFFFFFFFFFFFFULL, &addr64)); |
| 184 | EXPECT_EQ(kInvalidRva, AddrValueToRva(0x0000000000000000ULL, &addr64)); |
| 185 | EXPECT_EQ(0x3FFFFFFFU, AddrValueToRva(0xC00000003FFFFFFFULL, &addr64)); |
| 186 | EXPECT_EQ(kInvalidRva, AddrValueToRva(0xFFFFFFFFFFFFFFFFULL, &addr64)); |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | TEST(Abs32UtilsTest, Win32Read32) { |
| 191 | constexpr uint32_t kImageBase = 0xA0000000U; |
| 192 | constexpr uint32_t kRvaBegin = 0x00C00000U; |
| 193 | struct { |
| 194 | std::vector<uint8_t> data32; |
| 195 | std::vector<offset_t> abs32_locations; // Assumtion: Sorted. |
| 196 | offset_t lo; // Assumption: In range, does not straddle |abs32_location|. |
| 197 | offset_t hi; // Assumption: Also >= |lo|. |
| 198 | std::vector<Reference> expected_refs; |
| 199 | } test_cases[] = { |
| 200 | // Targets at beginning and end. |
| 201 | {ParseHexString("FF FF FF FF 0F 00 C0 A0 00 00 C0 A0 FF FF FF FF"), |
| 202 | {0x4U, 0x8U}, |
| 203 | 0x0U, |
| 204 | 0x10U, |
| 205 | {{0x4U, 0xFU}, {0x8U, 0x0U}}}, |
| 206 | // Targets at beginning and end are out of bound: Rejected. |
| 207 | {ParseHexString("FF FF FF FF 10 00 C0 A0 FF FF BF A0 FF FF FF FF"), |
| 208 | {0x4U, 0x8U}, |
| 209 | 0x0U, |
| 210 | 0x10U, |
| 211 | std::vector<Reference>()}, |
| 212 | // Same with more extreme target values: Rejected. |
| 213 | {ParseHexString("FF FF FF FF FF FF FF FF 00 00 00 00 FF FF FF FF"), |
| 214 | {0x4U, 0x8U}, |
| 215 | 0x0U, |
| 216 | 0x10U, |
| 217 | std::vector<Reference>()}, |
| 218 | // Locations at beginning and end, plus invalid locations. |
| 219 | {ParseHexString("08 00 C0 A0 FF FF FF FF FF FF FF FF 04 00 C0 A0"), |
| 220 | {0x0U, 0xCU, 0x10U, 0x1000U, 0x80000000U, 0xFFFFFFFFU}, |
| 221 | 0x0U, |
| 222 | 0x10U, |
| 223 | {{0x0U, 0x8U}, {0xCU, 0x4U}}}, |
| 224 | // Odd size, location, target. |
| 225 | {ParseHexString("FF FF FF 09 00 C0 A0 FF FF FF FF FF FF FF FF FF " |
| 226 | "FF FF FF"), |
| 227 | {0x3U}, |
| 228 | 0x0U, |
| 229 | 0x13U, |
| 230 | {{0x3U, 0x9U}}}, |
| 231 | // No location given. |
| 232 | {ParseHexString("FF FF FF FF 0C 00 C0 A0 00 00 C0 A0 FF FF FF FF"), |
| 233 | std::vector<offset_t>(), 0x0U, 0x10U, std::vector<Reference>()}, |
| 234 | // Simple alternation. |
| 235 | {ParseHexString("04 00 C0 A0 FF FF FF FF 0C 00 C0 A0 FF FF FF FF " |
| 236 | "14 00 C0 A0 FF FF FF FF 1C 00 C0 A0 FF FF FF FF"), |
| 237 | {0x0U, 0x8U, 0x10U, 0x18U}, |
| 238 | 0x0U, |
| 239 | 0x20U, |
| 240 | {{0x0U, 0x4U}, {0x8U, 0xCU}, {0x10U, 0x14U}, {0x18U, 0x1CU}}}, |
| 241 | // Same, with locations limited by |lo| and |hi|. By assumption these must |
| 242 | // not cut accross Reference body. |
| 243 | {ParseHexString("04 00 C0 A0 FF FF FF FF 0C 00 C0 A0 FF FF FF FF " |
| 244 | "14 00 C0 A0 FF FF FF FF 1C 00 C0 A0 FF FF FF FF"), |
| 245 | {0x0U, 0x8U, 0x10U, 0x18U}, |
| 246 | 0x04U, |
| 247 | 0x17U, |
| 248 | {{0x8U, 0xCU}, {0x10U, 0x14U}}}, |
| 249 | // Same, with very limiting |lo| and |hi|. |
| 250 | {ParseHexString("04 00 C0 A0 FF FF FF FF 0C 00 C0 A0 FF FF FF FF " |
| 251 | "14 00 C0 A0 FF FF FF FF 1C 00 C0 A0 FF FF FF FF"), |
| 252 | {0x0U, 0x8U, 0x10U, 0x18U}, |
| 253 | 0x0CU, |
| 254 | 0x10U, |
| 255 | std::vector<Reference>()}, |
| 256 | // Same, |lo| == |hi|. |
| 257 | {ParseHexString("04 00 C0 A0 FF FF FF FF 0C 00 C0 A0 FF FF FF FF " |
| 258 | "14 00 C0 A0 FF FF FF FF 1C 00 C0 A0 FF FF FF FF"), |
| 259 | {0x0U, 0x8U, 0x10U, 0x18U}, |
| 260 | 0x14U, |
| 261 | 0x14U, |
| 262 | std::vector<Reference>()}, |
| 263 | // Same, |lo| and |hi| at end. |
| 264 | {ParseHexString("04 00 C0 A0 FF FF FF FF 0C 00 C0 A0 FF FF FF FF " |
| 265 | "14 00 C0 A0 FF FF FF FF 1C 00 C0 A0 FF FF FF FF"), |
| 266 | {0x0U, 0x8U, 0x10U, 0x18U}, |
| 267 | 0x20U, |
| 268 | 0x20U, |
| 269 | std::vector<Reference>()}, |
| 270 | // Mix. Note that targets can overlap. |
| 271 | {ParseHexString("FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF " |
| 272 | "06 00 C0 A0 2C 00 C0 A0 FF FF C0 A0 2B 00 C0 A0 " |
| 273 | "FF 06 00 C0 A0 00 00 C0 A0 FF FF FF FF FF FF FF"), |
| 274 | {0x10U, 0x14U, 0x18U, 0x1CU, 0x21U, 0x25U, 0xAAAAU}, |
| 275 | 0x07U, |
| 276 | 0x25U, |
| 277 | {{0x10U, 0x6U}, {0x14U, 0x2CU}, {0x1CU, 0x2BU}, {0x21, 0x6U}}}, |
| 278 | }; |
| 279 | |
| 280 | for (const auto& test_case : test_cases) { |
| 281 | ConstBufferView image32(test_case.data32.data(), test_case.data32.size()); |
| 282 | Abs32RvaExtractorWin32 extractor(image32, {kBit32, kImageBase}, |
| 283 | test_case.abs32_locations, test_case.lo, |
| 284 | test_case.hi); |
| 285 | |
| 286 | TestAddressTranslator translator(test_case.data32.size(), kRvaBegin); |
| 287 | Abs32ReaderWin32 reader(std::move(extractor), translator); |
| 288 | |
| 289 | // Loop over |expected_ref| to check element-by-element. |
Anton Bikineev | 1a96551 | 2021-05-15 22:35:36 +0000 | [diff] [blame] | 290 | absl::optional<Reference> ref; |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 291 | for (const auto& expected_ref : test_case.expected_refs) { |
| 292 | ref = reader.GetNext(); |
| 293 | EXPECT_TRUE(ref.has_value()); |
| 294 | EXPECT_EQ(expected_ref, ref.value()); |
| 295 | } |
| 296 | // Check that nothing is left. |
| 297 | ref = reader.GetNext(); |
| 298 | EXPECT_FALSE(ref.has_value()); |
| 299 | } |
| 300 | } |
| 301 | |
| 302 | TEST(Abs32UtilsTest, Win32Read64) { |
| 303 | constexpr uint64_t kImageBase = 0x31415926A0000000U; |
| 304 | constexpr uint32_t kRvaBegin = 0x00C00000U; |
| 305 | // For simplicity, just test mixed case. |
| 306 | std::vector<uint8_t> data64 = ParseHexString( |
| 307 | "FF FF FF FF FF FF FF FF 00 00 C0 A0 26 59 41 31 " |
| 308 | "06 00 C0 A0 26 59 41 31 02 00 C0 A0 26 59 41 31 " |
| 309 | "FF FF FF BF 26 59 41 31 FF FF FF FF FF FF FF FF " |
| 310 | "02 00 C0 A0 26 59 41 31 07 00 C0 A0 26 59 41 31"); |
| 311 | std::vector<offset_t> abs32_locations = {0x8U, 0x10U, 0x18U, 0x20U, |
| 312 | 0x28U, 0x30U, 0x38U, 0x40U}; |
| 313 | offset_t lo = 0x10U; |
| 314 | offset_t hi = 0x38U; |
| 315 | std::vector<Reference> expected_refs = { |
| 316 | {0x10U, 0x06U}, {0x18U, 0x02U}, {0x30U, 0x02U}}; |
| 317 | |
| 318 | ConstBufferView image64(data64.data(), data64.size()); |
| 319 | Abs32RvaExtractorWin32 extractor(image64, {kBit64, kImageBase}, |
| 320 | abs32_locations, lo, hi); |
| 321 | TestAddressTranslator translator(data64.size(), kRvaBegin); |
| 322 | Abs32ReaderWin32 reader(std::move(extractor), translator); |
| 323 | |
| 324 | std::vector<Reference> refs; |
Anton Bikineev | 1a96551 | 2021-05-15 22:35:36 +0000 | [diff] [blame] | 325 | absl::optional<Reference> ref; |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 326 | for (ref = reader.GetNext(); ref.has_value(); ref = reader.GetNext()) |
| 327 | refs.push_back(ref.value()); |
| 328 | EXPECT_EQ(expected_refs, refs); |
| 329 | } |
| 330 | |
| 331 | TEST(Abs32UtilsTest, Win32ReadFail) { |
| 332 | // Make |bitness| a state to reduce repetition. |
| 333 | Bitness bitness = kBit32; |
| 334 | |
| 335 | constexpr uint32_t kImageBase = 0xA0000000U; // Shared for 32-bit and 64-bit. |
| 336 | std::vector<uint8_t> data(32U, 0xFFU); |
| 337 | ConstBufferView image(data.data(), data.size()); |
| 338 | |
| 339 | auto try_make = [&](std::vector<offset_t>&& abs32_locations, offset_t lo, |
| 340 | offset_t hi) { |
| 341 | Abs32RvaExtractorWin32 extractor(image, {bitness, kImageBase}, |
| 342 | abs32_locations, lo, hi); |
| 343 | extractor.GetNext(); // Dummy call so |extractor| gets used. |
| 344 | }; |
| 345 | |
| 346 | // 32-bit tests. |
| 347 | bitness = kBit32; |
| 348 | try_make({8U, 24U}, 0U, 32U); |
| 349 | EXPECT_DEATH(try_make({4U, 24U}, 32U, 0U), ""); // |lo| > |hi|. |
| 350 | try_make({8U, 24U}, 0U, 12U); |
| 351 | try_make({8U, 24U}, 0U, 28U); |
| 352 | try_make({8U, 24U}, 8U, 32U); |
| 353 | try_make({8U, 24U}, 24U, 32U); |
| 354 | EXPECT_DEATH(try_make({8U, 24U}, 0U, 11U), ""); // |hi| straddles. |
| 355 | EXPECT_DEATH(try_make({8U, 24U}, 26U, 32U), ""); // |lo| straddles. |
| 356 | try_make({8U, 24U}, 12U, 24U); |
| 357 | |
| 358 | // 64-bit tests. |
| 359 | bitness = kBit64; |
| 360 | try_make({6U, 22U}, 0U, 32U); |
| 361 | // |lo| > |hi|. |
| 362 | EXPECT_DEATH(try_make(std::vector<offset_t>(), 32U, 31U), ""); |
| 363 | try_make({6U, 22U}, 0U, 14U); |
| 364 | try_make({6U, 22U}, 0U, 30U); |
| 365 | try_make({6U, 22U}, 6U, 32U); |
| 366 | try_make({6U, 22U}, 22U, 32U); |
| 367 | EXPECT_DEATH(try_make({6U, 22U}, 0U, 29U), ""); // |hi| straddles. |
| 368 | EXPECT_DEATH(try_make({6U, 22U}, 7U, 32U), ""); // |lo| straddles. |
| 369 | try_make({6U, 22U}, 14U, 20U); |
| 370 | try_make({16U}, 16U, 24U); |
| 371 | EXPECT_DEATH(try_make({16U}, 18U, 18U), ""); // |lo|, |hi| straddle. |
| 372 | } |
| 373 | |
| 374 | TEST(Abs32UtilsTest, Win32Write32) { |
| 375 | constexpr uint32_t kImageBase = 0xA0000000U; |
| 376 | constexpr uint32_t kRvaBegin = 0x00C00000U; |
| 377 | std::vector<uint8_t> data32(0x30, 0xFFU); |
| 378 | MutableBufferView image32(data32.data(), data32.size()); |
| 379 | AbsoluteAddress addr(kBit32, kImageBase); |
| 380 | TestAddressTranslator translator(data32.size(), kRvaBegin); |
| 381 | Abs32WriterWin32 writer(image32, std::move(addr), translator); |
| 382 | |
| 383 | // Successful writes. |
| 384 | writer.PutNext({0x02U, 0x10U}); |
| 385 | writer.PutNext({0x0BU, 0x21U}); |
| 386 | writer.PutNext({0x16U, 0x10U}); |
| 387 | writer.PutNext({0x2CU, 0x00U}); |
| 388 | |
| 389 | // Invalid data: For simplicity, Abs32WriterWin32 simply ignores bad writes. |
| 390 | // Invalid location. |
| 391 | writer.PutNext({0x2DU, 0x20U}); |
| 392 | writer.PutNext({0x80000000U, 0x20U}); |
| 393 | writer.PutNext({0xFFFFFFFFU, 0x20U}); |
| 394 | // Invalid target. |
| 395 | writer.PutNext({0x1CU, 0x00001111U}); |
| 396 | writer.PutNext({0x10U, 0xFFFFFF00U}); |
| 397 | |
| 398 | std::vector<uint8_t> expected_data32 = ParseHexString( |
| 399 | "FF FF 10 00 C0 A0 FF FF FF FF FF 21 00 C0 A0 FF " |
| 400 | "FF FF FF FF FF FF 10 00 C0 A0 FF FF FF FF FF FF " |
| 401 | "FF FF FF FF FF FF FF FF FF FF FF FF 00 00 C0 A0"); |
| 402 | EXPECT_EQ(expected_data32, data32); |
| 403 | } |
| 404 | |
| 405 | TEST(Abs32UtilsTest, Win32Write64) { |
| 406 | constexpr uint64_t kImageBase = 0x31415926A0000000U; |
| 407 | constexpr uint32_t kRvaBegin = 0x00C00000U; |
| 408 | std::vector<uint8_t> data64(0x30, 0xFFU); |
| 409 | MutableBufferView image32(data64.data(), data64.size()); |
| 410 | AbsoluteAddress addr(kBit64, kImageBase); |
| 411 | TestAddressTranslator translator(data64.size(), kRvaBegin); |
| 412 | Abs32WriterWin32 writer(image32, std::move(addr), translator); |
| 413 | |
| 414 | // Successful writes. |
| 415 | writer.PutNext({0x02U, 0x10U}); |
| 416 | writer.PutNext({0x0BU, 0x21U}); |
| 417 | writer.PutNext({0x16U, 0x10U}); |
| 418 | writer.PutNext({0x28U, 0x00U}); |
| 419 | |
| 420 | // Invalid data: For simplicity, Abs32WriterWin32 simply ignores bad writes. |
| 421 | // Invalid location. |
| 422 | writer.PutNext({0x29U, 0x20U}); |
| 423 | writer.PutNext({0x80000000U, 0x20U}); |
| 424 | writer.PutNext({0xFFFFFFFFU, 0x20U}); |
| 425 | // Invalid target. |
| 426 | writer.PutNext({0x1CU, 0x00001111U}); |
| 427 | writer.PutNext({0x10U, 0xFFFFFF00U}); |
| 428 | |
| 429 | std::vector<uint8_t> expected_data64 = ParseHexString( |
| 430 | "FF FF 10 00 C0 A0 26 59 41 31 FF 21 00 C0 A0 26 " |
| 431 | "59 41 31 FF FF FF 10 00 C0 A0 26 59 41 31 FF FF " |
| 432 | "FF FF FF FF FF FF FF FF 00 00 C0 A0 26 59 41 31"); |
| 433 | EXPECT_EQ(expected_data64, data64); |
| 434 | } |
| 435 | |
Samuel Huang | 98dd017 | 2018-10-10 15:48:10 +0000 | [diff] [blame] | 436 | TEST(Abs32UtilsTest, RemoveUntranslatableAbs32) { |
| 437 | Bitness kBitness = kBit32; |
| 438 | uint64_t kImageBase = 0x2BCD0000; |
| 439 | |
| 440 | // Valid RVAs: [0x00001A00, 0x00001A28) and [0x00003A00, 0x00004000). |
| 441 | // Valid AVAs: [0x2BCD1A00, 0x2BCD1A28) and [0x2BCD3A00, 0x2BCD4000). |
| 442 | // Notice that the second section has has dangling RVA. |
| 443 | AddressTranslator translator; |
| 444 | ASSERT_EQ(AddressTranslator::kSuccess, |
| 445 | translator.Initialize( |
| 446 | {{0x04, +0x28, 0x1A00, +0x28}, {0x30, +0x30, 0x3A00, +0x600}})); |
| 447 | |
| 448 | std::vector<uint8_t> data = ParseHexString( |
| 449 | "FF FF FF FF 0B 3A CD 2B 00 00 00 04 3A CD 2B 00 " |
| 450 | "FC 3F CD 2B 14 1A CD 2B 44 00 00 00 CC 00 00 00 " |
| 451 | "00 00 55 00 00 00 1E 1A CD 2B 00 99 FF FF FF FF " |
| 452 | "10 3A CD 2B 22 00 00 00 00 00 00 11 00 00 00 00 " |
| 453 | "66 00 00 00 28 1A CD 2B 00 00 CD 2B 27 1A CD 2B " |
| 454 | "FF 39 CD 2B 00 00 00 00 18 1A CD 2B 00 00 00 00 " |
| 455 | "FF FF FF FF FF FF FF FF"); |
| 456 | MutableBufferView image(data.data(), data.size()); |
| 457 | |
| 458 | const offset_t kAbs1 = 0x04; // a:2BCD3A0B = r:3A0B = o:3B |
| 459 | const offset_t kAbs2 = 0x0B; // a:2BCD3A04 = r:3A04 = o:34 |
| 460 | const offset_t kAbs3 = 0x10; // a:2BCD3FFF = r:3FFF (dangling) |
| 461 | const offset_t kAbs4 = 0x14; // a:2BCD1A14 = r:1A14 = o:18 |
| 462 | const offset_t kAbs5 = 0x26; // a:2BCD1A1E = r:1A1E = o:22 |
| 463 | const offset_t kAbs6 = 0x30; // a:2BCD3A10 = r:3A10 = 0x40 |
| 464 | const offset_t kAbs7 = 0x44; // a:2BCD1A28 = r:1A28 (bad: sentinel) |
| 465 | const offset_t kAbs8 = 0x48; // a:2BCD0000 = r:0000 (bad: not covered) |
| 466 | const offset_t kAbs9 = 0x4C; // a:2BCD1A27 = r:1A27 = 0x2B |
| 467 | const offset_t kAbsA = 0x50; // a:2BCD39FF (bad: not covered) |
| 468 | const offset_t kAbsB = 0x54; // a:00000000 (bad: underflow) |
| 469 | const offset_t kAbsC = 0x58; // a:2BCD1A18 = r:1A18 = 0x1C |
| 470 | |
| 471 | std::vector<offset_t> locations = {kAbs1, kAbs2, kAbs3, kAbs4, kAbs5, kAbs6, |
| 472 | kAbs7, kAbs8, kAbs9, kAbsA, kAbsB, kAbsC}; |
| 473 | std::vector<offset_t> exp_locations = {kAbs1, kAbs2, kAbs3, kAbs4, |
| 474 | kAbs5, kAbs6, kAbs9, kAbsC}; |
| 475 | size_t exp_num_removed = locations.size() - exp_locations.size(); |
| 476 | size_t num_removed = RemoveUntranslatableAbs32(image, {kBitness, kImageBase}, |
| 477 | translator, &locations); |
| 478 | EXPECT_EQ(exp_num_removed, num_removed); |
| 479 | EXPECT_EQ(exp_locations, locations); |
| 480 | } |
| 481 | |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 482 | TEST(Abs32UtilsTest, RemoveOverlappingAbs32Locations) { |
Etienne Pierre-doray | e53806a | 2018-10-05 20:15:13 +0000 | [diff] [blame] | 483 | // Make |width| a state to reduce repetition. |
| 484 | uint32_t width = WidthOf(kBit32); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 485 | |
Etienne Pierre-doray | e53806a | 2018-10-05 20:15:13 +0000 | [diff] [blame] | 486 | auto run_test = [&width](const std::vector<offset_t>& expected_locations, |
| 487 | std::vector<offset_t>&& locations) { |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 488 | ASSERT_TRUE(std::is_sorted(locations.begin(), locations.end())); |
| 489 | size_t expected_removals = locations.size() - expected_locations.size(); |
Etienne Pierre-doray | e53806a | 2018-10-05 20:15:13 +0000 | [diff] [blame] | 490 | size_t removals = RemoveOverlappingAbs32Locations(width, &locations); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 491 | EXPECT_EQ(expected_removals, removals); |
| 492 | EXPECT_EQ(expected_locations, locations); |
| 493 | }; |
| 494 | |
| 495 | // 32-bit tests. |
Etienne Pierre-doray | e53806a | 2018-10-05 20:15:13 +0000 | [diff] [blame] | 496 | width = WidthOf(kBit32); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 497 | run_test(std::vector<offset_t>(), std::vector<offset_t>()); |
| 498 | run_test({4U}, {4U}); |
| 499 | run_test({4U, 10U}, {4U, 10U}); |
| 500 | run_test({4U, 8U}, {4U, 8U}); |
| 501 | run_test({4U}, {4U, 7U}); |
| 502 | run_test({4U}, {4U, 4U}); |
| 503 | run_test({4U, 8U}, {4U, 7U, 8U}); |
| 504 | run_test({4U, 10U}, {4U, 7U, 10U}); |
| 505 | run_test({4U, 9U}, {4U, 9U, 10U}); |
| 506 | run_test({3U}, {3U, 5U, 6U}); |
| 507 | run_test({3U, 7U}, {3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U}); |
| 508 | run_test({3U, 7U, 11U}, {3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 11U, 12U}); |
| 509 | run_test({4U, 8U, 12U}, {4U, 6U, 8U, 10U, 12U}); |
| 510 | run_test({4U, 8U, 12U, 16U}, {4U, 8U, 12U, 16U}); |
| 511 | run_test({4U, 8U, 12U}, {4U, 8U, 9U, 12U}); |
| 512 | run_test({4U}, {4U, 4U, 4U, 4U, 4U, 4U}); |
| 513 | run_test({3U}, {3U, 4U, 4U, 4U, 5U, 5U}); |
| 514 | run_test({3U, 7U}, {3U, 4U, 4U, 4U, 7U, 7U, 8U}); |
| 515 | run_test({10U, 20U, 30U, 40U}, {10U, 20U, 22U, 22U, 30U, 40U}); |
| 516 | run_test({1000000U, 1000004U}, {1000000U, 1000004U}); |
| 517 | run_test({1000000U}, {1000000U, 1000002U}); |
| 518 | |
| 519 | // 64-bit tests. |
Etienne Pierre-doray | e53806a | 2018-10-05 20:15:13 +0000 | [diff] [blame] | 520 | width = WidthOf(kBit64); |
Samuel Huang | 06f1ae9 | 2018-03-13 18:19:34 +0000 | [diff] [blame] | 521 | run_test(std::vector<offset_t>(), std::vector<offset_t>()); |
| 522 | run_test({4U}, {4U}); |
| 523 | run_test({4U, 20U}, {4U, 20U}); |
| 524 | run_test({4U, 12U}, {4U, 12U}); |
| 525 | run_test({4U}, {4U, 11U}); |
| 526 | run_test({4U}, {4U, 5U}); |
| 527 | run_test({4U}, {4U, 4U}); |
| 528 | run_test({4U, 12U, 20U}, {4U, 12U, 20U}); |
| 529 | run_test({1U, 9U, 17U}, {1U, 9U, 17U}); |
| 530 | run_test({1U, 17U}, {1U, 8U, 17U}); |
| 531 | run_test({1U, 10U}, {1U, 10U, 17U}); |
| 532 | run_test({3U, 11U}, {3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 11U, 12U}); |
| 533 | run_test({4U, 12U}, {4U, 6U, 8U, 10U, 12U}); |
| 534 | run_test({4U, 12U}, {4U, 12U, 16U}); |
| 535 | run_test({4U, 12U, 20U, 28U}, {4U, 12U, 20U, 28U}); |
| 536 | run_test({4U}, {4U, 4U, 4U, 4U, 5U, 5U}); |
| 537 | run_test({3U, 11U}, {3U, 4U, 4U, 4U, 11U, 11U, 12U}); |
| 538 | run_test({10U, 20U, 30U, 40U}, {10U, 20U, 22U, 22U, 30U, 40U}); |
| 539 | run_test({1000000U, 1000008U}, {1000000U, 1000008U}); |
| 540 | run_test({1000000U}, {1000000U, 1000004U}); |
| 541 | } |
| 542 | |
| 543 | } // namespace zucchini |