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

aCaB acab at clamav.net
Sun Apr 4 01:13:47 UTC 2010


The following commit has been merged in the debian/unstable branch:
commit 853101585e6f79e673e15db85d278a78ed3a3b89
Author: aCaB <acab at clamav.net>
Date:   Tue Jan 5 01:01:48 2010 +0100

    versioninfo parser reworked

diff --git a/libclamav/pe.c b/libclamav/pe.c
index c274e60..19771b9 100644
--- a/libclamav/pe.c
+++ b/libclamav/pe.c
@@ -193,10 +193,18 @@ static void cli_multifree(void *f, ...) {
     va_end(ap);
 }
 
-int versioninfo(void *opaque, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva) {
-    uint32_t *rvas = (uint32_t *)opaque;
-    cli_errmsg("type: %x, name: %x, lang: %x, rva: %x\n", type, name, lang, rva);
-    *rvas = rva;
+struct vinfo_list {
+    uint32_t rvas[16];
+    unsigned int count;
+};
+
+int versioninfo_cb(void *opaque, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva) {
+    struct vinfo_list *vlist = (struct vinfo_list *)opaque;
+
+    cli_errmsg("versioninfo_cb: type: %x, name: %x, lang: %x, rva: %x\n", type, name, lang, rva);
+    vlist->rvas[vlist->count] = rva;
+    if(++vlist->count == sizeof(vlist->rvas) / sizeof(vlist->rvas[0]))
+	return 1;
     return 0;
 }
 
@@ -2405,141 +2413,170 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo)
 	return -1;
     }
 
-    if(cli_hashset_init(peinfo->vinfo, 32, 80)) {
-	cli_errmsg("Unable to init vinfo hs\n");
-	free(section_hdr);
-	free(peinfo->section);
-	peinfo->section = NULL;
-	return -1;
-    }
-
-    if(dirs[2].Size) {
-    	uint32_t rvas, res_sz;
+    while(dirs[2].Size) {
+	struct vinfo_list vlist;
 	uint8_t *vptr, *baseptr;
+    	uint32_t rva, res_sz;
+	unsigned int i;
+
+	memset(&vlist, 0, sizeof(vlist));
+    	findres(0x10, 0xffffffff, EC32(dirs[2].VirtualAddress), map, peinfo->section, peinfo->nsections, hdr_size, versioninfo_cb, &vlist);
+	if(!vlist.count) break; /* No version_information */
+	if(cli_hashset_init(peinfo->vinfo, 32, 80)) {
+	    cli_errmsg("cli_peheader: Unable to init vinfo hashset\n");
+	    free(section_hdr);
+	    free(peinfo->section);
+	    peinfo->section = NULL;
+	    return -1;
+	}
 
-    	findres(0x10, 0xffffffff, EC32(dirs[2].VirtualAddress), map, peinfo->section, peinfo->nsections, hdr_size, versioninfo, &rvas);
-	rvas = cli_rawaddr(rvas, peinfo->section, peinfo->nsections, &err, fsize, hdr_size); /* FIXME: this shall be an array */
-	vptr = fmap_need_off_once(map, rvas, 16); /* FIXME: check for failure */
-	baseptr = vptr - rvas;
-	rvas = cli_readint32(vptr);
-	res_sz = cli_readint32(vptr+4);
-	rvas = cli_rawaddr(rvas, peinfo->section, peinfo->nsections, &err, fsize, hdr_size); /* FIXME: check for failure */
-	vptr = fmap_need_off_once(map, rvas, res_sz); /* FIXME: check for failure */
-
-	while(res_sz>4) { /* look for versioninfo */
-	    uint32_t vinfo_sz, vinfo_val_sz;
-
-	    vinfo_sz = vinfo_val_sz = cli_readint32(vptr);
-	    vinfo_sz &= 0xffff;
-	    if(vinfo_sz > res_sz) {
-		/* the content is larger than the container */
-		break; /* this is a hard fail */
-	    }
-	    vinfo_val_sz >>= 16;
-	    if(vinfo_sz <= 6 + 0x22 + 0x34 ||
-	       vinfo_val_sz != 0x34 || 
-	       memcmp(vptr+6, "V\0S\0_\0V\0E\0R\0S\0I\0O\0N\0_\0I\0N\0F\0O\0\0\0", 0x20) ||
-	       cli_readint32(vptr + 0x28) != 0xfeef04bd) {
-		/* - there should be enough room for the header(6), the key "VS_VERSION_INFO"(20), the padding(2) and the value(34)
-		 * - the value should be sizeof(fixedfileinfo)
-		 * - the key should match
-		 * - there should be some proper magic for fixedfileinfo */
-		vptr += vinfo_sz;
-		res_sz -= vinfo_sz;
-		continue; /* this is a soft fail - FIXME: is there anything else we can find here? */
-	    }
-
-	    /* move to the end of fixedfileinfo where the child elements are located */
-	    vptr += 6 + 0x20 + 2 + 0x34;
-	    vinfo_sz -= 6 + 0x20 + 2 + 0x34;
+	err = 0;
+	for(i=0; i<vlist.count; i++) { /* enum all version_information res - RESUMABLE */
+	    cli_dbgmsg("cli_peheader: parsing version info @ rva %x\n", vlist.rvas[i]);
+	    rva = cli_rawaddr(vlist.rvas[i], peinfo->section, peinfo->nsections, &err, fsize, hdr_size);
+	    if(err)
+		continue;
 
-	    while(vinfo_sz > 6) { /* look for stringfileinfo */
-		uint32_t sfi_sz = cli_readint32(vptr) & 0xffff;
+	    if(!(vptr = fmap_need_off_once(map, rva, 16)))
+		continue;
 
-		if(sfi_sz > vinfo_sz) {
-		    res_sz = 0;
-		    break; /* this is a hard fail */
-		}
-		if(sfi_sz <= 6 + 0x1e || memcmp(vptr+6, "S\0t\0r\0i\0n\0g\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0", 0x1e)) {
-		    /* - there should be enough room for the header(6) and the key "StringFileInfo"(1e)
-		     * - the key should match */
-		    vptr += sfi_sz;
-		    vinfo_sz -= sfi_sz;
-		    continue; /* this is a soft fail - FIXME: we might only find VarFileInfo, and at most ONCE */
+	    baseptr = vptr - rva;
+	    /* parse resource */
+	    rva = cli_readint32(vptr); /* ptr to version_info */
+	    res_sz = cli_readint32(vptr+4); /* sizeof(resource) */
+	    rva = cli_rawaddr(rva, peinfo->section, peinfo->nsections, &err, fsize, hdr_size);
+	    if(err)
+		continue;
+	    if(!(vptr = fmap_need_off_once(map, rva, res_sz)))
+		continue;
+	    
+	    while(res_sz>4) { /* look for version_info - NOT RESUMABLE (expecting exactly one versioninfo) */
+		uint32_t vinfo_sz, vinfo_val_sz;
+
+		vinfo_sz = vinfo_val_sz = cli_readint32(vptr);
+		vinfo_sz &= 0xffff;
+		if(vinfo_sz > res_sz)
+		    break; /* the content is larger than the container */
+
+		vinfo_val_sz >>= 16;
+		if(vinfo_sz <= 6 + 0x20 + 2 + 0x34 ||
+		   vinfo_val_sz != 0x34 || 
+		   memcmp(vptr+6, "V\0S\0_\0V\0E\0R\0S\0I\0O\0N\0_\0I\0N\0F\0O\0\0\0", 0x20) ||
+		   cli_readint32(vptr + 0x28) != 0xfeef04bd) {
+		    /* - there should be enough room for the header(6), the key "VS_VERSION_INFO"(20), the padding(2) and the value(34)
+		     * - the value should be sizeof(fixedfileinfo)
+		     * - the key should match
+		     * - there should be some proper magic for fixedfileinfo */
+		    break; /* there's no point in looking further */
 		}
 
-		/* move to the end of stringfileinfo where the child elements are located */
-		vptr += 6 + 0x1e;
-		sfi_sz -= 6 + 0x1e;
+		/* move to the end of fixedfileinfo where the child elements are located */
+		vptr += 6 + 0x20 + 2 + 0x34;
+		vinfo_sz -= 6 + 0x20 + 2 + 0x34;
+
+		while(vinfo_sz > 6) { /* look for stringfileinfo - NOT RESUMABLE (expecting at most one stringfileinfo) */
+		    uint32_t sfi_sz = cli_readint32(vptr) & 0xffff;
 
-		while(sfi_sz > 6) { /* look for stringtable */
-		    uint32_t st_sz = cli_readint32(vptr) & 0xffff;
+		    if(sfi_sz > vinfo_sz)
+			break; /* the content is larger than the container */
 
-		    if(st_sz > sfi_sz || st_sz <= 24) {
-			/* - the content is larger than the container
-			   - there's no room for a stringtables (headers(6) + key(16) + padding(2)) */
-			res_sz = 0;
-			vinfo_sz = 0;
-			break; /* this is a hard fail */
+		    /* expecting stringfileinfo to always precede varfileinfo */
+		    if(sfi_sz <= 6 + 0x1e || memcmp(vptr+6, "S\0t\0r\0i\0n\0g\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0", 0x1e)) {
+			/* - there should be enough room for the header(6) and the key "StringFileInfo"(1e)
+			 * - the key should match */
+			break; /* this is an implicit hard fail: parent is not resumable */
 		    }
 
-		    /* move to the end of stringtable where the child elements are located */
-		    vptr += 24;
-		    st_sz -= 24;
+		    /* move to the end of stringfileinfo where the child elements are located */
+		    vptr += 6 + 0x1e;
+		    sfi_sz -= 6 + 0x1e;
 
-		    while(st_sz > 6) {  /* look for string */
-			uint32_t s_sz, s_key_sz, s_val_sz;
-			char *k, *v;
+		    while(sfi_sz > 6) { /* enum all stringtables - RESUMABLE */
+			uint32_t st_sz = cli_readint32(vptr) & 0xffff;
 
-			s_sz = s_val_sz = cli_readint32(vptr);
-			s_sz &= 0xffff;
-			s_val_sz = (s_val_sz & 0xffff0000)>>15;
-			if(s_sz > st_sz || s_sz <= 6 + 2 + 2 || s_val_sz > s_sz - 6 - 2 - 2) {
+			if(st_sz > sfi_sz || st_sz <= 24) {
 			    /* - the content is larger than the container
-			     * - there's no room for a minimal string (headers(6) + key(2) + padding(2))
-			     * - there's no room for the value */
-			    res_sz = 0;
-			    vinfo_sz = 0;
-			    sfi_sz = 0;
-			    break; /* this is a hard fail */
+			       - there's no room for a stringtables (headers(6) + key(16) + padding(2)) */
+			    break; /* this is an implicit hard fail: parent is not resumable */
 			}
 
-			if(!s_val_sz) {
-			    /* value unset */
-			    vptr += s_sz;
-			    st_sz -= s_sz;
-			    continue;
-			}
-			for(s_key_sz = 0; s_key_sz < s_sz - 6 - s_val_sz; s_key_sz += 2) {
-			    if(vptr[6+s_key_sz] || vptr[6+s_key_sz+1]) continue;
-			    s_key_sz += 2;
-			    break;
-			}
-			if(s_key_sz >= s_sz - 6 - s_val_sz) {
-			    /* key overflow */
+			/* move to the end of stringtable where the child elements are located */
+			vptr += 24;
+			st_sz -= 24;
+
+			while(st_sz > 6) {  /* enum all strings - RESUMABLE */
+			    uint32_t s_sz, s_key_sz, s_val_sz;
+			    char *k, *v;
+
+			    s_sz = s_val_sz = cli_readint32(vptr);
+			    s_sz &= 0xffff;
+			    s_val_sz = (s_val_sz & 0xffff0000)>>15;
+			    if(s_sz > st_sz || s_sz <= 6 + 2 + 2 || s_val_sz > s_sz - 6 - 2 - 2) {
+				/* - the content is larger than the container
+				 * - there's no room for a minimal string (headers(6) + key(2) + padding(2))
+				 * - there's no room for the value */
+				st_sz = 0;
+				sfi_sz = 0;
+				break; /* force a hard fail */
+			    }
+
+			    if(!s_val_sz) {
+				/* skip unset value */
+				vptr += s_sz;
+				st_sz -= s_sz;
+				continue;
+			    }
+
+			    /* ~wcstrlen(key) */
+			    for(s_key_sz = 0; s_key_sz < s_sz - 6 - s_val_sz; s_key_sz += 2) {
+				if(vptr[6+s_key_sz] || vptr[6+s_key_sz+1]) continue;
+				s_key_sz += 2;
+				break;
+			    }
+			    if(s_key_sz >= s_sz - 6 - s_val_sz) {
+				/* key overflow */
+				vptr += s_sz;
+				st_sz -= s_sz;
+				continue;
+			    }
+
+			    if(cli_hashset_addkey(peinfo->vinfo, (uint32_t)(vptr - baseptr + 6))) {
+				cli_errmsg("cli_peheader: Unable to add rva to vinfo hashset\n");
+				cli_hashset_destroy(peinfo->vinfo);
+				free(section_hdr);
+				free(peinfo->section);
+				peinfo->section = NULL;
+				return -1;
+			    }
+
+			    cli_errmsg("ADD %x\n", (uint32_t)(vptr - baseptr + 6));
+			    if(cli_debug_flag) {
+				/* FIXME: pretty print an usable VI-sig */
+				k = cli_utf16toascii(vptr + 6, s_key_sz);
+				if(k) {
+				    s_key_sz += 6 + 3;
+				    s_key_sz &= ~3;
+				    v = cli_utf16toascii(vptr + s_key_sz, s_val_sz);
+				    if(v) {
+					cli_errmsg("VersionInfo: '%s' = '%s'\n", k, v);
+					free(v);
+				    }
+				    free(k);
+				}
+			    }
 			    vptr += s_sz;
 			    st_sz -= s_sz;
-			    continue;
-			}
-			cli_hashset_addkey(peinfo->vinfo, (uint32_t)(vptr - baseptr + 6));
-			cli_errmsg("ADD %x\n", (uint32_t)(vptr - baseptr + 6));
-			k = cli_utf16toascii(vptr + 6, s_key_sz);
-			s_key_sz += 6 + 3;
-			s_key_sz &= ~3;
-			v = cli_utf16toascii(vptr + s_key_sz, s_val_sz);
-			if(v) {
-			    cli_errmsg("%x - %s=%s\n", s_key_sz, k, v);
-			    free(v);
-			}
-			vptr += s_sz;
-			st_sz -= s_sz;
-		    }
-		    /* FIXME: resmue here */
-		}
-	    }
-	}
-    }
-
+			} /* enum all strings - RESUMABLE */
+			vptr += st_sz;
+			sfi_sz -= st_sz;
+		    } /* enum all stringtables - RESUMABLE */
+		    break;
+		} /* look for stringfileinfo - NOT RESUMABLE */
+		break;
+	    } /* look for version_info - NOT RESUMABLE */
+	} /* enum all version_information res - RESUMABLE */
+	break;
+    } /* while(dirs[2].Size) */
 
     free(section_hdr);
     return 0;

-- 
Debian repository for ClamAV



More information about the Pkg-clamav-commits mailing list