Skip to content

Commit

Permalink
Fix issue VirusTotal#1317.
Browse files Browse the repository at this point in the history
  • Loading branch information
plusvic committed Jul 8, 2020
1 parent d4617ee commit a07fae7
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 21 deletions.
61 changes: 40 additions & 21 deletions libyara/modules/macho/macho.c
@@ -1,4 +1,4 @@
/*
/*
Copyright (c) 2014. The YARA Authors. All Rights Reserved.
Redistribution and use in source and binary forms, with or without modification,
Expand Down Expand Up @@ -80,23 +80,26 @@ int is_fat_macho_file_block(


// Check if file is 32-bit fat file.

int macho_fat_is_32(
const uint8_t* magic)
{
// Magic must be CAFEBA[BE].
return magic[3] == 0xbe;
}

static int should_swap_bytes(const uint32_t magic)

static int should_swap_bytes(
const uint32_t magic)
{
return magic == MH_CIGAM
|| magic == MH_CIGAM_64
|| magic == FAT_CIGAM
|| magic == FAT_CIGAM_64;
}

static void swap_mach_header(yr_mach_header_32_t *mh)

static void swap_mach_header(
yr_mach_header_64_t *mh)
{
// Don't swap the magic number so we can tell if swapping is needed
mh->cputype = yr_bswap32(mh->cputype);
Expand All @@ -105,14 +108,19 @@ static void swap_mach_header(yr_mach_header_32_t *mh)
mh->ncmds = yr_bswap32(mh->ncmds);
mh->sizeofcmds = yr_bswap32(mh->sizeofcmds);
mh->flags = yr_bswap32(mh->flags);

if (!macho_is_32((const uint8_t*) &mh->magic))
mh->reserved = yr_bswap32(mh->reserved);
}


static void swap_load_command(yr_load_command_t *lc)
{
lc->cmd = yr_bswap32(lc->cmd);
lc->cmdsize = yr_bswap32(lc->cmdsize);
}


static void swap_segment_command(yr_segment_command_32_t *sg)
{
sg->cmd = yr_bswap32(sg->cmd);
Expand All @@ -127,6 +135,7 @@ static void swap_segment_command(yr_segment_command_32_t *sg)
sg->flags = yr_bswap32(sg->flags);
}


static void swap_segment_command_64(yr_segment_command_64_t *sg)
{
sg->cmd = yr_bswap32(sg->cmd);
Expand All @@ -141,6 +150,7 @@ static void swap_segment_command_64(yr_segment_command_64_t *sg)
sg->flags = yr_bswap32(sg->flags);
}


static void swap_section(yr_section_32_t *sec)
{
sec->addr = yr_bswap32(sec->addr);
Expand All @@ -154,6 +164,7 @@ static void swap_section(yr_section_32_t *sec)
sec->reserved2 = yr_bswap32(sec->reserved2);
}


static void swap_section_64(yr_section_64_t *sec)
{
sec->addr = yr_bswap64(sec->addr);
Expand All @@ -168,6 +179,7 @@ static void swap_section_64(yr_section_64_t *sec)
sec->reserved3 = yr_bswap32(sec->reserved3);
}


static void swap_entry_point_command(yr_entry_point_command_t* ep_command)
{
ep_command->cmd = yr_bswap32(ep_command->cmd);
Expand Down Expand Up @@ -525,18 +537,22 @@ void macho_parse_file(
YR_OBJECT* object,
YR_SCAN_CONTEXT* context)
{
size_t header_size = sizeof(yr_mach_header_64_t);

if (macho_is_32(data))
header_size = sizeof(yr_mach_header_32_t);
size_t header_size = macho_is_32(data)?
sizeof(yr_mach_header_32_t):
sizeof(yr_mach_header_64_t);

if (size < header_size)
return;

yr_mach_header_32_t header;
memcpy(&header, data, sizeof(yr_mach_header_32_t));
// yr_mach_header_64_t is used for storing the header for both for 32-bits and
// 64-bits files. yr_mach_header_64_t is exactly like yr_mach_header_32_t
// but with an extra "reserved" field at the end.
yr_mach_header_64_t header;

memcpy(&header, data, header_size);

int should_swap = should_swap_bytes(header.magic);

if (should_swap)
swap_mach_header(&header);

Expand All @@ -548,22 +564,22 @@ void macho_parse_file(
set_integer(header.sizeofcmds, object, "sizeofcmds");
set_integer(header.flags, object, "flags");

// The "reserved" field exists only in 64 bits files.
if (!macho_is_32(data))
{
yr_mach_header_64_t* header64 = (yr_mach_header_64_t*)data;
if (should_swap)
header64->reserved = yr_bswap32(header64->reserved);
set_integer(header64->reserved, object, "reserved");
}
set_integer(header.reserved, object, "reserved");

/* The first command parsing pass handles only segments. */
// The first command parsing pass handles only segments.
uint64_t seg_count = 0;
uint64_t parsed_size = header_size;

uint8_t *command = (uint8_t*)(data + header_size);

yr_load_command_t command_struct;

for (unsigned i = 0; i < header.ncmds; i++)
{
memcpy(&command_struct, command, sizeof(yr_load_command_t));

if (should_swap)
swap_load_command(&command_struct);

Expand All @@ -590,12 +606,14 @@ void macho_parse_file(

set_integer(seg_count, object, "number_of_segments");

/* The second command parsing pass handles others, who use segment count */
// The second command parsing pass handles others, who use segment count.
parsed_size = header_size;
command = (uint8_t*)(data + header_size);

for (unsigned i = 0; i < header.ncmds; i++)
{
memcpy(&command_struct, command, sizeof(yr_load_command_t));

if (should_swap)
swap_load_command(&command_struct);

Expand Down Expand Up @@ -670,7 +688,7 @@ void macho_parse_fat_file(

/* All data in Mach-O fat binary headers are in big-endian byte order. */

const yr_fat_header_t* header = (yr_fat_header_t*)data;
const yr_fat_header_t* header = (yr_fat_header_t*) data;
set_integer(yr_be32toh(header->magic), object, "fat_magic");

uint32_t count = yr_be32toh(header->nfat_arch);
Expand All @@ -680,6 +698,7 @@ void macho_parse_fat_file(
return;

yr_fat_arch_64_t arch;

for (uint32_t i = 0; i < count; i++)
{
macho_load_fat_arch_header(data, size, i, &arch);
Expand Down Expand Up @@ -1337,14 +1356,14 @@ int module_load(
continue;

// Parse Mach-O binary.
if (is_macho_file_block((uint32_t*)block_data))
if (is_macho_file_block((uint32_t*) block_data))
{
macho_parse_file(block_data, block->size, module_object, context);
break;
}

// Parse fat Mach-O binary.
if (is_fat_macho_file_block((uint32_t*)block_data))
if (is_fat_macho_file_block((uint32_t*) block_data))
{
macho_parse_fat_file(block_data, block->size, module_object, context);
break;
Expand Down
Binary file not shown.

0 comments on commit a07fae7

Please sign in to comment.