pe_icon: restructured icon callback to locate and scan in one pass

0.98.2
Kevin Lin 11 years ago
parent e33d8379c1
commit a47e693479
  1. 91
      libclamav/pe_icons.c

@ -32,6 +32,7 @@
#include "pe_icons.h" #include "pe_icons.h"
#include "others.h" #include "others.h"
#define PE_MAXICONS 100
#define READ32(x) cli_readint32(&(x)) #define READ32(x) cli_readint32(&(x))
#define READ16(x) cli_readint16(&(x)) #define READ16(x) cli_readint16(&(x))
@ -47,7 +48,7 @@
struct GICONS { struct GICONS {
unsigned int cnt; unsigned int cnt;
uint32_t lastg; uint32_t lastg;
uint32_t rvas[100]; uint32_t rvas[PE_MAXICONS];
}; };
static int groupicon_cb(void *ptr, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva) { static int groupicon_cb(void *ptr, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva) {
@ -58,47 +59,66 @@ static int groupicon_cb(void *ptr, uint32_t type, uint32_t name, uint32_t lang,
gicons->rvas[gicons->cnt] = rva; gicons->rvas[gicons->cnt] = rva;
gicons->cnt++; gicons->cnt++;
gicons->lastg = name; gicons->lastg = name;
if(gicons->cnt < 100) if(gicons->cnt < PE_MAXICONS)
return 0; return 0;
} }
return 1; return 1;
} }
struct ICONS { struct ICON_ENV {
unsigned int cnt; cli_ctx *ctx;
uint32_t rvas[100]; unsigned int icnt;
int result;
icon_groupset *set;
struct cli_exe_section *exe_sections;
uint16_t nsections;
uint32_t hdr_size;
}; };
static int icon_cb(void *ptr, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva) { static int parseicon(icon_groupset *set, uint32_t rva, cli_ctx *ctx, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size);
struct ICONS *icons = ptr;
static int icon_scan_cb(void *ptr, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva) {
struct ICON_ENV *icon_env = ptr;
int ret = CL_CLEAN;
type = type; lang = lang; type = type; lang = lang;
cli_dbgmsg("icon_cb: got icon %x\n", name); cli_dbgmsg("icon_cb: scanning icon %x\n", name);
if(icons->cnt >= 100)
ret = parseicon(icon_env->set, rva, icon_env->ctx, icon_env->exe_sections, icon_env->nsections, icon_env->hdr_size);
if (ret != CL_CLEAN) icon_env->result = ret;
icon_env->icnt++;
if ((ret != CL_CLEAN) &&
!((icon_env->ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))) {
return 1; return 1;
icons->rvas[icons->cnt] = rva; }
icons->cnt++;
return 0; return 0;
} }
static int parseicon(icon_groupset *set, uint32_t rva, cli_ctx *ctx, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size);
int cli_scanicon(icon_groupset *set, uint32_t resdir_rva, cli_ctx *ctx, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size) { int cli_scanicon(icon_groupset *set, uint32_t resdir_rva, cli_ctx *ctx, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size) {
struct GICONS gicons; struct GICONS gicons;
struct ICONS icons; struct ICON_ENV icon_env;
unsigned int curicon, err; unsigned int curicon, err;
fmap_t *map = *ctx->fmap; fmap_t *map = *ctx->fmap;
icon_env.ctx = ctx;
icon_env.icnt = 0;
icon_env.result = CL_CLEAN;
icon_env.set = set;
icon_env.exe_sections = exe_sections;
icon_env.nsections = nsections;
icon_env.hdr_size = hdr_size;
gicons.cnt = 0; gicons.cnt = 0;
icons.cnt = 0;
findres(14, 0xffffffff, resdir_rva, map, exe_sections, nsections, hdr_size, groupicon_cb, &gicons); findres(14, 0xffffffff, resdir_rva, map, exe_sections, nsections, hdr_size, groupicon_cb, &gicons);
for(curicon=0; curicon<gicons.cnt; curicon++) { for(curicon=0; curicon<gicons.cnt /* && (remaining amount of icons) */; curicon++) {
const uint8_t *grp = fmap_need_off_once(map, cli_rawaddr(gicons.rvas[curicon], exe_sections, nsections, &err, map->len, hdr_size), 16); const uint8_t *grp = fmap_need_off_once(map, cli_rawaddr(gicons.rvas[curicon], exe_sections, nsections, &err, map->len, hdr_size), 16);
if(grp && !err) { if(grp && !err) {
uint32_t gsz = cli_readint32(grp + 4); uint32_t gsz = cli_readint32(grp + 4);
if(gsz>6) { if(gsz>6) {
uint32_t icnt; uint32_t icnt;
unsigned int piconcnt;
struct icondir { struct icondir {
uint8_t w; uint8_t w;
uint8_t h; uint8_t h;
@ -110,29 +130,52 @@ int cli_scanicon(icon_groupset *set, uint32_t resdir_rva, cli_ctx *ctx, struct c
uint16_t id; uint16_t id;
} *dir; } *dir;
cli_dbgmsg("cli_scanicon: start of icon group @%x\n", cli_rawaddr(cli_readint32(grp), exe_sections, nsections, &err, map->len, hdr_size));
grp = fmap_need_off_once(map, cli_rawaddr(cli_readint32(grp), exe_sections, nsections, &err, map->len, hdr_size), gsz); grp = fmap_need_off_once(map, cli_rawaddr(cli_readint32(grp), exe_sections, nsections, &err, map->len, hdr_size), gsz);
if(grp && !err) { if(grp && !err /* && (remaining amount of icons) */) {
icnt = cli_readint32(grp+2) >> 16; icnt = cli_readint32(grp+2) >> 16;
if (icnt > /* remaining amount of icons */icnt) {
icnt = /* remaining amount of icons */icnt;
}
grp+=6; grp+=6;
gsz-=6; gsz-=6;
while(icnt && gsz >= 14) { while(icnt && gsz >= 14) {
piconcnt = icon_env.icnt;
dir = (struct icondir *)grp; dir = (struct icondir *)grp;
cli_dbgmsg("cli_scanicon: Icongrp @%x - %ux%ux%u - (id=%x, rsvd=%u, planes=%u, palcnt=%u, sz=%x)\n", gicons.rvas[curicon], dir->w, dir->h, cli_readint16(&dir->depth), cli_readint16(&dir->id), cli_readint16(&dir->planes), dir->palcnt, dir->rsvd, cli_readint32(&dir->sz)); cli_dbgmsg("cli_scanicon: Icongrp @%x - %ux%ux%u - (id=%x, rsvd=%u, planes=%u, palcnt=%u, sz=%x)\n", gicons.rvas[curicon], dir->w, dir->h, cli_readint16(&dir->depth), cli_readint16(&dir->id), cli_readint16(&dir->planes), dir->palcnt, dir->rsvd, cli_readint32(&dir->sz));
findres(3, cli_readint16(&dir->id), resdir_rva, map, exe_sections, nsections, hdr_size, icon_cb, &icons); findres(3, cli_readint16(&dir->id), resdir_rva, map, exe_sections, nsections, hdr_size, icon_scan_cb, &icon_env);
if ((icon_env.result != CL_CLEAN) &&
!((ctx->options & CL_SCAN_ALLMATCHES) && (icon_env.result == CL_VIRUS))) {
return icon_env.result;
}
if (piconcnt == icon_env.icnt) {
cli_dbgmsg("cli_scanicon: could not find icon id %u in group @%x\n",
dir->id, gicons.rvas[curicon]);
if (0) {
/* heuristic goes here */
}
}
grp += 14; grp += 14;
gsz -= 14; gsz -= 14;
icnt--;
}
if (icnt != 0) {
cli_dbgmsg("cli_scanicon: could not find %u icons\n", icnt);
}
if (gsz != 0) {
cli_dbgmsg("cli_scanicon: could not parse %u bytes of icon entries\n", gsz);
} }
} }
} }
} }
} }
for(curicon=0; curicon<icons.cnt; curicon++) { return icon_env.result;
if(parseicon(set, icons.rvas[curicon], ctx, exe_sections, nsections, hdr_size) == CL_VIRUS)
return CL_VIRUS;
}
return 0;
} }

Loading…
Cancel
Save