Coverage Report

Created: 2025-07-18 06:53

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