Coverage Report

Created: 2026-08-13 06:11

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
2.12k
#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.62k
{
49
7.62k
  PIMAGE_DOS_HEADER mz_header;
50
7.62k
  PIMAGE_NT_HEADERS32 pe_header;
51
52
7.62k
  size_t headers_size = 0;
53
54
7.62k
  if (buffer_length < sizeof(IMAGE_DOS_HEADER))
55
1.20k
    return NULL;
56
57
6.41k
  mz_header = (PIMAGE_DOS_HEADER) buffer;
58
59
6.41k
  if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE)
60
6.14k
    return NULL;
61
62
265
  if ((int32_t) yr_le32toh(mz_header->e_lfanew) < 0)
63
35
    return NULL;
64
65
230
  headers_size = yr_le32toh(mz_header->e_lfanew) +
66
230
                 sizeof(pe_header->Signature) + sizeof(IMAGE_FILE_HEADER);
67
68
230
  if (buffer_length < headers_size)
69
29
    return NULL;
70
71
201
  pe_header = (PIMAGE_NT_HEADERS32)(buffer + yr_le32toh(mz_header->e_lfanew));
72
73
201
  headers_size += sizeof(IMAGE_OPTIONAL_HEADER32);
74
75
201
  if (yr_le32toh(pe_header->Signature) == IMAGE_NT_SIGNATURE &&
76
147
      (yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_I386 ||
77
35
       yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_AMD64) &&
78
113
      buffer_length > headers_size)
79
103
  {
80
103
    return pe_header;
81
103
  }
82
98
  else
83
98
  {
84
98
    return NULL;
85
98
  }
86
201
}
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
103
{
93
103
  int i = 0;
94
103
  PIMAGE_SECTION_HEADER section;
95
103
  DWORD section_rva;
96
103
  DWORD section_offset;
97
98
103
  section = IMAGE_FIRST_SECTION(pe_header);
99
103
  section_rva = 0;
100
103
  section_offset = 0;
101
102
2.12k
  while (i < MIN(yr_le16toh(pe_header->FileHeader.NumberOfSections), 60))
103
2.09k
  {
104
2.09k
    if ((uint8_t*) section - (uint8_t*) pe_header +
105
2.09k
            sizeof(IMAGE_SECTION_HEADER) <
106
2.09k
        buffer_length)
107
2.02k
    {
108
2.02k
      if (rva >= yr_le32toh(section->VirtualAddress) &&
109
1.42k
          section_rva <= yr_le32toh(section->VirtualAddress))
110
417
      {
111
417
        section_rva = yr_le32toh(section->VirtualAddress);
112
417
        section_offset = yr_le32toh(section->PointerToRawData);
113
417
      }
114
115
2.02k
      section++;
116
2.02k
      i++;
117
2.02k
    }
118
71
    else
119
71
    {
120
71
      return 0;
121
71
    }
122
2.09k
  }
123
124
32
  return section_offset + (rva - section_rva);
125
103
}
126
127
int yr_get_elf_type(const uint8_t* buffer, size_t buffer_length)
128
7.51k
{
129
7.51k
  elf_ident_t* elf_ident;
130
131
7.51k
  if (buffer_length < sizeof(elf_ident_t))
132
17
    return 0;
133
134
7.50k
  elf_ident = (elf_ident_t*) buffer;
135
136
7.50k
  if (yr_le32toh(elf_ident->magic) != ELF_MAGIC)
137
223
  {
138
223
    return 0;
139
223
  }
140
141
7.27k
  switch (elf_ident->_class)
142
7.27k
  {
143
2.78k
  case ELF_CLASS_32:
144
2.78k
    if (buffer_length < sizeof(elf32_header_t))
145
31
    {
146
31
      return 0;
147
31
    }
148
2.75k
    break;
149
4.47k
  case ELF_CLASS_64:
150
4.47k
    if (buffer_length < sizeof(elf64_header_t))
151
22
    {
152
22
      return 0;
153
22
    }
154
4.45k
    break;
155
4.45k
  default:
156
    /* Unexpected class */
157
20
    return 0;
158
7.27k
  }
159
160
7.20k
  return elf_ident->_class;
161
7.27k
}
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
2.75k
{
168
  // if the binary is an executable then prefer the program headers to resolve
169
  // the offset
170
2.75k
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
171
454
  {
172
454
    int i;
173
454
    elf32_program_header_t* program;
174
454
    if (yr_le32toh(elf_header->ph_offset) == 0 ||
175
439
        yr_le16toh(elf_header->ph_entry_count == 0))
176
42
      return 0;
177
178
    // check to prevent integer wraps
179
412
    if (ULONG_MAX - yr_le16toh(elf_header->ph_entry_count) <
180
412
        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
412
    if (ULONG_MAX - yr_le32toh(elf_header->ph_offset) <
186
412
        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
412
    if (yr_le32toh(elf_header->ph_offset) +
191
412
            sizeof(elf32_program_header_t) *
192
412
                yr_le16toh(elf_header->ph_entry_count) >
193
412
        buffer_length)
194
168
      return 0;
195
196
244
    program =
197
244
        (elf32_program_header_t*) ((uint8_t*) elf_header + yr_le32toh(elf_header->ph_offset));
198
199
6.05k
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
200
5.90k
    {
201
5.90k
      if (rva >= yr_le32toh(program->virt_addr) &&
202
5.39k
          rva < yr_le32toh(program->virt_addr) + yr_le32toh(program->mem_size))
203
96
      {
204
96
        return yr_le32toh(program->offset) +
205
96
               (rva - yr_le32toh(program->virt_addr));
206
96
      }
207
208
5.80k
      program++;
209
5.80k
    }
210
244
  }
211
2.30k
  else
212
2.30k
  {
213
2.30k
    int i;
214
2.30k
    elf32_section_header_t* section;
215
216
2.30k
    if (yr_le32toh(elf_header->sh_offset) == 0 ||
217
2.19k
        yr_le16toh(elf_header->sh_entry_count == 0))
218
164
      return 0;
219
220
    // check to prevent integer wraps
221
222
2.13k
    if (ULONG_MAX - yr_le16toh(elf_header->sh_entry_count) <
223
2.13k
        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
2.13k
    if (ULONG_MAX - yr_le32toh(elf_header->sh_offset) <
230
2.13k
        sizeof(elf32_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
231
0
      return 0;
232
233
2.13k
    if (yr_le32toh(elf_header->sh_offset) +
234
2.13k
            sizeof(elf32_section_header_t) *
235
2.13k
                yr_le16toh(elf_header->sh_entry_count) >
236
2.13k
        buffer_length)
237
1.27k
      return 0;
238
239
864
    section = (elf32_section_header_t*)
240
864
      ((unsigned char*) elf_header + yr_le32toh(elf_header->sh_offset));
241
242
16.1k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
243
15.6k
    {
244
15.6k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
245
13.2k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
246
12.9k
          rva >= yr_le32toh(section->addr) &&
247
4.67k
          rva < yr_le32toh(section->addr) + yr_le32toh(section->size))
248
386
      {
249
        // prevent integer wrapping with the return value
250
251
386
        if (ULONG_MAX - yr_le32toh(section->offset) <
252
386
            (rva - yr_le32toh(section->addr)))
253
0
          return 0;
254
386
        else
255
386
          return yr_le32toh(section->offset) +
256
386
                 (rva - yr_le32toh(section->addr));
257
386
      }
258
259
15.2k
      section++;
260
15.2k
    }
261
864
  }
262
263
626
  return 0;
264
2.75k
}
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
4.45k
{
271
  // if the binary is an executable then prefer the program headers to resolve
272
  // the offset
273
4.45k
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
274
741
  {
275
741
    int i;
276
741
    elf64_program_header_t* program;
277
741
    if (yr_le64toh(elf_header->ph_offset) == 0 ||
278
733
        yr_le16toh(elf_header->ph_entry_count == 0))
279
67
      return 0;
280
281
    // check that 'ph_offset' doesn't wrap when added to the
282
    // size of entries.
283
674
    if (ULONG_MAX - yr_le64toh(elf_header->ph_offset) <
284
674
        sizeof(elf64_program_header_t) * yr_le16toh(elf_header->ph_entry_count))
285
29
      return 0;
286
287
    // ensure we don't exceed the buffer size
288
645
    if (yr_le64toh(elf_header->ph_offset) +
289
645
            sizeof(elf64_program_header_t) *
290
645
                yr_le16toh(elf_header->ph_entry_count) >
291
645
        buffer_length)
292
319
      return 0;
293
294
326
    program =
295
326
        (elf64_program_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->ph_offset));
296
297
3.64k
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
298
3.37k
    {
299
3.37k
      if (rva >= yr_le64toh(program->virt_addr) &&
300
2.94k
          rva < yr_le64toh(program->virt_addr) + yr_le64toh(program->mem_size))
301
47
      {
302
47
        return yr_le64toh(program->offset) +
303
47
               (rva - yr_le64toh(program->virt_addr));
304
47
      }
305
306
3.32k
      program++;
307
3.32k
    }
308
326
  }
309
3.70k
  else
310
3.70k
  {
311
3.70k
    int i;
312
3.70k
    elf64_section_header_t* section;
313
314
3.70k
    if (yr_le64toh(elf_header->sh_offset) == 0 ||
315
3.58k
        yr_le16toh(elf_header->sh_entry_count) == 0)
316
292
      return 0;
317
318
    // check that 'sh_offset' doesn't wrap when added to the
319
    // size of entries.
320
3.41k
    if (ULONG_MAX - yr_le64toh(elf_header->sh_offset) <
321
3.41k
        sizeof(elf64_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
322
51
      return 0;
323
324
3.36k
    if (yr_le64toh(elf_header->sh_offset) +
325
3.36k
            sizeof(elf64_section_header_t) *
326
3.36k
                yr_le16toh(elf_header->sh_entry_count) >
327
3.36k
        buffer_length)
328
2.19k
      return 0;
329
330
1.17k
    section =
331
1.17k
        (elf64_section_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->sh_offset));
332
333
9.23k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
334
8.78k
    {
335
8.78k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
336
7.32k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
337
6.89k
          rva >= yr_le64toh(section->addr) &&
338
6.04k
          rva < yr_le64toh(section->addr) + yr_le64toh(section->size))
339
725
      {
340
725
        return yr_le64toh(section->offset) + (rva - yr_le64toh(section->addr));
341
725
      }
342
343
8.05k
      section++;
344
8.05k
    }
345
1.17k
  }
346
347
726
  return 0;
348
4.45k
}
349
350
uint64_t yr_get_entry_point_offset(const uint8_t* buffer, size_t buffer_length)
351
7.62k
{
352
7.62k
  PIMAGE_NT_HEADERS32 pe_header;
353
7.62k
  elf32_header_t* elf_header32;
354
7.62k
  elf64_header_t* elf_header64;
355
356
7.62k
  pe_header = yr_get_pe_header(buffer, buffer_length);
357
358
7.62k
  if (pe_header != NULL)
359
103
  {
360
103
    return yr_pe_rva_to_offset(
361
103
        pe_header,
362
103
        yr_le32toh(pe_header->OptionalHeader.AddressOfEntryPoint),
363
103
        buffer_length - ((uint8_t*) pe_header - buffer));
364
103
  }
365
366
7.51k
  switch (yr_get_elf_type(buffer, buffer_length))
367
7.51k
  {
368
2.75k
  case ELF_CLASS_32:
369
2.75k
    elf_header32 = (elf32_header_t*) buffer;
370
2.75k
    return yr_elf_rva_to_offset_32(
371
2.75k
        elf_header32, yr_le32toh(elf_header32->entry), buffer_length);
372
373
4.45k
  case ELF_CLASS_64:
374
4.45k
    elf_header64 = (elf64_header_t*) buffer;
375
4.45k
    return yr_elf_rva_to_offset_64(
376
4.45k
        elf_header64, yr_le64toh(elf_header64->entry), buffer_length);
377
7.51k
  }
378
379
313
  return YR_UNDEFINED;
380
7.51k
}
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
}