~ubuntu-branches/ubuntu/trusty/clamav/trusty-proposed

« back to all changes in this revision

Viewing changes to libclamav/pe.c

  • Committer: Bazaar Package Importer
  • Author(s): Stephen Gran
  • Date: 2005-09-19 09:05:59 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050919090559-hikpqduq8yx5qxo2
Tags: 0.87-1
* New upstream version
  - Fixes CAN-2005-2920 and CAN-2005-2919 (closes: #328660)
* New logcheck line for clamav-daemon (closes: #323132)
* relibtoolize and apply kfreebsd patch (closes: #327707)
* Make sure init.d script starts freshclam up again after upgrade when run
  from if-up.d (closes: #328912)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2004 - 2005 Tomasz Kojm <tkojm@clamav.net>
 
3
 *
 
4
 *  With additions from aCaB <acab@clamav.net>
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
 */
 
20
 
 
21
#if HAVE_CONFIG_H
 
22
#include "clamav-config.h"
 
23
#endif
 
24
 
 
25
#include <stdio.h>
 
26
#include <string.h>
 
27
#include <sys/types.h>
 
28
#include <sys/stat.h>
 
29
#include <fcntl.h>
 
30
#include <sys/stat.h>
 
31
#include <unistd.h>
 
32
#include <time.h>
 
33
 
 
34
#include "cltypes.h"
 
35
#include "clamav.h"
 
36
#include "others.h"
 
37
#include "pe.h"
 
38
#include "upx.h"
 
39
#include "petite.h"
 
40
#include "fsg.h"
 
41
#include "scanners.h"
 
42
#include "rebuildpe.h"
 
43
#include "str.h"
 
44
 
 
45
#define IMAGE_DOS_SIGNATURE         0x5a4d          /* MZ */
 
46
#define IMAGE_DOS_SIGNATURE_OLD     0x4d5a          /* ZM */
 
47
#define IMAGE_NT_SIGNATURE          0x00004550
 
48
#define IMAGE_OPTIONAL_SIGNATURE    0x010b
 
49
 
 
50
#define DETECT_BROKEN               (options & CL_SCAN_BLOCKBROKEN)
 
51
 
 
52
#define UPX_NRV2B "\x11\xdb\x11\xc9\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9\x11\xc9\x75\x20\x41\x01\xdb"
 
53
#define UPX_NRV2D "\x83\xf0\xff\x74\x78\xd1\xf8\x89\xc5\xeb\x0b\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9"
 
54
#define UPX_NRV2E "\xeb\x52\x31\xc9\x83\xe8\x03\x72\x11\xc1\xe0\x08\x8a\x06\x46\x83\xf0\xff\x74\x75\xd1\xf8\x89\xc5"
 
55
 
 
56
#if WORDS_BIGENDIAN == 0
 
57
#define EC16(v) (v)
 
58
#define EC32(v) (v)
 
59
#else
 
60
static inline uint16_t EC16(uint16_t v)
 
61
{
 
62
    return ((v >> 8) + (v << 8));
 
63
}
 
64
 
 
65
static inline uint32_t EC32(uint32_t v)
 
66
{
 
67
    return ((v >> 24) | ((v & 0x00FF0000) >> 8) | ((v & 0x0000FF00) << 8) | (v << 24));
 
68
}
 
69
#endif
 
70
 
 
71
extern short cli_leavetemps_flag;
 
72
 
 
73
static uint32_t cli_rawaddr(uint32_t rva, struct pe_image_section_hdr *shp, uint16_t nos, unsigned int *err)
 
74
{
 
75
        int i, found = 0;
 
76
 
 
77
 
 
78
    for(i = 0; i < nos; i++) {
 
79
        if(EC32(shp[i].VirtualAddress) <= rva && EC32(shp[i].VirtualAddress) + EC32(shp[i].SizeOfRawData) > rva) {
 
80
            found = 1;
 
81
            break;
 
82
        }
 
83
    }
 
84
 
 
85
    if(!found) {
 
86
        cli_dbgmsg("Can't calculate raw address from RVA 0x%x\n", rva);
 
87
        *err = 1;
 
88
        return 0;
 
89
    }
 
90
 
 
91
    *err = 0;
 
92
    return rva - EC32(shp[i].VirtualAddress) + EC32(shp[i].PointerToRawData);
 
93
}
 
94
 
 
95
/*
 
96
static int cli_ddump(int desc, int offset, int size, const char *file)
 
97
{
 
98
        int pos, ndesc, bread, sum = 0;
 
99
        char buff[FILEBUFF];
 
100
 
 
101
 
 
102
    cli_dbgmsg("in ddump()\n");
 
103
 
 
104
    if((pos = lseek(desc, 0, SEEK_CUR)) == -1) {
 
105
        cli_dbgmsg("Invalid descriptor\n");
 
106
        return -1;
 
107
    }
 
108
 
 
109
    if(lseek(desc, offset, SEEK_SET) == -1) {
 
110
        cli_dbgmsg("lseek() failed\n");
 
111
        lseek(desc, pos, SEEK_SET);
 
112
        return -1;
 
113
    }
 
114
 
 
115
    if((ndesc = open(file, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU)) < 0) {
 
116
        cli_dbgmsg("Can't create file %s\n", file);
 
117
        lseek(desc, pos, SEEK_SET);
 
118
        return -1;
 
119
    }
 
120
 
 
121
    while((bread = read(desc, buff, FILEBUFF)) > 0) {
 
122
        if(sum + bread >= size) {
 
123
            if(write(ndesc, buff, size - sum) == -1) {
 
124
                cli_dbgmsg("Can't write to file\n");
 
125
                lseek(desc, pos, SEEK_SET);
 
126
                close(ndesc);
 
127
                unlink(file);
 
128
                return -1;
 
129
            }
 
130
            break;
 
131
        } else {
 
132
            if(write(ndesc, buff, bread) == -1) {
 
133
                cli_dbgmsg("Can't write to file\n");
 
134
                lseek(desc, pos, SEEK_SET);
 
135
                close(ndesc);
 
136
                unlink(file);
 
137
                return -1;
 
138
            }
 
139
        }
 
140
        sum += bread;
 
141
    }
 
142
 
 
143
    close(ndesc);
 
144
    lseek(desc, pos, SEEK_SET);
 
145
    return 0;
 
146
}
 
147
*/
 
148
 
 
149
int cli_scanpe(int desc, const char **virname, long int *scanned, const struct cl_node *root, const struct cl_limits *limits, unsigned int options, unsigned int arec, unsigned int mrec)
 
150
{
 
151
        uint16_t e_magic; /* DOS signature ("MZ") */
 
152
        uint16_t nsections;
 
153
        uint32_t e_lfanew; /* address of new exe header */
 
154
        uint32_t ep; /* entry point (raw) */
 
155
        time_t timestamp;
 
156
        struct pe_image_file_hdr file_hdr;
 
157
        struct pe_image_optional_hdr optional_hdr;
 
158
        struct pe_image_section_hdr *section_hdr;
 
159
        struct stat sb;
 
160
        char sname[9], buff[4096], *tempfile;
 
161
        unsigned int i, found, upx_success = 0, min = 0, max = 0, err, broken = 0;
 
162
        unsigned int ssize = 0, dsize = 0, dll = 0;
 
163
        int (*upxfn)(char *, int , char *, int *, uint32_t, uint32_t, uint32_t) = NULL;
 
164
        char *src = NULL, *dest = NULL;
 
165
        int ndesc, ret;
 
166
 
 
167
 
 
168
    if(read(desc, &e_magic, sizeof(e_magic)) != sizeof(e_magic)) {
 
169
        cli_dbgmsg("Can't read DOS signature\n");
 
170
        return CL_CLEAN;
 
171
    }
 
172
 
 
173
    if(EC16(e_magic) != IMAGE_DOS_SIGNATURE && EC16(e_magic) != IMAGE_DOS_SIGNATURE_OLD) {
 
174
        cli_dbgmsg("Invalid DOS signature\n");
 
175
        return CL_CLEAN;
 
176
    }
 
177
 
 
178
    lseek(desc, 58, SEEK_CUR); /* skip to the end of the DOS header */
 
179
 
 
180
    if(read(desc, &e_lfanew, sizeof(e_lfanew)) != sizeof(e_lfanew)) {
 
181
        cli_dbgmsg("Can't read new header address\n");
 
182
        /* truncated header? */
 
183
        if(DETECT_BROKEN) {
 
184
            if(virname)
 
185
                *virname = "Broken.Executable";
 
186
            return CL_VIRUS;
 
187
        }
 
188
        return CL_CLEAN;
 
189
    }
 
190
 
 
191
    e_lfanew = EC32(e_lfanew);
 
192
    cli_dbgmsg("e_lfanew == %d\n", e_lfanew);
 
193
    if(!e_lfanew) {
 
194
        cli_dbgmsg("Not a PE file\n");
 
195
        return CL_CLEAN;
 
196
    }
 
197
 
 
198
    if(lseek(desc, e_lfanew, SEEK_SET) < 0) {
 
199
        /* probably not a PE file */
 
200
        cli_dbgmsg("Can't lseek to e_lfanew\n");
 
201
        return CL_CLEAN;
 
202
    }
 
203
 
 
204
    if(read(desc, &file_hdr, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) {
 
205
        /* bad information in e_lfanew - probably not a PE file */
 
206
        cli_dbgmsg("Can't read file header\n");
 
207
        return CL_CLEAN;
 
208
    }
 
209
 
 
210
    if(EC32(file_hdr.Magic) != IMAGE_NT_SIGNATURE) {
 
211
        cli_dbgmsg("Invalid PE signature (probably NE file)\n");
 
212
        return CL_CLEAN;
 
213
    }
 
214
 
 
215
    if(EC16(file_hdr.Characteristics) & 0x2000) {
 
216
        cli_dbgmsg("File type: DLL\n");
 
217
        dll = 1;
 
218
    } else if(EC16(file_hdr.Characteristics) & 0x01) {
 
219
        cli_dbgmsg("File type: Executable\n");
 
220
    }
 
221
 
 
222
    switch(EC16(file_hdr.Machine)) {
 
223
        case 0x0:
 
224
            cli_dbgmsg("Machine type: Unknown\n");
 
225
        case 0x14c:
 
226
            cli_dbgmsg("Machine type: 80386\n");
 
227
            break;
 
228
        case 0x14d:
 
229
            cli_dbgmsg("Machine type: 80486\n");
 
230
            break;
 
231
        case 0x14e:
 
232
            cli_dbgmsg("Machine type: 80586\n");
 
233
            break;
 
234
        case 0x160:
 
235
            cli_dbgmsg("Machine type: R30000 (big-endian)\n");
 
236
            break;
 
237
        case 0x162:
 
238
            cli_dbgmsg("Machine type: R3000\n");
 
239
            break;
 
240
        case 0x166:
 
241
            cli_dbgmsg("Machine type: R4000\n");
 
242
            break;
 
243
        case 0x168:
 
244
            cli_dbgmsg("Machine type: R10000\n");
 
245
            break;
 
246
        case 0x184:
 
247
            cli_dbgmsg("Machine type: DEC Alpha AXP\n");
 
248
            break;
 
249
        case 0x284:
 
250
            cli_dbgmsg("Machine type: DEC Alpha AXP 64bit\n");
 
251
            break;
 
252
        case 0x1f0:
 
253
            cli_dbgmsg("Machine type: PowerPC\n");
 
254
            break;
 
255
        case 0x200:
 
256
            cli_dbgmsg("Machine type: IA64\n");
 
257
            break;
 
258
        case 0x268:
 
259
            cli_dbgmsg("Machine type: M68k\n");
 
260
            break;
 
261
        case 0x266:
 
262
            cli_dbgmsg("Machine type: MIPS16\n");
 
263
            break;
 
264
        case 0x366:
 
265
            cli_dbgmsg("Machine type: MIPS+FPU\n");
 
266
            break;
 
267
        case 0x466:
 
268
            cli_dbgmsg("Machine type: MIPS16+FPU\n");
 
269
            break;
 
270
        case 0x1a2:
 
271
            cli_dbgmsg("Machine type: Hitachi SH3\n");
 
272
            break;
 
273
        case 0x1a3:
 
274
            cli_dbgmsg("Machine type: Hitachi SH3-DSP\n");
 
275
            break;
 
276
        case 0x1a4:
 
277
            cli_dbgmsg("Machine type: Hitachi SH3-E\n");
 
278
            break;
 
279
        case 0x1a6:
 
280
            cli_dbgmsg("Machine type: Hitachi SH4\n");
 
281
            break;
 
282
        case 0x1a8:
 
283
            cli_dbgmsg("Machine type: Hitachi SH5\n");
 
284
            break;
 
285
        case 0x1c0:
 
286
            cli_dbgmsg("Machine type: ARM\n");
 
287
            break;
 
288
        case 0x1c2:
 
289
            cli_dbgmsg("Machine type: THUMB\n");
 
290
            break;
 
291
        case 0x1d3:
 
292
            cli_dbgmsg("Machine type: AM33\n");
 
293
            break;
 
294
        case 0x520:
 
295
            cli_dbgmsg("Machine type: Infineon TriCore\n");
 
296
            break;
 
297
        case 0xcef:
 
298
            cli_dbgmsg("Machine type: CEF\n");
 
299
            break;
 
300
        case 0xebc:
 
301
            cli_dbgmsg("Machine type: EFI Byte Code\n");
 
302
            break;
 
303
        case 0x9041:
 
304
            cli_dbgmsg("Machine type: M32R\n");
 
305
            break;
 
306
        case 0xc0ee:
 
307
            cli_dbgmsg("Machine type: CEE\n");
 
308
            break;
 
309
        case 0x8664:
 
310
            cli_dbgmsg("Machine type: AMD64\n");
 
311
            break;
 
312
        default:
 
313
            cli_warnmsg("Unknown machine type in PE header (0x%x)\n", EC16(file_hdr.Machine));
 
314
    }
 
315
 
 
316
    nsections = EC16(file_hdr.NumberOfSections);
 
317
    if(nsections < 1) {
 
318
        if(DETECT_BROKEN) {
 
319
            if(virname)
 
320
                *virname = "Broken.Executable";
 
321
            return CL_VIRUS;
 
322
        }
 
323
        cli_warnmsg("PE file contains no sections\n");
 
324
        return CL_CLEAN;
 
325
    }
 
326
 
 
327
    cli_dbgmsg("NumberOfSections: %d\n", nsections);
 
328
 
 
329
    timestamp = (time_t) EC32(file_hdr.TimeDateStamp);
 
330
    cli_dbgmsg("TimeDateStamp: %s", ctime(&timestamp));
 
331
 
 
332
    cli_dbgmsg("SizeOfOptionalHeader: %d\n", EC16(file_hdr.SizeOfOptionalHeader));
 
333
 
 
334
    if(EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr)) {
 
335
        cli_warnmsg("Broken PE header detected.\n");
 
336
        if(DETECT_BROKEN) {
 
337
            if(virname)
 
338
                *virname = "Broken.Executable";
 
339
            return CL_VIRUS;
 
340
        }
 
341
        return CL_CLEAN;
 
342
    }
 
343
 
 
344
    if(read(desc, &optional_hdr, sizeof(struct pe_image_optional_hdr)) != sizeof(struct pe_image_optional_hdr)) {
 
345
        cli_dbgmsg("Can't optional file header\n");
 
346
        if(DETECT_BROKEN) {
 
347
            if(virname)
 
348
                *virname = "Broken.Executable";
 
349
            return CL_VIRUS;
 
350
        }
 
351
        return CL_CLEAN;
 
352
    }
 
353
 
 
354
    cli_dbgmsg("MajorLinkerVersion: %d\n", optional_hdr.MajorLinkerVersion);
 
355
    cli_dbgmsg("MinorLinkerVersion: %d\n", optional_hdr.MinorLinkerVersion);
 
356
    cli_dbgmsg("SizeOfCode: %d\n", EC32(optional_hdr.SizeOfCode));
 
357
    cli_dbgmsg("SizeOfInitializedData: %d\n", EC32(optional_hdr.SizeOfInitializedData));
 
358
    cli_dbgmsg("SizeOfUninitializedData: %d\n", EC32(optional_hdr.SizeOfUninitializedData));
 
359
    cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", EC32(optional_hdr.AddressOfEntryPoint));
 
360
    cli_dbgmsg("SectionAlignment: %d\n", EC32(optional_hdr.SectionAlignment));
 
361
    cli_dbgmsg("FileAlignment: %d\n", EC32(optional_hdr.FileAlignment));
 
362
    cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(optional_hdr.MajorSubsystemVersion));
 
363
    cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(optional_hdr.MinorSubsystemVersion));
 
364
    cli_dbgmsg("SizeOfImage: %d\n", EC32(optional_hdr.SizeOfImage));
 
365
    cli_dbgmsg("SizeOfHeaders: %d\n", EC32(optional_hdr.SizeOfHeaders));
 
366
 
 
367
    switch(EC16(optional_hdr.Subsystem)) {
 
368
        case 0:
 
369
            cli_dbgmsg("Subsystem: Unknown\n");
 
370
            break;
 
371
        case 1:
 
372
            cli_dbgmsg("Subsystem: Native (a driver ?)\n");
 
373
            break;
 
374
        case 2:
 
375
            cli_dbgmsg("Subsystem: Win32 GUI\n");
 
376
            break;
 
377
        case 3:
 
378
            cli_dbgmsg("Subsystem: Win32 console\n");
 
379
            break;
 
380
        case 5:
 
381
            cli_dbgmsg("Subsystem: OS/2 console\n");
 
382
            break;
 
383
        case 7:
 
384
            cli_dbgmsg("Subsystem: POSIX console\n");
 
385
            break;
 
386
        case 8:
 
387
            cli_dbgmsg("Subsystem: Native Win9x driver\n");
 
388
            break;
 
389
        case 9:
 
390
            cli_dbgmsg("Subsystem: WinCE GUI\n");
 
391
            break;
 
392
        case 10:
 
393
            cli_dbgmsg("Subsystem: EFI application\n");
 
394
            break;
 
395
        case 11:
 
396
            cli_dbgmsg("Subsystem: EFI driver\n");
 
397
            break;
 
398
        case 12:
 
399
            cli_dbgmsg("Subsystem: EFI runtime driver\n");
 
400
            break;
 
401
        default:
 
402
            cli_warnmsg("Unknown subsystem in PE header (0x%x)\n", EC16(optional_hdr.Subsystem));
 
403
    }
 
404
 
 
405
    cli_dbgmsg("NumberOfRvaAndSizes: %d\n", EC32(optional_hdr.NumberOfRvaAndSizes));
 
406
    cli_dbgmsg("------------------------------------\n");
 
407
 
 
408
    if(fstat(desc, &sb) == -1) {
 
409
        cli_dbgmsg("fstat failed\n");
 
410
        return CL_EIO;
 
411
    }
 
412
 
 
413
    section_hdr = (struct pe_image_section_hdr *) cli_calloc(nsections, sizeof(struct pe_image_section_hdr));
 
414
 
 
415
    if(!section_hdr) {
 
416
        cli_dbgmsg("Can't allocate memory for section headers\n");
 
417
        return CL_EMEM;
 
418
    }
 
419
 
 
420
    for(i = 0; i < nsections; i++) {
 
421
 
 
422
        if(read(desc, &section_hdr[i], sizeof(struct pe_image_section_hdr)) != sizeof(struct pe_image_section_hdr)) {
 
423
            cli_dbgmsg("Can't read section header\n");
 
424
            cli_dbgmsg("Possibly broken PE file\n");
 
425
            free(section_hdr);
 
426
            if(DETECT_BROKEN) {
 
427
                if(virname)
 
428
                    *virname = "Broken.Executable";
 
429
                return CL_VIRUS;
 
430
            }
 
431
            return CL_CLEAN;
 
432
        }
 
433
 
 
434
        strncpy(sname, section_hdr[i].Name, 8);
 
435
        sname[8] = 0;
 
436
        cli_dbgmsg("Section %d\n", i);
 
437
        cli_dbgmsg("Section name: %s\n", sname);
 
438
        cli_dbgmsg("VirtualSize: %d\n", EC32(section_hdr[i].VirtualSize));
 
439
        cli_dbgmsg("VirtualAddress: 0x%x\n", EC32(section_hdr[i].VirtualAddress));
 
440
        cli_dbgmsg("SizeOfRawData: %d\n", EC32(section_hdr[i].SizeOfRawData));
 
441
        cli_dbgmsg("PointerToRawData: 0x%x (%d)\n", EC32(section_hdr[i].PointerToRawData), EC32(section_hdr[i].PointerToRawData));
 
442
 
 
443
        if(EC32(section_hdr[i].Characteristics) & 0x20) {
 
444
            cli_dbgmsg("Section contains executable code\n");
 
445
 
 
446
            if(EC32(section_hdr[i].VirtualSize) < EC32(section_hdr[i].SizeOfRawData)) {
 
447
                cli_dbgmsg("Section contains free space\n");
 
448
                /*
 
449
                cli_dbgmsg("Dumping %d bytes\n", section_hdr.SizeOfRawData - section_hdr.VirtualSize);
 
450
                ddump(desc, section_hdr.PointerToRawData + section_hdr.VirtualSize, section_hdr.SizeOfRawData - section_hdr.VirtualSize, cli_gentemp(NULL));
 
451
                */
 
452
 
 
453
            }
 
454
        }
 
455
 
 
456
        if(EC32(section_hdr[i].Characteristics) & 0x20000000)
 
457
            cli_dbgmsg("Section's memory is executable\n");
 
458
 
 
459
        if(EC32(section_hdr[i].Characteristics) & 0x80000000)
 
460
            cli_dbgmsg("Section's memory is writeable\n");
 
461
 
 
462
        cli_dbgmsg("------------------------------------\n");
 
463
 
 
464
        if(EC32(section_hdr[i].PointerToRawData) + EC32(section_hdr[i].SizeOfRawData) > (unsigned long int) sb.st_size) {
 
465
            cli_dbgmsg("Possibly broken PE file - Section %d out of file (Offset@ %d, Rsize %d, Total filesize %d)\n", i, EC32(section_hdr[i].PointerToRawData), EC32(section_hdr[i].SizeOfRawData), sb.st_size);
 
466
            if(DETECT_BROKEN) {
 
467
                if(virname)
 
468
                    *virname = "Broken.Executable";
 
469
                free(section_hdr);
 
470
                return CL_VIRUS;
 
471
            }
 
472
            broken = 1;
 
473
        }
 
474
 
 
475
        if(!i) {
 
476
            min = EC32(section_hdr[i].VirtualAddress);
 
477
            max = EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData);
 
478
        } else {
 
479
            if(EC32(section_hdr[i].VirtualAddress) < min)
 
480
                min = EC32(section_hdr[i].VirtualAddress);
 
481
 
 
482
            if(EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData) > max)
 
483
                max = EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData);
 
484
        }
 
485
 
 
486
    }
 
487
 
 
488
    if((ep = EC32(optional_hdr.AddressOfEntryPoint)) >= min && !(ep = cli_rawaddr(EC32(optional_hdr.AddressOfEntryPoint), section_hdr, nsections, &err)) && err) {
 
489
        cli_dbgmsg("Possibly broken PE file\n");
 
490
        free(section_hdr);
 
491
        if(DETECT_BROKEN) {
 
492
            if(virname)
 
493
                *virname = "Broken.Executable";
 
494
            return CL_VIRUS;
 
495
        }
 
496
        return CL_CLEAN;
 
497
    }
 
498
 
 
499
    cli_dbgmsg("EntryPoint offset: 0x%x (%d)\n", ep, ep);
 
500
 
 
501
    /* Attempt to detect some popular polymorphic viruses */
 
502
 
 
503
    /* W32.Parite.B */
 
504
    if(!dll && ep == EC32(section_hdr[nsections - 1].PointerToRawData)) {
 
505
        lseek(desc, ep, SEEK_SET);
 
506
        if(read(desc, buff, 4096) == 4096) {
 
507
                const char *pt = cli_memstr(buff, 4040, "\x47\x65\x74\x50\x72\x6f\x63\x41\x64\x64\x72\x65\x73\x73\x00", 15);
 
508
            if(pt) {
 
509
                    uint32_t dw1, dw2;
 
510
 
 
511
                pt += 15;
 
512
                if(((dw1 = cli_readint32(pt)) ^ (dw2 = cli_readint32(pt + 4))) == 0x505a4f && ((dw1 = cli_readint32(pt + 8)) ^ (dw2 = cli_readint32(pt + 12))) == 0xffffb && ((dw1 = cli_readint32(pt + 16)) ^ (dw2 = cli_readint32(pt + 20))) == 0xb8) {
 
513
                    *virname = "W32.Parite.B";
 
514
                    free(section_hdr);
 
515
                    return CL_VIRUS;
 
516
                }
 
517
            }
 
518
        }
 
519
    }
 
520
 
 
521
    /* W32.Magistr.A/B */
 
522
    if(!dll && (EC32(section_hdr[nsections - 1].Characteristics) & 0x80000000)) {
 
523
            uint32_t rsize, vsize;
 
524
 
 
525
        rsize = EC32(section_hdr[nsections - 1].SizeOfRawData);
 
526
        vsize = EC32(section_hdr[nsections - 1].VirtualSize);
 
527
 
 
528
        if(rsize >= 0x612c && vsize >= 0x612c && ((vsize & 0xff) == 0xec)) {
 
529
                int bw = rsize < 0x7000 ? rsize : 0x7000;
 
530
 
 
531
            lseek(desc, EC32(section_hdr[nsections - 1].PointerToRawData) + rsize - bw, SEEK_SET);
 
532
            if(read(desc, buff, 4096) == 4096) {
 
533
                if(cli_memstr(buff, 4091, "\xe8\x2c\x61\x00\x00", 5)) {
 
534
                    *virname = "W32.Magistr.A";
 
535
                    free(section_hdr);
 
536
                    return CL_VIRUS;
 
537
                } 
 
538
            }
 
539
 
 
540
        } else if(rsize >= 0x7000 && vsize >= 0x7000 && ((vsize & 0xff) == 0xed)) {
 
541
                int bw = rsize < 0x8000 ? rsize : 0x8000;
 
542
 
 
543
            lseek(desc, EC32(section_hdr[nsections - 1].PointerToRawData) + rsize - bw, SEEK_SET);
 
544
            if(read(desc, buff, 4096) == 4096) {
 
545
                if(cli_memstr(buff, 4091, "\xe8\x04\x72\x00\x00", 5)) {
 
546
                    *virname = "W32.Magistr.B";
 
547
                    free(section_hdr);
 
548
                    return CL_VIRUS;
 
549
                } 
 
550
            }
 
551
        }
 
552
    }
 
553
 
 
554
    if(broken) {
 
555
        free(section_hdr);
 
556
        return CL_CLEAN;
 
557
    }
 
558
 
 
559
    /* UPX & FSG support */
 
560
 
 
561
    /* try to find the first section with physical size == 0 */
 
562
    found = 0;
 
563
    for(i = 0; i < (unsigned int) nsections - 1; i++) {
 
564
        if(!section_hdr[i].SizeOfRawData && section_hdr[i].VirtualSize && section_hdr[i + 1].SizeOfRawData && section_hdr[i + 1].VirtualSize) {
 
565
            found = 1;
 
566
            cli_dbgmsg("UPX/FSG: empty section found - assuming compression\n");
 
567
            break;
 
568
        }
 
569
    }
 
570
 
 
571
    if(found) {
 
572
 
 
573
        /* Check EP for UPX vs. FSG */
 
574
        if(lseek(desc, ep, SEEK_SET) == -1) {
 
575
            cli_dbgmsg("UPX/FSG: lseek() failed\n");
 
576
            free(section_hdr);
 
577
            return CL_EIO;
 
578
        }
 
579
 
 
580
        if(read(desc, buff, 168) != 168) {
 
581
            cli_dbgmsg("UPX/FSG: Can't read 168 bytes at 0x%x (%d)\n", ep, ep);
 
582
            cli_dbgmsg("UPX/FSG: Broken or not UPX/FSG compressed file\n");
 
583
            free(section_hdr);
 
584
            return CL_CLEAN;
 
585
        }
 
586
 
 
587
        if(buff[0] == '\x87' && buff[1] == '\x25') {
 
588
 
 
589
            /* FSG v2.0 support - thanks to aCaB ! */
 
590
 
 
591
            ssize = EC32(section_hdr[i + 1].SizeOfRawData);
 
592
            dsize = EC32(section_hdr[i].VirtualSize);
 
593
 
 
594
            while(found) {
 
595
                    uint32_t newesi, newedi, newebx, newedx;
 
596
 
 
597
                if(limits && limits->maxfilesize && (ssize > limits->maxfilesize || dsize > limits->maxfilesize)) {
 
598
                    cli_dbgmsg("FSG: Sizes exceeded (ssize: %d, dsize: %d, max: %lu)\n", ssize, dsize , limits->maxfilesize);
 
599
                    free(section_hdr);
 
600
                    return CL_CLEAN;
 
601
                }
 
602
 
 
603
                if(ssize <= 0x19 || dsize <= ssize) {
 
604
                    cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
 
605
                    free(section_hdr);
 
606
                    return CL_CLEAN;
 
607
                }
 
608
 
 
609
                if((newedx = cli_readint32(buff + 2) - EC32(optional_hdr.ImageBase)) < EC32(section_hdr[i + 1].VirtualAddress) || newedx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 4) {
 
610
                    cli_dbgmsg("FSG: xchg out of bounds (%x), giving up\n", newedx);
 
611
                    break;
 
612
                }
 
613
 
 
614
                if((src = (char *) cli_malloc(ssize)) == NULL) {
 
615
                    free(section_hdr);
 
616
                    return CL_EMEM;
 
617
                }
 
618
 
 
619
                lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET);
 
620
                if((unsigned int) read(desc, src, ssize) != ssize) {
 
621
                    cli_dbgmsg("Can't read raw data of section %d\n", i);
 
622
                    free(section_hdr);
 
623
                    free(src);
 
624
                    return CL_EIO;
 
625
                }
 
626
 
 
627
                if(newedx < EC32(section_hdr[i + 1].VirtualAddress) || ((dest = src + newedx - EC32(section_hdr[i + 1].VirtualAddress)) < src && dest >= src + EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 4)) {
 
628
                    cli_dbgmsg("FSG: New ESP out of bounds\n");
 
629
                    free(src);
 
630
                    break;
 
631
                }
 
632
 
 
633
                if((newedx = cli_readint32(dest) - EC32(optional_hdr.ImageBase)) <= EC32(section_hdr[i + 1].VirtualAddress) || newedx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 4) {
 
634
                    cli_dbgmsg("FSG: New ESP (%x) is wrong\n", newedx);
 
635
                    free(src);
 
636
                    break;
 
637
                }
 
638
 
 
639
                if((dest = src + newedx - EC32(section_hdr[i + 1].VirtualAddress)) < src || dest >= src + EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 32) {
 
640
                    cli_dbgmsg("FSG: New stack out of bounds\n");
 
641
                    free(src);
 
642
                    break;
 
643
                }
 
644
 
 
645
                newedi = cli_readint32(dest) - EC32(optional_hdr.ImageBase);
 
646
                newesi = cli_readint32(dest + 4) - EC32(optional_hdr.ImageBase);
 
647
                newebx = cli_readint32(dest + 16) - EC32(optional_hdr.ImageBase);
 
648
                newedx = cli_readint32(dest + 20);
 
649
 
 
650
                if(newedi != EC32(section_hdr[i].VirtualAddress)) {
 
651
                    cli_dbgmsg("FSG: Bad destination buffer (edi is %x should be %x)\n", newedi, EC32(section_hdr[i].VirtualAddress));
 
652
                    free(src);
 
653
                    break;
 
654
                }
 
655
 
 
656
                if(newesi < EC32(section_hdr[i + 1].VirtualAddress) || newesi >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData)) {
 
657
                    cli_dbgmsg("FSG: Source buffer out of section bounds\n");
 
658
                    free(src);
 
659
                    break;
 
660
                }
 
661
 
 
662
                if(newebx < EC32(section_hdr[i + 1].VirtualAddress) || newebx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 16) {
 
663
                    cli_dbgmsg("FSG: Array of functions out of bounds\n");
 
664
                    free(src);
 
665
                    break;
 
666
                }
 
667
 
 
668
                /* FIXME: unused atm, needed for pe rebuilding */
 
669
                cli_dbgmsg("FSG: found old EP @%x\n", cli_readint32(newebx + 12 - EC32(section_hdr[i + 1].VirtualAddress) + src) - EC32(optional_hdr.ImageBase));
 
670
 
 
671
                if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
 
672
                    free(section_hdr);
 
673
                    free(src);
 
674
                    return CL_EMEM;
 
675
                }
 
676
 
 
677
                if(unfsg_200(newesi - EC32(section_hdr[i + 1].VirtualAddress) + src, dest, ssize + EC32(section_hdr[i + 1].VirtualAddress) - newesi, dsize) == -1) {
 
678
                    cli_dbgmsg("FSG: Unpacking failed\n");
 
679
                    free(src);
 
680
                    free(dest);
 
681
                    break;
 
682
                }
 
683
 
 
684
                found = 0;
 
685
                upx_success = 1;
 
686
                cli_dbgmsg("FSG: Successfully decompressed\n");
 
687
            }
 
688
        }
 
689
 
 
690
        if(found && buff[0] == '\xbe' && cli_readint32(buff + 1) - EC32(optional_hdr.ImageBase) < min) {
 
691
 
 
692
            /* FSG support - v. 1.33 (thx trog for the many samples) */
 
693
 
 
694
            ssize = EC32(section_hdr[i + 1].SizeOfRawData);
 
695
            dsize = EC32(section_hdr[i].VirtualSize);
 
696
 
 
697
            while(found) {
 
698
                    int gp, t, sectcnt = 0;
 
699
                    char *support;
 
700
                    uint32_t newesi, newedi, newebx, oldep;
 
701
                    struct SECTION *sections;
 
702
 
 
703
 
 
704
                if(limits && limits->maxfilesize && (ssize > limits->maxfilesize || dsize > limits->maxfilesize)) {
 
705
                    cli_dbgmsg("FSG: Sizes exceeded (ssize: %d, dsize: %d, max: %lu)\n", ssize, dsize, limits->maxfilesize);
 
706
                    free(section_hdr);
 
707
                    return CL_CLEAN;
 
708
                }
 
709
 
 
710
                if(ssize <= 0x19 || dsize <= ssize) {
 
711
                    cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
 
712
                    free(section_hdr);
 
713
                    return CL_CLEAN;
 
714
                }
 
715
 
 
716
                if((gp = cli_readint32(buff + 1) - EC32(optional_hdr.ImageBase)) >= (int) EC32(section_hdr[i + 1].PointerToRawData) || gp < 0) {
 
717
                    cli_dbgmsg("FSG: Support data out of padding area (vaddr: %d)\n", EC32(section_hdr[i].VirtualAddress));
 
718
                    break;
 
719
                }
 
720
 
 
721
                lseek(desc, gp, SEEK_SET);
 
722
                gp = EC32(section_hdr[i + 1].PointerToRawData) - gp;
 
723
 
 
724
                if(limits && limits->maxfilesize && (unsigned int) gp > limits->maxfilesize) {
 
725
                    cli_dbgmsg("FSG: Buffer size exceeded (size: %d, max: %lu)\n", gp, limits->maxfilesize);
 
726
                    free(section_hdr);
 
727
                    return CL_CLEAN;
 
728
                }
 
729
 
 
730
                if((support = (char *) cli_malloc(gp)) == NULL) {
 
731
                    free(section_hdr);
 
732
                    return CL_EMEM;
 
733
                }
 
734
 
 
735
                if(read(desc, support, gp) != gp) {
 
736
                    cli_dbgmsg("Can't read %d bytes from padding area\n", gp); 
 
737
                    free(section_hdr);
 
738
                    free(support);
 
739
                    return CL_EIO;
 
740
                }
 
741
 
 
742
                newebx = cli_readint32(support) - EC32(optional_hdr.ImageBase); /* Unused */
 
743
                newedi = cli_readint32(support + 4) - EC32(optional_hdr.ImageBase); /* 1st dest */
 
744
                newesi = cli_readint32(support + 8) - EC32(optional_hdr.ImageBase); /* Source */
 
745
 
 
746
                if(newesi < EC32(section_hdr[i + 1].VirtualAddress) || newesi >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData)) {
 
747
                    cli_dbgmsg("FSG: Source buffer out of section bounds\n");
 
748
                    free(support);
 
749
                    break;
 
750
                }
 
751
 
 
752
                if(newedi != EC32(section_hdr[i].VirtualAddress)) {
 
753
                    cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, EC32(section_hdr[i].VirtualAddress));
 
754
                    free(support);
 
755
                    break;
 
756
                }
 
757
 
 
758
                /* Counting original sections */
 
759
                for(t = 12; t < gp - 4; t += 4) {
 
760
                        uint32_t rva = cli_readint32(support+t);
 
761
 
 
762
                    if(!rva)
 
763
                        break;
 
764
 
 
765
                    rva -= EC32(optional_hdr.ImageBase)+1;
 
766
                    sectcnt++;
 
767
 
 
768
                    if(rva % 0x1000)
 
769
                        /* FIXME: really need to bother? */
 
770
                        cli_dbgmsg("FSG: Original section %d is misaligned\n", sectcnt);
 
771
 
 
772
                    if(rva < EC32(section_hdr[i].VirtualAddress) || rva >= EC32(section_hdr[i].VirtualAddress)+EC32(section_hdr[i].VirtualSize)) {
 
773
                        cli_dbgmsg("FSG: Original section %d is out of bounds\n", sectcnt);
 
774
                        break;
 
775
                    }
 
776
                }
 
777
 
 
778
                if(t >= gp - 4 || cli_readint32(support + t)) {
 
779
                    free(support);
 
780
                    break;
 
781
                }
 
782
 
 
783
                if((sections = (struct SECTION *) cli_malloc((sectcnt + 1) * sizeof(struct SECTION))) == NULL) {
 
784
                    free(section_hdr);
 
785
                    free(support);
 
786
                    return CL_EMEM;
 
787
                }
 
788
 
 
789
                sections[0].rva = newedi;
 
790
                for(t = 1; t <= sectcnt; t++)
 
791
                    sections[t].rva = cli_readint32(support + 8 + t * 4) - 1 -EC32(optional_hdr.ImageBase);
 
792
 
 
793
                free(support);
 
794
 
 
795
                if((src = (char *) cli_malloc(ssize)) == NULL) {
 
796
                    free(section_hdr);
 
797
                    free(sections);
 
798
                    return CL_EMEM;
 
799
                }
 
800
 
 
801
                lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET);
 
802
                if((unsigned int) read(desc, src, ssize) != ssize) {
 
803
                    cli_dbgmsg("Can't read raw data of section %d\n", i);
 
804
                    free(section_hdr);
 
805
                    free(sections);
 
806
                    free(src);
 
807
                    return CL_EIO;
 
808
                }
 
809
 
 
810
                if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
 
811
                    free(section_hdr);
 
812
                    free(src);
 
813
                    free(sections);
 
814
                    return CL_EMEM;
 
815
                }
 
816
 
 
817
                oldep = EC32(optional_hdr.AddressOfEntryPoint) + 161 + 6 + cli_readint32(buff+163);
 
818
                cli_dbgmsg("FSG: found old EP @%x\n", oldep);
 
819
 
 
820
                tempfile = cli_gentemp(NULL);
 
821
                if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC, S_IRWXU)) < 0) {
 
822
                    cli_dbgmsg("FSG: Can't create file %s\n", tempfile);
 
823
                    free(tempfile);
 
824
                    free(section_hdr);
 
825
                    free(src);
 
826
                    free(dest);
 
827
                    free(sections);
 
828
                    return CL_EIO;
 
829
                }
 
830
 
 
831
                switch(unfsg_133(src + newesi - EC32(section_hdr[i + 1].VirtualAddress), dest, ssize + EC32(section_hdr[i + 1].VirtualAddress) - newesi, dsize, sections, sectcnt, EC32(optional_hdr.ImageBase), oldep, ndesc)) {
 
832
                    case 1: /* Everything OK */
 
833
                        cli_dbgmsg("FSG: Unpacked and rebuilt executable saved in %s\n", tempfile);
 
834
                        free(src);
 
835
                        free(dest);
 
836
                        free(sections);
 
837
                        fsync(ndesc);
 
838
                        lseek(ndesc, 0, SEEK_SET);
 
839
 
 
840
                        cli_dbgmsg("***** Scanning rebuilt PE file *****\n");
 
841
                        if(cli_magic_scandesc(ndesc, virname, scanned, root, limits, options, arec, mrec) == CL_VIRUS) {
 
842
                            free(section_hdr);
 
843
                            close(ndesc);
 
844
                            if(!cli_leavetemps_flag)
 
845
                                unlink(tempfile);
 
846
                            free(tempfile);
 
847
                            return CL_VIRUS;
 
848
                        }
 
849
 
 
850
                        close(ndesc);
 
851
                        if(!cli_leavetemps_flag)
 
852
                            unlink(tempfile);
 
853
                        free(tempfile);
 
854
                        free(section_hdr);
 
855
                        return CL_CLEAN;
 
856
 
 
857
                    case 0: /* We've got an unpacked buffer, no exe though */
 
858
                        cli_dbgmsg("FSG: FSG: Successfully decompressed\n");
 
859
                        close(ndesc);
 
860
                        unlink(tempfile);
 
861
                        free(tempfile);
 
862
                        free(sections);
 
863
                        found = 0;
 
864
                        upx_success = 1;
 
865
                        break; /* Go and scan the buffer! */
 
866
 
 
867
                    default: /* Everything gone wrong */
 
868
                        cli_dbgmsg("FSG: Unpacking failed\n");
 
869
                        close(ndesc);
 
870
                        unlink(tempfile); // It's empty anyway
 
871
                        free(tempfile);
 
872
                        free(src);
 
873
                        free(dest);
 
874
                        free(sections);
 
875
                        break;
 
876
                }
 
877
 
 
878
                break; /* were done with 1.33 */
 
879
            }
 
880
        }
 
881
 
 
882
        /* FIXME: easy 2 hack */
 
883
        if(found && buff[0] == '\xbb' && cli_readint32(buff + 1) - EC32(optional_hdr.ImageBase) < min && buff[5] == '\xbf' && buff[10] == '\xbe') {
 
884
 
 
885
            /* FSG support - v. 1.31 */
 
886
 
 
887
            ssize = EC32(section_hdr[i + 1].SizeOfRawData);
 
888
            dsize = EC32(section_hdr[i].VirtualSize);
 
889
 
 
890
            while(found) {
 
891
                    int gp = cli_readint32(buff+1) - EC32(optional_hdr.ImageBase), t, sectcnt = 0;
 
892
                    char *support;
 
893
                    uint32_t newesi = cli_readint32(buff+11) - EC32(optional_hdr.ImageBase);
 
894
                    uint32_t newedi = cli_readint32(buff+6) - EC32(optional_hdr.ImageBase);
 
895
                    uint32_t oldep = EC32(optional_hdr.AddressOfEntryPoint);
 
896
                    struct SECTION *sections;
 
897
 
 
898
                if (oldep <= EC32(section_hdr[i + 1].VirtualAddress) || oldep > EC32(section_hdr[i + 1].VirtualAddress)+EC32(section_hdr[i + 1].SizeOfRawData) - 0xe0) {
 
899
                  cli_dbgmsg("FSG: EP not in section %d\n", i+1);
 
900
                  break;
 
901
                }
 
902
                oldep -= EC32(section_hdr[i + 1].VirtualAddress);
 
903
 
 
904
                if(newesi < EC32(section_hdr[i + 1].VirtualAddress) || newesi >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData)) {
 
905
                    cli_dbgmsg("FSG: Source buffer out of section bounds\n");
 
906
                    break;
 
907
                }
 
908
 
 
909
                if(newedi != EC32(section_hdr[i].VirtualAddress)) {
 
910
                    cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, EC32(section_hdr[i].VirtualAddress));
 
911
                    break;
 
912
                }
 
913
 
 
914
                if(limits && limits->maxfilesize && (ssize > limits->maxfilesize || dsize > limits->maxfilesize)) {
 
915
                    cli_dbgmsg("FSG: Sizes exceeded (ssize: %d, dsize: %d, max: %lu)\n", ssize, dsize, limits->maxfilesize);
 
916
                    free(section_hdr);
 
917
                    return CL_CLEAN;
 
918
                }
 
919
 
 
920
                if(ssize <= 0x19 || dsize <= ssize) {
 
921
                    cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
 
922
                    free(section_hdr);
 
923
                    return CL_CLEAN;
 
924
                }
 
925
 
 
926
                if(gp >= (int) EC32(section_hdr[i + 1].PointerToRawData) || gp < 0) {
 
927
                    cli_dbgmsg("FSG: Support data out of padding area (newedi: %d, vaddr: %d)\n", newedi, EC32(section_hdr[i].VirtualAddress));
 
928
                    break;
 
929
                }
 
930
 
 
931
                lseek(desc, gp, SEEK_SET);
 
932
                gp = EC32(section_hdr[i + 1].PointerToRawData) - gp;
 
933
 
 
934
                if(limits && limits->maxfilesize && (unsigned int) gp > limits->maxfilesize) {
 
935
                    cli_dbgmsg("FSG: Buffer size exceeded (size: %d, max: %lu)\n", gp, limits->maxfilesize);
 
936
                    free(section_hdr);
 
937
                    return CL_CLEAN;
 
938
                }
 
939
 
 
940
                if((support = (char *) cli_malloc(gp)) == NULL) {
 
941
                    free(section_hdr);
 
942
                    return CL_EMEM;
 
943
                }
 
944
 
 
945
                if(read(desc, support, gp) != gp) {
 
946
                    cli_dbgmsg("Can't read %d bytes from padding area\n", gp); 
 
947
                    free(section_hdr);
 
948
                    free(support);
 
949
                    return CL_EIO;
 
950
                }
 
951
 
 
952
                /* Counting original sections */
 
953
                for(t = 0; t < gp - 2; t += 2) {
 
954
                  uint32_t rva = support[t]+256*support[t+1];
 
955
                  
 
956
                  if (rva == 2 || rva == 1)
 
957
                    break;
 
958
 
 
959
                  rva = ((rva-2)<<12) - EC32(optional_hdr.ImageBase);
 
960
                  sectcnt++;
 
961
 
 
962
                  if(rva < EC32(section_hdr[i].VirtualAddress) || rva >= EC32(section_hdr[i].VirtualAddress)+EC32(section_hdr[i].VirtualSize)) {
 
963
                    cli_dbgmsg("FSG: Original section %d is out of bounds\n", sectcnt);
 
964
                    break;
 
965
                  }
 
966
                }
 
967
 
 
968
                if(t >= gp-10 || cli_readint32(support + t + 6) != 2) {
 
969
                    free(support);
 
970
                    break;
 
971
                }
 
972
 
 
973
                if((sections = (struct SECTION *) cli_malloc((sectcnt + 1) * sizeof(struct SECTION))) == NULL) {
 
974
                    free(section_hdr);
 
975
                    free(support);
 
976
                    return CL_EMEM;
 
977
                }
 
978
 
 
979
                sections[0].rva = newedi;
 
980
                for(t = 0; t <= sectcnt - 1; t++) {
 
981
                  sections[t+1].rva = (((support[t*2]+256*support[t*2+1])-2)<<12)-EC32(optional_hdr.ImageBase);
 
982
                }
 
983
 
 
984
                free(support);
 
985
 
 
986
                if((src = (char *) cli_malloc(ssize)) == NULL) {
 
987
                    free(section_hdr);
 
988
                    free(sections);
 
989
                    return CL_EMEM;
 
990
                }
 
991
 
 
992
                lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET);
 
993
                if((unsigned int) read(desc, src, ssize) != ssize) {
 
994
                    cli_dbgmsg("Can't read raw data of section %d\n", i);
 
995
                    free(section_hdr);
 
996
                    free(sections);
 
997
                    free(src);
 
998
                    return CL_EIO;
 
999
                }
 
1000
 
 
1001
                if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
 
1002
                    free(section_hdr);
 
1003
                    free(src);
 
1004
                    free(sections);
 
1005
                    return CL_EMEM;
 
1006
                }
 
1007
 
 
1008
                /* Better not increasing buff size any further, let's go the hard way */
 
1009
                gp = 0xda + 6*(buff[16]=='\xe8');
 
1010
                oldep = EC32(optional_hdr.AddressOfEntryPoint) + gp + 6 + cli_readint32(src+gp+2+oldep);
 
1011
                cli_dbgmsg("FSG: found old EP @%x\n", oldep);
 
1012
 
 
1013
                tempfile = cli_gentemp(NULL);
 
1014
                if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC, S_IRWXU)) < 0) {
 
1015
                    cli_dbgmsg("FSG: Can't create file %s\n", tempfile);
 
1016
                    free(tempfile);
 
1017
                    free(section_hdr);
 
1018
                    free(src);
 
1019
                    free(dest);
 
1020
                    free(sections);
 
1021
                    return CL_EIO;
 
1022
                }
 
1023
 
 
1024
                switch(unfsg_133(src + newesi - EC32(section_hdr[i + 1].VirtualAddress), dest, ssize + EC32(section_hdr[i + 1].VirtualAddress) - newesi, dsize, sections, sectcnt, EC32(optional_hdr.ImageBase), oldep, ndesc)) {
 
1025
                    case 1: /* Everything OK */
 
1026
                        cli_dbgmsg("FSG: Unpacked and rebuilt executable saved in %s\n", tempfile);
 
1027
                        free(src);
 
1028
                        free(dest);
 
1029
                        free(sections);
 
1030
                        fsync(ndesc);
 
1031
                        lseek(ndesc, 0, SEEK_SET);
 
1032
 
 
1033
                        cli_dbgmsg("***** Scanning rebuilt PE file *****\n");
 
1034
                        if(cli_magic_scandesc(ndesc, virname, scanned, root, limits, options, arec, mrec) == CL_VIRUS) {
 
1035
                            free(section_hdr);
 
1036
                            close(ndesc);
 
1037
                            if(!cli_leavetemps_flag)
 
1038
                                unlink(tempfile);
 
1039
                            free(tempfile);
 
1040
                            return CL_VIRUS;
 
1041
                        }
 
1042
 
 
1043
                        close(ndesc);
 
1044
                        if(!cli_leavetemps_flag)
 
1045
                            unlink(tempfile);
 
1046
                        free(tempfile);
 
1047
                        free(section_hdr);
 
1048
                        return CL_CLEAN;
 
1049
 
 
1050
                    case 0: /* We've got an unpacked buffer, no exe though */
 
1051
                        cli_dbgmsg("FSG: FSG: Successfully decompressed\n");
 
1052
                        close(ndesc);
 
1053
                        unlink(tempfile);
 
1054
                        free(tempfile);
 
1055
                        free(sections);
 
1056
                        found = 0;
 
1057
                        upx_success = 1;
 
1058
                        break; /* Go and scan the buffer! */
 
1059
 
 
1060
                    default: /* Everything gone wrong */
 
1061
                        cli_dbgmsg("FSG: Unpacking failed\n");
 
1062
                        close(ndesc);
 
1063
                        unlink(tempfile); // It's empty anyway
 
1064
                        free(tempfile);
 
1065
                        free(src);
 
1066
                        free(dest);
 
1067
                        free(sections);
 
1068
                        break;
 
1069
                }
 
1070
 
 
1071
                break; /* were done with 1.31 */
 
1072
            }
 
1073
        }
 
1074
 
 
1075
 
 
1076
        if(found) {
 
1077
 
 
1078
            /* UPX support */
 
1079
 
 
1080
            strncpy(sname, section_hdr[i].Name, 8);
 
1081
            sname[8] = 0;
 
1082
            cli_dbgmsg("UPX: Section %d name: %s\n", i, sname);
 
1083
            strncpy(sname, section_hdr[i + 1].Name, 8);
 
1084
            sname[8] = 0;
 
1085
            cli_dbgmsg("UPX: Section %d name: %s\n", i + 1, sname);
 
1086
 
 
1087
            if(strncmp(section_hdr[i].Name, "UPX0", 4) || strncmp(section_hdr[i + 1].Name, "UPX1", 4))
 
1088
                cli_dbgmsg("UPX: Possibly hacked UPX section headers\n");
 
1089
 
 
1090
            /* we assume (i + 1) is UPX1 */
 
1091
            ssize = EC32(section_hdr[i + 1].SizeOfRawData);
 
1092
            dsize = EC32(section_hdr[i].VirtualSize) + EC32(section_hdr[i + 1].VirtualSize);
 
1093
 
 
1094
            if(limits && limits->maxfilesize && (ssize > limits->maxfilesize || dsize > limits->maxfilesize)) {
 
1095
                cli_dbgmsg("UPX: Sizes exceeded (ssize: %d, dsize: %d, max: %lu)\n", ssize, dsize , limits->maxfilesize);
 
1096
                free(section_hdr);
 
1097
                return CL_CLEAN;
 
1098
            }
 
1099
 
 
1100
            if(ssize <= 0x19 || dsize <= ssize) { /* FIXME: What are reasonable values? */
 
1101
                cli_dbgmsg("UPX: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
 
1102
                free(section_hdr);
 
1103
                return CL_CLEAN;
 
1104
            }
 
1105
 
 
1106
            /* FIXME: use file operations in case of big files */
 
1107
            if((src = (char *) cli_malloc(ssize)) == NULL) {
 
1108
                free(section_hdr);
 
1109
                return CL_EMEM;
 
1110
            }
 
1111
 
 
1112
            if((dest = (char *) cli_calloc(dsize + 1024 + nsections * 40, sizeof(char))) == NULL) {
 
1113
                free(section_hdr);
 
1114
                free(src);
 
1115
                return CL_EMEM;
 
1116
            }
 
1117
 
 
1118
            lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET);
 
1119
            if((unsigned int) read(desc, src, ssize) != ssize) {
 
1120
                cli_dbgmsg("Can't read raw data of section %d\n", i);
 
1121
                free(section_hdr);
 
1122
                free(src);
 
1123
                free(dest);
 
1124
                return CL_EIO;
 
1125
            }
 
1126
 
 
1127
            /* try to detect UPX code */
 
1128
 
 
1129
            if(lseek(desc, ep, SEEK_SET) == -1) {
 
1130
                cli_dbgmsg("lseek() failed\n");
 
1131
                free(section_hdr);
 
1132
                free(src);
 
1133
                free(dest);
 
1134
                return CL_EIO;
 
1135
            }
 
1136
 
 
1137
            if(read(desc, buff, 126) != 126) { /* i.e. 0x69 + 13 + 8 */
 
1138
                cli_dbgmsg("UPX: Can't read 126 bytes at 0x%x (%d)\n", ep, ep);
 
1139
                cli_dbgmsg("UPX/FSG: Broken or not UPX/FSG compressed file\n");
 
1140
                free(section_hdr);
 
1141
                free(src);
 
1142
                free(dest);
 
1143
                return CL_CLEAN;
 
1144
            } else {
 
1145
                if(cli_memstr(UPX_NRV2B, 24, buff + 0x69, 13) || cli_memstr(UPX_NRV2B, 24, buff + 0x69 + 8, 13)) {
 
1146
                    cli_dbgmsg("UPX: Looks like a NRV2B decompression routine\n");
 
1147
                    upxfn = upx_inflate2b;
 
1148
                } else if(cli_memstr(UPX_NRV2D, 24, buff + 0x69, 13) || cli_memstr(UPX_NRV2D, 24, buff + 0x69 + 8, 13)) {
 
1149
                    cli_dbgmsg("UPX: Looks like a NRV2D decompression routine\n");
 
1150
                    upxfn = upx_inflate2d;
 
1151
                } else if(cli_memstr(UPX_NRV2E, 24, buff + 0x69, 13) || cli_memstr(UPX_NRV2E, 24, buff + 0x69 + 8, 13)) {
 
1152
                    cli_dbgmsg("UPX: Looks like a NRV2E decompression routine\n");
 
1153
                    upxfn = upx_inflate2e;
 
1154
                }
 
1155
            }
 
1156
 
 
1157
            if(upxfn) {
 
1158
                    int skew = cli_readint32(buff + 2) - EC32(optional_hdr.ImageBase) - EC32(section_hdr[i + 1].VirtualAddress);
 
1159
 
 
1160
                if(buff[1] != '\xbe' || skew <= 0 || skew > 0xfff) { /* FIXME: legit skews?? */
 
1161
                    skew = 0; 
 
1162
                    if(upxfn(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint)) >= 0)
 
1163
                        upx_success = 1;
 
1164
 
 
1165
                } else {
 
1166
                    cli_dbgmsg("UPX: UPX1 seems skewed by %d bytes\n", skew);
 
1167
                    if(upxfn(src + skew, ssize - skew, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint)-skew) >= 0 || upxfn(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint)) >= 0)
 
1168
                        upx_success = 1;
 
1169
                }
 
1170
 
 
1171
                if(upx_success)
 
1172
                    cli_dbgmsg("UPX: Successfully decompressed\n");
 
1173
                else
 
1174
                    cli_dbgmsg("UPX: Prefered decompressor failed\n");
 
1175
            }
 
1176
 
 
1177
            if(!upx_success && upxfn != upx_inflate2b) {
 
1178
                if(upx_inflate2b(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint)) == -1 && upx_inflate2b(src + 0x15, ssize - 0x15, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint) - 0x15) == -1) {
 
1179
 
 
1180
                    cli_dbgmsg("UPX: NRV2B decompressor failed\n");
 
1181
                } else {
 
1182
                    upx_success = 1;
 
1183
                    cli_dbgmsg("UPX: Successfully decompressed with NRV2B\n");
 
1184
                }
 
1185
            }
 
1186
 
 
1187
            if(!upx_success && upxfn != upx_inflate2d) {
 
1188
                if(upx_inflate2d(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint)) == -1 && upx_inflate2d(src + 0x15, ssize - 0x15, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint) - 0x15) == -1) {
 
1189
 
 
1190
                    cli_dbgmsg("UPX: NRV2D decompressor failed\n");
 
1191
                } else {
 
1192
                    upx_success = 1;
 
1193
                    cli_dbgmsg("UPX: Successfully decompressed with NRV2D\n");
 
1194
                }
 
1195
            }
 
1196
 
 
1197
            if(!upx_success && upxfn != upx_inflate2e) {
 
1198
                if(upx_inflate2e(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint)) == -1 && upx_inflate2e(src + 0x15, ssize - 0x15, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr.AddressOfEntryPoint) - 0x15) == -1) {
 
1199
                    cli_dbgmsg("UPX: NRV2E decompressor failed\n");
 
1200
                } else {
 
1201
                    upx_success = 1;
 
1202
                    cli_dbgmsg("UPX: Successfully decompressed with NRV2E\n");
 
1203
                }
 
1204
            }
 
1205
 
 
1206
            if(!upx_success) {
 
1207
                cli_dbgmsg("UPX: All decompressors failed\n");
 
1208
                free(src);
 
1209
                free(dest);
 
1210
            }
 
1211
        }
 
1212
 
 
1213
        if(upx_success) {
 
1214
            free(src);
 
1215
            free(section_hdr);
 
1216
 
 
1217
            tempfile = cli_gentemp(NULL);
 
1218
            if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC, S_IRWXU)) < 0) {
 
1219
                cli_dbgmsg("UPX/FSG: Can't create file %s\n", tempfile);
 
1220
                free(tempfile);
 
1221
                free(dest);
 
1222
                return CL_EIO;
 
1223
            }
 
1224
 
 
1225
            if((unsigned int) write(ndesc, dest, dsize) != dsize) {
 
1226
                cli_dbgmsg("UPX/FSG: Can't write %d bytes\n", dsize);
 
1227
                free(tempfile);
 
1228
                free(dest);
 
1229
                close(ndesc);
 
1230
                return CL_EIO;
 
1231
            }
 
1232
 
 
1233
            free(dest);
 
1234
            fsync(ndesc);
 
1235
            lseek(ndesc, 0, SEEK_SET);
 
1236
 
 
1237
            if(cli_leavetemps_flag)
 
1238
                cli_dbgmsg("UPX/FSG: Decompressed data saved in %s\n", tempfile);
 
1239
 
 
1240
            cli_dbgmsg("***** Scanning decompressed data *****\n");
 
1241
            if((ret = cli_magic_scandesc(ndesc, virname, scanned, root, limits, options, arec, mrec)) == CL_VIRUS) {
 
1242
                close(ndesc);
 
1243
                if(!cli_leavetemps_flag)
 
1244
                    unlink(tempfile);
 
1245
                free(tempfile);
 
1246
                return CL_VIRUS;
 
1247
            }
 
1248
 
 
1249
            close(ndesc);
 
1250
            if(!cli_leavetemps_flag)
 
1251
                unlink(tempfile);
 
1252
            free(tempfile);
 
1253
            return ret;
 
1254
        }
 
1255
    }
 
1256
 
 
1257
    /* Petite */
 
1258
 
 
1259
    found = 2;
 
1260
 
 
1261
    lseek(desc, ep, SEEK_SET);
 
1262
    if(read(desc, buff, 200) != 200) {
 
1263
        cli_dbgmsg("Can't read 200 bytes\n");
 
1264
        free(section_hdr);
 
1265
        return CL_EIO;
 
1266
    }
 
1267
 
 
1268
    if(buff[0] != '\xb8' || (uint32_t) cli_readint32(buff + 1) != EC32(section_hdr[nsections - 1].VirtualAddress) + EC32(optional_hdr.ImageBase)) {
 
1269
        if(nsections < 2 || buff[0] != '\xb8' || (uint32_t) cli_readint32(buff + 1) != EC32(section_hdr[nsections - 2].VirtualAddress) + EC32(optional_hdr.ImageBase))
 
1270
            found = 0;
 
1271
        else
 
1272
            found = 1;
 
1273
    }
 
1274
 
 
1275
    if(found) {
 
1276
        cli_dbgmsg("Petite: v2.%d compression detected\n", found);
 
1277
 
 
1278
        if(cli_readint32(buff + 0x80) == 0x163c988d) {
 
1279
            cli_dbgmsg("Petite: level zero compression is not supported yet\n");
 
1280
        } else {
 
1281
            dsize = max - min;
 
1282
 
 
1283
            if(limits && limits->maxfilesize && dsize > limits->maxfilesize) {
 
1284
                cli_dbgmsg("Petite: Size exceeded (dsize: %d, max: %lu)\n", dsize, limits->maxfilesize);
 
1285
                free(section_hdr);
 
1286
                return CL_CLEAN;
 
1287
            }
 
1288
 
 
1289
            if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
 
1290
                cli_dbgmsg("Petite: Can't allocate %d bytes\n", dsize);
 
1291
                free(section_hdr);
 
1292
                return CL_EMEM;
 
1293
            }
 
1294
 
 
1295
            for(i = 0 ; i < nsections; i++) {
 
1296
                if(section_hdr[i].SizeOfRawData) {
 
1297
                        uint32_t offset = cli_rawaddr(EC32(section_hdr[i].VirtualAddress), section_hdr, nsections, &err);
 
1298
 
 
1299
                    if(err || lseek(desc, offset, SEEK_SET) == -1 || (unsigned int) read(desc, dest + EC32(section_hdr[i].VirtualAddress) - min, EC32(section_hdr[i].SizeOfRawData)) != EC32(section_hdr[i].SizeOfRawData)) {
 
1300
                        free(section_hdr);
 
1301
                        free(dest);
 
1302
                        return CL_EIO;
 
1303
                    }
 
1304
                }
 
1305
            }
 
1306
 
 
1307
            tempfile = cli_gentemp(NULL);
 
1308
            if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC, S_IRWXU)) < 0) {
 
1309
                cli_dbgmsg("Petite: Can't create file %s\n", tempfile);
 
1310
                free(tempfile);
 
1311
                free(section_hdr);
 
1312
                free(dest);
 
1313
                return CL_EIO;
 
1314
            }
 
1315
 
 
1316
            /* aCaB: Fixed to allow petite v2.1 unpacking (last section is a ghost) */
 
1317
            switch(petite_inflate2x_1to9(dest, min, max - min, section_hdr,
 
1318
                    nsections - (found == 1 ? 1 : 0), EC32(optional_hdr.ImageBase),
 
1319
                    EC32(optional_hdr.AddressOfEntryPoint), ndesc,
 
1320
                    found, EC32(optional_hdr.DataDirectory[2].VirtualAddress),
 
1321
                    EC32(optional_hdr.DataDirectory[2].Size))) {
 
1322
                case 1:
 
1323
                    cli_dbgmsg("Petite: Unpacked and rebuilt executable saved in %s\n", tempfile);
 
1324
                    cli_dbgmsg("***** Scanning rebuilt PE file *****\n");
 
1325
                    break;
 
1326
 
 
1327
                case 0:
 
1328
                    cli_dbgmsg("Petite: Unpacked data saved in %s\n", tempfile);
 
1329
                    break;
 
1330
 
 
1331
                default:
 
1332
                    cli_dbgmsg("Petite: Unpacking failed\n");
 
1333
            }
 
1334
 
 
1335
            free(dest);
 
1336
            fsync(ndesc);
 
1337
            lseek(ndesc, 0, SEEK_SET);
 
1338
 
 
1339
            if(cli_magic_scandesc(ndesc, virname, scanned, root, limits, options, arec, mrec) == CL_VIRUS) {
 
1340
                free(section_hdr);
 
1341
                close(ndesc);
 
1342
                if(!cli_leavetemps_flag) {
 
1343
                    unlink(tempfile);
 
1344
                    free(tempfile);
 
1345
                } else {
 
1346
                    free(tempfile);
 
1347
                }
 
1348
                return CL_VIRUS;
 
1349
            }
 
1350
 
 
1351
            close(ndesc);
 
1352
 
 
1353
            if(!cli_leavetemps_flag) {
 
1354
                unlink(tempfile);
 
1355
                free(tempfile);
 
1356
            } else {
 
1357
                free(tempfile);
 
1358
            }
 
1359
        }
 
1360
    }
 
1361
 
 
1362
    /* to be continued ... */
 
1363
 
 
1364
    free(section_hdr);
 
1365
    return CL_CLEAN;
 
1366
}
 
1367
 
 
1368
int cli_peheader(int desc, struct cli_pe_info *peinfo)
 
1369
{
 
1370
        uint16_t e_magic; /* DOS signature ("MZ") */
 
1371
        uint32_t e_lfanew; /* address of new exe header */
 
1372
        uint32_t min, max;
 
1373
        struct pe_image_file_hdr file_hdr;
 
1374
        struct pe_image_optional_hdr optional_hdr;
 
1375
        struct pe_image_section_hdr *section_hdr;
 
1376
        struct stat sb;
 
1377
        int i;
 
1378
        unsigned int err;
 
1379
 
 
1380
 
 
1381
    cli_dbgmsg("in cli_peheader\n");
 
1382
 
 
1383
    if(read(desc, &e_magic, sizeof(e_magic)) != sizeof(e_magic)) {
 
1384
        cli_dbgmsg("Can't read DOS signature\n");
 
1385
        return -1;
 
1386
    }
 
1387
 
 
1388
    if(EC16(e_magic) != IMAGE_DOS_SIGNATURE && EC16(e_magic) != IMAGE_DOS_SIGNATURE_OLD) {
 
1389
        cli_dbgmsg("Invalid DOS signature\n");
 
1390
        return -1;
 
1391
    }
 
1392
 
 
1393
    lseek(desc, 58, SEEK_CUR); /* skip to the end of the DOS header */
 
1394
 
 
1395
    if(read(desc, &e_lfanew, sizeof(e_lfanew)) != sizeof(e_lfanew)) {
 
1396
        cli_dbgmsg("Can't read new header address\n");
 
1397
        /* truncated header? */
 
1398
        return -1;
 
1399
    }
 
1400
 
 
1401
    e_lfanew = EC32(e_lfanew);
 
1402
    if(!e_lfanew) {
 
1403
        cli_dbgmsg("Not a PE file\n");
 
1404
        return -1;
 
1405
    }
 
1406
 
 
1407
    if(lseek(desc, e_lfanew, SEEK_SET) < 0) {
 
1408
        /* probably not a PE file */
 
1409
        cli_dbgmsg("Can't lseek to e_lfanew\n");
 
1410
        return -1;
 
1411
    }
 
1412
 
 
1413
    if(read(desc, &file_hdr, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) {
 
1414
        /* bad information in e_lfanew - probably not a PE file */
 
1415
        cli_dbgmsg("Can't read file header\n");
 
1416
        return -1;
 
1417
    }
 
1418
 
 
1419
    if(EC32(file_hdr.Magic) != IMAGE_NT_SIGNATURE) {
 
1420
        cli_dbgmsg("Invalid PE signature (probably NE file)\n");
 
1421
        return -1;
 
1422
    }
 
1423
 
 
1424
    if(EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr)) {
 
1425
        cli_warnmsg("Broken PE header detected.\n");
 
1426
        return -1;
 
1427
    }
 
1428
 
 
1429
    peinfo->nsections = EC16(file_hdr.NumberOfSections);
 
1430
 
 
1431
    if(read(desc, &optional_hdr, sizeof(struct pe_image_optional_hdr)) != sizeof(struct pe_image_optional_hdr)) {
 
1432
        cli_dbgmsg("Can't optional file header\n");
 
1433
        return -1;
 
1434
    }
 
1435
 
 
1436
    peinfo->section = (struct SECTION *) cli_calloc(peinfo->nsections, sizeof(struct SECTION));
 
1437
 
 
1438
    if(!peinfo->section) {
 
1439
        cli_dbgmsg("Can't allocate memory for section headers\n");
 
1440
        return -1;
 
1441
    }
 
1442
 
 
1443
    if(fstat(desc, &sb) == -1) {
 
1444
        cli_dbgmsg("fstat failed\n");
 
1445
        free(peinfo->section);
 
1446
        return -1;
 
1447
    }
 
1448
 
 
1449
    section_hdr = (struct pe_image_section_hdr *) cli_calloc(peinfo->nsections, sizeof(struct pe_image_section_hdr));
 
1450
 
 
1451
    if(!section_hdr) {
 
1452
        cli_dbgmsg("Can't allocate memory for section headers\n");
 
1453
        free(peinfo->section);
 
1454
        return -1;
 
1455
    }
 
1456
 
 
1457
    for(i = 0; i < peinfo->nsections; i++) {
 
1458
 
 
1459
        if(read(desc, &section_hdr[i], sizeof(struct pe_image_section_hdr)) != sizeof(struct pe_image_section_hdr)) {
 
1460
            cli_dbgmsg("Can't read section header\n");
 
1461
            cli_dbgmsg("Possibly broken PE file\n");
 
1462
            free(section_hdr);
 
1463
            free(peinfo->section);
 
1464
            return -1;
 
1465
        }
 
1466
 
 
1467
        peinfo->section[i].rva = EC32(section_hdr[i].VirtualAddress);
 
1468
        peinfo->section[i].vsz = EC32(section_hdr[i].VirtualSize);
 
1469
        peinfo->section[i].raw = EC32(section_hdr[i].PointerToRawData);
 
1470
        peinfo->section[i].rsz = EC32(section_hdr[i].SizeOfRawData);
 
1471
 
 
1472
        if(!i) {
 
1473
            min = EC32(section_hdr[i].VirtualAddress);
 
1474
            max = EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData);
 
1475
        } else {
 
1476
            if(EC32(section_hdr[i].VirtualAddress) < min)
 
1477
                min = EC32(section_hdr[i].VirtualAddress);
 
1478
 
 
1479
            if(EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData) > max)
 
1480
                max = EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData);
 
1481
        }
 
1482
    }
 
1483
 
 
1484
    if((peinfo->ep = EC32(optional_hdr.AddressOfEntryPoint)) >= min && !(peinfo->ep = cli_rawaddr(EC32(optional_hdr.AddressOfEntryPoint), section_hdr, peinfo->nsections, &err)) && err) {
 
1485
        cli_dbgmsg("Possibly broken PE file\n");
 
1486
        free(section_hdr);
 
1487
        free(peinfo->section);
 
1488
        return -1;
 
1489
    }
 
1490
 
 
1491
    free(section_hdr);
 
1492
    return 0;
 
1493
}