Coverage Report

Created: 2023-06-07 07:18

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