Coverage Report

Created: 2025-08-29 07:04

/src/zydis/src/Utils.c
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
/* ============================================================================================== */