Coverage Report

Created: 2023-03-26 07:37

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