Coverage Report

Created: 2026-06-10 06:08

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
293
#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
1.71k
{
49
1.71k
  PIMAGE_DOS_HEADER mz_header;
50
1.71k
  PIMAGE_NT_HEADERS32 pe_header;
51
52
1.71k
  size_t headers_size = 0;
53
54
1.71k
  if (buffer_length < sizeof(IMAGE_DOS_HEADER))
55
468
    return NULL;
56
57
1.24k
  mz_header = (PIMAGE_DOS_HEADER) buffer;
58
59
1.24k
  if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE)
60
1.06k
    return NULL;
61
62
185
  if ((int32_t) yr_le32toh(mz_header->e_lfanew) < 0)
63
37
    return NULL;
64
65
148
  headers_size = yr_le32toh(mz_header->e_lfanew) +
66
148
                 sizeof(pe_header->Signature) + sizeof(IMAGE_FILE_HEADER);
67
68
148
  if (buffer_length < headers_size)
69
36
    return NULL;
70
71
112
  pe_header = (PIMAGE_NT_HEADERS32)(buffer + yr_le32toh(mz_header->e_lfanew));
72
73
112
  headers_size += sizeof(IMAGE_OPTIONAL_HEADER32);
74
75
112
  if (yr_le32toh(pe_header->Signature) == IMAGE_NT_SIGNATURE &&
76
51
      (yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_I386 ||
77
11
       yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_AMD64) &&
78
40
      buffer_length > headers_size)
79
38
  {
80
38
    return pe_header;
81
38
  }
82
74
  else
83
74
  {
84
74
    return NULL;
85
74
  }
86
112
}
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
38
{
93
38
  int i = 0;
94
38
  PIMAGE_SECTION_HEADER section;
95
38
  DWORD section_rva;
96
38
  DWORD section_offset;
97
98
38
  section = IMAGE_FIRST_SECTION(pe_header);
99
38
  section_rva = 0;
100
38
  section_offset = 0;
101
102
293
  while (i < MIN(yr_le16toh(pe_header->FileHeader.NumberOfSections), 60))
103
290
  {
104
290
    if ((uint8_t*) section - (uint8_t*) pe_header +
105
290
            sizeof(IMAGE_SECTION_HEADER) <
106
290
        buffer_length)
107
255
    {
108
255
      if (rva >= yr_le32toh(section->VirtualAddress) &&
109
136
          section_rva <= yr_le32toh(section->VirtualAddress))
110
78
      {
111
78
        section_rva = yr_le32toh(section->VirtualAddress);
112
78
        section_offset = yr_le32toh(section->PointerToRawData);
113
78
      }
114
115
255
      section++;
116
255
      i++;
117
255
    }
118
35
    else
119
35
    {
120
35
      return 0;
121
35
    }
122
290
  }
123
124
3
  return section_offset + (rva - section_rva);
125
38
}
126
127
int yr_get_elf_type(const uint8_t* buffer, size_t buffer_length)
128
1.67k
{
129
1.67k
  elf_ident_t* elf_ident;
130
131
1.67k
  if (buffer_length < sizeof(elf_ident_t))
132
71
    return 0;
133
134
1.60k
  elf_ident = (elf_ident_t*) buffer;
135
136
1.60k
  if (yr_le32toh(elf_ident->magic) != ELF_MAGIC)
137
288
  {
138
288
    return 0;
139
288
  }
140
141
1.31k
  switch (elf_ident->_class)
142
1.31k
  {
143
498
  case ELF_CLASS_32:
144
498
    if (buffer_length < sizeof(elf32_header_t))
145
11
    {
146
11
      return 0;
147
11
    }
148
487
    break;
149
814
  case ELF_CLASS_64:
150
814
    if (buffer_length < sizeof(elf64_header_t))
151
5
    {
152
5
      return 0;
153
5
    }
154
809
    break;
155
809
  default:
156
    /* Unexpected class */
157
4
    return 0;
158
1.31k
  }
159
160
1.29k
  return elf_ident->_class;
161
1.31k
}
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
487
{
168
  // if the binary is an executable then prefer the program headers to resolve
169
  // the offset
170
487
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
171
210
  {
172
210
    int i;
173
210
    elf32_program_header_t* program;
174
210
    if (yr_le32toh(elf_header->ph_offset) == 0 ||
175
209
        yr_le16toh(elf_header->ph_entry_count == 0))
176
8
      return 0;
177
178
    // check to prevent integer wraps
179
202
    if (ULONG_MAX - yr_le16toh(elf_header->ph_entry_count) <
180
202
        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
202
    if (ULONG_MAX - yr_le32toh(elf_header->ph_offset) <
186
202
        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
202
    if (yr_le32toh(elf_header->ph_offset) +
191
202
            sizeof(elf32_program_header_t) *
192
202
                yr_le16toh(elf_header->ph_entry_count) >
193
202
        buffer_length)
194
88
      return 0;
195
196
114
    program =
197
114
        (elf32_program_header_t*) ((uint8_t*) elf_header + yr_le32toh(elf_header->ph_offset));
198
199
3.32k
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
200
3.25k
    {
201
3.25k
      if (rva >= yr_le32toh(program->virt_addr) &&
202
1.94k
          rva < yr_le32toh(program->virt_addr) + yr_le32toh(program->mem_size))
203
44
      {
204
44
        return yr_le32toh(program->offset) +
205
44
               (rva - yr_le32toh(program->virt_addr));
206
44
      }
207
208
3.21k
      program++;
209
3.21k
    }
210
114
  }
211
277
  else
212
277
  {
213
277
    int i;
214
277
    elf32_section_header_t* section;
215
216
277
    if (yr_le32toh(elf_header->sh_offset) == 0 ||
217
275
        yr_le16toh(elf_header->sh_entry_count == 0))
218
9
      return 0;
219
220
    // check to prevent integer wraps
221
222
268
    if (ULONG_MAX - yr_le16toh(elf_header->sh_entry_count) <
223
268
        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
268
    if (ULONG_MAX - yr_le32toh(elf_header->sh_offset) <
230
268
        sizeof(elf32_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
231
0
      return 0;
232
233
268
    if (yr_le32toh(elf_header->sh_offset) +
234
268
            sizeof(elf32_section_header_t) *
235
268
                yr_le16toh(elf_header->sh_entry_count) >
236
268
        buffer_length)
237
93
      return 0;
238
239
175
    section = (elf32_section_header_t*)
240
175
      ((unsigned char*) elf_header + yr_le32toh(elf_header->sh_offset));
241
242
2.68k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
243
2.60k
    {
244
2.60k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
245
1.37k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
246
1.36k
          rva >= yr_le32toh(section->addr) &&
247
1.03k
          rva < yr_le32toh(section->addr) + yr_le32toh(section->size))
248
91
      {
249
        // prevent integer wrapping with the return value
250
251
91
        if (ULONG_MAX - yr_le32toh(section->offset) <
252
91
            (rva - yr_le32toh(section->addr)))
253
0
          return 0;
254
91
        else
255
91
          return yr_le32toh(section->offset) +
256
91
                 (rva - yr_le32toh(section->addr));
257
91
      }
258
259
2.51k
      section++;
260
2.51k
    }
261
175
  }
262
263
154
  return 0;
264
487
}
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
809
{
271
  // if the binary is an executable then prefer the program headers to resolve
272
  // the offset
273
809
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
274
372
  {
275
372
    int i;
276
372
    elf64_program_header_t* program;
277
372
    if (yr_le64toh(elf_header->ph_offset) == 0 ||
278
371
        yr_le16toh(elf_header->ph_entry_count == 0))
279
11
      return 0;
280
281
    // check that 'ph_offset' doesn't wrap when added to the
282
    // size of entries.
283
361
    if (ULONG_MAX - yr_le64toh(elf_header->ph_offset) <
284
361
        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
342
    if (yr_le64toh(elf_header->ph_offset) +
289
342
            sizeof(elf64_program_header_t) *
290
342
                yr_le16toh(elf_header->ph_entry_count) >
291
342
        buffer_length)
292
156
      return 0;
293
294
186
    program =
295
186
        (elf64_program_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->ph_offset));
296
297
1.51k
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
298
1.37k
    {
299
1.37k
      if (rva >= yr_le64toh(program->virt_addr) &&
300
1.01k
          rva < yr_le64toh(program->virt_addr) + yr_le64toh(program->mem_size))
301
38
      {
302
38
        return yr_le64toh(program->offset) +
303
38
               (rva - yr_le64toh(program->virt_addr));
304
38
      }
305
306
1.33k
      program++;
307
1.33k
    }
308
186
  }
309
437
  else
310
437
  {
311
437
    int i;
312
437
    elf64_section_header_t* section;
313
314
437
    if (yr_le64toh(elf_header->sh_offset) == 0 ||
315
436
        yr_le16toh(elf_header->sh_entry_count) == 0)
316
15
      return 0;
317
318
    // check that 'sh_offset' doesn't wrap when added to the
319
    // size of entries.
320
422
    if (ULONG_MAX - yr_le64toh(elf_header->sh_offset) <
321
422
        sizeof(elf64_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
322
36
      return 0;
323
324
386
    if (yr_le64toh(elf_header->sh_offset) +
325
386
            sizeof(elf64_section_header_t) *
326
386
                yr_le16toh(elf_header->sh_entry_count) >
327
386
        buffer_length)
328
146
      return 0;
329
330
240
    section =
331
240
        (elf64_section_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->sh_offset));
332
333
2.62k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
334
2.43k
    {
335
2.43k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
336
2.06k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
337
2.04k
          rva >= yr_le64toh(section->addr) &&
338
937
          rva < yr_le64toh(section->addr) + yr_le64toh(section->size))
339
53
      {
340
53
        return yr_le64toh(section->offset) + (rva - yr_le64toh(section->addr));
341
53
      }
342
343
2.38k
      section++;
344
2.38k
    }
345
240
  }
346
347
335
  return 0;
348
809
}
349
350
uint64_t yr_get_entry_point_offset(const uint8_t* buffer, size_t buffer_length)
351
1.71k
{
352
1.71k
  PIMAGE_NT_HEADERS32 pe_header;
353
1.71k
  elf32_header_t* elf_header32;
354
1.71k
  elf64_header_t* elf_header64;
355
356
1.71k
  pe_header = yr_get_pe_header(buffer, buffer_length);
357
358
1.71k
  if (pe_header != NULL)
359
38
  {
360
38
    return yr_pe_rva_to_offset(
361
38
        pe_header,
362
38
        yr_le32toh(pe_header->OptionalHeader.AddressOfEntryPoint),
363
38
        buffer_length - ((uint8_t*) pe_header - buffer));
364
38
  }
365
366
1.67k
  switch (yr_get_elf_type(buffer, buffer_length))
367
1.67k
  {
368
487
  case ELF_CLASS_32:
369
487
    elf_header32 = (elf32_header_t*) buffer;
370
487
    return yr_elf_rva_to_offset_32(
371
487
        elf_header32, yr_le32toh(elf_header32->entry), buffer_length);
372
373
809
  case ELF_CLASS_64:
374
809
    elf_header64 = (elf64_header_t*) buffer;
375
809
    return yr_elf_rva_to_offset_64(
376
809
        elf_header64, yr_le64toh(elf_header64->entry), buffer_length);
377
1.67k
  }
378
379
379
  return YR_UNDEFINED;
380
1.67k
}
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
}