OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "courgette/disassembler_win32_x64.h" | 5 #include "courgette/rel32_finder_x64.h" |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/numerics/safe_conversions.h" | |
11 #include "courgette/assembly_program.h" | |
12 #include "courgette/courgette.h" | |
13 | |
14 #if COURGETTE_HISTOGRAM_TARGETS | |
15 #include <iostream> | |
16 #endif | |
17 | 6 |
18 namespace courgette { | 7 namespace courgette { |
19 | 8 |
20 DisassemblerWin32X64::DisassemblerWin32X64(const void* start, size_t length) | 9 Rel32FinderX64::Rel32FinderX64(RVA relocs_start_rva, RVA relocs_end_rva) |
21 : DisassemblerWin32(start, length) {} | 10 : Rel32Finder(relocs_start_rva, relocs_end_rva) {} |
22 | 11 |
23 RVA DisassemblerWin32X64::PointerToTargetRVA(const uint8_t* p) const { | 12 void Rel32FinderX64::Find(const uint8_t* start_pointer, |
24 return Address64ToRVA(Read64LittleEndian(p)); | 13 const uint8_t* end_pointer, |
25 } | 14 RVA start_rva, |
26 | 15 RVA end_rva, |
27 RVA DisassemblerWin32X64::Address64ToRVA(uint64_t address) const { | 16 uint32_t size_of_image, |
28 if (address < image_base() || address >= image_base() + size_of_image_) | 17 const std::vector<RVA>& abs32_locations) { |
29 return kNoRVA; | |
30 return base::checked_cast<RVA>(address - image_base()); | |
31 } | |
32 | |
33 CheckBool DisassemblerWin32X64::EmitAbs(Label* label, | |
34 AssemblyProgram* program) { | |
35 return program->EmitAbs64(label); | |
36 } | |
37 | |
38 void DisassemblerWin32X64::ParseRel32RelocsFromSection(const Section* section) { | |
39 // TODO(sra): use characteristic. | |
40 bool isCode = strcmp(section->name, ".text") == 0; | |
41 if (!isCode) | |
42 return; | |
43 | |
44 FileOffset start_file_offset = section->file_offset_of_raw_data; | |
45 FileOffset end_file_offset = start_file_offset + section->size_of_raw_data; | |
46 RVA relocs_start_rva = base_relocation_table().address_; | |
47 | |
48 const uint8_t* start_pointer = FileOffsetToPointer(start_file_offset); | |
49 const uint8_t* end_pointer = FileOffsetToPointer(end_file_offset); | |
50 | |
51 RVA start_rva = FileOffsetToRVA(start_file_offset); | |
52 RVA end_rva = start_rva + section->virtual_size; | |
53 | |
54 // Quick way to convert from Pointer to RVA within a single Section is to | 18 // Quick way to convert from Pointer to RVA within a single Section is to |
55 // subtract |pointer_to_rva|. | 19 // subtract 'pointer_to_rva'. |
huangs
2016/05/26 22:11:17
NIT: |adjust_pointer_to_rva|.
etiennep
2016/05/27 18:12:34
Done.
| |
56 const uint8_t* const adjust_pointer_to_rva = start_pointer - start_rva; | 20 const uint8_t* const adjust_pointer_to_rva = start_pointer - start_rva; |
57 | 21 |
58 std::vector<RVA>::iterator abs32_pos = abs32_locations_.begin(); | 22 std::vector<RVA>::const_iterator abs32_pos = abs32_locations.begin(); |
59 | 23 |
60 // Find the rel32 relocations. | 24 // Find the rel32 relocations. |
61 const uint8_t* p = start_pointer; | 25 const uint8_t* p = start_pointer; |
62 while (p < end_pointer) { | 26 while (p < end_pointer) { |
63 RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva); | 27 RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva); |
64 if (current_rva == relocs_start_rva) { | 28 |
65 uint32_t relocs_size = base_relocation_table().size_; | 29 // Skip the base reloation table if we encounter it. |
66 if (relocs_size) { | 30 // Note: We're not bothering to handle the edge case where a Rel32 pointer |
67 p += relocs_size; | 31 // collides with |relocs_start_rva_| by being {1, 2, 3}-bytes before it. |
68 continue; | 32 if (current_rva >= relocs_start_rva_ && current_rva < relocs_end_rva_) { |
69 } | 33 p += relocs_end_rva_ - current_rva; |
34 continue; | |
70 } | 35 } |
71 | 36 |
72 // Heuristic discovery of rel32 locations in instruction stream: are the | 37 // Heuristic discovery of rel32 locations in instruction stream: are the |
73 // next few bytes the start of an instruction containing a rel32 | 38 // next few bytes the start of an instruction containing a rel32 |
74 // addressing mode? | 39 // addressing mode? |
75 const uint8_t* rel32 = nullptr; | 40 const uint8_t* rel32 = nullptr; |
76 bool is_rip_relative = false; | 41 bool is_rip_relative = false; |
77 | 42 |
78 if (p + 5 <= end_pointer) { | 43 if (p + 5 <= end_pointer) { |
79 if (*p == 0xE8 || *p == 0xE9) // jmp rel32 and call rel32 | 44 if (*p == 0xE8 || *p == 0xE9) // jmp rel32 and call rel32 |
80 rel32 = p + 1; | 45 rel32 = p + 1; |
81 } | 46 } |
82 if (p + 6 <= end_pointer) { | 47 if (p + 6 <= end_pointer) { |
83 if (*p == 0x0F && (*(p + 1) & 0xF0) == 0x80) { // Jcc long form | 48 if (*p == 0x0F && (*(p + 1) & 0xF0) == 0x80) { // Jcc long form |
84 if (p[1] != 0x8A && p[1] != 0x8B) // JPE/JPO unlikely | 49 if (p[1] != 0x8A && p[1] != 0x8B) // JPE/JPO unlikely |
85 rel32 = p + 2; | 50 rel32 = p + 2; |
86 } else if (*p == 0xFF && (*(p + 1) == 0x15 || *(p + 1) == 0x25)) { | 51 } else if (*p == 0xFF && (*(p + 1) == 0x15 || *(p + 1) == 0x25)) { |
87 // rip relative call/jmp | 52 // rip relative call/jmp |
88 rel32 = p + 2; | 53 rel32 = p + 2; |
89 is_rip_relative = true; | 54 is_rip_relative = true; |
90 } | 55 } |
91 } | 56 } |
92 if (p + 7 <= end_pointer) { | 57 if (p + 7 <= end_pointer) { |
93 if ((*p & 0xFB) == 0x48 && *(p + 1) == 0x8D && | 58 if ((*p & 0xFB) == 0x48 && *(p + 1) == 0x8D && |
huangs
2016/05/26 22:11:17
Comments on these instructions?
etiennep
2016/05/27 18:12:34
Done.
| |
94 (*(p + 2) & 0xC7) == 0x05) { | 59 (*(p + 2) & 0xC7) == 0x05) { |
95 // rip relative lea | 60 // rip relative lea |
96 rel32 = p + 3; | 61 rel32 = p + 3; |
97 is_rip_relative = true; | 62 is_rip_relative = true; |
98 } else if ((*p & 0xFB) == 0x48 && *(p + 1) == 0x8B && | 63 } else if ((*p & 0xFB) == 0x48 && *(p + 1) == 0x8B && |
99 (*(p + 2) & 0xC7) == 0x05) { | 64 (*(p + 2) & 0xC7) == 0x05) { |
100 // rip relative mov | 65 // rip relative mov |
101 rel32 = p + 3; | 66 rel32 = p + 3; |
102 is_rip_relative = true; | 67 is_rip_relative = true; |
103 } | 68 } |
104 } | 69 } |
105 | 70 |
106 if (rel32) { | 71 if (rel32) { |
107 RVA rel32_rva = static_cast<RVA>(rel32 - adjust_pointer_to_rva); | 72 RVA rel32_rva = static_cast<RVA>(rel32 - adjust_pointer_to_rva); |
108 | 73 |
109 // Is there an abs32 reloc overlapping the candidate? | 74 // Is there an abs32 reloc overlapping the candidate? |
110 while (abs32_pos != abs32_locations_.end() && *abs32_pos < rel32_rva - 3) | 75 while (abs32_pos != abs32_locations.end() && *abs32_pos < rel32_rva - 3) |
111 ++abs32_pos; | 76 ++abs32_pos; |
112 // Now: (*abs32_pos > rel32_rva - 4) i.e. the lowest addressed 4-byte | 77 // Now: (*abs32_pos > rel32_rva - 4) i.e. the lowest addressed 4-byte |
113 // region that could overlap rel32_rva. | 78 // region that could overlap rel32_rva. |
114 if (abs32_pos != abs32_locations_.end()) { | 79 if (abs32_pos != abs32_locations.end()) { |
115 if (*abs32_pos < rel32_rva + 4) { | 80 if (*abs32_pos < rel32_rva + 4) { |
116 // Beginning of abs32 reloc is before end of rel32 reloc so they | 81 // Beginning of abs32 reloc is before end of rel32 reloc so they |
117 // overlap. Skip four bytes past the abs32 reloc. | 82 // overlap. Skip four bytes past the abs32 reloc. |
huangs
2016/05/26 22:11:17
NIT: Remove space before "Skip".
etiennep
2016/05/27 18:12:34
Done.
| |
118 p += (*abs32_pos + 4) - current_rva; | 83 p += (*abs32_pos + 4) - current_rva; |
119 continue; | 84 continue; |
120 } | 85 } |
121 } | 86 } |
122 | 87 |
huangs
2016/05/26 22:40:55
Why did the comment disappear?
etiennep
2016/05/27 18:12:34
Idk, it's back now!
| |
123 // + 4 since offset is relative to start of next instruction. | |
124 RVA target_rva = rel32_rva + 4 + Read32LittleEndian(rel32); | 88 RVA target_rva = rel32_rva + 4 + Read32LittleEndian(rel32); |
125 // To be valid, rel32 target must be within image, and within this | 89 // To be valid, rel32 target must be within image, and within this |
126 // section. | 90 // section. |
127 if (target_rva < size_of_image_ && // Subsumes rva != kUnassignedRVA. | 91 if (target_rva < size_of_image && // Subsumes rva != kUnassignedRVA. |
huangs
2016/05/26 22:40:55
target_rva < size_of_image
seems kinda bogus and
etiennep
2016/05/27 18:12:34
I moved size_of_image as an member variable. It wo
| |
128 (is_rip_relative || | 92 (is_rip_relative || |
129 (start_rva <= target_rva && target_rva < end_rva))) { | 93 (start_rva <= target_rva && target_rva < end_rva))) { |
130 rel32_locations_.push_back(rel32_rva); | 94 rel32_locations_.push_back(rel32_rva); |
131 #if COURGETTE_HISTOGRAM_TARGETS | 95 #if COURGETTE_HISTOGRAM_TARGETS |
132 ++rel32_target_rvas_[target_rva]; | 96 ++rel32_target_rvas_[target_rva]; |
133 #endif | 97 #endif |
134 p = rel32 + 4; | 98 p = rel32 + 4; |
135 continue; | 99 continue; |
136 } | 100 } |
137 } | 101 } |
138 p += 1; | 102 p += 1; |
139 } | 103 } |
140 } | 104 } |
141 | 105 |
142 } // namespace courgette | 106 } // namespace courgette |
OLD | NEW |