Coverage Report

Created: 2025-08-29 07:08

/src/yara/libyara/exefiles.c
Line
Count
Source (jump to first uncovered line)
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
15.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
26.6k
{
49
26.6k
  PIMAGE_DOS_HEADER mz_header;
50
26.6k
  PIMAGE_NT_HEADERS32 pe_header;
51
52
26.6k
  size_t headers_size = 0;
53
54
26.6k
  if (buffer_length < sizeof(IMAGE_DOS_HEADER))
55
3.96k
    return NULL;
56
57
22.6k
  mz_header = (PIMAGE_DOS_HEADER) buffer;
58
59
22.6k
  if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE)
60
9.64k
    return NULL;
61
62
12.9k
  if ((int32_t) yr_le32toh(mz_header->e_lfanew) < 0)
63
129
    return NULL;
64
65
12.8k
  headers_size = yr_le32toh(mz_header->e_lfanew) +
66
12.8k
                 sizeof(pe_header->Signature) + sizeof(IMAGE_FILE_HEADER);
67
68
12.8k
  if (buffer_length < headers_size)
69
126
    return NULL;
70
71
12.7k
  pe_header = (PIMAGE_NT_HEADERS32)(buffer + yr_le32toh(mz_header->e_lfanew));
72
73
12.7k
  headers_size += sizeof(IMAGE_OPTIONAL_HEADER32);
74
75
12.7k
  if (yr_le32toh(pe_header->Signature) == IMAGE_NT_SIGNATURE &&
76
12.7k
      (yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_I386 ||
77
12.6k
       yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_AMD64) &&
78
12.7k
      buffer_length > headers_size)
79
1.64k
  {
80
1.64k
    return pe_header;
81
1.64k
  }
82
11.0k
  else
83
11.0k
  {
84
11.0k
    return NULL;
85
11.0k
  }
86
12.7k
}
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.64k
{
93
1.64k
  int i = 0;
94
1.64k
  PIMAGE_SECTION_HEADER section;
95
1.64k
  DWORD section_rva;
96
1.64k
  DWORD section_offset;
97
98
1.64k
  section = IMAGE_FIRST_SECTION(pe_header);
99
1.64k
  section_rva = 0;
100
1.64k
  section_offset = 0;
101
102
15.5k
  while (i < MIN(yr_le16toh(pe_header->FileHeader.NumberOfSections), 60))
103
14.2k
  {
104
14.2k
    if ((uint8_t*) section - (uint8_t*) pe_header +
105
14.2k
            sizeof(IMAGE_SECTION_HEADER) <
106
14.2k
        buffer_length)
107
13.9k
    {
108
13.9k
      if (rva >= yr_le32toh(section->VirtualAddress) &&
109
13.9k
          section_rva <= yr_le32toh(section->VirtualAddress))
110
2.72k
      {
111
2.72k
        section_rva = yr_le32toh(section->VirtualAddress);
112
2.72k
        section_offset = yr_le32toh(section->PointerToRawData);
113
2.72k
      }
114
115
13.9k
      section++;
116
13.9k
      i++;
117
13.9k
    }
118
333
    else
119
333
    {
120
333
      return 0;
121
333
    }
122
14.2k
  }
123
124
1.30k
  return section_offset + (rva - section_rva);
125
1.64k
}
126
127
int yr_get_elf_type(const uint8_t* buffer, size_t buffer_length)
128
24.9k
{
129
24.9k
  elf_ident_t* elf_ident;
130
131
24.9k
  if (buffer_length < sizeof(elf_ident_t))
132
374
    return 0;
133
134
24.5k
  elf_ident = (elf_ident_t*) buffer;
135
136
24.5k
  if (yr_le32toh(elf_ident->magic) != ELF_MAGIC)
137
14.0k
  {
138
14.0k
    return 0;
139
14.0k
  }
140
141
10.5k
  switch (elf_ident->_class)
142
10.5k
  {
143
4.18k
  case ELF_CLASS_32:
144
4.18k
    if (buffer_length < sizeof(elf32_header_t))
145
64
    {
146
64
      return 0;
147
64
    }
148
4.12k
    break;
149
6.36k
  case ELF_CLASS_64:
150
6.36k
    if (buffer_length < sizeof(elf64_header_t))
151
27
    {
152
27
      return 0;
153
27
    }
154
6.33k
    break;
155
6.33k
  default:
156
    /* Unexpected class */
157
29
    return 0;
158
10.5k
  }
159
160
10.4k
  return elf_ident->_class;
161
10.5k
}
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
4.12k
{
168
  // if the binary is an executable then prefer the program headers to resolve
169
  // the offset
170
4.12k
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
171
986
  {
172
986
    int i;
173
986
    elf32_program_header_t* program;
174
986
    if (yr_le32toh(elf_header->ph_offset) == 0 ||
175
986
        yr_le16toh(elf_header->ph_entry_count == 0))
176
65
      return 0;
177
178
    // check to prevent integer wraps
179
921
    if (ULONG_MAX - yr_le16toh(elf_header->ph_entry_count) <
180
921
        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
921
    if (ULONG_MAX - yr_le32toh(elf_header->ph_offset) <
186
921
        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
921
    if (yr_le32toh(elf_header->ph_offset) +
191
921
            sizeof(elf32_program_header_t) *
192
921
                yr_le16toh(elf_header->ph_entry_count) >
193
921
        buffer_length)
194
408
      return 0;
195
196
513
    program =
197
513
        (elf32_program_header_t*) ((uint8_t*) elf_header + yr_le32toh(elf_header->ph_offset));
198
199
8.12k
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
200
7.79k
    {
201
7.79k
      if (rva >= yr_le32toh(program->virt_addr) &&
202
7.79k
          rva < yr_le32toh(program->virt_addr) + yr_le32toh(program->mem_size))
203
180
      {
204
180
        return yr_le32toh(program->offset) +
205
180
               (rva - yr_le32toh(program->virt_addr));
206
180
      }
207
208
7.61k
      program++;
209
7.61k
    }
210
513
  }
211
3.13k
  else
212
3.13k
  {
213
3.13k
    int i;
214
3.13k
    elf32_section_header_t* section;
215
216
3.13k
    if (yr_le32toh(elf_header->sh_offset) == 0 ||
217
3.13k
        yr_le16toh(elf_header->sh_entry_count == 0))
218
248
      return 0;
219
220
    // check to prevent integer wraps
221
222
2.88k
    if (ULONG_MAX - yr_le16toh(elf_header->sh_entry_count) <
223
2.88k
        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.88k
    if (ULONG_MAX - yr_le32toh(elf_header->sh_offset) <
230
2.88k
        sizeof(elf32_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
231
0
      return 0;
232
233
2.88k
    if (yr_le32toh(elf_header->sh_offset) +
234
2.88k
            sizeof(elf32_section_header_t) *
235
2.88k
                yr_le16toh(elf_header->sh_entry_count) >
236
2.88k
        buffer_length)
237
1.66k
      return 0;
238
239
1.22k
    section = (elf32_section_header_t*)
240
1.22k
      ((unsigned char*) elf_header + yr_le32toh(elf_header->sh_offset));
241
242
19.8k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
243
19.1k
    {
244
19.1k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
245
19.1k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
246
19.1k
          rva >= yr_le32toh(section->addr) &&
247
19.1k
          rva < yr_le32toh(section->addr) + yr_le32toh(section->size))
248
512
      {
249
        // prevent integer wrapping with the return value
250
251
512
        if (ULONG_MAX - yr_le32toh(section->offset) <
252
512
            (rva - yr_le32toh(section->addr)))
253
0
          return 0;
254
512
        else
255
512
          return yr_le32toh(section->offset) +
256
512
                 (rva - yr_le32toh(section->addr));
257
512
      }
258
259
18.6k
      section++;
260
18.6k
    }
261
1.22k
  }
262
263
1.04k
  return 0;
264
4.12k
}
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
6.33k
{
271
  // if the binary is an executable then prefer the program headers to resolve
272
  // the offset
273
6.33k
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
274
1.74k
  {
275
1.74k
    int i;
276
1.74k
    elf64_program_header_t* program;
277
1.74k
    if (yr_le64toh(elf_header->ph_offset) == 0 ||
278
1.74k
        yr_le16toh(elf_header->ph_entry_count == 0))
279
84
      return 0;
280
281
    // check that 'ph_offset' doesn't wrap when added to the
282
    // size of entries.
283
1.66k
    if (ULONG_MAX - yr_le64toh(elf_header->ph_offset) <
284
1.66k
        sizeof(elf64_program_header_t) * yr_le16toh(elf_header->ph_entry_count))
285
49
      return 0;
286
287
    // ensure we don't exceed the buffer size
288
1.61k
    if (yr_le64toh(elf_header->ph_offset) +
289
1.61k
            sizeof(elf64_program_header_t) *
290
1.61k
                yr_le16toh(elf_header->ph_entry_count) >
291
1.61k
        buffer_length)
292
784
      return 0;
293
294
831
    program =
295
831
        (elf64_program_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->ph_offset));
296
297
8.99k
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
298
8.38k
    {
299
8.38k
      if (rva >= yr_le64toh(program->virt_addr) &&
300
8.38k
          rva < yr_le64toh(program->virt_addr) + yr_le64toh(program->mem_size))
301
225
      {
302
225
        return yr_le64toh(program->offset) +
303
225
               (rva - yr_le64toh(program->virt_addr));
304
225
      }
305
306
8.15k
      program++;
307
8.15k
    }
308
831
  }
309
4.59k
  else
310
4.59k
  {
311
4.59k
    int i;
312
4.59k
    elf64_section_header_t* section;
313
314
4.59k
    if (yr_le64toh(elf_header->sh_offset) == 0 ||
315
4.59k
        yr_le16toh(elf_header->sh_entry_count) == 0)
316
358
      return 0;
317
318
    // check that 'sh_offset' doesn't wrap when added to the
319
    // size of entries.
320
4.23k
    if (ULONG_MAX - yr_le64toh(elf_header->sh_offset) <
321
4.23k
        sizeof(elf64_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
322
103
      return 0;
323
324
4.13k
    if (yr_le64toh(elf_header->sh_offset) +
325
4.13k
            sizeof(elf64_section_header_t) *
326
4.13k
                yr_le16toh(elf_header->sh_entry_count) >
327
4.13k
        buffer_length)
328
2.51k
      return 0;
329
330
1.62k
    section =
331
1.62k
        (elf64_section_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->sh_offset));
332
333
17.7k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
334
16.7k
    {
335
16.7k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
336
16.7k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
337
16.7k
          rva >= yr_le64toh(section->addr) &&
338
16.7k
          rva < yr_le64toh(section->addr) + yr_le64toh(section->size))
339
695
      {
340
695
        return yr_le64toh(section->offset) + (rva - yr_le64toh(section->addr));
341
695
      }
342
343
16.0k
      section++;
344
16.0k
    }
345
1.62k
  }
346
347
1.53k
  return 0;
348
6.33k
}
349
350
uint64_t yr_get_entry_point_offset(const uint8_t* buffer, size_t buffer_length)
351
26.6k
{
352
26.6k
  PIMAGE_NT_HEADERS32 pe_header;
353
26.6k
  elf32_header_t* elf_header32;
354
26.6k
  elf64_header_t* elf_header64;
355
356
26.6k
  pe_header = yr_get_pe_header(buffer, buffer_length);
357
358
26.6k
  if (pe_header != NULL)
359
1.64k
  {
360
1.64k
    return yr_pe_rva_to_offset(
361
1.64k
        pe_header,
362
1.64k
        yr_le32toh(pe_header->OptionalHeader.AddressOfEntryPoint),
363
1.64k
        buffer_length - ((uint8_t*) pe_header - buffer));
364
1.64k
  }
365
366
24.9k
  switch (yr_get_elf_type(buffer, buffer_length))
367
24.9k
  {
368
4.12k
  case ELF_CLASS_32:
369
4.12k
    elf_header32 = (elf32_header_t*) buffer;
370
4.12k
    return yr_elf_rva_to_offset_32(
371
4.12k
        elf_header32, yr_le32toh(elf_header32->entry), buffer_length);
372
373
6.33k
  case ELF_CLASS_64:
374
6.33k
    elf_header64 = (elf64_header_t*) buffer;
375
6.33k
    return yr_elf_rva_to_offset_64(
376
6.33k
        elf_header64, yr_le64toh(elf_header64->entry), buffer_length);
377
24.9k
  }
378
379
14.5k
  return YR_UNDEFINED;
380
24.9k
}
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
}