libclamav/pe.c
6307ca15
 /*
46a35abe
  *  Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
2023340a
  *  Copyright (C) 2007-2008 Sourcefire, Inc.
  *
  *  Authors: Alberto Wu, Tomasz Kojm
5eb34fac
  *
6307ca15
  *  This program is free software; you can redistribute it and/or modify
2023340a
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
6307ca15
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
48b7b4a7
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  *  MA 02110-1301, USA.
6307ca15
  */
b9f41ff4
 /*
   Portions of Code (i.e. pe_ordinal) Copyright (c) 2014. The YARA Authors. All Rights Reserved.
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at
 
   http://www.apache.org/licenses/LICENSE-2.0
 
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
6307ca15
 
 #if HAVE_CONFIG_H
 #include "clamav-config.h"
 #endif
cd94be7a
 
 /*
42d26ac9
 #define _XOPEN_SOURCE 500
cd94be7a
 */
 
6307ca15
 #include <stdio.h>
cd94be7a
 #include <stdlib.h>
 
f377e052
 #if HAVE_STRING_H
6307ca15
 #include <string.h>
f377e052
 #endif
cd94be7a
 
6307ca15
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
3fcb62ca
 #ifdef HAVE_UNISTD_H
6307ca15
 #include <unistd.h>
3fcb62ca
 #endif
6307ca15
 #include <time.h>
95e31dc7
 #include <stdarg.h>
6307ca15
 
 #include "cltypes.h"
 #include "clamav.h"
 #include "others.h"
85dd8460
 #include "pe.h"
 #include "petite.h"
5f1a932b
 #include "fsg.h"
c2dfe70e
 #include "spin.h"
822930fc
 #include "upx.h"
 #include "yc.h"
2f73b977
 #include "aspack.h"
60cd49c9
 #include "wwunpack.h"
81030038
 #include "unsp.h"
85dd8460
 #include "scanners.h"
41fd7c2f
 #include "str.h"
01302683
 #include "execs.h"
4aa4a05c
 #include "mew.h"
e8042398
 #include "upack.h"
0a3d4094
 #include "matcher.h"
3faa9783
 #include "matcher-hash.h"
7f67d9e3
 #include "disasm.h"
42d26ac9
 #include "special.h"
56e5821b
 #include "ishield.h"
0393aa56
 #include "asn1.h"
6307ca15
 
172c4dd2
 #include "json_api.h"
 
bc93eda0
 #define DCONF ctx->dconf->pe
 
3b857f14
 #define PE_IMAGE_DOS_SIGNATURE	    0x5a4d	    /* MZ */
 #define PE_IMAGE_DOS_SIGNATURE_OLD  0x4d5a          /* ZM */
 #define PE_IMAGE_NT_SIGNATURE	    0x00004550
667a4b35
 #define PE32_SIGNATURE		    0x010b
 #define PE32P_SIGNATURE		    0x020b
6307ca15
 
a9b1e8d2
 #define optional_hdr64 pe_opt.opt64
 #define optional_hdr32 pe_opt.opt32
 
ce389c9c
 #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"
 #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"
 #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"
f2b223fe
 #define UPX_LZMA1 "\x56\x83\xc3\x04\x53\x50\xc7\x03\x03\x00\x02\x00\x90\x90\x90\x55\x57\x56\x53\x83"
 #define UPX_LZMA2 "\x56\x83\xc3\x04\x53\x50\xc7\x03\x03\x00\x02\x00\x90\x90\x90\x90\x90\x55\x57\x56"
342e27a5
 
7959fb61
 #define PE_MAXNAMESIZE 256
 #define PE_MAXIMPORTS  1024
 
0a23f3d9
 #define EC64(x) ((uint64_t)cli_readint64(&(x))) /* Convert little endian to host */
 #define EC32(x) ((uint32_t)cli_readint32(&(x)))
09f20cb6
 #define EC16(x) ((uint16_t)cli_readint16(&(x)))
81030038
 /* lower and upper bondary alignment (size vs offset) */
 #define PEALIGN(o,a) (((a))?(((o)/(a))*(a)):(o))
 #define PESALIGN(o,a) (((a))?(((o)/(a)+((o)%(a)!=0))*(a)):(o))
a9082ea2
 
95e31dc7
 #define CLI_UNPSIZELIMITS(NAME,CHK) \
850db69e
 if(cli_checklimits(NAME, ctx, (CHK), 0, 0)!=CL_CLEAN) {	\
     free(exe_sections);					\
     return CL_CLEAN;					\
95e31dc7
 }
 
61894353
 #define CLI_UNPTEMP(NAME,FREEME) \
33068e09
 if(!(tempfile = cli_gentemp(ctx->engine->tmpdir))) { \
61894353
     cli_multifree FREEME; \
95e31dc7
     return CL_EMEM; \
 } \
 if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) { \
     cli_dbgmsg(NAME": Can't create file %s\n", tempfile); \
61894353
     free(tempfile); \
     cli_multifree FREEME; \
871177cd
     return CL_ECREAT; \
95e31dc7
 }
 
33068e09
 #define CLI_TMPUNLK() if(!ctx->engine->keeptmp) { \
997a0e0b
     if (cli_unlink(tempfile)) { \
017f3490
         free(tempfile); \
         return CL_EUNLINK; \
997a0e0b
     } \
 }
95e31dc7
 
16b28d07
 #ifdef HAVE__INTERNAL__SHA_COLLECT
 #define SHA_OFF do { ctx->sha_collect = -1; } while(0)
 #define SHA_RESET do { ctx->sha_collect = sha_collect; } while(0)
 #else
 #define SHA_OFF do {} while(0)
 #define SHA_RESET do {} while(0)
 #endif
 
95e31dc7
 #define FSGCASE(NAME,FREESEC) \
     case 0: /* Unpacked and NOT rebuilt */ \
017f3490
     cli_dbgmsg(NAME": Successfully decompressed\n"); \
     close(ndesc); \
     if (cli_unlink(tempfile)) { \
         free(exe_sections); \
         free(tempfile); \
         FREESEC; \
         return CL_EUNLINK; \
     } \
     free(tempfile); \
     FREESEC; \
     found = 0; \
     upx_success = 1; \
     break; /* FSG ONLY! - scan raw data after upx block */
95e31dc7
 
 #define SPINCASE() \
     case 2: \
017f3490
     free(spinned); \
     close(ndesc); \
     if (cli_unlink(tempfile)) { \
         free(exe_sections); \
         free(tempfile); \
         return CL_EUNLINK; \
     } \
     cli_dbgmsg("PESpin: Size exceeded\n"); \
     free(tempfile); \
     break; \
95e31dc7
 
61894353
 #define CLI_UNPRESULTS_(NAME,FSGSTUFF,EXPR,GOOD,FREEME) \
95e31dc7
     switch(EXPR) { \
     case GOOD: /* Unpacked and rebuilt */ \
017f3490
         if(ctx->engine->keeptmp) \
             cli_dbgmsg(NAME": Unpacked and rebuilt executable saved in %s\n", tempfile); \
         else \
             cli_dbgmsg(NAME": Unpacked and rebuilt executable\n"); \
         cli_multifree FREEME; \
61894353
         free(exe_sections); \
017f3490
         lseek(ndesc, 0, SEEK_SET); \
         cli_dbgmsg("***** Scanning rebuilt PE file *****\n"); \
         SHA_OFF; \
         if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) { \
             close(ndesc); \
             CLI_TMPUNLK(); \
             free(tempfile); \
             SHA_RESET; \
             return CL_VIRUS; \
         } \
         SHA_RESET; \
         close(ndesc); \
         CLI_TMPUNLK(); \
         free(tempfile); \
         return CL_CLEAN; \
95e31dc7
 \
61894353
 FSGSTUFF; \
95e31dc7
 \
     default: \
017f3490
         cli_dbgmsg(NAME": Unpacking failed\n"); \
         close(ndesc); \
         if (cli_unlink(tempfile)) { \
             free(exe_sections); \
             free(tempfile); \
             cli_multifree FREEME; \
             return CL_EUNLINK; \
         } \
         cli_multifree FREEME; \
61894353
         free(tempfile); \
95e31dc7
     }
 
 
5a1034b9
 #define CLI_UNPRESULTS(NAME,EXPR,GOOD,FREEME) CLI_UNPRESULTS_(NAME,(void)0,EXPR,GOOD,FREEME)
61894353
 #define CLI_UNPRESULTSFSG1(NAME,EXPR,GOOD,FREEME) CLI_UNPRESULTS_(NAME,FSGCASE(NAME,free(sections)),EXPR,GOOD,FREEME)
5a1034b9
 #define CLI_UNPRESULTSFSG2(NAME,EXPR,GOOD,FREEME) CLI_UNPRESULTS_(NAME,FSGCASE(NAME,(void)0),EXPR,GOOD,FREEME)
a9082ea2
 
c6b9d863
 #define DETECT_BROKEN_PE (DETECT_BROKEN && !ctx->corrupted_input)
 
8cb85148
 extern const unsigned int hashlen[];
 
be62f8ce
 struct offset_list {
     uint32_t offset;
     struct offset_list *next;
 };
 
7478245e
 struct pe_image_import_descriptor {
     union {
         uint32_t Characteristics;
         uint32_t OriginalFirstThunk;
     } u;
     uint32_t TimeDateStamp;
     uint32_t ForwarderChain;
     uint32_t Name;
     uint32_t FirstThunk;
 };
 
e27ec91e
 #define PE_IMAGEDIR_ORDINAL_FLAG32  0x80000000
 #define PE_IMAGEDIR_ORDINAL_FLAG64  0x8000000000000000L
7478245e
 
 struct pe_image_thunk32 {
     union {
         uint32_t ForwarderString;
         uint32_t Function;
         uint32_t Ordinal;
         uint32_t AddressOfData;
     } u;
 };
 
 struct pe_image_thunk64 {
     union {
         uint64_t ForwarderString;
         uint64_t Function;
         uint64_t Ordinal;
         uint64_t AddressOfData;
     } u;
 };
 
 struct pe_image_import_by_name {
     uint16_t Hint;
     uint8_t Name[1];
 };
 
95e31dc7
 static void cli_multifree(void *f, ...) {
     void *ff;
     va_list ap;
     free(f);
     va_start(ap, f);
     while((ff=va_arg(ap, void*))) free(ff);
     va_end(ap);
 }
 
85310158
 struct vinfo_list {
     uint32_t rvas[16];
     unsigned int count;
 };
 
b33354e5
 static int versioninfo_cb(void *opaque, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva) {
85310158
     struct vinfo_list *vlist = (struct vinfo_list *)opaque;
 
1e7afd20
     cli_dbgmsg("versioninfo_cb: type: %x, name: %x, lang: %x, rva: %x\n", type, name, lang, rva);
85310158
     vlist->rvas[vlist->count] = rva;
     if(++vlist->count == sizeof(vlist->rvas) / sizeof(vlist->rvas[0]))
017f3490
         return 1;
f018e8b1
     return 0;
 }
 
 
c80f26a2
 uint32_t cli_rawaddr(uint32_t rva, const struct cli_exe_section *shp, uint16_t nos, unsigned int *err, size_t fsize, uint32_t hdr_size)
ac75a532
 {
95e31dc7
     int i, found = 0;
     uint32_t ret;
ac75a532
 
5deedfa5
     if (rva<hdr_size) { /* Out of section EP - mapped to imagebase+rva */
017f3490
         if (rva >= fsize) {
             *err=1;
             return 0;
         }
 
57866af1
         *err=0;
017f3490
         return rva;
57866af1
     }
ac75a532
 
57866af1
     for(i = nos-1; i >= 0; i--) {
         if(shp[i].rsz && shp[i].rva <= rva && shp[i].rsz > rva - shp[i].rva) {
017f3490
             found = 1;
             break;
         }
ac75a532
     }
 
     if(!found) {
017f3490
         *err = 1;
         return 0;
ac75a532
     }
 
57866af1
     ret = rva - shp[i].rva + shp[i].raw;
33f89aa5
     *err = 0;
57866af1
     return ret;
ac75a532
 }
 
235464bb
 /* 
    void findres(uint32_t by_type, uint32_t by_name, uint32_t res_rva, cli_ctx *ctx, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size, int (*cb)(void *, uint32_t, uint32_t, uint32_t, uint32_t), void *opaque)
    callback based res lookup
 
    by_type: lookup type
    by_name: lookup name or (unsigned)-1 to look for any name
    res_rva: base resource rva (i.e. dirs[2].VirtualAddress)
    ctx, exe_sections, nsections, hdr_size: same as in scanpe
    cb: the callback function executed on each successful match
    opaque: an opaque pointer passed to the callback
 
    the callback proto is
    int pe_res_cballback (void *opaque, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva);
    the callback shall return 0 to continue the lookup or 1 to abort
 */
d2ba6f98
 void findres(uint32_t by_type, uint32_t by_name, uint32_t res_rva, fmap_t *map, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size, int (*cb)(void *, uint32_t, uint32_t, uint32_t, uint32_t), void *opaque) {
235464bb
     unsigned int err = 0;
     uint32_t type, type_offs, name, name_offs, lang, lang_offs;
f304dc68
     const uint8_t *resdir, *type_entry, *name_entry, *lang_entry ;
235464bb
     uint16_t type_cnt, name_cnt, lang_cnt;
 
     if (!(resdir = fmap_need_off_once(map, cli_rawaddr(res_rva, exe_sections, nsections, &err, map->len, hdr_size), 16)) || err)
 	return;
 
     type_cnt = (uint16_t)cli_readint16(resdir+12);
     type_entry = resdir+16;
     if(!(by_type>>31)) {
 	type_entry += type_cnt * 8;
 	type_cnt = (uint16_t)cli_readint16(resdir+14);
     }
 
     while(type_cnt--) {
 	if(!fmap_need_ptr_once(map, type_entry, 8))
 	    return;
 	type = cli_readint32(type_entry);
 	type_offs = cli_readint32(type_entry+4);
 	if(type == by_type && (type_offs>>31)) {
 	    type_offs &= 0x7fffffff;
 	    if (!(resdir = fmap_need_off_once(map, cli_rawaddr(res_rva + type_offs, exe_sections, nsections, &err, map->len, hdr_size), 16)) || err)
 		return;
 
 	    name_cnt = (uint16_t)cli_readint16(resdir+12);
 	    name_entry = resdir+16;
 	    if(by_name == 0xffffffff)
 		name_cnt += (uint16_t)cli_readint16(resdir+14);
 	    else if(!(by_name>>31)) {
 		name_entry += name_cnt * 8;
 		name_cnt = (uint16_t)cli_readint16(resdir+14);
 	    }
 	    while(name_cnt--) {
 		if(!fmap_need_ptr_once(map, name_entry, 8))
 		    return;
 		name = cli_readint32(name_entry);
 		name_offs = cli_readint32(name_entry+4);
 		if((by_name == 0xffffffff || name == by_name) && (name_offs>>31)) {
 		    name_offs &= 0x7fffffff;
 		    if (!(resdir = fmap_need_off_once(map, cli_rawaddr(res_rva + name_offs, exe_sections, nsections, &err, map->len, hdr_size), 16)) || err)
 			return;
 		    
 		    lang_cnt = (uint16_t)cli_readint16(resdir+12) + (uint16_t)cli_readint16(resdir+14);
 		    lang_entry = resdir+16;
 		    while(lang_cnt--) {
 			if(!fmap_need_ptr_once(map, lang_entry, 8))
 			    return;
 			lang = cli_readint32(lang_entry);
 			lang_offs = cli_readint32(lang_entry+4);
 			if(!(lang_offs >>31)) {
 			    if(cb(opaque, type, name, lang, res_rva + lang_offs))
 				return;
 			}
 			lang_entry += 8;
 		    }
 		}
 		name_entry += 8;
 	    }
 	    return; /* FIXME: unless we want to find ALL types */
 	}
 	type_entry += 8;
     }
 }
 
49cc1e3c
 static void cli_parseres_special(uint32_t base, uint32_t rva, fmap_t *map, struct cli_exe_section *exe_sections, uint16_t nsections, size_t fsize, uint32_t hdr_size, unsigned int level, uint32_t type, unsigned int *maxres, struct swizz_stats *stats) {
42d26ac9
     unsigned int err = 0, i;
f304dc68
     const uint8_t *resdir;
     const uint8_t *entry, *oentry;
42d26ac9
     uint16_t named, unnamed;
     uint32_t rawaddr = cli_rawaddr(rva, exe_sections, nsections, &err, fsize, hdr_size);
     uint32_t entries;
 
     if(level>2 || !*maxres) return;
     *maxres-=1;
a5241d27
     if(err || !(resdir = fmap_need_off_once(map, rawaddr, 16)))
42d26ac9
 	    return;
     named = (uint16_t)cli_readint16(resdir+12);
     unnamed = (uint16_t)cli_readint16(resdir+14);
 
     entries = /*named+*/unnamed;
     if (!entries)
 	    return;
     rawaddr += named*8; /* skip named */
     /* this is just used in a heuristic detection, so don't give error on failure */
a5241d27
     if(!(entry = fmap_need_off(map, rawaddr+16, entries*8))) {
42d26ac9
 	    cli_dbgmsg("cli_parseres_special: failed to read resource directory at:%lu\n", (unsigned long)rawaddr+16);
 	    return;
     }
a5241d27
     oentry = entry;
42d26ac9
     /*for (i=0; i<named; i++) {
 	uint32_t id, offs;
 	id = cli_readint32(entry);
 	offs = cli_readint32(entry+4);
 	if(offs>>31)
 	    cli_parseres( base, base + (offs&0x7fffffff), srcfd, exe_sections, nsections, fsize, hdr_size, level+1, type, maxres, stats);
 	entry+=8;
     }*/
188914fe
     for (i=0; i<unnamed; i++, entry += 8) {
42d26ac9
 	uint32_t id, offs;
e6d1a8b7
 	if (stats->errors >= SWIZZ_MAXERRORS) {
 	    cli_dbgmsg("cli_parseres_special: resources broken, ignoring\n");
 	    return;
 	}
42d26ac9
 	id = cli_readint32(entry)&0x7fffffff;
 	if(level==0) {
188914fe
 		type = 0;
42d26ac9
 		switch(id) {
 			case 4: /* menu */
 			case 5: /* dialog */
 			case 6: /* string */
 			case 11:/* msgtable */
 				type = id;
 				break;
 			case 16:
188914fe
 				type = id;
42d26ac9
 				/* 14: version */
 				stats->has_version = 1;
 				break;
 			case 24: /* manifest */
 				stats->has_manifest = 1;
 				break;
 			/* otherwise keep it 0, we don't want it */
 		}
188914fe
 	}
 	if (!type) {
42d26ac9
 		/* if we are not interested in this type, skip */
 		continue;
 	}
 	offs = cli_readint32(entry+4);
 	if(offs>>31)
a5241d27
 		cli_parseres_special(base, base + (offs&0x7fffffff), map, exe_sections, nsections, fsize, hdr_size, level+1, type, maxres, stats);
42d26ac9
 	else {
 			offs = cli_readint32(entry+4);
 			rawaddr = cli_rawaddr(base + offs, exe_sections, nsections, &err, fsize, hdr_size);
a5241d27
 			if (!err && (resdir = fmap_need_off_once(map, rawaddr, 16))) {
42d26ac9
 				uint32_t isz = cli_readint32(resdir+4);
f304dc68
 				const uint8_t *str;
42d26ac9
 				rawaddr = cli_rawaddr(cli_readint32(resdir), exe_sections, nsections, &err, fsize, hdr_size);
646c2a48
 				if (err || !isz || isz >= fsize || rawaddr+isz >= fsize) {
42d26ac9
 					cli_dbgmsg("cli_parseres_special: invalid resource table entry: %lu + %lu\n", 
 							(unsigned long)rawaddr, 
 							(unsigned long)isz);
e6d1a8b7
 					stats->errors++;
42d26ac9
 					continue;
 				}
271f08e5
 				if ((id&0xff) != 0x09) /* english res only */
 				    continue;
a5241d27
 				if((str = fmap_need_off_once(map, rawaddr, isz)))
42d26ac9
 					cli_detect_swizz_str(str, isz, stats, type);
 			}
 	}
     }
a5241d27
     fmap_unneed_ptr(map, oentry, entries*8);
42d26ac9
 }
 
e37613ad
 static unsigned int cli_hashsect(fmap_t *map, struct cli_exe_section *s, unsigned char **digest, int * foundhash, int * foundwild)
 {
     const void *hashme;
 
     if (s->rsz > CLI_MAX_ALLOCATION) {
         cli_dbgmsg("cli_hashsect: skipping hash calculation for too big section\n");
         return 0;
     }
 
     if(!s->rsz) return 0;
     if(!(hashme=fmap_need_off_once(map, s->raw, s->rsz))) {
         cli_dbgmsg("cli_hashsect: unable to read section data\n");
         return 0;
     }
 
b2e7c931
     if(foundhash[CLI_HASH_MD5] || foundwild[CLI_HASH_MD5])
         cl_hash_data("md5", hashme, s->rsz, digest[CLI_HASH_MD5], NULL);
     if(foundhash[CLI_HASH_SHA1] || foundwild[CLI_HASH_SHA1])
         cl_sha1(hashme, s->rsz, digest[CLI_HASH_SHA1], NULL);
     if(foundhash[CLI_HASH_SHA256] || foundwild[CLI_HASH_SHA256])
         cl_sha256(hashme, s->rsz, digest[CLI_HASH_SHA256], NULL);
e37613ad
 
     return 1;
 }
 
 /* check hash section sigs */
 static int scan_pe_mdb (cli_ctx * ctx, struct cli_exe_section *exe_section)
 {
     struct cli_matcher * mdb_sect = ctx->engine->hm_mdb;
     unsigned char * hashset[CLI_HASH_AVAIL_TYPES];
     const char * virname = NULL;
     int foundsize[CLI_HASH_AVAIL_TYPES];
     int foundwild[CLI_HASH_AVAIL_TYPES];
     enum CLI_HASH_TYPE type;
     int ret = CL_CLEAN;
8cb85148
     unsigned char * md5 = NULL;
e37613ad
  
     /* pick hashtypes to generate */
     for(type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
         foundsize[type] = cli_hm_have_size(mdb_sect, type, exe_section->rsz);
         foundwild[type] = cli_hm_have_wild(mdb_sect, type);
         if(foundsize[type] || foundwild[type]) {
8cb85148
             hashset[type] = cli_malloc(hashlen[type]);
e37613ad
             if(!hashset[type]) {
                 cli_errmsg("scan_pe: cli_malloc failed!\n");
                 for(; type > 0;)
                     free(hashset[--type]);
                 return CL_EMEM;
             }
         }
         else {
             hashset[type] = NULL;
         }
     }
 
     /* Generate hashes */
     cli_hashsect(*ctx->fmap, exe_section, hashset, foundsize, foundwild);
 
8cb85148
     /* Print hash */
     if (cli_debug_flag) {
         md5 = hashset[CLI_HASH_MD5];
3ca11170
         if (md5) {
d87dfbb2
             cli_dbgmsg("MDB hashset: %u:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
fea6f9a7
                 exe_section->rsz, md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], md5[7],
                 md5[8], md5[9], md5[10], md5[11], md5[12], md5[13], md5[14], md5[15]);
3ca11170
         } else if (cli_always_gen_section_hash) {
             const void *hashme = fmap_need_off_once(*ctx->fmap, exe_section->raw, exe_section->rsz);
             if (!(hashme)) {
                 cli_errmsg("scan_pe_mdb: unable to read section data\n");
                 ret = CL_EREAD;
                 goto end;
             }
 
             md5 = cli_malloc(16);
             if (!(md5)) {
                 cli_errmsg("scan_pe_mdb: cli_malloc failed!\n");
                 ret = CL_EMEM;
                 goto end;
             }
 
b2e7c931
             cl_hash_data("md5", hashme, exe_section->rsz, md5, NULL);
3ca11170
 
             cli_dbgmsg("MDB: %u:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
                 exe_section->rsz, md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], md5[7],
                 md5[8], md5[9], md5[10], md5[11], md5[12], md5[13], md5[14], md5[15]);
 
             free(md5);
 
         } else {
fea6f9a7
             cli_dbgmsg("MDB: %u:notgenerated\n", exe_section->rsz);
3ca11170
         }
8cb85148
     }
 
e37613ad
     /* Do scans */
     for(type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
        if(foundsize[type] && cli_hm_scan(hashset[type], exe_section->rsz, &virname, mdb_sect, type) == CL_VIRUS) {
d87dfbb2
             ret = cli_append_virus(ctx, virname);
             if (ret != CL_CLEAN) {
                 if (ret != CL_VIRUS)
                     break;
                 else if (!SCAN_ALL)
                     break;
e37613ad
             }
        }
        if(foundwild[type] && cli_hm_scan_wild(hashset[type], &virname, mdb_sect, type) == CL_VIRUS) {
d87dfbb2
             ret = cli_append_virus(ctx, virname);
             if (ret != CL_CLEAN) {
                 if (ret != CL_VIRUS)
                     break;
                 else if (!SCAN_ALL)
                     break;
e37613ad
             }
        }
     }
 
3ca11170
 end:
efdb83da
     for(type = CLI_HASH_AVAIL_TYPES; type > 0;)
         free(hashset[--type]);
e37613ad
     return ret;
 }
 
7478245e
 /* imptbl scanning */
0a23f3d9
 static char *pe_ordinal(const char *dll, uint16_t ord)
7478245e
 {
   char name[64];
   name[0] = '\0';
 
   if (strncasecmp(dll, "WS2_32.dll", 10) == 0 ||
       strncasecmp(dll, "wsock32.dll", 11) == 0)
   {
     switch(ord) {
       case 1:
         sprintf(name, "accept");
         break;
       case 2:
         sprintf(name, "bind");
         break;
       case 3:
         sprintf(name, "closesocket");
         break;
       case 4:
         sprintf(name, "connect");
         break;
       case 5:
         sprintf(name, "getpeername");
         break;
       case 6:
         sprintf(name, "getsockname");
         break;
       case 7:
         sprintf(name, "getsockopt");
         break;
       case 8:
         sprintf(name, "htonl");
         break;
       case 9:
         sprintf(name, "htons");
         break;
       case 10:
         sprintf(name, "ioctlsocket");
         break;
       case 11:
         sprintf(name, "inet_addr");
         break;
       case 12:
         sprintf(name, "inet_ntoa");
         break;
       case 13:
         sprintf(name, "listen");
         break;
       case 14:
         sprintf(name, "ntohl");
         break;
       case 15:
         sprintf(name, "ntohs");
         break;
       case 16:
         sprintf(name, "recv");
         break;
       case 17:
         sprintf(name, "recvfrom");
         break;
       case 18:
         sprintf(name, "select");
         break;
       case 19:
         sprintf(name, "send");
         break;
       case 20:
         sprintf(name, "sendto");
         break;
       case 21:
         sprintf(name, "setsockopt");
         break;
       case 22:
         sprintf(name, "shutdown");
         break;
       case 23:
         sprintf(name, "socket");
         break;
       case 24:
         sprintf(name, "GetAddrInfoW");
         break;
       case 25:
         sprintf(name, "GetNameInfoW");
         break;
       case 26:
         sprintf(name, "WSApSetPostRoutine");
         break;
       case 27:
         sprintf(name, "FreeAddrInfoW");
         break;
       case 28:
         sprintf(name, "WPUCompleteOverlappedRequest");
         break;
       case 29:
         sprintf(name, "WSAAccept");
         break;
       case 30:
         sprintf(name, "WSAAddressToStringA");
         break;
       case 31:
         sprintf(name, "WSAAddressToStringW");
         break;
       case 32:
         sprintf(name, "WSACloseEvent");
         break;
       case 33:
         sprintf(name, "WSAConnect");
         break;
       case 34:
         sprintf(name, "WSACreateEvent");
         break;
       case 35:
         sprintf(name, "WSADuplicateSocketA");
         break;
       case 36:
         sprintf(name, "WSADuplicateSocketW");
         break;
       case 37:
         sprintf(name, "WSAEnumNameSpaceProvidersA");
         break;
       case 38:
         sprintf(name, "WSAEnumNameSpaceProvidersW");
         break;
       case 39:
         sprintf(name, "WSAEnumNetworkEvents");
         break;
       case 40:
         sprintf(name, "WSAEnumProtocolsA");
         break;
       case 41:
         sprintf(name, "WSAEnumProtocolsW");
         break;
       case 42:
         sprintf(name, "WSAEventSelect");
         break;
       case 43:
         sprintf(name, "WSAGetOverlappedResult");
         break;
       case 44:
         sprintf(name, "WSAGetQOSByName");
         break;
       case 45:
         sprintf(name, "WSAGetServiceClassInfoA");
         break;
       case 46:
         sprintf(name, "WSAGetServiceClassInfoW");
         break;
       case 47:
         sprintf(name, "WSAGetServiceClassNameByClassIdA");
         break;
       case 48:
         sprintf(name, "WSAGetServiceClassNameByClassIdW");
         break;
       case 49:
         sprintf(name, "WSAHtonl");
         break;
       case 50:
         sprintf(name, "WSAHtons");
         break;
       case 51:
         sprintf(name, "gethostbyaddr");
         break;
       case 52:
         sprintf(name, "gethostbyname");
         break;
       case 53:
         sprintf(name, "getprotobyname");
         break;
       case 54:
         sprintf(name, "getprotobynumber");
         break;
       case 55:
         sprintf(name, "getservbyname");
         break;
       case 56:
         sprintf(name, "getservbyport");
         break;
       case 57:
         sprintf(name, "gethostname");
         break;
       case 58:
         sprintf(name, "WSAInstallServiceClassA");
         break;
       case 59:
         sprintf(name, "WSAInstallServiceClassW");
         break;
       case 60:
         sprintf(name, "WSAIoctl");
         break;
       case 61:
         sprintf(name, "WSAJoinLeaf");
         break;
       case 62:
         sprintf(name, "WSALookupServiceBeginA");
         break;
       case 63:
         sprintf(name, "WSALookupServiceBeginW");
         break;
       case 64:
         sprintf(name, "WSALookupServiceEnd");
         break;
       case 65:
         sprintf(name, "WSALookupServiceNextA");
         break;
       case 66:
         sprintf(name, "WSALookupServiceNextW");
         break;
       case 67:
         sprintf(name, "WSANSPIoctl");
         break;
       case 68:
         sprintf(name, "WSANtohl");
         break;
       case 69:
         sprintf(name, "WSANtohs");
         break;
       case 70:
         sprintf(name, "WSAProviderConfigChange");
         break;
       case 71:
         sprintf(name, "WSARecv");
         break;
       case 72:
         sprintf(name, "WSARecvDisconnect");
         break;
       case 73:
         sprintf(name, "WSARecvFrom");
         break;
       case 74:
         sprintf(name, "WSARemoveServiceClass");
         break;
       case 75:
         sprintf(name, "WSAResetEvent");
         break;
       case 76:
         sprintf(name, "WSASend");
         break;
       case 77:
         sprintf(name, "WSASendDisconnect");
         break;
       case 78:
         sprintf(name, "WSASendTo");
         break;
       case 79:
         sprintf(name, "WSASetEvent");
         break;
       case 80:
         sprintf(name, "WSASetServiceA");
         break;
       case 81:
         sprintf(name, "WSASetServiceW");
         break;
       case 82:
         sprintf(name, "WSASocketA");
         break;
       case 83:
         sprintf(name, "WSASocketW");
         break;
       case 84:
         sprintf(name, "WSAStringToAddressA");
         break;
       case 85:
         sprintf(name, "WSAStringToAddressW");
         break;
       case 86:
         sprintf(name, "WSAWaitForMultipleEvents");
         break;
       case 87:
         sprintf(name, "WSCDeinstallProvider");
         break;
       case 88:
         sprintf(name, "WSCEnableNSProvider");
         break;
       case 89:
         sprintf(name, "WSCEnumProtocols");
         break;
       case 90:
         sprintf(name, "WSCGetProviderPath");
         break;
       case 91:
         sprintf(name, "WSCInstallNameSpace");
         break;
       case 92:
         sprintf(name, "WSCInstallProvider");
         break;
       case 93:
         sprintf(name, "WSCUnInstallNameSpace");
         break;
       case 94:
         sprintf(name, "WSCUpdateProvider");
         break;
       case 95:
         sprintf(name, "WSCWriteNameSpaceOrder");
         break;
       case 96:
         sprintf(name, "WSCWriteProviderOrder");
         break;
       case 97:
         sprintf(name, "freeaddrinfo");
         break;
       case 98:
         sprintf(name, "getaddrinfo");
         break;
       case 99:
         sprintf(name, "getnameinfo");
         break;
       case 101:
         sprintf(name, "WSAAsyncSelect");
         break;
       case 102:
         sprintf(name, "WSAAsyncGetHostByAddr");
         break;
       case 103:
         sprintf(name, "WSAAsyncGetHostByName");
         break;
       case 104:
         sprintf(name, "WSAAsyncGetProtoByNumber");
         break;
       case 105:
         sprintf(name, "WSAAsyncGetProtoByName");
         break;
       case 106:
         sprintf(name, "WSAAsyncGetServByPort");
         break;
       case 107:
         sprintf(name, "WSAAsyncGetServByName");
         break;
       case 108:
         sprintf(name, "WSACancelAsyncRequest");
         break;
       case 109:
         sprintf(name, "WSASetBlockingHook");
         break;
       case 110:
         sprintf(name, "WSAUnhookBlockingHook");
         break;
       case 111:
         sprintf(name, "WSAGetLastError");
         break;
       case 112:
         sprintf(name, "WSASetLastError");
         break;
       case 113:
         sprintf(name, "WSACancelBlockingCall");
         break;
       case 114:
         sprintf(name, "WSAIsBlocking");
         break;
       case 115:
         sprintf(name, "WSAStartup");
         break;
       case 116:
         sprintf(name, "WSACleanup");
         break;
       case 151:
         sprintf(name, "__WSAFDIsSet");
         break;
       case 500:
         sprintf(name, "WEP");
         break;
       default:
         break;
     }
   }
   else if (strncasecmp(dll, "oleaut32.dll", 12) == 0)
   {
     switch (ord) {
       case 2:
         sprintf(name, "SysAllocString");
         break;
       case 3:
         sprintf(name, "SysReAllocString");
         break;
       case 4:
         sprintf(name, "SysAllocStringLen");
         break;
       case 5:
         sprintf(name, "SysReAllocStringLen");
         break;
       case 6:
         sprintf(name, "SysFreeString");
         break;
       case 7:
         sprintf(name, "SysStringLen");
         break;
       case 8:
         sprintf(name, "VariantInit");
         break;
       case 9:
         sprintf(name, "VariantClear");
         break;
       case 10:
         sprintf(name, "VariantCopy");
         break;
       case 11:
         sprintf(name, "VariantCopyInd");
         break;
       case 12:
         sprintf(name, "VariantChangeType");
         break;
       case 13:
         sprintf(name, "VariantTimeToDosDateTime");
         break;
       case 14:
         sprintf(name, "DosDateTimeToVariantTime");
         break;
       case 15:
         sprintf(name, "SafeArrayCreate");
         break;
       case 16:
         sprintf(name, "SafeArrayDestroy");
         break;
       case 17:
         sprintf(name, "SafeArrayGetDim");
         break;
       case 18:
         sprintf(name, "SafeArrayGetElemsize");
         break;
       case 19:
         sprintf(name, "SafeArrayGetUBound");
         break;
       case 20:
         sprintf(name, "SafeArrayGetLBound");
         break;
       case 21:
         sprintf(name, "SafeArrayLock");
         break;
       case 22:
         sprintf(name, "SafeArrayUnlock");
         break;
       case 23:
         sprintf(name, "SafeArrayAccessData");
         break;
       case 24:
         sprintf(name, "SafeArrayUnaccessData");
         break;
       case 25:
         sprintf(name, "SafeArrayGetElement");
         break;
       case 26:
         sprintf(name, "SafeArrayPutElement");
         break;
       case 27:
         sprintf(name, "SafeArrayCopy");
         break;
       case 28:
         sprintf(name, "DispGetParam");
         break;
       case 29:
         sprintf(name, "DispGetIDsOfNames");
         break;
       case 30:
         sprintf(name, "DispInvoke");
         break;
       case 31:
         sprintf(name, "CreateDispTypeInfo");
         break;
       case 32:
         sprintf(name, "CreateStdDispatch");
         break;
       case 33:
         sprintf(name, "RegisterActiveObject");
         break;
       case 34:
         sprintf(name, "RevokeActiveObject");
         break;
       case 35:
         sprintf(name, "GetActiveObject");
         break;
       case 36:
         sprintf(name, "SafeArrayAllocDescriptor");
         break;
       case 37:
         sprintf(name, "SafeArrayAllocData");
         break;
       case 38:
         sprintf(name, "SafeArrayDestroyDescriptor");
         break;
       case 39:
         sprintf(name, "SafeArrayDestroyData");
         break;
       case 40:
         sprintf(name, "SafeArrayRedim");
         break;
       case 41:
         sprintf(name, "SafeArrayAllocDescriptorEx");
         break;
       case 42:
         sprintf(name, "SafeArrayCreateEx");
         break;
       case 43:
         sprintf(name, "SafeArrayCreateVectorEx");
         break;
       case 44:
         sprintf(name, "SafeArraySetRecordInfo");
         break;
       case 45:
         sprintf(name, "SafeArrayGetRecordInfo");
         break;
       case 46:
         sprintf(name, "VarParseNumFromStr");
         break;
       case 47:
         sprintf(name, "VarNumFromParseNum");
         break;
       case 48:
         sprintf(name, "VarI2FromUI1");
         break;
       case 49:
         sprintf(name, "VarI2FromI4");
         break;
       case 50:
         sprintf(name, "VarI2FromR4");
         break;
       case 51:
         sprintf(name, "VarI2FromR8");
         break;
       case 52:
         sprintf(name, "VarI2FromCy");
         break;
       case 53:
         sprintf(name, "VarI2FromDate");
         break;
       case 54:
         sprintf(name, "VarI2FromStr");
         break;
       case 55:
         sprintf(name, "VarI2FromDisp");
         break;
       case 56:
         sprintf(name, "VarI2FromBool");
         break;
       case 57:
         sprintf(name, "SafeArraySetIID");
         break;
       case 58:
         sprintf(name, "VarI4FromUI1");
         break;
       case 59:
         sprintf(name, "VarI4FromI2");
         break;
       case 60:
         sprintf(name, "VarI4FromR4");
         break;
       case 61:
         sprintf(name, "VarI4FromR8");
         break;
       case 62:
         sprintf(name, "VarI4FromCy");
         break;
       case 63:
         sprintf(name, "VarI4FromDate");
         break;
       case 64:
         sprintf(name, "VarI4FromStr");
         break;
       case 65:
         sprintf(name, "VarI4FromDisp");
         break;
       case 66:
         sprintf(name, "VarI4FromBool");
         break;
       case 67:
         sprintf(name, "SafeArrayGetIID");
         break;
       case 68:
         sprintf(name, "VarR4FromUI1");
         break;
       case 69:
         sprintf(name, "VarR4FromI2");
         break;
       case 70:
         sprintf(name, "VarR4FromI4");
         break;
       case 71:
         sprintf(name, "VarR4FromR8");
         break;
       case 72:
         sprintf(name, "VarR4FromCy");
         break;
       case 73:
         sprintf(name, "VarR4FromDate");
         break;
       case 74:
         sprintf(name, "VarR4FromStr");
         break;
       case 75:
         sprintf(name, "VarR4FromDisp");
         break;
       case 76:
         sprintf(name, "VarR4FromBool");
         break;
       case 77:
         sprintf(name, "SafeArrayGetVartype");
         break;
       case 78:
         sprintf(name, "VarR8FromUI1");
         break;
       case 79:
         sprintf(name, "VarR8FromI2");
         break;
       case 80:
         sprintf(name, "VarR8FromI4");
         break;
       case 81:
         sprintf(name, "VarR8FromR4");
         break;
       case 82:
         sprintf(name, "VarR8FromCy");
         break;
       case 83:
         sprintf(name, "VarR8FromDate");
         break;
       case 84:
         sprintf(name, "VarR8FromStr");
         break;
       case 85:
         sprintf(name, "VarR8FromDisp");
         break;
       case 86:
         sprintf(name, "VarR8FromBool");
         break;
       case 87:
         sprintf(name, "VarFormat");
         break;
       case 88:
         sprintf(name, "VarDateFromUI1");
         break;
       case 89:
         sprintf(name, "VarDateFromI2");
         break;
       case 90:
         sprintf(name, "VarDateFromI4");
         break;
       case 91:
         sprintf(name, "VarDateFromR4");
         break;
       case 92:
         sprintf(name, "VarDateFromR8");
         break;
       case 93:
         sprintf(name, "VarDateFromCy");
         break;
       case 94:
         sprintf(name, "VarDateFromStr");
         break;
       case 95:
         sprintf(name, "VarDateFromDisp");
         break;
       case 96:
         sprintf(name, "VarDateFromBool");
         break;
       case 97:
         sprintf(name, "VarFormatDateTime");
         break;
       case 98:
         sprintf(name, "VarCyFromUI1");
         break;
       case 99:
         sprintf(name, "VarCyFromI2");
         break;
       case 100:
         sprintf(name, "VarCyFromI4");
         break;
       case 101:
         sprintf(name, "VarCyFromR4");
         break;
       case 102:
         sprintf(name, "VarCyFromR8");
         break;
       case 103:
         sprintf(name, "VarCyFromDate");
         break;
       case 104:
         sprintf(name, "VarCyFromStr");
         break;
       case 105:
         sprintf(name, "VarCyFromDisp");
         break;
       case 106:
         sprintf(name, "VarCyFromBool");
         break;
       case 107:
         sprintf(name, "VarFormatNumber");
         break;
       case 108:
         sprintf(name, "VarBstrFromUI1");
         break;
       case 109:
         sprintf(name, "VarBstrFromI2");
         break;
       case 110:
         sprintf(name, "VarBstrFromI4");
         break;
       case 111:
         sprintf(name, "VarBstrFromR4");
         break;
       case 112:
         sprintf(name, "VarBstrFromR8");
         break;
       case 113:
         sprintf(name, "VarBstrFromCy");
         break;
       case 114:
         sprintf(name, "VarBstrFromDate");
         break;
       case 115:
         sprintf(name, "VarBstrFromDisp");
         break;
       case 116:
         sprintf(name, "VarBstrFromBool");
         break;
       case 117:
         sprintf(name, "VarFormatPercent");
         break;
       case 118:
         sprintf(name, "VarBoolFromUI1");
         break;
       case 119:
         sprintf(name, "VarBoolFromI2");
         break;
       case 120:
         sprintf(name, "VarBoolFromI4");
         break;
       case 121:
         sprintf(name, "VarBoolFromR4");
         break;
       case 122:
         sprintf(name, "VarBoolFromR8");
         break;
       case 123:
         sprintf(name, "VarBoolFromDate");
         break;
       case 124:
         sprintf(name, "VarBoolFromCy");
         break;
       case 125:
         sprintf(name, "VarBoolFromStr");
         break;
       case 126:
         sprintf(name, "VarBoolFromDisp");
         break;
       case 127:
         sprintf(name, "VarFormatCurrency");
         break;
       case 128:
         sprintf(name, "VarWeekdayName");
         break;
       case 129:
         sprintf(name, "VarMonthName");
         break;
       case 130:
         sprintf(name, "VarUI1FromI2");
         break;
       case 131:
         sprintf(name, "VarUI1FromI4");
         break;
       case 132:
         sprintf(name, "VarUI1FromR4");
         break;
       case 133:
         sprintf(name, "VarUI1FromR8");
         break;
       case 134:
         sprintf(name, "VarUI1FromCy");
         break;
       case 135:
         sprintf(name, "VarUI1FromDate");
         break;
       case 136:
         sprintf(name, "VarUI1FromStr");
         break;
       case 137:
         sprintf(name, "VarUI1FromDisp");
         break;
       case 138:
         sprintf(name, "VarUI1FromBool");
         break;
       case 139:
         sprintf(name, "VarFormatFromTokens");
         break;
       case 140:
         sprintf(name, "VarTokenizeFormatString");
         break;
       case 141:
         sprintf(name, "VarAdd");
         break;
       case 142:
         sprintf(name, "VarAnd");
         break;
       case 143:
         sprintf(name, "VarDiv");
         break;
       case 144:
         sprintf(name, "DllCanUnloadNow");
         break;
       case 145:
         sprintf(name, "DllGetClassObject");
         break;
       case 146:
         sprintf(name, "DispCallFunc");
         break;
       case 147:
         sprintf(name, "VariantChangeTypeEx");
         break;
       case 148:
         sprintf(name, "SafeArrayPtrOfIndex");
         break;
       case 149:
         sprintf(name, "SysStringByteLen");
         break;
       case 150:
         sprintf(name, "SysAllocStringByteLen");
         break;
       case 151:
         sprintf(name, "DllRegisterServer");
         break;
       case 152:
         sprintf(name, "VarEqv");
         break;
       case 153:
         sprintf(name, "VarIdiv");
         break;
       case 154:
         sprintf(name, "VarImp");
         break;
       case 155:
         sprintf(name, "VarMod");
         break;
       case 156:
         sprintf(name, "VarMul");
         break;
       case 157:
         sprintf(name, "VarOr");
         break;
       case 158:
         sprintf(name, "VarPow");
         break;
       case 159:
         sprintf(name, "VarSub");
         break;
       case 160:
         sprintf(name, "CreateTypeLib");
         break;
       case 161:
         sprintf(name, "LoadTypeLib");
         break;
       case 162:
         sprintf(name, "LoadRegTypeLib");
         break;
       case 163:
         sprintf(name, "RegisterTypeLib");
         break;
       case 164:
         sprintf(name, "QueryPathOfRegTypeLib");
         break;
       case 165:
         sprintf(name, "LHashValOfNameSys");
         break;
       case 166:
         sprintf(name, "LHashValOfNameSysA");
         break;
       case 167:
         sprintf(name, "VarXor");
         break;
       case 168:
         sprintf(name, "VarAbs");
         break;
       case 169:
         sprintf(name, "VarFix");
         break;
       case 170:
         sprintf(name, "OaBuildVersion");
         break;
       case 171:
         sprintf(name, "ClearCustData");
         break;
       case 172:
         sprintf(name, "VarInt");
         break;
       case 173:
         sprintf(name, "VarNeg");
         break;
       case 174:
         sprintf(name, "VarNot");
         break;
       case 175:
         sprintf(name, "VarRound");
         break;
       case 176:
         sprintf(name, "VarCmp");
         break;
       case 177:
         sprintf(name, "VarDecAdd");
         break;
       case 178:
         sprintf(name, "VarDecDiv");
         break;
       case 179:
         sprintf(name, "VarDecMul");
         break;
       case 180:
         sprintf(name, "CreateTypeLib2");
         break;
       case 181:
         sprintf(name, "VarDecSub");
         break;
       case 182:
         sprintf(name, "VarDecAbs");
         break;
       case 183:
         sprintf(name, "LoadTypeLibEx");
         break;
       case 184:
         sprintf(name, "SystemTimeToVariantTime");
         break;
       case 185:
         sprintf(name, "VariantTimeToSystemTime");
         break;
       case 186:
         sprintf(name, "UnRegisterTypeLib");
         break;
       case 187:
         sprintf(name, "VarDecFix");
         break;
       case 188:
         sprintf(name, "VarDecInt");
         break;
       case 189:
         sprintf(name, "VarDecNeg");
         break;
       case 190:
         sprintf(name, "VarDecFromUI1");
         break;
       case 191:
         sprintf(name, "VarDecFromI2");
         break;
       case 192:
         sprintf(name, "VarDecFromI4");
         break;
       case 193:
         sprintf(name, "VarDecFromR4");
         break;
       case 194:
         sprintf(name, "VarDecFromR8");
         break;
       case 195:
         sprintf(name, "VarDecFromDate");
         break;
       case 196:
         sprintf(name, "VarDecFromCy");
         break;
       case 197:
         sprintf(name, "VarDecFromStr");
         break;
       case 198:
         sprintf(name, "VarDecFromDisp");
         break;
       case 199:
         sprintf(name, "VarDecFromBool");
         break;
       case 200:
         sprintf(name, "GetErrorInfo");
         break;
       case 201:
         sprintf(name, "SetErrorInfo");
         break;
       case 202:
         sprintf(name, "CreateErrorInfo");
         break;
       case 203:
         sprintf(name, "VarDecRound");
         break;
       case 204:
         sprintf(name, "VarDecCmp");
         break;
       case 205:
         sprintf(name, "VarI2FromI1");
         break;
       case 206:
         sprintf(name, "VarI2FromUI2");
         break;
       case 207:
         sprintf(name, "VarI2FromUI4");
         break;
       case 208:
         sprintf(name, "VarI2FromDec");
         break;
       case 209:
         sprintf(name, "VarI4FromI1");
         break;
       case 210:
         sprintf(name, "VarI4FromUI2");
         break;
       case 211:
         sprintf(name, "VarI4FromUI4");
         break;
       case 212:
         sprintf(name, "VarI4FromDec");
         break;
       case 213:
         sprintf(name, "VarR4FromI1");
         break;
       case 214:
         sprintf(name, "VarR4FromUI2");
         break;
       case 215:
         sprintf(name, "VarR4FromUI4");
         break;
       case 216:
         sprintf(name, "VarR4FromDec");
         break;
       case 217:
         sprintf(name, "VarR8FromI1");
         break;
       case 218:
         sprintf(name, "VarR8FromUI2");
         break;
       case 219:
         sprintf(name, "VarR8FromUI4");
         break;
       case 220:
         sprintf(name, "VarR8FromDec");
         break;
       case 221:
         sprintf(name, "VarDateFromI1");
         break;
       case 222:
         sprintf(name, "VarDateFromUI2");
         break;
       case 223:
         sprintf(name, "VarDateFromUI4");
         break;
       case 224:
         sprintf(name, "VarDateFromDec");
         break;
       case 225:
         sprintf(name, "VarCyFromI1");
         break;
       case 226:
         sprintf(name, "VarCyFromUI2");
         break;
       case 227:
         sprintf(name, "VarCyFromUI4");
         break;
       case 228:
         sprintf(name, "VarCyFromDec");
         break;
       case 229:
         sprintf(name, "VarBstrFromI1");
         break;
       case 230:
         sprintf(name, "VarBstrFromUI2");
         break;
       case 231:
         sprintf(name, "VarBstrFromUI4");
         break;
       case 232:
         sprintf(name, "VarBstrFromDec");
         break;
       case 233:
         sprintf(name, "VarBoolFromI1");
         break;
       case 234:
         sprintf(name, "VarBoolFromUI2");
         break;
       case 235:
         sprintf(name, "VarBoolFromUI4");
         break;
       case 236:
         sprintf(name, "VarBoolFromDec");
         break;
       case 237:
         sprintf(name, "VarUI1FromI1");
         break;
       case 238:
         sprintf(name, "VarUI1FromUI2");
         break;
       case 239:
         sprintf(name, "VarUI1FromUI4");
         break;
       case 240:
         sprintf(name, "VarUI1FromDec");
         break;
       case 241:
         sprintf(name, "VarDecFromI1");
         break;
       case 242:
         sprintf(name, "VarDecFromUI2");
         break;
       case 243:
         sprintf(name, "VarDecFromUI4");
         break;
       case 244:
         sprintf(name, "VarI1FromUI1");
         break;
       case 245:
         sprintf(name, "VarI1FromI2");
         break;
       case 246:
         sprintf(name, "VarI1FromI4");
         break;
       case 247:
         sprintf(name, "VarI1FromR4");
         break;
       case 248:
         sprintf(name, "VarI1FromR8");
         break;
       case 249:
         sprintf(name, "VarI1FromDate");
         break;
       case 250:
         sprintf(name, "VarI1FromCy");
         break;
       case 251:
         sprintf(name, "VarI1FromStr");
         break;
       case 252:
         sprintf(name, "VarI1FromDisp");
         break;
       case 253:
         sprintf(name, "VarI1FromBool");
         break;
       case 254:
         sprintf(name, "VarI1FromUI2");
         break;
       case 255:
         sprintf(name, "VarI1FromUI4");
         break;
       case 256:
         sprintf(name, "VarI1FromDec");
         break;
       case 257:
         sprintf(name, "VarUI2FromUI1");
         break;
       case 258:
         sprintf(name, "VarUI2FromI2");
         break;
       case 259:
         sprintf(name, "VarUI2FromI4");
         break;
       case 260:
         sprintf(name, "VarUI2FromR4");
         break;
       case 261:
         sprintf(name, "VarUI2FromR8");
         break;
       case 262:
         sprintf(name, "VarUI2FromDate");
         break;
       case 263:
         sprintf(name, "VarUI2FromCy");
         break;
       case 264:
         sprintf(name, "VarUI2FromStr");
         break;
       case 265:
         sprintf(name, "VarUI2FromDisp");
         break;
       case 266:
         sprintf(name, "VarUI2FromBool");
         break;
       case 267:
         sprintf(name, "VarUI2FromI1");
         break;
       case 268:
         sprintf(name, "VarUI2FromUI4");
         break;
       case 269:
         sprintf(name, "VarUI2FromDec");
         break;
       case 270:
         sprintf(name, "VarUI4FromUI1");
         break;
       case 271:
         sprintf(name, "VarUI4FromI2");
         break;
       case 272:
         sprintf(name, "VarUI4FromI4");
         break;
       case 273:
         sprintf(name, "VarUI4FromR4");
         break;
       case 274:
         sprintf(name, "VarUI4FromR8");
         break;
       case 275:
         sprintf(name, "VarUI4FromDate");
         break;
       case 276:
         sprintf(name, "VarUI4FromCy");
         break;
       case 277:
         sprintf(name, "VarUI4FromStr");
         break;
       case 278:
         sprintf(name, "VarUI4FromDisp");
         break;
       case 279:
         sprintf(name, "VarUI4FromBool");
         break;
       case 280:
         sprintf(name, "VarUI4FromI1");
         break;
       case 281:
         sprintf(name, "VarUI4FromUI2");
         break;
       case 282:
         sprintf(name, "VarUI4FromDec");
         break;
       case 283:
         sprintf(name, "BSTR_UserSize");
         break;
       case 284:
         sprintf(name, "BSTR_UserMarshal");
         break;
       case 285:
         sprintf(name, "BSTR_UserUnmarshal");
         break;
       case 286:
         sprintf(name, "BSTR_UserFree");
         break;
       case 287:
         sprintf(name, "VARIANT_UserSize");
         break;
       case 288:
         sprintf(name, "VARIANT_UserMarshal");
         break;
       case 289:
         sprintf(name, "VARIANT_UserUnmarshal");
         break;
       case 290:
         sprintf(name, "VARIANT_UserFree");
         break;
       case 291:
         sprintf(name, "LPSAFEARRAY_UserSize");
         break;
       case 292:
         sprintf(name, "LPSAFEARRAY_UserMarshal");
         break;
       case 293:
         sprintf(name, "LPSAFEARRAY_UserUnmarshal");
         break;
       case 294:
         sprintf(name, "LPSAFEARRAY_UserFree");
         break;
       case 295:
         sprintf(name, "LPSAFEARRAY_Size");
         break;
       case 296:
         sprintf(name, "LPSAFEARRAY_Marshal");
         break;
       case 297:
         sprintf(name, "LPSAFEARRAY_Unmarshal");
         break;
       case 298:
         sprintf(name, "VarDecCmpR8");
         break;
       case 299:
         sprintf(name, "VarCyAdd");
         break;
       case 300:
         sprintf(name, "DllUnregisterServer");
         break;
       case 301:
         sprintf(name, "OACreateTypeLib2");
         break;
       case 303:
         sprintf(name, "VarCyMul");
         break;
       case 304:
         sprintf(name, "VarCyMulI4");
         break;
       case 305:
         sprintf(name, "VarCySub");
         break;
       case 306:
         sprintf(name, "VarCyAbs");
         break;
       case 307:
         sprintf(name, "VarCyFix");
         break;
       case 308:
         sprintf(name, "VarCyInt");
         break;
       case 309:
         sprintf(name, "VarCyNeg");
         break;
       case 310:
         sprintf(name, "VarCyRound");
         break;
       case 311:
         sprintf(name, "VarCyCmp");
         break;
       case 312:
         sprintf(name, "VarCyCmpR8");
         break;
       case 313:
         sprintf(name, "VarBstrCat");
         break;
       case 314:
         sprintf(name, "VarBstrCmp");
         break;
       case 315:
         sprintf(name, "VarR8Pow");
         break;
       case 316:
         sprintf(name, "VarR4CmpR8");
         break;
       case 317:
         sprintf(name, "VarR8Round");
         break;
       case 318:
         sprintf(name, "VarCat");
         break;
       case 319:
         sprintf(name, "VarDateFromUdateEx");
         break;
       case 322:
         sprintf(name, "GetRecordInfoFromGuids");
         break;
       case 323:
         sprintf(name, "GetRecordInfoFromTypeInfo");
         break;
       case 325:
         sprintf(name, "SetVarConversionLocaleSetting");
         break;
       case 326:
         sprintf(name, "GetVarConversionLocaleSetting");
         break;
       case 327:
         sprintf(name, "SetOaNoCache");
         break;
       case 329:
         sprintf(name, "VarCyMulI8");
         break;
       case 330:
         sprintf(name, "VarDateFromUdate");
         break;
       case 331:
         sprintf(name, "VarUdateFromDate");
         break;
       case 332:
         sprintf(name, "GetAltMonthNames");
         break;
       case 333:
         sprintf(name, "VarI8FromUI1");
         break;
       case 334:
         sprintf(name, "VarI8FromI2");
         break;
       case 335:
         sprintf(name, "VarI8FromR4");
         break;
       case 336:
         sprintf(name, "VarI8FromR8");
         break;
       case 337:
         sprintf(name, "VarI8FromCy");
         break;
       case 338:
         sprintf(name, "VarI8FromDate");
         break;
       case 339:
         sprintf(name, "VarI8FromStr");
         break;
       case 340:
         sprintf(name, "VarI8FromDisp");
         break;
       case 341:
         sprintf(name, "VarI8FromBool");
         break;
       case 342:
         sprintf(name, "VarI8FromI1");
         break;
       case 343:
         sprintf(name, "VarI8FromUI2");
         break;
       case 344:
         sprintf(name, "VarI8FromUI4");
         break;
       case 345:
         sprintf(name, "VarI8FromDec");
         break;
       case 346:
         sprintf(name, "VarI2FromI8");
         break;
       case 347:
         sprintf(name, "VarI2FromUI8");
         break;
       case 348:
         sprintf(name, "VarI4FromI8");
         break;
       case 349:
         sprintf(name, "VarI4FromUI8");
         break;
       case 360:
         sprintf(name, "VarR4FromI8");
         break;
       case 361:
         sprintf(name, "VarR4FromUI8");
         break;
       case 362:
         sprintf(name, "VarR8FromI8");
         break;
       case 363:
         sprintf(name, "VarR8FromUI8");
         break;
       case 364:
         sprintf(name, "VarDateFromI8");
         break;
       case 365:
         sprintf(name, "VarDateFromUI8");
         break;
       case 366:
         sprintf(name, "VarCyFromI8");
         break;
       case 367:
         sprintf(name, "VarCyFromUI8");
         break;
       case 368:
         sprintf(name, "VarBstrFromI8");
         break;
       case 369:
         sprintf(name, "VarBstrFromUI8");
         break;
       case 370:
         sprintf(name, "VarBoolFromI8");
         break;
       case 371:
         sprintf(name, "VarBoolFromUI8");
         break;
       case 372:
         sprintf(name, "VarUI1FromI8");
         break;
       case 373:
         sprintf(name, "VarUI1FromUI8");
         break;
       case 374:
         sprintf(name, "VarDecFromI8");
         break;
       case 375:
         sprintf(name, "VarDecFromUI8");
         break;
       case 376:
         sprintf(name, "VarI1FromI8");
         break;
       case 377:
         sprintf(name, "VarI1FromUI8");
         break;
       case 378:
         sprintf(name, "VarUI2FromI8");
         break;
       case 379:
         sprintf(name, "VarUI2FromUI8");
         break;
       case 401:
         sprintf(name, "OleLoadPictureEx");
         break;
       case 402:
         sprintf(name, "OleLoadPictureFileEx");
         break;
       case 411:
         sprintf(name, "SafeArrayCreateVector");
         break;
       case 412:
         sprintf(name, "SafeArrayCopyData");
         break;
       case 413:
         sprintf(name, "VectorFromBstr");
         break;
       case 414:
         sprintf(name, "BstrFromVector");
         break;
       case 415:
         sprintf(name, "OleIconToCursor");
         break;
       case 416:
         sprintf(name, "OleCreatePropertyFrameIndirect");
         break;
       case 417:
         sprintf(name, "OleCreatePropertyFrame");
         break;
       case 418:
         sprintf(name, "OleLoadPicture");
         break;
       case 419:
         sprintf(name, "OleCreatePictureIndirect");
         break;
       case 420:
         sprintf(name, "OleCreateFontIndirect");
         break;
       case 421:
         sprintf(name, "OleTranslateColor");
         break;
       case 422:
         sprintf(name, "OleLoadPictureFile");
         break;
       case 423:
         sprintf(name, "OleSavePictureFile");
         break;
       case 424:
         sprintf(name, "OleLoadPicturePath");
         break;
       case 425:
         sprintf(name, "VarUI4FromI8");
         break;
       case 426:
         sprintf(name, "VarUI4FromUI8");
         break;
       case 427:
         sprintf(name, "VarI8FromUI8");
         break;
       case 428:
         sprintf(name, "VarUI8FromI8");
         break;
       case 429:
         sprintf(name, "VarUI8FromUI1");
         break;
       case 430:
         sprintf(name, "VarUI8FromI2");
         break;
       case 431:
         sprintf(name, "VarUI8FromR4");
         break;
       case 432:
         sprintf(name, "VarUI8FromR8");
         break;
       case 433:
         sprintf(name, "VarUI8FromCy");
         break;
       case 434:
         sprintf(name, "VarUI8FromDate");
         break;
       case 435:
         sprintf(name, "VarUI8FromStr");
         break;
       case 436:
         sprintf(name, "VarUI8FromDisp");
         break;
       case 437:
         sprintf(name, "VarUI8FromBool");
         break;
       case 438:
         sprintf(name, "VarUI8FromI1");
         break;
       case 439:
         sprintf(name, "VarUI8FromUI2");
         break;
       case 440:
         sprintf(name, "VarUI8FromUI4");
         break;
       case 441:
         sprintf(name, "VarUI8FromDec");
         break;
       case 442:
         sprintf(name, "RegisterTypeLibForUser");
         break;
       case 443:
         sprintf(name, "UnRegisterTypeLibForUser");
         break;
       default:
         break;
     }
   }
 
   if (name[0] == '\0')
     sprintf(name, "ord%u", ord);
 
   return cli_strdup(name);    
 }
 
a5d40420
 static int validate_impname(const char *name, uint32_t length, int dll)
 {
     uint32_t i = 0;
     const char *c = name;
 
     if (!name || length == 0)
0a23f3d9
         return 1;
a5d40420
 
     while (i < length && *c != '\0') {
         if ((*c >= '0' && *c <= '9') ||
             (*c >= 'a' && *c <= 'z') ||
             (*c >= 'A' && *c <= 'Z') ||
             (*c == '_') ||
             (dll && *c == '.')) {
 
             c++;
             i++;
         } else
0a23f3d9
             return 0;
a5d40420
     }
 
0a23f3d9
     return 1;
a5d40420
 }
 
0a23f3d9
 static inline int hash_impfns(cli_ctx *ctx, void **hashctx, uint32_t *impsz, struct pe_image_import_descriptor *image, const char *dllname, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size, int pe_plus, int *first)
c96e3331
 {
d87dfbb2
     uint32_t thuoff = 0, offset;
7478245e
     fmap_t *map = *ctx->fmap;
     size_t dlllen = 0, fsize = map->len;
d87dfbb2
     int i, j, err = 0, num_fns = 0, ret = CL_SUCCESS;
7478245e
     const char *buffer;
c96e3331
     enum CLI_HASH_TYPE type;
7a47c63d
 #if HAVE_JSON
     json_object *imptbl = NULL;
941dc246
 #else
     void *imptbl = NULL;
7a47c63d
 #endif
7478245e
 
2ba07d63
     if (image->u.OriginalFirstThunk)
         thuoff = cli_rawaddr(image->u.OriginalFirstThunk, exe_sections, nsections, &err, fsize, hdr_size);
     if (err || thuoff == 0)
c96e3331
         thuoff = cli_rawaddr(image->FirstThunk, exe_sections, nsections, &err, fsize, hdr_size);
7478245e
     if (err) {
c96e3331
         cli_dbgmsg("scan_pe: invalid rva for image first thunk\n");
0a23f3d9
         return CL_EFORMAT;
7478245e
     }
 
7a47c63d
 #if HAVE_JSON
     if (ctx->wrkproperty) {
         imptbl = cli_jsonarray(ctx->wrkproperty, "ImportTable");
         if (!imptbl) {
c96e3331
             cli_dbgmsg("scan_pe: cannot allocate import table json object\n");
7a47c63d
             return CL_EMEM;
         }
     }
 #endif
 
c96e3331
 #define update_imphash()                                                \
0a23f3d9
     do {                                                                \
941dc246
     if (funcname) {                                                     \
         char *fname;                                                    \
         size_t funclen;                                                 \
                                                                         \
         if (dlllen == 0) {                                              \
             char* ext = strstr(dllname, ".");                           \
                                                                         \
             if (ext && (strncasecmp(ext, ".ocx", 4) == 0 ||             \
                         strncasecmp(ext, ".sys", 4) == 0 ||             \
                         strncasecmp(ext, ".dll", 4) == 0))              \
                 dlllen = ext - dllname;                                 \
             else                                                        \
                 dlllen = strlen(dllname);                               \
         }                                                               \
                                                                         \
         funclen = strlen(funcname);                                     \
0a23f3d9
         if (validate_impname(funcname, funclen, 1) == 0) {              \
             cli_dbgmsg("scan_pe: invalid name for imported function\n"); \
             ret = CL_EFORMAT;                                           \
a5d40420
             break;                                                      \
0a23f3d9
         }                                                               \
941dc246
                                                                         \
         fname = cli_calloc(funclen + dlllen + 3, sizeof(char));         \
         if (fname == NULL) {                                            \
c96e3331
             cli_dbgmsg("scan_pe: cannot allocate memory for imphash string\n"); \
0a23f3d9
             ret = CL_EMEM;                                              \
             break;                                                      \
941dc246
         }                                                               \
         j = 0;                                                          \
         if (!*first)                                                    \
             fname[j++] = ',';                                           \
         for (i = 0; i < dlllen; i++, j++)                               \
             fname[j] = tolower(dllname[i]);                             \
         fname[j++] = '.';                                               \
         for (i = 0; i < funclen; i++, j++)                              \
             fname[j] = tolower(funcname[i]);                            \
                                                                         \
         if (imptbl) {                                                   \
             char *jname = *first ? fname : fname+1;                     \
             cli_jsonstr(imptbl, NULL, jname);                           \
         }                                                               \
                                                                         \
c96e3331
         for(type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++)   \
             cl_update_hash(hashctx[type], fname, strlen(fname));        \
         *impsz += strlen(fname);                                        \
941dc246
                                                                         \
         *first = 0;                                                     \
         free(fname);                                                    \
0a23f3d9
     }                                                                   \
     } while(0)
941dc246
 
7478245e
     if (!pe_plus) {
         struct pe_image_thunk32 thunk32;
 
c96e3331
         while ((num_fns < PE_MAXIMPORTS) && (fmap_readn(map, &thunk32, thuoff, sizeof(struct pe_image_thunk32)) == sizeof(struct pe_image_thunk32)) && (thunk32.u.Ordinal != 0)) {
7478245e
             char *funcname = NULL;
c96e3331
             thuoff += sizeof(struct pe_image_thunk32);
7478245e
 
0a23f3d9
             thunk32.u.Ordinal = EC32(thunk32.u.Ordinal);
 
e27ec91e
             if (!(thunk32.u.Ordinal & PE_IMAGEDIR_ORDINAL_FLAG32)) {
7478245e
                 offset = cli_rawaddr(thunk32.u.Function, exe_sections, nsections, &err, fsize, hdr_size);
 
                 if (offset >= 0) {
                     /* Hint field is a uint16_t and precedes the Name field */
                     if ((buffer = fmap_need_off_once(map, offset+sizeof(uint16_t), MIN(PE_MAXNAMESIZE, fsize-offset))) != NULL) {
140914f3
                         funcname = cli_strndup(buffer, MIN(PE_MAXNAMESIZE, fsize-offset));
7478245e
                         if (funcname == NULL) {
c96e3331
                             cli_dbgmsg("scan_pe: cannot duplicate function name\n");
7478245e
                             return CL_EMEM;
                         }
                     }
                 }
             } else {
                 /* ordinal lookup */
                 funcname = pe_ordinal(dllname, thunk32.u.Ordinal & 0xFFFF);
                 if (funcname == NULL) {
c96e3331
                     cli_dbgmsg("scan_pe: cannot duplicate function name\n");
7478245e
                     return CL_EMEM;
                 }
             }
 
c96e3331
             update_imphash();
0a23f3d9
             free(funcname);
             if (ret != CL_SUCCESS)
                 return ret;
7478245e
         }
     } else {
         struct pe_image_thunk64 thunk64;
 
c96e3331
         while ((num_fns < PE_MAXIMPORTS) && (fmap_readn(map, &thunk64, thuoff, sizeof(struct pe_image_thunk64)) == sizeof(struct pe_image_thunk64)) && (thunk64.u.Ordinal != 0)) {
7478245e
             char *funcname = NULL;
c96e3331
             thuoff += sizeof(struct pe_image_thunk64);
7478245e
 
0a23f3d9
             thunk64.u.Ordinal = EC64(thunk64.u.Ordinal);
 
e27ec91e
             if (!(thunk64.u.Ordinal & PE_IMAGEDIR_ORDINAL_FLAG64)) {
7478245e
                 offset = cli_rawaddr(thunk64.u.Function, exe_sections, nsections, &err, fsize, hdr_size);
 
                 if (offset >= 0) {
                     /* Hint field is a uint16_t and precedes the Name field */
                     if ((buffer = fmap_need_off_once(map, offset+sizeof(uint16_t), MIN(PE_MAXNAMESIZE, fsize-offset))) != NULL) {
140914f3
                         funcname = cli_strndup(buffer, MIN(PE_MAXNAMESIZE, fsize-offset));
7478245e
                         if (funcname == NULL) {
c96e3331
                             cli_dbgmsg("scan_pe: cannot duplicate function name\n");
7478245e
                             return CL_EMEM;
                         }
                     }
                 }
             } else {
                 /* ordinal lookup */
bb5d66be
                 funcname = pe_ordinal(dllname, thunk64.u.Ordinal & 0xFFFF);
7478245e
                 if (funcname == NULL) {
c96e3331
                     cli_dbgmsg("scan_pe: cannot duplicate function name\n");
7478245e
                     return CL_EMEM;
                 }
             }
 
c96e3331
             update_imphash();
0a23f3d9
             free(funcname);
             if (ret != CL_SUCCESS)
                 return ret;
7478245e
         }
     }
 
     return CL_SUCCESS;
 }
 
c96e3331
 static unsigned int hash_imptbl(cli_ctx *ctx, unsigned char **digest, uint32_t *impsz, int *genhash, struct pe_image_data_dir *datadir, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size, int pe_plus)
 {
7478245e
     struct pe_image_import_descriptor *image;
     fmap_t *map = *ctx->fmap;
     size_t left, fsize = map->len;
c96e3331
     uint32_t impoff, offset;
     const char *impdes, *buffer;
     void *hashctx[CLI_HASH_AVAIL_TYPES];
     enum CLI_HASH_TYPE type;
0a23f3d9
     int err, nimps = 0, ret = CL_SUCCESS;
c96e3331
     int first = 1;
 
     if(datadir->VirtualAddress == 0 || datadir->Size == 0) {
         cli_errmsg("scan_pe: import table data directory does not exist\n");
7478245e
         return CL_SUCCESS;
     }
 
     impoff = cli_rawaddr(datadir->VirtualAddress, exe_sections, nsections, &err, fsize, hdr_size);
c96e3331
     if(err || impoff + datadir->Size > fsize) {
         cli_dbgmsg("scan_pe: invalid rva for import table data\n");
7478245e
         return CL_SUCCESS;
     }
 
     impdes = fmap_need_off(map, impoff, datadir->Size);
c96e3331
     if(impdes == NULL) {
         cli_dbgmsg("scan_pe: failed to acquire fmap buffer\n");
7959fb61
         return CL_EREAD;
7478245e
     }
     left = datadir->Size;
 
c96e3331
     memset(hashctx, 0, sizeof(hashctx));
     if(genhash[CLI_HASH_MD5]) {
         hashctx[CLI_HASH_MD5] = cl_hash_init("md5");
0a23f3d9
         if (hashctx[CLI_HASH_MD5] == NULL) {
             fmap_unneed_off(map, impoff, datadir->Size);
c96e3331
             return CL_EMEM;
0a23f3d9
         }
c96e3331
     }
     if(genhash[CLI_HASH_SHA1]) {
         hashctx[CLI_HASH_SHA1] = cl_hash_init("sha1");
0a23f3d9
         if (hashctx[CLI_HASH_SHA1] == NULL) {
             fmap_unneed_off(map, impoff, datadir->Size);
c96e3331
             return CL_EMEM;
0a23f3d9
         }
c96e3331
     }
     if(genhash[CLI_HASH_SHA256]) {
         hashctx[CLI_HASH_SHA256] = cl_hash_init("sha256");
0a23f3d9
         if (hashctx[CLI_HASH_SHA256] == NULL) {
             fmap_unneed_off(map, impoff, datadir->Size);
c96e3331
             return CL_EMEM;
0a23f3d9
         }
c96e3331
     }
7478245e
 
     image = (struct pe_image_import_descriptor *)impdes;
0a23f3d9
     while(left > sizeof(struct pe_image_import_descriptor) && image->Name != 0 && nimps < PE_MAXIMPORTS) {
7478245e
         char *dllname = NULL;
 
         left -= sizeof(struct pe_image_import_descriptor);
c96e3331
         nimps++;
7478245e
 
0a23f3d9
         /* Endian Conversion */
         image->u.OriginalFirstThunk = EC32(image->u.OriginalFirstThunk);
         image->TimeDateStamp = EC32(image->TimeDateStamp);
         image->ForwarderChain = EC32(image->ForwarderChain);
         image->Name = EC32(image->Name);
         image->FirstThunk = EC32(image->FirstThunk);
 
7478245e
         /* DLL name aquisition */
         offset = cli_rawaddr(image->Name, exe_sections, nsections, &err, fsize, hdr_size);
c96e3331
         if(err || offset > fsize) {
             cli_dbgmsg("scan_pe: invalid rva for dll name\n");
7959fb61
             /* TODO: ignore or return? */
7478245e
             /*
               image++;
               continue;
              */
0a23f3d9
             ret = CL_EFORMAT;
             goto hash_imptbl_end;
7478245e
         }
 
0a23f3d9
         buffer = fmap_need_off_once(map, offset, MIN(PE_MAXNAMESIZE, fsize-offset));
         if (buffer == NULL) {
             cli_dbgmsg("scan_pe: failed to read name for dll\n");
             ret = CL_EREAD;
             goto hash_imptbl_end;
         }
 
         if (validate_impname(dllname, MIN(PE_MAXNAMESIZE, fsize-offset), 1) == 0) {
             cli_dbgmsg("scan_pe: invalid name for imported dll\n");
             ret = CL_EFORMAT;
             goto hash_imptbl_end;
         }
 
140914f3
         dllname = cli_strndup(buffer, MIN(PE_MAXNAMESIZE, fsize-offset));
0a23f3d9
         if (dllname == NULL) {
             cli_dbgmsg("scan_pe: cannot duplicate dll name\n");
             ret = CL_EMEM;
             goto hash_imptbl_end;
7478245e
         }
 
7959fb61
         /* DLL function handling - inline function */
c96e3331
         ret = hash_impfns(ctx, hashctx, impsz, image, dllname, exe_sections, nsections, hdr_size, pe_plus, &first);
0a23f3d9
         free(dllname);
         dllname = NULL;
         if (ret != CL_SUCCESS)
             goto hash_imptbl_end;
7478245e
 
         image++;
     }
 
0a23f3d9
  hash_imptbl_end:
7478245e
     fmap_unneed_off(map, impoff, datadir->Size);
c96e3331
     for(type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++)
         cl_finish_hash(hashctx[type], digest[type]);
0a23f3d9
     return ret;
c96e3331
 }
7959fb61
 
c96e3331
 static int scan_pe_imp(cli_ctx *ctx, struct pe_image_data_dir *dirs, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size, int pe_plus)
 {
     struct cli_matcher *imp = ctx->engine->hm_imp;
     unsigned char *hashset[CLI_HASH_AVAIL_TYPES];
     const char *virname = NULL;
     int genhash[CLI_HASH_AVAIL_TYPES];
     uint32_t impsz = 0;
     enum CLI_HASH_TYPE type;
     int ret = CL_CLEAN;
 
     /* pick hashtypes to generate */
     for(type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
         genhash[type] = cli_hm_have_any(imp, type);
0a23f3d9
         if(genhash[type]) {
             hashset[type] = cli_malloc(hashlen[type]);
             if(!hashset[type]) {
                 cli_errmsg("scan_pe: cli_malloc failed!\n");
                 for(; type > 0;)
                     free(hashset[--type]);
                 return CL_EMEM;
             }
         }
         else {
             hashset[type] = NULL;
c96e3331
         }
     }
 
     /* Force md5 hash generation for debug and preclass */
 #if HAVE_JSON
     if ((cli_debug_flag || ctx->wrkproperty) && !genhash[CLI_HASH_MD5]) {
 #else
     if (cli_debug_flag && !genhash[CLI_HASH_MD5]) {
 #endif
         genhash[CLI_HASH_MD5] = 1;
         hashset[CLI_HASH_MD5] = cli_malloc(hashlen[CLI_HASH_MD5]);
         if(!hashset[CLI_HASH_MD5]) {
             cli_errmsg("scan_pe: cli_malloc failed!\n");
0a23f3d9
             for(type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++)
                 free(hashset[type]);
c96e3331
             return CL_EMEM;
         }
     }
 
     /* Generate hashes */
0a23f3d9
     ret = hash_imptbl(ctx, hashset, &impsz, genhash, &dirs[1], exe_sections, nsections, hdr_size, pe_plus);
     if (ret != CL_SUCCESS) {
         for(type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++)
             free(hashset[type]);
         return ret;
     }
c96e3331
 
     /* Print hash */
7a47c63d
 #if HAVE_JSON
7959fb61
     if (cli_debug_flag || ctx->wrkproperty) {
 #else
     if (cli_debug_flag) {
7a47c63d
 #endif
c96e3331
         char *dstr = cli_str2hex(hashset[CLI_HASH_MD5], hashlen[CLI_HASH_MD5]);
         cli_dbgmsg("IMP: %s:%u\n", dstr ? (char *)dstr : "(NULL)", impsz);
7959fb61
 #if HAVE_JSON
         if (ctx->wrkproperty)
             cli_jsonstr(ctx->wrkproperty, "Imphash", dstr ? dstr : "(NULL)");
 #endif
         if (dstr)
             free(dstr);
     }
 
c96e3331
     /* Do scans */
     for(type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
         if(cli_hm_scan(hashset[type], impsz, &virname, imp, type) == CL_VIRUS) {
d87dfbb2
             ret = cli_append_virus(ctx, virname);
             if (ret != CL_CLEAN) {
                 if (ret != CL_VIRUS)
                     break;
                 else if (!SCAN_ALL)
                     break;
             }
0a23f3d9
         }
         if(cli_hm_scan_wild(hashset[type], &virname, imp, type) == CL_VIRUS) {
941dc246
             cli_append_virus(ctx, virname);
d87dfbb2
             if (ret != CL_CLEAN) {
                 if (ret != CL_VIRUS)
                     break;
                 else if (!SCAN_ALL)
                     break;
             }
        }
941dc246
     }
86465add
 
0a23f3d9
     for(type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++)
         free(hashset[type]);
7478245e
     return ret;
 }
 
172c4dd2
 #if HAVE_JSON
 static struct json_object *get_pe_property(cli_ctx *ctx)
 {
     struct json_object *pe;
 
     if (!(ctx) || !(ctx->wrkproperty))
         return NULL;
 
6c048b8a
     if (!json_object_object_get_ex(ctx->wrkproperty, "PE", &pe)) {
172c4dd2
         pe = json_object_new_object();
         if (!(pe))
             return NULL;
 
         json_object_object_add(ctx->wrkproperty, "PE", pe);
     }
 
     return pe;
 }
 
 static void pe_add_heuristic_property(cli_ctx *ctx, const char *key)
 {
     struct json_object *heuristics;
     struct json_object *pe;
     struct json_object *str;
 
     pe = get_pe_property(ctx);
     if (!(pe))
         return;
 
6c048b8a
     if (!json_object_object_get_ex(pe, "Heuristics", &heuristics)) {
172c4dd2
         heuristics = json_object_new_array();
         if (!(heuristics))
             return;
 
         json_object_object_add(pe, "Heuristics", heuristics);
     }
 
     str = json_object_new_string(key);
     if (!(str))
         return;
 
     json_object_array_add(heuristics, str);
 }
 
 static struct json_object *get_section_json(cli_ctx *ctx)
 {
     struct json_object *pe;
     struct json_object *section;
 
     pe = get_pe_property(ctx);
     if (!(pe))
         return NULL;
 
6c048b8a
     if (!json_object_object_get_ex(pe, "Sections", &section)) {
172c4dd2
         section = json_object_new_array();
         if (!(section))
             return NULL;
 
         json_object_object_add(pe, "Sections", section);
     }
 
     return section;
 }
 
 static void add_section_info(cli_ctx *ctx, struct cli_exe_section *s)
 {
     struct json_object *sections, *section, *obj;
     char address[16];
 
     sections = get_section_json(ctx);
     if (!(sections))
         return;
 
     section = json_object_new_object();
     if (!(section))
         return;
 
     obj = json_object_new_int((int32_t)(s->rsz));
     if (!(obj))
         return;
 
     json_object_object_add(section, "RawSize", obj);
 
     obj = json_object_new_int((int32_t)(s->raw));
     if (!(obj))
         return;
 
     json_object_object_add(section, "RawOffset", obj);
 
     snprintf(address, sizeof(address), "0x%08x", s->rva);
 
     obj = json_object_new_string(address);
     if (!(obj))
         return;
 
     json_object_object_add(section, "VirtualAddress", obj);
 
636b7178
     obj = json_object_new_boolean((s->chr & 0x20000000) == 0x20000000);
     if ((obj))
         json_object_object_add(section, "Executable", obj);
 
     obj = json_object_new_boolean((s->chr & 0x80000000) == 0x80000000);
     if ((obj))
         json_object_object_add(section, "Writable", obj);
 
     obj = json_object_new_boolean(s->urva>>31 || s->uvsz>>31 || (s->rsz && s->uraw>>31) || s->ursz>>31);
     if ((obj))
         json_object_object_add(section, "Signed", obj);
 
172c4dd2
     json_object_array_add(sections, section);
 }
 #endif
 
453d8180
 int cli_scanpe(cli_ctx *ctx)
6307ca15
 {
f98a68af
     uint16_t e_magic; /* DOS signature ("MZ") */
     uint16_t nsections;
     uint32_t e_lfanew; /* address of new exe header */
     uint32_t ep, vep; /* entry point (raw, virtual) */
     uint8_t polipos = 0;
     time_t timestamp;
     struct pe_image_file_hdr file_hdr;
     union {
         struct pe_image_optional_hdr64 opt64;
         struct pe_image_optional_hdr32 opt32;
     } pe_opt;
     struct pe_image_section_hdr *section_hdr;
     char sname[9], epbuff[4096], *tempfile;
     uint32_t epsize;
     ssize_t bytes, at;
     unsigned int i, j, found, upx_success = 0, min = 0, max = 0, err, overlays = 0, rescan = 1;
     unsigned int ssize = 0, dsize = 0, dll = 0, pe_plus = 0, corrupted_cur;
     int (*upxfn)(const char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t) = NULL;
     const char *src = NULL;
     char *dest = NULL;
     int ndesc, ret = CL_CLEAN, upack = 0, native=0;
     size_t fsize;
     uint32_t valign, falign, hdr_size;
     struct cli_exe_section *exe_sections;
     char timestr[32];
     struct pe_image_data_dir *dirs;
     struct cli_bc_ctx *bc_ctx;
     fmap_t *map;
     struct cli_pe_hook_data pedata;
16b28d07
 #ifdef HAVE__INTERNAL__SHA_COLLECT
f98a68af
     int sha_collect = ctx->sha_collect;
16b28d07
 #endif
cd94be7a
     const char *archtype=NULL, *subsystem=NULL;
f98a68af
     uint32_t viruses_found = 0;
172c4dd2
 #if HAVE_JSON
f98a68af
     int toval = 0;
     struct json_object *pe_json=NULL;
     char jsonbuf[128];
172c4dd2
 #endif
6307ca15
 
b07f9a5e
     if(!ctx) {
f98a68af
         cli_errmsg("cli_scanpe: ctx == NULL\n");
         return CL_ENULLARG;
b07f9a5e
     }
172c4dd2
 
 #if HAVE_JSON
20b45621
     if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) {
         return CL_ETIMEOUT;
     }
 
     if (ctx->options & CL_SCAN_FILE_PROPERTIES) {
172c4dd2
         pe_json = get_pe_property(ctx);
20b45621
     }
172c4dd2
 #endif
a5241d27
     map = *ctx->fmap;
     if(fmap_readn(map, &e_magic, 0, sizeof(e_magic)) != sizeof(e_magic)) {
f98a68af
         cli_dbgmsg("Can't read DOS signature\n");
         return CL_CLEAN;
6307ca15
     }
 
3b857f14
     if(EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE && EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE_OLD) {
f98a68af
         cli_dbgmsg("Invalid DOS signature\n");
         return CL_CLEAN;
6307ca15
     }
 
a5241d27
     if(fmap_readn(map, &e_lfanew, 58 + sizeof(e_magic), sizeof(e_lfanew)) != sizeof(e_lfanew)) {
f98a68af
         cli_dbgmsg("Can't read new header address\n");
         /* truncated header? */
         if(DETECT_BROKEN_PE) {
d87dfbb2
             ret = cli_append_virus(ctx,"Heuristics.Broken.Executable");
             return ret;
f98a68af
         }
 
         return CL_CLEAN;
6307ca15
     }
 
a9082ea2
     e_lfanew = EC32(e_lfanew);
6307ca15
     cli_dbgmsg("e_lfanew == %d\n", e_lfanew);
     if(!e_lfanew) {
f98a68af
         cli_dbgmsg("Not a PE file\n");
         return CL_CLEAN;
6307ca15
     }
7a0143cf
 
a5241d27
     if(fmap_readn(map, &file_hdr, e_lfanew, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) {
f98a68af
         /* bad information in e_lfanew - probably not a PE file */
d87dfbb2
         cli_dbgmsg("cli_scanpe: Can't read file header\n");
f98a68af
         return CL_CLEAN;
6307ca15
     }
 
1f9eb12b
     if(EC32(file_hdr.Magic) != PE_IMAGE_NT_SIGNATURE) {
f98a68af
         cli_dbgmsg("Invalid PE signature (probably NE file)\n");
         return CL_CLEAN;
6307ca15
     }
 
9ad59d16
     if(EC16(file_hdr.Characteristics) & 0x2000) {
172c4dd2
 #if HAVE_JSON
fcff42e9
         if (pe_json != NULL)
172c4dd2
             cli_jsonstr(pe_json, "Type", "DLL");
 #endif
f98a68af
         cli_dbgmsg("File type: DLL\n");
         dll = 1;
9ad59d16
     } else if(EC16(file_hdr.Characteristics) & 0x01) {
172c4dd2
 #if HAVE_JSON
fcff42e9
         if (pe_json != NULL)
172c4dd2
             cli_jsonstr(pe_json, "Type", "EXE");
 #endif
f98a68af
         cli_dbgmsg("File type: Executable\n");
9ad59d16
     }
 
a9082ea2
     switch(EC16(file_hdr.Machine)) {
f98a68af
     case 0x0:
172c4dd2
         archtype = "Unknown";
f98a68af
         break;
     case 0x14c:
172c4dd2
         archtype = "80386";
f98a68af
         break;
     case 0x14d:
172c4dd2
         archtype = "80486";
f98a68af
         break;
     case 0x14e:
172c4dd2
         archtype = "80586";
f98a68af
         break;
     case 0x160:
172c4dd2
         archtype = "R30000 (big-endian)";
f98a68af
         break;
     case 0x162:
172c4dd2
         archtype = "R3000";
f98a68af
         break;
     case 0x166:
172c4dd2
         archtype = "R4000";
f98a68af
         break;
     case 0x168:
172c4dd2
         archtype = "R10000";
f98a68af
         break;
     case 0x184:
172c4dd2
         archtype = "DEC Alpha AXP";
f98a68af
         break;
     case 0x284:
172c4dd2
         archtype = "DEC Alpha AXP 64bit";
f98a68af
         break;
     case 0x1f0:
172c4dd2
         archtype = "PowerPC";
f98a68af
         break;
     case 0x200:
172c4dd2
         archtype = "IA64";
f98a68af
         break;
     case 0x268:
172c4dd2
         archtype = "M68k";
f98a68af
         break;
     case 0x266:
172c4dd2
         archtype = "MIPS16";
f98a68af
         break;
     case 0x366:
172c4dd2
         archtype = "MIPS+FPU";
f98a68af
         break;
     case 0x466:
172c4dd2
         archtype = "MIPS16+FPU";
f98a68af
         break;
     case 0x1a2:
172c4dd2
         archtype = "Hitachi SH3";
f98a68af
         break;
     case 0x1a3:
172c4dd2
         archtype = "Hitachi SH3-DSP";
f98a68af
         break;
     case 0x1a4:
172c4dd2
         archtype = "Hitachi SH3-E";
f98a68af
         break;
     case 0x1a6:
172c4dd2
         archtype = "Hitachi SH4";
f98a68af
         break;
     case 0x1a8:
172c4dd2
         archtype = "Hitachi SH5";
f98a68af
         break;
     case 0x1c0:
172c4dd2
         archtype = "ARM";
f98a68af
         break;
     case 0x1c2:
172c4dd2
         archtype = "THUMB";
f98a68af
         break;
     case 0x1d3:
172c4dd2
         archtype = "AM33";
f98a68af
         break;
     case 0x520:
172c4dd2
         archtype = "Infineon TriCore";
f98a68af
         break;
     case 0xcef:
172c4dd2
         archtype = "CEF";
f98a68af
         break;
     case 0xebc:
172c4dd2
         archtype = "EFI Byte Code";
f98a68af
         break;
     case 0x9041:
172c4dd2
         archtype = "M32R";
f98a68af
         break;
     case 0xc0ee:
172c4dd2
         archtype = "CEEE";
f98a68af
         break;
     case 0x8664:
172c4dd2
         archtype = "AMD64";
f98a68af
         break;
     default:
172c4dd2
         archtype = "Unknown";
     }
 
     if ((archtype)) {
         cli_dbgmsg("Machine type: %s\n", archtype);
 #if HAVE_JSON
fcff42e9
         if (pe_json != NULL)
             cli_jsonstr(pe_json, "ArchType", archtype);
172c4dd2
 #endif
6307ca15
     }
 
a9082ea2
     nsections = EC16(file_hdr.NumberOfSections);
57866af1
     if(nsections < 1 || nsections > 96) {
172c4dd2
 #if HAVE_JSON
         pe_add_heuristic_property(ctx, "BadNumberOfSections");
 #endif
f98a68af
         if(DETECT_BROKEN_PE) {
d87dfbb2
             ret = cli_append_virus(ctx,"Heuristics.Broken.Executable");
             return ret;
f98a68af
         }
 
         if(!ctx->corrupted_input) {
             if(nsections)
             cli_warnmsg("PE file contains %d sections\n", nsections);
             else
             cli_warnmsg("PE file contains no sections\n");
         }
 
         return CL_CLEAN;
f86b5ac1
     }
f98a68af
 
a9082ea2
     cli_dbgmsg("NumberOfSections: %d\n", nsections);
 
8000d078
     timestamp = (time_t) EC32(file_hdr.TimeDateStamp);
aa9a0f4b
     cli_dbgmsg("TimeDateStamp: %s", cli_ctime(&timestamp, timestr, sizeof(timestr)));
6307ca15
 
636b7178
 #if HAVE_JSON
fcff42e9
     if (pe_json != NULL)
         cli_jsonstr(pe_json, "TimeDateStamp", cli_ctime(&timestamp, timestr, sizeof(timestr)));
636b7178
 #endif
 
d399f19b
     cli_dbgmsg("SizeOfOptionalHeader: %x\n", EC16(file_hdr.SizeOfOptionalHeader));
6307ca15
 
636b7178
 #if HAVE_JSON
fcff42e9
     if (pe_json != NULL)
         cli_jsonint(pe_json, "SizeOfOptionalHeader", EC16(file_hdr.SizeOfOptionalHeader));
636b7178
 #endif
 
57866af1
     if (EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) {
172c4dd2
 #if HAVE_JSON
         pe_add_heuristic_property(ctx, "BadOptionalHeaderSize");
 #endif
57866af1
         cli_dbgmsg("SizeOfOptionalHeader too small\n");
f98a68af
         if(DETECT_BROKEN_PE) {
d87dfbb2
             ret = cli_append_virus(ctx,"Heuristics.Broken.Executable");
             return ret;
f98a68af
         }
 
         return CL_CLEAN;
6307ca15
     }
 
a5241d27
     at = e_lfanew + sizeof(struct pe_image_file_hdr);
     if(fmap_readn(map, &optional_hdr32, at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) {
57866af1
         cli_dbgmsg("Can't read optional file header\n");
f98a68af
         if(DETECT_BROKEN_PE) {
d87dfbb2
             ret = cli_append_virus(ctx,"Heuristics.Broken.Executable");
             return ret;
f98a68af
         }
 
         return CL_CLEAN;
57866af1
     }
a5241d27
     at += sizeof(struct pe_image_optional_hdr32);
667a4b35
 
57866af1
     /* This will be a chicken and egg problem until we drop 9x */
3d478af1
     if(EC16(optional_hdr64.Magic)==PE32P_SIGNATURE) {
172c4dd2
 #if HAVE_JSON
         pe_add_heuristic_property(ctx, "BadOptionalHeaderSizePE32Plus");
 #endif
57866af1
         if(EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr64)) {
f98a68af
             /* FIXME: need to play around a bit more with xp64 */
             cli_dbgmsg("Incorrect SizeOfOptionalHeader for PE32+\n");
 
             if(DETECT_BROKEN_PE) {
d87dfbb2
                 ret = cli_append_virus(ctx,"Heuristics.Broken.Executable");
                 return ret;
f98a68af
             }
 
             return CL_CLEAN;
         }
         pe_plus = 1;
57866af1
     }
 
     if(!pe_plus) { /* PE */
f98a68af
         if (EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr32)) {
             /* Seek to the end of the long header */
             at += EC16(file_hdr.SizeOfOptionalHeader)-sizeof(struct pe_image_optional_hdr32);
         }
57866af1
 
f98a68af
         if(DCONF & PE_CONF_UPACK)
             upack = (EC16(file_hdr.SizeOfOptionalHeader)==0x148);
 
         vep = EC32(optional_hdr32.AddressOfEntryPoint);
         hdr_size = EC32(optional_hdr32.SizeOfHeaders);
         cli_dbgmsg("File format: PE\n");
 
         cli_dbgmsg("MajorLinkerVersion: %d\n", optional_hdr32.MajorLinkerVersion);
         cli_dbgmsg("MinorLinkerVersion: %d\n", optional_hdr32.MinorLinkerVersion);
         cli_dbgmsg("SizeOfCode: 0x%x\n", EC32(optional_hdr32.SizeOfCode));
         cli_dbgmsg("SizeOfInitializedData: 0x%x\n", EC32(optional_hdr32.SizeOfInitializedData));
         cli_dbgmsg("SizeOfUninitializedData: 0x%x\n", EC32(optional_hdr32.SizeOfUninitializedData));
         cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", vep);
         cli_dbgmsg("BaseOfCode: 0x%x\n", EC32(optional_hdr32.BaseOfCode));
         cli_dbgmsg("SectionAlignment: 0x%x\n", EC32(optional_hdr32.SectionAlignment));
         cli_dbgmsg("FileAlignment: 0x%x\n", EC32(optional_hdr32.FileAlignment));
         cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(optional_hdr32.MajorSubsystemVersion));
         cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(optional_hdr32.MinorSubsystemVersion));
         cli_dbgmsg("SizeOfImage: 0x%x\n", EC32(optional_hdr32.SizeOfImage));
         cli_dbgmsg("SizeOfHeaders: 0x%x\n", hdr_size);
         cli_dbgmsg("NumberOfRvaAndSizes: %d\n", EC32(optional_hdr32.NumberOfRvaAndSizes));
         dirs = optional_hdr32.DataDirectory;
636b7178
 #if HAVE_JSON
fcff42e9
         if (pe_json != NULL) {
             cli_jsonint(pe_json, "MajorLinkerVersion", optional_hdr32.MajorLinkerVersion);
             cli_jsonint(pe_json, "MinorLinkerVersion", optional_hdr32.MinorLinkerVersion);
             cli_jsonint(pe_json, "SizeOfCode", EC32(optional_hdr32.SizeOfCode));
             cli_jsonint(pe_json, "SizeOfInitializedData", EC32(optional_hdr32.SizeOfInitializedData));
             cli_jsonint(pe_json, "SizeOfUninitializedData", EC32(optional_hdr32.SizeOfUninitializedData));
             cli_jsonint(pe_json, "NumberOfRvaAndSizes", EC32(optional_hdr32.NumberOfRvaAndSizes));
             cli_jsonint(pe_json, "MajorSubsystemVersion", EC16(optional_hdr32.MajorSubsystemVersion));
             cli_jsonint(pe_json, "MinorSubsystemVersion", EC16(optional_hdr32.MinorSubsystemVersion));
636b7178
 
fcff42e9
             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(optional_hdr32.BaseOfCode));
             cli_jsonstr(pe_json, "BaseOfCode", jsonbuf);
636b7178
 
fcff42e9
             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(optional_hdr32.SectionAlignment));
             cli_jsonstr(pe_json, "SectionAlignment", jsonbuf);
636b7178
 
fcff42e9
             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(optional_hdr32.FileAlignment));
             cli_jsonstr(pe_json, "FileAlignment", jsonbuf);
636b7178
 
fcff42e9
             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(optional_hdr32.SizeOfImage));
             cli_jsonstr(pe_json, "SizeOfImage", jsonbuf);
636b7178
 
fcff42e9
             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", hdr_size);
             cli_jsonstr(pe_json, "SizeOfHeaders", jsonbuf);
         }
636b7178
 #endif
667a4b35
 
     } else { /* PE+ */
f98a68af
             /* read the remaining part of the header */
             if(fmap_readn(map, &optional_hdr32 + 1, at, sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) {
             cli_dbgmsg("Can't read optional file header\n");
             if(DETECT_BROKEN_PE) {
d87dfbb2
                 ret = cli_append_virus(ctx,"Heuristics.Broken.Executable");
                 return ret;
f98a68af
             }
 
             return CL_CLEAN;
         }
 
         at += sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32);
         vep = EC32(optional_hdr64.AddressOfEntryPoint);
         hdr_size = EC32(optional_hdr64.SizeOfHeaders);
         cli_dbgmsg("File format: PE32+\n");
 
         cli_dbgmsg("MajorLinkerVersion: %d\n", optional_hdr64.MajorLinkerVersion);
         cli_dbgmsg("MinorLinkerVersion: %d\n", optional_hdr64.MinorLinkerVersion);
         cli_dbgmsg("SizeOfCode: 0x%x\n", EC32(optional_hdr64.SizeOfCode));
         cli_dbgmsg("SizeOfInitializedData: 0x%x\n", EC32(optional_hdr64.SizeOfInitializedData));
         cli_dbgmsg("SizeOfUninitializedData: 0x%x\n", EC32(optional_hdr64.SizeOfUninitializedData));
         cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", vep);
         cli_dbgmsg("BaseOfCode: 0x%x\n", EC32(optional_hdr64.BaseOfCode));
         cli_dbgmsg("SectionAlignment: 0x%x\n", EC32(optional_hdr64.SectionAlignment));
         cli_dbgmsg("FileAlignment: 0x%x\n", EC32(optional_hdr64.FileAlignment));
         cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(optional_hdr64.MajorSubsystemVersion));
         cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(optional_hdr64.MinorSubsystemVersion));
         cli_dbgmsg("SizeOfImage: 0x%x\n", EC32(optional_hdr64.SizeOfImage));
         cli_dbgmsg("SizeOfHeaders: 0x%x\n", hdr_size);
         cli_dbgmsg("NumberOfRvaAndSizes: %d\n", EC32(optional_hdr64.NumberOfRvaAndSizes));
         dirs = optional_hdr64.DataDirectory;
636b7178
 #if HAVE_JSON
fcff42e9
         if (pe_json != NULL) {
             cli_jsonint(pe_json, "MajorLinkerVersion", optional_hdr64.MajorLinkerVersion);
             cli_jsonint(pe_json, "MinorLinkerVersion", optional_hdr64.MinorLinkerVersion);
             cli_jsonint(pe_json, "SizeOfCode", EC32(optional_hdr64.SizeOfCode));
             cli_jsonint(pe_json, "SizeOfInitializedData", EC32(optional_hdr64.SizeOfInitializedData));
             cli_jsonint(pe_json, "SizeOfUninitializedData", EC32(optional_hdr64.SizeOfUninitializedData));
             cli_jsonint(pe_json, "NumberOfRvaAndSizes", EC32(optional_hdr64.NumberOfRvaAndSizes));
             cli_jsonint(pe_json, "MajorSubsystemVersion", EC16(optional_hdr64.MajorSubsystemVersion));
             cli_jsonint(pe_json, "MinorSubsystemVersion", EC16(optional_hdr64.MinorSubsystemVersion));
636b7178
 
fcff42e9
             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(optional_hdr64.BaseOfCode));
             cli_jsonstr(pe_json, "BaseOfCode", jsonbuf);
636b7178
 
fcff42e9
             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(optional_hdr64.SectionAlignment));
             cli_jsonstr(pe_json, "SectionAlignment", jsonbuf);
636b7178
 
fcff42e9
             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(optional_hdr64.FileAlignment));
             cli_jsonstr(pe_json, "FileAlignment", jsonbuf);
636b7178
 
fcff42e9
             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(optional_hdr64.SizeOfImage));
             cli_jsonstr(pe_json, "SizeOfImage", jsonbuf);
636b7178
 
fcff42e9
             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", hdr_size);
             cli_jsonstr(pe_json, "SizeOfHeaders", jsonbuf);
         }
636b7178
 #endif
6307ca15
     }
 
172c4dd2
 #if HAVE_JSON
     if (ctx->options & CL_SCAN_FILE_PROPERTIES) {
         snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", vep);
fcff42e9
         if (pe_json != NULL)
             cli_jsonstr(pe_json, "EntryPoint", jsonbuf);
172c4dd2
     }
 #endif
 
e1e5af58
 
667a4b35
     switch(pe_plus ? EC16(optional_hdr64.Subsystem) : EC16(optional_hdr32.Subsystem)) {
f98a68af
     case 0:
172c4dd2
         subsystem = "Unknown";
f98a68af
         break;
     case 1:
172c4dd2
         subsystem = "Native (svc)";
f98a68af
         native = 1;
         break;
     case 2:
172c4dd2
         subsystem = "Win32 GUI";
f98a68af
         break;
     case 3:
172c4dd2
         subsystem = "Win32 console";
f98a68af
         break;
     case 5:
172c4dd2
         subsystem = "OS/2 console";
f98a68af
         break;
     case 7:
172c4dd2
         subsystem = "POSIX console";
f98a68af
         break;
     case 8:
172c4dd2
         subsystem = "Native Win9x driver";
f98a68af
         break;
     case 9:
172c4dd2
         subsystem = "WinCE GUI";
f98a68af
         break;
     case 10:
172c4dd2
         subsystem = "EFI application";
f98a68af
         break;
     case 11:
172c4dd2
         subsystem = "EFI driver";
f98a68af
         break;
     case 12:
172c4dd2
         subsystem = "EFI runtime driver";
f98a68af
         break;
     case 13:
172c4dd2
         subsystem = "EFI ROM image";
f98a68af
         break;
     case 14:
172c4dd2
         subsystem = "Xbox";
f98a68af
         break;
     case 16:
172c4dd2
         subsystem = "Boot application";
f98a68af
         break;
     default:
172c4dd2
         subsystem = "Unknown";
6307ca15
     }
 
172c4dd2
     cli_dbgmsg("Subsystem: %s\n", subsystem);
 
 #if HAVE_JSON
fcff42e9
     if (pe_json != NULL)
         cli_jsonstr(pe_json, "Subsystem", subsystem);
172c4dd2
 #endif
 
85dd8460
     cli_dbgmsg("------------------------------------\n");
6307ca15
 
c6b9d863
     if (DETECT_BROKEN_PE && !native && (!(pe_plus?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment)) || (pe_plus?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment))%0x1000)) {
4921d90b
         cli_dbgmsg("Bad virtual alignment\n");
d87dfbb2
         ret = cli_append_virus(ctx,"Heuristics.Broken.Executable");
         return ret;
5deedfa5
     }
 
c6b9d863
     if (DETECT_BROKEN_PE && !native && (!(pe_plus?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment)) || (pe_plus?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment))%0x200)) {
4921d90b
         cli_dbgmsg("Bad file alignment\n");
d87dfbb2
         ret = cli_append_virus(ctx, "Heuristics.Broken.Executable");
         return ret;
5deedfa5
     }
 
a5241d27
     fsize = map->len;
e0264472
 
a9082ea2
     section_hdr = (struct pe_image_section_hdr *) cli_calloc(nsections, sizeof(struct pe_image_section_hdr));
ac75a532
 
     if(!section_hdr) {
f98a68af
         cli_dbgmsg("Can't allocate memory for section headers\n");
         return CL_EMEM;
ac75a532
     }
 
57866af1
     exe_sections = (struct cli_exe_section *) cli_calloc(nsections, sizeof(struct cli_exe_section));
     
     if(!exe_sections) {
f98a68af
         cli_dbgmsg("Can't allocate memory for section headers\n");
         free(section_hdr);
         return CL_EMEM;
57866af1
     }
6307ca15
 
57866af1
     valign = (pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment);
     falign = (pe_plus)?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment);
 
a5241d27
     if(fmap_readn(map, section_hdr, at, sizeof(struct pe_image_section_hdr)*nsections) != (int)(nsections*sizeof(struct pe_image_section_hdr))) {
57866af1
         cli_dbgmsg("Can't read section header\n");
f98a68af
         cli_dbgmsg("Possibly broken PE file\n");
 
         free(section_hdr);
         free(exe_sections);
 
         if(DETECT_BROKEN_PE) {
d87dfbb2
             ret = cli_append_virus(ctx,"Heuristics.Broken.Executable");
             return ret;
f98a68af
         }
 
         return CL_CLEAN;
57866af1
     }
f98a68af
 
a5241d27
     at += sizeof(struct pe_image_section_hdr)*nsections;
 
57866af1
     for(i = 0; falign!=0x200 && i<nsections; i++) {
f98a68af
         /* file alignment fallback mode - blah */
         if (falign && section_hdr[i].SizeOfRawData && EC32(section_hdr[i].PointerToRawData)%falign && !(EC32(section_hdr[i].PointerToRawData)%0x200)) {
             cli_dbgmsg("Found misaligned section, using 0x200\n");
             falign = 0x200;
         }
57866af1
     }
6307ca15
 
9c0614e8
     hdr_size = PESALIGN(hdr_size, valign); /* Aligned headers virtual size */
5deedfa5
 
172c4dd2
 #if HAVE_JSON
fcff42e9
     if (pe_json != NULL)
         cli_jsonint(pe_json, "NumberOfSections", nsections);
172c4dd2
 #endif
 
fc3794a5
     while (rescan==1) {
         rescan=0;
         for (i=0; i < nsections; i++) {
             exe_sections[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign);
             exe_sections[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign);
             exe_sections[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign);
             exe_sections[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign);
             exe_sections[i].chr = EC32(section_hdr[i].Characteristics);
             exe_sections[i].urva = EC32(section_hdr[i].VirtualAddress); /* Just in case */
             exe_sections[i].uvsz = EC32(section_hdr[i].VirtualSize);
             exe_sections[i].uraw = EC32(section_hdr[i].PointerToRawData);
             exe_sections[i].ursz = EC32(section_hdr[i].SizeOfRawData);
 
             if (exe_sections[i].rsz) { /* Don't bother with virtual only sections */
182c2d69
                 if (exe_sections[i].raw >= fsize || exe_sections[i].uraw > fsize) {
fc3794a5
                     cli_dbgmsg("Broken PE file - Section %d starts or exists beyond the end of file (Offset@ %lu, Total filesize %lu)\n", i, (unsigned long)exe_sections[i].raw, (unsigned long)fsize);
                     if (nsections == 1) {
                         free(section_hdr);
                         free(exe_sections);
 
                         if(DETECT_BROKEN_PE) {
d87dfbb2
                             ret = cli_append_virus(ctx, "Heuristics.Broken.Executable");
                             return ret;
fc3794a5
                         }
 
                         return CL_CLEAN; /* no ninjas to see here! move along! */
                     }
 
                     for (j=i; j < nsections-1; j++)
                         memcpy(&exe_sections[j], &exe_sections[j+1], sizeof(struct cli_exe_section));
 
                     for (j=i; j < nsections-1; j++)
                         memcpy(&section_hdr[j], &section_hdr[j+1], sizeof(struct pe_image_section_hdr));
 
                     nsections--;
                     rescan=1;
                     break;
                 }
182c2d69
 
                 if (!CLI_ISCONTAINED(0, (uint32_t) fsize, exe_sections[i].raw, exe_sections[i].rsz))
                     exe_sections[i].rsz = fsize - exe_sections[i].raw;
 
                 if (!CLI_ISCONTAINED(0, fsize, exe_sections[i].uraw, exe_sections[i].ursz))
                     exe_sections[i].ursz = fsize - exe_sections[i].uraw;
fc3794a5
             }
         }
     }
 
182c2d69
     for(i = 0; i < nsections; i++) {
fc3794a5
         strncpy(sname, (char *) section_hdr[i].Name, 8);
         sname[8] = 0;
3c45f3f4
 
172c4dd2
 #if HAVE_JSON
20b45621
         add_section_info(ctx, &exe_sections[i]);
 
         if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) {
             free(section_hdr);
             free(exe_sections);
             return CL_ETIMEOUT;
         }
172c4dd2
 #endif
 
f98a68af
         if (!exe_sections[i].vsz && exe_sections[i].rsz)
             exe_sections[i].vsz=PESALIGN(exe_sections[i].ursz, valign);
 
         cli_dbgmsg("Section %d\n", i);
         cli_dbgmsg("Section name: %s\n", sname);
         cli_dbgmsg("Section data (from headers - in memory)\n");
         cli_dbgmsg("VirtualSize: 0x%x 0x%x\n", exe_sections[i].uvsz, exe_sections[i].vsz);
         cli_dbgmsg("VirtualAddress: 0x%x 0x%x\n", exe_sections[i].urva, exe_sections[i].rva);
         cli_dbgmsg("SizeOfRawData: 0x%x 0x%x\n", exe_sections[i].ursz, exe_sections[i].rsz);
         cli_dbgmsg("PointerToRawData: 0x%x 0x%x\n", exe_sections[i].uraw, exe_sections[i].raw);
 
         if(exe_sections[i].chr & 0x20) {
             cli_dbgmsg("Section contains executable code\n");
 
             if(exe_sections[i].vsz < exe_sections[i].rsz) {
                 cli_dbgmsg("Section contains free space\n");
                 /*
                 cli_dbgmsg("Dumping %d bytes\n", section_hdr.SizeOfRawData - section_hdr.VirtualSize);
                 ddump(desc, section_hdr.PointerToRawData + section_hdr.VirtualSize, section_hdr.SizeOfRawData - section_hdr.VirtualSize, cli_gentemp(NULL));
                 */
             }
         }
6c9455c2
 
f98a68af
         if(exe_sections[i].chr & 0x20000000)
             cli_dbgmsg("Section's memory is executable\n");
6307ca15
 
f98a68af
         if(exe_sections[i].chr & 0x80000000)
             cli_dbgmsg("Section's memory is writeable\n");
9ad59d16
 
f98a68af
         if (DETECT_BROKEN_PE && (!valign || (exe_sections[i].urva % valign))) { /* Bad virtual alignment */
             cli_dbgmsg("VirtualAddress is misaligned\n");
             cli_dbgmsg("------------------------------------\n");
d87dfbb2
             ret = cli_append_virus(ctx, "Heuristics.Broken.Executable");
f98a68af
             free(section_hdr);
             free(exe_sections);
d87dfbb2
             return ret;
f98a68af
         }
9ad59d16
 
f98a68af
         if (exe_sections[i].rsz) { /* Don't bother with virtual only sections */
             if(SCAN_ALGO && (DCONF & PE_CONF_POLIPOS) && !*sname && exe_sections[i].vsz > 40000 && exe_sections[i].vsz < 70000 && exe_sections[i].chr == 0xe0000060) polipos = i;
c09d6c19
 
f98a68af
             /* check hash section sigs */
             if((DCONF & PE_CONF_MD5SECT) && ctx->engine->hm_mdb) {
                 ret = scan_pe_mdb(ctx, &exe_sections[i]);
                 if (ret != CL_CLEAN) {
                     if (ret != CL_VIRUS)
                         cli_errmsg("scan_pe: scan_pe_mdb failed: %s!\n", cl_strerror(ret));
f0f7f92f
 
f98a68af
                     cli_dbgmsg("------------------------------------\n");
                     free(section_hdr);
                     free(exe_sections);
                     return ret;
                 }
             }
         }
         cli_dbgmsg("------------------------------------\n");
6c9455c2
 
f98a68af
         if (exe_sections[i].urva>>31 || exe_sections[i].uvsz>>31 || (exe_sections[i].rsz && exe_sections[i].uraw>>31) || exe_sections[i].ursz>>31) {
             cli_dbgmsg("Found PE values with sign bit set\n");
 
             free(section_hdr);
             free(exe_sections);
             if(DETECT_BROKEN_PE) {
d87dfbb2
                 ret = cli_append_virus(ctx, "Heuristics.Broken.Executable");
                 return ret;
f98a68af
             }
 
             return CL_CLEAN;
         }
 
         if(!i) {
             if (DETECT_BROKEN_PE && exe_sections[i].urva!=hdr_size) { /* Bad first section RVA */
                 cli_dbgmsg("First section is in the wrong place\n");
d87dfbb2
                 ret = cli_append_virus(ctx, "Heuristics.Broken.Executable");
f98a68af
                 free(section_hdr);
                 free(exe_sections);
d87dfbb2
                 return ret;
f98a68af
             }
 
             min = exe_sections[i].rva;
             max = exe_sections[i].rva + exe_sections[i].rsz;
         } else {
             if (DETECT_BROKEN_PE && exe_sections[i].urva - exe_sections[i-1].urva != exe_sections[i-1].vsz) { /* No holes, no overlapping, no virtual disorder */
                 cli_dbgmsg("Virtually misplaced section (wrong order, overlapping, non contiguous)\n");
d87dfbb2
                 ret = cli_append_virus(ctx, "Heuristics.Broken.Executable");
f98a68af
                 free(section_hdr);
                 free(exe_sections);
d87dfbb2
                 return ret;
f98a68af
             }
 
             if(exe_sections[i].rva < min)
                 min = exe_sections[i].rva;
 
             if(exe_sections[i].rva + exe_sections[i].rsz > max) {
                 max = exe_sections[i].rva + exe_sections[i].rsz;
                 overlays = exe_sections[i].raw + exe_sections[i].rsz;
             }
         }
6307ca15
     }
 
e9d44a24
     free(section_hdr);
 
5deedfa5
     if(!(ep = cli_rawaddr(vep, exe_sections, nsections, &err, fsize, hdr_size)) && err) {
f98a68af
         cli_dbgmsg("EntryPoint out of file\n");
         free(exe_sections);
         if(DETECT_BROKEN_PE) {
d87dfbb2
             ret = cli_append_virus(ctx,"Heuristics.Broken.Executable");
             return ret;
f98a68af
         }
 
         return CL_CLEAN;
6307ca15
     }
 
172c4dd2
 #if HAVE_JSON
fcff42e9
     if (pe_json != NULL)
         cli_jsonint(pe_json, "EntryPointOffset", ep);
20b45621
 
     if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) {
         return CL_ETIMEOUT;
     }
172c4dd2
 #endif
 
342e27a5
     cli_dbgmsg("EntryPoint offset: 0x%x (%d)\n", ep, ep);
 
5c9300e7
     if(pe_plus) { /* Do not continue for PE32+ files */
f98a68af
         free(exe_sections);
         return CL_CLEAN;
5c9300e7
     }
 
a5241d27
     epsize = fmap_readn(map, epbuff, ep, 4096);
fa4f9e8b
 
59098a11
 
     /* Disasm scan disabled since it's now handled by the bytecode */
 
     /* CLI_UNPTEMP("DISASM",(exe_sections,0)); */
     /* if(disasmbuf((unsigned char*)epbuff, epsize, ndesc)) */
     /* 	ret = cli_scandesc(ndesc, ctx, CL_TYPE_PE_DISASM, 1, NULL, AC_SCAN_VIR); */
     /* close(ndesc); */
     /* CLI_TMPUNLK(); */
     /* free(tempfile); */
     /* if(ret == CL_VIRUS) { */
     /* 	free(exe_sections); */
     /* 	return ret; */
     /* } */
68a77450
 
56e5821b
     if(overlays) {
f98a68af
         int overlays_sz = fsize - overlays;
         if(overlays_sz > 0) {
             ret = cli_scanishield(ctx, overlays, overlays_sz);
             if(ret != CL_CLEAN) {
                 free(exe_sections);
                 return ret;
             }
         }
56e5821b
     }
 
0df99607
     pedata.nsections = nsections;
     pedata.ep = ep;
     pedata.offset = 0;
     memcpy(&pedata.file_hdr, &file_hdr, sizeof(file_hdr));
     memcpy(&pedata.opt32, &pe_opt.opt32, sizeof(pe_opt.opt32));
     memcpy(&pedata.opt64, &pe_opt.opt64, sizeof(pe_opt.opt64));
     memcpy(&pedata.dirs, dirs, sizeof(pedata.dirs));
     pedata.e_lfanew = e_lfanew;
     pedata.overlays = overlays;
     pedata.overlays_sz = fsize - overlays;
     pedata.hdr_size = hdr_size;
 
     /* Bytecode BC_PE_ALL hook */
     bc_ctx = cli_bytecode_context_alloc();
     if (!bc_ctx) {
f98a68af
         cli_errmsg("cli_scanpe: can't allocate memory for bc_ctx\n");
         free(exe_sections);
         return CL_EMEM;
0df99607
     }
f98a68af
 
0df99607
     cli_bytecode_context_setpe(bc_ctx, &pedata, exe_sections);
     cli_bytecode_context_setctx(bc_ctx, ctx);
6ad45a29
     ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_ALL, map);
6a049897
     switch (ret) {
         case CL_ENULLARG:
             cli_warnmsg("cli_scanpe: NULL argument supplied\n");
             break;
         case CL_VIRUS:
         case CL_BREAK:
             free(exe_sections);
             cli_bytecode_context_destroy(bc_ctx);
             return ret == CL_VIRUS ? CL_VIRUS : CL_CLEAN;
0df99607
     }
042a78ac
     cli_bytecode_context_destroy(bc_ctx);
7478245e
 
     /* Attempt to run scans on import table */
03cc2476
     /* Run if there are existing signatures and/or preclassing */
7959fb61
 #if HAVE_JSON
97d552f5
     if (DCONF & PE_CONF_IMPTBL && (ctx->engine->hm_imp || ctx->wrkproperty)) {
7959fb61
 #else
97d552f5
     if (DCONF & PE_CONF_IMPTBL && ctx->engine->hm_imp) {
7959fb61
 #endif
c96e3331
         ret = scan_pe_imp(ctx, dirs, exe_sections, nsections, hdr_size, pe_plus);
03cc2476
         switch (ret) {
7959fb61
             case CL_SUCCESS:
                 break;
03cc2476
             case CL_ENULLARG:
                 cli_warnmsg("cli_scanpe: NULL argument supplied\n");
7478245e
                 break;
03cc2476
             case CL_VIRUS:
                 if (SCAN_ALL)
                     break;
                 /* intentional fall-through */
             case CL_BREAK:
                 free(exe_sections);
                 return ret == CL_VIRUS ? CL_VIRUS : CL_CLEAN;
7959fb61
             default:
                 free(exe_sections);
                 return ret;
03cc2476
         }
7478245e
     }
41fd7c2f
     /* Attempt to detect some popular polymorphic viruses */
 
     /* W32.Parite.B */
95e31dc7
     if(SCAN_ALGO && (DCONF & PE_CONF_PARITE) && !dll && epsize == 4096 && ep == exe_sections[nsections - 1].raw) {
         const char *pt = cli_memstr(epbuff, 4040, "\x47\x65\x74\x50\x72\x6f\x63\x41\x64\x64\x72\x65\x73\x73\x00", 15);
f98a68af
         if(pt) {
             pt += 15;
             if((((uint32_t)cli_readint32(pt) ^ (uint32_t)cli_readint32(pt + 4)) == 0x505a4f) && (((uint32_t)cli_readint32(pt + 8) ^ (uint32_t)cli_readint32(pt + 12)) == 0xffffb) && (((uint32_t)cli_readint32(pt + 16) ^ (uint32_t)cli_readint32(pt + 20)) == 0xb8)) {
d87dfbb2
                 ret = cli_append_virus(ctx,"Heuristics.W32.Parite.B");
                 if (ret != CL_CLEAN) {
                     if (ret == CL_VIRUS) {
                         if (!SCAN_ALL) {
                             free(exe_sections);
                             return ret;
                         }
                         else
                             viruses_found++;
                     } else {
                         free(exe_sections);
                         return ret;
                     }
f98a68af
                 }
             }
         }
41fd7c2f
     }
 
343316ab
     /* Kriz */
a993c5ad
     if(SCAN_ALGO && (DCONF & PE_CONF_KRIZ) && epsize >= 200 && CLI_ISCONTAINED(exe_sections[nsections - 1].raw, exe_sections[nsections - 1].rsz, ep, 0x0fd2) && epbuff[1]=='\x9c' && epbuff[2]=='\x60') {
f98a68af
         enum {KZSTRASH,KZSCDELTA,KZSPDELTA,KZSGETSIZE,KZSXORPRFX,KZSXOR,KZSDDELTA,KZSLOOP,KZSTOP};
         uint8_t kzs[] = {KZSTRASH,KZSCDELTA,KZSPDELTA,KZSGETSIZE,KZSTRASH,KZSXORPRFX,KZSXOR,KZSTRASH,KZSDDELTA,KZSTRASH,KZSLOOP,KZSTOP};
         uint8_t *kzstate = kzs;
         uint8_t *kzcode = (uint8_t *)epbuff + 3;
         uint8_t kzdptr=0xff, kzdsize=0xff;
         int kzlen = 197, kzinitlen=0xffff, kzxorlen=-1;
         cli_dbgmsg("in kriz\n");
 
         while(*kzstate!=KZSTOP) {
             uint8_t op;
             if(kzlen<=6)
                 break;
 
             op = *kzcode++;
             kzlen--;
 
             switch (*kzstate) {
             case KZSTRASH:
             case KZSGETSIZE: {
                 int opsz=0;
                 switch(op) {
                 case 0x81:
                     kzcode+=5;
                     kzlen-=5;
                     break;
                 case 0xb8:
                 case 0xb9:
                 case 0xba:
                 case 0xbb:
                 case 0xbd:
                 case 0xbe:
                 case 0xbf:
                     if(*kzstate==KZSGETSIZE && cli_readint32(kzcode)==0x0fd2) {
                         kzinitlen = kzlen-5;
                         kzdsize=op-0xb8;
                         kzstate++;
                         op=4; /* fake the register to avoid breaking out */
 
                         cli_dbgmsg("kriz: using #%d as size counter\n", kzdsize);
                     }
                     opsz=4;
                 case 0x48:
                 case 0x49:
                 case 0x4a:
                 case 0x4b:
                 case 0x4d:
                 case 0x4e:
                 case 0x4f:
                     op&=7;
                     if(op!=kzdptr && op!=kzdsize) {
                         kzcode+=opsz;
                         kzlen-=opsz;
                         break;
                     }
                 default:
                     kzcode--;
                     kzlen++;
                     kzstate++;
                 }
 
                 break;
             }
             case KZSCDELTA:
                 if(op==0xe8 && (uint32_t)cli_readint32(kzcode) < 0xff) {
                     kzlen-=*kzcode+4;
                     kzcode+=*kzcode+4;
                     kzstate++;
                 } else {
                     *kzstate=KZSTOP;
                 }
 
                 break;
             case KZSPDELTA:
                 if((op&0xf8)==0x58 && (kzdptr=op-0x58)!=4) {
                     kzstate++;
                     cli_dbgmsg("kriz: using #%d as pointer\n", kzdptr);
                 } else {
                     *kzstate=KZSTOP;
                 }
 
                 break;
             case KZSXORPRFX:
                 kzstate++;
                 if(op==0x3e)
                     break;
             case KZSXOR:
                 if (op==0x80 && *kzcode==kzdptr+0xb0) {
                     kzxorlen=kzlen;
                     kzcode+=+6;
                     kzlen-=+6;
                     kzstate++;
                 } else {
                     *kzstate=KZSTOP;
                 }
 
                 break;
             case KZSDDELTA:
                 if (op==kzdptr+0x48)
                     kzstate++;
                 else
                     *kzstate=KZSTOP;
 
                 break;
             case KZSLOOP:
                 if (op==kzdsize+0x48 && *kzcode==0x75 && kzlen-(int8_t)kzcode[1]-3<=kzinitlen && kzlen-(int8_t)kzcode[1]>=kzxorlen) {
d87dfbb2
                     ret = cli_append_virus(ctx,"Heuristics.W32.Kriz");
                     if (ret != CL_CLEAN) {
                         if (ret == CL_VIRUS) {
                             if (!SCAN_ALL) {
                                 free(exe_sections);
                                 return ret;
                             }
                             else
                                 viruses_found++;
                         } else {
                             free(exe_sections);
                             return ret;
                         }
f98a68af
                     }
                 }
                 cli_dbgmsg("kriz: loop out of bounds, corrupted sample?\n");
                 kzstate++;
             }
         }
343316ab
     }
 
9ad59d16
     /* W32.Magistr.A/B */
e9d44a24
     if(SCAN_ALGO && (DCONF & PE_CONF_MAGISTR) && !dll && (nsections>1) && (exe_sections[nsections - 1].chr & 0x80000000)) {
95e31dc7
         uint32_t rsize, vsize, dam = 0;
9ad59d16
 
f98a68af
         vsize = exe_sections[nsections - 1].uvsz;
         rsize = exe_sections[nsections - 1].rsz;
         if(rsize < exe_sections[nsections - 1].ursz) {
             rsize = exe_sections[nsections - 1].ursz;
             dam = 1;
         }
9ad59d16
 
f98a68af
         if(vsize >= 0x612c && rsize >= 0x612c && ((vsize & 0xff) == 0xec)) {
             int bw = rsize < 0x7000 ? rsize : 0x7000;
             const char *tbuff;
9ad59d16
 
f98a68af
             if((tbuff = fmap_need_off_once(map, exe_sections[nsections - 1].raw + rsize - bw, 4096))) {
                 if(cli_memstr(tbuff, 4091, "\xe8\x2c\x61\x00\x00", 5)) {
d87dfbb2
                     ret = cli_append_virus(ctx, dam ? "Heuristics.W32.Magistr.A.dam" : "Heuristics.W32.Magistr.A");
                     if (ret != CL_CLEAN) {
                         if (ret == CL_VIRUS) {
                             if (!SCAN_ALL) {
                                 free(exe_sections);
                                 return ret;
                             }
                             else
                                 viruses_found++;
                         } else {
                             free(exe_sections);
                             return ret;
                         }
f98a68af
                     }
                 }
             }
         } else if(rsize >= 0x7000 && vsize >= 0x7000 && ((vsize & 0xff) == 0xed)) {
             int bw = rsize < 0x8000 ? rsize : 0x8000;
             const char *tbuff;
 
             if((tbuff = fmap_need_off_once(map, exe_sections[nsections - 1].raw + rsize - bw, 4096))) {
                 if(cli_memstr(tbuff, 4091, "\xe8\x04\x72\x00\x00", 5)) {
d87dfbb2
                     ret = cli_append_virus(ctx,dam ? "Heuristics.W32.Magistr.B.dam" : "Heuristics.W32.Magistr.B");
                     if (ret != CL_CLEAN) {
                         if (ret == CL_VIRUS) {
                             if (!SCAN_ALL) {
                                 free(exe_sections);
                                 return ret;
                             }
                             else
                                 viruses_found++;
                         } else {
                             free(exe_sections);
                             return ret;
                         }
f98a68af
                     }
                 } 
             }
         }
9ad59d16
     }
 
be62f8ce
     /* W32.Polipos.A */
95e31dc7
     while(polipos && !dll && nsections > 2 && nsections < 13 && e_lfanew <= 0x800 && (EC16(optional_hdr32.Subsystem) == 2 || EC16(optional_hdr32.Subsystem) == 3) && EC16(file_hdr.Machine) == 0x14c && optional_hdr32.SizeOfStackReserve >= 0x80000) {
f98a68af
         uint32_t jump, jold, *jumps = NULL;
         const uint8_t *code;
         unsigned int xsjs = 0;
 
         if(exe_sections[0].rsz > CLI_MAX_ALLOCATION)
             break;
be8b084e
         if(exe_sections[0].rsz < 5)
f98a68af
             break;
         if(!(code=fmap_need_off_once(map, exe_sections[0].raw, exe_sections[0].rsz)))
             break;
 
         for(i=0; i<exe_sections[0].rsz - 5; i++) {
             if((uint8_t)(code[i]-0xe8) > 1)
                 continue;
 
             jump = cli_rawaddr(exe_sections[0].rva+i+5+cli_readint32(&code[i+1]), exe_sections, nsections, &err, fsize, hdr_size);
             if(err || !CLI_ISCONTAINED(exe_sections[polipos].raw, exe_sections[polipos].rsz, jump, 9))
                 continue;
 
             if(xsjs % 128 == 0) {
                 if(xsjs == 1280)
                     break;
 
                 if(!(jumps=(uint32_t *)cli_realloc2(jumps, (xsjs+128)*sizeof(uint32_t)))) {
                     free(exe_sections);
                     return CL_EMEM;
                 }
             }
 
             j=0;
             for(; j<xsjs; j++) {
                 if(jumps[j]<jump)
                     continue;
                 if(jumps[j]==jump) {
                     xsjs--;
                     break;
                 }
 
                 jold=jumps[j];
                 jumps[j]=jump;
                 jump=jold;
             }
 
             jumps[j]=jump;
             xsjs++;
         }
 
         if(!xsjs)
             break;
 
         cli_dbgmsg("Polipos: Checking %d xsect jump(s)\n", xsjs);
         for(i=0;i<xsjs;i++) {
             if(!(code = fmap_need_off_once(map, jumps[i], 9)))
                 continue;
 
             if((jump=cli_readint32(code))==0x60ec8b55 || (code[4]==0x0ec && ((jump==0x83ec8b55 && code[6]==0x60) || (jump==0x81ec8b55 && !code[7] && !code[8])))) {
d87dfbb2
                 ret = cli_append_virus(ctx,"Heuristics.W32.Polipos.A");
                 if (ret != CL_CLEAN) {
                     if (ret == CL_VIRUS) {
                         if (!SCAN_ALL) {
                             free(jumps);
                             free(exe_sections);
                             return ret;
                         }
                         else
                             viruses_found++;
                     } else {
                         free(jumps);
                         free(exe_sections);
                         return ret;
                     }
f98a68af
                 }
             }
         }
 
         free(jumps);
         break;
be62f8ce
     }
 
42d26ac9
     /* Trojan.Swizzor.Gen */
     if (SCAN_ALGO && (DCONF & PE_CONF_SWIZZOR) && nsections > 1 && fsize > 64*1024 && fsize < 4*1024*1024) {
f98a68af
         if(dirs[2].Size) {
             struct swizz_stats *stats = cli_calloc(1, sizeof(*stats));
             unsigned int m = 1000;
             ret = CL_CLEAN;
 
             if (!stats) {
d87dfbb2
                 free(exe_sections);
                 return CL_EMEM;
f98a68af
             } else {
                 cli_parseres_special(EC32(dirs[2].VirtualAddress), EC32(dirs[2].VirtualAddress), map, exe_sections, nsections, fsize, hdr_size, 0, 0, &m, stats);
d87dfbb2
                 if ((ret = cli_detect_swizz(stats)) == CL_VIRUS) {
                     ret = cli_append_virus(ctx,"Heuristics.Trojan.Swizzor.Gen");
                     if (ret != CL_CLEAN) {
                         if (ret == CL_VIRUS) {
                             if (!SCAN_ALL) {
                                 free(stats);
                                 free(exe_sections);
                                 return ret;
                             }
                             else
                                 viruses_found++;
                         } else {
                             free(stats);
                             free(exe_sections);
                             return ret;
                         }
                     }
f98a68af
                 }
             }
         }
42d26ac9
     }
3fcb62ca
 
50177b5c
 
     /* !!!!!!!!!!!!!!    PACKERS START HERE    !!!!!!!!!!!!!! */
f5933780
     corrupted_cur = ctx->corrupted_input;
50177b5c
     ctx->corrupted_input = 2; /* caller will reset on return */
 
 
4aa4a05c
     /* UPX, FSG, MEW support */
a9082ea2
 
     /* try to find the first section with physical size == 0 */
     found = 0;
b6aee321
     if(DCONF & (PE_CONF_UPX | PE_CONF_FSG | PE_CONF_MEW)) {
f98a68af
         for(i = 0; i < (unsigned int) nsections - 1; i++) {
             if(!exe_sections[i].rsz && exe_sections[i].vsz && exe_sections[i + 1].rsz && exe_sections[i + 1].vsz) {
                 found = 1;
                 cli_dbgmsg("UPX/FSG/MEW: empty section found - assuming compression\n");
172c4dd2
 #if HAVE_JSON
fcff42e9
                 if (pe_json != NULL)
                     cli_jsonbool(pe_json, "HasEmptySection", 1);
172c4dd2
 #endif
f98a68af
                 break;
             }
         }
a9082ea2
     }
 
4aa4a05c
     /* MEW support */
95e31dc7
     if (found && (DCONF & PE_CONF_MEW) && epsize>=16 && epbuff[0]=='\xe9') {
f98a68af
         uint32_t fileoffset;
         const char *tbuff;
4aa4a05c
 
f98a68af
         fileoffset = (vep + cli_readint32(epbuff + 1) + 5);
         while (fileoffset == 0x154 || fileoffset == 0x158) {
             char *src;
             uint32_t offdiff, uselzma;
4aa4a05c
 
f98a68af
             cli_dbgmsg ("MEW: found MEW characteristics %08X + %08X + 5 = %08X\n", 
                 cli_readint32(epbuff + 1), vep, cli_readint32(epbuff + 1) + vep + 5);
4aa4a05c
 
f98a68af
             if(!(tbuff = fmap_need_off_once(map, fileoffset, 0xb0)))
                 break;
4aa4a05c
 
f98a68af
             if (fileoffset == 0x154)
                 cli_dbgmsg("MEW: Win9x compatibility was set!\n");
             else
                 cli_dbgmsg("MEW: Win9x compatibility was NOT set!\n");
4aa4a05c
 
f98a68af
             if((offdiff = cli_readint32(tbuff+1) - EC32(optional_hdr32.ImageBase)) <= exe_sections[i + 1].rva || offdiff >= exe_sections[i + 1].rva + exe_sections[i + 1].raw - 4) {
                 cli_dbgmsg("MEW: ESI is not in proper section\n");
                 break;
             }
4aa4a05c
 
f98a68af
             offdiff -= exe_sections[i + 1].rva;
4aa4a05c
 
f98a68af
             if(!exe_sections[i + 1].rsz) {
                 cli_dbgmsg("MEW: mew section is empty\n");
                 break;
             }
4aa4a05c
 
f98a68af
             ssize = exe_sections[i + 1].vsz;
             dsize = exe_sections[i].vsz;
a5241d27
 
f98a68af
             cli_dbgmsg("MEW: ssize %08x dsize %08x offdiff: %08x\n", ssize, dsize, offdiff);
4aa4a05c
 
f98a68af
             CLI_UNPSIZELIMITS("MEW", MAX(ssize, dsize));
             CLI_UNPSIZELIMITS("MEW", MAX(ssize + dsize, exe_sections[i + 1].rsz));
 
             if (exe_sections[i + 1].rsz < offdiff + 12 || exe_sections[i + 1].rsz > ssize) {
                 cli_dbgmsg("MEW: Size mismatch: %08x\n", exe_sections[i + 1].rsz);
                 break;
             }
 
             /* allocate needed buffer */
             if (!(src = cli_calloc (ssize + dsize, sizeof(char)))) {
                 free(exe_sections);
                 return CL_EMEM;
             }
 
             if((bytes = fmap_readn(map, src + dsize, exe_sections[i + 1].raw, exe_sections[i + 1].rsz)) != exe_sections[i + 1].rsz) {
                 cli_dbgmsg("MEW: Can't read %d bytes [read: %lu]\n", exe_sections[i + 1].rsz, (unsigned long)bytes);
                 free(exe_sections);
                 free(src);
                 return CL_EREAD;
             }
 
             cli_dbgmsg("MEW: %u (%08x) bytes read\n", (unsigned int)bytes, (unsigned int)bytes);
 
             /* count offset to lzma proc, if lzma used, 0xe8 -> call */
             if (tbuff[0x7b] == '\xe8') {
                 if (!CLI_ISCONTAINED(exe_sections[1].rva, exe_sections[1].vsz, cli_readint32(tbuff + 0x7c) + fileoffset + 0x80, 4)) {
                     cli_dbgmsg("MEW: lzma proc out of bounds!\n");
                     free(src);
                     break; /* to next unpacker in chain */
                 }
 
                 uselzma = cli_readint32(tbuff + 0x7c) - (exe_sections[0].rva - fileoffset - 0x80);
             } else {
                 uselzma = 0;
             }
e9d44a24
 
172c4dd2
 #if HAVE_JSON
fcff42e9
             if (pe_json != NULL)
                 cli_jsonstr(pe_json, "Packer", "MEW");
172c4dd2
 #endif
 
f98a68af
             CLI_UNPTEMP("MEW",(src,exe_sections,0));
             CLI_UNPRESULTS("MEW",(unmew11(src, offdiff, ssize, dsize, EC32(optional_hdr32.ImageBase), exe_sections[0].rva, uselzma, ndesc)),1,(src,0));
             break;
         }
95e31dc7
     }
03a2d04a
 
95e31dc7
     if(epsize<168) {
f98a68af
         free(exe_sections);
         return CL_CLEAN;
95e31dc7
     }
 
     if (found || upack) {
f98a68af
         /* Check EP for UPX vs. FSG vs. Upack */
 
         /* Upack 0.39 produces 2 types of executables
          * 3 sections:           | 2 sections (one empty, I don't chech found if !upack, since it's in OR above):
          *   mov esi, value      |   pusha
          *   lodsd               |   call $+0x9
          *   push eax            |
          *
          * Upack 1.1/1.2 Beta produces [based on 2 samples (sUx) provided by aCaB]:
          * 2 sections
          *   mov esi, value
          *   loads
          *   mov edi, eax
          *
          * Upack unknown [sample 0297729]
          * 3 sections
          *   mov esi, value
          *   push [esi]
          *   jmp
          * 
          */
         /* upack 0.39-3s + sample 0151477*/
         while(((upack && nsections == 3) && /* 3 sections */
             ((
              epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) > min && /* mov esi */
              epbuff[5] == '\xad' && epbuff[6] == '\x50' /* lodsd; push eax */
              )
             || 
             /* based on 0297729 sample from aCaB */
             (epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) > min && /* mov esi */
              epbuff[5] == '\xff' && epbuff[6] == '\x36' /* push [esi] */
              )
            )) 
            ||
            ((!upack && nsections == 2) && /* 2 sections */
             (( /* upack 0.39-2s */
              epbuff[0] == '\x60' && epbuff[1] == '\xe8' && cli_readint32(epbuff+2) == 0x9 /* pusha; call+9 */
              )
             ||
             ( /* upack 1.1/1.2, based on 2 samples */
              epbuff[0] == '\xbe' && cli_readint32(epbuff+1) - EC32(optional_hdr32.ImageBase) < min &&  /* mov esi */
              cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) > 0 &&
              epbuff[5] == '\xad' && epbuff[6] == '\x8b' && epbuff[7] == '\xf8' /* loads;  mov edi, eax */
              )
            ))
            ) { 
             uint32_t vma, off;
             int a,b,c;
 
             cli_dbgmsg("Upack characteristics found.\n");
             a = exe_sections[0].vsz;
             b = exe_sections[1].vsz;
             if (upack) {
                 cli_dbgmsg("Upack: var set\n");
 
                 c = exe_sections[2].vsz;
                 ssize = exe_sections[0].ursz + exe_sections[0].uraw;
                 off = exe_sections[0].rva;
                 vma = EC32(optional_hdr32.ImageBase) + exe_sections[0].rva;
             } else {
                 cli_dbgmsg("Upack: var NOT set\n");
                 c = exe_sections[1].rva;
                 ssize = exe_sections[1].uraw;
                 off = 0;
                 vma = exe_sections[1].rva - exe_sections[1].uraw;
             }
e8042398
 
f98a68af
             dsize = a+b+c;
e8042398
 
f98a68af
             CLI_UNPSIZELIMITS("Upack", MAX(MAX(dsize, ssize), exe_sections[1].ursz));
e8042398
 
f98a68af
             if (!CLI_ISCONTAINED(0, dsize, exe_sections[1].rva - off, exe_sections[1].ursz) || (upack && !CLI_ISCONTAINED(0, dsize, exe_sections[2].rva - exe_sections[0].rva, ssize)) || ssize > dsize) {
                 cli_dbgmsg("Upack: probably malformed pe-header, skipping to next unpacker\n");
                 break;
             }
                 
             if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
                 free(exe_sections);
                 return CL_EMEM;
             }
e8042398
 
f98a68af
             if((unsigned int)fmap_readn(map, dest, 0, ssize) != ssize) {
                 cli_dbgmsg("Upack: Can't read raw data of section 0\n");
                 free(dest);
                 break;
             }
e8042398
 
f98a68af
             if(upack)
                 memmove(dest + exe_sections[2].rva - exe_sections[0].rva, dest, ssize);
9a25caf3
 
f98a68af
             if((unsigned int)fmap_readn(map, dest + exe_sections[1].rva - off, exe_sections[1].uraw, exe_sections[1].ursz) != exe_sections[1].ursz) {
                 cli_dbgmsg("Upack: Can't read raw data of section 1\n");
                 free(dest);
                 break;
             }
342e27a5
 
172c4dd2
 #if HAVE_JSON
fcff42e9
             if (pe_json != NULL)
                 cli_jsonstr(pe_json, "Packer", "Upack");
172c4dd2
 #endif
 
f98a68af
             CLI_UNPTEMP("Upack",(dest,exe_sections,0));
             CLI_UNPRESULTS("Upack",(unupack(upack, dest, dsize, epbuff, vma, ep, EC32(optional_hdr32.ImageBase), exe_sections[0].rva, ndesc)),1,(dest,0));
342e27a5
 
f98a68af
             break;
         }
     }
95e31dc7
     
f304dc68
     while(found  && (DCONF & PE_CONF_FSG) && epbuff[0] == '\x87' && epbuff[1] == '\x25') {
f98a68af
         const char *dst;
         uint32_t newesi, newedi, newebx, newedx;
03a2d04a
 
f98a68af
         /* FSG v2.0 support - thanks to aCaB ! */
         
         ssize = exe_sections[i + 1].rsz;
         dsize = exe_sections[i].vsz;
03a2d04a
 
f98a68af
         CLI_UNPSIZELIMITS("FSG", MAX(dsize, ssize));
5f1a932b
 
f98a68af
         if(ssize <= 0x19 || dsize <= ssize) {
             cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
             free(exe_sections);
             return CL_CLEAN;
         }
         
         newedx = cli_readint32(epbuff + 2) - EC32(optional_hdr32.ImageBase);
         if(!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newedx, 4)) {
             cli_dbgmsg("FSG: xchg out of bounds (%x), giving up\n", newedx);
             break;
         }
         
         if(!exe_sections[i + 1].rsz || !(src = fmap_need_off_once(map, exe_sections[i + 1].raw, ssize))) {
             cli_dbgmsg("Can't read raw data of section %d\n", i + 1);
             free(exe_sections);
             return CL_ESEEK;
         }
5f1a932b
 
f98a68af
         dst = src + newedx - exe_sections[i + 1].rva;
         if(newedx < exe_sections[i + 1].rva || !CLI_ISCONTAINED(src, ssize, dst, 4)) {
             cli_dbgmsg("FSG: New ESP out of bounds\n");
             break;
         }
5f1a932b
 
f98a68af
         newedx = cli_readint32(dst) - EC32(optional_hdr32.ImageBase);
         if(!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newedx, 4)) {
             cli_dbgmsg("FSG: New ESP (%x) is wrong\n", newedx);
             break;
         }
      
         dst = src + newedx - exe_sections[i + 1].rva;
         if(!CLI_ISCONTAINED(src, ssize, dst, 32)) {
             cli_dbgmsg("FSG: New stack out of bounds\n");
             break;
         }
5f1a932b
 
f98a68af
         newedi = cli_readint32(dst) - EC32(optional_hdr32.ImageBase);
         newesi = cli_readint32(dst + 4) - EC32(optional_hdr32.ImageBase);
         newebx = cli_readint32(dst + 16) - EC32(optional_hdr32.ImageBase);
         newedx = cli_readint32(dst + 20);
5f1a932b
 
f98a68af
         if(newedi != exe_sections[i].rva) {
             cli_dbgmsg("FSG: Bad destination buffer (edi is %x should be %x)\n", newedi, exe_sections[i].rva);
             break;
         }
5f1a932b
 
f98a68af
         if(newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].rsz) {
             cli_dbgmsg("FSG: Source buffer out of section bounds\n");
             break;
         }
5f1a932b
 
f98a68af
         if(!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newebx, 16)) {
             cli_dbgmsg("FSG: Array of functions out of bounds\n");
             break;
         }
5f1a932b
 
f98a68af
         newedx=cli_readint32(newebx + 12 - exe_sections[i + 1].rva + src) - EC32(optional_hdr32.ImageBase);
         cli_dbgmsg("FSG: found old EP @%x\n",newedx);
5f1a932b
 
f98a68af
         if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
             free(exe_sections);
             return CL_EMEM;
         }
5f1a932b
 
172c4dd2
 #if HAVE_JSON
fcff42e9
         if (pe_json != NULL)
             cli_jsonstr(pe_json, "Packer", "FSG");
172c4dd2
 #endif
 
f98a68af
         CLI_UNPTEMP("FSG",(dest,exe_sections,0));
         CLI_UNPRESULTSFSG2("FSG",(unfsg_200(newesi - exe_sections[i + 1].rva + src, dest, ssize + exe_sections[i + 1].rva - newesi, dsize, newedi, EC32(optional_hdr32.ImageBase), newedx, ndesc)),1,(dest,0));
         break;
95e31dc7
     }
e0264472
 
8080fbe3
 
95e31dc7
     while(found && (DCONF & PE_CONF_FSG) && epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) < min) {
f98a68af
         int sectcnt = 0;
         const char *support;
         uint32_t newesi, newedi, oldep, gp, t;
         struct cli_exe_section *sections;
5f1a932b
 
f98a68af
         /* FSG support - v. 1.33 (thx trog for the many samples) */
03a2d04a
 
f98a68af
         ssize = exe_sections[i + 1].rsz;
         dsize = exe_sections[i].vsz;
5eb34fac
 
f98a68af
         CLI_UNPSIZELIMITS("FSG", MAX(dsize, ssize));
5eb34fac
 
f98a68af
         if(ssize <= 0x19 || dsize <= ssize) {
             cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
             free(exe_sections);
             return CL_CLEAN;
         }
5eb34fac
 
f98a68af
         if(!(t = cli_rawaddr(cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase), NULL, 0 , &err, fsize, hdr_size)) && err ) {
             cli_dbgmsg("FSG: Support data out of padding area\n");
             break;
         }
5eb34fac
 
f98a68af
         gp = exe_sections[i + 1].raw - t;
5eb34fac
 
f98a68af
         CLI_UNPSIZELIMITS("FSG", gp);
5eb34fac
 
f98a68af
         if(!(support = fmap_need_off_once(map, t, gp))) {
             cli_dbgmsg("Can't read %d bytes from padding area\n", gp); 
             free(exe_sections);
             return CL_EREAD;
         }
f628a181
 
f98a68af
         /* newebx = cli_readint32(support) - EC32(optional_hdr32.ImageBase);  Unused */
         newedi = cli_readint32(support + 4) - EC32(optional_hdr32.ImageBase); /* 1st dest */
         newesi = cli_readint32(support + 8) - EC32(optional_hdr32.ImageBase); /* Source */
5eb34fac
 
f98a68af
         if(newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].rsz) {
             cli_dbgmsg("FSG: Source buffer out of section bounds\n");
             break;
         }
5eb34fac
 
f98a68af
         if(newedi != exe_sections[i].rva) {
             cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, exe_sections[i].rva);
             break;
         }
5eb34fac
 
f98a68af
         /* Counting original sections */
         for(t = 12; t < gp - 4; t += 4) {
             uint32_t rva = cli_readint32(support+t);
5eb34fac
 
f98a68af
             if(!rva)
                 break;
5eb34fac
 
f98a68af
             rva -= EC32(optional_hdr32.ImageBase)+1;
             sectcnt++;
5eb34fac
 
f98a68af
             if(rva % 0x1000)
                 cli_dbgmsg("FSG: Original section %d is misaligned\n", sectcnt);
5eb34fac
 
f98a68af
             if(rva < exe_sections[i].rva || rva - exe_sections[i].rva >= exe_sections[i].vsz) {
                 cli_dbgmsg("FSG: Original section %d is out of bounds\n", sectcnt);
                 break;
             }
         }
5eb34fac
 
f98a68af
         if(t >= gp - 4 || cli_readint32(support + t)) {
             break;
         }
5eb34fac
 
f98a68af
         if((sections = (struct cli_exe_section *) cli_malloc((sectcnt + 1) * sizeof(struct cli_exe_section))) == NULL) {
059ca614
             cli_errmsg("FSG: Unable to allocate memory for sections %llu\n", (long long unsigned)((sectcnt + 1) * sizeof(struct cli_exe_section)));
f98a68af
             free(exe_sections);
             return CL_EMEM;
         }
5eb34fac
 
f98a68af
         sections[0].rva = newedi;
         for(t = 1; t <= (uint32_t)sectcnt; t++)
             sections[t].rva = cli_readint32(support + 8 + t * 4) - 1 - EC32(optional_hdr32.ImageBase);
5eb34fac
 
f98a68af
         if(!exe_sections[i + 1].rsz || !(src = fmap_need_off_once(map, exe_sections[i + 1].raw, ssize))) {
             cli_dbgmsg("Can't read raw data of section %d\n", i);
             free(exe_sections);
             free(sections);
             return CL_EREAD;
         }
5eb34fac
 
f98a68af
         if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
             free(exe_sections);
             free(sections);
             return CL_EMEM;
         }
5eb34fac
 
f98a68af
         oldep = vep + 161 + 6 + cli_readint32(epbuff+163);
         cli_dbgmsg("FSG: found old EP @%x\n", oldep);
5eb34fac
 
172c4dd2
 #if HAVE_JSON
fcff42e9
         if (pe_json != NULL)
             cli_jsonstr(pe_json, "Packer", "FSG");
172c4dd2
 #endif
 
f98a68af
         CLI_UNPTEMP("FSG",(dest,sections,exe_sections,0));
         CLI_UNPRESULTSFSG1("FSG",(unfsg_133(src + newesi - exe_sections[i + 1].rva, dest, ssize + exe_sections[i + 1].rva - newesi, dsize, sections, sectcnt, EC32(optional_hdr32.ImageBase), oldep, ndesc)),1,(dest,sections,0));
         break; /* were done with 1.33 */
95e31dc7
     }
5eb34fac
 
95e31dc7
     while(found && (DCONF & PE_CONF_FSG) && epbuff[0] == '\xbb' && cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) < min && epbuff[5] == '\xbf' && epbuff[10] == '\xbe' && vep >= exe_sections[i + 1].rva && vep - exe_sections[i + 1].rva > exe_sections[i + 1].rva - 0xe0 ) {
f98a68af
         int sectcnt = 0;
         uint32_t gp, t = cli_rawaddr(cli_readint32(epbuff+1) - EC32(optional_hdr32.ImageBase), NULL, 0 , &err, fsize, hdr_size);
         const char *support;
         uint32_t newesi = cli_readint32(epbuff+11) - EC32(optional_hdr32.ImageBase);
         uint32_t newedi = cli_readint32(epbuff+6) - EC32(optional_hdr32.ImageBase);
         uint32_t oldep = vep - exe_sections[i + 1].rva;
         struct cli_exe_section *sections;
5eb34fac
 
f98a68af
         /* FSG support - v. 1.31 */
5eb34fac
 
f98a68af
         ssize = exe_sections[i + 1].rsz;
         dsize = exe_sections[i].vsz;
5eb34fac
 
f98a68af
         if(err) {
             cli_dbgmsg("FSG: Support data out of padding area\n");
             break;
         }
5eb34fac
 
f98a68af
         if(newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].raw) {
             cli_dbgmsg("FSG: Source buffer out of section bounds\n");
             break;
         }
f628a181
 
f98a68af
         if(newedi != exe_sections[i].rva) {
             cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, exe_sections[i].rva);
             break;
         }
f628a181
 
f98a68af
         CLI_UNPSIZELIMITS("FSG", MAX(dsize, ssize));
f628a181
 
f98a68af
         if(ssize <= 0x19 || dsize <= ssize) {
             cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
             free(exe_sections);
             return CL_CLEAN;
         }
f628a181
 
f98a68af
         gp = exe_sections[i + 1].raw - t;
f628a181
 
f98a68af
         CLI_UNPSIZELIMITS("FSG", gp)
f628a181
 
f98a68af
         if(!(support = fmap_need_off_once(map, t, gp))) {
             cli_dbgmsg("Can't read %d bytes from padding area\n", gp); 
             free(exe_sections);
             return CL_EREAD;
         }
f628a181
 
f98a68af
         /* Counting original sections */
         for(t = 0; t < gp - 2; t += 2) {
             uint32_t rva = support[t]|(support[t+1]<<8);
f628a181
 
f98a68af
             if (rva == 2 || rva == 1)
                 break;
f628a181
 
f98a68af
             rva = ((rva-2)<<12) - EC32(optional_hdr32.ImageBase);
             sectcnt++;
f628a181
 
f98a68af
             if(rva < exe_sections[i].rva || rva - exe_sections[i].rva >= exe_sections[i].vsz) {
                 cli_dbgmsg("FSG: Original section %d is out of bounds\n", sectcnt);
                 break;
             }
         }
f628a181
 
f98a68af
         if(t >= gp-10 || cli_readint32(support + t + 6) != 2)
             break;
f628a181
 
f98a68af
         if((sections = (struct cli_exe_section *) cli_malloc((sectcnt + 1) * sizeof(struct cli_exe_section))) == NULL) {
059ca614
             cli_errmsg("FSG: Unable to allocate memory for sections %llu\n", (long long unsigned)((sectcnt + 1) * sizeof(struct cli_exe_section)));
f98a68af
             free(exe_sections);
             return CL_EMEM;
         }
f628a181
 
f98a68af
         sections[0].rva = newedi;
         for(t = 0; t <= (uint32_t)sectcnt - 1; t++)
             sections[t+1].rva = (((support[t*2]|(support[t*2+1]<<8))-2)<<12)-EC32(optional_hdr32.ImageBase);
f628a181
 
f98a68af
         if(!exe_sections[i + 1].rsz || !(src = fmap_need_off_once(map, exe_sections[i + 1].raw, ssize))) {
             cli_dbgmsg("FSG: Can't read raw data of section %d\n", i);
             free(exe_sections);
             free(sections);
             return CL_EREAD;
         }
f628a181
 
f98a68af
         if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
             free(exe_sections);
             free(sections);
             return CL_EMEM;
         }
f628a181
 
f98a68af
         gp = 0xda + 6*(epbuff[16]=='\xe8');
         oldep = vep + gp + 6 + cli_readint32(src+gp+2+oldep);
         cli_dbgmsg("FSG: found old EP @%x\n", oldep);
f628a181
 
172c4dd2
 #if HAVE_JSON
fcff42e9
         if (pe_json != NULL)
             cli_jsonstr(pe_json, "Packer", "FSG");
172c4dd2
 #endif
 
f98a68af
         CLI_UNPTEMP("FSG",(dest,sections,exe_sections,0));
         CLI_UNPRESULTSFSG1("FSG",(unfsg_133(src + newesi - exe_sections[i + 1].rva, dest, ssize + exe_sections[i + 1].rva - newesi, dsize, sections, sectcnt, EC32(optional_hdr32.ImageBase), oldep, ndesc)),1,(dest,sections,0));
 
         break; /* were done with 1.31 */
95e31dc7
     }
f628a181
 
 
95e31dc7
     if(found && (DCONF & PE_CONF_UPX)) {
f98a68af
         ssize = exe_sections[i + 1].rsz;
         dsize = exe_sections[i].vsz + exe_sections[i + 1].vsz;
e0264472
 
f98a68af
         /* 
          * UPX support
          * we assume (i + 1) is UPX1
          */
f628a181
 
f98a68af
             /* cli_dbgmsg("UPX: ssize %u dsize %u\n", ssize, dsize); */
f628a181
 
f98a68af
         CLI_UNPSIZELIMITS("UPX", MAX(dsize, ssize));
10882c9f
 
f98a68af
         if(ssize <= 0x19 || dsize <= ssize || dsize > CLI_MAX_ALLOCATION ) {
             cli_dbgmsg("UPX: Size mismatch or dsize too big (ssize: %d, dsize: %d)\n", ssize, dsize);
             free(exe_sections);
             return CL_CLEAN;
         }
f628a181
 
f98a68af
         if(!exe_sections[i + 1].rsz || !(src = fmap_need_off_once(map, exe_sections[i + 1].raw, ssize))) {
             cli_dbgmsg("UPX: Can't read raw data of section %d\n", i+1);
             free(exe_sections);
             return CL_EREAD;
         }
f628a181
 
f98a68af
         if((dest = (char *) cli_calloc(dsize + 8192, sizeof(char))) == NULL) {
             free(exe_sections);
             return CL_EMEM;
         }
f628a181
 
f98a68af
         /* try to detect UPX code */
         if(cli_memstr(UPX_NRV2B, 24, epbuff + 0x69, 13) || cli_memstr(UPX_NRV2B, 24, epbuff + 0x69 + 8, 13)) {
             cli_dbgmsg("UPX: Looks like a NRV2B decompression routine\n");
             upxfn = upx_inflate2b;
         } else if(cli_memstr(UPX_NRV2D, 24, epbuff + 0x69, 13) || cli_memstr(UPX_NRV2D, 24, epbuff + 0x69 + 8, 13)) {
             cli_dbgmsg("UPX: Looks like a NRV2D decompression routine\n");
             upxfn = upx_inflate2d;
         } else if(cli_memstr(UPX_NRV2E, 24, epbuff + 0x69, 13) || cli_memstr(UPX_NRV2E, 24, epbuff + 0x69 + 8, 13)) {
             cli_dbgmsg("UPX: Looks like a NRV2E decompression routine\n");
             upxfn = upx_inflate2e;
         }
e2ff1490
 
f98a68af
         if(upxfn) {
             int skew = cli_readint32(epbuff + 2) - EC32(optional_hdr32.ImageBase) - exe_sections[i + 1].rva;
 
             if(epbuff[1] != '\xbe' || skew <= 0 || skew > 0xfff) {
                 /* FIXME: legit skews?? */
                 skew = 0; 
             } else if ((unsigned int)skew > ssize) {
                 /* Ignore suggested skew larger than section size */
                 skew = 0;
             } else {
                 cli_dbgmsg("UPX: UPX1 seems skewed by %d bytes\n", skew);
             }
5f1a932b
 
f98a68af
             /* Try skewed first (skew may be zero) */
             if(upxfn(src + skew, ssize - skew, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep-skew) >= 0) {
                 upx_success = 1;
             }
             /* If skew not successful and non-zero, try no skew */
             else if(skew && (upxfn(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) >= 0)) {
                 upx_success = 1;
             }
5f1a932b
 
f98a68af
             if(upx_success)
                 cli_dbgmsg("UPX: Successfully decompressed\n");
             else
                 cli_dbgmsg("UPX: Preferred decompressor failed\n");
         }
e37613ad
 
f98a68af
         if(!upx_success && upxfn != upx_inflate2b) {
             if(upx_inflate2b(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2b(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) {
5f1a932b
 
f98a68af
                 cli_dbgmsg("UPX: NRV2B decompressor failed\n");
             } else {
                 upx_success = 1;
                 cli_dbgmsg("UPX: Successfully decompressed with NRV2B\n");
             }
         }
5f1a932b
 
f98a68af
         if(!upx_success && upxfn != upx_inflate2d) {
             if(upx_inflate2d(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2d(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) {
4a24fe30
 
f98a68af
                 cli_dbgmsg("UPX: NRV2D decompressor failed\n");
             } else {
                 upx_success = 1;
                 cli_dbgmsg("UPX: Successfully decompressed with NRV2D\n");
             }
         }
5f1a932b
 
f98a68af
         if(!upx_success && upxfn != upx_inflate2e) {
             if(upx_inflate2e(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2e(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) {
                 cli_dbgmsg("UPX: NRV2E decompressor failed\n");
             } else {
                 upx_success = 1;
                 cli_dbgmsg("UPX: Successfully decompressed with NRV2E\n");
             }
         }
4a24fe30
 
f98a68af
         if(cli_memstr(UPX_LZMA2, 20, epbuff + 0x2f, 20)) {
             uint32_t strictdsize=cli_readint32(epbuff+0x21), skew = 0;
             if(ssize > 0x15 && epbuff[0] == '\x60' && epbuff[1] == '\xbe') {
                 skew = cli_readint32(epbuff+2) - exe_sections[i + 1].rva - optional_hdr32.ImageBase;
                 if(skew!=0x15)
                     skew = 0;
             }
5f1a932b
 
f98a68af
             if(strictdsize<=dsize)
                 upx_success = upx_inflatelzma(src+skew, ssize-skew, dest, &strictdsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) >=0;
         } else if (cli_memstr(UPX_LZMA1, 20, epbuff + 0x39, 20)) {
             uint32_t strictdsize=cli_readint32(epbuff+0x2b), skew = 0;
             if(ssize > 0x15 && epbuff[0] == '\x60' && epbuff[1] == '\xbe') {
                 skew = cli_readint32(epbuff+2) - exe_sections[i + 1].rva - optional_hdr32.ImageBase;
                 if(skew!=0x15)
                     skew = 0;
             }
342e27a5
 
f98a68af
             if(strictdsize<=dsize)
                 upx_success = upx_inflatelzma(src+skew, ssize-skew, dest, &strictdsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) >=0;
         }
f2b223fe
 
f98a68af
         if(!upx_success) {
             cli_dbgmsg("UPX: All decompressors failed\n");
             free(dest);
         }
95e31dc7
     }
e0264472
 
95e31dc7
     if(upx_success) {
f98a68af
         free(exe_sections);
342e27a5
 
f98a68af
         CLI_UNPTEMP("UPX/FSG",(dest,0));
172c4dd2
 #if HAVE_JSON
fcff42e9
         if (pe_json != NULL)
             cli_jsonstr(pe_json, "Packer", "UPX");
172c4dd2
 #endif
4a24fe30
 
f98a68af
         if((unsigned int) write(ndesc, dest, dsize) != dsize) {
             cli_dbgmsg("UPX/FSG: Can't write %d bytes\n", dsize);
             free(tempfile);
             free(dest);
             close(ndesc);
             return CL_EWRITE;
         }
 
         free(dest);
         if (lseek(ndesc, 0, SEEK_SET) == -1) {
             cli_dbgmsg("UPX/FSG: lseek() failed\n");
             close(ndesc);
             CLI_TMPUNLK();
             free(tempfile);
             SHA_RESET;
             return CL_ESEEK;
         }
4a24fe30
 
f98a68af
         if(ctx->engine->keeptmp)
             cli_dbgmsg("UPX/FSG: Decompressed data saved in %s\n", tempfile);
 
         cli_dbgmsg("***** Scanning decompressed file *****\n");
         SHA_OFF;
         if((ret = cli_magic_scandesc(ndesc, ctx)) == CL_VIRUS) {
             close(ndesc);
             CLI_TMPUNLK();
             free(tempfile);
             SHA_RESET;
             return CL_VIRUS;
         }
 
         SHA_RESET;
96914546
         close(ndesc);
         CLI_TMPUNLK();
         free(tempfile);
f98a68af
         return ret;
342e27a5
     }
ac75a532
 
85dd8460
 
95e31dc7
     /* Petite */
85dd8460
 
95e31dc7
     if(epsize<200) {
f98a68af
         free(exe_sections);
         return CL_CLEAN;
20c3d44d
     }
85dd8460
 
95e31dc7
     found = 2;
 
     if(epbuff[0] != '\xb8' || (uint32_t) cli_readint32(epbuff + 1) != exe_sections[nsections - 1].rva + EC32(optional_hdr32.ImageBase)) {
f98a68af
         if(nsections < 2 || epbuff[0] != '\xb8' || (uint32_t) cli_readint32(epbuff + 1) != exe_sections[nsections - 2].rva + EC32(optional_hdr32.ImageBase))
             found = 0;
         else
             found = 1;
85dd8460
     }
 
95e31dc7
     if(found && (DCONF & PE_CONF_PETITE)) {
f98a68af
         cli_dbgmsg("Petite: v2.%d compression detected\n", found);
85dd8460
 
f98a68af
         if(cli_readint32(epbuff + 0x80) == 0x163c988d) {
             cli_dbgmsg("Petite: level zero compression is not supported yet\n");
         } else {
             dsize = max - min;
85dd8460
 
f98a68af
             CLI_UNPSIZELIMITS("Petite", dsize);
85dd8460
 
f98a68af
             if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
                 cli_dbgmsg("Petite: Can't allocate %d bytes\n", dsize);
                 free(exe_sections);
                 return CL_EMEM;
             }
85dd8460
 
f98a68af
             for(i = 0 ; i < nsections; i++) {
                 if(exe_sections[i].raw) {
8aeedf3c
 			unsigned int r_ret;
 
 			if (!exe_sections[i].rsz)
 				goto out_no_petite;
 
 			if (!CLI_ISCONTAINED(dest, dsize,
 					     dest + exe_sections[i].rva - min,
 					     exe_sections[i].ursz))
 				goto out_no_petite;
 
 			r_ret = fmap_readn(map, dest + exe_sections[i].rva - min,
 					exe_sections[i].raw,
 					exe_sections[i].ursz);
 		    if (r_ret != exe_sections[i].ursz) {
 out_no_petite:
f98a68af
                         free(exe_sections);
                         free(dest);
                         return CL_CLEAN;
                     }
                 }
             }
85dd8460
 
172c4dd2
 #if HAVE_JSON
fcff42e9
             if (pe_json != NULL)
                 cli_jsonstr(pe_json, "Packer", "Petite");
172c4dd2
 #endif
 
f98a68af
             CLI_UNPTEMP("Petite",(dest,exe_sections,0));
             CLI_UNPRESULTS("Petite",(petite_inflate2x_1to9(dest, min, max - min, exe_sections, nsections - (found == 1 ? 1 : 0), EC32(optional_hdr32.ImageBase),vep, ndesc, found, EC32(optional_hdr32.DataDirectory[2].VirtualAddress),EC32(optional_hdr32.DataDirectory[2].Size))),0,(dest,0));
         }
85dd8460
     }
 
c2dfe70e
     /* PESpin 1.1 */
 
bc93eda0
     if((DCONF & PE_CONF_PESPIN) && nsections > 1 &&
9a25caf3
        vep >= exe_sections[nsections - 1].rva &&
14d24ec2
        0x3217 - 4 <= exe_sections[nsections - 1].rva + exe_sections[nsections - 1].rsz &&
9a25caf3
        vep < exe_sections[nsections - 1].rva + exe_sections[nsections - 1].rsz - 0x3217 - 4 &&
95e31dc7
        memcmp(epbuff+4, "\xe8\x00\x00\x00\x00\x8b\x1c\x24\x83\xc3", 10) == 0)  {
c2dfe70e
 
f98a68af
         char *spinned;
81030038
 
f98a68af
         CLI_UNPSIZELIMITS("PEspin", fsize);
c2dfe70e
 
f98a68af
         if((spinned = (char *) cli_malloc(fsize)) == NULL) {
             cli_errmsg("PESping: Unable to allocate memory for spinned %lu\n", (unsigned long)fsize);
             free(exe_sections);
             return CL_EMEM;
         }
c2dfe70e
 
f98a68af
         if((size_t) fmap_readn(map, spinned, 0, fsize) != fsize) {
             cli_dbgmsg("PESpin: Can't read %lu bytes\n", (unsigned long)fsize);
             free(spinned);
             free(exe_sections);
             return CL_EREAD;
         }
c2dfe70e
 
172c4dd2
 #if HAVE_JSON
fcff42e9
         if (pe_json != NULL)
             cli_jsonstr(pe_json, "Packer", "PEspin");
172c4dd2
 #endif
 
f98a68af
         CLI_UNPTEMP("PESpin",(spinned,exe_sections,0));
         CLI_UNPRESULTS_("PEspin",SPINCASE(),(unspin(spinned, fsize, exe_sections, nsections - 1, vep, ndesc, ctx)),0,(spinned,0));
c2dfe70e
     }
de800f2a
 
822930fc
 
d0b31fa3
     /* yC 1.3 & variants */
2253fca3
     if((DCONF & PE_CONF_YC) && nsections > 1 &&
d0b31fa3
        (EC32(optional_hdr32.AddressOfEntryPoint) == exe_sections[nsections - 1].rva + 0x60)) {
 
f98a68af
         uint32_t ecx = 0;
         int16_t offset;
d0b31fa3
 
f98a68af
         /* yC 1.3 */
         if (!memcmp(epbuff, "\x55\x8B\xEC\x53\x56\x57\x60\xE8\x00\x00\x00\x00\x5D\x81\xED", 15) &&
             !memcmp(epbuff+0x26, "\x8D\x3A\x8B\xF7\x33\xC0\xEB\x04\x90\xEB\x01\xC2\xAC", 13) &&
             ((uint8_t)epbuff[0x13] == 0xB9) &&
             ((uint16_t)(cli_readint16(epbuff+0x18)) == 0xE981) &&
             !memcmp(epbuff+0x1e,"\x8B\xD5\x81\xC2", 4)) {
d0b31fa3
 
f98a68af
             offset = 0;
             if (0x6c - cli_readint32(epbuff+0xf) + cli_readint32(epbuff+0x22) == 0xC6)
             ecx = cli_readint32(epbuff+0x14) - cli_readint32(epbuff+0x1a);
         }
d0b31fa3
 
f98a68af
         /* yC 1.3 variant */
         if (!ecx && !memcmp(epbuff, "\x55\x8B\xEC\x83\xEC\x40\x53\x56\x57", 9) &&
             !memcmp(epbuff+0x17, "\xe8\x00\x00\x00\x00\x5d\x81\xed", 8) &&
             ((uint8_t)epbuff[0x23] == 0xB9)) {
d0b31fa3
 
f98a68af
             offset = 0x10;
             if (0x6c - cli_readint32(epbuff+0x1f) + cli_readint32(epbuff+0x32) == 0xC6)
             ecx = cli_readint32(epbuff+0x24) - cli_readint32(epbuff+0x2a);
         }
d0b31fa3
 
f98a68af
         /* yC 1.x/modified */
         if (!ecx && !memcmp(epbuff, "\x60\xe8\x00\x00\x00\x00\x5d\x81\xed",9) &&
             ((uint8_t)epbuff[0xd] == 0xb9) &&
             ((uint16_t)cli_readint16(epbuff + 0x12)== 0xbd8d) &&
             !memcmp(epbuff+0x18, "\x8b\xf7\xac", 3)) {
d0b31fa3
 
f98a68af
             offset = -0x18;
             if (0x66 - cli_readint32(epbuff+0x9) + cli_readint32(epbuff+0x14) == 0xae)
             ecx = cli_readint32(epbuff+0xe);
         }
d0b31fa3
 
f98a68af
         if (ecx > 0x800 && ecx < 0x2000 &&
             !memcmp(epbuff+0x63+offset, "\xaa\xe2\xcc", 3) &&
             (fsize >= exe_sections[nsections-1].raw + 0xC6 + ecx + offset)) {
822930fc
 
f98a68af
             char *spinned;
822930fc
 
f98a68af
             if((spinned = (char *) cli_malloc(fsize)) == NULL) {
                 cli_errmsg("yC: Unable to allocate memory for spinned %lu\n", (unsigned long)fsize);
                 free(exe_sections);
                 return CL_EMEM;
             }
822930fc
 
f98a68af
             if((size_t) fmap_readn(map, spinned, 0, fsize) != fsize) {
                 cli_dbgmsg("yC: Can't read %lu bytes\n", (unsigned long)fsize);
                 free(spinned);
                 free(exe_sections);
                 return CL_EREAD;
             }
95e31dc7
 
172c4dd2
 #if HAVE_JSON
fcff42e9
             if (pe_json != NULL)
                 cli_jsonstr(pe_json, "Packer", "yC");
172c4dd2
 #endif
 
771c2309
             do {
                 unsigned int yc_unp_num_viruses = ctx->num_viruses;
                 const char *yc_unp_virname = NULL;
 
                 if (ctx->virname)
                     yc_unp_virname = ctx->virname[0];
 
                 cli_dbgmsg("%d,%d,%d,%d\n", nsections-1, e_lfanew, ecx, offset);
                 CLI_UNPTEMP("yC",(spinned,exe_sections,0));
                 CLI_UNPRESULTS("yC",(yc_decrypt(ctx, spinned, fsize, exe_sections, nsections-1, e_lfanew, ndesc, ecx, offset)),0,(spinned,0));
 
                 if (SCAN_ALL && yc_unp_num_viruses != ctx->num_viruses) {
                     free(exe_sections);
                     return CL_VIRUS;
                 }
                 else if (ctx->virname && yc_unp_virname != ctx->virname[0]) {
                     free(exe_sections);
                     return CL_VIRUS;
                 }
             } while(0);
f98a68af
         }
822930fc
     }
 
60cd49c9
     /* WWPack */
 
f377e052
     while ((DCONF & PE_CONF_WWPACK) && nsections > 1 &&
57866af1
        vep == exe_sections[nsections - 1].rva &&
95e31dc7
        memcmp(epbuff, "\x53\x55\x8b\xe8\x33\xdb\xeb", 7) == 0 &&
        memcmp(epbuff+0x68, "\xe8\x00\x00\x00\x00\x58\x2d\x6d\x00\x00\x00\x50\x60\x33\xc9\x50\x58\x50\x50", 19) == 0)  {
f98a68af
         uint32_t head = exe_sections[nsections - 1].raw;
f377e052
         uint8_t *packer;
f98a68af
         char *src;
60cd49c9
 
f98a68af
         ssize = 0;
         for(i=0 ; ; i++) {
             if(exe_sections[i].raw<head)
                 head=exe_sections[i].raw;
 
             if(i+1==nsections)
                 break;
 
             if(ssize<exe_sections[i].rva+exe_sections[i].vsz)
                 ssize=exe_sections[i].rva+exe_sections[i].vsz;
         }
 
         if(!head || !ssize || head>ssize)
             break;
 
         CLI_UNPSIZELIMITS("WWPack", ssize);
60cd49c9
 
f377e052
         if(!(src=(char *)cli_calloc(ssize, sizeof(char)))) {
f98a68af
             free(exe_sections);
             return CL_EMEM;
         }
 
         if((size_t) fmap_readn(map, src, 0, head) != head) {
             cli_dbgmsg("WWPack: Can't read %d bytes from headers\n", head);
             free(src);
             free(exe_sections);
             return CL_EREAD;
         }
 
f377e052
         for(i = 0 ; i < (unsigned int)nsections-1; i++) {
f98a68af
             if(!exe_sections[i].rsz)
                 continue;
 
             if(!CLI_ISCONTAINED(src, ssize, src+exe_sections[i].rva, exe_sections[i].rsz))
                 break;
 
             if((unsigned int)fmap_readn(map, src+exe_sections[i].rva, exe_sections[i].raw, exe_sections[i].rsz)!=exe_sections[i].rsz)
                 break;
f377e052
         }
f98a68af
 
08402afa
         if(i+1!=nsections) {
f377e052
             cli_dbgmsg("WWpack: Probably hacked/damaged file.\n");
             free(src);
             break;
         }
f98a68af
 
         if((packer = (uint8_t *) cli_calloc(exe_sections[nsections - 1].rsz, sizeof(char))) == NULL) {
             free(src);
             free(exe_sections);
             return CL_EMEM;
         }
 
         if(!exe_sections[nsections - 1].rsz || (size_t) fmap_readn(map, packer, exe_sections[nsections - 1].raw, exe_sections[nsections - 1].rsz) != exe_sections[nsections - 1].rsz) {
             cli_dbgmsg("WWPack: Can't read %d bytes from wwpack sect\n", exe_sections[nsections - 1].rsz);
             free(src);
             free(packer);
             free(exe_sections);
             return CL_EREAD;
         }
60cd49c9
 
172c4dd2
 #if HAVE_JSON
fcff42e9
         if (pe_json != NULL)
             cli_jsonstr(pe_json, "Packer", "WWPack");
172c4dd2
 #endif
 
f98a68af
         CLI_UNPTEMP("WWPack",(src,packer,exe_sections,0));
         CLI_UNPRESULTS("WWPack",(wwunpack((uint8_t *)src, ssize, packer, exe_sections, nsections-1, e_lfanew, ndesc)),0,(src,packer,0));
         break;
60cd49c9
     }
 
95e31dc7
 
2f73b977
     /* ASPACK support */
95e31dc7
     while((DCONF & PE_CONF_ASPACK) && ep+58+0x70e < fsize && !memcmp(epbuff,"\x60\xe8\x03\x00\x00\x00\xe9\xeb",8)) {
f98a68af
         char *src;
2f73b977
 
f98a68af
         if(epsize<0x3bf || memcmp(epbuff+0x3b9, "\x68\x00\x00\x00\x00\xc3",6))
             break;
         ssize = 0;
         for(i=0 ; i< nsections ; i++)
             if(ssize<exe_sections[i].rva+exe_sections[i].vsz)
                 ssize=exe_sections[i].rva+exe_sections[i].vsz;
 
         if(!ssize)
             break;
95e31dc7
 
f98a68af
         CLI_UNPSIZELIMITS("Aspack", ssize);
95e31dc7
 
2f73b977
         if(!(src=(char *)cli_calloc(ssize, sizeof(char)))) {
f98a68af
             free(exe_sections);
             return CL_EMEM;
         }
2f73b977
         for(i = 0 ; i < (unsigned int)nsections; i++) {
f98a68af
             if(!exe_sections[i].rsz)
                 continue;
 
             if(!CLI_ISCONTAINED(src, ssize, src+exe_sections[i].rva, exe_sections[i].rsz))
                 break;
 
             if((unsigned int)fmap_readn(map, src+exe_sections[i].rva, exe_sections[i].raw, exe_sections[i].rsz)!=exe_sections[i].rsz)
                 break;
2f73b977
         }
f98a68af
 
2f73b977
         if(i!=nsections) {
             cli_dbgmsg("Aspack: Probably hacked/damaged Aspack file.\n");
             free(src);
             break;
         }
 
172c4dd2
 #if HAVE_JSON
fcff42e9
         if (pe_json != NULL)
             cli_jsonstr(pe_json, "Packer", "Aspack");
172c4dd2
 #endif
 
f98a68af
         CLI_UNPTEMP("Aspack",(src,exe_sections,0));
         CLI_UNPRESULTS("Aspack",(unaspack212((uint8_t *)src, ssize, exe_sections, nsections, vep-1, EC32(optional_hdr32.ImageBase), ndesc)),1,(src,0));
         break;
2f73b977
     }
 
81030038
     /* NsPack */
 
bc93eda0
     while (DCONF & PE_CONF_NSPACK) {
f98a68af
         uint32_t eprva = vep;
         uint32_t start_of_stuff, rep = ep;
         unsigned int nowinldr;
         const char *nbuff;
 
         src=epbuff;
         if (*epbuff=='\xe9') { /* bitched headers */
             eprva = cli_readint32(epbuff+1)+vep+5;
             if (!(rep = cli_rawaddr(eprva, exe_sections, nsections, &err, fsize, hdr_size)) && err)
                 break;
95e31dc7
 
f98a68af
             if (!(nbuff = fmap_need_off_once(map, rep, 24)))
                 break;
95e31dc7
 
f98a68af
             src = nbuff;
         }
95e31dc7
 
f98a68af
         if (memcmp(src, "\x9c\x60\xe8\x00\x00\x00\x00\x5d\xb8\x07\x00\x00\x00", 13))
             break;
81030038
 
f98a68af
         nowinldr = 0x54-cli_readint32(src+17);
         cli_dbgmsg("NsPack: Found *start_of_stuff @delta-%x\n", nowinldr);
81030038
 
f98a68af
         if(!(nbuff = fmap_need_off_once(map, rep-nowinldr, 4)))
             break;
81030038
 
f98a68af
         start_of_stuff=rep+cli_readint32(nbuff);
         if(!(nbuff = fmap_need_off_once(map, start_of_stuff, 20)))
             break;
81030038
 
f98a68af
         src = nbuff;
         if (!cli_readint32(nbuff)) {
             start_of_stuff+=4; /* FIXME: more to do */
             src+=4;
         }
81030038
 
f98a68af
         ssize = cli_readint32(src+5)|0xff;
         dsize = cli_readint32(src+9);
 
         CLI_UNPSIZELIMITS("NsPack", MAX(ssize,dsize));
 
         if (!ssize || !dsize || dsize != exe_sections[0].vsz)
             break;
 
         if (!(dest=cli_malloc(dsize))) {
             cli_errmsg("NsPack: Unable to allocate memory for dest %u\n", dsize);
             break;
         }
         /* memset(dest, 0xfc, dsize); */
 
         if(!(src = fmap_need_off(map, start_of_stuff, ssize))) {
             free(dest);
             break;
         }
         /* memset(src, 0x00, ssize); */
 
         eprva+=0x27a;
         if (!(rep = cli_rawaddr(eprva, exe_sections, nsections, &err, fsize, hdr_size)) && err) {
           free(dest);
           break;
         }
 
         if(!(nbuff = fmap_need_off_once(map, rep, 5))) {
           free(dest);
           break;
         }
 
         fmap_unneed_off(map, start_of_stuff, ssize);
         eprva=eprva+5+cli_readint32(nbuff+1);
         cli_dbgmsg("NsPack: OEP = %08x\n", eprva);
81030038
 
172c4dd2
 #if HAVE_JSON
fcff42e9
         if (pe_json != NULL)
             cli_jsonstr(pe_json, "Packer", "NsPack");
172c4dd2
 #endif
 
f98a68af
         CLI_UNPTEMP("NsPack",(dest,exe_sections,0));
         CLI_UNPRESULTS("NsPack",(unspack(src, dest, ctx, exe_sections[0].rva, EC32(optional_hdr32.ImageBase), eprva, ndesc)),0,(dest,0));
         break;
81030038
     }
60cd49c9
 
6307ca15
     /* to be continued ... */
 
f5933780
     /* !!!!!!!!!!!!!!    PACKERS END HERE    !!!!!!!!!!!!!! */
     ctx->corrupted_input = corrupted_cur;
 
0df99607
     /* Bytecode BC_PE_UNPACKER hook */
ab636570
     bc_ctx = cli_bytecode_context_alloc();
     if (!bc_ctx) {
f98a68af
         cli_errmsg("cli_scanpe: can't allocate memory for bc_ctx\n");
         return CL_EMEM;
ab636570
     }
f98a68af
 
236fb136
     cli_bytecode_context_setpe(bc_ctx, &pedata, exe_sections);
3ae0a76d
     cli_bytecode_context_setctx(bc_ctx, ctx);
f98a68af
 
6ad45a29
     ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_UNPACKER, map);
3ae0a76d
     switch (ret) {
f98a68af
     case CL_VIRUS:
         free(exe_sections);
         cli_bytecode_context_destroy(bc_ctx);
         return CL_VIRUS;
     case CL_SUCCESS:
         ndesc = cli_bytecode_context_getresult_file(bc_ctx, &tempfile);
         cli_bytecode_context_destroy(bc_ctx);
         if (ndesc != -1 && tempfile) {
             CLI_UNPRESULTS("bytecode PE hook", 1, 1, (0));
         }
 
         break;
     default:
         cli_bytecode_context_destroy(bc_ctx);
3ae0a76d
     }
ab636570
 
57866af1
     free(exe_sections);
f98a68af
 
20b45621
 #if HAVE_JSON
f98a68af
     if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS)
20b45621
         return CL_ETIMEOUT;
 #endif
f98a68af
 
6ad45a29
     if (SCAN_ALL && viruses_found)
f98a68af
         return CL_VIRUS;
 
342e27a5
     return CL_CLEAN;
6307ca15
 }
cdbf8c8e
 
49cc1e3c
 int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo)
cdbf8c8e
 {
017f3490
     uint16_t e_magic; /* DOS signature ("MZ") */
     uint32_t e_lfanew; /* address of new exe header */
     /* Obsolete - see below
       uint32_t min = 0, max = 0;
     */
     struct pe_image_file_hdr file_hdr;
     union {
         struct pe_image_optional_hdr64 opt64;
         struct pe_image_optional_hdr32 opt32;
     } pe_opt;
     struct pe_image_section_hdr *section_hdr;
     unsigned int i;
     unsigned int err, pe_plus = 0;
     uint32_t valign, falign, hdr_size;
     size_t fsize;
     ssize_t at;
     struct pe_image_data_dir *dirs;
cdbf8c8e
 
     cli_dbgmsg("in cli_peheader\n");
 
048d7677
     fsize = map->len - peinfo->offset;
     if(fmap_readn(map, &e_magic, peinfo->offset, sizeof(e_magic)) != sizeof(e_magic)) {
017f3490
         cli_dbgmsg("Can't read DOS signature\n");
         return -1;
cdbf8c8e
     }
 
3b857f14
     if(EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE && EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE_OLD) {
017f3490
         cli_dbgmsg("Invalid DOS signature\n");
         return -1;
cdbf8c8e
     }
 
048d7677
     if(fmap_readn(map, &e_lfanew, peinfo->offset + 58 + sizeof(e_magic), sizeof(e_lfanew)) != sizeof(e_lfanew)) {
017f3490
         /* truncated header? */
         return -1;
cdbf8c8e
     }
 
     e_lfanew = EC32(e_lfanew);
     if(!e_lfanew) {
017f3490
         cli_dbgmsg("Not a PE file\n");
         return -1;
cdbf8c8e
     }
 
048d7677
     if(fmap_readn(map, &file_hdr, peinfo->offset + e_lfanew, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) {
017f3490
         /* bad information in e_lfanew - probably not a PE file */
d87dfbb2
         cli_dbgmsg("cli_peheader: Can't read file header\n");
017f3490
         return -1;
cdbf8c8e
     }
 
1f9eb12b
     if(EC32(file_hdr.Magic) != PE_IMAGE_NT_SIGNATURE) {
017f3490
         cli_dbgmsg("Invalid PE signature (probably NE file)\n");
         return -1;
cdbf8c8e
     }
 
21bf52c0
     if ( (peinfo->nsections = EC16(file_hdr.NumberOfSections)) < 1 || peinfo->nsections > 96 ) return -1;
667a4b35
 
57866af1
     if (EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) {
         cli_dbgmsg("SizeOfOptionalHeader too small\n");
017f3490
         return -1;
57866af1
     }
 
048d7677
     at = peinfo->offset + e_lfanew + sizeof(struct pe_image_file_hdr);
     if(fmap_readn(map, &optional_hdr32, at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) {
57866af1
         cli_dbgmsg("Can't read optional file header\n");
017f3490
         return -1;
57866af1
     }
048d7677
     at += sizeof(struct pe_image_optional_hdr32);
57866af1
 
3d478af1
     if(EC16(optional_hdr64.Magic)==PE32P_SIGNATURE) { /* PE+ */
57866af1
         if(EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr64)) {
017f3490
             cli_dbgmsg("Incorrect SizeOfOptionalHeader for PE32+\n");
             return -1;
         }
 
         if(fmap_readn(map, &optional_hdr32 + 1, at, sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) {
             cli_dbgmsg("Can't read optional file header\n");
             return -1;
         }
 
         at += sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32);
         hdr_size = EC32(optional_hdr64.SizeOfHeaders);
         pe_plus=1;
21bf52c0
     } else { /* PE */
017f3490
         if (EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr32)) {
             /* Seek to the end of the long header */
             at += EC16(file_hdr.SizeOfOptionalHeader)-sizeof(struct pe_image_optional_hdr32);
         }
 
         hdr_size = EC32(optional_hdr32.SizeOfHeaders);
cdbf8c8e
     }
 
57866af1
     valign = (pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment);
     falign = (pe_plus)?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment);
 
453d8180
     peinfo->hdr_size = hdr_size = PESALIGN(hdr_size, valign);
21bf52c0
 
01302683
     peinfo->section = (struct cli_exe_section *) cli_calloc(peinfo->nsections, sizeof(struct cli_exe_section));
cdbf8c8e
 
7ec67e94
     if(!peinfo->section) {
017f3490
         cli_dbgmsg("Can't allocate memory for section headers\n");
         return -1;
cdbf8c8e
     }
 
7ec67e94
     section_hdr = (struct pe_image_section_hdr *) cli_calloc(peinfo->nsections, sizeof(struct pe_image_section_hdr));
cdbf8c8e
 
     if(!section_hdr) {
017f3490
         cli_dbgmsg("Can't allocate memory for section headers\n");
         free(peinfo->section);
         peinfo->section = NULL;
         return -1;
cdbf8c8e
     }
 
048d7677
     if(fmap_readn(map, section_hdr, at, peinfo->nsections * sizeof(struct pe_image_section_hdr)) != peinfo->nsections * sizeof(struct pe_image_section_hdr)) {
21bf52c0
         cli_dbgmsg("Can't read section header\n");
017f3490
         cli_dbgmsg("Possibly broken PE file\n");
         free(section_hdr);
         free(peinfo->section);
         peinfo->section = NULL;
         return -1;
21bf52c0
     }
048d7677
     at += sizeof(struct pe_image_section_hdr)*peinfo->nsections;
cdbf8c8e
 
21bf52c0
     for(i = 0; falign!=0x200 && i<peinfo->nsections; i++) {
017f3490
         /* file alignment fallback mode - blah */
         if (falign && section_hdr[i].SizeOfRawData && EC32(section_hdr[i].PointerToRawData)%falign && !(EC32(section_hdr[i].PointerToRawData)%0x200)) {
             falign = 0x200;
         }
21bf52c0
     }
cdbf8c8e
 
21bf52c0
     for(i = 0; i < peinfo->nsections; i++) {
         peinfo->section[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign);
017f3490
         peinfo->section[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign);
         peinfo->section[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign);
         peinfo->section[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign);
21bf52c0
 
017f3490
         if (!peinfo->section[i].vsz && peinfo->section[i].rsz)
             peinfo->section[i].vsz=PESALIGN(EC32(section_hdr[i].SizeOfRawData), valign);
21bf52c0
 
017f3490
         if (peinfo->section[i].rsz && !CLI_ISCONTAINED(0, (uint32_t) fsize, peinfo->section[i].raw, peinfo->section[i].rsz))
             peinfo->section[i].rsz = (fsize - peinfo->section[i].raw)*(fsize>peinfo->section[i].raw);
239983bc
     }
33f89aa5
 
d2ba6f98
     if(pe_plus) {
017f3490
         peinfo->ep = EC32(optional_hdr64.AddressOfEntryPoint);
         dirs = optional_hdr64.DataDirectory;
d2ba6f98
     } else {
017f3490
         peinfo->ep = EC32(optional_hdr32.AddressOfEntryPoint);
         dirs = optional_hdr32.DataDirectory;
d2ba6f98
     }
667a4b35
 
21bf52c0
     if(!(peinfo->ep = cli_rawaddr(peinfo->ep, peinfo->section, peinfo->nsections, &err, fsize, hdr_size)) && err) {
017f3490
         cli_dbgmsg("Broken PE file\n");
         free(section_hdr);
         free(peinfo->section);
         peinfo->section = NULL;
         return -1;
cdbf8c8e
     }
 
453d8180
     if(EC16(file_hdr.Characteristics) & 0x2000 || !dirs[2].Size)
017f3490
         peinfo->res_addr = 0;
453d8180
     else
017f3490
         peinfo->res_addr = EC32(dirs[2].VirtualAddress);
453d8180
 
04ec2e19
     while(dirs[2].Size) {
017f3490
         struct vinfo_list vlist;
         const uint8_t *vptr, *baseptr;
         uint32_t rva, res_sz;
d2ba6f98
 
017f3490
         memset(&vlist, 0, sizeof(vlist));
         findres(0x10, 0xffffffff, EC32(dirs[2].VirtualAddress), map, peinfo->section, peinfo->nsections, hdr_size, versioninfo_cb, &vlist);
         if(!vlist.count)
             break; /* No version_information */
d2ba6f98
 
017f3490
         if(cli_hashset_init(&peinfo->vinfo, 32, 80)) {
             cli_errmsg("cli_peheader: Unable to init vinfo hashset\n");
             free(section_hdr);
             free(peinfo->section);
             peinfo->section = NULL;
             return -1;
         }
d2ba6f98
 
017f3490
         err = 0;
         for(i=0; i<vlist.count; i++) { /* enum all version_information res - RESUMABLE */
             cli_dbgmsg("cli_peheader: parsing version info @ rva %x (%u/%u)\n", vlist.rvas[i], i+1, vlist.count);
             rva = cli_rawaddr(vlist.rvas[i], peinfo->section, peinfo->nsections, &err, fsize, hdr_size);
             if(err)
                 continue;
 
             if(!(vptr = fmap_need_off_once(map, rva, 16)))
                 continue;
 
             baseptr = vptr - rva;
             /* parse resource */
             rva = cli_readint32(vptr); /* ptr to version_info */
             res_sz = cli_readint32(vptr+4); /* sizeof(resource) */
             rva = cli_rawaddr(rva, peinfo->section, peinfo->nsections, &err, fsize, hdr_size);
             if(err)
                 continue;
             if(!(vptr = fmap_need_off_once(map, rva, res_sz)))
                 continue;
             
             while(res_sz>4) { /* look for version_info - NOT RESUMABLE (expecting exactly one versioninfo) */
                 uint32_t vinfo_sz, vinfo_val_sz, got_varfileinfo = 0;
 
                 vinfo_sz = vinfo_val_sz = cli_readint32(vptr);
                 vinfo_sz &= 0xffff;
                 if(vinfo_sz > res_sz)
                     break; /* the content is larger than the container */
 
                 vinfo_val_sz >>= 16;
                 if(vinfo_sz <= 6 + 0x20 + 2 + 0x34 ||
                    vinfo_val_sz != 0x34 || 
                    memcmp(vptr+6, "V\0S\0_\0V\0E\0R\0S\0I\0O\0N\0_\0I\0N\0F\0O\0\0\0", 0x20) ||
                    (unsigned int)cli_readint32(vptr + 0x28) != 0xfeef04bd) {
                     /* - there should be enough room for the header(6), the key "VS_VERSION_INFO"(20), the padding(2) and the value(34)
                      * - the value should be sizeof(fixedfileinfo)
                      * - the key should match
                      * - there should be some proper magic for fixedfileinfo */
                     break; /* there's no point in looking further */
                 }
d2ba6f98
 
017f3490
                 /* move to the end of fixedfileinfo where the child elements are located */
                 vptr += 6 + 0x20 + 2 + 0x34;
                 vinfo_sz -= 6 + 0x20 + 2 + 0x34;
85310158
 
017f3490
                 while(vinfo_sz > 6) { /* look for stringfileinfo - NOT RESUMABLE (expecting at most one stringfileinfo) */
                     uint32_t sfi_sz = cli_readint32(vptr) & 0xffff;
d2ba6f98
 
017f3490
                     if(sfi_sz > vinfo_sz)
                         break; /* the content is larger than the container */
d2ba6f98
 
017f3490
                     if(!got_varfileinfo && sfi_sz > 6 + 0x18 && !memcmp(vptr+6, "V\0a\0r\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0", 0x18)) {
                         /* skip varfileinfo as it sometimes appear before stringtableinfo */
                         vptr += sfi_sz;
                         vinfo_sz -= sfi_sz;
                         got_varfileinfo = 1;
                         continue;
                     }
00f5854d
 
017f3490
                     if(sfi_sz <= 6 + 0x1e || memcmp(vptr+6, "S\0t\0r\0i\0n\0g\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0", 0x1e)) {
                         /* - there should be enough room for the header(6) and the key "StringFileInfo"(1e)
                          * - the key should match */
                         break; /* this is an implicit hard fail: parent is not resumable */
                     }
d2ba6f98
 
017f3490
                     /* move to the end of stringfileinfo where the child elements are located */
                     vptr += 6 + 0x1e;
                     sfi_sz -= 6 + 0x1e;
d2ba6f98
 
017f3490
                     while(sfi_sz > 6) { /* enum all stringtables - RESUMABLE */
                         uint32_t st_sz = cli_readint32(vptr) & 0xffff;
                         const uint8_t *next_vptr = vptr + st_sz;
                         uint32_t next_sfi_sz = sfi_sz - st_sz;
d2ba6f98
 
017f3490
                         if(st_sz > sfi_sz || st_sz <= 24) {
                             /* - the content is larger than the container
                                - there's no room for a stringtables (headers(6) + key(16) + padding(2)) */
                             break; /* this is an implicit hard fail: parent is not resumable */
                         }
d2ba6f98
 
017f3490
                         /* move to the end of stringtable where the child elements are located */
                         vptr += 24;
                         st_sz -= 24;
 
                         while(st_sz > 6) {  /* enum all strings - RESUMABLE */
                             uint32_t s_sz, s_key_sz, s_val_sz;
 
                             s_sz = (cli_readint32(vptr) & 0xffff) + 3;
                             s_sz &= ~3;
                             if(s_sz > st_sz || s_sz <= 6 + 2 + 8) {
                                 /* - the content is larger than the container
                                  * - there's no room for a minimal string
                                  * - there's no room for the value */
                                 st_sz = 0;
                                 sfi_sz = 0;
                                 break; /* force a hard fail */
                             }
 
                             /* ~wcstrlen(key) */
                             for(s_key_sz = 6; s_key_sz+1 < s_sz; s_key_sz += 2) {
                                 if(vptr[s_key_sz] || vptr[s_key_sz+1])
                                     continue;
 
                                 s_key_sz += 2;
                                 break;
                             }
 
                             s_key_sz += 3;
                             s_key_sz &= ~3;
 
                             if(s_key_sz >= s_sz) {
                                 /* key overflow */
                                 vptr += s_sz;
                                 st_sz -= s_sz;
                                 continue;
                             }
 
                             s_val_sz = s_sz - s_key_sz;
                             s_key_sz -= 6;
 
                             if(s_val_sz <= 2) {
                                 /* skip unset value */
                                 vptr += s_sz;
                                 st_sz -= s_sz;
                                 continue;
                             }
 
                             if(cli_hashset_addkey(&peinfo->vinfo, (uint32_t)(vptr - baseptr + 6))) {
                                 cli_errmsg("cli_peheader: Unable to add rva to vinfo hashset\n");
                                 cli_hashset_destroy(&peinfo->vinfo);
                                 free(section_hdr);
                                 free(peinfo->section);
                                 peinfo->section = NULL;
                                 return -1;
                             }
 
                             if(cli_debug_flag) {
                                 char *k, *v, *s;
 
                                 /* FIXME: skip too long strings */
                                 k = cli_utf16toascii((const char*)vptr + 6, s_key_sz);
                                 if(k) {
                                     v = cli_utf16toascii((const char*)vptr + s_key_sz + 6, s_val_sz);
                                     if(v) {
87fc762e
                                         s = cli_str2hex((const char*)vptr + 6, s_key_sz + s_val_sz);
017f3490
                                         if(s) {
                                             cli_dbgmsg("VersionInfo (%x): '%s'='%s' - VI:%s\n", (uint32_t)(vptr - baseptr + 6), k, v, s);
                                             free(s);
                                         }
                                         free(v);
                                     }
                                     free(k);
                                 }
                             }
                             vptr += s_sz;
                             st_sz -= s_sz;
                         } /* enum all strings - RESUMABLE */
                         vptr = next_vptr;
                         sfi_sz = next_sfi_sz * (sfi_sz != 0);
                     } /* enum all stringtables - RESUMABLE */
                     break;
                 } /* look for stringfileinfo - NOT RESUMABLE */
                 break;
             } /* look for version_info - NOT RESUMABLE */
         } /* enum all version_information res - RESUMABLE */
         break;
85310158
     } /* while(dirs[2].Size) */
d2ba6f98
 
cdbf8c8e
     free(section_hdr);
     return 0;
 }
0393aa56
 
 
 static int sort_sects(const void *first, const void *second) {
     const struct cli_exe_section *a = first, *b = second;
     return (a->raw - b->raw);
 }
 
3c29ca0b
 int cli_checkfp_pe(cli_ctx *ctx, uint8_t *authsha1, stats_section_t *hashes, uint32_t flags) {
0393aa56
     uint16_t e_magic; /* DOS signature ("MZ") */
     uint16_t nsections;
     uint32_t e_lfanew; /* address of new exe header */
     struct pe_image_file_hdr file_hdr;
     union {
8fdd05d2
         struct pe_image_optional_hdr64 opt64;
         struct pe_image_optional_hdr32 opt32;
0393aa56
     } pe_opt;
     const struct pe_image_section_hdr *section_hdr;
     ssize_t at;
     unsigned int i, pe_plus = 0, hlen;
     size_t fsize;
     uint32_t valign, falign, hdr_size;
     struct cli_exe_section *exe_sections;
     struct pe_image_data_dir *dirs;
     fmap_t *map = *ctx->fmap;
da6e06dd
     void *hashctx=NULL;
3c29ca0b
 
     if (flags & CL_CHECKFP_PE_FLAG_STATS)
         if (!(hashes))
             return CL_EFORMAT;
 
     if (flags == CL_CHECKFP_PE_FLAG_NONE)
e8a1a905
         return CL_VIRUS;
0393aa56
 
1e2c5907
     if(!(DCONF & PE_CONF_CATALOG))
8fdd05d2
         return CL_EFORMAT;
1e2c5907
 
0393aa56
     if(fmap_readn(map, &e_magic, 0, sizeof(e_magic)) != sizeof(e_magic))
8fdd05d2
         return CL_EFORMAT;
0393aa56
 
     if(EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE && EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE_OLD)
8fdd05d2
         return CL_EFORMAT;
0393aa56
 
     if(fmap_readn(map, &e_lfanew, 58 + sizeof(e_magic), sizeof(e_lfanew)) != sizeof(e_lfanew))
8fdd05d2
         return CL_EFORMAT;
0393aa56
 
     e_lfanew = EC32(e_lfanew);
     if(!e_lfanew)
8fdd05d2
         return CL_EFORMAT;
0393aa56
 
     if(fmap_readn(map, &file_hdr, e_lfanew, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr))
8fdd05d2
         return CL_EFORMAT;
0393aa56
 
     if(EC32(file_hdr.Magic) != PE_IMAGE_NT_SIGNATURE)
8fdd05d2
         return CL_EFORMAT;
0393aa56
 
     nsections = EC16(file_hdr.NumberOfSections);
     if(nsections < 1 || nsections > 96)
8fdd05d2
         return CL_EFORMAT;
0393aa56
 
     if(EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32))
8fdd05d2
         return CL_EFORMAT;
0393aa56
 
     at = e_lfanew + sizeof(struct pe_image_file_hdr);
     if(fmap_readn(map, &optional_hdr32, at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32))
8fdd05d2
         return CL_EFORMAT;
 
0393aa56
     at += sizeof(struct pe_image_optional_hdr32);
 
     /* This will be a chicken and egg problem until we drop 9x */
     if(EC16(optional_hdr64.Magic)==PE32P_SIGNATURE) {
         if(EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr64))
8fdd05d2
             return CL_EFORMAT;
 
         pe_plus = 1;
0393aa56
     }
 
     if(!pe_plus) { /* PE */
8fdd05d2
         if (EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr32)) {
             /* Seek to the end of the long header */
             at += EC16(file_hdr.SizeOfOptionalHeader)-sizeof(struct pe_image_optional_hdr32);
         }
0393aa56
 
8fdd05d2
         hdr_size = EC32(optional_hdr32.SizeOfHeaders);
         dirs = optional_hdr32.DataDirectory;
0393aa56
     } else { /* PE+ */
8fdd05d2
         size_t readlen = sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32);
0393aa56
         /* read the remaining part of the header */
cd94be7a
         if((size_t)fmap_readn(map, &optional_hdr32 + 1, at, readlen) != readlen)
8fdd05d2
             return CL_EFORMAT;
 
         at += sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32);
         hdr_size = EC32(optional_hdr64.SizeOfHeaders);
         dirs = optional_hdr64.DataDirectory;
0393aa56
     }
 
     fsize = map->len;
 
     valign = (pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment);
     falign = (pe_plus)?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment);
 
     section_hdr = fmap_need_off_once(map, at, sizeof(*section_hdr) * nsections);
     if(!section_hdr)
8fdd05d2
         return CL_EFORMAT;
 
0393aa56
     at += sizeof(*section_hdr) * nsections;
 
     exe_sections = (struct cli_exe_section *) cli_calloc(nsections, sizeof(struct cli_exe_section));
     if(!exe_sections)
8fdd05d2
         return CL_EMEM;
0393aa56
 
     for(i = 0; falign!=0x200 && i<nsections; i++) {
8fdd05d2
         /* file alignment fallback mode - blah */
         if (falign && section_hdr[i].SizeOfRawData && EC32(section_hdr[i].PointerToRawData)%falign && !(EC32(section_hdr[i].PointerToRawData)%0x200))
             falign = 0x200;
0393aa56
     }
 
d4b8e1a6
     hdr_size = PESALIGN(hdr_size, falign); /* Aligned headers virtual size */
0393aa56
 
3c29ca0b
     if (flags & CL_CHECKFP_PE_FLAG_STATS) {
         hashes->nsections = nsections;
         hashes->sections = cli_calloc(nsections, sizeof(struct cli_section_hash));
         if (!(hashes->sections)) {
             free(exe_sections);
             return CL_EMEM;
         }
     }
 
0393aa56
     for(i = 0; i < nsections; i++) {
8fdd05d2
         exe_sections[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign);
         exe_sections[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign);
         exe_sections[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign);
         exe_sections[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign);
0393aa56
 
8fdd05d2
         if (!exe_sections[i].vsz && exe_sections[i].rsz)
             exe_sections[i].vsz=PESALIGN(exe_sections[i].ursz, valign);
0393aa56
 
8fdd05d2
         if (exe_sections[i].rsz && fsize>exe_sections[i].raw && !CLI_ISCONTAINED(0, (uint32_t) fsize, exe_sections[i].raw, exe_sections[i].rsz))
             exe_sections[i].rsz = fsize - exe_sections[i].raw;
0393aa56
 
8fdd05d2
         if (exe_sections[i].rsz && exe_sections[i].raw >= fsize) {
             free(exe_sections);
             return CL_EFORMAT;
         }
0393aa56
 
8fdd05d2
         if (exe_sections[i].urva>>31 || exe_sections[i].uvsz>>31 || (exe_sections[i].rsz && exe_sections[i].uraw>>31) || exe_sections[i].ursz>>31) {
             free(exe_sections);
             return CL_EFORMAT;
         }
0393aa56
     }
 
     cli_qsort(exe_sections, nsections, sizeof(*exe_sections), sort_sects);
da6e06dd
     hashctx = cl_hash_init("sha1");
f077c617
     if (!(hashctx)) {
         if (flags & CL_CHECKFP_PE_FLAG_AUTHENTICODE)
             flags ^= CL_CHECKFP_PE_FLAG_AUTHENTICODE;
     }
0393aa56
 
7db9ec74
     if (flags & CL_CHECKFP_PE_FLAG_AUTHENTICODE) {
         /* Check to see if we have a security section. */
         if(!cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, 2) && dirs[4].Size < 8) {
             if (flags & CL_CHECKFP_PE_FLAG_STATS) {
                 /* If stats is enabled, continue parsing the sample */
                 flags ^= CL_CHECKFP_PE_FLAG_AUTHENTICODE;
             } else {
f077c617
                 if (hashctx)
da6e06dd
                     cl_hash_destroy(hashctx);
7db9ec74
                 return CL_BREAK;
             }
         }
     }
0393aa56
 
3c29ca0b
 #define hash_chunk(where, size, isStatAble, section) \
8fdd05d2
     do { \
         const uint8_t *hptr; \
         if(!(size)) break; \
         if(!(hptr = fmap_need_off_once(map, where, size))){ \
             free(exe_sections); \
f077c617
             if (hashctx) \
da6e06dd
                 cl_hash_destroy(hashctx); \
8fdd05d2
             return CL_EFORMAT; \
         } \
f077c617
         if (flags & CL_CHECKFP_PE_FLAG_AUTHENTICODE && hashctx) \
cd94be7a
             cl_update_hash(hashctx, (void *)hptr, size); \
3c29ca0b
         if (isStatAble && flags & CL_CHECKFP_PE_FLAG_STATS) { \
da6e06dd
             void *md5ctx; \
             md5ctx = cl_hash_init("md5"); \
f077c617
             if (md5ctx) { \
cd94be7a
                 cl_update_hash(md5ctx, (void *)hptr, size); \
da6e06dd
                 cl_finish_hash(md5ctx, hashes->sections[section].md5); \
f077c617
             } \
3c29ca0b
         } \
0393aa56
     } while(0)
 
7db9ec74
     while (flags & CL_CHECKFP_PE_FLAG_AUTHENTICODE) {
         /* MZ to checksum */
         at = 0;
         hlen = e_lfanew + sizeof(struct pe_image_file_hdr) + (pe_plus ? offsetof(struct pe_image_optional_hdr64, CheckSum) : offsetof(struct pe_image_optional_hdr32, CheckSum));
         hash_chunk(0, hlen, 0, 0);
         at = hlen + 4;
 
         /* Checksum to security */
         if(pe_plus)
             hlen = offsetof(struct pe_image_optional_hdr64, DataDirectory[4]) - offsetof(struct pe_image_optional_hdr64, CheckSum) - 4;
         else
             hlen = offsetof(struct pe_image_optional_hdr32, DataDirectory[4]) - offsetof(struct pe_image_optional_hdr32, CheckSum) - 4;
         hash_chunk(at, hlen, 0, 0);
         at += hlen + 8;
0393aa56
 
7db9ec74
         if(at > hdr_size) {
             if (flags & CL_CHECKFP_PE_FLAG_STATS) {
                 flags ^= CL_CHECKFP_PE_FLAG_AUTHENTICODE;
                 break;
             } else {
                 free(exe_sections);
f077c617
                 if (hashctx)
da6e06dd
                     cl_hash_destroy(hashctx);
7db9ec74
                 return CL_EFORMAT;
             }
         }
0393aa56
 
7db9ec74
         /* Security to End of header */
         hlen = hdr_size - at;
         hash_chunk(at, hlen, 0, 0);
0393aa56
 
7db9ec74
         at = hdr_size;
         break;
     }
0393aa56
 
7db9ec74
     /* Hash the sections */
0393aa56
     for(i = 0; i < nsections; i++) {
8fdd05d2
         if(!exe_sections[i].rsz)
             continue;
 
3c29ca0b
         hash_chunk(exe_sections[i].raw, exe_sections[i].rsz, 1, i);
7db9ec74
         if (flags & CL_CHECKFP_PE_FLAG_AUTHENTICODE)
             at += exe_sections[i].rsz;
     }
 
     while (flags & CL_CHECKFP_PE_FLAG_AUTHENTICODE) {
cd94be7a
         if((size_t)at < fsize) {
7db9ec74
             hlen = fsize - at;
             if(dirs[4].Size > hlen) {
                 if (flags & CL_CHECKFP_PE_FLAG_STATS) {
                     flags ^= CL_CHECKFP_PE_FLAG_AUTHENTICODE;
                     break;
                 } else {
                     free(exe_sections);
f077c617
                     if (hashctx)
da6e06dd
                         cl_hash_destroy(hashctx);
7db9ec74
                     return CL_EFORMAT;
                 }
             }
0393aa56
 
7db9ec74
             hlen -= dirs[4].Size;
             hash_chunk(at, hlen, 0, 0);
             at += hlen;
8fdd05d2
         }
 
7db9ec74
         break;
     } while (0);
 
0393aa56
     free(exe_sections);
 
f077c617
     if (flags & CL_CHECKFP_PE_FLAG_AUTHENTICODE && hashctx) {
da6e06dd
         cl_finish_hash(hashctx, authsha1);
43adde3e
 
         if(cli_debug_flag) {
             char shatxt[SHA1_HASH_SIZE*2+1];
             for(i=0; i<SHA1_HASH_SIZE; i++)
                 sprintf(&shatxt[i*2], "%02x", authsha1[i]);
             cli_dbgmsg("Authenticode: %s\n", shatxt);
         }
0393aa56
 
43adde3e
         hlen = dirs[4].Size;
         if(hlen < 8)
             return CL_VIRUS;
8fdd05d2
 
43adde3e
         hlen -= 8;
8fdd05d2
 
43adde3e
         return asn1_check_mscat((struct cl_engine *)(ctx->engine), map, at + 8, hlen, authsha1);
     } else {
f077c617
         if (hashctx)
da6e06dd
             cl_hash_destroy(hashctx);
43adde3e
         return CL_VIRUS;
     }
0393aa56
 }
28c8c64b
 
 int cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type)
 {
     uint16_t e_magic; /* DOS signature ("MZ") */
     uint16_t nsections;
     uint32_t e_lfanew; /* address of new exe header */
     union {
         struct pe_image_optional_hdr64 opt64;
         struct pe_image_optional_hdr32 opt32;
     } pe_opt;
     const struct pe_image_section_hdr *section_hdr;
     ssize_t at;
     unsigned int i, j, pe_plus = 0;
     size_t fsize;
     uint32_t valign, falign, hdr_size;
     struct pe_image_file_hdr file_hdr;
     struct cli_exe_section *exe_sections;
     struct pe_image_data_dir *dirs;
     fmap_t *map = *ctx->fmap;
 
c96e3331
     unsigned char *hash, *hashset[CLI_HASH_AVAIL_TYPES];
     int genhash[CLI_HASH_AVAIL_TYPES];
     int hlen = 0;
 
28c8c64b
     if (class >= CL_GENHASH_PE_CLASS_LAST)
         return CL_EARG;
 
     if(fmap_readn(map, &e_magic, 0, sizeof(e_magic)) != sizeof(e_magic))
         return CL_EFORMAT;
 
     if(EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE && EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE_OLD)
         return CL_EFORMAT;
 
     if(fmap_readn(map, &e_lfanew, 58 + sizeof(e_magic), sizeof(e_lfanew)) != sizeof(e_lfanew))
         return CL_EFORMAT;
 
     e_lfanew = EC32(e_lfanew);
     if(!e_lfanew)
         return CL_EFORMAT;
 
     if(fmap_readn(map, &file_hdr, e_lfanew, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr))
         return CL_EFORMAT;
 
     if(EC32(file_hdr.Magic) != PE_IMAGE_NT_SIGNATURE)
         return CL_EFORMAT;
 
     nsections = EC16(file_hdr.NumberOfSections);
     if(nsections < 1 || nsections > 96)
         return CL_EFORMAT;
 
     if(EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32))
         return CL_EFORMAT;
 
     at = e_lfanew + sizeof(struct pe_image_file_hdr);
     if(fmap_readn(map, &optional_hdr32, at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32))
         return CL_EFORMAT;
 
     at += sizeof(struct pe_image_optional_hdr32);
 
     /* This will be a chicken and egg problem until we drop 9x */
     if(EC16(optional_hdr64.Magic)==PE32P_SIGNATURE) {
         if(EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr64))
             return CL_EFORMAT;
 
         pe_plus = 1;
     }
 
     if(!pe_plus) { /* PE */
         if (EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr32)) {
             /* Seek to the end of the long header */
             at += EC16(file_hdr.SizeOfOptionalHeader)-sizeof(struct pe_image_optional_hdr32);
         }
 
         hdr_size = EC32(optional_hdr32.SizeOfHeaders);
         dirs = optional_hdr32.DataDirectory;
     } else { /* PE+ */
         size_t readlen = sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32);
         /* read the remaining part of the header */
         if((size_t)fmap_readn(map, &optional_hdr32 + 1, at, readlen) != readlen)
             return CL_EFORMAT;
 
         at += sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32);
         hdr_size = EC32(optional_hdr64.SizeOfHeaders);
         dirs = optional_hdr64.DataDirectory;
     }
 
     fsize = map->len;
 
     valign = (pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment);
     falign = (pe_plus)?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment);
 
     section_hdr = fmap_need_off_once(map, at, sizeof(*section_hdr) * nsections);
     if(!section_hdr)
         return CL_EFORMAT;
 
     at += sizeof(*section_hdr) * nsections;
 
     exe_sections = (struct cli_exe_section *) cli_calloc(nsections, sizeof(struct cli_exe_section));
     if(!exe_sections)
         return CL_EMEM;
 
     for(i = 0; falign!=0x200 && i<nsections; i++) {
         /* file alignment fallback mode - blah */
         if (falign && section_hdr[i].SizeOfRawData && EC32(section_hdr[i].PointerToRawData)%falign && !(EC32(section_hdr[i].PointerToRawData)%0x200))
             falign = 0x200;
     }
 
     hdr_size = PESALIGN(hdr_size, falign); /* Aligned headers virtual size */
 
     for(i = 0; i < nsections; i++) {
         exe_sections[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign);
         exe_sections[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign);
         exe_sections[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign);
         exe_sections[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign);
 
         if (!exe_sections[i].vsz && exe_sections[i].rsz)
             exe_sections[i].vsz=PESALIGN(exe_sections[i].ursz, valign);
 
         if (exe_sections[i].rsz && fsize>exe_sections[i].raw && !CLI_ISCONTAINED(0, (uint32_t) fsize, exe_sections[i].raw, exe_sections[i].rsz))
             exe_sections[i].rsz = fsize - exe_sections[i].raw;
 
         if (exe_sections[i].rsz && exe_sections[i].raw >= fsize) {
             free(exe_sections);
             return CL_EFORMAT;
         }
 
         if (exe_sections[i].urva>>31 || exe_sections[i].uvsz>>31 || (exe_sections[i].rsz && exe_sections[i].uraw>>31) || exe_sections[i].ursz>>31) {
             free(exe_sections);
             return CL_EFORMAT;
         }
     }
 
     cli_qsort(exe_sections, nsections, sizeof(*exe_sections), sort_sects);
 
c96e3331
     /* pick hashtypes to generate */
     memset(genhash, 0, sizeof(genhash));
0a23f3d9
     memset(hashset, 0, sizeof(hashset));
c96e3331
     switch(type) {
     case 1:
         genhash[CLI_HASH_MD5] = 1;
         hlen = hashlen[CLI_HASH_MD5];
0a23f3d9
         hash = hashset[CLI_HASH_MD5] = cli_calloc(hlen, sizeof(char));
c96e3331
         break;
     case 2:
         genhash[CLI_HASH_SHA1] = 1;
         hlen = hashlen[CLI_HASH_SHA1];
0a23f3d9
         hash = hashset[CLI_HASH_SHA1] = cli_calloc(hlen, sizeof(char));
c96e3331
         break;
     default:
         genhash[CLI_HASH_SHA256] = 1;
         hlen = hashlen[CLI_HASH_SHA256];
0a23f3d9
         hash = hashset[CLI_HASH_SHA256] = cli_calloc(hlen, sizeof(char));
c96e3331
         break;
     }
28c8c64b
 
c96e3331
     if(!hash) {
         cli_errmsg("cli_genhash_pe: cli_malloc failed!\n");
         free(exe_sections);
         return CL_EMEM;
     }
 
     if (class == CL_GENHASH_PE_CLASS_SECTION) {
0a23f3d9
         char *dstr = NULL;
28c8c64b
 
         for (i = 0; i < nsections; i++) {
             /* Generate hashes */
0a23f3d9
             if (cli_hashsect(*ctx->fmap, &exe_sections[i], hashset, genhash, genhash) == 1) {
                 dstr = cli_str2hex(hash, hlen);
                 cli_dbgmsg("Section{%u}: %u:%s\n", i, exe_sections[i].rsz, dstr ? (char *)dstr : "(NULL)");
                 if (dstr != NULL) {
                     free(dstr);
                     dstr = NULL;
                 }
             } else {
                 cli_dbgmsg("Section{%u}: failed to generate hash for section\n", i);
             }
28c8c64b
         }
     } else if (class == CL_GENHASH_PE_CLASS_IMPTBL) {
0a23f3d9
         char *dstr = NULL;
c96e3331
         uint32_t impsz = 0;
0a23f3d9
         int ret;
c96e3331
 
         /* Generate hash */
0a23f3d9
         ret = hash_imptbl(ctx, hashset, &impsz, genhash, &dirs[1], exe_sections, nsections, hdr_size, pe_plus);
         if (ret == CL_SUCCESS) {
             dstr = cli_str2hex(hash, hlen);
             cli_dbgmsg("Imphash: %s:%u\n", dstr ? (char *)dstr : "(NULL)", impsz);
             if (dstr != NULL) {
                 free(dstr);
                 dstr = NULL;
             }
         } else {
             cli_dbgmsg("Imphash: failed to generate hash for import table (%d)\n", ret);
         }
28c8c64b
     } else {
         cli_dbgmsg("cli_genhash_pe: unknown pe genhash class: %u\n", class);
     }
 
c96e3331
     if (hash)
         free(hash);
28c8c64b
     free(exe_sections);
     return CL_SUCCESS;
 }