[Pkg-clamav-commits] [SCM] Debian repository for ClamAV branch, debian/unstable, updated. debian/0.95+dfsg-1-6156-g094ec9b

Tomasz Kojm tkojm at clamav.net
Sun Apr 4 00:58:21 UTC 2010


The following commit has been merged in the debian/unstable branch:
commit 907ce30cae167d99e306193b9318f94c63bd186a
Author: Tomasz Kojm <tkojm at clamav.net>
Date:   Mon Jul 13 16:07:08 2009 +0200

    libclamav/macho.c: handle LC_THREAD; calculate EP

diff --git a/ChangeLog b/ChangeLog
index 2bb7156..c3dee83 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Mon Jul 13 16:06:31 CEST 2009 (tk)
+----------------------------------
+ * libclamav/macho.c: handle LC_THREAD; calculate EP
+
 Fri Jul 10 10:10:35 CEST 2009 (tk)
 ----------------------------------
  * libclamav/filetypes_int.h: sync with daily.ftm
diff --git a/libclamav/macho.c b/libclamav/macho.c
index 4791f36..c1a0cb4 100644
--- a/libclamav/macho.c
+++ b/libclamav/macho.c
@@ -19,13 +19,13 @@
  */
 
 /* TODO:
- *  - handle LC_THREAD
  *  - integrate with the matcher
  */
 
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -112,6 +112,80 @@ struct macho_section64
     uint32_t res2;
 };
 
+struct macho_thread_state_ppc
+{
+    uint32_t srr0; /* PC */
+    uint32_t srr1;
+    uint32_t reg[32];
+    uint32_t cr;
+    uint32_t xer;
+    uint32_t lr;
+    uint32_t ctr;
+    uint32_t mq;
+    uint32_t vrsave;
+};
+
+struct macho_thread_state_ppc64
+{
+    uint64_t srr0; /* PC */
+    uint64_t srr1;
+    uint64_t reg[32];
+    uint32_t cr;
+    uint64_t xer;
+    uint64_t lr;
+    uint64_t ctr;
+    uint32_t vrsave;
+};
+
+struct macho_thread_state_x86
+{
+    uint32_t eax;
+    uint32_t ebx;
+    uint32_t ecx;
+    uint32_t edx;
+    uint32_t edi;
+    uint32_t esi;
+    uint32_t ebp;
+    uint32_t esp;
+    uint32_t ss;
+    uint32_t eflags;
+    uint32_t eip;
+    uint32_t cs;
+    uint32_t ds;
+    uint32_t es;
+    uint32_t fs;
+    uint32_t gs;
+};
+
+#define RETURN_BROKEN					    \
+    if(DETECT_BROKEN) {					    \
+	if(ctx->virname)				    \
+	    *ctx->virname = "Broken.Executable";	    \
+	return cli_checkfp(fd, ctx) ? CL_CLEAN : CL_VIRUS;  \
+    }							    \
+    return CL_EFORMAT
+
+
+static uint32_t cli_rawaddr(uint32_t vaddr, struct cli_exe_section *sects, uint16_t nsects, unsigned int *err)
+{
+	unsigned int i, found = 0;
+
+    for(i = 0; i < nsects; i++) {
+	if(sects[i].rva <= vaddr && sects[i].rva + sects[i].vsz > vaddr) {
+	    found = 1;
+	    break;
+	}
+    }
+
+    if(!found) {
+	*err = 1;
+	return 0;
+    }
+
+    *err = 0;
+    return vaddr - sects[i].rva + sects[i].raw;
+}
+
 int cli_scanmacho(int fd, cli_ctx *ctx)
 {
 	struct macho_hdr hdr;
@@ -120,7 +194,9 @@ 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, vaddr, vsize, offset;
+	unsigned int i, j, sect = 0, conv, m64, nsects;
+	unsigned int arch = 0, ep = 0, err;
+	struct cli_exe_section *sections = NULL;
 	char name[16];
 
     if(read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
@@ -148,6 +224,7 @@ int cli_scanmacho(int fd, cli_ctx *ctx)
     switch(EC32(hdr.cpu_type, conv)) {
 	case 7:
 	    cli_dbgmsg("MACHO: CPU Type: Intel 32-bit\n");
+	    arch = 1;
 	    break;
 	case 7 | 0x1000000:
 	    cli_dbgmsg("MACHO: CPU Type: Intel 64-bit\n");
@@ -160,9 +237,11 @@ int cli_scanmacho(int fd, cli_ctx *ctx)
 	    break;
 	case 18:
 	    cli_dbgmsg("MACHO: CPU Type: POWERPC 32-bit\n");
+	    arch = 2;
 	    break;
 	case 18 | 0x1000000:
 	    cli_dbgmsg("MACHO: CPU Type: POWERPC 64-bit\n");
+	    arch = 3;
 	    break;
 	default:
 	    cli_dbgmsg("MACHO: CPU Type: ** UNKNOWN ** (%u)\n", EC32(hdr.cpu_type, conv));
@@ -204,52 +283,43 @@ int cli_scanmacho(int fd, cli_ctx *ctx)
     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 && EC32(load_cmd.cmdsize, conv) % 8) || (!m64 && EC32(load_cmd.cmdsize, conv) % 4)) {
-	cli_dbgmsg("cli_scanmacho: Invalid command size (%u)\n", EC32(load_cmd.cmdsize, conv));
-        if(DETECT_BROKEN) {
-	    if(ctx->virname)
-		*ctx->virname = "Broken.Executable";
-	    return cli_checkfp(fd, ctx) ? CL_CLEAN : CL_VIRUS;
-        }
-	return CL_EFORMAT;
-    }
-
     if(m64)
 	lseek(fd, 4, SEEK_CUR);
 
-    for(i = 0; i < EC32(hdr.ncmds, conv); i++) {
+    hdr.ncmds = EC32(hdr.ncmds, conv);
+    if(!hdr.ncmds || hdr.ncmds > 1024) {
+	cli_dbgmsg("cli_scanmacho: Invalid number of load commands (%u)\n", hdr.ncmds);
+	RETURN_BROKEN;
+    }
+
+    for(i = 0; i < hdr.ncmds; i++) {
 	if(read(fd, &load_cmd, sizeof(load_cmd)) != sizeof(load_cmd)) {
 	    cli_dbgmsg("cli_scanmacho: Can't read load command\n");
-	    if(DETECT_BROKEN) {
-		if(ctx->virname)
-		    *ctx->virname = "Broken.Executable";
-		return cli_checkfp(fd, ctx) ? CL_CLEAN : CL_VIRUS;
-	    }
-	    return CL_EFORMAT;
+	    free(sections);
+	    RETURN_BROKEN;
 	}
-
-	if((m64 && EC32(load_cmd.cmd, conv) == 0x19) || (!m64 && EC32(load_cmd.cmd, conv) == 0x01)) { /* LC_SEGMENT */
+	/*
+	if((m64 && EC32(load_cmd.cmdsize, conv) % 8) || (!m64 && EC32(load_cmd.cmdsize, conv) % 4)) {
+	    cli_dbgmsg("cli_scanmacho: Invalid command size (%u)\n", EC32(load_cmd.cmdsize, conv));
+	    free(sections);
+	    RETURN_BROKEN;
+	}
+	*/
+	load_cmd.cmd = EC32(load_cmd.cmd, conv);
+	if((m64 && load_cmd.cmd == 0x19) || (!m64 && load_cmd.cmd == 0x01)) { /* LC_SEGMENT */
 	    if(m64) {
 		if(read(fd, &segment_cmd64, sizeof(segment_cmd64)) != sizeof(segment_cmd64)) {
 		    cli_dbgmsg("cli_scanmacho: Can't read segment command\n");
-		    if(DETECT_BROKEN) {
-			if(ctx->virname)
-			    *ctx->virname = "Broken.Executable";
-			return cli_checkfp(fd, ctx) ? CL_CLEAN : CL_VIRUS;
-		    }
-		    return CL_EFORMAT;
+		    free(sections);
+		    RETURN_BROKEN;
 		}
 		nsects = EC32(segment_cmd64.nsects, conv);
 		strncpy(name, segment_cmd64.segname, 16);
 	    } else {
 		if(read(fd, &segment_cmd, sizeof(segment_cmd)) != sizeof(segment_cmd)) {
 		    cli_dbgmsg("cli_scanmacho: Can't read segment command\n");
-		    if(DETECT_BROKEN) {
-			if(ctx->virname)
-			    *ctx->virname = "Broken.Executable";
-			return cli_checkfp(fd, ctx) ? CL_CLEAN : CL_VIRUS;
-		    }
-		    return CL_EFORMAT;
+		    free(sections);
+		    RETURN_BROKEN;
 		}
 		nsects = EC32(segment_cmd.nsects, conv);
 		strncpy(name, segment_cmd.segname, 16);
@@ -257,136 +327,103 @@ int cli_scanmacho(int fd, cli_ctx *ctx)
 	    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) {
+		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;
+	    }
+
 	    for(j = 0; j < nsects; j++) {
 		if(m64) {
 		    if(read(fd, &section64, sizeof(section64)) != sizeof(section64)) {
 			cli_dbgmsg("cli_scanmacho: Can't read section\n");
-			if(DETECT_BROKEN) {
-			    if(ctx->virname)
-				*ctx->virname = "Broken.Executable";
-			    return cli_checkfp(fd, ctx) ? CL_CLEAN : CL_VIRUS;
-			}
-			return CL_EFORMAT;
+			free(sections);
+			RETURN_BROKEN;
 		    }
-		    vaddr = EC64(section64.addr, conv);
-		    vsize = EC64(section64.size, conv);
-		    offset = EC32(section64.offset, conv);
+		    sections[sect].rva = EC64(section64.addr, conv);
+		    sections[sect].vsz = EC64(section64.size, conv);
+		    sections[sect].raw = EC32(section64.offset, conv);
+		    section64.align = EC32(section64.align, conv);
+		    sections[sect].rsz = sections[sect].vsz + (section64.align - (sections[sect].vsz % section64.align)) % section64.align; /* most likely we can assume it's the same as .vsz */
 		    strncpy(name, section64.sectname, 16);
 		} else {
 		    if(read(fd, &section, sizeof(section)) != sizeof(section)) {
 			cli_dbgmsg("cli_scanmacho: Can't read section\n");
-			if(DETECT_BROKEN) {
-			    if(ctx->virname)
-				*ctx->virname = "Broken.Executable";
-			    return cli_checkfp(fd, ctx) ? CL_CLEAN : CL_VIRUS;
-			}
-			return CL_EFORMAT;
+			free(sections);
+			RETURN_BROKEN;
 		    }
-		    vaddr = EC32(section.addr, conv);
-		    vsize = EC32(section.size, conv);
-		    offset = EC32(section.offset, conv);
+		    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;
 		    strncpy(name, section.sectname, 16);
 		}
 		name[15] = 0;
 		cli_dbgmsg("MACHO: --- Section %u ---\n", sect);
 		cli_dbgmsg("MACHO: Name: %s\n", name);
-		cli_dbgmsg("MACHO: Virtual address: 0x%x\n", vaddr);
-		cli_dbgmsg("MACHO: Virtual size: %u\n", vsize);
-		if(offset)
-		    cli_dbgmsg("MACHO: File offset: %u\n", offset);
+		cli_dbgmsg("MACHO: Virtual address: 0x%x\n", (unsigned int) sections[sect].rva);
+		cli_dbgmsg("MACHO: Virtual size: %u\n", (unsigned int) sections[sect].vsz);
+		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++;
 	    }
 	    cli_dbgmsg("MACHO: ------------------\n");
-	} else {
-	    if(EC32(load_cmd.cmdsize, conv) > sizeof(load_cmd))
-		lseek(fd, EC32(load_cmd.cmdsize, conv) - sizeof(load_cmd), SEEK_CUR);
-	}
-    }
 
-    return CL_SUCCESS;
-}
-
-int cli_machoheader(int fd, struct cli_exe_info *elfinfo)
-{
-	struct macho_hdr hdr;
-	struct macho_load_cmd load_cmd;
-	struct macho_segment_cmd segment_cmd;
-	struct macho_segment_cmd64 segment_cmd64;
-	struct macho_section section;
-	struct macho_section64 section64;
-	unsigned int i, j, sect = 0, conv, m64, nsects, vaddr, vsize, offset;
-
-    cli_dbgmsg("in cli_machoheader()\n");
-
-    if(read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
-	cli_dbgmsg("cli_scanmacho: Can't read header\n");
-	return -1;
-    }
+	} else if(arch && (load_cmd.cmd == 0x4 || load_cmd.cmd == 0x5)) { /* LC_(UNIX)THREAD */
+	    lseek(fd, 8, SEEK_CUR);
+	    switch(arch) {
+		case 1: /* x86 */
+		{
+			struct macho_thread_state_x86 thread_state_x86;
 
-    if(hdr.magic == 0xfeedface) {
-	conv = 0;
-	m64 = 0;
-    } else if(hdr.magic == 0xcefaedfe) {
-	conv = 1;
-	m64 = 0;
-    } else if(hdr.magic == 0xfeedfacf) {
-	conv = 0;
-	m64 = 1;
-    } else if(hdr.magic == 0xcffaedfe) {
-	conv = 1;
-	m64 = 1;
-    } else {
-	cli_dbgmsg("cli_scanmacho: Incorrect magic\n");
-	return CL_EFORMAT;
-    }
+		    if(read(fd, &thread_state_x86, sizeof(thread_state_x86)) != sizeof(thread_state_x86)) {
+			cli_dbgmsg("cli_scanmacho: Can't read thread_state_x86\n");
+			free(sections);
+			RETURN_BROKEN;
+		    }
+		    break;
+		}
 
-    if((m64 && EC32(load_cmd.cmdsize, conv) % 8) || (!m64 && EC32(load_cmd.cmdsize, conv) % 4)) {
-	cli_dbgmsg("cli_scanmacho: Invalid command size (%u)\n", EC32(load_cmd.cmdsize, conv));
-	return -1;
-    }
+		case 2: /* PPC */
+		{
+			struct macho_thread_state_ppc thread_state_ppc;
 
-    if(m64)
-	lseek(fd, 4, SEEK_CUR);
+		    if(read(fd, &thread_state_ppc, sizeof(thread_state_ppc)) != sizeof(thread_state_ppc)) {
+			cli_dbgmsg("cli_scanmacho: Can't read thread_state_ppc\n");
+			free(sections);
+			RETURN_BROKEN;
+		    }
+		    ep = EC32(thread_state_ppc.srr0, conv);
+		    break;
+		}
 
-    for(i = 0; i < EC32(hdr.ncmds, conv); i++) {
-	if(read(fd, &load_cmd, sizeof(load_cmd)) != sizeof(load_cmd)) {
-	    cli_dbgmsg("cli_scanmacho: Can't read load command\n");
-	    return -1;
-	}
+		case 3: /* PPC64 */
+		{
+			struct macho_thread_state_ppc64 thread_state_ppc64;
 
-	if((m64 && EC32(load_cmd.cmd, conv) == 0x19) || (!m64 && EC32(load_cmd.cmd, conv) == 0x01)) { /* LC_SEGMENT */
-	    if(m64) {
-		if(read(fd, &segment_cmd64, sizeof(segment_cmd64)) != sizeof(segment_cmd64)) {
-		    cli_dbgmsg("cli_scanmacho: Can't read segment command\n");
-		    return -1;
-		}
-		nsects = EC32(segment_cmd64.nsects, conv);
-	    } else {
-		if(read(fd, &segment_cmd, sizeof(segment_cmd)) != sizeof(segment_cmd)) {
-		    cli_dbgmsg("cli_scanmacho: Can't read segment command\n");
-		    return -1;
-		}
-		nsects = EC32(segment_cmd.nsects, conv);
-	    }
-	    for(j = 0; j < nsects; j++) {
-		if(m64) {
-		    if(read(fd, &section64, sizeof(section64)) != sizeof(section64)) {
-			cli_dbgmsg("cli_scanmacho: Can't read section\n");
-			return -1;
-		    }
-		    vaddr = EC64(section64.addr, conv);
-		    vsize = EC64(section64.size, conv);
-		    offset = EC32(section64.offset, conv);
-		} else {
-		    if(read(fd, &section, sizeof(section)) != sizeof(section)) {
-			cli_dbgmsg("cli_scanmacho: Can't read section\n");
-			return -1;
+		    if(read(fd, &thread_state_ppc64, sizeof(thread_state_ppc64)) != sizeof(thread_state_ppc64)) {
+			cli_dbgmsg("cli_scanmacho: Can't read thread_state_ppc64\n");
+			free(sections);
+			RETURN_BROKEN;
 		    }
-		    vaddr = EC32(section.addr, conv);
-		    vsize = EC32(section.size, conv);
-		    offset = EC32(section.offset, conv);
+		    ep = EC64(thread_state_ppc64.srr0, conv);
+		    break;
 		}
-		sect++;
+		default:
+		    cli_errmsg("cli_scanmacho: Invalid arch setting!\n");
+		    free(sections);
+		    return CL_EARG;
 	    }
 	} else {
 	    if(EC32(load_cmd.cmdsize, conv) > sizeof(load_cmd))
@@ -394,5 +431,19 @@ int cli_machoheader(int fd, struct cli_exe_info *elfinfo)
 	}
     }
 
-    return 0;
+    if(ep) {
+	cli_dbgmsg("Entry Point: 0x%x (%u)\n", ep, 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;
+	    }
+	    cli_dbgmsg("Entry Point file offset: %u\n", ep);
+	}
+    }
+
+    free(sections);
+    return CL_SUCCESS;
 }

-- 
Debian repository for ClamAV



More information about the Pkg-clamav-commits mailing list