~ubuntu-branches/ubuntu/saucy/clamav/saucy-backports

« back to all changes in this revision

Viewing changes to libclamav/pe_icons.c

  • Committer: Package Import Robot
  • Author(s): Scott Kitterman
  • Date: 2014-07-15 01:08:10 UTC
  • mfrom: (0.35.47 sid)
  • Revision ID: package-import@ubuntu.com-20140715010810-ru66ek4fun2iseba
Tags: 0.98.4+dfsg-2~ubuntu13.10.1
No-change backport to saucy (LP: #1341962)

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
#include <string.h>
26
26
#include <math.h>
27
27
 
 
28
#include <openssl/ssl.h>
 
29
#include <openssl/err.h>
 
30
#include "libclamav/crypto.h"
 
31
 
28
32
#include "pe_icons.h"
29
33
#include "others.h"
30
34
 
31
 
 
32
35
#define READ32(x) cli_readint32(&(x))
33
36
#define READ16(x) cli_readint16(&(x))
34
37
#define USE_FLOATS
40
43
 
41
44
/* #define LOGPARSEICONDETAILS */
42
45
 
43
 
struct GICONS {
44
 
    unsigned int cnt;
 
46
struct ICON_ENV {
 
47
    cli_ctx *ctx;
 
48
    unsigned int gcnt, hcnt; /* gcnt -> number of icon groups parsed, hcnt -> "actual" image count */
45
49
    uint32_t lastg;
46
 
    uint32_t rvas[100];
 
50
    int result;
 
51
 
 
52
    icon_groupset *set;
 
53
    uint32_t resdir_rva;
 
54
    struct cli_exe_section *exe_sections;
 
55
    uint16_t nsections;
 
56
    uint32_t hdr_size;
 
57
 
 
58
    uint32_t icnt; /* number of icon entries parsed, declared images */
 
59
    uint32_t max_icons;
 
60
 
 
61
    uint32_t err_oof;   /* parseicon: offset to icon is out of file */
 
62
    uint32_t err_bhoof; /* parseicon: bmp header is out of file */
 
63
    uint32_t err_bhts;  /* parseicon: BMP header too small */
 
64
    uint32_t err_tstl;  /* parseicon: Image too small or too big */
 
65
    uint32_t err_insl;  /* parseicon: Image not square enough */
47
66
};
48
67
 
49
 
static int groupicon_cb(void *ptr, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva) {
50
 
    struct GICONS *gicons = ptr;
51
 
    type = type; lang = lang;
52
 
    cli_dbgmsg("groupicon_cb: got group %x\n", name);
53
 
    if(!gicons->cnt || gicons->lastg == name) {
54
 
        gicons->rvas[gicons->cnt] = rva;
55
 
        gicons->cnt++;
56
 
        gicons->lastg = name;
57
 
        if(gicons->cnt < 100)
58
 
            return 0;
 
68
int cli_groupiconscan(struct ICON_ENV *icon_env, uint32_t rva);
 
69
 
 
70
static int groupicon_scan_cb(void *ptr, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva) {
 
71
    struct ICON_ENV *icon_env = ptr;
 
72
    int ret = CL_CLEAN;
 
73
    type = type; lang = lang; /* Prevent compiler warnings regarding unused variables */
 
74
 
 
75
    cli_dbgmsg("groupicon_cb: scanning group %x\n", name);
 
76
    if(!icon_env->gcnt || icon_env->lastg == name) {
 
77
        icon_env->gcnt++;
 
78
        icon_env->lastg = name;
 
79
 
 
80
        /* scan icon group */
 
81
        ret = cli_groupiconscan(icon_env, rva);
 
82
        if (ret != CL_CLEAN)
 
83
            return 1;
 
84
 
 
85
        return 0;
59
86
    }
 
87
 
60
88
    return 1;
61
89
}
62
90
 
63
 
struct ICONS {
64
 
    unsigned int cnt;
65
 
    uint32_t rvas[100];
66
 
};
67
 
 
68
 
static int icon_cb(void *ptr, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva) {
69
 
    struct ICONS *icons = ptr;
70
 
    type = type; lang = lang;
71
 
    cli_dbgmsg("icon_cb: got icon %x\n", name);
72
 
    if(icons->cnt >= 100)
73
 
        return 1;
74
 
    icons->rvas[icons->cnt] = rva;
75
 
    icons->cnt++;
 
91
static int parseicon(struct ICON_ENV *icon_env, uint32_t rva);
 
92
 
 
93
static int icon_scan_cb(void *ptr, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva) {
 
94
    struct ICON_ENV *icon_env = ptr;
 
95
    type = type; lang = lang; /* Prevent compiler warnings regarding unused variables */
 
96
    //cli_dbgmsg("icon_cb: scanning icon %x\n", name);
 
97
 
 
98
    /* scan icon */
 
99
    icon_env->result = parseicon(icon_env, rva);
 
100
    icon_env->hcnt++;
 
101
 
 
102
    if (icon_env->result != CL_CLEAN)
 
103
        return 1;
 
104
 
76
105
    return 0;
77
106
}
78
107
 
79
 
 
80
 
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);
81
 
 
82
108
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) {
83
 
    struct GICONS gicons;
84
 
    struct ICONS icons;
85
 
    unsigned int curicon, err;
86
 
    fmap_t *map = *ctx->fmap;
87
 
 
88
 
    gicons.cnt = 0;
89
 
    icons.cnt = 0;
90
 
    findres(14, 0xffffffff, resdir_rva, map, exe_sections, nsections, hdr_size, groupicon_cb, &gicons);
91
 
        
92
 
    for(curicon=0; curicon<gicons.cnt; curicon++) {
93
 
        const uint8_t *grp = fmap_need_off_once(map, cli_rawaddr(gicons.rvas[curicon], exe_sections, nsections, &err, map->len, hdr_size), 16);
94
 
        if(grp && !err) {
95
 
            uint32_t gsz = cli_readint32(grp + 4);
96
 
            if(gsz>6) {
97
 
                uint32_t icnt;
98
 
                struct icondir {
99
 
                    uint8_t w;
100
 
                    uint8_t h;
101
 
                    uint8_t palcnt;
102
 
                    uint8_t rsvd;
103
 
                    uint16_t planes;
104
 
                    uint16_t depth;
105
 
                    uint32_t sz;
106
 
                    uint16_t id;
107
 
                } *dir;
108
 
 
109
 
                grp = fmap_need_off_once(map, cli_rawaddr(cli_readint32(grp), exe_sections, nsections, &err, map->len, hdr_size), gsz);
110
 
                if(grp && !err) {
111
 
                    icnt = cli_readint32(grp+2) >> 16;
112
 
                    grp+=6;
113
 
                    gsz-=6;
114
 
 
115
 
                    while(icnt && gsz >= 14) {
116
 
                        dir = (struct icondir *)grp;
117
 
                        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));
118
 
                        findres(3, cli_readint16(&dir->id), resdir_rva, map, exe_sections, nsections, hdr_size, icon_cb, &icons);
119
 
                        grp += 14;
120
 
                        gsz -= 14;
121
 
                    }
122
 
                }
123
 
            }
124
 
        }
125
 
    }
126
 
 
127
 
    for(curicon=0; curicon<icons.cnt; curicon++) {
128
 
        if(parseicon(set, icons.rvas[curicon], ctx, exe_sections, nsections, hdr_size) == CL_VIRUS)
129
 
            return CL_VIRUS;
130
 
    }
131
 
    return 0;
 
109
    struct ICON_ENV icon_env;
 
110
    fmap_t *map = *ctx->fmap;
 
111
    uint32_t err_total = 0;
 
112
 
 
113
    icon_env.ctx = ctx;
 
114
    icon_env.gcnt = 0;
 
115
    icon_env.hcnt = 0;
 
116
    icon_env.icnt = 0;
 
117
    icon_env.lastg = 0;
 
118
    icon_env.result = CL_CLEAN;
 
119
 
 
120
    icon_env.set = set;
 
121
    icon_env.resdir_rva = resdir_rva;
 
122
    icon_env.exe_sections = exe_sections;
 
123
    icon_env.nsections = nsections;
 
124
    icon_env.hdr_size = hdr_size;
 
125
 
 
126
    icon_env.max_icons = ctx->engine->maxiconspe;
 
127
 
 
128
    icon_env.err_oof = 0;
 
129
    icon_env.err_bhoof = 0;
 
130
    icon_env.err_bhts = 0;
 
131
    icon_env.err_tstl = 0;
 
132
    icon_env.err_insl = 0;
 
133
 
 
134
    /* icon group scan callback --> groupicon_scan_cb() */
 
135
    findres(14, 0xffffffff, resdir_rva, map, exe_sections, nsections, hdr_size, groupicon_scan_cb, &icon_env);
 
136
 
 
137
    /* CL_EMAXSIZE is used to track the icon limit */
 
138
    if (icon_env.result == CL_EMAXSIZE)
 
139
        cli_dbgmsg("cli_scanicon: max icon count reached\n");
 
140
 
 
141
    cli_dbgmsg("cli_scanicon: scanned a total of %u[%u actual] icons across %u groups\n", icon_env.icnt, icon_env.hcnt, icon_env.gcnt);
 
142
    if (icon_env.hcnt < icon_env.icnt)
 
143
        cli_warnmsg("cli_scanicon: found %u invalid icon entries of %u total\n", icon_env.icnt-icon_env.hcnt, icon_env.icnt);
 
144
 
 
145
    err_total = icon_env.err_oof + icon_env.err_bhoof + icon_env.err_bhts + icon_env.err_tstl + icon_env.err_insl;
 
146
    if (err_total > 0) {
 
147
        cli_dbgmsg("cli_scanicon: detected %u total image parsing issues\n", err_total);
 
148
        if (icon_env.err_oof > 0)
 
149
            cli_dbgmsg("cli_scanicon: detected %u cases of 'parseicon: offset to icon is out of file'\n", icon_env.err_oof);
 
150
        if (icon_env.err_bhoof > 0)
 
151
            cli_dbgmsg("cli_scanicon: detected %u cases of 'parseicon: bmp header is out of file'\n", icon_env.err_bhoof);
 
152
        if (icon_env.err_bhts > 0)
 
153
            cli_dbgmsg("cli_scanicon: detected %u cases of 'parseicon: BMP header too small'\n", icon_env.err_bhts);
 
154
        if (icon_env.err_tstl > 0)
 
155
            cli_dbgmsg("cli_scanicon: detected %u cases of 'parseicon: Image too small or too big'\n", icon_env.err_tstl);
 
156
        if (icon_env.err_insl > 0)
 
157
            cli_dbgmsg("cli_scanicon: detected %u cases of 'parseicon: Image not square enough'\n", icon_env.err_insl);
 
158
    }
 
159
 
 
160
    /* ignore all error returns (previous behavior) */
 
161
    if (icon_env.result == CL_VIRUS)
 
162
        return CL_VIRUS;
 
163
 
 
164
    return CL_CLEAN;
 
165
}
 
166
 
 
167
int cli_groupiconscan(struct ICON_ENV *icon_env, uint32_t rva)
 
168
{
 
169
    /* import environment */
 
170
    icon_groupset *set = icon_env->set;
 
171
    uint32_t resdir_rva = icon_env->resdir_rva;
 
172
    cli_ctx *ctx = icon_env->ctx;
 
173
    struct cli_exe_section *exe_sections = icon_env->exe_sections;
 
174
    uint16_t nsections = icon_env->nsections;
 
175
    uint32_t hdr_size = icon_env->hdr_size;
 
176
 
 
177
    int err = 0;
 
178
    fmap_t *map = *ctx->fmap;
 
179
    const uint8_t *grp = fmap_need_off_once(map, cli_rawaddr(rva, exe_sections, nsections, &err, map->len, hdr_size), 16);
 
180
 
 
181
    if(grp && !err) {
 
182
        uint32_t gsz = cli_readint32(grp + 4);
 
183
        if(gsz>6) {
 
184
            uint32_t icnt, raddr;
 
185
            unsigned int piconcnt;
 
186
            struct icondir {
 
187
                uint8_t w;
 
188
                uint8_t h;
 
189
                uint8_t palcnt;
 
190
                uint8_t rsvd;
 
191
                uint16_t planes;
 
192
                uint16_t depth;
 
193
                uint32_t sz;
 
194
                uint16_t id;
 
195
            } *dir;
 
196
 
 
197
            raddr = cli_rawaddr(cli_readint32(grp), exe_sections, nsections, &err, map->len, hdr_size);
 
198
            cli_dbgmsg("cli_scanicon: icon group @%x\n", raddr);
 
199
            grp = fmap_need_off_once(map, raddr, gsz);
 
200
            if(grp && !err) {
 
201
                icnt = cli_readint32(grp+2) >> 16;
 
202
 
 
203
                grp += 6;
 
204
                gsz -= 6;
 
205
 
 
206
                while(icnt && gsz >= 14 /* && (remaining amount of icons) */) {
 
207
                    piconcnt = icon_env->hcnt;
 
208
 
 
209
                    dir = (struct icondir *)grp;
 
210
                    cli_dbgmsg("cli_scanicon: Icongrp @%x - %ux%ux%u - (id=%x, rsvd=%u, planes=%u, palcnt=%u, sz=%x)\n", rva, dir->w, dir->h, cli_readint16(&dir->depth), cli_readint16(&dir->id), cli_readint16(&dir->planes), dir->palcnt, dir->rsvd, cli_readint32(&dir->sz));
 
211
 
 
212
                    /* icon scan callback --> icon_scan_cb() */
 
213
                    findres(3, cli_readint16(&dir->id), resdir_rva, map, exe_sections, nsections, hdr_size, icon_scan_cb, icon_env);
 
214
                    if (icon_env->result != CL_CLEAN)
 
215
                        return icon_env->result;
 
216
 
 
217
                    if (piconcnt == icon_env->hcnt)
 
218
                        cli_dbgmsg("cli_scanicon: invalid icon entry %u in group @%x\n", dir->id, rva);
 
219
 
 
220
                    icon_env->icnt++;
 
221
                    icnt--;
 
222
 
 
223
                    if (icon_env->icnt >= icon_env->max_icons) {
 
224
                        icon_env->result = CL_EMAXSIZE;
 
225
                        return icon_env->result;
 
226
                    }
 
227
 
 
228
                    grp += 14;
 
229
                    gsz -= 14;
 
230
                }
 
231
 
 
232
                if (icnt != 0)
 
233
                    cli_dbgmsg("cli_scanicon: could not find %u icons\n", icnt);
 
234
                if (gsz != 0)
 
235
                    cli_dbgmsg("cli_scanicon: could not parse %u bytes of icon entries\n", gsz);
 
236
            }
 
237
        }
 
238
    }
 
239
 
 
240
    return icon_env->result;
132
241
}
133
242
 
134
243
 
638
747
#endif
639
748
 
640
749
static void makebmp(const char *step, const char *tempd, int w, int h, void *data) {
641
 
    unsigned int tmp1, tmp2, tmp3, tmp4, y;
 
750
    unsigned int tmp1=0, tmp2=0, tmp3=0, tmp4=0, y;
642
751
    char *fname;
643
752
    FILE *f;
644
753
 
1181
1290
    return CL_CLEAN;
1182
1291
}
1183
1292
 
 
1293
static int parseicon(struct ICON_ENV *icon_env, uint32_t rva) {
 
1294
    icon_groupset *set = icon_env->set;
 
1295
    cli_ctx *ctx = icon_env->ctx;
 
1296
    struct cli_exe_section *exe_sections = icon_env->exe_sections;
 
1297
    uint16_t nsections = icon_env->nsections;
 
1298
    uint32_t hdr_size = icon_env->hdr_size;
1184
1299
 
1185
 
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) {
1186
1300
    struct {
1187
1301
        unsigned int sz;
1188
1302
        unsigned int w;
1217
1331
 
1218
1332
    /* read the bitmap header */
1219
1333
    if(err || !(rawimage = fmap_need_off_once(map, icoff, 4))) {
1220
 
        cli_dbgmsg("parseicon: offset to icon is out of file\n");
 
1334
        icon_env->err_oof++;
 
1335
        //cli_dbgmsg("parseicon: offset to icon is out of file\n");
1221
1336
        return CL_SUCCESS;
1222
1337
    }
1223
1338
 
1224
1339
    rva = cli_readint32(rawimage);
1225
1340
    icoff = cli_rawaddr(rva, exe_sections, nsections, &err, map->len, hdr_size);
1226
1341
    if(err || fmap_readn(map, &bmphdr, icoff, sizeof(bmphdr)) != sizeof(bmphdr)) {
1227
 
        cli_dbgmsg("parseicon: bmp header is out of file\n");
 
1342
        icon_env->err_bhoof++;
 
1343
        //cli_dbgmsg("parseicon: bmp header is out of file\n");
1228
1344
        return CL_SUCCESS;
1229
1345
    }
1230
1346
 
1231
1347
    if(READ32(bmphdr.sz) < sizeof(bmphdr)) {
1232
 
        cli_dbgmsg("parseicon: BMP header too small\n");
 
1348
        icon_env->err_bhts++;
 
1349
        //cli_dbgmsg("parseicon: BMP header too small\n");
1233
1350
        return CL_SUCCESS;
1234
1351
    }
1235
1352
 
1240
1357
    height = READ32(bmphdr.h) / 2;
1241
1358
    depth = READ16(bmphdr.depth);
1242
1359
    if(width > 256 || height > 256 || width < 16 || height < 16) {
1243
 
        cli_dbgmsg("parseicon: Image too small or too big (%ux%u)\n", width, height);
 
1360
        icon_env->err_tstl++;
 
1361
        //cli_dbgmsg("parseicon: Image too small or too big (%ux%u)\n", width, height);
1244
1362
        return CL_SUCCESS;
1245
1363
    }
1246
1364
    if(width < height * 3 / 4 || height < width * 3 / 4) {
1247
 
        cli_dbgmsg("parseicon: Image not square enough (%ux%u)\n", width, height);
 
1365
        icon_env->err_insl++;
 
1366
        //cli_dbgmsg("parseicon: Image not square enough (%ux%u)\n", width, height);
1248
1367
        return CL_SUCCESS;
1249
1368
    }   
1250
1369
 
1519
1638
 
1520
1639
        if(confidence >= positivematch) {
1521
1640
            cli_dbgmsg("confidence: %u\n", confidence);
1522
 
 
1523
 
            cli_append_virus(ctx,matcher->icons[enginesize][x].name);
1524
1641
            return CL_VIRUS;
1525
1642
        }
1526
1643
    }