Coverage Report

Created: 2025-11-01 06:39

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