Coverage Report

Created: 2025-11-11 06:56

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
20.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
27.6k
{
49
27.6k
  PIMAGE_DOS_HEADER mz_header;
50
27.6k
  PIMAGE_NT_HEADERS32 pe_header;
51
52
27.6k
  size_t headers_size = 0;
53
54
27.6k
  if (buffer_length < sizeof(IMAGE_DOS_HEADER))
55
3.69k
    return NULL;
56
57
23.9k
  mz_header = (PIMAGE_DOS_HEADER) buffer;
58
59
23.9k
  if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE)
60
10.2k
    return NULL;
61
62
13.7k
  if ((int32_t) yr_le32toh(mz_header->e_lfanew) < 0)
63
100
    return NULL;
64
65
13.6k
  headers_size = yr_le32toh(mz_header->e_lfanew) +
66
13.6k
                 sizeof(pe_header->Signature) + sizeof(IMAGE_FILE_HEADER);
67
68
13.6k
  if (buffer_length < headers_size)
69
115
    return NULL;
70
71
13.5k
  pe_header = (PIMAGE_NT_HEADERS32)(buffer + yr_le32toh(mz_header->e_lfanew));
72
73
13.5k
  headers_size += sizeof(IMAGE_OPTIONAL_HEADER32);
74
75
13.5k
  if (yr_le32toh(pe_header->Signature) == IMAGE_NT_SIGNATURE &&
76
13.3k
      (yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_I386 ||
77
11.6k
       yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_AMD64) &&
78
2.22k
      buffer_length > headers_size)
79
1.96k
  {
80
1.96k
    return pe_header;
81
1.96k
  }
82
11.5k
  else
83
11.5k
  {
84
11.5k
    return NULL;
85
11.5k
  }
86
13.5k
}
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.96k
{
93
1.96k
  int i = 0;
94
1.96k
  PIMAGE_SECTION_HEADER section;
95
1.96k
  DWORD section_rva;
96
1.96k
  DWORD section_offset;
97
98
1.96k
  section = IMAGE_FIRST_SECTION(pe_header);
99
1.96k
  section_rva = 0;
100
1.96k
  section_offset = 0;
101
102
20.2k
  while (i < MIN(yr_le16toh(pe_header->FileHeader.NumberOfSections), 60))
103
18.6k
  {
104
18.6k
    if ((uint8_t*) section - (uint8_t*) pe_header +
105
18.6k
            sizeof(IMAGE_SECTION_HEADER) <
106
18.6k
        buffer_length)
107
18.2k
    {
108
18.2k
      if (rva >= yr_le32toh(section->VirtualAddress) &&
109
8.23k
          section_rva <= yr_le32toh(section->VirtualAddress))
110
2.80k
      {
111
2.80k
        section_rva = yr_le32toh(section->VirtualAddress);
112
2.80k
        section_offset = yr_le32toh(section->PointerToRawData);
113
2.80k
      }
114
115
18.2k
      section++;
116
18.2k
      i++;
117
18.2k
    }
118
358
    else
119
358
    {
120
358
      return 0;
121
358
    }
122
18.6k
  }
123
124
1.60k
  return section_offset + (rva - section_rva);
125
1.96k
}
126
127
int yr_get_elf_type(const uint8_t* buffer, size_t buffer_length)
128
25.7k
{
129
25.7k
  elf_ident_t* elf_ident;
130
131
25.7k
  if (buffer_length < sizeof(elf_ident_t))
132
373
    return 0;
133
134
25.3k
  elf_ident = (elf_ident_t*) buffer;
135
136
25.3k
  if (yr_le32toh(elf_ident->magic) != ELF_MAGIC)
137
14.4k
  {
138
14.4k
    return 0;
139
14.4k
  }
140
141
10.8k
  switch (elf_ident->_class)
142
10.8k
  {
143
4.25k
  case ELF_CLASS_32:
144
4.25k
    if (buffer_length < sizeof(elf32_header_t))
145
62
    {
146
62
      return 0;
147
62
    }
148
4.18k
    break;
149
6.60k
  case ELF_CLASS_64:
150
6.60k
    if (buffer_length < sizeof(elf64_header_t))
151
29
    {
152
29
      return 0;
153
29
    }
154
6.57k
    break;
155
6.57k
  default:
156
    /* Unexpected class */
157
23
    return 0;
158
10.8k
  }
159
160
10.7k
  return elf_ident->_class;
161
10.8k
}
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.18k
{
168
  // if the binary is an executable then prefer the program headers to resolve
169
  // the offset
170
4.18k
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
171
945
  {
172
945
    int i;
173
945
    elf32_program_header_t* program;
174
945
    if (yr_le32toh(elf_header->ph_offset) == 0 ||
175
929
        yr_le16toh(elf_header->ph_entry_count == 0))
176
46
      return 0;
177
178
    // check to prevent integer wraps
179
899
    if (ULONG_MAX - yr_le16toh(elf_header->ph_entry_count) <
180
899
        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
899
    if (ULONG_MAX - yr_le32toh(elf_header->ph_offset) <
186
899
        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
899
    if (yr_le32toh(elf_header->ph_offset) +
191
899
            sizeof(elf32_program_header_t) *
192
899
                yr_le16toh(elf_header->ph_entry_count) >
193
899
        buffer_length)
194
382
      return 0;
195
196
517
    program =
197
517
        (elf32_program_header_t*) ((uint8_t*) elf_header + yr_le32toh(elf_header->ph_offset));
198
199
4.24k
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
200
3.91k
    {
201
3.91k
      if (rva >= yr_le32toh(program->virt_addr) &&
202
2.70k
          rva < yr_le32toh(program->virt_addr) + yr_le32toh(program->mem_size))
203
187
      {
204
187
        return yr_le32toh(program->offset) +
205
187
               (rva - yr_le32toh(program->virt_addr));
206
187
      }
207
208
3.72k
      program++;
209
3.72k
    }
210
517
  }
211
3.24k
  else
212
3.24k
  {
213
3.24k
    int i;
214
3.24k
    elf32_section_header_t* section;
215
216
3.24k
    if (yr_le32toh(elf_header->sh_offset) == 0 ||
217
3.08k
        yr_le16toh(elf_header->sh_entry_count == 0))
218
259
      return 0;
219
220
    // check to prevent integer wraps
221
222
2.98k
    if (ULONG_MAX - yr_le16toh(elf_header->sh_entry_count) <
223
2.98k
        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.98k
    if (ULONG_MAX - yr_le32toh(elf_header->sh_offset) <
230
2.98k
        sizeof(elf32_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
231
0
      return 0;
232
233
2.98k
    if (yr_le32toh(elf_header->sh_offset) +
234
2.98k
            sizeof(elf32_section_header_t) *
235
2.98k
                yr_le16toh(elf_header->sh_entry_count) >
236
2.98k
        buffer_length)
237
1.62k
      return 0;
238
239
1.36k
    section = (elf32_section_header_t*)
240
1.36k
      ((unsigned char*) elf_header + yr_le32toh(elf_header->sh_offset));
241
242
31.2k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
243
30.5k
    {
244
30.5k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
245
26.5k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
246
25.3k
          rva >= yr_le32toh(section->addr) &&
247
16.8k
          rva < yr_le32toh(section->addr) + yr_le32toh(section->size))
248
607
      {
249
        // prevent integer wrapping with the return value
250
251
607
        if (ULONG_MAX - yr_le32toh(section->offset) <
252
607
            (rva - yr_le32toh(section->addr)))
253
0
          return 0;
254
607
        else
255
607
          return yr_le32toh(section->offset) +
256
607
                 (rva - yr_le32toh(section->addr));
257
607
      }
258
259
29.9k
      section++;
260
29.9k
    }
261
1.36k
  }
262
263
1.08k
  return 0;
264
4.18k
}
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.57k
{
271
  // if the binary is an executable then prefer the program headers to resolve
272
  // the offset
273
6.57k
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
274
1.72k
  {
275
1.72k
    int i;
276
1.72k
    elf64_program_header_t* program;
277
1.72k
    if (yr_le64toh(elf_header->ph_offset) == 0 ||
278
1.71k
        yr_le16toh(elf_header->ph_entry_count == 0))
279
89
      return 0;
280
281
    // check that 'ph_offset' doesn't wrap when added to the
282
    // size of entries.
283
1.63k
    if (ULONG_MAX - yr_le64toh(elf_header->ph_offset) <
284
1.63k
        sizeof(elf64_program_header_t) * yr_le16toh(elf_header->ph_entry_count))
285
77
      return 0;
286
287
    // ensure we don't exceed the buffer size
288
1.56k
    if (yr_le64toh(elf_header->ph_offset) +
289
1.56k
            sizeof(elf64_program_header_t) *
290
1.56k
                yr_le16toh(elf_header->ph_entry_count) >
291
1.56k
        buffer_length)
292
763
      return 0;
293
294
799
    program =
295
799
        (elf64_program_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->ph_offset));
296
297
8.00k
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
298
7.33k
    {
299
7.33k
      if (rva >= yr_le64toh(program->virt_addr) &&
300
6.12k
          rva < yr_le64toh(program->virt_addr) + yr_le64toh(program->mem_size))
301
126
      {
302
126
        return yr_le64toh(program->offset) +
303
126
               (rva - yr_le64toh(program->virt_addr));
304
126
      }
305
306
7.21k
      program++;
307
7.21k
    }
308
799
  }
309
4.84k
  else
310
4.84k
  {
311
4.84k
    int i;
312
4.84k
    elf64_section_header_t* section;
313
314
4.84k
    if (yr_le64toh(elf_header->sh_offset) == 0 ||
315
4.72k
        yr_le16toh(elf_header->sh_entry_count) == 0)
316
347
      return 0;
317
318
    // check that 'sh_offset' doesn't wrap when added to the
319
    // size of entries.
320
4.50k
    if (ULONG_MAX - yr_le64toh(elf_header->sh_offset) <
321
4.50k
        sizeof(elf64_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
322
122
      return 0;
323
324
4.37k
    if (yr_le64toh(elf_header->sh_offset) +
325
4.37k
            sizeof(elf64_section_header_t) *
326
4.37k
                yr_le16toh(elf_header->sh_entry_count) >
327
4.37k
        buffer_length)
328
2.57k
      return 0;
329
330
1.80k
    section =
331
1.80k
        (elf64_section_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->sh_offset));
332
333
17.2k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
334
16.2k
    {
335
16.2k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
336
13.4k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
337
12.1k
          rva >= yr_le64toh(section->addr) &&
338
10.0k
          rva < yr_le64toh(section->addr) + yr_le64toh(section->size))
339
820
      {
340
820
        return yr_le64toh(section->offset) + (rva - yr_le64toh(section->addr));
341
820
      }
342
343
15.4k
      section++;
344
15.4k
    }
345
1.80k
  }
346
347
1.66k
  return 0;
348
6.57k
}
349
350
uint64_t yr_get_entry_point_offset(const uint8_t* buffer, size_t buffer_length)
351
27.6k
{
352
27.6k
  PIMAGE_NT_HEADERS32 pe_header;
353
27.6k
  elf32_header_t* elf_header32;
354
27.6k
  elf64_header_t* elf_header64;
355
356
27.6k
  pe_header = yr_get_pe_header(buffer, buffer_length);
357
358
27.6k
  if (pe_header != NULL)
359
1.96k
  {
360
1.96k
    return yr_pe_rva_to_offset(
361
1.96k
        pe_header,
362
1.96k
        yr_le32toh(pe_header->OptionalHeader.AddressOfEntryPoint),
363
1.96k
        buffer_length - ((uint8_t*) pe_header - buffer));
364
1.96k
  }
365
366
25.7k
  switch (yr_get_elf_type(buffer, buffer_length))
367
25.7k
  {
368
4.18k
  case ELF_CLASS_32:
369
4.18k
    elf_header32 = (elf32_header_t*) buffer;
370
4.18k
    return yr_elf_rva_to_offset_32(
371
4.18k
        elf_header32, yr_le32toh(elf_header32->entry), buffer_length);
372
373
6.57k
  case ELF_CLASS_64:
374
6.57k
    elf_header64 = (elf64_header_t*) buffer;
375
6.57k
    return yr_elf_rva_to_offset_64(
376
6.57k
        elf_header64, yr_le64toh(elf_header64->entry), buffer_length);
377
25.7k
  }
378
379
14.9k
  return YR_UNDEFINED;
380
25.7k
}
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
}