libclamav: handle Mach-O files with type-9 signatures;

all special offsets are supported for PPC32/64 and x86 executables; for ARM and other archs only section based extensions (Sx[+-]n, SL[+-]n) are supported atm
0.96
Tomasz Kojm 16 years ago
parent 001b408e25
commit 8af7ccd0af
  1. 6
      ChangeLog
  2. 60
      libclamav/macho.c
  3. 4
      libclamav/macho.h
  4. 4
      libclamav/matcher.c
  5. 5
      libclamav/matcher.h
  6. 2
      libclamav/readdb.c
  7. 2
      libclamav/scanners.c

@ -1,3 +1,9 @@
Mon Jul 13 21:24:05 CEST 2009 (tk)
----------------------------------
* libclamav: handle Mach-O files with type-9 signatures; all special offsets are
supported for PPC32/64 and x86 executables; for ARM and other archs
only section based extensions (Sx[+-]n, SL[+-]n) are supported atm
Mon Jul 13 19:34:36 EEST 2009 (edwin)
-------------------------------------
* clambc/, libclamav/, unit_tests/: Initial draft of bytecode interpreter (bb #1243).

@ -18,10 +18,6 @@
* MA 02110-1301, USA.
*/
/* TODO:
* - integrate with the matcher
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@ -158,6 +154,8 @@ struct macho_thread_state_x86
};
#define RETURN_BROKEN \
if(matcher) \
return -1; \
if(DETECT_BROKEN) { \
if(ctx->virname) \
*ctx->virname = "Broken.Executable"; \
@ -186,7 +184,7 @@ static uint32_t cli_rawaddr(uint32_t vaddr, struct cli_exe_section *sects, uint1
return vaddr - sects[i].rva + sects[i].raw;
}
int cli_scanmacho(int fd, cli_ctx *ctx)
int cli_scanmacho(int fd, cli_ctx *ctx, struct cli_exe_info *fileinfo)
{
struct macho_hdr hdr;
struct macho_load_cmd load_cmd;
@ -194,14 +192,17 @@ int cli_scanmacho(int fd, cli_ctx *ctx)
struct macho_segment_cmd64 segment_cmd64;
struct macho_section section;
struct macho_section64 section64;
unsigned int i, j, sect = 0, conv, m64, nsects;
unsigned int i, j, sect = 0, conv, m64, nsects, matcher = 0;
unsigned int arch = 0, ep = 0, err;
struct cli_exe_section *sections = NULL;
char name[16];
if(fileinfo)
matcher = 1;
if(read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
cli_dbgmsg("cli_scanmacho: Can't read header\n");
return CL_EFORMAT;
return matcher ? -1 : CL_EFORMAT;
}
if(hdr.magic == 0xfeedface) {
@ -218,37 +219,44 @@ int cli_scanmacho(int fd, cli_ctx *ctx)
m64 = 1;
} else {
cli_dbgmsg("cli_scanmacho: Incorrect magic\n");
return CL_EFORMAT;
return matcher ? -1 : CL_EFORMAT;
}
switch(EC32(hdr.cpu_type, conv)) {
case 7:
if(!matcher)
cli_dbgmsg("MACHO: CPU Type: Intel 32-bit\n");
arch = 1;
break;
case 7 | 0x1000000:
if(!matcher)
cli_dbgmsg("MACHO: CPU Type: Intel 64-bit\n");
break;
case 12:
if(!matcher)
cli_dbgmsg("MACHO: CPU Type: ARM\n");
break;
case 14:
if(!matcher)
cli_dbgmsg("MACHO: CPU Type: SPARC\n");
break;
case 18:
if(!matcher)
cli_dbgmsg("MACHO: CPU Type: POWERPC 32-bit\n");
arch = 2;
break;
case 18 | 0x1000000:
if(!matcher)
cli_dbgmsg("MACHO: CPU Type: POWERPC 64-bit\n");
arch = 3;
break;
default:
if(!matcher)
cli_dbgmsg("MACHO: CPU Type: ** UNKNOWN ** (%u)\n", EC32(hdr.cpu_type, conv));
break;
}
switch(EC32(hdr.filetype, conv)) {
if(!matcher) switch(EC32(hdr.filetype, conv)) {
case 0x1: /* MH_OBJECT */
cli_dbgmsg("MACHO: Filetype: Relocatable object file\n");
break;
@ -280,8 +288,10 @@ int cli_scanmacho(int fd, cli_ctx *ctx)
cli_dbgmsg("MACHO: Filetype: ** UNKNOWN ** (0x%x)\n", EC32(hdr.filetype, conv));
}
if(!matcher) {
cli_dbgmsg("MACHO: Number of load commands: %u\n", EC32(hdr.ncmds, conv));
cli_dbgmsg("MACHO: Size of load commands: %u\n", EC32(hdr.sizeofcmds, conv));
}
if(m64)
lseek(fd, 4, SEEK_CUR);
@ -324,22 +334,25 @@ int cli_scanmacho(int fd, cli_ctx *ctx)
nsects = EC32(segment_cmd.nsects, conv);
strncpy(name, segment_cmd.segname, 16);
}
if(!matcher) {
name[15] = 0;
cli_dbgmsg("MACHO: Segment name: %s\n", name);
cli_dbgmsg("MACHO: Number of sections: %u\n", nsects);
}
if(nsects > 255) {
cli_dbgmsg("cli_scanmacho: Invalid number of sections\n");
free(sections);
RETURN_BROKEN;
}
if(!nsects) {
if(!matcher)
cli_dbgmsg("MACHO: ------------------\n");
continue;
}
sections = (struct cli_exe_section *) cli_realloc2(sections, (sect + nsects) * sizeof(struct cli_exe_section));
if(!sections) {
cli_errmsg("cli_scanmacho: Can't allocate memory for 'sections'\n");
return CL_EMEM;
return matcher ? -1 : CL_EMEM;
}
for(j = 0; j < nsects; j++) {
@ -364,10 +377,11 @@ int cli_scanmacho(int fd, cli_ctx *ctx)
sections[sect].rva = EC32(section.addr, conv);
sections[sect].vsz = EC32(section.size, conv);
sections[sect].raw = EC32(section.offset, conv);
section64.align = EC32(section64.align, conv);
sections[sect].rsz = sections[sect].vsz + (section64.align - (sections[sect].vsz % section64.align)) % section64.align;
section.align = EC32(section.align, conv);
sections[sect].rsz = sections[sect].vsz + (section.align - (sections[sect].vsz % section.align)) % section.align;
strncpy(name, section.sectname, 16);
}
if(!matcher) {
name[15] = 0;
cli_dbgmsg("MACHO: --- Section %u ---\n", sect);
cli_dbgmsg("MACHO: Name: %s\n", name);
@ -376,8 +390,10 @@ int cli_scanmacho(int fd, cli_ctx *ctx)
cli_dbgmsg("MACHO: Raw size: %u\n", (unsigned int) sections[sect].rsz);
if(sections[sect].raw)
cli_dbgmsg("MACHO: File offset: %u\n", (unsigned int) sections[sect].raw);
}
sect++;
}
if(!matcher)
cli_dbgmsg("MACHO: ------------------\n");
} else if(arch && (load_cmd.cmd == 0x4 || load_cmd.cmd == 0x5)) { /* LC_(UNIX)THREAD */
@ -423,7 +439,7 @@ int cli_scanmacho(int fd, cli_ctx *ctx)
default:
cli_errmsg("cli_scanmacho: Invalid arch setting!\n");
free(sections);
return CL_EARG;
return matcher ? -1 : CL_EARG;
}
} else {
if(EC32(load_cmd.cmdsize, conv) > sizeof(load_cmd))
@ -432,18 +448,32 @@ int cli_scanmacho(int fd, cli_ctx *ctx)
}
if(ep) {
cli_dbgmsg("Entry Point: 0x%x (%u)\n", ep, ep);
if(!matcher)
cli_dbgmsg("Entry Point: 0x%x\n", ep);
if(sections) {
ep = cli_rawaddr(ep, sections, sect, &err);
if(err) {
cli_dbgmsg("cli_scanmacho: Can't calculate EP offset\n");
free(sections);
return CL_EFORMAT;
return matcher ? -1 : CL_EFORMAT;
}
if(!matcher)
cli_dbgmsg("Entry Point file offset: %u\n", ep);
}
}
if(matcher) {
fileinfo->ep = ep;
fileinfo->nsections = sect;
fileinfo->section = sections;
return 0;
} else {
free(sections);
return CL_SUCCESS;
}
}
int cli_machoheader(int fd, struct cli_exe_info *fileinfo)
{
return cli_scanmacho(fd, NULL, fileinfo);
}

@ -24,7 +24,7 @@
#include "others.h"
#include "execs.h"
int cli_scanmacho(int fd, cli_ctx *ctx);
int cli_machoheader(int fd, struct cli_exe_info *elfinfo);
int cli_scanmacho(int fd, cli_ctx *ctx, struct cli_exe_info *fileinfo);
int cli_machoheader(int fd, struct cli_exe_info *fileinfo);
#endif

@ -44,7 +44,7 @@
#include "str.h"
#include "cltypes.h"
#include "default.h"
#include "macho.h"
int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset, cli_ctx *ctx, cli_file_t ftype, struct cli_ac_data **acdata)
{
@ -131,6 +131,8 @@ off_t cli_caloff(const char *offstr, struct cli_target_info *info, int fd, cli_f
einfo = cli_peheader;
else if(ftype == CL_TYPE_ELF)
einfo = cli_elfheader;
else if(ftype == CL_TYPE_MACHO)
einfo = cli_machoheader;
if(einfo) {
if((pos = lseek(fd, 0, SEEK_CUR)) == -1) {

@ -104,7 +104,7 @@ struct cli_mtarget {
uint8_t ac_only;
};
#define CLI_MTARGETS 9
#define CLI_MTARGETS 10
static const struct cli_mtarget cli_mtargets[CLI_MTARGETS] = {
{ 0, "GENERIC", 0, 0 },
{ CL_TYPE_MSEXE, "PE", 1, 0 },
@ -114,7 +114,8 @@ static const struct cli_mtarget cli_mtargets[CLI_MTARGETS] = {
{ CL_TYPE_GRAPHICS, "GRAPHICS", 5, 1 },
{ CL_TYPE_ELF, "ELF", 6, 1 },
{ CL_TYPE_TEXT_ASCII, "ASCII", 7, 1 },
{ CL_TYPE_PE_DISASM, "DISASM", 8, 1 }
{ CL_TYPE_PE_DISASM, "DISASM", 8, 1 },
{ CL_TYPE_MACHO, "MACH-O", 9, 1 }
};
struct cli_target_info {

@ -532,7 +532,7 @@ static int cli_checkoffset(const char *offset, unsigned int type)
if(!strncmp(offset, "EOF-", 4))
return 0;
if((type == 1 || type == 6) && (!strncmp(offset, "EP+", 3) || !strncmp(offset, "EP-", 3) || (sscanf(offset, "SL+%u", &foo) == 1) || (sscanf(offset, "S%u+%u", &foo, &foo) == 2)))
if((type == 1 || type == 6 || type == 9) && (!strncmp(offset, "EP+", 3) || !strncmp(offset, "EP-", 3) || (sscanf(offset, "SL+%u", &foo) == 1) || (sscanf(offset, "S%u+%u", &foo, &foo) == 2)))
return 0;
return 1;

@ -2087,7 +2087,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
case CL_TYPE_MACHO:
if(ctx->dconf->macho)
ret = cli_scanmacho(desc, ctx);
ret = cli_scanmacho(desc, ctx, NULL);
break;
case CL_TYPE_SIS:

Loading…
Cancel
Save