Coverage Report

Created: 2025-07-11 06:08

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