~vcs-imports/clamav/main-old

« back to all changes in this revision

Viewing changes to libclamav/special.c

  • Committer: nervoso
  • Date: 2006-05-21 15:16:39 UTC
  • Revision ID: Arch-1:clamav@arch.ubuntu.com%clamav--MAIN--0--patch-1959
repository moved to cvs.clamav.net

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *  Copyright (C) 2004-2005 trog@uncon.org
3
 
 *
4
 
 *  This program is free software; you can redistribute it and/or modify
5
 
 *  it under the terms of the GNU General Public License as published by
6
 
 *  the Free Software Foundation; either version 2 of the License, or
7
 
 *  (at your option) any later version.
8
 
 *
9
 
 *  This program is distributed in the hope that it will be useful,
10
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
 *  GNU General Public License for more details.
13
 
 *
14
 
 *  You should have received a copy of the GNU General Public License
15
 
 *  along with this program; if not, write to the Free Software
16
 
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17
 
 *  MA 02110-1301, USA.
18
 
 */
19
 
 
20
 
#include "clamav-config.h"
21
 
 
22
 
#include <sys/types.h>
23
 
#include <sys/stat.h>
24
 
#include <fcntl.h>
25
 
#include <unistd.h>
26
 
#include <netinet/in.h>
27
 
#include <string.h>
28
 
 
29
 
#include "clamav.h"
30
 
#include "others.h"
31
 
#include "cltypes.h"
32
 
#include "special.h"
33
 
 
34
 
/* NOTE: Photoshop stores data in BIG ENDIAN format, this is the opposite
35
 
        to virtually everything else */
36
 
 
37
 
#define special_endian_convert_16(v) be16_to_host(v)
38
 
#define special_endian_convert_32(v) be32_to_host(v)
39
 
 
40
 
int cli_check_mydoom_log(int desc, const char **virname)
41
 
{
42
 
        int32_t record[8], check;
43
 
        int i, retval=CL_VIRUS, j;
44
 
 
45
 
    cli_dbgmsg("in cli_check_mydoom_log()\n");
46
 
 
47
 
    /* Check upto the first five records in the file */
48
 
    for (j=0 ; j<5 ; j++) {
49
 
        if (cli_readn(desc, &record, 32) != 32) {
50
 
            break;
51
 
        }
52
 
 
53
 
        /* Decode the key */
54
 
        record[0] = ~ntohl(record[0]);
55
 
        cli_dbgmsg("Mydoom: key: %lu\n", record[0]);
56
 
        check = 0;
57
 
        for (i=1 ; i<8; i++) {
58
 
            record[i] = ntohl(record[i]) ^ record[0];
59
 
            check += record[i];
60
 
        }
61
 
        cli_dbgmsg("Mydoom: check: %lu\n", ~check);
62
 
        if ((~check) != record[0]) {
63
 
            return CL_CLEAN;
64
 
        }
65
 
    }
66
 
 
67
 
    if (j < 2) {
68
 
        retval = CL_CLEAN;
69
 
    } else if (retval==CL_VIRUS) {
70
 
        if(virname)
71
 
            *virname = "Worm.Mydoom.M.log";
72
 
    }
73
 
 
74
 
    return retval;
75
 
}
76
 
 
77
 
static int jpeg_check_photoshop_8bim(int fd)
78
 
{
79
 
        unsigned char bim[5];
80
 
        uint16_t id, ntmp;
81
 
        uint8_t nlength;
82
 
        uint32_t size;
83
 
        off_t offset;
84
 
        int retval;
85
 
 
86
 
        if (cli_readn(fd, bim, 4) != 4) {
87
 
                cli_dbgmsg("read bim failed\n");
88
 
                return -1;
89
 
        }
90
 
 
91
 
        if (memcmp(bim, "8BIM", 4) != 0) {
92
 
                bim[4] = '\0';
93
 
                cli_dbgmsg("missed 8bim: %s\n", bim);
94
 
                return -1;
95
 
        }
96
 
 
97
 
        if (cli_readn(fd, &id, 2) != 2) {
98
 
                return -1;
99
 
        }
100
 
        id = special_endian_convert_16(id);
101
 
        cli_dbgmsg("ID: 0x%.4x\n", id);
102
 
        if (cli_readn(fd, &nlength, 1) != 1) {
103
 
                return -1;
104
 
        }
105
 
        ntmp = nlength + ((((uint16_t)nlength)+1) & 0x01);
106
 
        lseek(fd, ntmp, SEEK_CUR);
107
 
        
108
 
        if (cli_readn(fd, &size, 4) != 4) {
109
 
                return -1;
110
 
        }
111
 
        size = special_endian_convert_32(size);
112
 
        if (size == 0) {
113
 
                return -1;
114
 
        }
115
 
        if ((size & 0x01) == 1) {
116
 
                size++;
117
 
        }
118
 
        /* Is it a thumbnail image */
119
 
        if ((id != 0x0409) && (id != 0x040c)) {
120
 
                /* No - Seek past record */
121
 
                lseek(fd, size, SEEK_CUR);
122
 
                return 0;
123
 
        }
124
 
 
125
 
        cli_dbgmsg("found thumbnail\n");
126
 
        /* Check for thumbmail image */
127
 
        offset = lseek(fd, 0, SEEK_CUR);
128
 
 
129
 
        /* Jump past header */
130
 
        lseek(fd, 28, SEEK_CUR);
131
 
 
132
 
        retval = cli_check_jpeg_exploit(fd);
133
 
        if (retval == 1) {
134
 
                cli_dbgmsg("Exploit found in thumbnail\n", retval);
135
 
        }
136
 
        lseek(fd, offset+size, SEEK_SET);
137
 
 
138
 
        return retval;
139
 
}
140
 
 
141
 
static int jpeg_check_photoshop(int fd)
142
 
{
143
 
        int retval;
144
 
        unsigned char buffer[14];
145
 
 
146
 
        if (cli_readn(fd, buffer, 14) != 14) {
147
 
                return 0;
148
 
        }
149
 
 
150
 
        if (memcmp(buffer, "Photoshop 3.0", 14) != 0) {
151
 
                return 0;
152
 
        }
153
 
 
154
 
        cli_dbgmsg("Found Photoshop segment\n");
155
 
        do {
156
 
                retval = jpeg_check_photoshop_8bim(fd);
157
 
        } while (retval == 0);
158
 
 
159
 
        if (retval == -1) {
160
 
                retval = 0;
161
 
        }
162
 
        return retval;
163
 
}
164
 
 
165
 
int cli_check_jpeg_exploit(int fd)
166
 
{
167
 
        unsigned char buffer[4];
168
 
        off_t offset;
169
 
        int retval;
170
 
 
171
 
 
172
 
        cli_dbgmsg("in cli_check_jpeg_exploit()\n");
173
 
 
174
 
        if (cli_readn(fd, buffer, 2) != 2) {
175
 
                return 0;
176
 
        }
177
 
 
178
 
        if ((buffer[0] != 0xff) || (buffer[1] != 0xd8)) {
179
 
                return 0;
180
 
        }
181
 
 
182
 
        for (;;) {
183
 
                if ((retval=cli_readn(fd, buffer, 4)) != 4) {
184
 
                        return 0;
185
 
                }
186
 
                /* Check for multiple 0xFF values, we need to skip them */
187
 
                if ((buffer[0] == 0xff) && (buffer[1] == 0xff)) {
188
 
                        lseek(fd, -3, SEEK_CUR);
189
 
                        continue;
190
 
                }
191
 
 
192
 
                if ((buffer[0] == 0xff) && (buffer[1] == 0xfe)) {
193
 
                        if (buffer[2] == 0x00) {
194
 
                                if ((buffer[3] == 0x00) || (buffer[3] == 0x01)) {
195
 
                                        return 1;
196
 
                                }
197
 
                        }
198
 
                }
199
 
                if (buffer[0] != 0xff) {
200
 
                        return -1;
201
 
                }
202
 
                if (buffer[1] == 0xda) {
203
 
                        /* End of Image marker */
204
 
                        return 0;
205
 
                }
206
 
 
207
 
                offset = ((unsigned int) buffer[2] << 8) + buffer[3];
208
 
                if (offset < 2) {
209
 
                        return 1;
210
 
                }
211
 
                offset -= 2;
212
 
                offset += lseek(fd, 0, SEEK_CUR);
213
 
 
214
 
                if (buffer[1] == 0xed) {
215
 
                        /* Possible Photoshop file */
216
 
                        if ((retval=jpeg_check_photoshop(fd)) != 0) {
217
 
                                return retval;
218
 
                        }
219
 
                }
220
 
 
221
 
                if (lseek(fd, offset, SEEK_SET) != offset) {
222
 
                        return -1;
223
 
                }
224
 
        }
225
 
}
226
 
 
227
 
static uint32_t riff_endian_convert_32(uint32_t value, int big_endian)
228
 
{
229
 
        if (big_endian)
230
 
                return be32_to_host(value);
231
 
        else
232
 
                return le32_to_host(value);
233
 
}
234
 
 
235
 
static int riff_read_chunk(int fd, int big_endian, int rec_level)
236
 
{
237
 
        uint32_t chunk_id;
238
 
        uint32_t chunk_size;
239
 
        int length;
240
 
        uint32_t list_type;
241
 
        off_t offset, cur_offset;
242
 
 
243
 
        if (rec_level > 1000) {
244
 
                cli_dbgmsg("riff_read_chunk: recursion level exceeded\n");
245
 
                return 0;
246
 
        }
247
 
        
248
 
        length = sizeof(uint32_t);
249
 
        if (cli_readn(fd, &chunk_id, length) != length) {
250
 
                return 0;
251
 
        }
252
 
        if (cli_readn(fd, &chunk_size, length) != length) {
253
 
                return 0;
254
 
        }
255
 
        chunk_size = riff_endian_convert_32(chunk_size, big_endian);
256
 
 
257
 
        if (memcmp(&chunk_id, "RIFF", 4) == 0) {
258
 
                return 0;
259
 
        } else if (memcmp(&chunk_id, "RIFX", 4) == 0) {
260
 
                return 0;
261
 
        }
262
 
        
263
 
        if ((memcmp(&chunk_id, "LIST", 4) == 0) ||
264
 
                 (memcmp(&chunk_id, "PROP", 4) == 0) ||
265
 
                 (memcmp(&chunk_id, "FORM", 4) == 0) ||
266
 
                 (memcmp(&chunk_id, "CAT ", 4) == 0)) {
267
 
                if (cli_readn(fd, &list_type, sizeof(list_type)) != sizeof(list_type)) {
268
 
                        cli_dbgmsg("riff_read_chunk: read list type failed\n");
269
 
                        return 0;
270
 
                }
271
 
                return riff_read_chunk(fd, big_endian, ++rec_level);    
272
 
        }
273
 
        
274
 
        cur_offset = lseek(fd, 0, SEEK_CUR);
275
 
        offset = cur_offset + chunk_size;
276
 
        /* Check for odd alignment */
277
 
        if ((offset & 0x01) == 1) {
278
 
                offset++;
279
 
        }
280
 
        if (offset < cur_offset) {
281
 
                return 0;
282
 
        }
283
 
        if (lseek(fd, offset, SEEK_SET) != offset) {
284
 
                return 2;
285
 
        }
286
 
        return 1;
287
 
}
288
 
 
289
 
int cli_check_riff_exploit(int fd)
290
 
{
291
 
        uint32_t chunk_id;
292
 
        uint32_t chunk_size;
293
 
        uint32_t form_type;
294
 
        int length, big_endian, retval;
295
 
        off_t offset;
296
 
        
297
 
        cli_dbgmsg("in cli_check_riff_exploit()\n");
298
 
 
299
 
        length = sizeof(uint32_t);
300
 
        if (cli_readn(fd, &chunk_id, length) != length) {
301
 
                return 0;
302
 
        }
303
 
        if (cli_readn(fd, &chunk_size, length) != length) {
304
 
                return 0;
305
 
        }
306
 
        if (cli_readn(fd, &form_type, length) != length) {
307
 
                return 0;
308
 
        }
309
 
        
310
 
        if (memcmp(&chunk_id, "RIFF", 4) == 0) {
311
 
                big_endian = FALSE;
312
 
        } else if (memcmp(&chunk_id, "RIFX", 4) == 0) {
313
 
                big_endian = TRUE;
314
 
        } else {
315
 
                /* Not a RIFF file */
316
 
                return 0;
317
 
        }
318
 
 
319
 
        if (memcmp(&form_type, "ACON", 4) != 0) {
320
 
                /* Only scan MS animated icon files */
321
 
                /* There is a *lot* of broken software out there that produces bad RIFF files */
322
 
                return 0;
323
 
        }
324
 
 
325
 
        chunk_size = riff_endian_convert_32(chunk_size, big_endian);
326
 
 
327
 
        do {
328
 
                retval = riff_read_chunk(fd, big_endian, 1);
329
 
        } while (retval == 1);
330
 
                
331
 
        offset = lseek(fd, 0, SEEK_CUR);
332
 
 
333
 
        if (offset < (int64_t)chunk_size) {
334
 
                retval = 2;
335
 
        }
336
 
        return retval;
337
 
}