Line | Count | Source (jump to first uncovered line) |
1 | | /*************************************************************************************************** |
2 | | |
3 | | Zyan Disassembler Library (Zydis) |
4 | | |
5 | | Original Author : Florian Bernd |
6 | | |
7 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
8 | | * of this software and associated documentation files (the "Software"), to deal |
9 | | * in the Software without restriction, including without limitation the rights |
10 | | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
11 | | * copies of the Software, and to permit persons to whom the Software is |
12 | | * furnished to do so, subject to the following conditions: |
13 | | * |
14 | | * The above copyright notice and this permission notice shall be included in all |
15 | | * copies or substantial portions of the Software. |
16 | | * |
17 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
20 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
21 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
22 | | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
23 | | * SOFTWARE. |
24 | | |
25 | | ***************************************************************************************************/ |
26 | | |
27 | | #include <Zycore/LibC.h> |
28 | | #include <Zydis/Utils.h> |
29 | | |
30 | | /* ============================================================================================== */ |
31 | | /* Exported functions */ |
32 | | /* ============================================================================================== */ |
33 | | |
34 | | /* ---------------------------------------------------------------------------------------------- */ |
35 | | /* Address calculation */ |
36 | | /* ---------------------------------------------------------------------------------------------- */ |
37 | | |
38 | | // Signed integer overflow is expected behavior in this function, for wrapping around the |
39 | | // instruction pointer on jumps right at the end of the address space. |
40 | | ZYAN_NO_SANITIZE("signed-integer-overflow") |
41 | | ZyanStatus ZydisCalcAbsoluteAddress(const ZydisDecodedInstruction* instruction, |
42 | | const ZydisDecodedOperand* operand, ZyanU64 runtime_address, ZyanU64* result_address) |
43 | 4.33k | { |
44 | 4.33k | if (!instruction || !operand || !result_address) |
45 | 0 | { |
46 | 0 | return ZYAN_STATUS_INVALID_ARGUMENT; |
47 | 0 | } |
48 | | |
49 | 4.33k | switch (operand->type) |
50 | 4.33k | { |
51 | 4.09k | case ZYDIS_OPERAND_TYPE_MEMORY: |
52 | 4.09k | if (!operand->mem.disp.size) |
53 | 1.54k | { |
54 | 1.54k | return ZYAN_STATUS_INVALID_ARGUMENT; |
55 | 1.54k | } |
56 | 2.55k | if (operand->mem.base == ZYDIS_REGISTER_EIP) |
57 | 12 | { |
58 | 12 | *result_address = ((ZyanU32)runtime_address + instruction->length + |
59 | 12 | (ZyanU32)operand->mem.disp.value); |
60 | 12 | return ZYAN_STATUS_SUCCESS; |
61 | 12 | } |
62 | 2.54k | if (operand->mem.base == ZYDIS_REGISTER_RIP) |
63 | 939 | { |
64 | 939 | *result_address = (ZyanU64)(runtime_address + instruction->length + |
65 | 939 | operand->mem.disp.value); |
66 | 939 | return ZYAN_STATUS_SUCCESS; |
67 | 939 | } |
68 | 1.60k | if ((operand->mem.base == ZYDIS_REGISTER_NONE) && |
69 | 1.60k | (operand->mem.index == ZYDIS_REGISTER_NONE)) |
70 | 1.18k | { |
71 | 1.18k | switch (instruction->address_width) |
72 | 1.18k | { |
73 | 204 | case 16: |
74 | 204 | *result_address = (ZyanU64)operand->mem.disp.value & 0x000000000000FFFF; |
75 | 204 | return ZYAN_STATUS_SUCCESS; |
76 | 518 | case 32: |
77 | 518 | *result_address = (ZyanU64)operand->mem.disp.value & 0x00000000FFFFFFFF; |
78 | 518 | return ZYAN_STATUS_SUCCESS; |
79 | 464 | case 64: |
80 | 464 | *result_address = (ZyanU64)operand->mem.disp.value; |
81 | 464 | return ZYAN_STATUS_SUCCESS; |
82 | 0 | default: |
83 | 0 | return ZYAN_STATUS_INVALID_ARGUMENT; |
84 | 1.18k | } |
85 | 1.18k | } |
86 | 416 | break; |
87 | 416 | case ZYDIS_OPERAND_TYPE_IMMEDIATE: |
88 | 240 | if (!operand->imm.is_address) |
89 | 0 | { |
90 | 0 | return ZYAN_STATUS_INVALID_ARGUMENT; |
91 | 0 | } |
92 | | |
93 | 240 | if (operand->imm.is_signed && operand->imm.is_relative) |
94 | 240 | { |
95 | 240 | *result_address = (ZyanU64)((ZyanI64)runtime_address + instruction->length + |
96 | 240 | operand->imm.value.s); |
97 | 240 | switch (instruction->machine_mode) |
98 | 240 | { |
99 | 43 | case ZYDIS_MACHINE_MODE_LONG_COMPAT_16: |
100 | 55 | case ZYDIS_MACHINE_MODE_LEGACY_16: |
101 | 68 | case ZYDIS_MACHINE_MODE_REAL_16: |
102 | 99 | case ZYDIS_MACHINE_MODE_LONG_COMPAT_32: |
103 | 121 | case ZYDIS_MACHINE_MODE_LEGACY_32: |
104 | | // `XBEGIN` is a special case as it doesn't truncate computed address |
105 | | // This behavior is documented by Intel (SDM Vol. 2C): |
106 | | // Use of the 16-bit operand size does not cause this address to be truncated to |
107 | | // 16 bits, unlike a near jump to a relative offset. |
108 | 121 | if ((instruction->operand_width == 16) && |
109 | 121 | (instruction->mnemonic != ZYDIS_MNEMONIC_XBEGIN)) |
110 | 67 | { |
111 | 67 | *result_address &= 0xFFFF; |
112 | 67 | } |
113 | 121 | break; |
114 | 119 | case ZYDIS_MACHINE_MODE_LONG_64: |
115 | 119 | break; |
116 | 0 | default: |
117 | 0 | return ZYAN_STATUS_INVALID_ARGUMENT; |
118 | 240 | } |
119 | 240 | return ZYAN_STATUS_SUCCESS; |
120 | 240 | } |
121 | 0 | else if (!operand->imm.is_signed && !operand->imm.is_relative && |
122 | 0 | (instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)) |
123 | 0 | { |
124 | 0 | *result_address = operand->imm.value.u; |
125 | 0 | return ZYAN_STATUS_SUCCESS; |
126 | 0 | } |
127 | 0 | break; |
128 | 0 | default: |
129 | 0 | break; |
130 | 4.33k | } |
131 | | |
132 | 416 | return ZYAN_STATUS_INVALID_ARGUMENT; |
133 | 4.33k | } |
134 | | |
135 | | ZyanStatus ZydisCalcAbsoluteAddressEx(const ZydisDecodedInstruction* instruction, |
136 | | const ZydisDecodedOperand* operand, ZyanU64 runtime_address, |
137 | | const ZydisRegisterContext* register_context, ZyanU64* result_address) |
138 | 0 | { |
139 | | // TODO: Test this with AGEN/MIB operands |
140 | | // TODO: Add support for Gather/Scatter instructions |
141 | |
|
142 | 0 | if (!instruction || !operand || !register_context || !result_address) |
143 | 0 | { |
144 | 0 | return ZYAN_STATUS_INVALID_ARGUMENT; |
145 | 0 | } |
146 | | |
147 | 0 | if ((operand->type != ZYDIS_OPERAND_TYPE_REGISTER) && |
148 | 0 | ((operand->type != ZYDIS_OPERAND_TYPE_MEMORY) || |
149 | 0 | ((operand->mem.base == ZYDIS_REGISTER_NONE) && |
150 | 0 | (operand->mem.index == ZYDIS_REGISTER_NONE)) || |
151 | 0 | (operand->mem.base == ZYDIS_REGISTER_EIP) || |
152 | 0 | (operand->mem.base == ZYDIS_REGISTER_RIP))) |
153 | 0 | { |
154 | 0 | return ZydisCalcAbsoluteAddress(instruction, operand, runtime_address, result_address); |
155 | 0 | } |
156 | | |
157 | 0 | ZyanU64 value; |
158 | 0 | if (operand->type == ZYDIS_OPERAND_TYPE_REGISTER) |
159 | 0 | { |
160 | 0 | value = register_context->values[operand->reg.value]; |
161 | 0 | } |
162 | 0 | else if (operand->type == ZYDIS_OPERAND_TYPE_MEMORY) |
163 | 0 | { |
164 | 0 | value = operand->mem.disp.value; |
165 | 0 | if (operand->mem.base) |
166 | 0 | { |
167 | 0 | value += register_context->values[operand->mem.base]; |
168 | 0 | } |
169 | 0 | if (operand->mem.index) |
170 | 0 | { |
171 | 0 | value += register_context->values[operand->mem.index] * operand->mem.scale; |
172 | 0 | } |
173 | 0 | } |
174 | 0 | else |
175 | 0 | { |
176 | 0 | return ZYAN_STATUS_INVALID_ARGUMENT; |
177 | 0 | } |
178 | | |
179 | 0 | switch (instruction->address_width) |
180 | 0 | { |
181 | 0 | case 16: |
182 | 0 | *result_address = value & 0x000000000000FFFF; |
183 | 0 | return ZYAN_STATUS_SUCCESS; |
184 | 0 | case 32: |
185 | 0 | *result_address = value & 0x00000000FFFFFFFF; |
186 | 0 | return ZYAN_STATUS_SUCCESS; |
187 | 0 | case 64: |
188 | 0 | *result_address = value; |
189 | 0 | return ZYAN_STATUS_SUCCESS; |
190 | 0 | default: |
191 | 0 | return ZYAN_STATUS_INVALID_ARGUMENT; |
192 | 0 | } |
193 | 0 | } |
194 | | |
195 | | /* ============================================================================================== */ |