Coverage Report

Created: 2023-03-26 07:38

/src/yara/libyara/modules/macho/macho.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
Copyright (c) 2014. 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 <yara/endian.h>
31
#include <yara/macho.h>
32
#include <yara/mem.h>
33
#include <yara/modules.h>
34
35
#define MODULE_NAME macho
36
37
// Check for Mach-O binary magic constant.
38
39
int is_macho_file_block(const uint32_t* magic)
40
0
{
41
0
  return *magic == MH_MAGIC || *magic == MH_CIGAM || *magic == MH_MAGIC_64 ||
42
0
         *magic == MH_CIGAM_64;
43
0
}
44
45
// Check if file is for 32-bit architecture.
46
47
int macho_is_32(const uint8_t* magic)
48
0
{
49
  // Magic must be [CE]FAEDFE or FEEDFA[CE].
50
0
  return magic[0] == 0xce || magic[3] == 0xce;
51
0
}
52
53
// Check if file is for big-endian architecture.
54
55
int macho_is_big(const uint8_t* magic)
56
0
{
57
  // Magic must be [FE]EDFACE or [FE]EDFACF.
58
0
  return magic[0] == 0xfe;
59
0
}
60
61
// Check for Mach-O fat binary magic constant.
62
63
int is_fat_macho_file_block(const uint32_t* magic)
64
0
{
65
0
  return *magic == FAT_MAGIC || *magic == FAT_CIGAM || *magic == FAT_MAGIC_64 ||
66
0
         *magic == FAT_CIGAM_64;
67
0
}
68
69
// Check if file is 32-bit fat file.
70
71
int macho_fat_is_32(const uint8_t* magic)
72
0
{
73
  // Magic must be CAFEBA[BE].
74
0
  return magic[3] == 0xbe;
75
0
}
76
77
static int should_swap_bytes(const uint32_t magic)
78
0
{
79
0
  return magic == MH_CIGAM || magic == MH_CIGAM_64 || magic == FAT_CIGAM ||
80
0
         magic == FAT_CIGAM_64;
81
0
}
82
83
static void swap_mach_header(yr_mach_header_64_t* mh)
84
0
{
85
  // Don't swap the magic number so we can tell if swapping is needed
86
0
  mh->cputype = yr_bswap32(mh->cputype);
87
0
  mh->cpusubtype = yr_bswap32(mh->cpusubtype);
88
0
  mh->filetype = yr_bswap32(mh->filetype);
89
0
  mh->ncmds = yr_bswap32(mh->ncmds);
90
0
  mh->sizeofcmds = yr_bswap32(mh->sizeofcmds);
91
0
  mh->flags = yr_bswap32(mh->flags);
92
93
0
  if (!macho_is_32((const uint8_t*) &mh->magic))
94
0
    mh->reserved = yr_bswap32(mh->reserved);
95
0
}
96
97
static void swap_load_command(yr_load_command_t* lc)
98
0
{
99
0
  lc->cmd = yr_bswap32(lc->cmd);
100
0
  lc->cmdsize = yr_bswap32(lc->cmdsize);
101
0
}
102
103
static void swap_segment_command(yr_segment_command_32_t* sg)
104
0
{
105
0
  sg->cmd = yr_bswap32(sg->cmd);
106
0
  sg->cmdsize = yr_bswap32(sg->cmdsize);
107
0
  sg->vmaddr = yr_bswap32(sg->vmaddr);
108
0
  sg->vmsize = yr_bswap32(sg->vmsize);
109
0
  sg->fileoff = yr_bswap32(sg->fileoff);
110
0
  sg->filesize = yr_bswap32(sg->filesize);
111
0
  sg->maxprot = yr_bswap32(sg->maxprot);
112
0
  sg->initprot = yr_bswap32(sg->initprot);
113
0
  sg->nsects = yr_bswap32(sg->nsects);
114
0
  sg->flags = yr_bswap32(sg->flags);
115
0
}
116
117
static void swap_segment_command_64(yr_segment_command_64_t* sg)
118
0
{
119
0
  sg->cmd = yr_bswap32(sg->cmd);
120
0
  sg->cmdsize = yr_bswap32(sg->cmdsize);
121
0
  sg->vmaddr = yr_bswap64(sg->vmaddr);
122
0
  sg->vmsize = yr_bswap64(sg->vmsize);
123
0
  sg->fileoff = yr_bswap64(sg->fileoff);
124
0
  sg->filesize = yr_bswap64(sg->filesize);
125
0
  sg->maxprot = yr_bswap32(sg->maxprot);
126
0
  sg->initprot = yr_bswap32(sg->initprot);
127
0
  sg->nsects = yr_bswap32(sg->nsects);
128
0
  sg->flags = yr_bswap32(sg->flags);
129
0
}
130
131
static void swap_section(yr_section_32_t* sec)
132
0
{
133
0
  sec->addr = yr_bswap32(sec->addr);
134
0
  sec->size = yr_bswap32(sec->size);
135
0
  sec->offset = yr_bswap32(sec->offset);
136
0
  sec->align = yr_bswap32(sec->align);
137
0
  sec->reloff = yr_bswap32(sec->reloff);
138
0
  sec->nreloc = yr_bswap32(sec->nreloc);
139
0
  sec->flags = yr_bswap32(sec->flags);
140
0
  sec->reserved1 = yr_bswap32(sec->reserved1);
141
0
  sec->reserved2 = yr_bswap32(sec->reserved2);
142
0
}
143
144
static void swap_section_64(yr_section_64_t* sec)
145
0
{
146
0
  sec->addr = yr_bswap64(sec->addr);
147
0
  sec->size = yr_bswap64(sec->size);
148
0
  sec->offset = yr_bswap32(sec->offset);
149
0
  sec->align = yr_bswap32(sec->align);
150
0
  sec->reloff = yr_bswap32(sec->reloff);
151
0
  sec->nreloc = yr_bswap32(sec->nreloc);
152
0
  sec->flags = yr_bswap32(sec->flags);
153
0
  sec->reserved1 = yr_bswap32(sec->reserved1);
154
0
  sec->reserved2 = yr_bswap32(sec->reserved2);
155
0
  sec->reserved3 = yr_bswap32(sec->reserved3);
156
0
}
157
158
static void swap_entry_point_command(yr_entry_point_command_t* ep_command)
159
0
{
160
0
  ep_command->cmd = yr_bswap32(ep_command->cmd);
161
0
  ep_command->cmdsize = yr_bswap32(ep_command->cmdsize);
162
0
  ep_command->entryoff = yr_bswap64(ep_command->entryoff);
163
0
  ep_command->stacksize = yr_bswap64(ep_command->stacksize);
164
0
}
165
166
// Convert virtual address to file offset. Segments have to be already loaded.
167
168
bool macho_rva_to_offset(uint64_t address, uint64_t* result, YR_OBJECT* object)
169
0
{
170
0
  uint64_t segment_count = yr_get_integer(object, "number_of_segments");
171
172
0
  for (int i = 0; i < segment_count; i++)
173
0
  {
174
0
    uint64_t start = yr_get_integer(object, "segments[%i].vmaddr", i);
175
0
    uint64_t end = start + yr_get_integer(object, "segments[%i].vmsize", i);
176
177
0
    if (address >= start && address < end)
178
0
    {
179
0
      uint64_t fileoff = yr_get_integer(object, "segments[%i].fileoff", i);
180
0
      *result = fileoff + (address - start);
181
0
      return true;
182
0
    }
183
0
  }
184
185
0
  return false;
186
0
}
187
188
// Convert file offset to virtual address. Segments have to be already loaded.
189
190
int macho_offset_to_rva(uint64_t offset, uint64_t* result, YR_OBJECT* object)
191
0
{
192
0
  uint64_t segment_count = yr_get_integer(object, "number_of_segments");
193
194
0
  for (int i = 0; i < segment_count; i++)
195
0
  {
196
0
    uint64_t start = yr_get_integer(object, "segments[%i].fileoff", i);
197
0
    uint64_t end = start + yr_get_integer(object, "segments[%i].filesize", i);
198
199
0
    if (offset >= start && offset < end)
200
0
    {
201
0
      uint64_t vmaddr = yr_get_integer(object, "segments[%i].vmaddr", i);
202
0
      *result = vmaddr + (offset - start);
203
0
      return true;
204
0
    }
205
0
  }
206
207
0
  return false;
208
0
}
209
210
// Get entry point address from LC_UNIXTHREAD load command.
211
void macho_handle_unixthread(
212
    const uint8_t* data,
213
    size_t size,
214
    YR_OBJECT* object,
215
    YR_SCAN_CONTEXT* context)
216
0
{
217
0
  int should_swap = should_swap_bytes(yr_get_integer(object, "magic"));
218
0
  bool is64 = false;
219
220
0
  if (size < sizeof(yr_thread_command_t))
221
0
    return;
222
223
  // command_size is the size indicated in yr_thread_command_t structure, but
224
  // limited to the data's size because we can't rely on the structure having a
225
  // valid size.
226
0
  uint32_t command_size = yr_min(size, ((yr_thread_command_t*) data)->cmdsize);
227
228
  // command_size should be at least the size of yr_thread_command_t.
229
0
  if (command_size < sizeof(yr_thread_command_t))
230
0
    return;
231
232
  // command_size includes the size of yr_thread_command_t and the thread
233
  // state structure that follows, let's compute the size of the thread state
234
  // structure.
235
0
  size_t thread_state_size = command_size - sizeof(yr_thread_command_t);
236
237
  // The structure that contains the thread state starts where
238
  // yr_thread_command_t ends.
239
0
  const void* thread_state = data + sizeof(yr_thread_command_t);
240
241
0
  uint64_t address = 0;
242
243
0
  switch (yr_get_integer(object, "cputype"))
244
0
  {
245
0
  case CPU_TYPE_MC680X0:
246
0
  {
247
0
    if (thread_state_size >= sizeof(yr_m68k_thread_state_t))
248
0
      address = ((yr_m68k_thread_state_t*) thread_state)->pc;
249
0
    break;
250
0
  }
251
0
  case CPU_TYPE_MC88000:
252
0
  {
253
0
    if (thread_state_size >= sizeof(yr_m88k_thread_state_t))
254
0
      address = ((yr_m88k_thread_state_t*) thread_state)->xip;
255
0
    break;
256
0
  }
257
0
  case CPU_TYPE_SPARC:
258
0
  {
259
0
    if (thread_state_size >= sizeof(yr_sparc_thread_state_t))
260
0
      address = ((yr_sparc_thread_state_t*) thread_state)->pc;
261
0
    break;
262
0
  }
263
0
  case CPU_TYPE_POWERPC:
264
0
  {
265
0
    if (thread_state_size >= sizeof(yr_ppc_thread_state_t))
266
0
      address = ((yr_ppc_thread_state_t*) thread_state)->srr0;
267
0
    break;
268
0
  }
269
0
  case CPU_TYPE_X86:
270
0
  {
271
0
    if (thread_state_size >= sizeof(yr_x86_thread_state_t))
272
0
      address = ((yr_x86_thread_state_t*) thread_state)->eip;
273
0
    break;
274
0
  }
275
0
  case CPU_TYPE_ARM:
276
0
  {
277
0
    if (thread_state_size >= sizeof(yr_arm_thread_state_t))
278
0
      address = ((yr_arm_thread_state_t*) thread_state)->pc;
279
0
    break;
280
0
  }
281
0
  case CPU_TYPE_X86_64:
282
0
  {
283
0
    if (thread_state_size >= sizeof(yr_x86_thread_state64_t))
284
0
      address = ((yr_x86_thread_state64_t*) thread_state)->rip;
285
0
    is64 = true;
286
0
    break;
287
0
  }
288
0
  case CPU_TYPE_ARM64:
289
0
  {
290
0
    if (thread_state_size >= sizeof(yr_arm_thread_state64_t))
291
0
      address = ((yr_arm_thread_state64_t*) thread_state)->pc;
292
0
    is64 = true;
293
0
    break;
294
0
  }
295
0
  case CPU_TYPE_POWERPC64:
296
0
  {
297
0
    if (thread_state_size >= sizeof(yr_ppc_thread_state64_t))
298
0
      address = ((yr_ppc_thread_state64_t*) thread_state)->srr0;
299
0
    is64 = true;
300
0
    break;
301
0
  }
302
303
0
  default:
304
0
    return;
305
0
  }
306
307
0
  if (should_swap)
308
0
  {
309
0
    if (is64)
310
0
      address = yr_bswap64(address);
311
0
    else
312
0
      address = yr_bswap32(address);
313
0
  }
314
315
0
  if (context->flags & SCAN_FLAGS_PROCESS_MEMORY)
316
0
  {
317
0
    yr_set_integer(address, object, "entry_point");
318
0
  }
319
0
  else
320
0
  {
321
0
    uint64_t offset = 0;
322
0
    if (macho_rva_to_offset(address, &offset, object))
323
0
    {
324
0
      yr_set_integer(offset, object, "entry_point");
325
0
    }
326
0
  }
327
0
}
328
329
// Get entry point offset and stack-size from LC_MAIN load command.
330
331
void macho_handle_main(
332
    void* data,
333
    size_t size,
334
    YR_OBJECT* object,
335
    YR_SCAN_CONTEXT* context)
336
0
{
337
0
  yr_entry_point_command_t ep_command;
338
339
0
  if (size < sizeof(yr_entry_point_command_t))
340
0
    return;
341
342
0
  memcpy(&ep_command, data, sizeof(yr_entry_point_command_t));
343
344
0
  if (should_swap_bytes(yr_get_integer(object, "magic")))
345
0
    swap_entry_point_command(&ep_command);
346
347
0
  if (context->flags & SCAN_FLAGS_PROCESS_MEMORY)
348
0
  {
349
0
    uint64_t address = 0;
350
0
    if (macho_offset_to_rva(ep_command.entryoff, &address, object))
351
0
    {
352
0
      yr_set_integer(address, object, "entry_point");
353
0
    }
354
0
  }
355
0
  else
356
0
  {
357
0
    yr_set_integer(ep_command.entryoff, object, "entry_point");
358
0
  }
359
0
  yr_set_integer(ep_command.stacksize, object, "stack_size");
360
0
}
361
362
// Load segment and its sections.
363
364
void macho_handle_segment(
365
    const uint8_t* data,
366
    size_t size,
367
    const unsigned i,
368
    YR_OBJECT* object)
369
0
{
370
0
  if (size < sizeof(yr_segment_command_32_t))
371
0
    return;
372
373
0
  yr_segment_command_32_t sg;
374
375
0
  memcpy(&sg, data, sizeof(yr_segment_command_32_t));
376
377
0
  int should_swap = should_swap_bytes(yr_get_integer(object, "magic"));
378
379
0
  if (should_swap)
380
0
    swap_segment_command(&sg);
381
382
0
  yr_set_sized_string(
383
0
      sg.segname, strnlen(sg.segname, 16), object, "segments[%i].segname", i);
384
385
0
  yr_set_integer(sg.vmaddr, object, "segments[%i].vmaddr", i);
386
0
  yr_set_integer(sg.vmsize, object, "segments[%i].vmsize", i);
387
0
  yr_set_integer(sg.fileoff, object, "segments[%i].fileoff", i);
388
0
  yr_set_integer(sg.filesize, object, "segments[%i].fsize", i);
389
0
  yr_set_integer(sg.maxprot, object, "segments[%i].maxprot", i);
390
0
  yr_set_integer(sg.initprot, object, "segments[%i].initprot", i);
391
0
  yr_set_integer(sg.nsects, object, "segments[%i].nsects", i);
392
0
  yr_set_integer(sg.flags, object, "segments[%i].flags", i);
393
394
0
  uint64_t parsed_size = sizeof(yr_segment_command_32_t);
395
396
  // The array of yr_section_32_t starts where yr_segment_command_32_t ends.
397
0
  yr_section_32_t* sections =
398
0
      (yr_section_32_t*) (data + sizeof(yr_segment_command_32_t));
399
400
0
  for (unsigned j = 0; j < sg.nsects; ++j)
401
0
  {
402
0
    yr_section_32_t sec;
403
404
0
    parsed_size += sizeof(yr_section_32_t);
405
406
0
    if (sg.cmdsize < parsed_size)
407
0
      break;
408
409
0
    memcpy(&sec, &sections[j], sizeof(yr_section_32_t));
410
411
0
    if (should_swap)
412
0
      swap_section(&sec);
413
414
0
    yr_set_sized_string(
415
0
        sec.segname,
416
0
        strnlen(sec.segname, 16),
417
0
        object,
418
0
        "segments[%i].sections[%i].segname",
419
0
        i,
420
0
        j);
421
422
0
    yr_set_sized_string(
423
0
        sec.sectname,
424
0
        strnlen(sec.sectname, 16),
425
0
        object,
426
0
        "segments[%i].sections[%i].sectname",
427
0
        i,
428
0
        j);
429
430
0
    yr_set_integer(sec.addr, object, "segments[%i].sections[%i].addr", i, j);
431
432
0
    yr_set_integer(sec.size, object, "segments[%i].sections[%i].size", i, j);
433
434
0
    yr_set_integer(sec.offset, object, "segments[%i].sections[%i].offset", i, j);
435
436
0
    yr_set_integer(sec.align, object, "segments[%i].sections[%i].align", i, j);
437
438
0
    yr_set_integer(sec.reloff, object, "segments[%i].sections[%i].reloff", i, j);
439
440
0
    yr_set_integer(sec.nreloc, object, "segments[%i].sections[%i].nreloc", i, j);
441
442
0
    yr_set_integer(sec.flags, object, "segments[%i].sections[%i].flags", i, j);
443
444
0
    yr_set_integer(
445
0
        sec.reserved1, object, "segments[%i].sections[%i].reserved1", i, j);
446
447
0
    yr_set_integer(
448
0
        sec.reserved2, object, "segments[%i].sections[%i].reserved2", i, j);
449
0
  }
450
0
}
451
452
void macho_handle_segment_64(
453
    const uint8_t* data,
454
    size_t size,
455
    const unsigned i,
456
    YR_OBJECT* object)
457
0
{
458
0
  if (size < sizeof(yr_segment_command_64_t))
459
0
    return;
460
461
0
  yr_segment_command_64_t sg;
462
463
0
  memcpy(&sg, data, sizeof(yr_segment_command_64_t));
464
465
0
  int should_swap = should_swap_bytes(yr_get_integer(object, "magic"));
466
467
0
  if (should_swap)
468
0
    swap_segment_command_64(&sg);
469
470
0
  yr_set_sized_string(
471
0
      sg.segname, strnlen(sg.segname, 16), object, "segments[%i].segname", i);
472
473
0
  yr_set_integer(sg.vmaddr, object, "segments[%i].vmaddr", i);
474
0
  yr_set_integer(sg.vmsize, object, "segments[%i].vmsize", i);
475
0
  yr_set_integer(sg.fileoff, object, "segments[%i].fileoff", i);
476
0
  yr_set_integer(sg.filesize, object, "segments[%i].fsize", i);
477
0
  yr_set_integer(sg.maxprot, object, "segments[%i].maxprot", i);
478
0
  yr_set_integer(sg.initprot, object, "segments[%i].initprot", i);
479
0
  yr_set_integer(sg.nsects, object, "segments[%i].nsects", i);
480
0
  yr_set_integer(sg.flags, object, "segments[%i].flags", i);
481
482
0
  uint64_t parsed_size = sizeof(yr_segment_command_64_t);
483
484
0
  yr_section_64_t sec;
485
486
0
  for (unsigned j = 0; j < sg.nsects; ++j)
487
0
  {
488
0
    parsed_size += sizeof(yr_section_64_t);
489
490
0
    if (sg.cmdsize < parsed_size)
491
0
      break;
492
493
0
    memcpy(
494
0
        &sec,
495
0
        data + sizeof(yr_segment_command_64_t) + (j * sizeof(yr_section_64_t)),
496
0
        sizeof(yr_section_64_t));
497
498
0
    if (should_swap)
499
0
      swap_section_64(&sec);
500
501
0
    yr_set_sized_string(
502
0
        sec.segname,
503
0
        strnlen(sec.segname, 16),
504
0
        object,
505
0
        "segments[%i].sections[%i].segname",
506
0
        i,
507
0
        j);
508
509
0
    yr_set_sized_string(
510
0
        sec.sectname,
511
0
        strnlen(sec.sectname, 16),
512
0
        object,
513
0
        "segments[%i].sections[%i].sectname",
514
0
        i,
515
0
        j);
516
517
0
    yr_set_integer(sec.addr, object, "segments[%i].sections[%i].addr", i, j);
518
519
0
    yr_set_integer(sec.size, object, "segments[%i].sections[%i].size", i, j);
520
521
0
    yr_set_integer(sec.offset, object, "segments[%i].sections[%i].offset", i, j);
522
523
0
    yr_set_integer(sec.align, object, "segments[%i].sections[%i].align", i, j);
524
525
0
    yr_set_integer(sec.reloff, object, "segments[%i].sections[%i].reloff", i, j);
526
527
0
    yr_set_integer(sec.nreloc, object, "segments[%i].sections[%i].nreloc", i, j);
528
529
0
    yr_set_integer(sec.flags, object, "segments[%i].sections[%i].flags", i, j);
530
531
0
    yr_set_integer(
532
0
        sec.reserved1, object, "segments[%i].sections[%i].reserved1", i, j);
533
534
0
    yr_set_integer(
535
0
        sec.reserved2, object, "segments[%i].sections[%i].reserved2", i, j);
536
537
0
    yr_set_integer(
538
0
        sec.reserved3, object, "segments[%i].sections[%i].reserved3", i, j);
539
0
  }
540
0
}
541
542
// Parse Mach-O file.
543
544
void macho_parse_file(
545
    const uint8_t* data,
546
    const uint64_t size,
547
    YR_OBJECT* object,
548
    YR_SCAN_CONTEXT* context)
549
0
{
550
  // Size must be large enough the hold yr_mach_header_64_t, which is larger
551
  // than yr_mach_header_32_t.
552
0
  if (size < sizeof(yr_mach_header_64_t))
553
0
    return;
554
555
0
  size_t header_size = macho_is_32(data) ? sizeof(yr_mach_header_32_t)
556
0
                                         : sizeof(yr_mach_header_64_t);
557
558
  // yr_mach_header_64_t is used for storing the header for both for 32-bits and
559
  // 64-bits files. yr_mach_header_64_t is exactly like yr_mach_header_32_t
560
  // but with an extra "reserved" field at the end.
561
0
  yr_mach_header_64_t header;
562
563
0
  memcpy(&header, data, header_size);
564
565
0
  int should_swap = should_swap_bytes(header.magic);
566
567
0
  if (should_swap)
568
0
    swap_mach_header(&header);
569
570
0
  yr_set_integer(header.magic, object, "magic");
571
0
  yr_set_integer(header.cputype, object, "cputype");
572
0
  yr_set_integer(header.cpusubtype, object, "cpusubtype");
573
0
  yr_set_integer(header.filetype, object, "filetype");
574
0
  yr_set_integer(header.ncmds, object, "ncmds");
575
0
  yr_set_integer(header.sizeofcmds, object, "sizeofcmds");
576
0
  yr_set_integer(header.flags, object, "flags");
577
578
  // The "reserved" field exists only in 64 bits files.
579
0
  if (!macho_is_32(data))
580
0
    yr_set_integer(header.reserved, object, "reserved");
581
582
  // The first command parsing pass handles only segments.
583
0
  uint64_t seg_count = 0;
584
0
  uint64_t parsed_size = header_size;
585
0
  uint8_t* command = (uint8_t*) (data + header_size);
586
587
0
  yr_load_command_t command_struct;
588
589
0
  for (unsigned i = 0; i < header.ncmds; i++)
590
0
  {
591
0
    if (data + size < command + sizeof(yr_load_command_t))
592
0
      break;
593
594
0
    memcpy(&command_struct, command, sizeof(yr_load_command_t));
595
596
0
    if (should_swap)
597
0
      swap_load_command(&command_struct);
598
599
0
    if (size - parsed_size < command_struct.cmdsize)
600
0
      break;
601
602
0
    if (command_struct.cmdsize < sizeof(yr_load_command_t))
603
0
      break;
604
605
0
    switch (command_struct.cmd)
606
0
    {
607
0
    case LC_SEGMENT:
608
0
      macho_handle_segment(command, size - parsed_size, seg_count++, object);
609
0
      break;
610
0
    case LC_SEGMENT_64:
611
0
      macho_handle_segment_64(command, size - parsed_size, seg_count++, object);
612
0
      break;
613
0
    }
614
615
0
    command += command_struct.cmdsize;
616
0
    parsed_size += command_struct.cmdsize;
617
0
  }
618
619
0
  yr_set_integer(seg_count, object, "number_of_segments");
620
621
  // The second command parsing pass handles others, who use segment count.
622
0
  parsed_size = header_size;
623
0
  command = (uint8_t*) (data + header_size);
624
625
0
  for (unsigned i = 0; i < header.ncmds; i++)
626
0
  {
627
0
    if (data + size < command + sizeof(yr_load_command_t))
628
0
      break;
629
630
0
    memcpy(&command_struct, command, sizeof(yr_load_command_t));
631
632
0
    if (should_swap)
633
0
      swap_load_command(&command_struct);
634
635
0
    if (size - parsed_size < command_struct.cmdsize)
636
0
      break;
637
638
0
    if (command_struct.cmdsize < sizeof(yr_load_command_t))
639
0
      break;
640
641
0
    switch (command_struct.cmd)
642
0
    {
643
0
    case LC_UNIXTHREAD:
644
0
      macho_handle_unixthread(command, size - parsed_size, object, context);
645
0
      break;
646
0
    case LC_MAIN:
647
0
      macho_handle_main(command, size - parsed_size, object, context);
648
0
      break;
649
0
    }
650
651
0
    command += command_struct.cmdsize;
652
0
    parsed_size += command_struct.cmdsize;
653
0
  }
654
0
}
655
656
// Parse Mach-O fat file.
657
658
void macho_load_fat_arch_header(
659
    const uint8_t* data,
660
    const uint64_t size,
661
    uint32_t num,
662
    yr_fat_arch_64_t* arch)
663
0
{
664
0
  if (macho_fat_is_32(data))
665
0
  {
666
0
    yr_fat_arch_32_t* arch32 =
667
0
        (yr_fat_arch_32_t*) (data + sizeof(yr_fat_header_t) + (num * sizeof(yr_fat_arch_32_t)));
668
669
0
    arch->cputype = yr_be32toh(arch32->cputype);
670
0
    arch->cpusubtype = yr_be32toh(arch32->cpusubtype);
671
0
    arch->offset = yr_be32toh(arch32->offset);
672
0
    arch->size = yr_be32toh(arch32->size);
673
0
    arch->align = yr_be32toh(arch32->align);
674
0
    arch->reserved = 0;
675
0
  }
676
0
  else
677
0
  {
678
0
    yr_fat_arch_64_t* arch64 =
679
0
        (yr_fat_arch_64_t*) (data + sizeof(yr_fat_header_t) + (num * sizeof(yr_fat_arch_64_t)));
680
681
0
    arch->cputype = yr_be32toh(arch64->cputype);
682
0
    arch->cpusubtype = yr_be32toh(arch64->cpusubtype);
683
0
    arch->offset = yr_be64toh(arch64->offset);
684
0
    arch->size = yr_be64toh(arch64->size);
685
0
    arch->align = yr_be32toh(arch64->align);
686
0
    arch->reserved = yr_be32toh(arch64->reserved);
687
0
  }
688
0
}
689
690
void macho_parse_fat_file(
691
    const uint8_t* data,
692
    const uint64_t size,
693
    YR_OBJECT* object,
694
    YR_SCAN_CONTEXT* context)
695
0
{
696
0
  size_t fat_arch_sz = sizeof(yr_fat_arch_64_t);
697
698
0
  if (macho_fat_is_32(data))
699
0
    fat_arch_sz = sizeof(yr_fat_arch_32_t);
700
701
0
  if (size < sizeof(yr_fat_header_t))
702
0
    return;
703
704
  /* All data in Mach-O fat binary headers are in big-endian byte order. */
705
706
0
  const yr_fat_header_t* header = (yr_fat_header_t*) data;
707
0
  yr_set_integer(yr_be32toh(header->magic), object, "fat_magic");
708
709
0
  uint32_t count = yr_be32toh(header->nfat_arch);
710
0
  yr_set_integer(count, object, "nfat_arch");
711
712
0
  if (size < sizeof(yr_fat_header_t) + count * fat_arch_sz)
713
0
    return;
714
715
0
  yr_fat_arch_64_t arch;
716
717
0
  for (uint32_t i = 0; i < count; i++)
718
0
  {
719
0
    macho_load_fat_arch_header(data, size, i, &arch);
720
721
0
    yr_set_integer(arch.cputype, object, "fat_arch[%i].cputype", i);
722
0
    yr_set_integer(arch.cpusubtype, object, "fat_arch[%i].cpusubtype", i);
723
0
    yr_set_integer(arch.offset, object, "fat_arch[%i].offset", i);
724
0
    yr_set_integer(arch.size, object, "fat_arch[%i].size", i);
725
0
    yr_set_integer(arch.align, object, "fat_arch[%i].align", i);
726
0
    yr_set_integer(arch.reserved, object, "fat_arch[%i].reserved", i);
727
728
    // Check for integer overflow.
729
0
    if (arch.offset + arch.size < arch.offset)
730
0
      continue;
731
732
0
    if (size < arch.offset + arch.size)
733
0
      continue;
734
735
    // Force 'file' array entry creation.
736
0
    yr_set_integer(YR_UNDEFINED, object, "file[%i].magic", i);
737
738
    // Get specific Mach-O file data.
739
0
    macho_parse_file(
740
0
        data + arch.offset,
741
0
        arch.size,
742
0
        yr_get_object(object, "file[%i]", i),
743
0
        context);
744
0
  }
745
0
}
746
747
// Sets all necessary Mach-O constants and definitions.
748
749
void macho_set_definitions(YR_OBJECT* object)
750
0
{
751
  // Magic constants
752
753
0
  yr_set_integer(MH_MAGIC, object, "MH_MAGIC");
754
0
  yr_set_integer(MH_CIGAM, object, "MH_CIGAM");
755
0
  yr_set_integer(MH_MAGIC_64, object, "MH_MAGIC_64");
756
0
  yr_set_integer(MH_CIGAM_64, object, "MH_CIGAM_64");
757
758
  // Fat magic constants
759
760
0
  yr_set_integer(FAT_MAGIC, object, "FAT_MAGIC");
761
0
  yr_set_integer(FAT_CIGAM, object, "FAT_CIGAM");
762
0
  yr_set_integer(FAT_MAGIC_64, object, "FAT_MAGIC_64");
763
0
  yr_set_integer(FAT_CIGAM_64, object, "FAT_CIGAM_64");
764
765
  // 64-bit masks
766
767
0
  yr_set_integer(CPU_ARCH_ABI64, object, "CPU_ARCH_ABI64");
768
0
  yr_set_integer(CPU_SUBTYPE_LIB64, object, "CPU_SUBTYPE_LIB64");
769
770
  // CPU types
771
772
0
  yr_set_integer(CPU_TYPE_MC680X0, object, "CPU_TYPE_MC680X0");
773
0
  yr_set_integer(CPU_TYPE_X86, object, "CPU_TYPE_X86");
774
0
  yr_set_integer(CPU_TYPE_X86, object, "CPU_TYPE_I386");
775
0
  yr_set_integer(CPU_TYPE_X86_64, object, "CPU_TYPE_X86_64");
776
0
  yr_set_integer(CPU_TYPE_MIPS, object, "CPU_TYPE_MIPS");
777
0
  yr_set_integer(CPU_TYPE_MC98000, object, "CPU_TYPE_MC98000");
778
0
  yr_set_integer(CPU_TYPE_ARM, object, "CPU_TYPE_ARM");
779
0
  yr_set_integer(CPU_TYPE_ARM64, object, "CPU_TYPE_ARM64");
780
0
  yr_set_integer(CPU_TYPE_MC88000, object, "CPU_TYPE_MC88000");
781
0
  yr_set_integer(CPU_TYPE_SPARC, object, "CPU_TYPE_SPARC");
782
0
  yr_set_integer(CPU_TYPE_POWERPC, object, "CPU_TYPE_POWERPC");
783
0
  yr_set_integer(CPU_TYPE_POWERPC64, object, "CPU_TYPE_POWERPC64");
784
785
  // CPU sub-types
786
787
0
  yr_set_integer(
788
0
      CPU_SUBTYPE_INTEL_MODEL_ALL, object, "CPU_SUBTYPE_INTEL_MODEL_ALL");
789
0
  yr_set_integer(CPU_SUBTYPE_386, object, "CPU_SUBTYPE_386");
790
0
  yr_set_integer(CPU_SUBTYPE_386, object, "CPU_SUBTYPE_I386_ALL");
791
0
  yr_set_integer(CPU_SUBTYPE_386, object, "CPU_SUBTYPE_X86_64_ALL");
792
0
  yr_set_integer(CPU_SUBTYPE_486, object, "CPU_SUBTYPE_486");
793
0
  yr_set_integer(CPU_SUBTYPE_486SX, object, "CPU_SUBTYPE_486SX");
794
0
  yr_set_integer(CPU_SUBTYPE_586, object, "CPU_SUBTYPE_586");
795
0
  yr_set_integer(CPU_SUBTYPE_PENT, object, "CPU_SUBTYPE_PENT");
796
0
  yr_set_integer(CPU_SUBTYPE_PENTPRO, object, "CPU_SUBTYPE_PENTPRO");
797
0
  yr_set_integer(CPU_SUBTYPE_PENTII_M3, object, "CPU_SUBTYPE_PENTII_M3");
798
0
  yr_set_integer(CPU_SUBTYPE_PENTII_M5, object, "CPU_SUBTYPE_PENTII_M5");
799
0
  yr_set_integer(CPU_SUBTYPE_CELERON, object, "CPU_SUBTYPE_CELERON");
800
0
  yr_set_integer(CPU_SUBTYPE_CELERON_MOBILE, object, "CPU_SUBTYPE_CELERON_MOBILE");
801
0
  yr_set_integer(CPU_SUBTYPE_PENTIUM_3, object, "CPU_SUBTYPE_PENTIUM_3");
802
0
  yr_set_integer(CPU_SUBTYPE_PENTIUM_3_M, object, "CPU_SUBTYPE_PENTIUM_3_M");
803
0
  yr_set_integer(CPU_SUBTYPE_PENTIUM_3_XEON, object, "CPU_SUBTYPE_PENTIUM_3_XEON");
804
0
  yr_set_integer(CPU_SUBTYPE_PENTIUM_M, object, "CPU_SUBTYPE_PENTIUM_M");
805
0
  yr_set_integer(CPU_SUBTYPE_PENTIUM_4, object, "CPU_SUBTYPE_PENTIUM_4");
806
0
  yr_set_integer(CPU_SUBTYPE_PENTIUM_4_M, object, "CPU_SUBTYPE_PENTIUM_4_M");
807
0
  yr_set_integer(CPU_SUBTYPE_ITANIUM, object, "CPU_SUBTYPE_ITANIUM");
808
0
  yr_set_integer(CPU_SUBTYPE_ITANIUM_2, object, "CPU_SUBTYPE_ITANIUM_2");
809
0
  yr_set_integer(CPU_SUBTYPE_XEON, object, "CPU_SUBTYPE_XEON");
810
0
  yr_set_integer(CPU_SUBTYPE_XEON_MP, object, "CPU_SUBTYPE_XEON_MP");
811
0
  yr_set_integer(CPU_SUBTYPE_ARM_ALL, object, "CPU_SUBTYPE_ARM_ALL");
812
0
  yr_set_integer(CPU_SUBTYPE_ARM_V4T, object, "CPU_SUBTYPE_ARM_V4T");
813
0
  yr_set_integer(CPU_SUBTYPE_ARM_V6, object, "CPU_SUBTYPE_ARM_V6");
814
0
  yr_set_integer(CPU_SUBTYPE_ARM_V5, object, "CPU_SUBTYPE_ARM_V5");
815
0
  yr_set_integer(CPU_SUBTYPE_ARM_V5TEJ, object, "CPU_SUBTYPE_ARM_V5TEJ");
816
0
  yr_set_integer(CPU_SUBTYPE_ARM_XSCALE, object, "CPU_SUBTYPE_ARM_XSCALE");
817
0
  yr_set_integer(CPU_SUBTYPE_ARM_V7, object, "CPU_SUBTYPE_ARM_V7");
818
0
  yr_set_integer(CPU_SUBTYPE_ARM_V7F, object, "CPU_SUBTYPE_ARM_V7F");
819
0
  yr_set_integer(CPU_SUBTYPE_ARM_V7S, object, "CPU_SUBTYPE_ARM_V7S");
820
0
  yr_set_integer(CPU_SUBTYPE_ARM_V7K, object, "CPU_SUBTYPE_ARM_V7K");
821
0
  yr_set_integer(CPU_SUBTYPE_ARM_V6M, object, "CPU_SUBTYPE_ARM_V6M");
822
0
  yr_set_integer(CPU_SUBTYPE_ARM_V7M, object, "CPU_SUBTYPE_ARM_V7M");
823
0
  yr_set_integer(CPU_SUBTYPE_ARM_V7EM, object, "CPU_SUBTYPE_ARM_V7EM");
824
0
  yr_set_integer(CPU_SUBTYPE_ARM64_ALL, object, "CPU_SUBTYPE_ARM64_ALL");
825
0
  yr_set_integer(CPU_SUBTYPE_SPARC_ALL, object, "CPU_SUBTYPE_SPARC_ALL");
826
0
  yr_set_integer(CPU_SUBTYPE_POWERPC_ALL, object, "CPU_SUBTYPE_POWERPC_ALL");
827
0
  yr_set_integer(CPU_SUBTYPE_MC980000_ALL, object, "CPU_SUBTYPE_MC980000_ALL");
828
0
  yr_set_integer(CPU_SUBTYPE_POWERPC_601, object, "CPU_SUBTYPE_POWERPC_601");
829
0
  yr_set_integer(CPU_SUBTYPE_MC98601, object, "CPU_SUBTYPE_MC98601");
830
0
  yr_set_integer(CPU_SUBTYPE_POWERPC_602, object, "CPU_SUBTYPE_POWERPC_602");
831
0
  yr_set_integer(CPU_SUBTYPE_POWERPC_603, object, "CPU_SUBTYPE_POWERPC_603");
832
0
  yr_set_integer(CPU_SUBTYPE_POWERPC_603e, object, "CPU_SUBTYPE_POWERPC_603e");
833
0
  yr_set_integer(CPU_SUBTYPE_POWERPC_603ev, object, "CPU_SUBTYPE_POWERPC_603ev");
834
0
  yr_set_integer(CPU_SUBTYPE_POWERPC_604, object, "CPU_SUBTYPE_POWERPC_604");
835
0
  yr_set_integer(CPU_SUBTYPE_POWERPC_604e, object, "CPU_SUBTYPE_POWERPC_604e");
836
0
  yr_set_integer(CPU_SUBTYPE_POWERPC_620, object, "CPU_SUBTYPE_POWERPC_620");
837
0
  yr_set_integer(CPU_SUBTYPE_POWERPC_750, object, "CPU_SUBTYPE_POWERPC_750");
838
0
  yr_set_integer(CPU_SUBTYPE_POWERPC_7400, object, "CPU_SUBTYPE_POWERPC_7400");
839
0
  yr_set_integer(CPU_SUBTYPE_POWERPC_7450, object, "CPU_SUBTYPE_POWERPC_7450");
840
0
  yr_set_integer(CPU_SUBTYPE_POWERPC_970, object, "CPU_SUBTYPE_POWERPC_970");
841
842
  // File types
843
844
0
  yr_set_integer(MH_OBJECT, object, "MH_OBJECT");
845
0
  yr_set_integer(MH_EXECUTE, object, "MH_EXECUTE");
846
0
  yr_set_integer(MH_FVMLIB, object, "MH_FVMLIB");
847
0
  yr_set_integer(MH_CORE, object, "MH_CORE");
848
0
  yr_set_integer(MH_PRELOAD, object, "MH_PRELOAD");
849
0
  yr_set_integer(MH_DYLIB, object, "MH_DYLIB");
850
0
  yr_set_integer(MH_DYLINKER, object, "MH_DYLINKER");
851
0
  yr_set_integer(MH_BUNDLE, object, "MH_BUNDLE");
852
0
  yr_set_integer(MH_DYLIB_STUB, object, "MH_DYLIB_STUB");
853
0
  yr_set_integer(MH_DSYM, object, "MH_DSYM");
854
0
  yr_set_integer(MH_KEXT_BUNDLE, object, "MH_KEXT_BUNDLE");
855
856
  // Header flags
857
858
0
  yr_set_integer(MH_NOUNDEFS, object, "MH_NOUNDEFS");
859
0
  yr_set_integer(MH_INCRLINK, object, "MH_INCRLINK");
860
0
  yr_set_integer(MH_DYLDLINK, object, "MH_DYLDLINK");
861
0
  yr_set_integer(MH_BINDATLOAD, object, "MH_BINDATLOAD");
862
0
  yr_set_integer(MH_PREBOUND, object, "MH_PREBOUND");
863
0
  yr_set_integer(MH_SPLIT_SEGS, object, "MH_SPLIT_SEGS");
864
0
  yr_set_integer(MH_LAZY_INIT, object, "MH_LAZY_INIT");
865
0
  yr_set_integer(MH_TWOLEVEL, object, "MH_TWOLEVEL");
866
0
  yr_set_integer(MH_FORCE_FLAT, object, "MH_FORCE_FLAT");
867
0
  yr_set_integer(MH_NOMULTIDEFS, object, "MH_NOMULTIDEFS");
868
0
  yr_set_integer(MH_NOFIXPREBINDING, object, "MH_NOFIXPREBINDING");
869
0
  yr_set_integer(MH_PREBINDABLE, object, "MH_PREBINDABLE");
870
0
  yr_set_integer(MH_ALLMODSBOUND, object, "MH_ALLMODSBOUND");
871
0
  yr_set_integer(MH_SUBSECTIONS_VIA_SYMBOLS, object, "MH_SUBSECTIONS_VIA_SYMBOLS");
872
0
  yr_set_integer(MH_CANONICAL, object, "MH_CANONICAL");
873
0
  yr_set_integer(MH_WEAK_DEFINES, object, "MH_WEAK_DEFINES");
874
0
  yr_set_integer(MH_BINDS_TO_WEAK, object, "MH_BINDS_TO_WEAK");
875
0
  yr_set_integer(MH_ALLOW_STACK_EXECUTION, object, "MH_ALLOW_STACK_EXECUTION");
876
0
  yr_set_integer(MH_ROOT_SAFE, object, "MH_ROOT_SAFE");
877
0
  yr_set_integer(MH_SETUID_SAFE, object, "MH_SETUID_SAFE");
878
0
  yr_set_integer(MH_NO_REEXPORTED_DYLIBS, object, "MH_NO_REEXPORTED_DYLIBS");
879
0
  yr_set_integer(MH_PIE, object, "MH_PIE");
880
0
  yr_set_integer(MH_DEAD_STRIPPABLE_DYLIB, object, "MH_DEAD_STRIPPABLE_DYLIB");
881
0
  yr_set_integer(MH_HAS_TLV_DESCRIPTORS, object, "MH_HAS_TLV_DESCRIPTORS");
882
0
  yr_set_integer(MH_NO_HEAP_EXECUTION, object, "MH_NO_HEAP_EXECUTION");
883
0
  yr_set_integer(MH_APP_EXTENSION_SAFE, object, "MH_APP_EXTENSION_SAFE");
884
885
  // Segment flags masks
886
887
0
  yr_set_integer(SG_HIGHVM, object, "SG_HIGHVM");
888
0
  yr_set_integer(SG_FVMLIB, object, "SG_FVMLIB");
889
0
  yr_set_integer(SG_NORELOC, object, "SG_NORELOC");
890
0
  yr_set_integer(SG_PROTECTED_VERSION_1, object, "SG_PROTECTED_VERSION_1");
891
892
  // Section flags masks
893
894
0
  yr_set_integer(SECTION_TYPE, object, "SECTION_TYPE");
895
0
  yr_set_integer(SECTION_ATTRIBUTES, object, "SECTION_ATTRIBUTES");
896
897
  // Section types
898
899
0
  yr_set_integer(S_REGULAR, object, "S_REGULAR");
900
0
  yr_set_integer(S_ZEROFILL, object, "S_ZEROFILL");
901
0
  yr_set_integer(S_CSTRING_LITERALS, object, "S_CSTRING_LITERALS");
902
0
  yr_set_integer(S_4BYTE_LITERALS, object, "S_4BYTE_LITERALS");
903
0
  yr_set_integer(S_8BYTE_LITERALS, object, "S_8BYTE_LITERALS");
904
0
  yr_set_integer(S_NON_LAZY_SYMBOL_POINTERS, object, "S_NON_LAZY_SYMBOL_POINTERS");
905
0
  yr_set_integer(S_LAZY_SYMBOL_POINTERS, object, "S_LAZY_SYMBOL_POINTERS");
906
0
  yr_set_integer(S_LITERAL_POINTERS, object, "S_LITERAL_POINTERS");
907
0
  yr_set_integer(S_SYMBOL_STUBS, object, "S_SYMBOL_STUBS");
908
0
  yr_set_integer(S_MOD_INIT_FUNC_POINTERS, object, "S_MOD_INIT_FUNC_POINTERS");
909
0
  yr_set_integer(S_MOD_TERM_FUNC_POINTERS, object, "S_MOD_TERM_FUNC_POINTERS");
910
0
  yr_set_integer(S_COALESCED, object, "S_COALESCED");
911
0
  yr_set_integer(S_GB_ZEROFILL, object, "S_GB_ZEROFILL");
912
0
  yr_set_integer(S_INTERPOSING, object, "S_INTERPOSING");
913
0
  yr_set_integer(S_16BYTE_LITERALS, object, "S_16BYTE_LITERALS");
914
0
  yr_set_integer(S_DTRACE_DOF, object, "S_DTRACE_DOF");
915
0
  yr_set_integer(
916
0
      S_LAZY_DYLIB_SYMBOL_POINTERS, object, "S_LAZY_DYLIB_SYMBOL_POINTERS");
917
0
  yr_set_integer(S_THREAD_LOCAL_REGULAR, object, "S_THREAD_LOCAL_REGULAR");
918
0
  yr_set_integer(S_THREAD_LOCAL_ZEROFILL, object, "S_THREAD_LOCAL_ZEROFILL");
919
0
  yr_set_integer(S_THREAD_LOCAL_VARIABLES, object, "S_THREAD_LOCAL_VARIABLES");
920
0
  yr_set_integer(
921
0
      S_THREAD_LOCAL_VARIABLE_POINTERS,
922
0
      object,
923
0
      "S_THREAD_LOCAL_VARIABLE_POINTERS");
924
0
  yr_set_integer(
925
0
      S_THREAD_LOCAL_INIT_FUNCTION_POINTERS,
926
0
      object,
927
0
      "S_THREAD_LOCAL_INIT_FUNCTION_POINTERS");
928
929
  // Section attributes
930
931
0
  yr_set_integer(S_ATTR_PURE_INSTRUCTIONS, object, "S_ATTR_PURE_INSTRUCTIONS");
932
0
  yr_set_integer(S_ATTR_NO_TOC, object, "S_ATTR_NO_TOC");
933
0
  yr_set_integer(S_ATTR_STRIP_STATIC_SYMS, object, "S_ATTR_STRIP_STATIC_SYMS");
934
0
  yr_set_integer(S_ATTR_NO_DEAD_STRIP, object, "S_ATTR_NO_DEAD_STRIP");
935
0
  yr_set_integer(S_ATTR_LIVE_SUPPORT, object, "S_ATTR_LIVE_SUPPORT");
936
0
  yr_set_integer(S_ATTR_SELF_MODIFYING_CODE, object, "S_ATTR_SELF_MODIFYING_CODE");
937
0
  yr_set_integer(S_ATTR_DEBUG, object, "S_ATTR_DEBUG");
938
0
  yr_set_integer(S_ATTR_SOME_INSTRUCTIONS, object, "S_ATTR_SOME_INSTRUCTIONS");
939
0
  yr_set_integer(S_ATTR_EXT_RELOC, object, "S_ATTR_EXT_RELOC");
940
0
  yr_set_integer(S_ATTR_LOC_RELOC, object, "S_ATTR_LOC_RELOC");
941
0
}
942
943
// Get Mach-O file index in fat file by cputype field.
944
945
define_function(file_index_type)
946
0
{
947
0
  YR_OBJECT* module = yr_module();
948
0
  int64_t type_arg = integer_argument(1);
949
950
0
  uint64_t nfat = yr_get_integer(module, "nfat_arch");
951
0
  if (yr_is_undefined(module, "nfat_arch"))
952
0
    return_integer(YR_UNDEFINED);
953
954
0
  for (int i = 0; i < nfat; i++)
955
0
  {
956
0
    int64_t type = yr_get_integer(module, "file[%i].cputype", i);
957
0
    if (type == type_arg)
958
0
    {
959
0
      return_integer(i);
960
0
    }
961
0
  }
962
0
  return_integer(YR_UNDEFINED);
963
0
}
964
965
// Get Mach-O file index in fat file by cputype and cpusubtype fields.
966
967
define_function(file_index_subtype)
968
0
{
969
0
  YR_OBJECT* module = yr_module();
970
0
  int64_t type_arg = integer_argument(1);
971
0
  int64_t subtype_arg = integer_argument(2);
972
0
  uint64_t nfat = yr_get_integer(module, "nfat_arch");
973
974
0
  if (yr_is_undefined(module, "nfat_arch"))
975
0
    return_integer(YR_UNDEFINED);
976
977
0
  for (int i = 0; i < nfat; i++)
978
0
  {
979
0
    int64_t type = yr_get_integer(module, "file[%i].cputype", i);
980
0
    int64_t subtype = yr_get_integer(module, "file[%i].cpusubtype", i);
981
982
0
    if (type == type_arg && subtype == subtype_arg)
983
0
    {
984
0
      return_integer(i);
985
0
    }
986
0
  }
987
988
0
  return_integer(YR_UNDEFINED);
989
0
}
990
991
// Get real entry point offset for specific architecture in fat Mach-O.
992
993
define_function(ep_for_arch_type)
994
0
{
995
0
  YR_OBJECT* module = yr_module();
996
0
  int64_t type_arg = integer_argument(1);
997
0
  uint64_t nfat = yr_get_integer(module, "nfat_arch");
998
999
0
  if (yr_is_undefined(module, "nfat_arch"))
1000
0
    return_integer(YR_UNDEFINED);
1001
1002
0
  for (int i = 0; i < nfat; i++)
1003
0
  {
1004
0
    int64_t type = yr_get_integer(module, "fat_arch[%i].cputype", i);
1005
0
    if (type == type_arg)
1006
0
    {
1007
0
      uint64_t file_offset = yr_get_integer(module, "fat_arch[%i].offset", i);
1008
0
      uint64_t entry_point = yr_get_integer(module, "file[%i].entry_point", i);
1009
0
      return_integer(file_offset + entry_point);
1010
0
    }
1011
0
  }
1012
1013
0
  return_integer(YR_UNDEFINED);
1014
0
}
1015
1016
// Get real entry point offset for specific architecture in fat Mach-O.
1017
1018
define_function(ep_for_arch_subtype)
1019
0
{
1020
0
  YR_OBJECT* module = yr_module();
1021
0
  int64_t type_arg = integer_argument(1);
1022
0
  int64_t subtype_arg = integer_argument(2);
1023
0
  uint64_t nfat = yr_get_integer(module, "nfat_arch");
1024
1025
0
  if (yr_is_undefined(module, "nfat_arch"))
1026
0
    return_integer(YR_UNDEFINED);
1027
1028
0
  for (int i = 0; i < nfat; i++)
1029
0
  {
1030
0
    int64_t type = yr_get_integer(module, "fat_arch[%i].cputype", i);
1031
0
    int64_t subtype = yr_get_integer(module, "fat_arch[%i].cpusubtype", i);
1032
1033
0
    if (type == type_arg && subtype == subtype_arg)
1034
0
    {
1035
0
      uint64_t entry_point = yr_get_integer(module, "file[%i].entry_point", i);
1036
0
      uint64_t file_offset = yr_get_integer(module, "fat_arch[%i].offset", i);
1037
1038
0
      if (entry_point == YR_UNDEFINED) {
1039
0
        return_integer(YR_UNDEFINED);
1040
0
      } else {
1041
0
        return_integer(file_offset + entry_point);
1042
0
      }
1043
0
    }
1044
0
  }
1045
1046
0
  return_integer(YR_UNDEFINED);
1047
0
}
1048
1049
0
begin_declarations
1050
  // Magic constants
1051
0
  declare_integer("MH_MAGIC");
1052
0
  declare_integer("MH_CIGAM");
1053
0
  declare_integer("MH_MAGIC_64");
1054
0
  declare_integer("MH_CIGAM_64");
1055
1056
  // Fat magic constants
1057
0
  declare_integer("FAT_MAGIC");
1058
0
  declare_integer("FAT_CIGAM");
1059
0
  declare_integer("FAT_MAGIC_64");
1060
0
  declare_integer("FAT_CIGAM_64");
1061
1062
  // 64-bit masks
1063
0
  declare_integer("CPU_ARCH_ABI64");
1064
0
  declare_integer("CPU_SUBTYPE_LIB64");
1065
1066
  // CPU types
1067
0
  declare_integer("CPU_TYPE_MC680X0");
1068
0
  declare_integer("CPU_TYPE_X86");
1069
0
  declare_integer("CPU_TYPE_I386");
1070
0
  declare_integer("CPU_TYPE_X86_64");
1071
0
  declare_integer("CPU_TYPE_MIPS");
1072
0
  declare_integer("CPU_TYPE_MC98000");
1073
0
  declare_integer("CPU_TYPE_ARM");
1074
0
  declare_integer("CPU_TYPE_ARM64");
1075
0
  declare_integer("CPU_TYPE_MC88000");
1076
0
  declare_integer("CPU_TYPE_SPARC");
1077
0
  declare_integer("CPU_TYPE_POWERPC");
1078
0
  declare_integer("CPU_TYPE_POWERPC64");
1079
1080
  // CPU sub-types
1081
0
  declare_integer("CPU_SUBTYPE_INTEL_MODEL_ALL");
1082
0
  declare_integer("CPU_SUBTYPE_386");
1083
0
  declare_integer("CPU_SUBTYPE_I386_ALL");
1084
0
  declare_integer("CPU_SUBTYPE_X86_64_ALL");
1085
0
  declare_integer("CPU_SUBTYPE_486");
1086
0
  declare_integer("CPU_SUBTYPE_486SX");
1087
0
  declare_integer("CPU_SUBTYPE_586");
1088
0
  declare_integer("CPU_SUBTYPE_PENT");
1089
0
  declare_integer("CPU_SUBTYPE_PENTPRO");
1090
0
  declare_integer("CPU_SUBTYPE_PENTII_M3");
1091
0
  declare_integer("CPU_SUBTYPE_PENTII_M5");
1092
0
  declare_integer("CPU_SUBTYPE_CELERON");
1093
0
  declare_integer("CPU_SUBTYPE_CELERON_MOBILE");
1094
0
  declare_integer("CPU_SUBTYPE_PENTIUM_3");
1095
0
  declare_integer("CPU_SUBTYPE_PENTIUM_3_M");
1096
0
  declare_integer("CPU_SUBTYPE_PENTIUM_3_XEON");
1097
0
  declare_integer("CPU_SUBTYPE_PENTIUM_M");
1098
0
  declare_integer("CPU_SUBTYPE_PENTIUM_4");
1099
0
  declare_integer("CPU_SUBTYPE_PENTIUM_4_M");
1100
0
  declare_integer("CPU_SUBTYPE_ITANIUM");
1101
0
  declare_integer("CPU_SUBTYPE_ITANIUM_2");
1102
0
  declare_integer("CPU_SUBTYPE_XEON");
1103
0
  declare_integer("CPU_SUBTYPE_XEON_MP");
1104
0
  declare_integer("CPU_SUBTYPE_ARM_ALL");
1105
0
  declare_integer("CPU_SUBTYPE_ARM_V4T");
1106
0
  declare_integer("CPU_SUBTYPE_ARM_V6");
1107
0
  declare_integer("CPU_SUBTYPE_ARM_V5");
1108
0
  declare_integer("CPU_SUBTYPE_ARM_V5TEJ");
1109
0
  declare_integer("CPU_SUBTYPE_ARM_XSCALE");
1110
0
  declare_integer("CPU_SUBTYPE_ARM_V7");
1111
0
  declare_integer("CPU_SUBTYPE_ARM_V7F");
1112
0
  declare_integer("CPU_SUBTYPE_ARM_V7S");
1113
0
  declare_integer("CPU_SUBTYPE_ARM_V7K");
1114
0
  declare_integer("CPU_SUBTYPE_ARM_V6M");
1115
0
  declare_integer("CPU_SUBTYPE_ARM_V7M");
1116
0
  declare_integer("CPU_SUBTYPE_ARM_V7EM");
1117
0
  declare_integer("CPU_SUBTYPE_ARM64_ALL");
1118
0
  declare_integer("CPU_SUBTYPE_SPARC_ALL");
1119
0
  declare_integer("CPU_SUBTYPE_POWERPC_ALL");
1120
0
  declare_integer("CPU_SUBTYPE_MC980000_ALL");
1121
0
  declare_integer("CPU_SUBTYPE_POWERPC_601");
1122
0
  declare_integer("CPU_SUBTYPE_MC98601");
1123
0
  declare_integer("CPU_SUBTYPE_POWERPC_602");
1124
0
  declare_integer("CPU_SUBTYPE_POWERPC_603");
1125
0
  declare_integer("CPU_SUBTYPE_POWERPC_603e");
1126
0
  declare_integer("CPU_SUBTYPE_POWERPC_603ev");
1127
0
  declare_integer("CPU_SUBTYPE_POWERPC_604");
1128
0
  declare_integer("CPU_SUBTYPE_POWERPC_604e");
1129
0
  declare_integer("CPU_SUBTYPE_POWERPC_620");
1130
0
  declare_integer("CPU_SUBTYPE_POWERPC_750");
1131
0
  declare_integer("CPU_SUBTYPE_POWERPC_7400");
1132
0
  declare_integer("CPU_SUBTYPE_POWERPC_7450");
1133
0
  declare_integer("CPU_SUBTYPE_POWERPC_970");
1134
1135
  // File types
1136
0
  declare_integer("MH_OBJECT");
1137
0
  declare_integer("MH_EXECUTE");
1138
0
  declare_integer("MH_FVMLIB");
1139
0
  declare_integer("MH_CORE");
1140
0
  declare_integer("MH_PRELOAD");
1141
0
  declare_integer("MH_DYLIB");
1142
0
  declare_integer("MH_DYLINKER");
1143
0
  declare_integer("MH_BUNDLE");
1144
0
  declare_integer("MH_DYLIB_STUB");
1145
0
  declare_integer("MH_DSYM");
1146
0
  declare_integer("MH_KEXT_BUNDLE");
1147
1148
  // Header flags
1149
0
  declare_integer("MH_NOUNDEFS");
1150
0
  declare_integer("MH_INCRLINK");
1151
0
  declare_integer("MH_DYLDLINK");
1152
0
  declare_integer("MH_BINDATLOAD");
1153
0
  declare_integer("MH_PREBOUND");
1154
0
  declare_integer("MH_SPLIT_SEGS");
1155
0
  declare_integer("MH_LAZY_INIT");
1156
0
  declare_integer("MH_TWOLEVEL");
1157
0
  declare_integer("MH_FORCE_FLAT");
1158
0
  declare_integer("MH_NOMULTIDEFS");
1159
0
  declare_integer("MH_NOFIXPREBINDING");
1160
0
  declare_integer("MH_PREBINDABLE");
1161
0
  declare_integer("MH_ALLMODSBOUND");
1162
0
  declare_integer("MH_SUBSECTIONS_VIA_SYMBOLS");
1163
0
  declare_integer("MH_CANONICAL");
1164
0
  declare_integer("MH_WEAK_DEFINES");
1165
0
  declare_integer("MH_BINDS_TO_WEAK");
1166
0
  declare_integer("MH_ALLOW_STACK_EXECUTION");
1167
0
  declare_integer("MH_ROOT_SAFE");
1168
0
  declare_integer("MH_SETUID_SAFE");
1169
0
  declare_integer("MH_NO_REEXPORTED_DYLIBS");
1170
0
  declare_integer("MH_PIE");
1171
0
  declare_integer("MH_DEAD_STRIPPABLE_DYLIB");
1172
0
  declare_integer("MH_HAS_TLV_DESCRIPTORS");
1173
0
  declare_integer("MH_NO_HEAP_EXECUTION");
1174
0
  declare_integer("MH_APP_EXTENSION_SAFE");
1175
1176
  // Segment flags
1177
0
  declare_integer("SG_HIGHVM");
1178
0
  declare_integer("SG_FVMLIB");
1179
0
  declare_integer("SG_NORELOC");
1180
0
  declare_integer("SG_PROTECTED_VERSION_1");
1181
1182
  // Section masks
1183
0
  declare_integer("SECTION_TYPE");
1184
0
  declare_integer("SECTION_ATTRIBUTES");
1185
1186
  // Section types
1187
0
  declare_integer("S_REGULAR");
1188
0
  declare_integer("S_ZEROFILL");
1189
0
  declare_integer("S_CSTRING_LITERALS");
1190
0
  declare_integer("S_4BYTE_LITERALS");
1191
0
  declare_integer("S_8BYTE_LITERALS");
1192
0
  declare_integer("S_LITERAL_POINTERS");
1193
0
  declare_integer("S_NON_LAZY_SYMBOL_POINTERS");
1194
0
  declare_integer("S_LAZY_SYMBOL_POINTERS");
1195
0
  declare_integer("S_SYMBOL_STUBS");
1196
0
  declare_integer("S_MOD_INIT_FUNC_POINTERS");
1197
0
  declare_integer("S_MOD_TERM_FUNC_POINTERS");
1198
0
  declare_integer("S_COALESCED");
1199
0
  declare_integer("S_GB_ZEROFILL");
1200
0
  declare_integer("S_INTERPOSING");
1201
0
  declare_integer("S_16BYTE_LITERALS");
1202
0
  declare_integer("S_DTRACE_DOF");
1203
0
  declare_integer("S_LAZY_DYLIB_SYMBOL_POINTERS");
1204
0
  declare_integer("S_THREAD_LOCAL_REGULAR");
1205
0
  declare_integer("S_THREAD_LOCAL_ZEROFILL");
1206
0
  declare_integer("S_THREAD_LOCAL_VARIABLES");
1207
0
  declare_integer("S_THREAD_LOCAL_VARIABLE_POINTERS");
1208
0
  declare_integer("S_THREAD_LOCAL_INIT_FUNCTION_POINTERS");
1209
1210
  // Section attributes
1211
0
  declare_integer("S_ATTR_PURE_INSTRUCTIONS");
1212
0
  declare_integer("S_ATTR_NO_TOC");
1213
0
  declare_integer("S_ATTR_STRIP_STATIC_SYMS");
1214
0
  declare_integer("S_ATTR_NO_DEAD_STRIP");
1215
0
  declare_integer("S_ATTR_LIVE_SUPPORT");
1216
0
  declare_integer("S_ATTR_SELF_MODIFYING_CODE");
1217
0
  declare_integer("S_ATTR_DEBUG");
1218
0
  declare_integer("S_ATTR_SOME_INSTRUCTIONS");
1219
0
  declare_integer("S_ATTR_EXT_RELOC");
1220
0
  declare_integer("S_ATTR_LOC_RELOC");
1221
1222
  // Header
1223
0
  declare_integer("magic");
1224
0
  declare_integer("cputype");
1225
0
  declare_integer("cpusubtype");
1226
0
  declare_integer("filetype");
1227
0
  declare_integer("ncmds");
1228
0
  declare_integer("sizeofcmds");
1229
0
  declare_integer("flags");
1230
0
  declare_integer("reserved");
1231
1232
  // Segments and nested sections
1233
0
  declare_integer("number_of_segments");
1234
1235
0
  begin_struct_array("segments")
1236
0
    declare_string("segname");
1237
0
    declare_integer("vmaddr");
1238
0
    declare_integer("vmsize");
1239
0
    declare_integer("fileoff");
1240
0
    declare_integer("fsize");
1241
0
    declare_integer("maxprot");
1242
0
    declare_integer("initprot");
1243
0
    declare_integer("nsects");
1244
0
    declare_integer("flags");
1245
0
    begin_struct_array("sections")
1246
0
      declare_string("sectname");
1247
0
      declare_string("segname");
1248
0
      declare_integer("addr");
1249
0
      declare_integer("size");
1250
0
      declare_integer("offset");
1251
0
      declare_integer("align");
1252
0
      declare_integer("reloff");
1253
0
      declare_integer("nreloc");
1254
0
      declare_integer("flags");
1255
0
      declare_integer("reserved1");
1256
0
      declare_integer("reserved2");
1257
0
      declare_integer("reserved3");
1258
0
    end_struct_array("sections");
1259
0
  end_struct_array("segments")
1260
1261
  // Entry point and stack size
1262
0
  declare_integer("entry_point");
1263
0
  declare_integer("stack_size");
1264
1265
  // Mach-O fat binary header
1266
0
  declare_integer("fat_magic");
1267
0
  declare_integer("nfat_arch");
1268
1269
0
  begin_struct_array("fat_arch")
1270
0
    declare_integer("cputype");
1271
0
    declare_integer("cpusubtype");
1272
0
    declare_integer("offset");
1273
0
    declare_integer("size");
1274
0
    declare_integer("align");
1275
0
  end_struct_array("fat_arch")
1276
1277
  // Included Mach-O files (must be same as single file structure above)
1278
0
  begin_struct_array("file")
1279
1280
    // Single file header
1281
0
    declare_integer("magic");
1282
0
    declare_integer("cputype");
1283
0
    declare_integer("cpusubtype");
1284
0
    declare_integer("filetype");
1285
0
    declare_integer("ncmds");
1286
0
    declare_integer("sizeofcmds");
1287
0
    declare_integer("flags");
1288
0
    declare_integer("reserved");
1289
1290
    // Segments and nested sections
1291
0
    declare_integer("number_of_segments");
1292
1293
0
    begin_struct_array("segments")
1294
0
      declare_string("segname");
1295
0
      declare_integer("vmaddr");
1296
0
      declare_integer("vmsize");
1297
0
      declare_integer("fileoff");
1298
0
      declare_integer("fsize");
1299
0
      declare_integer("maxprot");
1300
0
      declare_integer("initprot");
1301
0
      declare_integer("nsects");
1302
0
      declare_integer("flags");
1303
0
      begin_struct_array("sections")
1304
0
        declare_string("sectname");
1305
0
        declare_string("segname");
1306
0
        declare_integer("addr");
1307
0
        declare_integer("size");
1308
0
        declare_integer("offset");
1309
0
        declare_integer("align");
1310
0
        declare_integer("reloff");
1311
0
        declare_integer("nreloc");
1312
0
        declare_integer("flags");
1313
0
        declare_integer("reserved1");
1314
0
        declare_integer("reserved2");
1315
0
        declare_integer("reserved3");
1316
0
      end_struct_array("sections");
1317
0
    end_struct_array("segments")
1318
1319
    // Entry point and stack size
1320
0
    declare_integer("entry_point");
1321
0
    declare_integer("stack_size");
1322
1323
0
  end_struct_array("file");
1324
1325
  // Mach-O fat binary helper functions
1326
0
  declare_function("file_index_for_arch", "i", "i", file_index_type);
1327
0
  declare_function("file_index_for_arch", "ii", "i", file_index_subtype);
1328
0
  declare_function("entry_point_for_arch", "i", "i", ep_for_arch_type);
1329
0
  declare_function("entry_point_for_arch", "ii", "i", ep_for_arch_subtype);
1330
0
end_declarations
1331
1332
int module_initialize(YR_MODULE* module)
1333
2
{
1334
2
  return ERROR_SUCCESS;
1335
2
}
1336
1337
int module_finalize(YR_MODULE* module)
1338
0
{
1339
0
  return ERROR_SUCCESS;
1340
0
}
1341
1342
int module_load(
1343
    YR_SCAN_CONTEXT* context,
1344
    YR_OBJECT* module_object,
1345
    void* module_data,
1346
    size_t module_data_size)
1347
0
{
1348
0
  YR_MEMORY_BLOCK* block;
1349
0
  YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator;
1350
1351
0
  foreach_memory_block(iterator, block)
1352
0
  {
1353
0
    const uint8_t* block_data = block->fetch_data(block);
1354
1355
0
    if (block_data == NULL || block->size < 4)
1356
0
      continue;
1357
1358
    // Parse Mach-O binary.
1359
0
    if (is_macho_file_block((uint32_t*) block_data))
1360
0
    {
1361
0
      macho_parse_file(block_data, block->size, module_object, context);
1362
0
      break;
1363
0
    }
1364
1365
    // Parse fat Mach-O binary.
1366
0
    if (is_fat_macho_file_block((uint32_t*) block_data))
1367
0
    {
1368
0
      macho_parse_fat_file(block_data, block->size, module_object, context);
1369
0
      break;
1370
0
    }
1371
0
  }
1372
1373
0
  macho_set_definitions(module_object);
1374
0
  return ERROR_SUCCESS;
1375
0
}
1376
1377
int module_unload(YR_OBJECT* module_object)
1378
0
{
1379
0
  return ERROR_SUCCESS;
1380
0
}