Coverage Report

Created: 2025-08-29 07:07

/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
1.01k
#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
4.17k
{
49
4.17k
  PIMAGE_DOS_HEADER mz_header;
50
4.17k
  PIMAGE_NT_HEADERS32 pe_header;
51
52
4.17k
  size_t headers_size = 0;
53
54
4.17k
  if (buffer_length < sizeof(IMAGE_DOS_HEADER))
55
1.56k
    return NULL;
56
57
2.61k
  mz_header = (PIMAGE_DOS_HEADER) buffer;
58
59
2.61k
  if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE)
60
2.42k
    return NULL;
61
62
189
  if ((int32_t) yr_le32toh(mz_header->e_lfanew) < 0)
63
30
    return NULL;
64
65
159
  headers_size = yr_le32toh(mz_header->e_lfanew) +
66
159
                 sizeof(pe_header->Signature) + sizeof(IMAGE_FILE_HEADER);
67
68
159
  if (buffer_length < headers_size)
69
18
    return NULL;
70
71
141
  pe_header = (PIMAGE_NT_HEADERS32)(buffer + yr_le32toh(mz_header->e_lfanew));
72
73
141
  headers_size += sizeof(IMAGE_OPTIONAL_HEADER32);
74
75
141
  if (yr_le32toh(pe_header->Signature) == IMAGE_NT_SIGNATURE &&
76
141
      (yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_I386 ||
77
133
       yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_AMD64) &&
78
141
      buffer_length > headers_size)
79
96
  {
80
96
    return pe_header;
81
96
  }
82
45
  else
83
45
  {
84
45
    return NULL;
85
45
  }
86
141
}
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
96
{
93
96
  int i = 0;
94
96
  PIMAGE_SECTION_HEADER section;
95
96
  DWORD section_rva;
96
96
  DWORD section_offset;
97
98
96
  section = IMAGE_FIRST_SECTION(pe_header);
99
96
  section_rva = 0;
100
96
  section_offset = 0;
101
102
1.01k
  while (i < MIN(yr_le16toh(pe_header->FileHeader.NumberOfSections), 60))
103
1.00k
  {
104
1.00k
    if ((uint8_t*) section - (uint8_t*) pe_header +
105
1.00k
            sizeof(IMAGE_SECTION_HEADER) <
106
1.00k
        buffer_length)
107
917
    {
108
917
      if (rva >= yr_le32toh(section->VirtualAddress) &&
109
917
          section_rva <= yr_le32toh(section->VirtualAddress))
110
226
      {
111
226
        section_rva = yr_le32toh(section->VirtualAddress);
112
226
        section_offset = yr_le32toh(section->PointerToRawData);
113
226
      }
114
115
917
      section++;
116
917
      i++;
117
917
    }
118
84
    else
119
84
    {
120
84
      return 0;
121
84
    }
122
1.00k
  }
123
124
12
  return section_offset + (rva - section_rva);
125
96
}
126
127
int yr_get_elf_type(const uint8_t* buffer, size_t buffer_length)
128
4.07k
{
129
4.07k
  elf_ident_t* elf_ident;
130
131
4.07k
  if (buffer_length < sizeof(elf_ident_t))
132
308
    return 0;
133
134
3.76k
  elf_ident = (elf_ident_t*) buffer;
135
136
3.76k
  if (yr_le32toh(elf_ident->magic) != ELF_MAGIC)
137
2.52k
  {
138
2.52k
    return 0;
139
2.52k
  }
140
141
1.24k
  switch (elf_ident->_class)
142
1.24k
  {
143
440
  case ELF_CLASS_32:
144
440
    if (buffer_length < sizeof(elf32_header_t))
145
10
    {
146
10
      return 0;
147
10
    }
148
430
    break;
149
803
  case ELF_CLASS_64:
150
803
    if (buffer_length < sizeof(elf64_header_t))
151
1
    {
152
1
      return 0;
153
1
    }
154
802
    break;
155
802
  default:
156
    /* Unexpected class */
157
1
    return 0;
158
1.24k
  }
159
160
1.23k
  return elf_ident->_class;
161
1.24k
}
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
430
{
168
  // if the binary is an executable then prefer the program headers to resolve
169
  // the offset
170
430
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
171
181
  {
172
181
    int i;
173
181
    elf32_program_header_t* program;
174
181
    if (yr_le32toh(elf_header->ph_offset) == 0 ||
175
181
        yr_le16toh(elf_header->ph_entry_count == 0))
176
7
      return 0;
177
178
    // check to prevent integer wraps
179
174
    if (ULONG_MAX - yr_le16toh(elf_header->ph_entry_count) <
180
174
        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
174
    if (ULONG_MAX - yr_le32toh(elf_header->ph_offset) <
186
174
        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
174
    if (yr_le32toh(elf_header->ph_offset) +
191
174
            sizeof(elf32_program_header_t) *
192
174
                yr_le16toh(elf_header->ph_entry_count) >
193
174
        buffer_length)
194
78
      return 0;
195
196
96
    program =
197
96
        (elf32_program_header_t*) ((uint8_t*) elf_header + yr_le32toh(elf_header->ph_offset));
198
199
661
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
200
584
    {
201
584
      if (rva >= yr_le32toh(program->virt_addr) &&
202
584
          rva < yr_le32toh(program->virt_addr) + yr_le32toh(program->mem_size))
203
19
      {
204
19
        return yr_le32toh(program->offset) +
205
19
               (rva - yr_le32toh(program->virt_addr));
206
19
      }
207
208
565
      program++;
209
565
    }
210
96
  }
211
249
  else
212
249
  {
213
249
    int i;
214
249
    elf32_section_header_t* section;
215
216
249
    if (yr_le32toh(elf_header->sh_offset) == 0 ||
217
249
        yr_le16toh(elf_header->sh_entry_count == 0))
218
12
      return 0;
219
220
    // check to prevent integer wraps
221
222
237
    if (ULONG_MAX - yr_le16toh(elf_header->sh_entry_count) <
223
237
        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
237
    if (ULONG_MAX - yr_le32toh(elf_header->sh_offset) <
230
237
        sizeof(elf32_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
231
0
      return 0;
232
233
237
    if (yr_le32toh(elf_header->sh_offset) +
234
237
            sizeof(elf32_section_header_t) *
235
237
                yr_le16toh(elf_header->sh_entry_count) >
236
237
        buffer_length)
237
77
      return 0;
238
239
160
    section = (elf32_section_header_t*)
240
160
      ((unsigned char*) elf_header + yr_le32toh(elf_header->sh_offset));
241
242
7.08k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
243
7.00k
    {
244
7.00k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
245
7.00k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
246
7.00k
          rva >= yr_le32toh(section->addr) &&
247
7.00k
          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
6.92k
      section++;
260
6.92k
    }
261
160
  }
262
263
154
  return 0;
264
430
}
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
802
{
271
  // if the binary is an executable then prefer the program headers to resolve
272
  // the offset
273
802
  if (yr_le16toh(elf_header->type) == ELF_ET_EXEC)
274
381
  {
275
381
    int i;
276
381
    elf64_program_header_t* program;
277
381
    if (yr_le64toh(elf_header->ph_offset) == 0 ||
278
381
        yr_le16toh(elf_header->ph_entry_count == 0))
279
10
      return 0;
280
281
    // check that 'ph_offset' doesn't wrap when added to the
282
    // size of entries.
283
371
    if (ULONG_MAX - yr_le64toh(elf_header->ph_offset) <
284
371
        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
356
    if (yr_le64toh(elf_header->ph_offset) +
289
356
            sizeof(elf64_program_header_t) *
290
356
                yr_le16toh(elf_header->ph_entry_count) >
291
356
        buffer_length)
292
165
      return 0;
293
294
191
    program =
295
191
        (elf64_program_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->ph_offset));
296
297
4.15k
    for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++)
298
4.01k
    {
299
4.01k
      if (rva >= yr_le64toh(program->virt_addr) &&
300
4.01k
          rva < yr_le64toh(program->virt_addr) + yr_le64toh(program->mem_size))
301
50
      {
302
50
        return yr_le64toh(program->offset) +
303
50
               (rva - yr_le64toh(program->virt_addr));
304
50
      }
305
306
3.96k
      program++;
307
3.96k
    }
308
191
  }
309
421
  else
310
421
  {
311
421
    int i;
312
421
    elf64_section_header_t* section;
313
314
421
    if (yr_le64toh(elf_header->sh_offset) == 0 ||
315
421
        yr_le16toh(elf_header->sh_entry_count) == 0)
316
12
      return 0;
317
318
    // check that 'sh_offset' doesn't wrap when added to the
319
    // size of entries.
320
409
    if (ULONG_MAX - yr_le64toh(elf_header->sh_offset) <
321
409
        sizeof(elf64_section_header_t) * yr_le16toh(elf_header->sh_entry_count))
322
22
      return 0;
323
324
387
    if (yr_le64toh(elf_header->sh_offset) +
325
387
            sizeof(elf64_section_header_t) *
326
387
                yr_le16toh(elf_header->sh_entry_count) >
327
387
        buffer_length)
328
161
      return 0;
329
330
226
    section =
331
226
        (elf64_section_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->sh_offset));
332
333
1.95k
    for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++)
334
1.78k
    {
335
1.78k
      if (yr_le32toh(section->type) != ELF_SHT_NULL &&
336
1.78k
          yr_le32toh(section->type) != ELF_SHT_NOBITS &&
337
1.78k
          rva >= yr_le64toh(section->addr) &&
338
1.78k
          rva < yr_le64toh(section->addr) + yr_le64toh(section->size))
339
51
      {
340
51
        return yr_le64toh(section->offset) + (rva - yr_le64toh(section->addr));
341
51
      }
342
343
1.73k
      section++;
344
1.73k
    }
345
226
  }
346
347
316
  return 0;
348
802
}
349
350
uint64_t yr_get_entry_point_offset(const uint8_t* buffer, size_t buffer_length)
351
4.17k
{
352
4.17k
  PIMAGE_NT_HEADERS32 pe_header;
353
4.17k
  elf32_header_t* elf_header32;
354
4.17k
  elf64_header_t* elf_header64;
355
356
4.17k
  pe_header = yr_get_pe_header(buffer, buffer_length);
357
358
4.17k
  if (pe_header != NULL)
359
96
  {
360
96
    return yr_pe_rva_to_offset(
361
96
        pe_header,
362
96
        yr_le32toh(pe_header->OptionalHeader.AddressOfEntryPoint),
363
96
        buffer_length - ((uint8_t*) pe_header - buffer));
364
96
  }
365
366
4.07k
  switch (yr_get_elf_type(buffer, buffer_length))
367
4.07k
  {
368
430
  case ELF_CLASS_32:
369
430
    elf_header32 = (elf32_header_t*) buffer;
370
430
    return yr_elf_rva_to_offset_32(
371
430
        elf_header32, yr_le32toh(elf_header32->entry), buffer_length);
372
373
802
  case ELF_CLASS_64:
374
802
    elf_header64 = (elf64_header_t*) buffer;
375
802
    return yr_elf_rva_to_offset_64(
376
802
        elf_header64, yr_le64toh(elf_header64->entry), buffer_length);
377
4.07k
  }
378
379
2.84k
  return YR_UNDEFINED;
380
4.07k
}
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
}