Coverage Report

Created: 2025-08-29 07: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
4.15k
{
40
4.15k
  return *magic == MH_MAGIC || *magic == MH_CIGAM || *magic == MH_MAGIC_64 ||
41
4.15k
         *magic == MH_CIGAM_64;
42
4.15k
}
43
44
// Check if file is for 32-bit architecture.
45
int macho_is_32(uint32_t magic)
46
49.9k
{
47
49.9k
  return magic == MH_MAGIC || magic == MH_CIGAM;
48
49.9k
}
49
50
// Check for Mach-O fat binary magic constant.
51
int is_fat_macho_file_block(const uint32_t* magic)
52
2.91k
{
53
2.91k
  return *magic == FAT_MAGIC || *magic == FAT_CIGAM || *magic == FAT_MAGIC_64 ||
54
2.91k
         *magic == FAT_CIGAM_64;
55
2.91k
}
56
57
// Check if file is 32-bit fat file.
58
int macho_fat_is_32(const uint32_t* magic)
59
427k
{
60
427k
  return yr_be32toh(*magic) == FAT_MAGIC;
61
427k
}
62
63
static int should_swap_bytes(const uint32_t magic)
64
1.02M
{
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
1.02M
  return magic == MH_MAGIC || magic == MH_MAGIC_64 || magic == FAT_MAGIC ||
73
1.02M
         magic == FAT_MAGIC_64;
74
1.02M
#endif
75
1.02M
}
76
77
static void swap_mach_header(yr_mach_header_64_t* mh)
78
5.01k
{
79
  // Don't swap the magic number so we can tell if swapping is needed
80
5.01k
  mh->cputype = yr_bswap32(mh->cputype);
81
5.01k
  mh->cpusubtype = yr_bswap32(mh->cpusubtype);
82
5.01k
  mh->filetype = yr_bswap32(mh->filetype);
83
5.01k
  mh->ncmds = yr_bswap32(mh->ncmds);
84
5.01k
  mh->sizeofcmds = yr_bswap32(mh->sizeofcmds);
85
5.01k
  mh->flags = yr_bswap32(mh->flags);
86
87
5.01k
  if (!macho_is_32(mh->magic))
88
3.11k
    mh->reserved = yr_bswap32(mh->reserved);
89
5.01k
}
90
91
static void swap_load_command(yr_load_command_t* lc)
92
1.25M
{
93
1.25M
  lc->cmd = yr_bswap32(lc->cmd);
94
1.25M
  lc->cmdsize = yr_bswap32(lc->cmdsize);
95
1.25M
}
96
97
static void swap_segment_command(yr_segment_command_32_t* sg)
98
62.1k
{
99
62.1k
  sg->cmd = yr_bswap32(sg->cmd);
100
62.1k
  sg->cmdsize = yr_bswap32(sg->cmdsize);
101
62.1k
  sg->vmaddr = yr_bswap32(sg->vmaddr);
102
62.1k
  sg->vmsize = yr_bswap32(sg->vmsize);
103
62.1k
  sg->fileoff = yr_bswap32(sg->fileoff);
104
62.1k
  sg->filesize = yr_bswap32(sg->filesize);
105
62.1k
  sg->maxprot = yr_bswap32(sg->maxprot);
106
62.1k
  sg->initprot = yr_bswap32(sg->initprot);
107
62.1k
  sg->nsects = yr_bswap32(sg->nsects);
108
62.1k
  sg->flags = yr_bswap32(sg->flags);
109
62.1k
}
110
111
static void swap_segment_command_64(yr_segment_command_64_t* sg)
112
535k
{
113
535k
  sg->cmd = yr_bswap32(sg->cmd);
114
535k
  sg->cmdsize = yr_bswap32(sg->cmdsize);
115
535k
  sg->vmaddr = yr_bswap64(sg->vmaddr);
116
535k
  sg->vmsize = yr_bswap64(sg->vmsize);
117
535k
  sg->fileoff = yr_bswap64(sg->fileoff);
118
535k
  sg->filesize = yr_bswap64(sg->filesize);
119
535k
  sg->maxprot = yr_bswap32(sg->maxprot);
120
535k
  sg->initprot = yr_bswap32(sg->initprot);
121
535k
  sg->nsects = yr_bswap32(sg->nsects);
122
535k
  sg->flags = yr_bswap32(sg->flags);
123
535k
}
124
125
static void swap_section(yr_section_32_t* sec)
126
13.7k
{
127
13.7k
  sec->addr = yr_bswap32(sec->addr);
128
13.7k
  sec->size = yr_bswap32(sec->size);
129
13.7k
  sec->offset = yr_bswap32(sec->offset);
130
13.7k
  sec->align = yr_bswap32(sec->align);
131
13.7k
  sec->reloff = yr_bswap32(sec->reloff);
132
13.7k
  sec->nreloc = yr_bswap32(sec->nreloc);
133
13.7k
  sec->flags = yr_bswap32(sec->flags);
134
13.7k
  sec->reserved1 = yr_bswap32(sec->reserved1);
135
13.7k
  sec->reserved2 = yr_bswap32(sec->reserved2);
136
13.7k
}
137
138
static void swap_section_64(yr_section_64_t* sec)
139
18.3k
{
140
18.3k
  sec->addr = yr_bswap64(sec->addr);
141
18.3k
  sec->size = yr_bswap64(sec->size);
142
18.3k
  sec->offset = yr_bswap32(sec->offset);
143
18.3k
  sec->align = yr_bswap32(sec->align);
144
18.3k
  sec->reloff = yr_bswap32(sec->reloff);
145
18.3k
  sec->nreloc = yr_bswap32(sec->nreloc);
146
18.3k
  sec->flags = yr_bswap32(sec->flags);
147
18.3k
  sec->reserved1 = yr_bswap32(sec->reserved1);
148
18.3k
  sec->reserved2 = yr_bswap32(sec->reserved2);
149
18.3k
  sec->reserved3 = yr_bswap32(sec->reserved3);
150
18.3k
}
151
152
static void swap_entry_point_command(yr_entry_point_command_t* ep_command)
153
1.46k
{
154
1.46k
  ep_command->cmd = yr_bswap32(ep_command->cmd);
155
1.46k
  ep_command->cmdsize = yr_bswap32(ep_command->cmdsize);
156
1.46k
  ep_command->entryoff = yr_bswap64(ep_command->entryoff);
157
1.46k
  ep_command->stacksize = yr_bswap64(ep_command->stacksize);
158
1.46k
}
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
6.45k
{
164
6.45k
  uint64_t segment_count = yr_get_integer(object, "number_of_segments");
165
166
2.24M
  for (int i = 0; i < segment_count; i++)
167
2.23M
  {
168
2.23M
    uint64_t start = yr_get_integer(object, "segments[%i].vmaddr", i);
169
2.23M
    uint64_t end = start + yr_get_integer(object, "segments[%i].vmsize", i);
170
171
2.23M
    if (address >= start && address < end)
172
2.00k
    {
173
2.00k
      uint64_t fileoff = yr_get_integer(object, "segments[%i].fileoff", i);
174
2.00k
      *result = fileoff + (address - start);
175
2.00k
      return true;
176
2.00k
    }
177
2.23M
  }
178
179
4.44k
  return false;
180
6.45k
}
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
22.5k
{
212
22.5k
  int should_swap = should_swap_bytes(yr_get_integer(object, "magic"));
213
22.5k
  bool is64 = false;
214
215
22.5k
  if (size < sizeof(yr_thread_command_t))
216
371
    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
22.1k
  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
22.1k
  if (command_size < sizeof(yr_thread_command_t))
225
11.1k
    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
11.0k
  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
11.0k
  const void* thread_state = data + sizeof(yr_thread_command_t);
235
236
11.0k
  uint64_t address = 0;
237
238
11.0k
  switch (yr_get_integer(object, "cputype"))
239
11.0k
  {
240
1.02k
  case CPU_TYPE_MC680X0:
241
1.02k
  {
242
1.02k
    if (thread_state_size < sizeof(yr_m68k_thread_state_t))
243
399
      return;
244
626
    address = ((yr_m68k_thread_state_t*) thread_state)->pc;
245
626
    break;
246
1.02k
  }
247
719
  case CPU_TYPE_MC88000:
248
719
  {
249
719
    if (thread_state_size < sizeof(yr_m88k_thread_state_t))
250
406
      return;
251
313
    address = ((yr_m88k_thread_state_t*) thread_state)->xip;
252
313
    break;
253
719
  }
254
1.01k
  case CPU_TYPE_SPARC:
255
1.01k
  {
256
1.01k
    if (thread_state_size < sizeof(yr_sparc_thread_state_t))
257
340
      return;
258
678
    address = ((yr_sparc_thread_state_t*) thread_state)->pc;
259
678
    break;
260
1.01k
  }
261
1.84k
  case CPU_TYPE_POWERPC:
262
1.84k
  {
263
1.84k
    if (thread_state_size < sizeof(yr_ppc_thread_state_t))
264
733
      return;
265
1.10k
    address = ((yr_ppc_thread_state_t*) thread_state)->srr0;
266
1.10k
    break;
267
1.84k
  }
268
1.95k
  case CPU_TYPE_X86:
269
1.95k
  {
270
1.95k
    if (thread_state_size < sizeof(yr_x86_thread_state_t))
271
549
      return;
272
1.40k
    address = ((yr_x86_thread_state_t*) thread_state)->eip;
273
1.40k
    break;
274
1.95k
  }
275
1.83k
  case CPU_TYPE_ARM:
276
1.83k
  {
277
1.83k
    if (thread_state_size < sizeof(yr_arm_thread_state_t))
278
544
      return;
279
1.28k
    address = ((yr_arm_thread_state_t*) thread_state)->pc;
280
1.28k
    break;
281
1.83k
  }
282
1.06k
  case CPU_TYPE_X86_64:
283
1.06k
  {
284
1.06k
    if (thread_state_size < sizeof(yr_x86_thread_state64_t))
285
558
      return;
286
505
    address = ((yr_x86_thread_state64_t*) thread_state)->rip;
287
505
    is64 = true;
288
505
    break;
289
1.06k
  }
290
525
  case CPU_TYPE_ARM64:
291
525
  {
292
525
    if (thread_state_size < sizeof(yr_arm_thread_state64_t))
293
264
      return;
294
261
    address = ((yr_arm_thread_state64_t*) thread_state)->pc;
295
261
    is64 = true;
296
261
    break;
297
525
  }
298
560
  case CPU_TYPE_POWERPC64:
299
560
  {
300
560
    if (thread_state_size < sizeof(yr_ppc_thread_state64_t))
301
282
      return;
302
278
    address = ((yr_ppc_thread_state64_t*) thread_state)->srr0;
303
278
    is64 = true;
304
278
    break;
305
560
  }
306
307
494
  default:
308
494
    return;
309
11.0k
  }
310
311
6.45k
  if (should_swap)
312
6.12k
  {
313
6.12k
    if (is64)
314
1.01k
      address = yr_bswap64(address);
315
5.11k
    else
316
5.11k
      address = yr_bswap32(address);
317
6.12k
  }
318
319
6.45k
  if (context->flags & SCAN_FLAGS_PROCESS_MEMORY)
320
0
  {
321
0
    yr_set_integer(base_address + address, object, "entry_point");
322
0
  }
323
6.45k
  else
324
6.45k
  {
325
6.45k
    uint64_t offset = 0;
326
6.45k
    if (macho_rva_to_offset(address, &offset, object))
327
2.00k
    {
328
2.00k
      yr_set_integer(offset, object, "entry_point");
329
2.00k
    }
330
6.45k
  }
331
6.45k
}
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
2.05k
{
341
2.05k
  yr_entry_point_command_t ep_command;
342
343
2.05k
  if (size < sizeof(yr_entry_point_command_t))
344
285
    return;
345
346
1.77k
  memcpy(&ep_command, data, sizeof(yr_entry_point_command_t));
347
348
1.77k
  if (should_swap_bytes(yr_get_integer(object, "magic")))
349
1.46k
    swap_entry_point_command(&ep_command);
350
351
1.77k
  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
1.77k
  else
360
1.77k
  {
361
1.77k
    yr_set_integer(ep_command.entryoff, object, "entry_point");
362
1.77k
  }
363
1.77k
  yr_set_integer(ep_command.stacksize, object, "stack_size");
364
1.77k
}
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
64.5k
{
374
64.5k
  if (size < sizeof(yr_segment_command_32_t))
375
1.25k
    return;
376
377
63.2k
  yr_segment_command_32_t sg;
378
379
63.2k
  memcpy(&sg, data, sizeof(yr_segment_command_32_t));
380
381
63.2k
  int should_swap = should_swap_bytes(yr_get_integer(object, "magic"));
382
383
63.2k
  if (should_swap)
384
62.1k
    swap_segment_command(&sg);
385
386
63.2k
  yr_set_sized_string(
387
63.2k
      sg.segname, strnlen(sg.segname, 16), object, "segments[%i].segname", i);
388
389
63.2k
  yr_set_integer(sg.vmaddr, object, "segments[%i].vmaddr", i);
390
63.2k
  yr_set_integer(sg.vmsize, object, "segments[%i].vmsize", i);
391
63.2k
  yr_set_integer(sg.fileoff, object, "segments[%i].fileoff", i);
392
63.2k
  yr_set_integer(sg.filesize, object, "segments[%i].fsize", i);
393
63.2k
  yr_set_integer(sg.maxprot, object, "segments[%i].maxprot", i);
394
63.2k
  yr_set_integer(sg.initprot, object, "segments[%i].initprot", i);
395
63.2k
  yr_set_integer(sg.nsects, object, "segments[%i].nsects", i);
396
63.2k
  yr_set_integer(sg.flags, object, "segments[%i].flags", i);
397
398
63.2k
  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
63.2k
  yr_section_32_t* sections =
402
63.2k
      (yr_section_32_t*) (data + sizeof(yr_segment_command_32_t));
403
404
82.1k
  for (unsigned j = 0; j < sg.nsects; ++j)
405
80.7k
  {
406
80.7k
    yr_section_32_t sec;
407
408
80.7k
    parsed_size += sizeof(yr_section_32_t);
409
410
80.7k
    if (sg.cmdsize < parsed_size)
411
61.8k
      break;
412
413
18.8k
    memcpy(&sec, &sections[j], sizeof(yr_section_32_t));
414
415
18.8k
    if (should_swap)
416
13.7k
      swap_section(&sec);
417
418
18.8k
    yr_set_sized_string(
419
18.8k
        sec.segname,
420
18.8k
        strnlen(sec.segname, 16),
421
18.8k
        object,
422
18.8k
        "segments[%i].sections[%i].segname",
423
18.8k
        i,
424
18.8k
        j);
425
426
18.8k
    yr_set_sized_string(
427
18.8k
        sec.sectname,
428
18.8k
        strnlen(sec.sectname, 16),
429
18.8k
        object,
430
18.8k
        "segments[%i].sections[%i].sectname",
431
18.8k
        i,
432
18.8k
        j);
433
434
18.8k
    yr_set_integer(sec.addr, object, "segments[%i].sections[%i].addr", i, j);
435
436
18.8k
    yr_set_integer(sec.size, object, "segments[%i].sections[%i].size", i, j);
437
438
18.8k
    yr_set_integer(
439
18.8k
        sec.offset, object, "segments[%i].sections[%i].offset", i, j);
440
441
18.8k
    yr_set_integer(sec.align, object, "segments[%i].sections[%i].align", i, j);
442
443
18.8k
    yr_set_integer(
444
18.8k
        sec.reloff, object, "segments[%i].sections[%i].reloff", i, j);
445
446
18.8k
    yr_set_integer(
447
18.8k
        sec.nreloc, object, "segments[%i].sections[%i].nreloc", i, j);
448
449
18.8k
    yr_set_integer(sec.flags, object, "segments[%i].sections[%i].flags", i, j);
450
451
18.8k
    yr_set_integer(
452
18.8k
        sec.reserved1, object, "segments[%i].sections[%i].reserved1", i, j);
453
454
18.8k
    yr_set_integer(
455
18.8k
        sec.reserved2, object, "segments[%i].sections[%i].reserved2", i, j);
456
18.8k
  }
457
63.2k
}
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
895k
{
465
895k
  if (size < sizeof(yr_segment_command_64_t))
466
5.93k
    return;
467
468
889k
  yr_segment_command_64_t sg;
469
470
889k
  memcpy(&sg, data, sizeof(yr_segment_command_64_t));
471
472
889k
  int should_swap = should_swap_bytes(yr_get_integer(object, "magic"));
473
474
889k
  if (should_swap)
475
535k
    swap_segment_command_64(&sg);
476
477
889k
  yr_set_sized_string(
478
889k
      sg.segname, strnlen(sg.segname, 16), object, "segments[%i].segname", i);
479
480
889k
  yr_set_integer(sg.vmaddr, object, "segments[%i].vmaddr", i);
481
889k
  yr_set_integer(sg.vmsize, object, "segments[%i].vmsize", i);
482
889k
  yr_set_integer(sg.fileoff, object, "segments[%i].fileoff", i);
483
889k
  yr_set_integer(sg.filesize, object, "segments[%i].fsize", i);
484
889k
  yr_set_integer(sg.maxprot, object, "segments[%i].maxprot", i);
485
889k
  yr_set_integer(sg.initprot, object, "segments[%i].initprot", i);
486
889k
  yr_set_integer(sg.nsects, object, "segments[%i].nsects", i);
487
889k
  yr_set_integer(sg.flags, object, "segments[%i].flags", i);
488
489
889k
  uint64_t parsed_size = sizeof(yr_segment_command_64_t);
490
491
889k
  yr_section_64_t sec;
492
493
908k
  for (unsigned j = 0; j < sg.nsects; ++j)
494
907k
  {
495
907k
    parsed_size += sizeof(yr_section_64_t);
496
497
907k
    if (sg.cmdsize < parsed_size)
498
888k
      break;
499
500
18.7k
    memcpy(
501
18.7k
        &sec,
502
18.7k
        data + sizeof(yr_segment_command_64_t) + (j * sizeof(yr_section_64_t)),
503
18.7k
        sizeof(yr_section_64_t));
504
505
18.7k
    if (should_swap)
506
18.3k
      swap_section_64(&sec);
507
508
18.7k
    yr_set_sized_string(
509
18.7k
        sec.segname,
510
18.7k
        strnlen(sec.segname, 16),
511
18.7k
        object,
512
18.7k
        "segments[%i].sections[%i].segname",
513
18.7k
        i,
514
18.7k
        j);
515
516
18.7k
    yr_set_sized_string(
517
18.7k
        sec.sectname,
518
18.7k
        strnlen(sec.sectname, 16),
519
18.7k
        object,
520
18.7k
        "segments[%i].sections[%i].sectname",
521
18.7k
        i,
522
18.7k
        j);
523
524
18.7k
    yr_set_integer(sec.addr, object, "segments[%i].sections[%i].addr", i, j);
525
526
18.7k
    yr_set_integer(sec.size, object, "segments[%i].sections[%i].size", i, j);
527
528
18.7k
    yr_set_integer(
529
18.7k
        sec.offset, object, "segments[%i].sections[%i].offset", i, j);
530
531
18.7k
    yr_set_integer(sec.align, object, "segments[%i].sections[%i].align", i, j);
532
533
18.7k
    yr_set_integer(
534
18.7k
        sec.reloff, object, "segments[%i].sections[%i].reloff", i, j);
535
536
18.7k
    yr_set_integer(
537
18.7k
        sec.nreloc, object, "segments[%i].sections[%i].nreloc", i, j);
538
539
18.7k
    yr_set_integer(sec.flags, object, "segments[%i].sections[%i].flags", i, j);
540
541
18.7k
    yr_set_integer(
542
18.7k
        sec.reserved1, object, "segments[%i].sections[%i].reserved1", i, j);
543
544
18.7k
    yr_set_integer(
545
18.7k
        sec.reserved2, object, "segments[%i].sections[%i].reserved2", i, j);
546
547
18.7k
    yr_set_integer(
548
18.7k
        sec.reserved3, object, "segments[%i].sections[%i].reserved3", i, j);
549
18.7k
  }
550
889k
}
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
258k
{
561
  // Size must be large enough the hold yr_mach_header_64_t, which is larger
562
  // than yr_mach_header_32_t.
563
258k
  if (size < sizeof(yr_mach_header_64_t))
564
213k
    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
44.9k
  yr_mach_header_64_t header;
570
571
44.9k
  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
44.9k
  header.magic = yr_be32toh(header.magic);
576
577
44.9k
  size_t header_size = (header.magic == MH_MAGIC || header.magic == MH_CIGAM)
578
44.9k
                           ? sizeof(yr_mach_header_32_t)
579
44.9k
                           : sizeof(yr_mach_header_64_t);
580
581
44.9k
  int should_swap = should_swap_bytes(header.magic);
582
583
44.9k
  if (should_swap)
584
5.01k
    swap_mach_header(&header);
585
586
44.9k
  yr_set_integer(header.magic, object, "magic");
587
44.9k
  yr_set_integer(header.cputype, object, "cputype");
588
44.9k
  yr_set_integer(header.cpusubtype, object, "cpusubtype");
589
44.9k
  yr_set_integer(header.filetype, object, "filetype");
590
44.9k
  yr_set_integer(header.ncmds, object, "ncmds");
591
44.9k
  yr_set_integer(header.sizeofcmds, object, "sizeofcmds");
592
44.9k
  yr_set_integer(header.flags, object, "flags");
593
594
  // The "reserved" field exists only in 64 bits files.
595
44.9k
  if (!macho_is_32(header.magic))
596
42.8k
    yr_set_integer(header.reserved, object, "reserved");
597
598
  // The first command parsing pass handles only segments.
599
44.9k
  uint64_t seg_count = 0;
600
44.9k
  uint64_t parsed_size = header_size;
601
44.9k
  uint8_t* command = (uint8_t*) (data + header_size);
602
603
44.9k
  yr_load_command_t command_struct;
604
605
1.04M
  for (unsigned i = 0; i < header.ncmds; i++)
606
1.04M
  {
607
1.04M
    if (data + size < command + sizeof(yr_load_command_t))
608
2.19k
      break;
609
610
1.04M
    memcpy(&command_struct, command, sizeof(yr_load_command_t));
611
612
1.04M
    if (should_swap)
613
628k
      swap_load_command(&command_struct);
614
615
1.04M
    if (size - parsed_size < command_struct.cmdsize)
616
38.3k
      break;
617
618
1.00M
    if (command_struct.cmdsize < sizeof(yr_load_command_t))
619
748
      break;
620
621
1.00M
    switch (command_struct.cmd)
622
1.00M
    {
623
64.5k
    case LC_SEGMENT:
624
64.5k
      macho_handle_segment(command, size - parsed_size, seg_count++, object);
625
64.5k
      break;
626
895k
    case LC_SEGMENT_64:
627
895k
      macho_handle_segment_64(command, size - parsed_size, seg_count++, object);
628
895k
      break;
629
1.00M
    }
630
631
1.00M
    command += command_struct.cmdsize;
632
1.00M
    parsed_size += command_struct.cmdsize;
633
1.00M
  }
634
635
44.9k
  yr_set_integer(seg_count, object, "number_of_segments");
636
637
  // The second command parsing pass handles others, who use segment count.
638
44.9k
  parsed_size = header_size;
639
44.9k
  command = (uint8_t*) (data + header_size);
640
641
1.04M
  for (unsigned i = 0; i < header.ncmds; i++)
642
1.04M
  {
643
1.04M
    if (data + size < command + sizeof(yr_load_command_t))
644
2.19k
      break;
645
646
1.04M
    memcpy(&command_struct, command, sizeof(yr_load_command_t));
647
648
1.04M
    if (should_swap)
649
628k
      swap_load_command(&command_struct);
650
651
1.04M
    if (size - parsed_size < command_struct.cmdsize)
652
38.3k
      break;
653
654
1.00M
    if (command_struct.cmdsize < sizeof(yr_load_command_t))
655
748
      break;
656
657
1.00M
    switch (command_struct.cmd)
658
1.00M
    {
659
22.5k
    case LC_UNIXTHREAD:
660
22.5k
      macho_handle_unixthread(
661
22.5k
          command, size - parsed_size, base_address, object, context);
662
22.5k
      break;
663
2.05k
    case LC_MAIN:
664
2.05k
      macho_handle_main(command, size - parsed_size, object, context);
665
2.05k
      break;
666
1.00M
    }
667
668
1.00M
    command += command_struct.cmdsize;
669
1.00M
    parsed_size += command_struct.cmdsize;
670
1.00M
  }
671
44.9k
}
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
426k
{
681
426k
  if (macho_fat_is_32((uint32_t*) data))
682
409k
  {
683
409k
    yr_fat_arch_32_t* arch32 =
684
409k
        (yr_fat_arch_32_t*) (data + sizeof(yr_fat_header_t) +
685
409k
                             (num * sizeof(yr_fat_arch_32_t)));
686
687
409k
    arch->cputype = yr_be32toh(arch32->cputype);
688
409k
    arch->cpusubtype = yr_be32toh(arch32->cpusubtype);
689
409k
    arch->offset = yr_be32toh(arch32->offset);
690
409k
    arch->size = yr_be32toh(arch32->size);
691
409k
    arch->align = yr_be32toh(arch32->align);
692
409k
    arch->reserved = 0;
693
409k
  }
694
17.4k
  else
695
17.4k
  {
696
17.4k
    yr_fat_arch_64_t* arch64 =
697
17.4k
        (yr_fat_arch_64_t*) (data + sizeof(yr_fat_header_t) +
698
17.4k
                             (num * sizeof(yr_fat_arch_64_t)));
699
700
17.4k
    arch->cputype = yr_be32toh(arch64->cputype);
701
17.4k
    arch->cpusubtype = yr_be32toh(arch64->cpusubtype);
702
17.4k
    arch->offset = yr_be64toh(arch64->offset);
703
17.4k
    arch->size = yr_be64toh(arch64->size);
704
17.4k
    arch->align = yr_be32toh(arch64->align);
705
17.4k
    arch->reserved = yr_be32toh(arch64->reserved);
706
17.4k
  }
707
426k
}
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
1.18k
{
716
1.18k
  size_t fat_arch_sz = sizeof(yr_fat_arch_64_t);
717
718
1.18k
  if (macho_fat_is_32((uint32_t*) data))
719
1.05k
    fat_arch_sz = sizeof(yr_fat_arch_32_t);
720
721
1.18k
  if (size < sizeof(yr_fat_header_t))
722
6
    return;
723
724
  /* All data in Mach-O fat binary headers are in big-endian byte order. */
725
726
1.18k
  const yr_fat_header_t* header = (yr_fat_header_t*) data;
727
1.18k
  yr_set_integer(yr_be32toh(header->magic), object, "fat_magic");
728
729
1.18k
  uint32_t count = yr_be32toh(header->nfat_arch);
730
1.18k
  yr_set_integer(count, object, "nfat_arch");
731
732
1.18k
  if (size < sizeof(yr_fat_header_t) + count * fat_arch_sz)
733
67
    return;
734
735
1.11k
  yr_fat_arch_64_t arch;
736
737
427k
  for (uint32_t i = 0; i < count; i++)
738
426k
  {
739
426k
    macho_load_fat_arch_header(data, size, i, &arch);
740
741
426k
    yr_set_integer(arch.cputype, object, "fat_arch[%i].cputype", i);
742
426k
    yr_set_integer(arch.cpusubtype, object, "fat_arch[%i].cpusubtype", i);
743
426k
    yr_set_integer(arch.offset, object, "fat_arch[%i].offset", i);
744
426k
    yr_set_integer(arch.size, object, "fat_arch[%i].size", i);
745
426k
    yr_set_integer(arch.align, object, "fat_arch[%i].align", i);
746
426k
    yr_set_integer(arch.reserved, object, "fat_arch[%i].reserved", i);
747
748
    // Check for integer overflow.
749
426k
    if (arch.offset + arch.size < arch.offset)
750
339
      continue;
751
752
426k
    if (size < arch.offset + arch.size)
753
168k
      continue;
754
755
    // Force 'file' array entry creation.
756
257k
    yr_set_integer(YR_UNDEFINED, object, "file[%i].magic", i);
757
758
    // Get specific Mach-O file data.
759
257k
    macho_parse_file(
760
257k
        data + arch.offset,
761
257k
        arch.size,
762
257k
        base_address,
763
257k
        yr_get_object(object, "file[%i]", i),
764
257k
        context);
765
257k
  }
766
1.11k
}
767
768
// Sets all necessary Mach-O constants and definitions.
769
770
void macho_set_definitions(YR_OBJECT* object)
771
4.17k
{
772
  // Magic constants
773
774
4.17k
  yr_set_integer(MH_MAGIC, object, "MH_MAGIC");
775
4.17k
  yr_set_integer(MH_CIGAM, object, "MH_CIGAM");
776
4.17k
  yr_set_integer(MH_MAGIC_64, object, "MH_MAGIC_64");
777
4.17k
  yr_set_integer(MH_CIGAM_64, object, "MH_CIGAM_64");
778
779
  // Fat magic constants
780
781
4.17k
  yr_set_integer(FAT_MAGIC, object, "FAT_MAGIC");
782
4.17k
  yr_set_integer(FAT_CIGAM, object, "FAT_CIGAM");
783
4.17k
  yr_set_integer(FAT_MAGIC_64, object, "FAT_MAGIC_64");
784
4.17k
  yr_set_integer(FAT_CIGAM_64, object, "FAT_CIGAM_64");
785
786
  // 64-bit masks
787
788
4.17k
  yr_set_integer(CPU_ARCH_ABI64, object, "CPU_ARCH_ABI64");
789
4.17k
  yr_set_integer(CPU_SUBTYPE_LIB64, object, "CPU_SUBTYPE_LIB64");
790
791
  // CPU types
792
793
4.17k
  yr_set_integer(CPU_TYPE_MC680X0, object, "CPU_TYPE_MC680X0");
794
4.17k
  yr_set_integer(CPU_TYPE_X86, object, "CPU_TYPE_X86");
795
4.17k
  yr_set_integer(CPU_TYPE_X86, object, "CPU_TYPE_I386");
796
4.17k
  yr_set_integer(CPU_TYPE_X86_64, object, "CPU_TYPE_X86_64");
797
4.17k
  yr_set_integer(CPU_TYPE_MIPS, object, "CPU_TYPE_MIPS");
798
4.17k
  yr_set_integer(CPU_TYPE_MC98000, object, "CPU_TYPE_MC98000");
799
4.17k
  yr_set_integer(CPU_TYPE_ARM, object, "CPU_TYPE_ARM");
800
4.17k
  yr_set_integer(CPU_TYPE_ARM64, object, "CPU_TYPE_ARM64");
801
4.17k
  yr_set_integer(CPU_TYPE_MC88000, object, "CPU_TYPE_MC88000");
802
4.17k
  yr_set_integer(CPU_TYPE_SPARC, object, "CPU_TYPE_SPARC");
803
4.17k
  yr_set_integer(CPU_TYPE_POWERPC, object, "CPU_TYPE_POWERPC");
804
4.17k
  yr_set_integer(CPU_TYPE_POWERPC64, object, "CPU_TYPE_POWERPC64");
805
806
  // CPU sub-types
807
808
4.17k
  yr_set_integer(
809
4.17k
      CPU_SUBTYPE_INTEL_MODEL_ALL, object, "CPU_SUBTYPE_INTEL_MODEL_ALL");
810
4.17k
  yr_set_integer(CPU_SUBTYPE_386, object, "CPU_SUBTYPE_386");
811
4.17k
  yr_set_integer(CPU_SUBTYPE_386, object, "CPU_SUBTYPE_I386_ALL");
812
4.17k
  yr_set_integer(CPU_SUBTYPE_386, object, "CPU_SUBTYPE_X86_64_ALL");
813
4.17k
  yr_set_integer(CPU_SUBTYPE_486, object, "CPU_SUBTYPE_486");
814
4.17k
  yr_set_integer(CPU_SUBTYPE_486SX, object, "CPU_SUBTYPE_486SX");
815
4.17k
  yr_set_integer(CPU_SUBTYPE_586, object, "CPU_SUBTYPE_586");
816
4.17k
  yr_set_integer(CPU_SUBTYPE_PENT, object, "CPU_SUBTYPE_PENT");
817
4.17k
  yr_set_integer(CPU_SUBTYPE_PENTPRO, object, "CPU_SUBTYPE_PENTPRO");
818
4.17k
  yr_set_integer(CPU_SUBTYPE_PENTII_M3, object, "CPU_SUBTYPE_PENTII_M3");
819
4.17k
  yr_set_integer(CPU_SUBTYPE_PENTII_M5, object, "CPU_SUBTYPE_PENTII_M5");
820
4.17k
  yr_set_integer(CPU_SUBTYPE_CELERON, object, "CPU_SUBTYPE_CELERON");
821
4.17k
  yr_set_integer(
822
4.17k
      CPU_SUBTYPE_CELERON_MOBILE, object, "CPU_SUBTYPE_CELERON_MOBILE");
823
4.17k
  yr_set_integer(CPU_SUBTYPE_PENTIUM_3, object, "CPU_SUBTYPE_PENTIUM_3");
824
4.17k
  yr_set_integer(CPU_SUBTYPE_PENTIUM_3_M, object, "CPU_SUBTYPE_PENTIUM_3_M");
825
4.17k
  yr_set_integer(
826
4.17k
      CPU_SUBTYPE_PENTIUM_3_XEON, object, "CPU_SUBTYPE_PENTIUM_3_XEON");
827
4.17k
  yr_set_integer(CPU_SUBTYPE_PENTIUM_M, object, "CPU_SUBTYPE_PENTIUM_M");
828
4.17k
  yr_set_integer(CPU_SUBTYPE_PENTIUM_4, object, "CPU_SUBTYPE_PENTIUM_4");
829
4.17k
  yr_set_integer(CPU_SUBTYPE_PENTIUM_4_M, object, "CPU_SUBTYPE_PENTIUM_4_M");
830
4.17k
  yr_set_integer(CPU_SUBTYPE_ITANIUM, object, "CPU_SUBTYPE_ITANIUM");
831
4.17k
  yr_set_integer(CPU_SUBTYPE_ITANIUM_2, object, "CPU_SUBTYPE_ITANIUM_2");
832
4.17k
  yr_set_integer(CPU_SUBTYPE_XEON, object, "CPU_SUBTYPE_XEON");
833
4.17k
  yr_set_integer(CPU_SUBTYPE_XEON_MP, object, "CPU_SUBTYPE_XEON_MP");
834
4.17k
  yr_set_integer(CPU_SUBTYPE_ARM_ALL, object, "CPU_SUBTYPE_ARM_ALL");
835
4.17k
  yr_set_integer(CPU_SUBTYPE_ARM_V4T, object, "CPU_SUBTYPE_ARM_V4T");
836
4.17k
  yr_set_integer(CPU_SUBTYPE_ARM_V6, object, "CPU_SUBTYPE_ARM_V6");
837
4.17k
  yr_set_integer(CPU_SUBTYPE_ARM_V5, object, "CPU_SUBTYPE_ARM_V5");
838
4.17k
  yr_set_integer(CPU_SUBTYPE_ARM_V5TEJ, object, "CPU_SUBTYPE_ARM_V5TEJ");
839
4.17k
  yr_set_integer(CPU_SUBTYPE_ARM_XSCALE, object, "CPU_SUBTYPE_ARM_XSCALE");
840
4.17k
  yr_set_integer(CPU_SUBTYPE_ARM_V7, object, "CPU_SUBTYPE_ARM_V7");
841
4.17k
  yr_set_integer(CPU_SUBTYPE_ARM_V7F, object, "CPU_SUBTYPE_ARM_V7F");
842
4.17k
  yr_set_integer(CPU_SUBTYPE_ARM_V7S, object, "CPU_SUBTYPE_ARM_V7S");
843
4.17k
  yr_set_integer(CPU_SUBTYPE_ARM_V7K, object, "CPU_SUBTYPE_ARM_V7K");
844
4.17k
  yr_set_integer(CPU_SUBTYPE_ARM_V6M, object, "CPU_SUBTYPE_ARM_V6M");
845
4.17k
  yr_set_integer(CPU_SUBTYPE_ARM_V7M, object, "CPU_SUBTYPE_ARM_V7M");
846
4.17k
  yr_set_integer(CPU_SUBTYPE_ARM_V7EM, object, "CPU_SUBTYPE_ARM_V7EM");
847
4.17k
  yr_set_integer(CPU_SUBTYPE_ARM64_ALL, object, "CPU_SUBTYPE_ARM64_ALL");
848
4.17k
  yr_set_integer(CPU_SUBTYPE_SPARC_ALL, object, "CPU_SUBTYPE_SPARC_ALL");
849
4.17k
  yr_set_integer(CPU_SUBTYPE_POWERPC_ALL, object, "CPU_SUBTYPE_POWERPC_ALL");
850
4.17k
  yr_set_integer(CPU_SUBTYPE_MC980000_ALL, object, "CPU_SUBTYPE_MC980000_ALL");
851
4.17k
  yr_set_integer(CPU_SUBTYPE_POWERPC_601, object, "CPU_SUBTYPE_POWERPC_601");
852
4.17k
  yr_set_integer(CPU_SUBTYPE_MC98601, object, "CPU_SUBTYPE_MC98601");
853
4.17k
  yr_set_integer(CPU_SUBTYPE_POWERPC_602, object, "CPU_SUBTYPE_POWERPC_602");
854
4.17k
  yr_set_integer(CPU_SUBTYPE_POWERPC_603, object, "CPU_SUBTYPE_POWERPC_603");
855
4.17k
  yr_set_integer(CPU_SUBTYPE_POWERPC_603e, object, "CPU_SUBTYPE_POWERPC_603e");
856
4.17k
  yr_set_integer(
857
4.17k
      CPU_SUBTYPE_POWERPC_603ev, object, "CPU_SUBTYPE_POWERPC_603ev");
858
4.17k
  yr_set_integer(CPU_SUBTYPE_POWERPC_604, object, "CPU_SUBTYPE_POWERPC_604");
859
4.17k
  yr_set_integer(CPU_SUBTYPE_POWERPC_604e, object, "CPU_SUBTYPE_POWERPC_604e");
860
4.17k
  yr_set_integer(CPU_SUBTYPE_POWERPC_620, object, "CPU_SUBTYPE_POWERPC_620");
861
4.17k
  yr_set_integer(CPU_SUBTYPE_POWERPC_750, object, "CPU_SUBTYPE_POWERPC_750");
862
4.17k
  yr_set_integer(CPU_SUBTYPE_POWERPC_7400, object, "CPU_SUBTYPE_POWERPC_7400");
863
4.17k
  yr_set_integer(CPU_SUBTYPE_POWERPC_7450, object, "CPU_SUBTYPE_POWERPC_7450");
864
4.17k
  yr_set_integer(CPU_SUBTYPE_POWERPC_970, object, "CPU_SUBTYPE_POWERPC_970");
865
866
  // File types
867
868
4.17k
  yr_set_integer(MH_OBJECT, object, "MH_OBJECT");
869
4.17k
  yr_set_integer(MH_EXECUTE, object, "MH_EXECUTE");
870
4.17k
  yr_set_integer(MH_FVMLIB, object, "MH_FVMLIB");
871
4.17k
  yr_set_integer(MH_CORE, object, "MH_CORE");
872
4.17k
  yr_set_integer(MH_PRELOAD, object, "MH_PRELOAD");
873
4.17k
  yr_set_integer(MH_DYLIB, object, "MH_DYLIB");
874
4.17k
  yr_set_integer(MH_DYLINKER, object, "MH_DYLINKER");
875
4.17k
  yr_set_integer(MH_BUNDLE, object, "MH_BUNDLE");
876
4.17k
  yr_set_integer(MH_DYLIB_STUB, object, "MH_DYLIB_STUB");
877
4.17k
  yr_set_integer(MH_DSYM, object, "MH_DSYM");
878
4.17k
  yr_set_integer(MH_KEXT_BUNDLE, object, "MH_KEXT_BUNDLE");
879
880
  // Header flags
881
882
4.17k
  yr_set_integer(MH_NOUNDEFS, object, "MH_NOUNDEFS");
883
4.17k
  yr_set_integer(MH_INCRLINK, object, "MH_INCRLINK");
884
4.17k
  yr_set_integer(MH_DYLDLINK, object, "MH_DYLDLINK");
885
4.17k
  yr_set_integer(MH_BINDATLOAD, object, "MH_BINDATLOAD");
886
4.17k
  yr_set_integer(MH_PREBOUND, object, "MH_PREBOUND");
887
4.17k
  yr_set_integer(MH_SPLIT_SEGS, object, "MH_SPLIT_SEGS");
888
4.17k
  yr_set_integer(MH_LAZY_INIT, object, "MH_LAZY_INIT");
889
4.17k
  yr_set_integer(MH_TWOLEVEL, object, "MH_TWOLEVEL");
890
4.17k
  yr_set_integer(MH_FORCE_FLAT, object, "MH_FORCE_FLAT");
891
4.17k
  yr_set_integer(MH_NOMULTIDEFS, object, "MH_NOMULTIDEFS");
892
4.17k
  yr_set_integer(MH_NOFIXPREBINDING, object, "MH_NOFIXPREBINDING");
893
4.17k
  yr_set_integer(MH_PREBINDABLE, object, "MH_PREBINDABLE");
894
4.17k
  yr_set_integer(MH_ALLMODSBOUND, object, "MH_ALLMODSBOUND");
895
4.17k
  yr_set_integer(
896
4.17k
      MH_SUBSECTIONS_VIA_SYMBOLS, object, "MH_SUBSECTIONS_VIA_SYMBOLS");
897
4.17k
  yr_set_integer(MH_CANONICAL, object, "MH_CANONICAL");
898
4.17k
  yr_set_integer(MH_WEAK_DEFINES, object, "MH_WEAK_DEFINES");
899
4.17k
  yr_set_integer(MH_BINDS_TO_WEAK, object, "MH_BINDS_TO_WEAK");
900
4.17k
  yr_set_integer(MH_ALLOW_STACK_EXECUTION, object, "MH_ALLOW_STACK_EXECUTION");
901
4.17k
  yr_set_integer(MH_ROOT_SAFE, object, "MH_ROOT_SAFE");
902
4.17k
  yr_set_integer(MH_SETUID_SAFE, object, "MH_SETUID_SAFE");
903
4.17k
  yr_set_integer(MH_NO_REEXPORTED_DYLIBS, object, "MH_NO_REEXPORTED_DYLIBS");
904
4.17k
  yr_set_integer(MH_PIE, object, "MH_PIE");
905
4.17k
  yr_set_integer(MH_DEAD_STRIPPABLE_DYLIB, object, "MH_DEAD_STRIPPABLE_DYLIB");
906
4.17k
  yr_set_integer(MH_HAS_TLV_DESCRIPTORS, object, "MH_HAS_TLV_DESCRIPTORS");
907
4.17k
  yr_set_integer(MH_NO_HEAP_EXECUTION, object, "MH_NO_HEAP_EXECUTION");
908
4.17k
  yr_set_integer(MH_APP_EXTENSION_SAFE, object, "MH_APP_EXTENSION_SAFE");
909
910
  // Segment flags masks
911
912
4.17k
  yr_set_integer(SG_HIGHVM, object, "SG_HIGHVM");
913
4.17k
  yr_set_integer(SG_FVMLIB, object, "SG_FVMLIB");
914
4.17k
  yr_set_integer(SG_NORELOC, object, "SG_NORELOC");
915
4.17k
  yr_set_integer(SG_PROTECTED_VERSION_1, object, "SG_PROTECTED_VERSION_1");
916
917
  // Section flags masks
918
919
4.17k
  yr_set_integer(SECTION_TYPE, object, "SECTION_TYPE");
920
4.17k
  yr_set_integer(SECTION_ATTRIBUTES, object, "SECTION_ATTRIBUTES");
921
922
  // Section types
923
924
4.17k
  yr_set_integer(S_REGULAR, object, "S_REGULAR");
925
4.17k
  yr_set_integer(S_ZEROFILL, object, "S_ZEROFILL");
926
4.17k
  yr_set_integer(S_CSTRING_LITERALS, object, "S_CSTRING_LITERALS");
927
4.17k
  yr_set_integer(S_4BYTE_LITERALS, object, "S_4BYTE_LITERALS");
928
4.17k
  yr_set_integer(S_8BYTE_LITERALS, object, "S_8BYTE_LITERALS");
929
4.17k
  yr_set_integer(
930
4.17k
      S_NON_LAZY_SYMBOL_POINTERS, object, "S_NON_LAZY_SYMBOL_POINTERS");
931
4.17k
  yr_set_integer(S_LAZY_SYMBOL_POINTERS, object, "S_LAZY_SYMBOL_POINTERS");
932
4.17k
  yr_set_integer(S_LITERAL_POINTERS, object, "S_LITERAL_POINTERS");
933
4.17k
  yr_set_integer(S_SYMBOL_STUBS, object, "S_SYMBOL_STUBS");
934
4.17k
  yr_set_integer(S_MOD_INIT_FUNC_POINTERS, object, "S_MOD_INIT_FUNC_POINTERS");
935
4.17k
  yr_set_integer(S_MOD_TERM_FUNC_POINTERS, object, "S_MOD_TERM_FUNC_POINTERS");
936
4.17k
  yr_set_integer(S_COALESCED, object, "S_COALESCED");
937
4.17k
  yr_set_integer(S_GB_ZEROFILL, object, "S_GB_ZEROFILL");
938
4.17k
  yr_set_integer(S_INTERPOSING, object, "S_INTERPOSING");
939
4.17k
  yr_set_integer(S_16BYTE_LITERALS, object, "S_16BYTE_LITERALS");
940
4.17k
  yr_set_integer(S_DTRACE_DOF, object, "S_DTRACE_DOF");
941
4.17k
  yr_set_integer(
942
4.17k
      S_LAZY_DYLIB_SYMBOL_POINTERS, object, "S_LAZY_DYLIB_SYMBOL_POINTERS");
943
4.17k
  yr_set_integer(S_THREAD_LOCAL_REGULAR, object, "S_THREAD_LOCAL_REGULAR");
944
4.17k
  yr_set_integer(S_THREAD_LOCAL_ZEROFILL, object, "S_THREAD_LOCAL_ZEROFILL");
945
4.17k
  yr_set_integer(S_THREAD_LOCAL_VARIABLES, object, "S_THREAD_LOCAL_VARIABLES");
946
4.17k
  yr_set_integer(
947
4.17k
      S_THREAD_LOCAL_VARIABLE_POINTERS,
948
4.17k
      object,
949
4.17k
      "S_THREAD_LOCAL_VARIABLE_POINTERS");
950
4.17k
  yr_set_integer(
951
4.17k
      S_THREAD_LOCAL_INIT_FUNCTION_POINTERS,
952
4.17k
      object,
953
4.17k
      "S_THREAD_LOCAL_INIT_FUNCTION_POINTERS");
954
955
  // Section attributes
956
957
4.17k
  yr_set_integer(S_ATTR_PURE_INSTRUCTIONS, object, "S_ATTR_PURE_INSTRUCTIONS");
958
4.17k
  yr_set_integer(S_ATTR_NO_TOC, object, "S_ATTR_NO_TOC");
959
4.17k
  yr_set_integer(S_ATTR_STRIP_STATIC_SYMS, object, "S_ATTR_STRIP_STATIC_SYMS");
960
4.17k
  yr_set_integer(S_ATTR_NO_DEAD_STRIP, object, "S_ATTR_NO_DEAD_STRIP");
961
4.17k
  yr_set_integer(S_ATTR_LIVE_SUPPORT, object, "S_ATTR_LIVE_SUPPORT");
962
4.17k
  yr_set_integer(
963
4.17k
      S_ATTR_SELF_MODIFYING_CODE, object, "S_ATTR_SELF_MODIFYING_CODE");
964
4.17k
  yr_set_integer(S_ATTR_DEBUG, object, "S_ATTR_DEBUG");
965
4.17k
  yr_set_integer(S_ATTR_SOME_INSTRUCTIONS, object, "S_ATTR_SOME_INSTRUCTIONS");
966
4.17k
  yr_set_integer(S_ATTR_EXT_RELOC, object, "S_ATTR_EXT_RELOC");
967
4.17k
  yr_set_integer(S_ATTR_LOC_RELOC, object, "S_ATTR_LOC_RELOC");
968
4.17k
}
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
4.18k
begin_declarations
1080
  // Magic constants
1081
4.18k
  declare_integer("MH_MAGIC");
1082
4.18k
  declare_integer("MH_CIGAM");
1083
4.18k
  declare_integer("MH_MAGIC_64");
1084
4.18k
  declare_integer("MH_CIGAM_64");
1085
1086
  // Fat magic constants
1087
4.18k
  declare_integer("FAT_MAGIC");
1088
4.18k
  declare_integer("FAT_CIGAM");
1089
4.18k
  declare_integer("FAT_MAGIC_64");
1090
4.18k
  declare_integer("FAT_CIGAM_64");
1091
1092
  // 64-bit masks
1093
4.18k
  declare_integer("CPU_ARCH_ABI64");
1094
4.18k
  declare_integer("CPU_SUBTYPE_LIB64");
1095
1096
  // CPU types
1097
4.18k
  declare_integer("CPU_TYPE_MC680X0");
1098
4.18k
  declare_integer("CPU_TYPE_X86");
1099
4.18k
  declare_integer("CPU_TYPE_I386");
1100
4.18k
  declare_integer("CPU_TYPE_X86_64");
1101
4.18k
  declare_integer("CPU_TYPE_MIPS");
1102
4.18k
  declare_integer("CPU_TYPE_MC98000");
1103
4.18k
  declare_integer("CPU_TYPE_ARM");
1104
4.18k
  declare_integer("CPU_TYPE_ARM64");
1105
4.18k
  declare_integer("CPU_TYPE_MC88000");
1106
4.18k
  declare_integer("CPU_TYPE_SPARC");
1107
4.18k
  declare_integer("CPU_TYPE_POWERPC");
1108
4.18k
  declare_integer("CPU_TYPE_POWERPC64");
1109
1110
  // CPU sub-types
1111
4.18k
  declare_integer("CPU_SUBTYPE_INTEL_MODEL_ALL");
1112
4.18k
  declare_integer("CPU_SUBTYPE_386");
1113
4.18k
  declare_integer("CPU_SUBTYPE_I386_ALL");
1114
4.18k
  declare_integer("CPU_SUBTYPE_X86_64_ALL");
1115
4.18k
  declare_integer("CPU_SUBTYPE_486");
1116
4.18k
  declare_integer("CPU_SUBTYPE_486SX");
1117
4.18k
  declare_integer("CPU_SUBTYPE_586");
1118
4.18k
  declare_integer("CPU_SUBTYPE_PENT");
1119
4.18k
  declare_integer("CPU_SUBTYPE_PENTPRO");
1120
4.18k
  declare_integer("CPU_SUBTYPE_PENTII_M3");
1121
4.18k
  declare_integer("CPU_SUBTYPE_PENTII_M5");
1122
4.18k
  declare_integer("CPU_SUBTYPE_CELERON");
1123
4.18k
  declare_integer("CPU_SUBTYPE_CELERON_MOBILE");
1124
4.18k
  declare_integer("CPU_SUBTYPE_PENTIUM_3");
1125
4.18k
  declare_integer("CPU_SUBTYPE_PENTIUM_3_M");
1126
4.18k
  declare_integer("CPU_SUBTYPE_PENTIUM_3_XEON");
1127
4.18k
  declare_integer("CPU_SUBTYPE_PENTIUM_M");
1128
4.18k
  declare_integer("CPU_SUBTYPE_PENTIUM_4");
1129
4.18k
  declare_integer("CPU_SUBTYPE_PENTIUM_4_M");
1130
4.18k
  declare_integer("CPU_SUBTYPE_ITANIUM");
1131
4.18k
  declare_integer("CPU_SUBTYPE_ITANIUM_2");
1132
4.18k
  declare_integer("CPU_SUBTYPE_XEON");
1133
4.18k
  declare_integer("CPU_SUBTYPE_XEON_MP");
1134
4.18k
  declare_integer("CPU_SUBTYPE_ARM_ALL");
1135
4.18k
  declare_integer("CPU_SUBTYPE_ARM_V4T");
1136
4.18k
  declare_integer("CPU_SUBTYPE_ARM_V6");
1137
4.18k
  declare_integer("CPU_SUBTYPE_ARM_V5");
1138
4.18k
  declare_integer("CPU_SUBTYPE_ARM_V5TEJ");
1139
4.18k
  declare_integer("CPU_SUBTYPE_ARM_XSCALE");
1140
4.18k
  declare_integer("CPU_SUBTYPE_ARM_V7");
1141
4.18k
  declare_integer("CPU_SUBTYPE_ARM_V7F");
1142
4.18k
  declare_integer("CPU_SUBTYPE_ARM_V7S");
1143
4.18k
  declare_integer("CPU_SUBTYPE_ARM_V7K");
1144
4.18k
  declare_integer("CPU_SUBTYPE_ARM_V6M");
1145
4.18k
  declare_integer("CPU_SUBTYPE_ARM_V7M");
1146
4.18k
  declare_integer("CPU_SUBTYPE_ARM_V7EM");
1147
4.18k
  declare_integer("CPU_SUBTYPE_ARM64_ALL");
1148
4.18k
  declare_integer("CPU_SUBTYPE_SPARC_ALL");
1149
4.18k
  declare_integer("CPU_SUBTYPE_POWERPC_ALL");
1150
4.18k
  declare_integer("CPU_SUBTYPE_MC980000_ALL");
1151
4.18k
  declare_integer("CPU_SUBTYPE_POWERPC_601");
1152
4.18k
  declare_integer("CPU_SUBTYPE_MC98601");
1153
4.18k
  declare_integer("CPU_SUBTYPE_POWERPC_602");
1154
4.18k
  declare_integer("CPU_SUBTYPE_POWERPC_603");
1155
4.18k
  declare_integer("CPU_SUBTYPE_POWERPC_603e");
1156
4.18k
  declare_integer("CPU_SUBTYPE_POWERPC_603ev");
1157
4.18k
  declare_integer("CPU_SUBTYPE_POWERPC_604");
1158
4.18k
  declare_integer("CPU_SUBTYPE_POWERPC_604e");
1159
4.18k
  declare_integer("CPU_SUBTYPE_POWERPC_620");
1160
4.18k
  declare_integer("CPU_SUBTYPE_POWERPC_750");
1161
4.18k
  declare_integer("CPU_SUBTYPE_POWERPC_7400");
1162
4.18k
  declare_integer("CPU_SUBTYPE_POWERPC_7450");
1163
4.18k
  declare_integer("CPU_SUBTYPE_POWERPC_970");
1164
1165
  // File types
1166
4.18k
  declare_integer("MH_OBJECT");
1167
4.18k
  declare_integer("MH_EXECUTE");
1168
4.18k
  declare_integer("MH_FVMLIB");
1169
4.18k
  declare_integer("MH_CORE");
1170
4.18k
  declare_integer("MH_PRELOAD");
1171
4.18k
  declare_integer("MH_DYLIB");
1172
4.18k
  declare_integer("MH_DYLINKER");
1173
4.18k
  declare_integer("MH_BUNDLE");
1174
4.18k
  declare_integer("MH_DYLIB_STUB");
1175
4.18k
  declare_integer("MH_DSYM");
1176
4.18k
  declare_integer("MH_KEXT_BUNDLE");
1177
1178
  // Header flags
1179
4.18k
  declare_integer("MH_NOUNDEFS");
1180
4.18k
  declare_integer("MH_INCRLINK");
1181
4.18k
  declare_integer("MH_DYLDLINK");
1182
4.18k
  declare_integer("MH_BINDATLOAD");
1183
4.18k
  declare_integer("MH_PREBOUND");
1184
4.18k
  declare_integer("MH_SPLIT_SEGS");
1185
4.18k
  declare_integer("MH_LAZY_INIT");
1186
4.18k
  declare_integer("MH_TWOLEVEL");
1187
4.18k
  declare_integer("MH_FORCE_FLAT");
1188
4.18k
  declare_integer("MH_NOMULTIDEFS");
1189
4.18k
  declare_integer("MH_NOFIXPREBINDING");
1190
4.18k
  declare_integer("MH_PREBINDABLE");
1191
4.18k
  declare_integer("MH_ALLMODSBOUND");
1192
4.18k
  declare_integer("MH_SUBSECTIONS_VIA_SYMBOLS");
1193
4.18k
  declare_integer("MH_CANONICAL");
1194
4.18k
  declare_integer("MH_WEAK_DEFINES");
1195
4.18k
  declare_integer("MH_BINDS_TO_WEAK");
1196
4.18k
  declare_integer("MH_ALLOW_STACK_EXECUTION");
1197
4.18k
  declare_integer("MH_ROOT_SAFE");
1198
4.18k
  declare_integer("MH_SETUID_SAFE");
1199
4.18k
  declare_integer("MH_NO_REEXPORTED_DYLIBS");
1200
4.18k
  declare_integer("MH_PIE");
1201
4.18k
  declare_integer("MH_DEAD_STRIPPABLE_DYLIB");
1202
4.18k
  declare_integer("MH_HAS_TLV_DESCRIPTORS");
1203
4.18k
  declare_integer("MH_NO_HEAP_EXECUTION");
1204
4.18k
  declare_integer("MH_APP_EXTENSION_SAFE");
1205
1206
  // Segment flags
1207
4.18k
  declare_integer("SG_HIGHVM");
1208
4.18k
  declare_integer("SG_FVMLIB");
1209
4.18k
  declare_integer("SG_NORELOC");
1210
4.18k
  declare_integer("SG_PROTECTED_VERSION_1");
1211
1212
  // Section masks
1213
4.18k
  declare_integer("SECTION_TYPE");
1214
4.18k
  declare_integer("SECTION_ATTRIBUTES");
1215
1216
  // Section types
1217
4.18k
  declare_integer("S_REGULAR");
1218
4.18k
  declare_integer("S_ZEROFILL");
1219
4.18k
  declare_integer("S_CSTRING_LITERALS");
1220
4.18k
  declare_integer("S_4BYTE_LITERALS");
1221
4.18k
  declare_integer("S_8BYTE_LITERALS");
1222
4.18k
  declare_integer("S_LITERAL_POINTERS");
1223
4.18k
  declare_integer("S_NON_LAZY_SYMBOL_POINTERS");
1224
4.18k
  declare_integer("S_LAZY_SYMBOL_POINTERS");
1225
4.18k
  declare_integer("S_SYMBOL_STUBS");
1226
4.18k
  declare_integer("S_MOD_INIT_FUNC_POINTERS");
1227
4.18k
  declare_integer("S_MOD_TERM_FUNC_POINTERS");
1228
4.18k
  declare_integer("S_COALESCED");
1229
4.18k
  declare_integer("S_GB_ZEROFILL");
1230
4.18k
  declare_integer("S_INTERPOSING");
1231
4.18k
  declare_integer("S_16BYTE_LITERALS");
1232
4.18k
  declare_integer("S_DTRACE_DOF");
1233
4.18k
  declare_integer("S_LAZY_DYLIB_SYMBOL_POINTERS");
1234
4.18k
  declare_integer("S_THREAD_LOCAL_REGULAR");
1235
4.18k
  declare_integer("S_THREAD_LOCAL_ZEROFILL");
1236
4.18k
  declare_integer("S_THREAD_LOCAL_VARIABLES");
1237
4.18k
  declare_integer("S_THREAD_LOCAL_VARIABLE_POINTERS");
1238
4.18k
  declare_integer("S_THREAD_LOCAL_INIT_FUNCTION_POINTERS");
1239
1240
  // Section attributes
1241
4.18k
  declare_integer("S_ATTR_PURE_INSTRUCTIONS");
1242
4.18k
  declare_integer("S_ATTR_NO_TOC");
1243
4.18k
  declare_integer("S_ATTR_STRIP_STATIC_SYMS");
1244
4.18k
  declare_integer("S_ATTR_NO_DEAD_STRIP");
1245
4.18k
  declare_integer("S_ATTR_LIVE_SUPPORT");
1246
4.18k
  declare_integer("S_ATTR_SELF_MODIFYING_CODE");
1247
4.18k
  declare_integer("S_ATTR_DEBUG");
1248
4.18k
  declare_integer("S_ATTR_SOME_INSTRUCTIONS");
1249
4.18k
  declare_integer("S_ATTR_EXT_RELOC");
1250
4.18k
  declare_integer("S_ATTR_LOC_RELOC");
1251
1252
  // Header
1253
4.18k
  declare_integer("magic");
1254
4.18k
  declare_integer("cputype");
1255
4.18k
  declare_integer("cpusubtype");
1256
4.18k
  declare_integer("filetype");
1257
4.18k
  declare_integer("ncmds");
1258
4.18k
  declare_integer("sizeofcmds");
1259
4.18k
  declare_integer("flags");
1260
4.18k
  declare_integer("reserved");
1261
1262
  // Segments and nested sections
1263
4.18k
  declare_integer("number_of_segments");
1264
1265
12.5k
  begin_struct_array("segments")
1266
4.18k
    declare_string("segname");
1267
4.18k
    declare_integer("vmaddr");
1268
4.18k
    declare_integer("vmsize");
1269
4.18k
    declare_integer("fileoff");
1270
4.18k
    declare_integer("fsize");
1271
4.18k
    declare_integer("maxprot");
1272
4.18k
    declare_integer("initprot");
1273
4.18k
    declare_integer("nsects");
1274
4.18k
    declare_integer("flags");
1275
12.5k
    begin_struct_array("sections")
1276
4.18k
      declare_string("sectname");
1277
4.18k
      declare_string("segname");
1278
4.18k
      declare_integer("addr");
1279
4.18k
      declare_integer("size");
1280
4.18k
      declare_integer("offset");
1281
4.18k
      declare_integer("align");
1282
4.18k
      declare_integer("reloff");
1283
4.18k
      declare_integer("nreloc");
1284
4.18k
      declare_integer("flags");
1285
4.18k
      declare_integer("reserved1");
1286
4.18k
      declare_integer("reserved2");
1287
4.18k
      declare_integer("reserved3");
1288
8.36k
    end_struct_array("sections");
1289
8.36k
  end_struct_array("segments")
1290
1291
  // Entry point and stack size
1292
4.18k
  declare_integer("entry_point");
1293
4.18k
  declare_integer("stack_size");
1294
1295
  // Mach-O fat binary header
1296
4.18k
  declare_integer("fat_magic");
1297
4.18k
  declare_integer("nfat_arch");
1298
1299
12.5k
  begin_struct_array("fat_arch")
1300
4.18k
    declare_integer("cputype");
1301
4.18k
    declare_integer("cpusubtype");
1302
4.18k
    declare_integer("offset");
1303
4.18k
    declare_integer("size");
1304
4.18k
    declare_integer("align");
1305
8.36k
  end_struct_array("fat_arch")
1306
1307
  // Included Mach-O files (must be same as single file structure above)
1308
12.5k
  begin_struct_array("file")
1309
1310
    // Single file header
1311
4.18k
    declare_integer("magic");
1312
4.18k
    declare_integer("cputype");
1313
4.18k
    declare_integer("cpusubtype");
1314
4.18k
    declare_integer("filetype");
1315
4.18k
    declare_integer("ncmds");
1316
4.18k
    declare_integer("sizeofcmds");
1317
4.18k
    declare_integer("flags");
1318
4.18k
    declare_integer("reserved");
1319
1320
    // Segments and nested sections
1321
4.18k
    declare_integer("number_of_segments");
1322
1323
12.5k
    begin_struct_array("segments")
1324
4.18k
      declare_string("segname");
1325
4.18k
      declare_integer("vmaddr");
1326
4.18k
      declare_integer("vmsize");
1327
4.18k
      declare_integer("fileoff");
1328
4.18k
      declare_integer("fsize");
1329
4.18k
      declare_integer("maxprot");
1330
4.18k
      declare_integer("initprot");
1331
4.18k
      declare_integer("nsects");
1332
4.18k
      declare_integer("flags");
1333
12.5k
      begin_struct_array("sections")
1334
4.18k
        declare_string("sectname");
1335
4.18k
        declare_string("segname");
1336
4.18k
        declare_integer("addr");
1337
4.18k
        declare_integer("size");
1338
4.18k
        declare_integer("offset");
1339
4.18k
        declare_integer("align");
1340
4.18k
        declare_integer("reloff");
1341
4.18k
        declare_integer("nreloc");
1342
4.18k
        declare_integer("flags");
1343
4.18k
        declare_integer("reserved1");
1344
4.18k
        declare_integer("reserved2");
1345
4.18k
        declare_integer("reserved3");
1346
8.36k
      end_struct_array("sections");
1347
8.36k
    end_struct_array("segments")
1348
1349
    // Entry point and stack size
1350
4.18k
    declare_integer("entry_point");
1351
4.18k
    declare_integer("stack_size");
1352
1353
8.36k
  end_struct_array("file");
1354
1355
  // Mach-O fat binary helper functions
1356
8.36k
  declare_function("file_index_for_arch", "i", "i", file_index_type);
1357
4.18k
  declare_function("file_index_for_arch", "ii", "i", file_index_subtype);
1358
4.18k
  declare_function("entry_point_for_arch", "i", "i", ep_for_arch_type);
1359
4.18k
  declare_function("entry_point_for_arch", "ii", "i", ep_for_arch_subtype);
1360
4.18k
end_declarations
1361
1362
int module_initialize(YR_MODULE* module)
1363
11
{
1364
11
  return ERROR_SUCCESS;
1365
11
}
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
4.17k
{
1378
4.17k
  YR_MEMORY_BLOCK* block;
1379
4.17k
  YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator;
1380
1381
4.17k
  foreach_memory_block(iterator, block)
1382
4.17k
  {
1383
4.17k
    const uint8_t* block_data = yr_fetch_block_data(block);
1384
1385
4.17k
    if (block_data == NULL || block->size < 4)
1386
22
      continue;
1387
1388
    // Parse Mach-O binary.
1389
4.15k
    if (is_macho_file_block((uint32_t*) block_data))
1390
1.23k
    {
1391
1.23k
      macho_parse_file(
1392
1.23k
          block_data, block->size, block->base, module_object, context);
1393
1.23k
      break;
1394
1.23k
    }
1395
1396
    // Parse fat Mach-O binary.
1397
2.91k
    if (is_fat_macho_file_block((uint32_t*) block_data))
1398
1.18k
    {
1399
1.18k
      macho_parse_fat_file(
1400
1.18k
          block_data, block->size, block->base, module_object, context);
1401
1.18k
      break;
1402
1.18k
    }
1403
2.91k
  }
1404
1405
4.17k
  macho_set_definitions(module_object);
1406
4.17k
  return ERROR_SUCCESS;
1407
4.17k
}
1408
1409
int module_unload(YR_OBJECT* module_object)
1410
4.17k
{
1411
4.17k
  return ERROR_SUCCESS;
1412
4.17k
}