Coverage Report

Created: 2026-08-31 06:09

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
16.2k
#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
16.3k
{
49
16.3k
  PIMAGE_DOS_HEADER mz_header;
50
16.3k
  PIMAGE_NT_HEADERS32 pe_header;
51
52
16.3k
  size_t headers_size = 0;
53
54
16.3k
  if (buffer_length < sizeof(IMAGE_DOS_HEADER))
55
2.17k
    return NULL;
56
57
14.2k
  mz_header = (PIMAGE_DOS_HEADER) buffer;
58
59
14.2k
  if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE)
60
7.64k
    return NULL;
61
62
6.57k
  if ((int32_t) yr_le32toh(mz_header->e_lfanew) < 0)
63
101
    return NULL;
64
65
6.47k
  headers_size = yr_le32toh(mz_header->e_lfanew) +
66
6.47k
                 sizeof(pe_header->Signature) + sizeof(IMAGE_FILE_HEADER);
67
68
6.47k
  if (buffer_length < headers_size)
69
87
    return NULL;
70
71
6.38k
  pe_header = (PIMAGE_NT_HEADERS32)(buffer + yr_le32toh(mz_header->e_lfanew));
72
73
6.38k
  headers_size += sizeof(IMAGE_OPTIONAL_HEADER32);
74
75
6.38k
  if (yr_le32toh(pe_header->Signature) == IMAGE_NT_SIGNATURE &&
76
6.22k
      (yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_I386 ||
77
4.86k
       yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_AMD64) &&
78
1.37k
      buffer_length > headers_size)
79
1.14k
  {
80
1.14k
    return pe_header;
81
1.14k
  }
82
5.24k
  else
83
5.24k
  {
84
5.24k
    return NULL;
85
5.24k
  }
86
6.38k
}
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
1.14k
{
93
1.14k
  int i = 0;
94
1.14k
  PIMAGE_SECTION_HEADER section;
95
1.14k
  DWORD section_rva;
96
1.14k
  DWORD section_offset;
97
98
1.14k
  section = IMAGE_FIRST_SECTION(pe_header);
99
1.14k
  section_rva = 0;
100
1.14k
  section_offset = 0;
101
102
16.2k
  while (i < MIN(yr_le16toh(pe_header->FileHeader.NumberOfSections), 60))
103
15.2k
  {
104
15.2k
    if ((uint8_t*) section - (uint8_t*) pe_header +
105
15.2k
            sizeof(IMAGE_SECTION_HEADER) <
106
15.2k
        buffer_length)
107
15.0k
    {
108
15.0k
      if (rva >= yr_le32toh(section->VirtualAddress) &&
109
7.36k
          section_rva <= yr_le32toh(section->VirtualAddress))
110
2.43k
      {
111
2.43k
        section_rva = yr_le32toh(section->VirtualAddress);
112
2.43k
        section_offset = yr_le32toh(section->PointerToRawData);
113
2.43k
      }
114
115
15.0k
      section++;
116
15.0k
      i++;
117
15.0k
    }
118
239
    else
119
239
    {
120
239
      return 0;
121
239
    }
122
15.2k
  }
123
124
906
  return section_offset + (rva - section_rva);
125
1.14k
}
126
127
int yr_get_elf_type(const uint8_t* buffer, size_t buffer_length)
128
15.2k
{
129
15.2k
  elf_ident_t* elf_ident;
130
131
15.2k
  if (buffer_length < sizeof(elf_ident_t))
132
127
    return 0;
133
134
15.1k
  elf_ident = (elf_ident_t*) buffer;
135
136
15.1k
  if (yr_le32toh(elf_ident->magic) != ELF_MAGIC)
137
5.73k
  {
138
5.73k
    return 0;
139
5.73k
  }
140
141
9.38k
  switch (elf_ident->_class)
142
9.38k
  {
143
3.60k
  case ELF_CLASS_32:
144
3.60k
    if (buffer_length < sizeof(elf32_header_t))
145
49
    {
146
49
      return 0;
147
49
    }
148
3.55k
    break;
149
5.74k
  case ELF_CLASS_64:
150
5.74k
    if (buffer_length < sizeof(elf64_header_t))
151
30
    {
152
30
      return 0;
153
30
    }
154
5.71k
    break;
155
5.71k
  default:
156
    /* Unexpected class */
157
28
    return 0;
158
9.38k
  }
159
160
9.27k
  return elf_ident->_class;
161
9.38k
}
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
3.55k
{
168
  // if the binary is an executable then prefer the program headers to resolve
169
  // the offset
170
3.55k
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
171
780
  {
172
780
    int i;
173
780
    elf32_program_header_t* program;
174
780
    if (yr_le32toh(elf_header->ph_offset) == 0 ||
175
765
        yr_le16toh(elf_header->ph_entry_count == 0))
176
57
      return 0;
177
178
    // check to prevent integer wraps
179
723
    if (ULONG_MAX - yr_le16toh(elf_header->ph_entry_count) <
180
723
        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
723
    if (ULONG_MAX - yr_le32toh(elf_header->ph_offset) <
186
723
        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
723
    if (yr_le32toh(elf_header->ph_offset) +
191
723
            sizeof(elf32_program_header_t) *
192
723
                yr_le16toh(elf_header->ph_entry_count) >
193
723
        buffer_length)
194
301
      return 0;
195
196
422
    program =
197
422
        (elf32_program_header_t*) ((uint8_t*) elf_header + yr_le32toh(elf_header->ph_offset));
198
199
8.76k
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
200
8.49k
    {
201
8.49k
      if (rva >= yr_le32toh(program->virt_addr) &&
202
7.54k
          rva < yr_le32toh(program->virt_addr) + yr_le32toh(program->mem_size))
203
151
      {
204
151
        return yr_le32toh(program->offset) +
205
151
               (rva - yr_le32toh(program->virt_addr));
206
151
      }
207
208
8.34k
      program++;
209
8.34k
    }
210
422
  }
211
2.77k
  else
212
2.77k
  {
213
2.77k
    int i;
214
2.77k
    elf32_section_header_t* section;
215
216
2.77k
    if (yr_le32toh(elf_header->sh_offset) == 0 ||
217
2.65k
        yr_le16toh(elf_header->sh_entry_count == 0))
218
199
      return 0;
219
220
    // check to prevent integer wraps
221
222
2.57k
    if (ULONG_MAX - yr_le16toh(elf_header->sh_entry_count) <
223
2.57k
        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.57k
    if (ULONG_MAX - yr_le32toh(elf_header->sh_offset) <
230
2.57k
        sizeof(elf32_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
231
0
      return 0;
232
233
2.57k
    if (yr_le32toh(elf_header->sh_offset) +
234
2.57k
            sizeof(elf32_section_header_t) *
235
2.57k
                yr_le16toh(elf_header->sh_entry_count) >
236
2.57k
        buffer_length)
237
1.44k
      return 0;
238
239
1.13k
    section = (elf32_section_header_t*)
240
1.13k
      ((unsigned char*) elf_header + yr_le32toh(elf_header->sh_offset));
241
242
23.9k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
243
23.3k
    {
244
23.3k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
245
19.8k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
246
19.0k
          rva >= yr_le32toh(section->addr) &&
247
10.4k
          rva < yr_le32toh(section->addr) + yr_le32toh(section->size))
248
539
      {
249
        // prevent integer wrapping with the return value
250
251
539
        if (ULONG_MAX - yr_le32toh(section->offset) <
252
539
            (rva - yr_le32toh(section->addr)))
253
0
          return 0;
254
539
        else
255
539
          return yr_le32toh(section->offset) +
256
539
                 (rva - yr_le32toh(section->addr));
257
539
      }
258
259
22.8k
      section++;
260
22.8k
    }
261
1.13k
  }
262
263
862
  return 0;
264
3.55k
}
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
5.71k
{
271
  // if the binary is an executable then prefer the program headers to resolve
272
  // the offset
273
5.71k
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
274
1.37k
  {
275
1.37k
    int i;
276
1.37k
    elf64_program_header_t* program;
277
1.37k
    if (yr_le64toh(elf_header->ph_offset) == 0 ||
278
1.37k
        yr_le16toh(elf_header->ph_entry_count == 0))
279
64
      return 0;
280
281
    // check that 'ph_offset' doesn't wrap when added to the
282
    // size of entries.
283
1.31k
    if (ULONG_MAX - yr_le64toh(elf_header->ph_offset) <
284
1.31k
        sizeof(elf64_program_header_t) * yr_le16toh(elf_header->ph_entry_count))
285
56
      return 0;
286
287
    // ensure we don't exceed the buffer size
288
1.25k
    if (yr_le64toh(elf_header->ph_offset) +
289
1.25k
            sizeof(elf64_program_header_t) *
290
1.25k
                yr_le16toh(elf_header->ph_entry_count) >
291
1.25k
        buffer_length)
292
635
      return 0;
293
294
622
    program =
295
622
        (elf64_program_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->ph_offset));
296
297
6.06k
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
298
5.54k
    {
299
5.54k
      if (rva >= yr_le64toh(program->virt_addr) &&
300
4.48k
          rva < yr_le64toh(program->virt_addr) + yr_le64toh(program->mem_size))
301
97
      {
302
97
        return yr_le64toh(program->offset) +
303
97
               (rva - yr_le64toh(program->virt_addr));
304
97
      }
305
306
5.44k
      program++;
307
5.44k
    }
308
622
  }
309
4.34k
  else
310
4.34k
  {
311
4.34k
    int i;
312
4.34k
    elf64_section_header_t* section;
313
314
4.34k
    if (yr_le64toh(elf_header->sh_offset) == 0 ||
315
4.19k
        yr_le16toh(elf_header->sh_entry_count) == 0)
316
299
      return 0;
317
318
    // check that 'sh_offset' doesn't wrap when added to the
319
    // size of entries.
320
4.04k
    if (ULONG_MAX - yr_le64toh(elf_header->sh_offset) <
321
4.04k
        sizeof(elf64_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
322
105
      return 0;
323
324
3.93k
    if (yr_le64toh(elf_header->sh_offset) +
325
3.93k
            sizeof(elf64_section_header_t) *
326
3.93k
                yr_le16toh(elf_header->sh_entry_count) >
327
3.93k
        buffer_length)
328
2.42k
      return 0;
329
330
1.51k
    section =
331
1.51k
        (elf64_section_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->sh_offset));
332
333
18.6k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
334
17.8k
    {
335
17.8k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
336
15.8k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
337
14.8k
          rva >= yr_le64toh(section->addr) &&
338
13.2k
          rva < yr_le64toh(section->addr) + yr_le64toh(section->size))
339
699
      {
340
699
        return yr_le64toh(section->offset) + (rva - yr_le64toh(section->addr));
341
699
      }
342
343
17.1k
      section++;
344
17.1k
    }
345
1.51k
  }
346
347
1.33k
  return 0;
348
5.71k
}
349
350
uint64_t yr_get_entry_point_offset(const uint8_t* buffer, size_t buffer_length)
351
16.3k
{
352
16.3k
  PIMAGE_NT_HEADERS32 pe_header;
353
16.3k
  elf32_header_t* elf_header32;
354
16.3k
  elf64_header_t* elf_header64;
355
356
16.3k
  pe_header = yr_get_pe_header(buffer, buffer_length);
357
358
16.3k
  if (pe_header != NULL)
359
1.14k
  {
360
1.14k
    return yr_pe_rva_to_offset(
361
1.14k
        pe_header,
362
1.14k
        yr_le32toh(pe_header->OptionalHeader.AddressOfEntryPoint),
363
1.14k
        buffer_length - ((uint8_t*) pe_header - buffer));
364
1.14k
  }
365
366
15.2k
  switch (yr_get_elf_type(buffer, buffer_length))
367
15.2k
  {
368
3.55k
  case ELF_CLASS_32:
369
3.55k
    elf_header32 = (elf32_header_t*) buffer;
370
3.55k
    return yr_elf_rva_to_offset_32(
371
3.55k
        elf_header32, yr_le32toh(elf_header32->entry), buffer_length);
372
373
5.71k
  case ELF_CLASS_64:
374
5.71k
    elf_header64 = (elf64_header_t*) buffer;
375
5.71k
    return yr_elf_rva_to_offset_64(
376
5.71k
        elf_header64, yr_le64toh(elf_header64->entry), buffer_length);
377
15.2k
  }
378
379
5.97k
  return YR_UNDEFINED;
380
15.2k
}
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
}