Coverage Report

Created: 2025-11-01 06:40

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
3.92k
#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
8.32k
{
49
8.32k
  PIMAGE_DOS_HEADER mz_header;
50
8.32k
  PIMAGE_NT_HEADERS32 pe_header;
51
52
8.32k
  size_t headers_size = 0;
53
54
8.32k
  if (buffer_length < sizeof(IMAGE_DOS_HEADER))
55
410
    return NULL;
56
57
7.91k
  mz_header = (PIMAGE_DOS_HEADER) buffer;
58
59
7.91k
  if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE)
60
839
    return NULL;
61
62
7.07k
  if ((int32_t) yr_le32toh(mz_header->e_lfanew) < 0)
63
31
    return NULL;
64
65
7.04k
  headers_size = yr_le32toh(mz_header->e_lfanew) +
66
7.04k
                 sizeof(pe_header->Signature) + sizeof(IMAGE_FILE_HEADER);
67
68
7.04k
  if (buffer_length < headers_size)
69
28
    return NULL;
70
71
7.01k
  pe_header = (PIMAGE_NT_HEADERS32)(buffer + yr_le32toh(mz_header->e_lfanew));
72
73
7.01k
  headers_size += sizeof(IMAGE_OPTIONAL_HEADER32);
74
75
7.01k
  if (yr_le32toh(pe_header->Signature) == IMAGE_NT_SIGNATURE &&
76
6.96k
      (yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_I386 ||
77
6.54k
       yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_AMD64) &&
78
949
      buffer_length > headers_size)
79
879
  {
80
879
    return pe_header;
81
879
  }
82
6.13k
  else
83
6.13k
  {
84
6.13k
    return NULL;
85
6.13k
  }
86
7.01k
}
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
879
{
93
879
  int i = 0;
94
879
  PIMAGE_SECTION_HEADER section;
95
879
  DWORD section_rva;
96
879
  DWORD section_offset;
97
98
879
  section = IMAGE_FIRST_SECTION(pe_header);
99
879
  section_rva = 0;
100
879
  section_offset = 0;
101
102
3.92k
  while (i < MIN(yr_le16toh(pe_header->FileHeader.NumberOfSections), 60))
103
3.17k
  {
104
3.17k
    if ((uint8_t*) section - (uint8_t*) pe_header +
105
3.17k
            sizeof(IMAGE_SECTION_HEADER) <
106
3.17k
        buffer_length)
107
3.04k
    {
108
3.04k
      if (rva >= yr_le32toh(section->VirtualAddress) &&
109
1.67k
          section_rva <= yr_le32toh(section->VirtualAddress))
110
874
      {
111
874
        section_rva = yr_le32toh(section->VirtualAddress);
112
874
        section_offset = yr_le32toh(section->PointerToRawData);
113
874
      }
114
115
3.04k
      section++;
116
3.04k
      i++;
117
3.04k
    }
118
127
    else
119
127
    {
120
127
      return 0;
121
127
    }
122
3.17k
  }
123
124
752
  return section_offset + (rva - section_rva);
125
879
}
126
127
int yr_get_elf_type(const uint8_t* buffer, size_t buffer_length)
128
7.44k
{
129
7.44k
  elf_ident_t* elf_ident;
130
131
7.44k
  if (buffer_length < sizeof(elf_ident_t))
132
31
    return 0;
133
134
7.41k
  elf_ident = (elf_ident_t*) buffer;
135
136
7.41k
  if (yr_le32toh(elf_ident->magic) != ELF_MAGIC)
137
6.27k
  {
138
6.27k
    return 0;
139
6.27k
  }
140
141
1.13k
  switch (elf_ident->_class)
142
1.13k
  {
143
417
  case ELF_CLASS_32:
144
417
    if (buffer_length < sizeof(elf32_header_t))
145
10
    {
146
10
      return 0;
147
10
    }
148
407
    break;
149
717
  case ELF_CLASS_64:
150
717
    if (buffer_length < sizeof(elf64_header_t))
151
2
    {
152
2
      return 0;
153
2
    }
154
715
    break;
155
715
  default:
156
    /* Unexpected class */
157
1
    return 0;
158
1.13k
  }
159
160
1.12k
  return elf_ident->_class;
161
1.13k
}
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
407
{
168
  // if the binary is an executable then prefer the program headers to resolve
169
  // the offset
170
407
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
171
172
  {
172
172
    int i;
173
172
    elf32_program_header_t* program;
174
172
    if (yr_le32toh(elf_header->ph_offset) == 0 ||
175
171
        yr_le16toh(elf_header->ph_entry_count == 0))
176
6
      return 0;
177
178
    // check to prevent integer wraps
179
166
    if (ULONG_MAX - yr_le16toh(elf_header->ph_entry_count) <
180
166
        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
166
    if (ULONG_MAX - yr_le32toh(elf_header->ph_offset) <
186
166
        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
166
    if (yr_le32toh(elf_header->ph_offset) +
191
166
            sizeof(elf32_program_header_t) *
192
166
                yr_le16toh(elf_header->ph_entry_count) >
193
166
        buffer_length)
194
82
      return 0;
195
196
84
    program =
197
84
        (elf32_program_header_t*) ((uint8_t*) elf_header + yr_le32toh(elf_header->ph_offset));
198
199
1.36k
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
200
1.31k
    {
201
1.31k
      if (rva >= yr_le32toh(program->virt_addr) &&
202
1.06k
          rva < yr_le32toh(program->virt_addr) + yr_le32toh(program->mem_size))
203
28
      {
204
28
        return yr_le32toh(program->offset) +
205
28
               (rva - yr_le32toh(program->virt_addr));
206
28
      }
207
208
1.28k
      program++;
209
1.28k
    }
210
84
  }
211
235
  else
212
235
  {
213
235
    int i;
214
235
    elf32_section_header_t* section;
215
216
235
    if (yr_le32toh(elf_header->sh_offset) == 0 ||
217
233
        yr_le16toh(elf_header->sh_entry_count == 0))
218
9
      return 0;
219
220
    // check to prevent integer wraps
221
222
226
    if (ULONG_MAX - yr_le16toh(elf_header->sh_entry_count) <
223
226
        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
226
    if (ULONG_MAX - yr_le32toh(elf_header->sh_offset) <
230
226
        sizeof(elf32_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
231
0
      return 0;
232
233
226
    if (yr_le32toh(elf_header->sh_offset) +
234
226
            sizeof(elf32_section_header_t) *
235
226
                yr_le16toh(elf_header->sh_entry_count) >
236
226
        buffer_length)
237
86
      return 0;
238
239
140
    section = (elf32_section_header_t*)
240
140
      ((unsigned char*) elf_header + yr_le32toh(elf_header->sh_offset));
241
242
1.44k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
243
1.38k
    {
244
1.38k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
245
1.05k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
246
982
          rva >= yr_le32toh(section->addr) &&
247
724
          rva < yr_le32toh(section->addr) + yr_le32toh(section->size))
248
78
      {
249
        // prevent integer wrapping with the return value
250
251
78
        if (ULONG_MAX - yr_le32toh(section->offset) <
252
78
            (rva - yr_le32toh(section->addr)))
253
0
          return 0;
254
78
        else
255
78
          return yr_le32toh(section->offset) +
256
78
                 (rva - yr_le32toh(section->addr));
257
78
      }
258
259
1.30k
      section++;
260
1.30k
    }
261
140
  }
262
263
118
  return 0;
264
407
}
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
715
{
271
  // if the binary is an executable then prefer the program headers to resolve
272
  // the offset
273
715
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
274
341
  {
275
341
    int i;
276
341
    elf64_program_header_t* program;
277
341
    if (yr_le64toh(elf_header->ph_offset) == 0 ||
278
340
        yr_le16toh(elf_header->ph_entry_count == 0))
279
9
      return 0;
280
281
    // check that 'ph_offset' doesn't wrap when added to the
282
    // size of entries.
283
332
    if (ULONG_MAX - yr_le64toh(elf_header->ph_offset) <
284
332
        sizeof(elf64_program_header_t) * yr_le16toh(elf_header->ph_entry_count))
285
13
      return 0;
286
287
    // ensure we don't exceed the buffer size
288
319
    if (yr_le64toh(elf_header->ph_offset) +
289
319
            sizeof(elf64_program_header_t) *
290
319
                yr_le16toh(elf_header->ph_entry_count) >
291
319
        buffer_length)
292
162
      return 0;
293
294
157
    program =
295
157
        (elf64_program_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->ph_offset));
296
297
984
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
298
845
    {
299
845
      if (rva >= yr_le64toh(program->virt_addr) &&
300
602
          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
827
      program++;
307
827
    }
308
157
  }
309
374
  else
310
374
  {
311
374
    int i;
312
374
    elf64_section_header_t* section;
313
314
374
    if (yr_le64toh(elf_header->sh_offset) == 0 ||
315
373
        yr_le16toh(elf_header->sh_entry_count) == 0)
316
9
      return 0;
317
318
    // check that 'sh_offset' doesn't wrap when added to the
319
    // size of entries.
320
365
    if (ULONG_MAX - yr_le64toh(elf_header->sh_offset) <
321
365
        sizeof(elf64_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
322
21
      return 0;
323
324
344
    if (yr_le64toh(elf_header->sh_offset) +
325
344
            sizeof(elf64_section_header_t) *
326
344
                yr_le16toh(elf_header->sh_entry_count) >
327
344
        buffer_length)
328
141
      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.76k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
334
2.59k
    {
335
2.59k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
336
2.00k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
337
1.67k
          rva >= yr_le64toh(section->addr) &&
338
1.27k
          rva < yr_le64toh(section->addr) + yr_le64toh(section->size))
339
31
      {
340
31
        return yr_le64toh(section->offset) + (rva - yr_le64toh(section->addr));
341
31
      }
342
343
2.56k
      section++;
344
2.56k
    }
345
203
  }
346
347
311
  return 0;
348
715
}
349
350
uint64_t yr_get_entry_point_offset(const uint8_t* buffer, size_t buffer_length)
351
8.32k
{
352
8.32k
  PIMAGE_NT_HEADERS32 pe_header;
353
8.32k
  elf32_header_t* elf_header32;
354
8.32k
  elf64_header_t* elf_header64;
355
356
8.32k
  pe_header = yr_get_pe_header(buffer, buffer_length);
357
358
8.32k
  if (pe_header != NULL)
359
879
  {
360
879
    return yr_pe_rva_to_offset(
361
879
        pe_header,
362
879
        yr_le32toh(pe_header->OptionalHeader.AddressOfEntryPoint),
363
879
        buffer_length - ((uint8_t*) pe_header - buffer));
364
879
  }
365
366
7.44k
  switch (yr_get_elf_type(buffer, buffer_length))
367
7.44k
  {
368
407
  case ELF_CLASS_32:
369
407
    elf_header32 = (elf32_header_t*) buffer;
370
407
    return yr_elf_rva_to_offset_32(
371
407
        elf_header32, yr_le32toh(elf_header32->entry), buffer_length);
372
373
715
  case ELF_CLASS_64:
374
715
    elf_header64 = (elf64_header_t*) buffer;
375
715
    return yr_elf_rva_to_offset_64(
376
715
        elf_header64, yr_le64toh(elf_header64->entry), buffer_length);
377
7.44k
  }
378
379
6.32k
  return YR_UNDEFINED;
380
7.44k
}
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
}