Coverage Report

Created: 2026-05-30 06:35

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
11.9k
#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.21k
{
49
7.21k
  PIMAGE_DOS_HEADER mz_header;
50
7.21k
  PIMAGE_NT_HEADERS32 pe_header;
51
52
7.21k
  size_t headers_size = 0;
53
54
7.21k
  if (buffer_length < sizeof(IMAGE_DOS_HEADER))
55
416
    return NULL;
56
57
6.79k
  mz_header = (PIMAGE_DOS_HEADER) buffer;
58
59
6.79k
  if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE)
60
793
    return NULL;
61
62
6.00k
  if ((int32_t) yr_le32toh(mz_header->e_lfanew) < 0)
63
34
    return NULL;
64
65
5.97k
  headers_size = yr_le32toh(mz_header->e_lfanew) +
66
5.97k
                 sizeof(pe_header->Signature) + sizeof(IMAGE_FILE_HEADER);
67
68
5.97k
  if (buffer_length < headers_size)
69
31
    return NULL;
70
71
5.94k
  pe_header = (PIMAGE_NT_HEADERS32)(buffer + yr_le32toh(mz_header->e_lfanew));
72
73
5.94k
  headers_size += sizeof(IMAGE_OPTIONAL_HEADER32);
74
75
5.94k
  if (yr_le32toh(pe_header->Signature) == IMAGE_NT_SIGNATURE &&
76
5.88k
      (yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_I386 ||
77
4.79k
       yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_AMD64) &&
78
1.09k
      buffer_length > headers_size)
79
881
  {
80
881
    return pe_header;
81
881
  }
82
5.06k
  else
83
5.06k
  {
84
5.06k
    return NULL;
85
5.06k
  }
86
5.94k
}
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
881
{
93
881
  int i = 0;
94
881
  PIMAGE_SECTION_HEADER section;
95
881
  DWORD section_rva;
96
881
  DWORD section_offset;
97
98
881
  section = IMAGE_FIRST_SECTION(pe_header);
99
881
  section_rva = 0;
100
881
  section_offset = 0;
101
102
11.9k
  while (i < MIN(yr_le16toh(pe_header->FileHeader.NumberOfSections), 60))
103
11.1k
  {
104
11.1k
    if ((uint8_t*) section - (uint8_t*) pe_header +
105
11.1k
            sizeof(IMAGE_SECTION_HEADER) <
106
11.1k
        buffer_length)
107
11.0k
    {
108
11.0k
      if (rva >= yr_le32toh(section->VirtualAddress) &&
109
4.31k
          section_rva <= yr_le32toh(section->VirtualAddress))
110
1.28k
      {
111
1.28k
        section_rva = yr_le32toh(section->VirtualAddress);
112
1.28k
        section_offset = yr_le32toh(section->PointerToRawData);
113
1.28k
      }
114
115
11.0k
      section++;
116
11.0k
      i++;
117
11.0k
    }
118
75
    else
119
75
    {
120
75
      return 0;
121
75
    }
122
11.1k
  }
123
124
806
  return section_offset + (rva - section_rva);
125
881
}
126
127
int yr_get_elf_type(const uint8_t* buffer, size_t buffer_length)
128
6.33k
{
129
6.33k
  elf_ident_t* elf_ident;
130
131
6.33k
  if (buffer_length < sizeof(elf_ident_t))
132
27
    return 0;
133
134
6.30k
  elf_ident = (elf_ident_t*) buffer;
135
136
6.30k
  if (yr_le32toh(elf_ident->magic) != ELF_MAGIC)
137
5.20k
  {
138
5.20k
    return 0;
139
5.20k
  }
140
141
1.10k
  switch (elf_ident->_class)
142
1.10k
  {
143
410
  case ELF_CLASS_32:
144
410
    if (buffer_length < sizeof(elf32_header_t))
145
12
    {
146
12
      return 0;
147
12
    }
148
398
    break;
149
695
  case ELF_CLASS_64:
150
695
    if (buffer_length < sizeof(elf64_header_t))
151
2
    {
152
2
      return 0;
153
2
    }
154
693
    break;
155
693
  default:
156
    /* Unexpected class */
157
1
    return 0;
158
1.10k
  }
159
160
1.09k
  return elf_ident->_class;
161
1.10k
}
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
398
{
168
  // if the binary is an executable then prefer the program headers to resolve
169
  // the offset
170
398
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
171
165
  {
172
165
    int i;
173
165
    elf32_program_header_t* program;
174
165
    if (yr_le32toh(elf_header->ph_offset) == 0 ||
175
164
        yr_le16toh(elf_header->ph_entry_count == 0))
176
5
      return 0;
177
178
    // check to prevent integer wraps
179
160
    if (ULONG_MAX - yr_le16toh(elf_header->ph_entry_count) <
180
160
        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
160
    if (ULONG_MAX - yr_le32toh(elf_header->ph_offset) <
186
160
        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
160
    if (yr_le32toh(elf_header->ph_offset) +
191
160
            sizeof(elf32_program_header_t) *
192
160
                yr_le16toh(elf_header->ph_entry_count) >
193
160
        buffer_length)
194
74
      return 0;
195
196
86
    program =
197
86
        (elf32_program_header_t*) ((uint8_t*) elf_header + yr_le32toh(elf_header->ph_offset));
198
199
12.7k
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
200
12.6k
    {
201
12.6k
      if (rva >= yr_le32toh(program->virt_addr) &&
202
12.4k
          rva < yr_le32toh(program->virt_addr) + yr_le32toh(program->mem_size))
203
33
      {
204
33
        return yr_le32toh(program->offset) +
205
33
               (rva - yr_le32toh(program->virt_addr));
206
33
      }
207
208
12.6k
      program++;
209
12.6k
    }
210
86
  }
211
233
  else
212
233
  {
213
233
    int i;
214
233
    elf32_section_header_t* section;
215
216
233
    if (yr_le32toh(elf_header->sh_offset) == 0 ||
217
232
        yr_le16toh(elf_header->sh_entry_count == 0))
218
8
      return 0;
219
220
    // check to prevent integer wraps
221
222
225
    if (ULONG_MAX - yr_le16toh(elf_header->sh_entry_count) <
223
225
        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
225
    if (ULONG_MAX - yr_le32toh(elf_header->sh_offset) <
230
225
        sizeof(elf32_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
231
0
      return 0;
232
233
225
    if (yr_le32toh(elf_header->sh_offset) +
234
225
            sizeof(elf32_section_header_t) *
235
225
                yr_le16toh(elf_header->sh_entry_count) >
236
225
        buffer_length)
237
78
      return 0;
238
239
147
    section = (elf32_section_header_t*)
240
147
      ((unsigned char*) elf_header + yr_le32toh(elf_header->sh_offset));
241
242
3.91k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
243
3.84k
    {
244
3.84k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
245
3.43k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
246
3.20k
          rva >= yr_le32toh(section->addr) &&
247
2.73k
          rva < yr_le32toh(section->addr) + yr_le32toh(section->size))
248
83
      {
249
        // prevent integer wrapping with the return value
250
251
83
        if (ULONG_MAX - yr_le32toh(section->offset) <
252
83
            (rva - yr_le32toh(section->addr)))
253
0
          return 0;
254
83
        else
255
83
          return yr_le32toh(section->offset) +
256
83
                 (rva - yr_le32toh(section->addr));
257
83
      }
258
259
3.76k
      section++;
260
3.76k
    }
261
147
  }
262
263
117
  return 0;
264
398
}
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
693
{
271
  // if the binary is an executable then prefer the program headers to resolve
272
  // the offset
273
693
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
274
320
  {
275
320
    int i;
276
320
    elf64_program_header_t* program;
277
320
    if (yr_le64toh(elf_header->ph_offset) == 0 ||
278
319
        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
309
    if (ULONG_MAX - yr_le64toh(elf_header->ph_offset) <
284
309
        sizeof(elf64_program_header_t) * yr_le16toh(elf_header->ph_entry_count))
285
15
      return 0;
286
287
    // ensure we don't exceed the buffer size
288
294
    if (yr_le64toh(elf_header->ph_offset) +
289
294
            sizeof(elf64_program_header_t) *
290
294
                yr_le16toh(elf_header->ph_entry_count) >
291
294
        buffer_length)
292
143
      return 0;
293
294
151
    program =
295
151
        (elf64_program_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->ph_offset));
296
297
936
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
298
803
    {
299
803
      if (rva >= yr_le64toh(program->virt_addr) &&
300
528
          rva < yr_le64toh(program->virt_addr) + yr_le64toh(program->mem_size))
301
18
      {
302
18
        return yr_le64toh(program->offset) +
303
18
               (rva - yr_le64toh(program->virt_addr));
304
18
      }
305
306
785
      program++;
307
785
    }
308
151
  }
309
373
  else
310
373
  {
311
373
    int i;
312
373
    elf64_section_header_t* section;
313
314
373
    if (yr_le64toh(elf_header->sh_offset) == 0 ||
315
372
        yr_le16toh(elf_header->sh_entry_count) == 0)
316
7
      return 0;
317
318
    // check that 'sh_offset' doesn't wrap when added to the
319
    // size of entries.
320
366
    if (ULONG_MAX - yr_le64toh(elf_header->sh_offset) <
321
366
        sizeof(elf64_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
322
20
      return 0;
323
324
346
    if (yr_le64toh(elf_header->sh_offset) +
325
346
            sizeof(elf64_section_header_t) *
326
346
                yr_le16toh(elf_header->sh_entry_count) >
327
346
        buffer_length)
328
143
      return 0;
329
330
203
    section =
331
203
        (elf64_section_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->sh_offset));
332
333
2.34k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
334
2.18k
    {
335
2.18k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
336
1.87k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
337
1.66k
          rva >= yr_le64toh(section->addr) &&
338
1.41k
          rva < yr_le64toh(section->addr) + yr_le64toh(section->size))
339
40
      {
340
40
        return yr_le64toh(section->offset) + (rva - yr_le64toh(section->addr));
341
40
      }
342
343
2.14k
      section++;
344
2.14k
    }
345
203
  }
346
347
296
  return 0;
348
693
}
349
350
uint64_t yr_get_entry_point_offset(const uint8_t* buffer, size_t buffer_length)
351
7.21k
{
352
7.21k
  PIMAGE_NT_HEADERS32 pe_header;
353
7.21k
  elf32_header_t* elf_header32;
354
7.21k
  elf64_header_t* elf_header64;
355
356
7.21k
  pe_header = yr_get_pe_header(buffer, buffer_length);
357
358
7.21k
  if (pe_header != NULL)
359
881
  {
360
881
    return yr_pe_rva_to_offset(
361
881
        pe_header,
362
881
        yr_le32toh(pe_header->OptionalHeader.AddressOfEntryPoint),
363
881
        buffer_length - ((uint8_t*) pe_header - buffer));
364
881
  }
365
366
6.33k
  switch (yr_get_elf_type(buffer, buffer_length))
367
6.33k
  {
368
398
  case ELF_CLASS_32:
369
398
    elf_header32 = (elf32_header_t*) buffer;
370
398
    return yr_elf_rva_to_offset_32(
371
398
        elf_header32, yr_le32toh(elf_header32->entry), buffer_length);
372
373
693
  case ELF_CLASS_64:
374
693
    elf_header64 = (elf64_header_t*) buffer;
375
693
    return yr_elf_rva_to_offset_64(
376
693
        elf_header64, yr_le64toh(elf_header64->entry), buffer_length);
377
6.33k
  }
378
379
5.24k
  return YR_UNDEFINED;
380
6.33k
}
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
}