Browse code

bb#2221

aCaB authored on 2010/08/31 08:43:04
Showing 2 changed files
... ...
@@ -1,3 +1,8 @@
1
+Tue Aug 31 01:39:11 CEST 2010 (acab)
2
+------------------------------------
3
+ * libclamav/pe_icons.c: support special case where icon is encoded as 32bpp but it really
4
+			 carries alpha as a mask... well go figure. (bb#2221)
5
+
1 6
 Thu Aug 26 14:06:55 CEST 2010 (tk)
2 7
 ----------------------------------
3 8
  * libclamav/mpool.c: permanently disable debug mode (bb#2222)
... ...
@@ -47,7 +47,7 @@ struct GICONS {
47 47
 static int groupicon_cb(void *ptr, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva) {
48 48
     struct GICONS *gicons = ptr;
49 49
     type = type; lang = lang;
50
-    cli_dbgmsg("groupicon_cb: got group %u\n", name);
50
+    cli_dbgmsg("groupicon_cb: got group %x\n", name);
51 51
     if(!gicons->cnt || gicons->lastg == name) {
52 52
 	gicons->rvas[gicons->cnt] = rva;
53 53
 	gicons->cnt++;
... ...
@@ -66,7 +66,7 @@ struct ICONS {
66 66
 static int icon_cb(void *ptr, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva) {
67 67
     struct ICONS *icons = ptr;
68 68
     type = type; lang = lang;
69
-    cli_dbgmsg("icon_cb: got icon %u\n", name);
69
+    cli_dbgmsg("icon_cb: got icon %x\n", name);
70 70
     if(icons->cnt > 100) 
71 71
 	return 1;
72 72
     icons->rvas[icons->cnt] = rva;
... ...
@@ -103,7 +103,7 @@ int cli_scanicon(icon_groupset *set, uint32_t resdir_rva, cli_ctx *ctx, struct c
103 103
 		    uint32_t sz;
104 104
 		    uint16_t id;
105 105
 		} *dir;
106
-		
106
+
107 107
 		grp = fmap_need_off_once(map, cli_rawaddr(cli_readint32(grp), exe_sections, nsections, &err, map->len, hdr_size), gsz);
108 108
 		if(grp && !err) {
109 109
 		    icnt = cli_readint32(grp+2) >> 16;
... ...
@@ -1201,6 +1201,7 @@ static int parseicon(icon_groupset *set, uint32_t rva, cli_ctx *ctx, struct cli_
1201 1201
     fmap_t *map;
1202 1202
     uint32_t icoff;
1203 1203
     struct icon_matcher *matcher;
1204
+    unsigned int special_32_is_32 = 0;
1204 1205
 
1205 1206
     if(!ctx || !ctx->engine || !(matcher=ctx->engine->iconcheck))
1206 1207
 	return CL_SUCCESS;
... ...
@@ -1228,7 +1229,7 @@ static int parseicon(icon_groupset *set, uint32_t rva, cli_ctx *ctx, struct cli_
1228 1228
 
1229 1229
     /* seek to the end of v4/v5 header */
1230 1230
     icoff += EC32(bmphdr.sz);
1231
-	    
1231
+
1232 1232
     width = EC32(bmphdr.w);
1233 1233
     height = EC32(bmphdr.h) / 2;
1234 1234
     depth = EC16(bmphdr.depth);
... ...
@@ -1333,7 +1334,9 @@ static int parseicon(icon_groupset *set, uint32_t rva, cli_ctx *ctx, struct cli_
1333 1333
 	    break;
1334 1334
 	case 32:
1335 1335
 	    for(x=0; x<width; x++) {
1336
-		imagedata[(height - 1 - y) * width + x] = rawimage[x_off] | (rawimage[x_off + 1] << 8) | (rawimage[x_off + 2] << 16) | (rawimage[x_off + 3] << 24);
1336
+		unsigned int a = rawimage[x_off + 3] << 24;
1337
+		imagedata[(height - 1 - y) * width + x] = rawimage[x_off] | (rawimage[x_off + 1] << 8) | (rawimage[x_off + 2] << 16) | a;
1338
+		special_32_is_32 |= a;
1337 1339
 		x_off+=4;
1338 1340
 	    }
1339 1341
 	    break;
... ...
@@ -1343,10 +1346,23 @@ static int parseicon(icon_groupset *set, uint32_t rva, cli_ctx *ctx, struct cli_
1343 1343
     if(palette) fmap_unneed_ptr(map, palette, (1<<depth) * sizeof(int));
1344 1344
     makebmp("0-noalpha", tempd, width, height, imagedata);
1345 1345
 
1346
+    if(depth == 32 && !special_32_is_32) { /* Sometimes it really is 24. Exploited live - see sample 0013839101 */
1347
+	andlinesz = 4*(width / 32) + 4*(width % 32 != 0);
1348
+	if(!(rawimage = fmap_need_off_once(map, icoff + height * scanlinesz, height * andlinesz))) {
1349
+	    /* Likely a broken sample - 32bit icon with 24bit data and a broken mask:
1350
+	       i could really break out here but i've got the full image, so i'm just forcing full alpha */
1351
+	    for(y=0; y<height; y++)
1352
+		for(x=0; x<width; x++)
1353
+		    imagedata[y * width + x] |= 0xff000000;
1354
+	    special_32_is_32 = 0;
1355
+	    cli_dbgmsg("parseicon: found a broken and stupid icon\n");
1356
+	} else cli_dbgmsg("parseicon: found a stupid icon\n");
1357
+    } else rawimage += height * scanlinesz;
1358
+
1346 1359
     /* Set alpha on or off based on the mask */
1347
-    if(depth & 0x1f) {
1360
+    if((depth & 0x1f) || !special_32_is_32) {
1348 1361
 	for(y=0; y<height; y++) {
1349
-	    unsigned int x_off = height * scanlinesz + y * andlinesz;
1362
+	    unsigned int x_off = y * andlinesz;
1350 1363
 	    unsigned int have = 0;
1351 1364
 	    unsigned char c;
1352 1365
 	    for(x=0; x<width; x++) {