Coverage Report

Created: 2026-04-12 06:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/yara/libyara/exefiles.c
Line
Count
Source
1
/*
2
Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved.
3
4
Redistribution and use in source and binary forms, with or without modification,
5
are permitted provided that the following conditions are met:
6
7
1. Redistributions of source code must retain the above copyright notice, this
8
list of conditions and the following disclaimer.
9
10
2. Redistributions in binary form must reproduce the above copyright notice,
11
this list of conditions and the following disclaimer in the documentation and/or
12
other materials provided with the distribution.
13
14
3. Neither the name of the copyright holder nor the names of its contributors
15
may be used to endorse or promote products derived from this software without
16
specific prior written permission.
17
18
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
22
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
*/
29
30
#include <limits.h>
31
#include <yara/elf.h>
32
#include <yara/endian.h>
33
#include <yara/exec.h>
34
#include <yara/pe.h>
35
#include <yara/utils.h>
36
37
#ifndef NULL
38
#define NULL 0
39
#endif
40
41
#ifndef MIN
42
12.5k
#define MIN(x, y) ((x < y) ? (x) : (y))
43
#endif
44
45
PIMAGE_NT_HEADERS32 yr_get_pe_header(
46
    const uint8_t* buffer,
47
    size_t buffer_length)
48
7.60k
{
49
7.60k
  PIMAGE_DOS_HEADER mz_header;
50
7.60k
  PIMAGE_NT_HEADERS32 pe_header;
51
52
7.60k
  size_t headers_size = 0;
53
54
7.60k
  if (buffer_length < sizeof(IMAGE_DOS_HEADER))
55
426
    return NULL;
56
57
7.17k
  mz_header = (PIMAGE_DOS_HEADER) buffer;
58
59
7.17k
  if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE)
60
865
    return NULL;
61
62
6.31k
  if ((int32_t) yr_le32toh(mz_header->e_lfanew) < 0)
63
36
    return NULL;
64
65
6.27k
  headers_size = yr_le32toh(mz_header->e_lfanew) +
66
6.27k
                 sizeof(pe_header->Signature) + sizeof(IMAGE_FILE_HEADER);
67
68
6.27k
  if (buffer_length < headers_size)
69
32
    return NULL;
70
71
6.24k
  pe_header = (PIMAGE_NT_HEADERS32)(buffer + yr_le32toh(mz_header->e_lfanew));
72
73
6.24k
  headers_size += sizeof(IMAGE_OPTIONAL_HEADER32);
74
75
6.24k
  if (yr_le32toh(pe_header->Signature) == IMAGE_NT_SIGNATURE &&
76
6.19k
      (yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_I386 ||
77
5.04k
       yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_AMD64) &&
78
1.14k
      buffer_length > headers_size)
79
937
  {
80
937
    return pe_header;
81
937
  }
82
5.30k
  else
83
5.30k
  {
84
5.30k
    return NULL;
85
5.30k
  }
86
6.24k
}
87
88
uint64_t yr_pe_rva_to_offset(
89
    PIMAGE_NT_HEADERS32 pe_header,
90
    uint64_t rva,
91
    size_t buffer_length)
92
937
{
93
937
  int i = 0;
94
937
  PIMAGE_SECTION_HEADER section;
95
937
  DWORD section_rva;
96
937
  DWORD section_offset;
97
98
937
  section = IMAGE_FIRST_SECTION(pe_header);
99
937
  section_rva = 0;
100
937
  section_offset = 0;
101
102
12.5k
  while (i < MIN(yr_le16toh(pe_header->FileHeader.NumberOfSections), 60))
103
11.7k
  {
104
11.7k
    if ((uint8_t*) section - (uint8_t*) pe_header +
105
11.7k
            sizeof(IMAGE_SECTION_HEADER) <
106
11.7k
        buffer_length)
107
11.6k
    {
108
11.6k
      if (rva >= yr_le32toh(section->VirtualAddress) &&
109
4.35k
          section_rva <= yr_le32toh(section->VirtualAddress))
110
1.29k
      {
111
1.29k
        section_rva = yr_le32toh(section->VirtualAddress);
112
1.29k
        section_offset = yr_le32toh(section->PointerToRawData);
113
1.29k
      }
114
115
11.6k
      section++;
116
11.6k
      i++;
117
11.6k
    }
118
72
    else
119
72
    {
120
72
      return 0;
121
72
    }
122
11.7k
  }
123
124
865
  return section_offset + (rva - section_rva);
125
937
}
126
127
int yr_get_elf_type(const uint8_t* buffer, size_t buffer_length)
128
6.66k
{
129
6.66k
  elf_ident_t* elf_ident;
130
131
6.66k
  if (buffer_length < sizeof(elf_ident_t))
132
25
    return 0;
133
134
6.64k
  elf_ident = (elf_ident_t*) buffer;
135
136
6.64k
  if (yr_le32toh(elf_ident->magic) != ELF_MAGIC)
137
5.46k
  {
138
5.46k
    return 0;
139
5.46k
  }
140
141
1.18k
  switch (elf_ident->_class)
142
1.18k
  {
143
433
  case ELF_CLASS_32:
144
433
    if (buffer_length < sizeof(elf32_header_t))
145
10
    {
146
10
      return 0;
147
10
    }
148
423
    break;
149
749
  case ELF_CLASS_64:
150
749
    if (buffer_length < sizeof(elf64_header_t))
151
1
    {
152
1
      return 0;
153
1
    }
154
748
    break;
155
748
  default:
156
    /* Unexpected class */
157
1
    return 0;
158
1.18k
  }
159
160
1.17k
  return elf_ident->_class;
161
1.18k
}
162
163
static uint64_t yr_elf_rva_to_offset_32(
164
    elf32_header_t* elf_header,
165
    uint64_t rva,
166
    size_t buffer_length)
167
423
{
168
  // if the binary is an executable then prefer the program headers to resolve
169
  // the offset
170
423
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
171
183
  {
172
183
    int i;
173
183
    elf32_program_header_t* program;
174
183
    if (yr_le32toh(elf_header->ph_offset) == 0 ||
175
182
        yr_le16toh(elf_header->ph_entry_count == 0))
176
7
      return 0;
177
178
    // check to prevent integer wraps
179
176
    if (ULONG_MAX - yr_le16toh(elf_header->ph_entry_count) <
180
176
        sizeof(elf32_program_header_t) * yr_le16toh(elf_header->ph_entry_count))
181
0
      return 0;
182
183
    // check that 'ph_offset' doesn't wrap when added to the
184
    // size of entries.
185
176
    if (ULONG_MAX - yr_le32toh(elf_header->ph_offset) <
186
176
        sizeof(elf32_program_header_t) * yr_le16toh(elf_header->ph_entry_count))
187
0
      return 0;
188
189
    // ensure we don't exceed the buffer size
190
176
    if (yr_le32toh(elf_header->ph_offset) +
191
176
            sizeof(elf32_program_header_t) *
192
176
                yr_le16toh(elf_header->ph_entry_count) >
193
176
        buffer_length)
194
83
      return 0;
195
196
93
    program =
197
93
        (elf32_program_header_t*) ((uint8_t*) elf_header + yr_le32toh(elf_header->ph_offset));
198
199
1.00k
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
200
953
    {
201
953
      if (rva >= yr_le32toh(program->virt_addr) &&
202
662
          rva < yr_le32toh(program->virt_addr) + yr_le32toh(program->mem_size))
203
39
      {
204
39
        return yr_le32toh(program->offset) +
205
39
               (rva - yr_le32toh(program->virt_addr));
206
39
      }
207
208
914
      program++;
209
914
    }
210
93
  }
211
240
  else
212
240
  {
213
240
    int i;
214
240
    elf32_section_header_t* section;
215
216
240
    if (yr_le32toh(elf_header->sh_offset) == 0 ||
217
239
        yr_le16toh(elf_header->sh_entry_count == 0))
218
7
      return 0;
219
220
    // check to prevent integer wraps
221
222
233
    if (ULONG_MAX - yr_le16toh(elf_header->sh_entry_count) <
223
233
        sizeof(elf32_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
224
0
      return 0;
225
226
    // check that 'sh_offset' doesn't wrap when added to the
227
    // size of entries.
228
229
233
    if (ULONG_MAX - yr_le32toh(elf_header->sh_offset) <
230
233
        sizeof(elf32_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
231
0
      return 0;
232
233
233
    if (yr_le32toh(elf_header->sh_offset) +
234
233
            sizeof(elf32_section_header_t) *
235
233
                yr_le16toh(elf_header->sh_entry_count) >
236
233
        buffer_length)
237
85
      return 0;
238
239
148
    section = (elf32_section_header_t*)
240
148
      ((unsigned char*) elf_header + yr_le32toh(elf_header->sh_offset));
241
242
2.72k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
243
2.66k
    {
244
2.66k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
245
2.30k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
246
2.07k
          rva >= yr_le32toh(section->addr) &&
247
1.54k
          rva < yr_le32toh(section->addr) + yr_le32toh(section->size))
248
86
      {
249
        // prevent integer wrapping with the return value
250
251
86
        if (ULONG_MAX - yr_le32toh(section->offset) <
252
86
            (rva - yr_le32toh(section->addr)))
253
0
          return 0;
254
86
        else
255
86
          return yr_le32toh(section->offset) +
256
86
                 (rva - yr_le32toh(section->addr));
257
86
      }
258
259
2.57k
      section++;
260
2.57k
    }
261
148
  }
262
263
116
  return 0;
264
423
}
265
266
static uint64_t yr_elf_rva_to_offset_64(
267
    elf64_header_t* elf_header,
268
    uint64_t rva,
269
    size_t buffer_length)
270
748
{
271
  // if the binary is an executable then prefer the program headers to resolve
272
  // the offset
273
748
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
274
350
  {
275
350
    int i;
276
350
    elf64_program_header_t* program;
277
350
    if (yr_le64toh(elf_header->ph_offset) == 0 ||
278
349
        yr_le16toh(elf_header->ph_entry_count == 0))
279
7
      return 0;
280
281
    // check that 'ph_offset' doesn't wrap when added to the
282
    // size of entries.
283
343
    if (ULONG_MAX - yr_le64toh(elf_header->ph_offset) <
284
343
        sizeof(elf64_program_header_t) * yr_le16toh(elf_header->ph_entry_count))
285
19
      return 0;
286
287
    // ensure we don't exceed the buffer size
288
324
    if (yr_le64toh(elf_header->ph_offset) +
289
324
            sizeof(elf64_program_header_t) *
290
324
                yr_le16toh(elf_header->ph_entry_count) >
291
324
        buffer_length)
292
157
      return 0;
293
294
167
    program =
295
167
        (elf64_program_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->ph_offset));
296
297
887
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
298
741
    {
299
741
      if (rva >= yr_le64toh(program->virt_addr) &&
300
487
          rva < yr_le64toh(program->virt_addr) + yr_le64toh(program->mem_size))
301
21
      {
302
21
        return yr_le64toh(program->offset) +
303
21
               (rva - yr_le64toh(program->virt_addr));
304
21
      }
305
306
720
      program++;
307
720
    }
308
167
  }
309
398
  else
310
398
  {
311
398
    int i;
312
398
    elf64_section_header_t* section;
313
314
398
    if (yr_le64toh(elf_header->sh_offset) == 0 ||
315
397
        yr_le16toh(elf_header->sh_entry_count) == 0)
316
8
      return 0;
317
318
    // check that 'sh_offset' doesn't wrap when added to the
319
    // size of entries.
320
390
    if (ULONG_MAX - yr_le64toh(elf_header->sh_offset) <
321
390
        sizeof(elf64_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
322
20
      return 0;
323
324
370
    if (yr_le64toh(elf_header->sh_offset) +
325
370
            sizeof(elf64_section_header_t) *
326
370
                yr_le16toh(elf_header->sh_entry_count) >
327
370
        buffer_length)
328
156
      return 0;
329
330
214
    section =
331
214
        (elf64_section_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->sh_offset));
332
333
3.29k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
334
3.11k
    {
335
3.11k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
336
2.74k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
337
2.53k
          rva >= yr_le64toh(section->addr) &&
338
2.12k
          rva < yr_le64toh(section->addr) + yr_le64toh(section->size))
339
34
      {
340
34
        return yr_le64toh(section->offset) + (rva - yr_le64toh(section->addr));
341
34
      }
342
343
3.08k
      section++;
344
3.08k
    }
345
214
  }
346
347
326
  return 0;
348
748
}
349
350
uint64_t yr_get_entry_point_offset(const uint8_t* buffer, size_t buffer_length)
351
7.60k
{
352
7.60k
  PIMAGE_NT_HEADERS32 pe_header;
353
7.60k
  elf32_header_t* elf_header32;
354
7.60k
  elf64_header_t* elf_header64;
355
356
7.60k
  pe_header = yr_get_pe_header(buffer, buffer_length);
357
358
7.60k
  if (pe_header != NULL)
359
937
  {
360
937
    return yr_pe_rva_to_offset(
361
937
        pe_header,
362
937
        yr_le32toh(pe_header->OptionalHeader.AddressOfEntryPoint),
363
937
        buffer_length - ((uint8_t*) pe_header - buffer));
364
937
  }
365
366
6.66k
  switch (yr_get_elf_type(buffer, buffer_length))
367
6.66k
  {
368
423
  case ELF_CLASS_32:
369
423
    elf_header32 = (elf32_header_t*) buffer;
370
423
    return yr_elf_rva_to_offset_32(
371
423
        elf_header32, yr_le32toh(elf_header32->entry), buffer_length);
372
373
748
  case ELF_CLASS_64:
374
748
    elf_header64 = (elf64_header_t*) buffer;
375
748
    return yr_elf_rva_to_offset_64(
376
748
        elf_header64, yr_le64toh(elf_header64->entry), buffer_length);
377
6.66k
  }
378
379
5.49k
  return YR_UNDEFINED;
380
6.66k
}
381
382
uint64_t yr_get_entry_point_address(
383
    const uint8_t* buffer,
384
    size_t buffer_length,
385
    uint64_t base_address)
386
0
{
387
0
  PIMAGE_NT_HEADERS32 pe_header;
388
389
0
  elf32_header_t* elf_header32;
390
0
  elf64_header_t* elf_header64;
391
392
0
  pe_header = yr_get_pe_header(buffer, buffer_length);
393
394
  // If file is PE but not a DLL.
395
396
0
  if (pe_header != NULL &&
397
0
      !(pe_header->FileHeader.Characteristics & IMAGE_FILE_DLL))
398
0
    return base_address + pe_header->OptionalHeader.AddressOfEntryPoint;
399
400
  // If file is executable ELF, not shared library.
401
402
0
  switch (yr_get_elf_type(buffer, buffer_length))
403
0
  {
404
0
  case ELF_CLASS_32:
405
0
    elf_header32 = (elf32_header_t*) buffer;
406
407
0
    if (elf_header32->type == ELF_ET_EXEC)
408
0
      return base_address + elf_header32->entry;
409
410
0
    break;
411
412
0
  case ELF_CLASS_64:
413
0
    elf_header64 = (elf64_header_t*) buffer;
414
415
0
    if (elf_header64->type == ELF_ET_EXEC)
416
0
      return base_address + elf_header64->entry;
417
418
0
    break;
419
0
  }
420
421
0
  return YR_UNDEFINED;
422
0
}