1 /*
2  *  Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3  *  Copyright (C) 2007-2013 Sourcefire, Inc.
4  *
5  *  Authors: Alberto Wu, Tomasz Kojm, Andrew Williams
6  *
7  *  Acknowledgements: The header structures were based upon a PE format
8  *                    analysis by B. Luevelsmeyer.
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License version 2 as
12  *  published by the Free Software Foundation.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22  *  MA 02110-1301, USA.
23  */
24 /*
25   Portions of Code (i.e. pe_ordinal) Copyright (c) 2014. The YARA Authors. All Rights Reserved.
26 
27   Licensed under the Apache License, Version 2.0 (the "License");
28   you may not use this file except in compliance with the License.
29   You may obtain a copy of the License at
30 
31   http://www.apache.org/licenses/LICENSE-2.0
32 
33   Unless required by applicable law or agreed to in writing, software
34   distributed under the License is distributed on an "AS IS" BASIS,
35   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
36   See the License for the specific language governing permissions and
37   limitations under the License.
38 */
39 
40 #if HAVE_CONFIG_H
41 #include "clamav-config.h"
42 #endif
43 
44 /*
45 #define _XOPEN_SOURCE 500
46 */
47 
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <stdint.h>
51 
52 #if HAVE_STRING_H
53 #include <string.h>
54 #endif
55 
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <fcntl.h>
59 #ifdef HAVE_UNISTD_H
60 #include <unistd.h>
61 #endif
62 #include <time.h>
63 #include <stdarg.h>
64 
65 #include "clamav.h"
66 #include "others.h"
67 #include "pe.h"
68 #include "petite.h"
69 #include "fsg.h"
70 #include "spin.h"
71 #include "upx.h"
72 #include "yc.h"
73 #include "aspack.h"
74 #include "wwunpack.h"
75 #include "unsp.h"
76 #include "scanners.h"
77 #include "str.h"
78 #include "entconv.h"
79 #include "execs.h"
80 #include "mew.h"
81 #include "upack.h"
82 #include "matcher.h"
83 #include "matcher-hash.h"
84 #include "disasm.h"
85 #include "special.h"
86 #include "ishield.h"
87 #include "asn1.h"
88 
89 #include "json_api.h"
90 
91 #define DCONF ctx->dconf->pe
92 
93 #define PE_IMAGE_DOS_SIGNATURE 0x5a4d     /* MZ */
94 #define PE_IMAGE_DOS_SIGNATURE_OLD 0x4d5a /* ZM */
95 #define PE_IMAGE_NT_SIGNATURE 0x00004550
96 #define PE32_SIGNATURE 0x010b
97 #define PE32P_SIGNATURE 0x020b
98 #define OPT_HDR_SIZE_DIFF (sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32))
99 
100 #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"
101 #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"
102 #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"
103 #define UPX_LZMA1_FIRST "\x56\x83\xc3\x04\x53\x50\xc7\x03"
104 #define UPX_LZMA1_SECOND "\x90\x90\x90\x55\x57\x56\x53\x83"
105 #define UPX_LZMA0 "\x56\x83\xc3\x04\x53\x50\xc7\x03\x03\x00\x00\x00\x90\x90\x90\x55\x57\x56\x53\x83"
106 #define UPX_LZMA2 "\x56\x83\xc3\x04\x53\x50\xc7\x03\x03\x00\x02\x00\x90\x90\x90\x90\x90\x55\x57\x56"
107 
108 #define PE_MAXNAMESIZE 256
109 #define PE_MAXIMPORTS 1024
110 // TODO On Vista and above, up to 65535 sections are allowed.  Make sure
111 // that using this lower limit from XP is acceptable in all cases
112 #define PE_MAXSECTIONS 96
113 
114 #define EC64(x) ((uint64_t)cli_readint64(&(x))) /* Convert little endian to host */
115 #define EC32(x) ((uint32_t)cli_readint32(&(x)))
116 #define EC16(x) ((uint16_t)cli_readint16(&(x)))
117 /* lower and upper boundary alignment (size vs offset) */
118 #define PEALIGN(o, a) (((a)) ? (((o) / (a)) * (a)) : (o))
119 #define PESALIGN(o, a) (((a)) ? (((o) / (a) + ((o) % (a) != 0)) * (a)) : (o))
120 
121 // TODO Replace all of these with static inline functions
122 #define CLI_UNPSIZELIMITS(NAME, CHK)                           \
123     if (cli_checklimits(NAME, ctx, (CHK), 0, 0) != CL_CLEAN) { \
124         cli_exe_info_destroy(peinfo);                          \
125         return CL_CLEAN;                                       \
126     }
127 
128 #define CLI_UNPTEMP(NAME, FREEME)                                                                 \
129     if (!(tempfile = cli_gentemp(ctx->sub_tmpdir))) {                                             \
130         cli_exe_info_destroy(peinfo);                                                             \
131         cli_multifree FREEME;                                                                     \
132         return CL_EMEM;                                                                           \
133     }                                                                                             \
134     if ((ndesc = open(tempfile, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR)) < 0) { \
135         cli_dbgmsg(NAME ": Can't create file %s\n", tempfile);                                    \
136         free(tempfile);                                                                           \
137         cli_exe_info_destroy(peinfo);                                                             \
138         cli_multifree FREEME;                                                                     \
139         return CL_ECREAT;                                                                         \
140     }
141 
142 #define CLI_TMPUNLK()               \
143     if (!ctx->engine->keeptmp) {    \
144         if (cli_unlink(tempfile)) { \
145             free(tempfile);         \
146             return CL_EUNLINK;      \
147         }                           \
148     }
149 
150 #ifdef HAVE__INTERNAL__SHA_COLLECT
151 #define SHA_OFF                \
152     do {                       \
153         ctx->sha_collect = -1; \
154     } while (0)
155 #define SHA_RESET                       \
156     do {                                \
157         ctx->sha_collect = sha_collect; \
158     } while (0)
159 #else
160 #define SHA_OFF \
161     do {        \
162     } while (0)
163 #define SHA_RESET \
164     do {          \
165     } while (0)
166 #endif
167 
168 #define FSGCASE(NAME, FREESEC)                            \
169     case 0: /* Unpacked and NOT rebuilt */                \
170         cli_dbgmsg(NAME ": Successfully decompressed\n"); \
171         close(ndesc);                                     \
172         if (cli_unlink(tempfile)) {                       \
173             cli_exe_info_destroy(peinfo);                 \
174             free(tempfile);                               \
175             FREESEC;                                      \
176             return CL_EUNLINK;                            \
177         }                                                 \
178         free(tempfile);                                   \
179         FREESEC;                                          \
180         found       = 0;                                  \
181         upx_success = 1;                                  \
182         break; /* FSG ONLY! - scan raw data after upx block */
183 
184 #define SPINCASE()                                         \
185     case 2:                                                \
186         free(spinned);                                     \
187         close(ndesc);                                      \
188         if (cli_unlink(tempfile)) {                        \
189             cli_exe_info_destroy(peinfo);                  \
190             free(tempfile);                                \
191             return CL_EUNLINK;                             \
192         }                                                  \
193         cli_dbgmsg("cli_scanpe: PESpin: Size exceeded\n"); \
194         free(tempfile);                                    \
195         break;
196 
197 #define CLI_UNPRESULTS_(NAME, FSGSTUFF, EXPR, GOOD, FREEME)                                   \
198     switch (EXPR) {                                                                           \
199         case GOOD: /* Unpacked and rebuilt */                                                 \
200             if (ctx->engine->keeptmp)                                                         \
201                 cli_dbgmsg(NAME ": Unpacked and rebuilt executable saved in %s\n", tempfile); \
202             else                                                                              \
203                 cli_dbgmsg(NAME ": Unpacked and rebuilt executable\n");                       \
204             cli_multifree FREEME;                                                             \
205             cli_exe_info_destroy(peinfo);                                                     \
206             lseek(ndesc, 0, SEEK_SET);                                                        \
207             cli_dbgmsg("***** Scanning rebuilt PE file *****\n");                             \
208             SHA_OFF;                                                                          \
209             if (cli_magic_scan_desc(ndesc, tempfile, ctx, NULL) == CL_VIRUS) {                \
210                 close(ndesc);                                                                 \
211                 SHA_RESET;                                                                    \
212                 CLI_TMPUNLK();                                                                \
213                 free(tempfile);                                                               \
214                 return CL_VIRUS;                                                              \
215             }                                                                                 \
216             SHA_RESET;                                                                        \
217             close(ndesc);                                                                     \
218             CLI_TMPUNLK();                                                                    \
219             free(tempfile);                                                                   \
220             return CL_CLEAN;                                                                  \
221                                                                                               \
222             FSGSTUFF;                                                                         \
223                                                                                               \
224         default:                                                                              \
225             cli_dbgmsg(NAME ": Unpacking failed\n");                                          \
226             close(ndesc);                                                                     \
227             if (cli_unlink(tempfile)) {                                                       \
228                 cli_exe_info_destroy(peinfo);                                                 \
229                 free(tempfile);                                                               \
230                 cli_multifree FREEME;                                                         \
231                 return CL_EUNLINK;                                                            \
232             }                                                                                 \
233             cli_multifree FREEME;                                                             \
234             free(tempfile);                                                                   \
235     }
236 
237 #define CLI_UNPRESULTS(NAME, EXPR, GOOD, FREEME) CLI_UNPRESULTS_(NAME, (void)0, EXPR, GOOD, FREEME)
238 // TODO The second argument to FSGCASE below should match what gets freed as
239 // indicated by FREEME, otherwise a memory leak can occur (as currently used,
240 // it looks like dest can get leaked by these macros).
241 #define CLI_UNPRESULTSFSG1(NAME, EXPR, GOOD, FREEME) CLI_UNPRESULTS_(NAME, FSGCASE(NAME, free(sections)), EXPR, GOOD, FREEME)
242 #define CLI_UNPRESULTSFSG2(NAME, EXPR, GOOD, FREEME) CLI_UNPRESULTS_(NAME, FSGCASE(NAME, (void)0), EXPR, GOOD, FREEME)
243 
244 #define DETECT_BROKEN_PE (SCAN_HEURISTIC_BROKEN && !ctx->corrupted_input)
245 
246 extern const unsigned int hashlen[];
247 
248 struct offset_list {
249     uint32_t offset;
250     struct offset_list *next;
251 };
252 
253 struct pe_image_import_descriptor {
254     union {
255         uint32_t Characteristics;
256         uint32_t OriginalFirstThunk;
257     } u;
258     uint32_t TimeDateStamp;
259     uint32_t ForwarderChain;
260     uint32_t Name;
261     uint32_t FirstThunk;
262 };
263 
264 #define PE_IMAGEDIR_ORDINAL_FLAG32 0x80000000
265 #define PE_IMAGEDIR_ORDINAL_FLAG64 0x8000000000000000L
266 
267 struct pe_image_thunk32 {
268     union {
269         uint32_t ForwarderString;
270         uint32_t Function;
271         uint32_t Ordinal;
272         uint32_t AddressOfData;
273     } u;
274 };
275 
276 struct pe_image_thunk64 {
277     union {
278         uint64_t ForwarderString;
279         uint64_t Function;
280         uint64_t Ordinal;
281         uint64_t AddressOfData;
282     } u;
283 };
284 
285 struct pe_image_import_by_name {
286     uint16_t Hint;
287     uint8_t Name[1];
288 };
289 
cli_multifree(void * f,...)290 static void cli_multifree(void *f, ...)
291 {
292     void *ff;
293     va_list ap;
294     free(f);
295     va_start(ap, f);
296     while ((ff = va_arg(ap, void *))) free(ff);
297     va_end(ap);
298 }
299 
300 struct vinfo_list {
301     uint32_t rvas[16];
302     unsigned int count;
303 };
304 
versioninfo_cb(void * opaque,uint32_t type,uint32_t name,uint32_t lang,uint32_t rva)305 static int versioninfo_cb(void *opaque, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva)
306 {
307     struct vinfo_list *vlist = (struct vinfo_list *)opaque;
308 
309     cli_dbgmsg("versioninfo_cb: type: %x, name: %x, lang: %x, rva: %x\n", type, name, lang, rva);
310     vlist->rvas[vlist->count] = rva;
311     if (++vlist->count == sizeof(vlist->rvas) / sizeof(vlist->rvas[0]))
312         return 1;
313     return 0;
314 }
315 
316 /* Given an RVA (relative to the ImageBase), return the file offset of the
317  * corresponding data */
cli_rawaddr(uint32_t rva,const struct cli_exe_section * shp,uint16_t nos,unsigned int * err,size_t fsize,uint32_t hdr_size)318 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)
319 {
320     int i, found = 0;
321     uint32_t ret;
322 
323     if (rva < hdr_size) { /* Out of section EP - mapped to imagebase+rva */
324         if (rva >= fsize) {
325             *err = 1;
326             return 0;
327         }
328 
329         *err = 0;
330         return rva;
331     }
332 
333     for (i = nos - 1; i >= 0; i--) {
334         if (shp[i].rsz && shp[i].rva <= rva && shp[i].rsz > (rva - shp[i].rva)) {
335             found = 1;
336             break;
337         }
338     }
339 
340     if (!found) {
341         *err = 1;
342         return 0;
343     }
344 
345     ret  = (rva - shp[i].rva) + shp[i].raw;
346     *err = 0;
347     return ret;
348 }
349 
350 /*
351    void findres(uint32_t by_type, uint32_t by_name, fmap_t *map, struct cli_exe_info *peinfo, int (*cb)(void *, uint32_t, uint32_t, uint32_t, uint32_t), void *opaque)
352    callback based res lookup
353 
354    by_type: lookup type
355    by_name: lookup name or (unsigned)-1 to look for any name
356    res_rva: base resource rva (i.e. dirs[2].VirtualAddress)
357    map, peinfo: same as in scanpe
358    cb: the callback function executed on each successful match
359    opaque: an opaque pointer passed to the callback
360 
361    the callback proto is
362    int pe_res_cballback (void *opaque, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva);
363    the callback shall return 0 to continue the lookup or 1 to abort
364 */
findres(uint32_t by_type,uint32_t by_name,fmap_t * map,struct cli_exe_info * peinfo,int (* cb)(void *,uint32_t,uint32_t,uint32_t,uint32_t),void * opaque)365 void findres(uint32_t by_type, uint32_t by_name, fmap_t *map, struct cli_exe_info *peinfo, int (*cb)(void *, uint32_t, uint32_t, uint32_t, uint32_t), void *opaque)
366 {
367     unsigned int err = 0;
368     uint32_t type, type_offs, name, name_offs, lang, lang_offs;
369     const uint8_t *resdir, *type_entry, *name_entry, *lang_entry;
370     uint16_t type_cnt, name_cnt, lang_cnt;
371     uint32_t res_rva;
372 
373     if (NULL == peinfo || peinfo->ndatadirs < 3) {
374         return;
375     }
376 
377     if (0 != peinfo->offset) {
378         cli_dbgmsg("findres: Assumption Violated: Looking for version info when peinfo->offset != 0\n");
379     }
380 
381     res_rva = EC32(peinfo->dirs[2].VirtualAddress);
382 
383     if (!(resdir = fmap_need_off_once(map, cli_rawaddr(res_rva, peinfo->sections, peinfo->nsections, &err, map->len, peinfo->hdr_size), 16)) || err)
384         return;
385 
386     type_cnt   = (uint16_t)cli_readint16(resdir + 12);
387     type_entry = resdir + 16;
388     if (!(by_type >> 31)) {
389         type_entry += type_cnt * 8;
390         type_cnt = (uint16_t)cli_readint16(resdir + 14);
391     }
392 
393     while (type_cnt--) {
394         if (!fmap_need_ptr_once(map, type_entry, 8))
395             return;
396         type      = cli_readint32(type_entry);
397         type_offs = cli_readint32(type_entry + 4);
398         if (type == by_type && (type_offs >> 31)) {
399             type_offs &= 0x7fffffff;
400             if (!(resdir = fmap_need_off_once(map, cli_rawaddr(res_rva + type_offs, peinfo->sections, peinfo->nsections, &err, map->len, peinfo->hdr_size), 16)) || err)
401                 return;
402 
403             name_cnt   = (uint16_t)cli_readint16(resdir + 12);
404             name_entry = resdir + 16;
405             if (by_name == 0xffffffff)
406                 name_cnt += (uint16_t)cli_readint16(resdir + 14);
407             else if (!(by_name >> 31)) {
408                 name_entry += name_cnt * 8;
409                 name_cnt = (uint16_t)cli_readint16(resdir + 14);
410             }
411             while (name_cnt--) {
412                 if (!fmap_need_ptr_once(map, name_entry, 8))
413                     return;
414                 name      = cli_readint32(name_entry);
415                 name_offs = cli_readint32(name_entry + 4);
416                 if ((by_name == 0xffffffff || name == by_name) && (name_offs >> 31)) {
417                     name_offs &= 0x7fffffff;
418                     if (!(resdir = fmap_need_off_once(map, cli_rawaddr(res_rva + name_offs, peinfo->sections, peinfo->nsections, &err, map->len, peinfo->hdr_size), 16)) || err)
419                         return;
420 
421                     lang_cnt   = (uint16_t)cli_readint16(resdir + 12) + (uint16_t)cli_readint16(resdir + 14);
422                     lang_entry = resdir + 16;
423                     while (lang_cnt--) {
424                         if (!fmap_need_ptr_once(map, lang_entry, 8))
425                             return;
426                         lang      = cli_readint32(lang_entry);
427                         lang_offs = cli_readint32(lang_entry + 4);
428                         if (!(lang_offs >> 31)) {
429                             if (cb(opaque, type, name, lang, res_rva + lang_offs))
430                                 return;
431                         }
432                         lang_entry += 8;
433                     }
434                 }
435                 name_entry += 8;
436             }
437             return; /* FIXME: unless we want to find ALL types */
438         }
439         type_entry += 8;
440     }
441 }
442 
cli_parseres_special(uint32_t base,uint32_t rva,fmap_t * map,struct cli_exe_info * peinfo,size_t fsize,unsigned int level,uint32_t type,unsigned int * maxres,struct swizz_stats * stats)443 static void cli_parseres_special(uint32_t base, uint32_t rva, fmap_t *map, struct cli_exe_info *peinfo, size_t fsize, unsigned int level, uint32_t type, unsigned int *maxres, struct swizz_stats *stats)
444 {
445     unsigned int err = 0, i;
446     const uint8_t *resdir;
447     const uint8_t *entry, *oentry;
448     uint16_t named, unnamed;
449     uint32_t rawaddr = cli_rawaddr(rva, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size);
450     uint32_t entries;
451 
452     if (level > 2 || !*maxres) return;
453     *maxres -= 1;
454     if (err || !(resdir = fmap_need_off_once(map, rawaddr, 16)))
455         return;
456     named   = (uint16_t)cli_readint16(resdir + 12);
457     unnamed = (uint16_t)cli_readint16(resdir + 14);
458 
459     entries = /*named+*/ unnamed;
460     if (!entries)
461         return;
462     rawaddr += named * 8; /* skip named */
463     /* this is just used in a heuristic detection, so don't give error on failure */
464     if (!(entry = fmap_need_off(map, rawaddr + 16, entries * 8))) {
465         cli_dbgmsg("cli_parseres_special: failed to read resource directory at:%lu\n", (unsigned long)rawaddr + 16);
466         return;
467     }
468     oentry = entry;
469     /*for (i=0; i<named; i++) {
470         uint32_t id, offs;
471         id = cli_readint32(entry);
472         offs = cli_readint32(entry+4);
473         if(offs>>31)
474             cli_parseres( base, base + (offs&0x7fffffff), srcfd, peinfo, fsize, level+1, type, maxres, stats);
475         entry+=8;
476     }*/
477     for (i = 0; i < unnamed; i++, entry += 8) {
478         uint32_t id, offs;
479         if (stats->errors >= SWIZZ_MAXERRORS) {
480             cli_dbgmsg("cli_parseres_special: resources broken, ignoring\n");
481             return;
482         }
483         id = cli_readint32(entry) & 0x7fffffff;
484         if (level == 0) {
485             type = 0;
486             switch (id) {
487                 case 4:  /* menu */
488                 case 5:  /* dialog */
489                 case 6:  /* string */
490                 case 11: /* msgtable */
491                     type = id;
492                     break;
493                 case 16:
494                     type = id;
495                     /* 14: version */
496                     stats->has_version = 1;
497                     break;
498                 case 24: /* manifest */
499                     stats->has_manifest = 1;
500                     break;
501                     /* otherwise keep it 0, we don't want it */
502             }
503         }
504         if (!type) {
505             /* if we are not interested in this type, skip */
506             continue;
507         }
508         offs = cli_readint32(entry + 4);
509         if (offs >> 31)
510             cli_parseres_special(base, base + (offs & 0x7fffffff), map, peinfo, fsize, level + 1, type, maxres, stats);
511         else {
512             offs    = cli_readint32(entry + 4);
513             rawaddr = cli_rawaddr(base + offs, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size);
514             if (!err && (resdir = fmap_need_off_once(map, rawaddr, 16))) {
515                 uint32_t isz = cli_readint32(resdir + 4);
516                 const uint8_t *str;
517                 rawaddr = cli_rawaddr(cli_readint32(resdir), peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size);
518                 if (err || !isz || isz >= fsize || rawaddr + isz >= fsize) {
519                     cli_dbgmsg("cli_parseres_special: invalid resource table entry: %lu + %lu\n",
520                                (unsigned long)rawaddr,
521                                (unsigned long)isz);
522                     stats->errors++;
523                     continue;
524                 }
525                 if ((id & 0xff) != 0x09) /* english res only */
526                     continue;
527                 if ((str = fmap_need_off_once(map, rawaddr, isz)))
528                     cli_detect_swizz_str(str, isz, stats, type);
529             }
530         }
531     }
532     fmap_unneed_ptr(map, oentry, entries * 8);
533 }
534 
cli_hashsect(fmap_t * map,struct cli_exe_section * s,unsigned char ** digest,int * foundhash,int * foundwild)535 static unsigned int cli_hashsect(fmap_t *map, struct cli_exe_section *s, unsigned char **digest, int *foundhash, int *foundwild)
536 {
537     const void *hashme;
538 
539     if (s->rsz > CLI_MAX_ALLOCATION) {
540         cli_dbgmsg("cli_hashsect: skipping hash calculation for too big section\n");
541         return 0;
542     }
543 
544     if (!s->rsz) return 0;
545     if (!(hashme = fmap_need_off_once(map, s->raw, s->rsz))) {
546         cli_dbgmsg("cli_hashsect: unable to read section data\n");
547         return 0;
548     }
549 
550     if (foundhash[CLI_HASH_MD5] || foundwild[CLI_HASH_MD5])
551         cl_hash_data("md5", hashme, s->rsz, digest[CLI_HASH_MD5], NULL);
552     if (foundhash[CLI_HASH_SHA1] || foundwild[CLI_HASH_SHA1])
553         cl_sha1(hashme, s->rsz, digest[CLI_HASH_SHA1], NULL);
554     if (foundhash[CLI_HASH_SHA256] || foundwild[CLI_HASH_SHA256])
555         cl_sha256(hashme, s->rsz, digest[CLI_HASH_SHA256], NULL);
556 
557     return 1;
558 }
559 
560 /* check hash section sigs */
scan_pe_mdb(cli_ctx * ctx,struct cli_exe_section * exe_section)561 static int scan_pe_mdb(cli_ctx *ctx, struct cli_exe_section *exe_section)
562 {
563     struct cli_matcher *mdb_sect = ctx->engine->hm_mdb;
564     unsigned char *hashset[CLI_HASH_AVAIL_TYPES];
565     const char *virname = NULL;
566     int foundsize[CLI_HASH_AVAIL_TYPES];
567     int foundwild[CLI_HASH_AVAIL_TYPES];
568     enum CLI_HASH_TYPE type;
569     int ret            = CL_CLEAN;
570     unsigned char *md5 = NULL;
571 
572     /* pick hashtypes to generate */
573     for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
574         foundsize[type] = cli_hm_have_size(mdb_sect, type, exe_section->rsz);
575         foundwild[type] = cli_hm_have_wild(mdb_sect, type);
576         if (foundsize[type] || foundwild[type]) {
577             hashset[type] = cli_malloc(hashlen[type]);
578             if (!hashset[type]) {
579                 cli_errmsg("scan_pe_mdb: cli_malloc failed!\n");
580                 for (; type > 0;)
581                     free(hashset[--type]);
582                 return CL_EMEM;
583             }
584         } else {
585             hashset[type] = NULL;
586         }
587     }
588 
589     /* Generate hashes */
590     cli_hashsect(ctx->fmap, exe_section, hashset, foundsize, foundwild);
591 
592     /* Print hash */
593     if (cli_debug_flag) {
594         md5 = hashset[CLI_HASH_MD5];
595         if (md5) {
596             cli_dbgmsg("MDB hashset: %u:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
597                        exe_section->rsz, md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], md5[7],
598                        md5[8], md5[9], md5[10], md5[11], md5[12], md5[13], md5[14], md5[15]);
599         } else if (cli_always_gen_section_hash) {
600             const void *hashme = fmap_need_off_once(ctx->fmap, exe_section->raw, exe_section->rsz);
601             if (!(hashme)) {
602                 cli_errmsg("scan_pe_mdb: unable to read section data\n");
603                 ret = CL_EREAD;
604                 goto end;
605             }
606 
607             md5 = cli_malloc(16);
608             if (!(md5)) {
609                 cli_errmsg("scan_pe_mdb: cli_malloc failed!\n");
610                 ret = CL_EMEM;
611                 goto end;
612             }
613 
614             cl_hash_data("md5", hashme, exe_section->rsz, md5, NULL);
615 
616             cli_dbgmsg("MDB: %u:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
617                        exe_section->rsz, md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], md5[7],
618                        md5[8], md5[9], md5[10], md5[11], md5[12], md5[13], md5[14], md5[15]);
619 
620             free(md5);
621 
622         } else {
623             cli_dbgmsg("MDB: %u:notgenerated\n", exe_section->rsz);
624         }
625     }
626 
627     /* Do scans */
628     for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
629         if (foundsize[type] && cli_hm_scan(hashset[type], exe_section->rsz, &virname, mdb_sect, type) == CL_VIRUS) {
630             ret = cli_append_virus(ctx, virname);
631             if (ret != CL_CLEAN) {
632                 if (ret != CL_VIRUS)
633                     break;
634                 else if (!SCAN_ALLMATCHES)
635                     break;
636             }
637         }
638         if (foundwild[type] && cli_hm_scan_wild(hashset[type], &virname, mdb_sect, type) == CL_VIRUS) {
639             ret = cli_append_virus(ctx, virname);
640             if (ret != CL_CLEAN) {
641                 if (ret != CL_VIRUS)
642                     break;
643                 else if (!SCAN_ALLMATCHES)
644                     break;
645             }
646         }
647     }
648 
649 end:
650     for (type = CLI_HASH_AVAIL_TYPES; type > 0;)
651         free(hashset[--type]);
652     return ret;
653 }
654 
655 /* imptbl scanning */
pe_ordinal(const char * dll,uint16_t ord)656 static char *pe_ordinal(const char *dll, uint16_t ord)
657 {
658     char name[64];
659     name[0] = '\0';
660 
661     if (strncasecmp(dll, "WS2_32.dll", 10) == 0 ||
662         strncasecmp(dll, "wsock32.dll", 11) == 0) {
663         switch (ord) {
664             case 1:
665                 sprintf(name, "accept");
666                 break;
667             case 2:
668                 sprintf(name, "bind");
669                 break;
670             case 3:
671                 sprintf(name, "closesocket");
672                 break;
673             case 4:
674                 sprintf(name, "connect");
675                 break;
676             case 5:
677                 sprintf(name, "getpeername");
678                 break;
679             case 6:
680                 sprintf(name, "getsockname");
681                 break;
682             case 7:
683                 sprintf(name, "getsockopt");
684                 break;
685             case 8:
686                 sprintf(name, "htonl");
687                 break;
688             case 9:
689                 sprintf(name, "htons");
690                 break;
691             case 10:
692                 sprintf(name, "ioctlsocket");
693                 break;
694             case 11:
695                 sprintf(name, "inet_addr");
696                 break;
697             case 12:
698                 sprintf(name, "inet_ntoa");
699                 break;
700             case 13:
701                 sprintf(name, "listen");
702                 break;
703             case 14:
704                 sprintf(name, "ntohl");
705                 break;
706             case 15:
707                 sprintf(name, "ntohs");
708                 break;
709             case 16:
710                 sprintf(name, "recv");
711                 break;
712             case 17:
713                 sprintf(name, "recvfrom");
714                 break;
715             case 18:
716                 sprintf(name, "select");
717                 break;
718             case 19:
719                 sprintf(name, "send");
720                 break;
721             case 20:
722                 sprintf(name, "sendto");
723                 break;
724             case 21:
725                 sprintf(name, "setsockopt");
726                 break;
727             case 22:
728                 sprintf(name, "shutdown");
729                 break;
730             case 23:
731                 sprintf(name, "socket");
732                 break;
733             case 24:
734                 sprintf(name, "GetAddrInfoW");
735                 break;
736             case 25:
737                 sprintf(name, "GetNameInfoW");
738                 break;
739             case 26:
740                 sprintf(name, "WSApSetPostRoutine");
741                 break;
742             case 27:
743                 sprintf(name, "FreeAddrInfoW");
744                 break;
745             case 28:
746                 sprintf(name, "WPUCompleteOverlappedRequest");
747                 break;
748             case 29:
749                 sprintf(name, "WSAAccept");
750                 break;
751             case 30:
752                 sprintf(name, "WSAAddressToStringA");
753                 break;
754             case 31:
755                 sprintf(name, "WSAAddressToStringW");
756                 break;
757             case 32:
758                 sprintf(name, "WSACloseEvent");
759                 break;
760             case 33:
761                 sprintf(name, "WSAConnect");
762                 break;
763             case 34:
764                 sprintf(name, "WSACreateEvent");
765                 break;
766             case 35:
767                 sprintf(name, "WSADuplicateSocketA");
768                 break;
769             case 36:
770                 sprintf(name, "WSADuplicateSocketW");
771                 break;
772             case 37:
773                 sprintf(name, "WSAEnumNameSpaceProvidersA");
774                 break;
775             case 38:
776                 sprintf(name, "WSAEnumNameSpaceProvidersW");
777                 break;
778             case 39:
779                 sprintf(name, "WSAEnumNetworkEvents");
780                 break;
781             case 40:
782                 sprintf(name, "WSAEnumProtocolsA");
783                 break;
784             case 41:
785                 sprintf(name, "WSAEnumProtocolsW");
786                 break;
787             case 42:
788                 sprintf(name, "WSAEventSelect");
789                 break;
790             case 43:
791                 sprintf(name, "WSAGetOverlappedResult");
792                 break;
793             case 44:
794                 sprintf(name, "WSAGetQOSByName");
795                 break;
796             case 45:
797                 sprintf(name, "WSAGetServiceClassInfoA");
798                 break;
799             case 46:
800                 sprintf(name, "WSAGetServiceClassInfoW");
801                 break;
802             case 47:
803                 sprintf(name, "WSAGetServiceClassNameByClassIdA");
804                 break;
805             case 48:
806                 sprintf(name, "WSAGetServiceClassNameByClassIdW");
807                 break;
808             case 49:
809                 sprintf(name, "WSAHtonl");
810                 break;
811             case 50:
812                 sprintf(name, "WSAHtons");
813                 break;
814             case 51:
815                 sprintf(name, "gethostbyaddr");
816                 break;
817             case 52:
818                 sprintf(name, "gethostbyname");
819                 break;
820             case 53:
821                 sprintf(name, "getprotobyname");
822                 break;
823             case 54:
824                 sprintf(name, "getprotobynumber");
825                 break;
826             case 55:
827                 sprintf(name, "getservbyname");
828                 break;
829             case 56:
830                 sprintf(name, "getservbyport");
831                 break;
832             case 57:
833                 sprintf(name, "gethostname");
834                 break;
835             case 58:
836                 sprintf(name, "WSAInstallServiceClassA");
837                 break;
838             case 59:
839                 sprintf(name, "WSAInstallServiceClassW");
840                 break;
841             case 60:
842                 sprintf(name, "WSAIoctl");
843                 break;
844             case 61:
845                 sprintf(name, "WSAJoinLeaf");
846                 break;
847             case 62:
848                 sprintf(name, "WSALookupServiceBeginA");
849                 break;
850             case 63:
851                 sprintf(name, "WSALookupServiceBeginW");
852                 break;
853             case 64:
854                 sprintf(name, "WSALookupServiceEnd");
855                 break;
856             case 65:
857                 sprintf(name, "WSALookupServiceNextA");
858                 break;
859             case 66:
860                 sprintf(name, "WSALookupServiceNextW");
861                 break;
862             case 67:
863                 sprintf(name, "WSANSPIoctl");
864                 break;
865             case 68:
866                 sprintf(name, "WSANtohl");
867                 break;
868             case 69:
869                 sprintf(name, "WSANtohs");
870                 break;
871             case 70:
872                 sprintf(name, "WSAProviderConfigChange");
873                 break;
874             case 71:
875                 sprintf(name, "WSARecv");
876                 break;
877             case 72:
878                 sprintf(name, "WSARecvDisconnect");
879                 break;
880             case 73:
881                 sprintf(name, "WSARecvFrom");
882                 break;
883             case 74:
884                 sprintf(name, "WSARemoveServiceClass");
885                 break;
886             case 75:
887                 sprintf(name, "WSAResetEvent");
888                 break;
889             case 76:
890                 sprintf(name, "WSASend");
891                 break;
892             case 77:
893                 sprintf(name, "WSASendDisconnect");
894                 break;
895             case 78:
896                 sprintf(name, "WSASendTo");
897                 break;
898             case 79:
899                 sprintf(name, "WSASetEvent");
900                 break;
901             case 80:
902                 sprintf(name, "WSASetServiceA");
903                 break;
904             case 81:
905                 sprintf(name, "WSASetServiceW");
906                 break;
907             case 82:
908                 sprintf(name, "WSASocketA");
909                 break;
910             case 83:
911                 sprintf(name, "WSASocketW");
912                 break;
913             case 84:
914                 sprintf(name, "WSAStringToAddressA");
915                 break;
916             case 85:
917                 sprintf(name, "WSAStringToAddressW");
918                 break;
919             case 86:
920                 sprintf(name, "WSAWaitForMultipleEvents");
921                 break;
922             case 87:
923                 sprintf(name, "WSCDeinstallProvider");
924                 break;
925             case 88:
926                 sprintf(name, "WSCEnableNSProvider");
927                 break;
928             case 89:
929                 sprintf(name, "WSCEnumProtocols");
930                 break;
931             case 90:
932                 sprintf(name, "WSCGetProviderPath");
933                 break;
934             case 91:
935                 sprintf(name, "WSCInstallNameSpace");
936                 break;
937             case 92:
938                 sprintf(name, "WSCInstallProvider");
939                 break;
940             case 93:
941                 sprintf(name, "WSCUnInstallNameSpace");
942                 break;
943             case 94:
944                 sprintf(name, "WSCUpdateProvider");
945                 break;
946             case 95:
947                 sprintf(name, "WSCWriteNameSpaceOrder");
948                 break;
949             case 96:
950                 sprintf(name, "WSCWriteProviderOrder");
951                 break;
952             case 97:
953                 sprintf(name, "freeaddrinfo");
954                 break;
955             case 98:
956                 sprintf(name, "getaddrinfo");
957                 break;
958             case 99:
959                 sprintf(name, "getnameinfo");
960                 break;
961             case 101:
962                 sprintf(name, "WSAAsyncSelect");
963                 break;
964             case 102:
965                 sprintf(name, "WSAAsyncGetHostByAddr");
966                 break;
967             case 103:
968                 sprintf(name, "WSAAsyncGetHostByName");
969                 break;
970             case 104:
971                 sprintf(name, "WSAAsyncGetProtoByNumber");
972                 break;
973             case 105:
974                 sprintf(name, "WSAAsyncGetProtoByName");
975                 break;
976             case 106:
977                 sprintf(name, "WSAAsyncGetServByPort");
978                 break;
979             case 107:
980                 sprintf(name, "WSAAsyncGetServByName");
981                 break;
982             case 108:
983                 sprintf(name, "WSACancelAsyncRequest");
984                 break;
985             case 109:
986                 sprintf(name, "WSASetBlockingHook");
987                 break;
988             case 110:
989                 sprintf(name, "WSAUnhookBlockingHook");
990                 break;
991             case 111:
992                 sprintf(name, "WSAGetLastError");
993                 break;
994             case 112:
995                 sprintf(name, "WSASetLastError");
996                 break;
997             case 113:
998                 sprintf(name, "WSACancelBlockingCall");
999                 break;
1000             case 114:
1001                 sprintf(name, "WSAIsBlocking");
1002                 break;
1003             case 115:
1004                 sprintf(name, "WSAStartup");
1005                 break;
1006             case 116:
1007                 sprintf(name, "WSACleanup");
1008                 break;
1009             case 151:
1010                 sprintf(name, "__WSAFDIsSet");
1011                 break;
1012             case 500:
1013                 sprintf(name, "WEP");
1014                 break;
1015             default:
1016                 break;
1017         }
1018     } else if (strncasecmp(dll, "oleaut32.dll", 12) == 0) {
1019         switch (ord) {
1020             case 2:
1021                 sprintf(name, "SysAllocString");
1022                 break;
1023             case 3:
1024                 sprintf(name, "SysReAllocString");
1025                 break;
1026             case 4:
1027                 sprintf(name, "SysAllocStringLen");
1028                 break;
1029             case 5:
1030                 sprintf(name, "SysReAllocStringLen");
1031                 break;
1032             case 6:
1033                 sprintf(name, "SysFreeString");
1034                 break;
1035             case 7:
1036                 sprintf(name, "SysStringLen");
1037                 break;
1038             case 8:
1039                 sprintf(name, "VariantInit");
1040                 break;
1041             case 9:
1042                 sprintf(name, "VariantClear");
1043                 break;
1044             case 10:
1045                 sprintf(name, "VariantCopy");
1046                 break;
1047             case 11:
1048                 sprintf(name, "VariantCopyInd");
1049                 break;
1050             case 12:
1051                 sprintf(name, "VariantChangeType");
1052                 break;
1053             case 13:
1054                 sprintf(name, "VariantTimeToDosDateTime");
1055                 break;
1056             case 14:
1057                 sprintf(name, "DosDateTimeToVariantTime");
1058                 break;
1059             case 15:
1060                 sprintf(name, "SafeArrayCreate");
1061                 break;
1062             case 16:
1063                 sprintf(name, "SafeArrayDestroy");
1064                 break;
1065             case 17:
1066                 sprintf(name, "SafeArrayGetDim");
1067                 break;
1068             case 18:
1069                 sprintf(name, "SafeArrayGetElemsize");
1070                 break;
1071             case 19:
1072                 sprintf(name, "SafeArrayGetUBound");
1073                 break;
1074             case 20:
1075                 sprintf(name, "SafeArrayGetLBound");
1076                 break;
1077             case 21:
1078                 sprintf(name, "SafeArrayLock");
1079                 break;
1080             case 22:
1081                 sprintf(name, "SafeArrayUnlock");
1082                 break;
1083             case 23:
1084                 sprintf(name, "SafeArrayAccessData");
1085                 break;
1086             case 24:
1087                 sprintf(name, "SafeArrayUnaccessData");
1088                 break;
1089             case 25:
1090                 sprintf(name, "SafeArrayGetElement");
1091                 break;
1092             case 26:
1093                 sprintf(name, "SafeArrayPutElement");
1094                 break;
1095             case 27:
1096                 sprintf(name, "SafeArrayCopy");
1097                 break;
1098             case 28:
1099                 sprintf(name, "DispGetParam");
1100                 break;
1101             case 29:
1102                 sprintf(name, "DispGetIDsOfNames");
1103                 break;
1104             case 30:
1105                 sprintf(name, "DispInvoke");
1106                 break;
1107             case 31:
1108                 sprintf(name, "CreateDispTypeInfo");
1109                 break;
1110             case 32:
1111                 sprintf(name, "CreateStdDispatch");
1112                 break;
1113             case 33:
1114                 sprintf(name, "RegisterActiveObject");
1115                 break;
1116             case 34:
1117                 sprintf(name, "RevokeActiveObject");
1118                 break;
1119             case 35:
1120                 sprintf(name, "GetActiveObject");
1121                 break;
1122             case 36:
1123                 sprintf(name, "SafeArrayAllocDescriptor");
1124                 break;
1125             case 37:
1126                 sprintf(name, "SafeArrayAllocData");
1127                 break;
1128             case 38:
1129                 sprintf(name, "SafeArrayDestroyDescriptor");
1130                 break;
1131             case 39:
1132                 sprintf(name, "SafeArrayDestroyData");
1133                 break;
1134             case 40:
1135                 sprintf(name, "SafeArrayRedim");
1136                 break;
1137             case 41:
1138                 sprintf(name, "SafeArrayAllocDescriptorEx");
1139                 break;
1140             case 42:
1141                 sprintf(name, "SafeArrayCreateEx");
1142                 break;
1143             case 43:
1144                 sprintf(name, "SafeArrayCreateVectorEx");
1145                 break;
1146             case 44:
1147                 sprintf(name, "SafeArraySetRecordInfo");
1148                 break;
1149             case 45:
1150                 sprintf(name, "SafeArrayGetRecordInfo");
1151                 break;
1152             case 46:
1153                 sprintf(name, "VarParseNumFromStr");
1154                 break;
1155             case 47:
1156                 sprintf(name, "VarNumFromParseNum");
1157                 break;
1158             case 48:
1159                 sprintf(name, "VarI2FromUI1");
1160                 break;
1161             case 49:
1162                 sprintf(name, "VarI2FromI4");
1163                 break;
1164             case 50:
1165                 sprintf(name, "VarI2FromR4");
1166                 break;
1167             case 51:
1168                 sprintf(name, "VarI2FromR8");
1169                 break;
1170             case 52:
1171                 sprintf(name, "VarI2FromCy");
1172                 break;
1173             case 53:
1174                 sprintf(name, "VarI2FromDate");
1175                 break;
1176             case 54:
1177                 sprintf(name, "VarI2FromStr");
1178                 break;
1179             case 55:
1180                 sprintf(name, "VarI2FromDisp");
1181                 break;
1182             case 56:
1183                 sprintf(name, "VarI2FromBool");
1184                 break;
1185             case 57:
1186                 sprintf(name, "SafeArraySetIID");
1187                 break;
1188             case 58:
1189                 sprintf(name, "VarI4FromUI1");
1190                 break;
1191             case 59:
1192                 sprintf(name, "VarI4FromI2");
1193                 break;
1194             case 60:
1195                 sprintf(name, "VarI4FromR4");
1196                 break;
1197             case 61:
1198                 sprintf(name, "VarI4FromR8");
1199                 break;
1200             case 62:
1201                 sprintf(name, "VarI4FromCy");
1202                 break;
1203             case 63:
1204                 sprintf(name, "VarI4FromDate");
1205                 break;
1206             case 64:
1207                 sprintf(name, "VarI4FromStr");
1208                 break;
1209             case 65:
1210                 sprintf(name, "VarI4FromDisp");
1211                 break;
1212             case 66:
1213                 sprintf(name, "VarI4FromBool");
1214                 break;
1215             case 67:
1216                 sprintf(name, "SafeArrayGetIID");
1217                 break;
1218             case 68:
1219                 sprintf(name, "VarR4FromUI1");
1220                 break;
1221             case 69:
1222                 sprintf(name, "VarR4FromI2");
1223                 break;
1224             case 70:
1225                 sprintf(name, "VarR4FromI4");
1226                 break;
1227             case 71:
1228                 sprintf(name, "VarR4FromR8");
1229                 break;
1230             case 72:
1231                 sprintf(name, "VarR4FromCy");
1232                 break;
1233             case 73:
1234                 sprintf(name, "VarR4FromDate");
1235                 break;
1236             case 74:
1237                 sprintf(name, "VarR4FromStr");
1238                 break;
1239             case 75:
1240                 sprintf(name, "VarR4FromDisp");
1241                 break;
1242             case 76:
1243                 sprintf(name, "VarR4FromBool");
1244                 break;
1245             case 77:
1246                 sprintf(name, "SafeArrayGetVartype");
1247                 break;
1248             case 78:
1249                 sprintf(name, "VarR8FromUI1");
1250                 break;
1251             case 79:
1252                 sprintf(name, "VarR8FromI2");
1253                 break;
1254             case 80:
1255                 sprintf(name, "VarR8FromI4");
1256                 break;
1257             case 81:
1258                 sprintf(name, "VarR8FromR4");
1259                 break;
1260             case 82:
1261                 sprintf(name, "VarR8FromCy");
1262                 break;
1263             case 83:
1264                 sprintf(name, "VarR8FromDate");
1265                 break;
1266             case 84:
1267                 sprintf(name, "VarR8FromStr");
1268                 break;
1269             case 85:
1270                 sprintf(name, "VarR8FromDisp");
1271                 break;
1272             case 86:
1273                 sprintf(name, "VarR8FromBool");
1274                 break;
1275             case 87:
1276                 sprintf(name, "VarFormat");
1277                 break;
1278             case 88:
1279                 sprintf(name, "VarDateFromUI1");
1280                 break;
1281             case 89:
1282                 sprintf(name, "VarDateFromI2");
1283                 break;
1284             case 90:
1285                 sprintf(name, "VarDateFromI4");
1286                 break;
1287             case 91:
1288                 sprintf(name, "VarDateFromR4");
1289                 break;
1290             case 92:
1291                 sprintf(name, "VarDateFromR8");
1292                 break;
1293             case 93:
1294                 sprintf(name, "VarDateFromCy");
1295                 break;
1296             case 94:
1297                 sprintf(name, "VarDateFromStr");
1298                 break;
1299             case 95:
1300                 sprintf(name, "VarDateFromDisp");
1301                 break;
1302             case 96:
1303                 sprintf(name, "VarDateFromBool");
1304                 break;
1305             case 97:
1306                 sprintf(name, "VarFormatDateTime");
1307                 break;
1308             case 98:
1309                 sprintf(name, "VarCyFromUI1");
1310                 break;
1311             case 99:
1312                 sprintf(name, "VarCyFromI2");
1313                 break;
1314             case 100:
1315                 sprintf(name, "VarCyFromI4");
1316                 break;
1317             case 101:
1318                 sprintf(name, "VarCyFromR4");
1319                 break;
1320             case 102:
1321                 sprintf(name, "VarCyFromR8");
1322                 break;
1323             case 103:
1324                 sprintf(name, "VarCyFromDate");
1325                 break;
1326             case 104:
1327                 sprintf(name, "VarCyFromStr");
1328                 break;
1329             case 105:
1330                 sprintf(name, "VarCyFromDisp");
1331                 break;
1332             case 106:
1333                 sprintf(name, "VarCyFromBool");
1334                 break;
1335             case 107:
1336                 sprintf(name, "VarFormatNumber");
1337                 break;
1338             case 108:
1339                 sprintf(name, "VarBstrFromUI1");
1340                 break;
1341             case 109:
1342                 sprintf(name, "VarBstrFromI2");
1343                 break;
1344             case 110:
1345                 sprintf(name, "VarBstrFromI4");
1346                 break;
1347             case 111:
1348                 sprintf(name, "VarBstrFromR4");
1349                 break;
1350             case 112:
1351                 sprintf(name, "VarBstrFromR8");
1352                 break;
1353             case 113:
1354                 sprintf(name, "VarBstrFromCy");
1355                 break;
1356             case 114:
1357                 sprintf(name, "VarBstrFromDate");
1358                 break;
1359             case 115:
1360                 sprintf(name, "VarBstrFromDisp");
1361                 break;
1362             case 116:
1363                 sprintf(name, "VarBstrFromBool");
1364                 break;
1365             case 117:
1366                 sprintf(name, "VarFormatPercent");
1367                 break;
1368             case 118:
1369                 sprintf(name, "VarBoolFromUI1");
1370                 break;
1371             case 119:
1372                 sprintf(name, "VarBoolFromI2");
1373                 break;
1374             case 120:
1375                 sprintf(name, "VarBoolFromI4");
1376                 break;
1377             case 121:
1378                 sprintf(name, "VarBoolFromR4");
1379                 break;
1380             case 122:
1381                 sprintf(name, "VarBoolFromR8");
1382                 break;
1383             case 123:
1384                 sprintf(name, "VarBoolFromDate");
1385                 break;
1386             case 124:
1387                 sprintf(name, "VarBoolFromCy");
1388                 break;
1389             case 125:
1390                 sprintf(name, "VarBoolFromStr");
1391                 break;
1392             case 126:
1393                 sprintf(name, "VarBoolFromDisp");
1394                 break;
1395             case 127:
1396                 sprintf(name, "VarFormatCurrency");
1397                 break;
1398             case 128:
1399                 sprintf(name, "VarWeekdayName");
1400                 break;
1401             case 129:
1402                 sprintf(name, "VarMonthName");
1403                 break;
1404             case 130:
1405                 sprintf(name, "VarUI1FromI2");
1406                 break;
1407             case 131:
1408                 sprintf(name, "VarUI1FromI4");
1409                 break;
1410             case 132:
1411                 sprintf(name, "VarUI1FromR4");
1412                 break;
1413             case 133:
1414                 sprintf(name, "VarUI1FromR8");
1415                 break;
1416             case 134:
1417                 sprintf(name, "VarUI1FromCy");
1418                 break;
1419             case 135:
1420                 sprintf(name, "VarUI1FromDate");
1421                 break;
1422             case 136:
1423                 sprintf(name, "VarUI1FromStr");
1424                 break;
1425             case 137:
1426                 sprintf(name, "VarUI1FromDisp");
1427                 break;
1428             case 138:
1429                 sprintf(name, "VarUI1FromBool");
1430                 break;
1431             case 139:
1432                 sprintf(name, "VarFormatFromTokens");
1433                 break;
1434             case 140:
1435                 sprintf(name, "VarTokenizeFormatString");
1436                 break;
1437             case 141:
1438                 sprintf(name, "VarAdd");
1439                 break;
1440             case 142:
1441                 sprintf(name, "VarAnd");
1442                 break;
1443             case 143:
1444                 sprintf(name, "VarDiv");
1445                 break;
1446             case 144:
1447                 sprintf(name, "DllCanUnloadNow");
1448                 break;
1449             case 145:
1450                 sprintf(name, "DllGetClassObject");
1451                 break;
1452             case 146:
1453                 sprintf(name, "DispCallFunc");
1454                 break;
1455             case 147:
1456                 sprintf(name, "VariantChangeTypeEx");
1457                 break;
1458             case 148:
1459                 sprintf(name, "SafeArrayPtrOfIndex");
1460                 break;
1461             case 149:
1462                 sprintf(name, "SysStringByteLen");
1463                 break;
1464             case 150:
1465                 sprintf(name, "SysAllocStringByteLen");
1466                 break;
1467             case 151:
1468                 sprintf(name, "DllRegisterServer");
1469                 break;
1470             case 152:
1471                 sprintf(name, "VarEqv");
1472                 break;
1473             case 153:
1474                 sprintf(name, "VarIdiv");
1475                 break;
1476             case 154:
1477                 sprintf(name, "VarImp");
1478                 break;
1479             case 155:
1480                 sprintf(name, "VarMod");
1481                 break;
1482             case 156:
1483                 sprintf(name, "VarMul");
1484                 break;
1485             case 157:
1486                 sprintf(name, "VarOr");
1487                 break;
1488             case 158:
1489                 sprintf(name, "VarPow");
1490                 break;
1491             case 159:
1492                 sprintf(name, "VarSub");
1493                 break;
1494             case 160:
1495                 sprintf(name, "CreateTypeLib");
1496                 break;
1497             case 161:
1498                 sprintf(name, "LoadTypeLib");
1499                 break;
1500             case 162:
1501                 sprintf(name, "LoadRegTypeLib");
1502                 break;
1503             case 163:
1504                 sprintf(name, "RegisterTypeLib");
1505                 break;
1506             case 164:
1507                 sprintf(name, "QueryPathOfRegTypeLib");
1508                 break;
1509             case 165:
1510                 sprintf(name, "LHashValOfNameSys");
1511                 break;
1512             case 166:
1513                 sprintf(name, "LHashValOfNameSysA");
1514                 break;
1515             case 167:
1516                 sprintf(name, "VarXor");
1517                 break;
1518             case 168:
1519                 sprintf(name, "VarAbs");
1520                 break;
1521             case 169:
1522                 sprintf(name, "VarFix");
1523                 break;
1524             case 170:
1525                 sprintf(name, "OaBuildVersion");
1526                 break;
1527             case 171:
1528                 sprintf(name, "ClearCustData");
1529                 break;
1530             case 172:
1531                 sprintf(name, "VarInt");
1532                 break;
1533             case 173:
1534                 sprintf(name, "VarNeg");
1535                 break;
1536             case 174:
1537                 sprintf(name, "VarNot");
1538                 break;
1539             case 175:
1540                 sprintf(name, "VarRound");
1541                 break;
1542             case 176:
1543                 sprintf(name, "VarCmp");
1544                 break;
1545             case 177:
1546                 sprintf(name, "VarDecAdd");
1547                 break;
1548             case 178:
1549                 sprintf(name, "VarDecDiv");
1550                 break;
1551             case 179:
1552                 sprintf(name, "VarDecMul");
1553                 break;
1554             case 180:
1555                 sprintf(name, "CreateTypeLib2");
1556                 break;
1557             case 181:
1558                 sprintf(name, "VarDecSub");
1559                 break;
1560             case 182:
1561                 sprintf(name, "VarDecAbs");
1562                 break;
1563             case 183:
1564                 sprintf(name, "LoadTypeLibEx");
1565                 break;
1566             case 184:
1567                 sprintf(name, "SystemTimeToVariantTime");
1568                 break;
1569             case 185:
1570                 sprintf(name, "VariantTimeToSystemTime");
1571                 break;
1572             case 186:
1573                 sprintf(name, "UnRegisterTypeLib");
1574                 break;
1575             case 187:
1576                 sprintf(name, "VarDecFix");
1577                 break;
1578             case 188:
1579                 sprintf(name, "VarDecInt");
1580                 break;
1581             case 189:
1582                 sprintf(name, "VarDecNeg");
1583                 break;
1584             case 190:
1585                 sprintf(name, "VarDecFromUI1");
1586                 break;
1587             case 191:
1588                 sprintf(name, "VarDecFromI2");
1589                 break;
1590             case 192:
1591                 sprintf(name, "VarDecFromI4");
1592                 break;
1593             case 193:
1594                 sprintf(name, "VarDecFromR4");
1595                 break;
1596             case 194:
1597                 sprintf(name, "VarDecFromR8");
1598                 break;
1599             case 195:
1600                 sprintf(name, "VarDecFromDate");
1601                 break;
1602             case 196:
1603                 sprintf(name, "VarDecFromCy");
1604                 break;
1605             case 197:
1606                 sprintf(name, "VarDecFromStr");
1607                 break;
1608             case 198:
1609                 sprintf(name, "VarDecFromDisp");
1610                 break;
1611             case 199:
1612                 sprintf(name, "VarDecFromBool");
1613                 break;
1614             case 200:
1615                 sprintf(name, "GetErrorInfo");
1616                 break;
1617             case 201:
1618                 sprintf(name, "SetErrorInfo");
1619                 break;
1620             case 202:
1621                 sprintf(name, "CreateErrorInfo");
1622                 break;
1623             case 203:
1624                 sprintf(name, "VarDecRound");
1625                 break;
1626             case 204:
1627                 sprintf(name, "VarDecCmp");
1628                 break;
1629             case 205:
1630                 sprintf(name, "VarI2FromI1");
1631                 break;
1632             case 206:
1633                 sprintf(name, "VarI2FromUI2");
1634                 break;
1635             case 207:
1636                 sprintf(name, "VarI2FromUI4");
1637                 break;
1638             case 208:
1639                 sprintf(name, "VarI2FromDec");
1640                 break;
1641             case 209:
1642                 sprintf(name, "VarI4FromI1");
1643                 break;
1644             case 210:
1645                 sprintf(name, "VarI4FromUI2");
1646                 break;
1647             case 211:
1648                 sprintf(name, "VarI4FromUI4");
1649                 break;
1650             case 212:
1651                 sprintf(name, "VarI4FromDec");
1652                 break;
1653             case 213:
1654                 sprintf(name, "VarR4FromI1");
1655                 break;
1656             case 214:
1657                 sprintf(name, "VarR4FromUI2");
1658                 break;
1659             case 215:
1660                 sprintf(name, "VarR4FromUI4");
1661                 break;
1662             case 216:
1663                 sprintf(name, "VarR4FromDec");
1664                 break;
1665             case 217:
1666                 sprintf(name, "VarR8FromI1");
1667                 break;
1668             case 218:
1669                 sprintf(name, "VarR8FromUI2");
1670                 break;
1671             case 219:
1672                 sprintf(name, "VarR8FromUI4");
1673                 break;
1674             case 220:
1675                 sprintf(name, "VarR8FromDec");
1676                 break;
1677             case 221:
1678                 sprintf(name, "VarDateFromI1");
1679                 break;
1680             case 222:
1681                 sprintf(name, "VarDateFromUI2");
1682                 break;
1683             case 223:
1684                 sprintf(name, "VarDateFromUI4");
1685                 break;
1686             case 224:
1687                 sprintf(name, "VarDateFromDec");
1688                 break;
1689             case 225:
1690                 sprintf(name, "VarCyFromI1");
1691                 break;
1692             case 226:
1693                 sprintf(name, "VarCyFromUI2");
1694                 break;
1695             case 227:
1696                 sprintf(name, "VarCyFromUI4");
1697                 break;
1698             case 228:
1699                 sprintf(name, "VarCyFromDec");
1700                 break;
1701             case 229:
1702                 sprintf(name, "VarBstrFromI1");
1703                 break;
1704             case 230:
1705                 sprintf(name, "VarBstrFromUI2");
1706                 break;
1707             case 231:
1708                 sprintf(name, "VarBstrFromUI4");
1709                 break;
1710             case 232:
1711                 sprintf(name, "VarBstrFromDec");
1712                 break;
1713             case 233:
1714                 sprintf(name, "VarBoolFromI1");
1715                 break;
1716             case 234:
1717                 sprintf(name, "VarBoolFromUI2");
1718                 break;
1719             case 235:
1720                 sprintf(name, "VarBoolFromUI4");
1721                 break;
1722             case 236:
1723                 sprintf(name, "VarBoolFromDec");
1724                 break;
1725             case 237:
1726                 sprintf(name, "VarUI1FromI1");
1727                 break;
1728             case 238:
1729                 sprintf(name, "VarUI1FromUI2");
1730                 break;
1731             case 239:
1732                 sprintf(name, "VarUI1FromUI4");
1733                 break;
1734             case 240:
1735                 sprintf(name, "VarUI1FromDec");
1736                 break;
1737             case 241:
1738                 sprintf(name, "VarDecFromI1");
1739                 break;
1740             case 242:
1741                 sprintf(name, "VarDecFromUI2");
1742                 break;
1743             case 243:
1744                 sprintf(name, "VarDecFromUI4");
1745                 break;
1746             case 244:
1747                 sprintf(name, "VarI1FromUI1");
1748                 break;
1749             case 245:
1750                 sprintf(name, "VarI1FromI2");
1751                 break;
1752             case 246:
1753                 sprintf(name, "VarI1FromI4");
1754                 break;
1755             case 247:
1756                 sprintf(name, "VarI1FromR4");
1757                 break;
1758             case 248:
1759                 sprintf(name, "VarI1FromR8");
1760                 break;
1761             case 249:
1762                 sprintf(name, "VarI1FromDate");
1763                 break;
1764             case 250:
1765                 sprintf(name, "VarI1FromCy");
1766                 break;
1767             case 251:
1768                 sprintf(name, "VarI1FromStr");
1769                 break;
1770             case 252:
1771                 sprintf(name, "VarI1FromDisp");
1772                 break;
1773             case 253:
1774                 sprintf(name, "VarI1FromBool");
1775                 break;
1776             case 254:
1777                 sprintf(name, "VarI1FromUI2");
1778                 break;
1779             case 255:
1780                 sprintf(name, "VarI1FromUI4");
1781                 break;
1782             case 256:
1783                 sprintf(name, "VarI1FromDec");
1784                 break;
1785             case 257:
1786                 sprintf(name, "VarUI2FromUI1");
1787                 break;
1788             case 258:
1789                 sprintf(name, "VarUI2FromI2");
1790                 break;
1791             case 259:
1792                 sprintf(name, "VarUI2FromI4");
1793                 break;
1794             case 260:
1795                 sprintf(name, "VarUI2FromR4");
1796                 break;
1797             case 261:
1798                 sprintf(name, "VarUI2FromR8");
1799                 break;
1800             case 262:
1801                 sprintf(name, "VarUI2FromDate");
1802                 break;
1803             case 263:
1804                 sprintf(name, "VarUI2FromCy");
1805                 break;
1806             case 264:
1807                 sprintf(name, "VarUI2FromStr");
1808                 break;
1809             case 265:
1810                 sprintf(name, "VarUI2FromDisp");
1811                 break;
1812             case 266:
1813                 sprintf(name, "VarUI2FromBool");
1814                 break;
1815             case 267:
1816                 sprintf(name, "VarUI2FromI1");
1817                 break;
1818             case 268:
1819                 sprintf(name, "VarUI2FromUI4");
1820                 break;
1821             case 269:
1822                 sprintf(name, "VarUI2FromDec");
1823                 break;
1824             case 270:
1825                 sprintf(name, "VarUI4FromUI1");
1826                 break;
1827             case 271:
1828                 sprintf(name, "VarUI4FromI2");
1829                 break;
1830             case 272:
1831                 sprintf(name, "VarUI4FromI4");
1832                 break;
1833             case 273:
1834                 sprintf(name, "VarUI4FromR4");
1835                 break;
1836             case 274:
1837                 sprintf(name, "VarUI4FromR8");
1838                 break;
1839             case 275:
1840                 sprintf(name, "VarUI4FromDate");
1841                 break;
1842             case 276:
1843                 sprintf(name, "VarUI4FromCy");
1844                 break;
1845             case 277:
1846                 sprintf(name, "VarUI4FromStr");
1847                 break;
1848             case 278:
1849                 sprintf(name, "VarUI4FromDisp");
1850                 break;
1851             case 279:
1852                 sprintf(name, "VarUI4FromBool");
1853                 break;
1854             case 280:
1855                 sprintf(name, "VarUI4FromI1");
1856                 break;
1857             case 281:
1858                 sprintf(name, "VarUI4FromUI2");
1859                 break;
1860             case 282:
1861                 sprintf(name, "VarUI4FromDec");
1862                 break;
1863             case 283:
1864                 sprintf(name, "BSTR_UserSize");
1865                 break;
1866             case 284:
1867                 sprintf(name, "BSTR_UserMarshal");
1868                 break;
1869             case 285:
1870                 sprintf(name, "BSTR_UserUnmarshal");
1871                 break;
1872             case 286:
1873                 sprintf(name, "BSTR_UserFree");
1874                 break;
1875             case 287:
1876                 sprintf(name, "VARIANT_UserSize");
1877                 break;
1878             case 288:
1879                 sprintf(name, "VARIANT_UserMarshal");
1880                 break;
1881             case 289:
1882                 sprintf(name, "VARIANT_UserUnmarshal");
1883                 break;
1884             case 290:
1885                 sprintf(name, "VARIANT_UserFree");
1886                 break;
1887             case 291:
1888                 sprintf(name, "LPSAFEARRAY_UserSize");
1889                 break;
1890             case 292:
1891                 sprintf(name, "LPSAFEARRAY_UserMarshal");
1892                 break;
1893             case 293:
1894                 sprintf(name, "LPSAFEARRAY_UserUnmarshal");
1895                 break;
1896             case 294:
1897                 sprintf(name, "LPSAFEARRAY_UserFree");
1898                 break;
1899             case 295:
1900                 sprintf(name, "LPSAFEARRAY_Size");
1901                 break;
1902             case 296:
1903                 sprintf(name, "LPSAFEARRAY_Marshal");
1904                 break;
1905             case 297:
1906                 sprintf(name, "LPSAFEARRAY_Unmarshal");
1907                 break;
1908             case 298:
1909                 sprintf(name, "VarDecCmpR8");
1910                 break;
1911             case 299:
1912                 sprintf(name, "VarCyAdd");
1913                 break;
1914             case 300:
1915                 sprintf(name, "DllUnregisterServer");
1916                 break;
1917             case 301:
1918                 sprintf(name, "OACreateTypeLib2");
1919                 break;
1920             case 303:
1921                 sprintf(name, "VarCyMul");
1922                 break;
1923             case 304:
1924                 sprintf(name, "VarCyMulI4");
1925                 break;
1926             case 305:
1927                 sprintf(name, "VarCySub");
1928                 break;
1929             case 306:
1930                 sprintf(name, "VarCyAbs");
1931                 break;
1932             case 307:
1933                 sprintf(name, "VarCyFix");
1934                 break;
1935             case 308:
1936                 sprintf(name, "VarCyInt");
1937                 break;
1938             case 309:
1939                 sprintf(name, "VarCyNeg");
1940                 break;
1941             case 310:
1942                 sprintf(name, "VarCyRound");
1943                 break;
1944             case 311:
1945                 sprintf(name, "VarCyCmp");
1946                 break;
1947             case 312:
1948                 sprintf(name, "VarCyCmpR8");
1949                 break;
1950             case 313:
1951                 sprintf(name, "VarBstrCat");
1952                 break;
1953             case 314:
1954                 sprintf(name, "VarBstrCmp");
1955                 break;
1956             case 315:
1957                 sprintf(name, "VarR8Pow");
1958                 break;
1959             case 316:
1960                 sprintf(name, "VarR4CmpR8");
1961                 break;
1962             case 317:
1963                 sprintf(name, "VarR8Round");
1964                 break;
1965             case 318:
1966                 sprintf(name, "VarCat");
1967                 break;
1968             case 319:
1969                 sprintf(name, "VarDateFromUdateEx");
1970                 break;
1971             case 322:
1972                 sprintf(name, "GetRecordInfoFromGuids");
1973                 break;
1974             case 323:
1975                 sprintf(name, "GetRecordInfoFromTypeInfo");
1976                 break;
1977             case 325:
1978                 sprintf(name, "SetVarConversionLocaleSetting");
1979                 break;
1980             case 326:
1981                 sprintf(name, "GetVarConversionLocaleSetting");
1982                 break;
1983             case 327:
1984                 sprintf(name, "SetOaNoCache");
1985                 break;
1986             case 329:
1987                 sprintf(name, "VarCyMulI8");
1988                 break;
1989             case 330:
1990                 sprintf(name, "VarDateFromUdate");
1991                 break;
1992             case 331:
1993                 sprintf(name, "VarUdateFromDate");
1994                 break;
1995             case 332:
1996                 sprintf(name, "GetAltMonthNames");
1997                 break;
1998             case 333:
1999                 sprintf(name, "VarI8FromUI1");
2000                 break;
2001             case 334:
2002                 sprintf(name, "VarI8FromI2");
2003                 break;
2004             case 335:
2005                 sprintf(name, "VarI8FromR4");
2006                 break;
2007             case 336:
2008                 sprintf(name, "VarI8FromR8");
2009                 break;
2010             case 337:
2011                 sprintf(name, "VarI8FromCy");
2012                 break;
2013             case 338:
2014                 sprintf(name, "VarI8FromDate");
2015                 break;
2016             case 339:
2017                 sprintf(name, "VarI8FromStr");
2018                 break;
2019             case 340:
2020                 sprintf(name, "VarI8FromDisp");
2021                 break;
2022             case 341:
2023                 sprintf(name, "VarI8FromBool");
2024                 break;
2025             case 342:
2026                 sprintf(name, "VarI8FromI1");
2027                 break;
2028             case 343:
2029                 sprintf(name, "VarI8FromUI2");
2030                 break;
2031             case 344:
2032                 sprintf(name, "VarI8FromUI4");
2033                 break;
2034             case 345:
2035                 sprintf(name, "VarI8FromDec");
2036                 break;
2037             case 346:
2038                 sprintf(name, "VarI2FromI8");
2039                 break;
2040             case 347:
2041                 sprintf(name, "VarI2FromUI8");
2042                 break;
2043             case 348:
2044                 sprintf(name, "VarI4FromI8");
2045                 break;
2046             case 349:
2047                 sprintf(name, "VarI4FromUI8");
2048                 break;
2049             case 360:
2050                 sprintf(name, "VarR4FromI8");
2051                 break;
2052             case 361:
2053                 sprintf(name, "VarR4FromUI8");
2054                 break;
2055             case 362:
2056                 sprintf(name, "VarR8FromI8");
2057                 break;
2058             case 363:
2059                 sprintf(name, "VarR8FromUI8");
2060                 break;
2061             case 364:
2062                 sprintf(name, "VarDateFromI8");
2063                 break;
2064             case 365:
2065                 sprintf(name, "VarDateFromUI8");
2066                 break;
2067             case 366:
2068                 sprintf(name, "VarCyFromI8");
2069                 break;
2070             case 367:
2071                 sprintf(name, "VarCyFromUI8");
2072                 break;
2073             case 368:
2074                 sprintf(name, "VarBstrFromI8");
2075                 break;
2076             case 369:
2077                 sprintf(name, "VarBstrFromUI8");
2078                 break;
2079             case 370:
2080                 sprintf(name, "VarBoolFromI8");
2081                 break;
2082             case 371:
2083                 sprintf(name, "VarBoolFromUI8");
2084                 break;
2085             case 372:
2086                 sprintf(name, "VarUI1FromI8");
2087                 break;
2088             case 373:
2089                 sprintf(name, "VarUI1FromUI8");
2090                 break;
2091             case 374:
2092                 sprintf(name, "VarDecFromI8");
2093                 break;
2094             case 375:
2095                 sprintf(name, "VarDecFromUI8");
2096                 break;
2097             case 376:
2098                 sprintf(name, "VarI1FromI8");
2099                 break;
2100             case 377:
2101                 sprintf(name, "VarI1FromUI8");
2102                 break;
2103             case 378:
2104                 sprintf(name, "VarUI2FromI8");
2105                 break;
2106             case 379:
2107                 sprintf(name, "VarUI2FromUI8");
2108                 break;
2109             case 401:
2110                 sprintf(name, "OleLoadPictureEx");
2111                 break;
2112             case 402:
2113                 sprintf(name, "OleLoadPictureFileEx");
2114                 break;
2115             case 411:
2116                 sprintf(name, "SafeArrayCreateVector");
2117                 break;
2118             case 412:
2119                 sprintf(name, "SafeArrayCopyData");
2120                 break;
2121             case 413:
2122                 sprintf(name, "VectorFromBstr");
2123                 break;
2124             case 414:
2125                 sprintf(name, "BstrFromVector");
2126                 break;
2127             case 415:
2128                 sprintf(name, "OleIconToCursor");
2129                 break;
2130             case 416:
2131                 sprintf(name, "OleCreatePropertyFrameIndirect");
2132                 break;
2133             case 417:
2134                 sprintf(name, "OleCreatePropertyFrame");
2135                 break;
2136             case 418:
2137                 sprintf(name, "OleLoadPicture");
2138                 break;
2139             case 419:
2140                 sprintf(name, "OleCreatePictureIndirect");
2141                 break;
2142             case 420:
2143                 sprintf(name, "OleCreateFontIndirect");
2144                 break;
2145             case 421:
2146                 sprintf(name, "OleTranslateColor");
2147                 break;
2148             case 422:
2149                 sprintf(name, "OleLoadPictureFile");
2150                 break;
2151             case 423:
2152                 sprintf(name, "OleSavePictureFile");
2153                 break;
2154             case 424:
2155                 sprintf(name, "OleLoadPicturePath");
2156                 break;
2157             case 425:
2158                 sprintf(name, "VarUI4FromI8");
2159                 break;
2160             case 426:
2161                 sprintf(name, "VarUI4FromUI8");
2162                 break;
2163             case 427:
2164                 sprintf(name, "VarI8FromUI8");
2165                 break;
2166             case 428:
2167                 sprintf(name, "VarUI8FromI8");
2168                 break;
2169             case 429:
2170                 sprintf(name, "VarUI8FromUI1");
2171                 break;
2172             case 430:
2173                 sprintf(name, "VarUI8FromI2");
2174                 break;
2175             case 431:
2176                 sprintf(name, "VarUI8FromR4");
2177                 break;
2178             case 432:
2179                 sprintf(name, "VarUI8FromR8");
2180                 break;
2181             case 433:
2182                 sprintf(name, "VarUI8FromCy");
2183                 break;
2184             case 434:
2185                 sprintf(name, "VarUI8FromDate");
2186                 break;
2187             case 435:
2188                 sprintf(name, "VarUI8FromStr");
2189                 break;
2190             case 436:
2191                 sprintf(name, "VarUI8FromDisp");
2192                 break;
2193             case 437:
2194                 sprintf(name, "VarUI8FromBool");
2195                 break;
2196             case 438:
2197                 sprintf(name, "VarUI8FromI1");
2198                 break;
2199             case 439:
2200                 sprintf(name, "VarUI8FromUI2");
2201                 break;
2202             case 440:
2203                 sprintf(name, "VarUI8FromUI4");
2204                 break;
2205             case 441:
2206                 sprintf(name, "VarUI8FromDec");
2207                 break;
2208             case 442:
2209                 sprintf(name, "RegisterTypeLibForUser");
2210                 break;
2211             case 443:
2212                 sprintf(name, "UnRegisterTypeLibForUser");
2213                 break;
2214             default:
2215                 break;
2216         }
2217     }
2218 
2219     if (name[0] == '\0')
2220         sprintf(name, "ord%u", ord);
2221 
2222     return cli_strdup(name);
2223 }
2224 
validate_impname(const char * name,uint32_t length,int dll)2225 static int validate_impname(const char *name, uint32_t length, int dll)
2226 {
2227     uint32_t i    = 0;
2228     const char *c = name;
2229 
2230     if (!name || length == 0)
2231         return 1;
2232 
2233     while (i < length && *c != '\0') {
2234         if ((*c >= '0' && *c <= '9') ||
2235             (*c >= 'a' && *c <= 'z') ||
2236             (*c >= 'A' && *c <= 'Z') ||
2237             (*c == '_') ||
2238             (dll && *c == '.')) {
2239 
2240             c++;
2241             i++;
2242         } else
2243             return 0;
2244     }
2245 
2246     return 1;
2247 }
2248 
hash_impfns(cli_ctx * ctx,void ** hashctx,uint32_t * impsz,struct pe_image_import_descriptor * image,const char * dllname,struct cli_exe_info * peinfo,int * first)2249 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_info *peinfo, int *first)
2250 {
2251     uint32_t thuoff = 0, offset;
2252     fmap_t *map     = ctx->fmap;
2253     size_t dlllen = 0, fsize = map->len;
2254     unsigned int err = 0;
2255     int num_fns = 0, ret = CL_SUCCESS;
2256     const char *buffer;
2257     enum CLI_HASH_TYPE type;
2258 #if HAVE_JSON
2259     json_object *imptbl = NULL;
2260 #else
2261     void *imptbl = NULL;
2262 #endif
2263 
2264     if (image->u.OriginalFirstThunk)
2265         thuoff = cli_rawaddr(image->u.OriginalFirstThunk, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size);
2266     if (err || thuoff == 0)
2267         thuoff = cli_rawaddr(image->FirstThunk, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size);
2268     if (err) {
2269         cli_dbgmsg("scan_pe: invalid rva for image first thunk\n");
2270         return CL_EFORMAT;
2271     }
2272 
2273 #if HAVE_JSON
2274     if (ctx->wrkproperty) {
2275         imptbl = cli_jsonarray(ctx->wrkproperty, "ImportTable");
2276         if (!imptbl) {
2277             cli_dbgmsg("scan_pe: cannot allocate import table json object\n");
2278             return CL_EMEM;
2279         }
2280     }
2281 #endif
2282 
2283 #define UPDATE_IMPHASH()                                                            \
2284     do {                                                                            \
2285         if (funcname) {                                                             \
2286             size_t i, j;                                                            \
2287             char *fname;                                                            \
2288             size_t funclen;                                                         \
2289                                                                                     \
2290             if (dlllen == 0) {                                                      \
2291                 char *ext = strstr(dllname, ".");                                   \
2292                                                                                     \
2293                 if (ext && (strncasecmp(ext, ".ocx", 4) == 0 ||                     \
2294                             strncasecmp(ext, ".sys", 4) == 0 ||                     \
2295                             strncasecmp(ext, ".dll", 4) == 0))                      \
2296                     dlllen = ext - dllname;                                         \
2297                 else                                                                \
2298                     dlllen = strlen(dllname);                                       \
2299             }                                                                       \
2300                                                                                     \
2301             funclen = strlen(funcname);                                             \
2302             if (validate_impname(funcname, funclen, 1) == 0) {                      \
2303                 cli_dbgmsg("scan_pe: invalid name for imported function\n");        \
2304                 ret = CL_EFORMAT;                                                   \
2305                 break;                                                              \
2306             }                                                                       \
2307                                                                                     \
2308             fname = cli_calloc(funclen + dlllen + 3, sizeof(char));                 \
2309             if (fname == NULL) {                                                    \
2310                 cli_dbgmsg("scan_pe: cannot allocate memory for imphash string\n"); \
2311                 ret = CL_EMEM;                                                      \
2312                 break;                                                              \
2313             }                                                                       \
2314             j = 0;                                                                  \
2315             if (!*first)                                                            \
2316                 fname[j++] = ',';                                                   \
2317             for (i = 0; i < dlllen; i++, j++)                                       \
2318                 fname[j] = tolower(dllname[i]);                                     \
2319             fname[j++] = '.';                                                       \
2320             for (i = 0; i < funclen; i++, j++)                                      \
2321                 fname[j] = tolower(funcname[i]);                                    \
2322                                                                                     \
2323             if (imptbl) {                                                           \
2324                 char *jname = *first ? fname : fname + 1;                           \
2325                 cli_jsonstr(imptbl, NULL, jname);                                   \
2326             }                                                                       \
2327                                                                                     \
2328             for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++)          \
2329                 cl_update_hash(hashctx[type], fname, strlen(fname));                \
2330             *impsz += strlen(fname);                                                \
2331                                                                                     \
2332             *first = 0;                                                             \
2333             free(fname);                                                            \
2334         }                                                                           \
2335     } while (0)
2336 
2337     if (!peinfo->is_pe32plus) {
2338         struct pe_image_thunk32 thunk32;
2339 
2340         while ((num_fns < PE_MAXIMPORTS) && (fmap_readn(map, &thunk32, thuoff, sizeof(struct pe_image_thunk32)) == sizeof(struct pe_image_thunk32)) && (thunk32.u.Ordinal != 0)) {
2341             char *funcname = NULL;
2342             thuoff += sizeof(struct pe_image_thunk32);
2343 
2344             thunk32.u.Ordinal = EC32(thunk32.u.Ordinal);
2345 
2346             if (!(thunk32.u.Ordinal & PE_IMAGEDIR_ORDINAL_FLAG32)) {
2347                 offset = cli_rawaddr(thunk32.u.Function, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size);
2348 
2349                 if (!ret) {
2350                     /* Hint field is a uint16_t and precedes the Name field */
2351                     if ((buffer = fmap_need_off_once(map, offset + sizeof(uint16_t), MIN(PE_MAXNAMESIZE, fsize - offset))) != NULL) {
2352                         funcname = CLI_STRNDUP(buffer, MIN(PE_MAXNAMESIZE, fsize - offset));
2353                         if (funcname == NULL) {
2354                             cli_dbgmsg("scan_pe: cannot duplicate function name\n");
2355                             return CL_EMEM;
2356                         }
2357                     }
2358                 }
2359             } else {
2360                 /* ordinal lookup */
2361                 funcname = pe_ordinal(dllname, thunk32.u.Ordinal & 0xFFFF);
2362                 if (funcname == NULL) {
2363                     cli_dbgmsg("scan_pe: cannot duplicate function name\n");
2364                     return CL_EMEM;
2365                 }
2366             }
2367 
2368             UPDATE_IMPHASH();
2369             free(funcname);
2370             if (ret != CL_SUCCESS)
2371                 return ret;
2372         }
2373     } else {
2374         struct pe_image_thunk64 thunk64;
2375 
2376         while ((num_fns < PE_MAXIMPORTS) && (fmap_readn(map, &thunk64, thuoff, sizeof(struct pe_image_thunk64)) == sizeof(struct pe_image_thunk64)) && (thunk64.u.Ordinal != 0)) {
2377             char *funcname = NULL;
2378             thuoff += sizeof(struct pe_image_thunk64);
2379 
2380             thunk64.u.Ordinal = EC64(thunk64.u.Ordinal);
2381 
2382             if (!(thunk64.u.Ordinal & PE_IMAGEDIR_ORDINAL_FLAG64)) {
2383                 offset = cli_rawaddr(thunk64.u.Function, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size);
2384 
2385                 if (!err) {
2386                     /* Hint field is a uint16_t and precedes the Name field */
2387                     if ((buffer = fmap_need_off_once(map, offset + sizeof(uint16_t), MIN(PE_MAXNAMESIZE, fsize - offset))) != NULL) {
2388                         funcname = CLI_STRNDUP(buffer, MIN(PE_MAXNAMESIZE, fsize - offset));
2389                         if (funcname == NULL) {
2390                             cli_dbgmsg("scan_pe: cannot duplicate function name\n");
2391                             return CL_EMEM;
2392                         }
2393                     }
2394                 }
2395             } else {
2396                 /* ordinal lookup */
2397                 funcname = pe_ordinal(dllname, thunk64.u.Ordinal & 0xFFFF);
2398                 if (funcname == NULL) {
2399                     cli_dbgmsg("scan_pe: cannot duplicate function name\n");
2400                     return CL_EMEM;
2401                 }
2402             }
2403 
2404             UPDATE_IMPHASH();
2405             free(funcname);
2406             if (ret != CL_SUCCESS)
2407                 return ret;
2408         }
2409     }
2410 
2411     return CL_SUCCESS;
2412 }
2413 
hash_imptbl(cli_ctx * ctx,unsigned char ** digest,uint32_t * impsz,int * genhash,struct cli_exe_info * peinfo)2414 static cl_error_t hash_imptbl(cli_ctx *ctx, unsigned char **digest, uint32_t *impsz, int *genhash, struct cli_exe_info *peinfo)
2415 {
2416     struct pe_image_import_descriptor *image;
2417     fmap_t *map = ctx->fmap;
2418     size_t left, fsize = map->len;
2419     uint32_t impoff, offset;
2420     const char *impdes, *buffer;
2421     void *hashctx[CLI_HASH_AVAIL_TYPES];
2422     enum CLI_HASH_TYPE type;
2423     int nimps      = 0;
2424     cl_error_t ret = CL_SUCCESS;
2425     unsigned int err;
2426     int first = 1;
2427 
2428     /* If the PE doesn't have an import table then skip it. This is an
2429      * uncommon case but can happen. */
2430     if (peinfo->dirs[1].VirtualAddress == 0 || peinfo->dirs[1].Size == 0) {
2431         cli_dbgmsg("scan_pe: import table data dir does not exist (skipping .imp scanning)\n");
2432         return CL_SUCCESS;
2433     }
2434 
2435     // TODO Add EC32 wrappers
2436     impoff = cli_rawaddr(peinfo->dirs[1].VirtualAddress, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size);
2437     if (err || impoff + peinfo->dirs[1].Size > fsize) {
2438         cli_dbgmsg("scan_pe: invalid rva for import table data\n");
2439         return CL_SUCCESS;
2440     }
2441 
2442     // TODO Add EC32 wrapper
2443     impdes = fmap_need_off(map, impoff, peinfo->dirs[1].Size);
2444     if (impdes == NULL) {
2445         cli_dbgmsg("scan_pe: failed to acquire fmap buffer\n");
2446         return CL_EREAD;
2447     }
2448     left = peinfo->dirs[1].Size;
2449 
2450     memset(hashctx, 0, sizeof(hashctx));
2451     if (genhash[CLI_HASH_MD5]) {
2452         hashctx[CLI_HASH_MD5] = cl_hash_init("md5");
2453         if (hashctx[CLI_HASH_MD5] == NULL) {
2454             fmap_unneed_off(map, impoff, peinfo->dirs[1].Size);
2455             return CL_EMEM;
2456         }
2457     }
2458     if (genhash[CLI_HASH_SHA1]) {
2459         hashctx[CLI_HASH_SHA1] = cl_hash_init("sha1");
2460         if (hashctx[CLI_HASH_SHA1] == NULL) {
2461             fmap_unneed_off(map, impoff, peinfo->dirs[1].Size);
2462             return CL_EMEM;
2463         }
2464     }
2465     if (genhash[CLI_HASH_SHA256]) {
2466         hashctx[CLI_HASH_SHA256] = cl_hash_init("sha256");
2467         if (hashctx[CLI_HASH_SHA256] == NULL) {
2468             fmap_unneed_off(map, impoff, peinfo->dirs[1].Size);
2469             return CL_EMEM;
2470         }
2471     }
2472 
2473     image = (struct pe_image_import_descriptor *)impdes;
2474     while (left > sizeof(struct pe_image_import_descriptor) && image->Name != 0 && nimps < PE_MAXIMPORTS) {
2475         char *dllname = NULL;
2476 
2477         left -= sizeof(struct pe_image_import_descriptor);
2478         nimps++;
2479 
2480         /* Endian Conversion */
2481         image->u.OriginalFirstThunk = EC32(image->u.OriginalFirstThunk);
2482         image->TimeDateStamp        = EC32(image->TimeDateStamp);
2483         image->ForwarderChain       = EC32(image->ForwarderChain);
2484         image->Name                 = EC32(image->Name);
2485         image->FirstThunk           = EC32(image->FirstThunk);
2486 
2487         /* DLL name acquisition */
2488         offset = cli_rawaddr(image->Name, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size);
2489         if (err || offset > fsize) {
2490             cli_dbgmsg("scan_pe: invalid rva for dll name\n");
2491             /* TODO: ignore or return? */
2492             /*
2493               image++;
2494               continue;
2495              */
2496             ret = CL_EFORMAT;
2497             goto hash_imptbl_end;
2498         }
2499 
2500         buffer = fmap_need_off_once(map, offset, MIN(PE_MAXNAMESIZE, fsize - offset));
2501         if (buffer == NULL) {
2502             cli_dbgmsg("scan_pe: failed to read name for dll\n");
2503             ret = CL_EREAD;
2504             goto hash_imptbl_end;
2505         }
2506 
2507         if (validate_impname(dllname, MIN(PE_MAXNAMESIZE, fsize - offset), 1) == 0) {
2508             cli_dbgmsg("scan_pe: invalid name for imported dll\n");
2509             ret = CL_EFORMAT;
2510             goto hash_imptbl_end;
2511         }
2512 
2513         dllname = CLI_STRNDUP(buffer, MIN(PE_MAXNAMESIZE, fsize - offset));
2514         if (dllname == NULL) {
2515             cli_dbgmsg("scan_pe: cannot duplicate dll name\n");
2516             ret = CL_EMEM;
2517             goto hash_imptbl_end;
2518         }
2519 
2520         /* DLL function handling - inline function */
2521         ret = hash_impfns(ctx, hashctx, impsz, image, dllname, peinfo, &first);
2522         free(dllname);
2523         dllname = NULL;
2524         if (ret != CL_SUCCESS)
2525             goto hash_imptbl_end;
2526 
2527         image++;
2528     }
2529 
2530 hash_imptbl_end:
2531     fmap_unneed_off(map, impoff, peinfo->dirs[1].Size);
2532     for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++)
2533         cl_finish_hash(hashctx[type], digest[type]);
2534     return ret;
2535 }
2536 
scan_pe_imp(cli_ctx * ctx,struct cli_exe_info * peinfo)2537 static int scan_pe_imp(cli_ctx *ctx, struct cli_exe_info *peinfo)
2538 {
2539     struct cli_matcher *imp = ctx->engine->hm_imp;
2540     unsigned char *hashset[CLI_HASH_AVAIL_TYPES];
2541     const char *virname = NULL;
2542     int genhash[CLI_HASH_AVAIL_TYPES];
2543     uint32_t impsz = 0;
2544     enum CLI_HASH_TYPE type;
2545     int ret = CL_CLEAN;
2546 
2547     /* pick hashtypes to generate */
2548     for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
2549         genhash[type] = cli_hm_have_any(imp, type);
2550         if (genhash[type]) {
2551             hashset[type] = cli_malloc(hashlen[type]);
2552             if (!hashset[type]) {
2553                 cli_errmsg("scan_pe: cli_malloc failed!\n");
2554                 for (; type > 0;)
2555                     free(hashset[--type]);
2556                 return CL_EMEM;
2557             }
2558         } else {
2559             hashset[type] = NULL;
2560         }
2561     }
2562 
2563     /* Force md5 hash generation for debug and preclass */
2564 #if HAVE_JSON
2565     if ((cli_debug_flag || ctx->wrkproperty) && !genhash[CLI_HASH_MD5]) {
2566 #else
2567     if (cli_debug_flag && !genhash[CLI_HASH_MD5]) {
2568 #endif
2569         genhash[CLI_HASH_MD5] = 1;
2570         hashset[CLI_HASH_MD5] = cli_calloc(hashlen[CLI_HASH_MD5], sizeof(char));
2571         if (!hashset[CLI_HASH_MD5]) {
2572             cli_errmsg("scan_pe: cli_malloc failed!\n");
2573             for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++)
2574                 free(hashset[type]);
2575             return CL_EMEM;
2576         }
2577     }
2578 
2579     /* Generate hashes */
2580     ret = hash_imptbl(ctx, hashset, &impsz, genhash, peinfo);
2581     if (ret != CL_SUCCESS) {
2582         for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++)
2583             free(hashset[type]);
2584         return ret;
2585     }
2586 
2587     /* Print hash */
2588 #if HAVE_JSON
2589     if (cli_debug_flag || ctx->wrkproperty) {
2590 #else
2591     if (cli_debug_flag) {
2592 #endif
2593         char *dstr = cli_str2hex((char *)hashset[CLI_HASH_MD5], hashlen[CLI_HASH_MD5]);
2594         cli_dbgmsg("IMP: %s:%u\n", dstr ? (char *)dstr : "(NULL)", impsz);
2595 #if HAVE_JSON
2596         if (ctx->wrkproperty)
2597             cli_jsonstr(ctx->wrkproperty, "Imphash", dstr ? dstr : "(NULL)");
2598 #endif
2599         if (dstr)
2600             free(dstr);
2601     }
2602 
2603     /* Do scans */
2604     for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
2605         if (cli_hm_scan(hashset[type], impsz, &virname, imp, type) == CL_VIRUS) {
2606             ret = cli_append_virus(ctx, virname);
2607             if (ret != CL_CLEAN) {
2608                 if (ret != CL_VIRUS)
2609                     break;
2610                 else if (!SCAN_ALLMATCHES)
2611                     break;
2612             }
2613         }
2614         if (cli_hm_scan_wild(hashset[type], &virname, imp, type) == CL_VIRUS) {
2615             cli_append_virus(ctx, virname);
2616             if (ret != CL_CLEAN) {
2617                 if (ret != CL_VIRUS)
2618                     break;
2619                 else if (!SCAN_ALLMATCHES)
2620                     break;
2621             }
2622         }
2623     }
2624 
2625     for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++)
2626         free(hashset[type]);
2627     return ret;
2628 }
2629 
2630 #if HAVE_JSON
2631 static struct json_object *get_pe_property(cli_ctx *ctx)
2632 {
2633     struct json_object *pe;
2634 
2635     if (!(ctx) || !(ctx->wrkproperty))
2636         return NULL;
2637 
2638     if (!json_object_object_get_ex(ctx->wrkproperty, "PE", &pe)) {
2639         pe = json_object_new_object();
2640         if (!(pe))
2641             return NULL;
2642 
2643         json_object_object_add(ctx->wrkproperty, "PE", pe);
2644     }
2645 
2646     return pe;
2647 }
2648 
2649 static void pe_add_heuristic_property(cli_ctx *ctx, const char *key)
2650 {
2651     struct json_object *heuristics;
2652     struct json_object *pe;
2653     struct json_object *str;
2654 
2655     pe = get_pe_property(ctx);
2656     if (!(pe))
2657         return;
2658 
2659     if (!json_object_object_get_ex(pe, "Heuristics", &heuristics)) {
2660         heuristics = json_object_new_array();
2661         if (!(heuristics))
2662             return;
2663 
2664         json_object_object_add(pe, "Heuristics", heuristics);
2665     }
2666 
2667     str = json_object_new_string(key);
2668     if (!(str))
2669         return;
2670 
2671     json_object_array_add(heuristics, str);
2672 }
2673 
2674 static struct json_object *get_section_json(cli_ctx *ctx)
2675 {
2676     struct json_object *pe;
2677     struct json_object *section;
2678 
2679     pe = get_pe_property(ctx);
2680     if (!(pe))
2681         return NULL;
2682 
2683     if (!json_object_object_get_ex(pe, "Sections", &section)) {
2684         section = json_object_new_array();
2685         if (!(section))
2686             return NULL;
2687 
2688         json_object_object_add(pe, "Sections", section);
2689     }
2690 
2691     return section;
2692 }
2693 
2694 static void add_section_info(cli_ctx *ctx, struct cli_exe_section *s)
2695 {
2696     struct json_object *sections, *section, *obj;
2697     char address[16];
2698 
2699     sections = get_section_json(ctx);
2700     if (!(sections))
2701         return;
2702 
2703     section = json_object_new_object();
2704     if (!(section))
2705         return;
2706 
2707     obj = json_object_new_int((int32_t)(s->rsz));
2708     if (!(obj))
2709         return;
2710 
2711     json_object_object_add(section, "RawSize", obj);
2712 
2713     obj = json_object_new_int((int32_t)(s->raw));
2714     if (!(obj))
2715         return;
2716 
2717     json_object_object_add(section, "RawOffset", obj);
2718 
2719     snprintf(address, sizeof(address), "0x%08x", s->rva);
2720 
2721     obj = json_object_new_string(address);
2722     if (!(obj))
2723         return;
2724 
2725     json_object_object_add(section, "VirtualAddress", obj);
2726 
2727     obj = json_object_new_boolean((s->chr & 0x20000000) == 0x20000000);
2728     if ((obj))
2729         json_object_object_add(section, "Executable", obj);
2730 
2731     obj = json_object_new_boolean((s->chr & 0x80000000) == 0x80000000);
2732     if ((obj))
2733         json_object_object_add(section, "Writable", obj);
2734 
2735     obj = json_object_new_boolean(s->urva >> 31 || s->uvsz >> 31 || (s->rsz && s->uraw >> 31) || s->ursz >> 31);
2736     if ((obj))
2737         json_object_object_add(section, "Signed", obj);
2738 
2739     json_object_array_add(sections, section);
2740 }
2741 #endif
2742 
2743 int cli_scanpe(cli_ctx *ctx)
2744 {
2745     uint8_t polipos = 0;
2746     char epbuff[4096], *tempfile;
2747     uint32_t epsize;
2748     size_t bytes;
2749     unsigned int i, j, found, upx_success = 0, err;
2750     unsigned int ssize = 0, dsize = 0, corrupted_cur;
2751     int (*upxfn)(const char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t) = NULL;
2752     const char *src                                                                        = NULL;
2753     char *dest                                                                             = NULL;
2754     int ndesc, ret = CL_CLEAN, upack = 0;
2755     size_t fsize;
2756     struct cli_bc_ctx *bc_ctx;
2757     fmap_t *map;
2758     struct cli_pe_hook_data pedata;
2759 #ifdef HAVE__INTERNAL__SHA_COLLECT
2760     int sha_collect = ctx->sha_collect;
2761 #endif
2762     uint32_t viruses_found = 0;
2763 #if HAVE_JSON
2764     int toval                   = 0;
2765     struct json_object *pe_json = NULL;
2766 #endif
2767 
2768     if (!ctx) {
2769         cli_errmsg("cli_scanpe: ctx == NULL\n");
2770         return CL_ENULLARG;
2771     }
2772 
2773 #if HAVE_JSON
2774     if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) {
2775         return CL_ETIMEOUT;
2776     }
2777 
2778     if (SCAN_COLLECT_METADATA) {
2779         pe_json = get_pe_property(ctx);
2780     }
2781 #endif
2782     map   = ctx->fmap;
2783     fsize = map->len;
2784 
2785     struct cli_exe_info _peinfo;
2786     struct cli_exe_info *peinfo = &_peinfo;
2787 
2788     uint32_t opts = CLI_PEHEADER_OPT_DBG_PRINT_INFO | CLI_PEHEADER_OPT_REMOVE_MISSING_SECTIONS;
2789 
2790 #if HAVE_JSON
2791     if (SCAN_COLLECT_METADATA) {
2792         opts |= CLI_PEHEADER_OPT_COLLECT_JSON;
2793     }
2794 #endif
2795 
2796     if (DETECT_BROKEN_PE) {
2797         opts |= CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS;
2798     }
2799 
2800     cli_exe_info_init(peinfo, 0);
2801 
2802     ret = cli_peheader(map, peinfo, opts, ctx);
2803 
2804     // Warn the user if PE header parsing failed - if it's a binary that runs
2805     // successfully on Windows, we need to relax our PE parsing standards so
2806     // that we make sure the executable gets scanned appropriately
2807 
2808 #define PE_HDR_PARSE_FAIL_CONSEQUENCE "won't attempt .mdb / .imp / PE-specific BC rule matching or exe unpacking\n"
2809 
2810     if (CLI_PEHEADER_RET_BROKEN_PE == ret) {
2811         if (DETECT_BROKEN_PE) {
2812             // TODO Handle allmatch
2813             ret = cli_append_virus(ctx, "Heuristics.Broken.Executable");
2814             cli_exe_info_destroy(peinfo);
2815             return ret;
2816         }
2817         cli_dbgmsg("cli_scanpe: PE header appears broken - " PE_HDR_PARSE_FAIL_CONSEQUENCE);
2818         cli_exe_info_destroy(peinfo);
2819         return CL_CLEAN;
2820 
2821     } else if (CLI_PEHEADER_RET_JSON_TIMEOUT == ret) {
2822         cli_dbgmsg("cli_scanpe: JSON creation timed out - " PE_HDR_PARSE_FAIL_CONSEQUENCE);
2823         cli_exe_info_destroy(peinfo);
2824         return CL_ETIMEOUT;
2825     } else if (CLI_PEHEADER_RET_GENERIC_ERROR == ret) {
2826         cli_dbgmsg("cli_scanpe: An error occurred when parsing the PE header - " PE_HDR_PARSE_FAIL_CONSEQUENCE);
2827         cli_exe_info_destroy(peinfo);
2828         return CL_CLEAN;
2829     }
2830 
2831     if (!peinfo->is_pe32plus) { /* PE */
2832         if (DCONF & PE_CONF_UPACK)
2833             upack = (EC16(peinfo->file_hdr.SizeOfOptionalHeader) == 0x148);
2834     }
2835     for (i = 0; i < peinfo->nsections; i++) {
2836 
2837         if (peinfo->sections[i].rsz) { /* Don't bother with virtual only sections */
2838             // TODO Regarding the commented out check below:
2839             // This used to check that the section name was NULL, but now that
2840             // header parsing is done in cli_peheader (and since we don't yet
2841             // make the section name availabe via peinfo->sections[]) it would
2842             // be a pain to fetch the name here.  Since this is the only place
2843             // in cli_scanpe that needs the section name, and since I verified
2844             // that detection still occurs for Polipos without this check,
2845             // let's leave it commented out for now.
2846             if (SCAN_HEURISTICS && (DCONF & PE_CONF_POLIPOS) && /*!*peinfo->sections[i].sname &&*/ peinfo->sections[i].vsz > 40000 && peinfo->sections[i].vsz < 70000 && peinfo->sections[i].chr == 0xe0000060) polipos = i;
2847 
2848             /* check hash section sigs */
2849             if ((DCONF & PE_CONF_MD5SECT) && ctx->engine->hm_mdb) {
2850                 ret = scan_pe_mdb(ctx, &(peinfo->sections[i]));
2851                 if (ret != CL_CLEAN) {
2852                     // TODO Handle allmatch
2853                     if (ret != CL_VIRUS)
2854                         cli_errmsg("cli_scanpe: scan_pe_mdb failed: %s!\n", cl_strerror(ret));
2855 
2856                     cli_dbgmsg("------------------------------------\n");
2857                     cli_exe_info_destroy(peinfo);
2858                     return ret;
2859                 }
2860             }
2861         }
2862     }
2863 
2864     // TODO Don't bail out here
2865     if (peinfo->is_pe32plus) { /* Do not continue for PE32+ files */
2866         cli_exe_info_destroy(peinfo);
2867         return CL_CLEAN;
2868     }
2869 
2870     epsize = fmap_readn(map, epbuff, peinfo->ep, 4096);
2871 
2872     /* Disasm scan disabled since it's now handled by the bytecode */
2873 
2874     /* CLI_UNPTEMP("cli_scanpe: DISASM",(peinfo->sections,0)); */
2875     /* if(disasmbuf((unsigned char*)epbuff, epsize, ndesc)) */
2876     /*  ret = cli_scan_desc(ndesc, ctx, CL_TYPE_PE_DISASM, 1, NULL, AC_SCAN_VIR); */
2877     /* close(ndesc); */
2878     /* if(ret == CL_VIRUS) { */
2879     /*  cli_exe_info_destroy(peinfo); */
2880     /*  CLI_TMPUNLK(); */
2881     /*  free(tempfile); */
2882     /*  return ret; */
2883     /* } */
2884     /* CLI_TMPUNLK(); */
2885     /* free(tempfile); */
2886 
2887     if (peinfo->overlay_start && peinfo->overlay_size > 0) {
2888         ret = cli_scanishield(ctx, peinfo->overlay_start, peinfo->overlay_size);
2889         if (ret != CL_CLEAN) {
2890             // TODO Handle allmatch
2891             cli_exe_info_destroy(peinfo);
2892             return ret;
2893         }
2894     }
2895 
2896     pedata.nsections = peinfo->nsections;
2897     pedata.ep        = peinfo->ep;
2898     pedata.offset    = 0;
2899     memcpy(&pedata.file_hdr, &(peinfo->file_hdr), sizeof(peinfo->file_hdr));
2900     // TODO no need to copy both of these for each binary
2901     memcpy(&pedata.opt32, &(peinfo->pe_opt.opt32), sizeof(peinfo->pe_opt.opt32));
2902     memcpy(&pedata.opt64, &(peinfo->pe_opt.opt64), sizeof(peinfo->pe_opt.opt64));
2903     memcpy(&pedata.dirs, &(peinfo->dirs), sizeof(peinfo->dirs));
2904     // Gross
2905     memcpy(&pedata.opt32_dirs, &(peinfo->dirs), sizeof(peinfo->dirs));
2906     memcpy(&pedata.opt64_dirs, &(peinfo->dirs), sizeof(peinfo->dirs));
2907     pedata.e_lfanew    = peinfo->e_lfanew;
2908     pedata.overlays    = peinfo->overlay_start;
2909     pedata.overlays_sz = peinfo->overlay_size;
2910     pedata.hdr_size    = peinfo->hdr_size;
2911 
2912     /* Bytecode BC_PE_ALL hook */
2913     bc_ctx = cli_bytecode_context_alloc();
2914     if (!bc_ctx) {
2915         cli_errmsg("cli_scanpe: can't allocate memory for bc_ctx\n");
2916         cli_exe_info_destroy(peinfo);
2917         return CL_EMEM;
2918     }
2919 
2920     cli_bytecode_context_setpe(bc_ctx, &pedata, peinfo->sections);
2921     cli_bytecode_context_setctx(bc_ctx, ctx);
2922     ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_ALL, map);
2923     switch (ret) {
2924         case CL_ENULLARG:
2925             cli_warnmsg("cli_scanpe: NULL argument supplied\n");
2926             break;
2927         case CL_VIRUS:
2928         case CL_BREAK:
2929             // TODO Handle allmatch
2930             cli_exe_info_destroy(peinfo);
2931             cli_bytecode_context_destroy(bc_ctx);
2932             return ret == CL_VIRUS ? CL_VIRUS : CL_CLEAN;
2933     }
2934     cli_bytecode_context_destroy(bc_ctx);
2935 
2936     /* Attempt to run scans on import table */
2937     /* Run if there are existing signatures and/or preclassing */
2938 #if HAVE_JSON
2939     if (DCONF & PE_CONF_IMPTBL && (ctx->engine->hm_imp || ctx->wrkproperty)) {
2940 #else
2941     if (DCONF & PE_CONF_IMPTBL && ctx->engine->hm_imp) {
2942 #endif
2943         ret = scan_pe_imp(ctx, peinfo);
2944         switch (ret) {
2945             case CL_SUCCESS:
2946                 break;
2947             case CL_ENULLARG:
2948                 cli_warnmsg("cli_scanpe: NULL argument supplied\n");
2949                 break;
2950             case CL_VIRUS:
2951                 if (SCAN_ALLMATCHES)
2952                     break;
2953                 /* intentional fall-through */
2954             case CL_BREAK:
2955                 cli_exe_info_destroy(peinfo);
2956                 return ret == CL_VIRUS ? CL_VIRUS : CL_CLEAN;
2957             default:
2958                 cli_exe_info_destroy(peinfo);
2959                 return ret;
2960         }
2961     }
2962     /* Attempt to detect some popular polymorphic viruses */
2963 
2964     /* W32.Parite.B */
2965     if (SCAN_HEURISTICS && (DCONF & PE_CONF_PARITE) && !peinfo->is_dll && epsize == 4096 && peinfo->ep == peinfo->sections[peinfo->nsections - 1].raw) {
2966         const char *pt = cli_memstr(epbuff, 4040, "\x47\x65\x74\x50\x72\x6f\x63\x41\x64\x64\x72\x65\x73\x73\x00", 15);
2967         if (pt) {
2968             pt += 15;
2969             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)) {
2970                 ret = cli_append_virus(ctx, "Heuristics.W32.Parite.B");
2971                 if (ret != CL_CLEAN) {
2972                     if (ret == CL_VIRUS) {
2973                         if (!SCAN_ALLMATCHES) {
2974                             cli_exe_info_destroy(peinfo);
2975                             return ret;
2976                         } else
2977                             viruses_found++;
2978                     } else {
2979                         cli_exe_info_destroy(peinfo);
2980                         return ret;
2981                     }
2982                 }
2983             }
2984         }
2985     }
2986 
2987     /* Kriz */
2988     if (SCAN_HEURISTICS && (DCONF & PE_CONF_KRIZ) && epsize >= 200 && CLI_ISCONTAINED(peinfo->sections[peinfo->nsections - 1].raw, peinfo->sections[peinfo->nsections - 1].rsz, peinfo->ep, 0x0fd2) && epbuff[1] == '\x9c' && epbuff[2] == '\x60') {
2989         enum { KZSTRASH,
2990                KZSCDELTA,
2991                KZSPDELTA,
2992                KZSGETSIZE,
2993                KZSXORPRFX,
2994                KZSXOR,
2995                KZSDDELTA,
2996                KZSLOOP,
2997                KZSTOP };
2998         uint8_t kzs[]    = {KZSTRASH, KZSCDELTA, KZSPDELTA, KZSGETSIZE, KZSTRASH, KZSXORPRFX, KZSXOR, KZSTRASH, KZSDDELTA, KZSTRASH, KZSLOOP, KZSTOP};
2999         uint8_t *kzstate = kzs;
3000         uint8_t *kzcode  = (uint8_t *)epbuff + 3;
3001         uint8_t kzdptr = 0xff, kzdsize = 0xff;
3002         int kzlen = 197, kzinitlen = 0xffff, kzxorlen = -1;
3003         cli_dbgmsg("cli_scanpe: in kriz\n");
3004 
3005         while (*kzstate != KZSTOP) {
3006             uint8_t op;
3007             if (kzlen <= 6)
3008                 break;
3009 
3010             op = *kzcode++;
3011             kzlen--;
3012 
3013             switch (*kzstate) {
3014                 case KZSTRASH:
3015                 case KZSGETSIZE: {
3016                     int opsz = 0;
3017                     switch (op) {
3018                         case 0x81:
3019                             kzcode += 5;
3020                             kzlen -= 5;
3021                             break;
3022                         case 0xb8:
3023                         case 0xb9:
3024                         case 0xba:
3025                         case 0xbb:
3026                         case 0xbd:
3027                         case 0xbe:
3028                         case 0xbf:
3029                             if (*kzstate == KZSGETSIZE && cli_readint32(kzcode) == 0x0fd2) {
3030                                 kzinitlen = kzlen - 5;
3031                                 kzdsize   = op - 0xb8;
3032                                 kzstate++;
3033                                 op = 4; /* fake the register to avoid breaking out */
3034 
3035                                 cli_dbgmsg("cli_scanpe: kriz: using #%d as size counter\n", kzdsize);
3036                             }
3037                             opsz = 4;
3038                         case 0x48:
3039                         case 0x49:
3040                         case 0x4a:
3041                         case 0x4b:
3042                         case 0x4d:
3043                         case 0x4e:
3044                         case 0x4f:
3045                             op &= 7;
3046                             if (op != kzdptr && op != kzdsize) {
3047                                 kzcode += opsz;
3048                                 kzlen -= opsz;
3049                                 break;
3050                             }
3051                         default:
3052                             kzcode--;
3053                             kzlen++;
3054                             kzstate++;
3055                     }
3056 
3057                     break;
3058                 }
3059                 case KZSCDELTA:
3060                     if (op == 0xe8 && (uint32_t)cli_readint32(kzcode) < 0xff) {
3061                         kzlen -= *kzcode + 4;
3062                         kzcode += *kzcode + 4;
3063                         kzstate++;
3064                     } else {
3065                         *kzstate = KZSTOP;
3066                     }
3067 
3068                     break;
3069                 case KZSPDELTA:
3070                     if ((op & 0xf8) == 0x58 && (kzdptr = op - 0x58) != 4) {
3071                         kzstate++;
3072                         cli_dbgmsg("cli_scanpe: kriz: using #%d as pointer\n", kzdptr);
3073                     } else {
3074                         *kzstate = KZSTOP;
3075                     }
3076 
3077                     break;
3078                 case KZSXORPRFX:
3079                     kzstate++;
3080                     if (op == 0x3e)
3081                         break;
3082                 case KZSXOR:
3083                     if (op == 0x80 && *kzcode == kzdptr + 0xb0) {
3084                         kzxorlen = kzlen;
3085                         kzcode += +6;
3086                         kzlen -= +6;
3087                         kzstate++;
3088                     } else {
3089                         *kzstate = KZSTOP;
3090                     }
3091 
3092                     break;
3093                 case KZSDDELTA:
3094                     if (op == kzdptr + 0x48)
3095                         kzstate++;
3096                     else
3097                         *kzstate = KZSTOP;
3098 
3099                     break;
3100                 case KZSLOOP:
3101                     if (op == kzdsize + 0x48 && *kzcode == 0x75 && kzlen - (int8_t)kzcode[1] - 3 <= kzinitlen && kzlen - (int8_t)kzcode[1] >= kzxorlen) {
3102                         ret = cli_append_virus(ctx, "Heuristics.W32.Kriz");
3103                         if (ret != CL_CLEAN) {
3104                             if (ret == CL_VIRUS) {
3105                                 if (!SCAN_ALLMATCHES) {
3106                                     cli_exe_info_destroy(peinfo);
3107                                     return ret;
3108                                 } else
3109                                     viruses_found++;
3110                             } else {
3111                                 cli_exe_info_destroy(peinfo);
3112                                 return ret;
3113                             }
3114                         }
3115                     }
3116                     cli_dbgmsg("cli_scanpe: kriz: loop out of bounds, corrupted sample?\n");
3117                     kzstate++;
3118             }
3119         }
3120     }
3121 
3122     /* W32.Magistr.A/B */
3123     if (SCAN_HEURISTICS && (DCONF & PE_CONF_MAGISTR) && !peinfo->is_dll && (peinfo->nsections > 1) && (peinfo->sections[peinfo->nsections - 1].chr & 0x80000000)) {
3124         uint32_t rsize, vsize, dam = 0;
3125 
3126         vsize = peinfo->sections[peinfo->nsections - 1].uvsz;
3127         rsize = peinfo->sections[peinfo->nsections - 1].rsz;
3128         if (rsize < peinfo->sections[peinfo->nsections - 1].ursz) {
3129             rsize = peinfo->sections[peinfo->nsections - 1].ursz;
3130             dam   = 1;
3131         }
3132 
3133         if (vsize >= 0x612c && rsize >= 0x612c && ((vsize & 0xff) == 0xec)) {
3134             int bw = rsize < 0x7000 ? rsize : 0x7000;
3135             const char *tbuff;
3136 
3137             if ((tbuff = fmap_need_off_once(map, peinfo->sections[peinfo->nsections - 1].raw + rsize - bw, 4096))) {
3138                 if (cli_memstr(tbuff, 4091, "\xe8\x2c\x61\x00\x00", 5)) {
3139                     ret = cli_append_virus(ctx, dam ? "Heuristics.W32.Magistr.A.dam" : "Heuristics.W32.Magistr.A");
3140                     if (ret != CL_CLEAN) {
3141                         if (ret == CL_VIRUS) {
3142                             if (!SCAN_ALLMATCHES) {
3143                                 cli_exe_info_destroy(peinfo);
3144                                 return ret;
3145                             } else
3146                                 viruses_found++;
3147                         } else {
3148                             cli_exe_info_destroy(peinfo);
3149                             return ret;
3150                         }
3151                     }
3152                 }
3153             }
3154         } else if (rsize >= 0x7000 && vsize >= 0x7000 && ((vsize & 0xff) == 0xed)) {
3155             int bw = rsize < 0x8000 ? rsize : 0x8000;
3156             const char *tbuff;
3157 
3158             if ((tbuff = fmap_need_off_once(map, peinfo->sections[peinfo->nsections - 1].raw + rsize - bw, 4096))) {
3159                 if (cli_memstr(tbuff, 4091, "\xe8\x04\x72\x00\x00", 5)) {
3160                     ret = cli_append_virus(ctx, dam ? "Heuristics.W32.Magistr.B.dam" : "Heuristics.W32.Magistr.B");
3161                     if (ret != CL_CLEAN) {
3162                         if (ret == CL_VIRUS) {
3163                             if (!SCAN_ALLMATCHES) {
3164                                 cli_exe_info_destroy(peinfo);
3165                                 return ret;
3166                             } else
3167                                 viruses_found++;
3168                         } else {
3169                             cli_exe_info_destroy(peinfo);
3170                             return ret;
3171                         }
3172                     }
3173                 }
3174             }
3175         }
3176     }
3177 
3178     /* W32.Polipos.A */
3179     // TODO Add endianness correction to SizeOfStackReserve access
3180     while (polipos && !peinfo->is_dll && peinfo->nsections > 2 && peinfo->nsections < 13 && peinfo->e_lfanew <= 0x800 && (EC16(peinfo->pe_opt.opt32.Subsystem) == 2 || EC16(peinfo->pe_opt.opt32.Subsystem) == 3) && EC16(peinfo->file_hdr.Machine) == 0x14c && peinfo->pe_opt.opt32.SizeOfStackReserve >= 0x80000) {
3181         uint32_t jump, jold, *jumps = NULL;
3182         const uint8_t *code;
3183         unsigned int xsjs = 0;
3184 
3185         if (peinfo->sections[0].rsz > CLI_MAX_ALLOCATION)
3186             break;
3187         if (peinfo->sections[0].rsz < 5)
3188             break;
3189         if (!(code = fmap_need_off_once(map, peinfo->sections[0].raw, peinfo->sections[0].rsz)))
3190             break;
3191 
3192         for (i = 0; i < peinfo->sections[0].rsz - 5; i++) {
3193             if ((uint8_t)(code[i] - 0xe8) > 1)
3194                 continue;
3195 
3196             jump = cli_rawaddr(peinfo->sections[0].rva + i + 5 + cli_readint32(&code[i + 1]), peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size);
3197             if (err || !CLI_ISCONTAINED(peinfo->sections[polipos].raw, peinfo->sections[polipos].rsz, jump, 9))
3198                 continue;
3199 
3200             if (xsjs % 128 == 0) {
3201                 if (xsjs == 1280)
3202                     break;
3203 
3204                 if (!(jumps = (uint32_t *)cli_realloc2(jumps, (xsjs + 128) * sizeof(uint32_t)))) {
3205                     cli_exe_info_destroy(peinfo);
3206                     return CL_EMEM;
3207                 }
3208             }
3209 
3210             j = 0;
3211             for (; j < xsjs; j++) {
3212                 if (jumps[j] < jump)
3213                     continue;
3214                 if (jumps[j] == jump) {
3215                     xsjs--;
3216                     break;
3217                 }
3218 
3219                 jold     = jumps[j];
3220                 jumps[j] = jump;
3221                 jump     = jold;
3222             }
3223 
3224             jumps[j] = jump;
3225             xsjs++;
3226         }
3227 
3228         if (!xsjs)
3229             break;
3230 
3231         cli_dbgmsg("cli_scanpe: Polipos: Checking %d xsect jump(s)\n", xsjs);
3232         for (i = 0; i < xsjs; i++) {
3233             if (!(code = fmap_need_off_once(map, jumps[i], 9)))
3234                 continue;
3235 
3236             if ((jump = cli_readint32(code)) == 0x60ec8b55 || (code[4] == 0x0ec && ((jump == 0x83ec8b55 && code[6] == 0x60) || (jump == 0x81ec8b55 && !code[7] && !code[8])))) {
3237                 ret = cli_append_virus(ctx, "Heuristics.W32.Polipos.A");
3238                 if (ret != CL_CLEAN) {
3239                     if (ret == CL_VIRUS) {
3240                         if (!SCAN_ALLMATCHES) {
3241                             free(jumps);
3242                             cli_exe_info_destroy(peinfo);
3243                             return ret;
3244                         } else
3245                             viruses_found++;
3246                     } else {
3247                         free(jumps);
3248                         cli_exe_info_destroy(peinfo);
3249                         return ret;
3250                     }
3251                 }
3252             }
3253         }
3254 
3255         free(jumps);
3256         break;
3257     }
3258 
3259     /* Trojan.Swizzor.Gen */
3260     if (SCAN_HEURISTICS && (DCONF & PE_CONF_SWIZZOR) && peinfo->nsections > 1 && fsize > 64 * 1024 && fsize < 4 * 1024 * 1024) {
3261         if (peinfo->dirs[2].Size) {
3262             struct swizz_stats *stats = cli_calloc(1, sizeof(*stats));
3263             unsigned int m            = 1000;
3264             ret                       = CL_CLEAN;
3265 
3266             if (!stats) {
3267                 cli_exe_info_destroy(peinfo);
3268                 return CL_EMEM;
3269             } else {
3270                 cli_parseres_special(EC32(peinfo->dirs[2].VirtualAddress), EC32(peinfo->dirs[2].VirtualAddress), map, peinfo, fsize, 0, 0, &m, stats);
3271                 if ((ret = cli_detect_swizz(stats)) == CL_VIRUS) {
3272                     ret = cli_append_virus(ctx, "Heuristics.Trojan.Swizzor.Gen");
3273                     if (ret != CL_CLEAN) {
3274                         if (ret == CL_VIRUS) {
3275                             if (!SCAN_ALLMATCHES) {
3276                                 free(stats);
3277                                 cli_exe_info_destroy(peinfo);
3278                                 return ret;
3279                             } else
3280                                 viruses_found++;
3281                         } else {
3282                             free(stats);
3283                             cli_exe_info_destroy(peinfo);
3284                             return ret;
3285                         }
3286                     }
3287                 }
3288             }
3289         }
3290     }
3291 
3292     /* !!!!!!!!!!!!!!    PACKERS START HERE    !!!!!!!!!!!!!! */
3293     corrupted_cur        = ctx->corrupted_input;
3294     ctx->corrupted_input = 2; /* caller will reset on return */
3295 
3296     /* UPX, FSG, MEW support */
3297 
3298     /* try to find the first section with physical size == 0 */
3299     found = 0;
3300     if (DCONF & (PE_CONF_UPX | PE_CONF_FSG | PE_CONF_MEW)) {
3301         for (i = 0; i < (unsigned int)peinfo->nsections - 1; i++) {
3302             if (!peinfo->sections[i].rsz && peinfo->sections[i].vsz && peinfo->sections[i + 1].rsz && peinfo->sections[i + 1].vsz) {
3303                 found = 1;
3304                 cli_dbgmsg("cli_scanpe: UPX/FSG/MEW: empty section found - assuming compression\n");
3305 #if HAVE_JSON
3306                 if (pe_json != NULL)
3307                     cli_jsonbool(pe_json, "HasEmptySection", 1);
3308 #endif
3309                 break;
3310             }
3311         }
3312     }
3313 
3314     /* MEW support */
3315     if (found && (DCONF & PE_CONF_MEW) && epsize >= 16 && epbuff[0] == '\xe9') {
3316         uint32_t fileoffset;
3317         const char *tbuff;
3318 
3319         // TODO shouldn't peinfo->ep be used here instead?  ep is the file
3320         // offset, vep is the entry point RVA
3321         fileoffset = (peinfo->vep + cli_readint32(epbuff + 1) + 5);
3322         while (fileoffset == 0x154 || fileoffset == 0x158) {
3323             char *src;
3324             uint32_t offdiff, uselzma;
3325 
3326             cli_dbgmsg("cli_scanpe: MEW: found MEW characteristics %08X + %08X + 5 = %08X\n",
3327                        cli_readint32(epbuff + 1), peinfo->vep, cli_readint32(epbuff + 1) + peinfo->vep + 5);
3328 
3329             if (!(tbuff = fmap_need_off_once(map, fileoffset, 0xb0)))
3330                 break;
3331 
3332             if (fileoffset == 0x154)
3333                 cli_dbgmsg("cli_scanpe: MEW: Win9x compatibility was set!\n");
3334             else
3335                 cli_dbgmsg("cli_scanpe: MEW: Win9x compatibility was NOT set!\n");
3336 
3337             offdiff = cli_readint32(tbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase);
3338             if ((offdiff <= peinfo->sections[i + 1].rva) ||
3339                 (offdiff >= peinfo->sections[i + 1].rva + peinfo->sections[i + 1].raw - 4)) {
3340                 cli_dbgmsg("cli_scanpe: MEW: ESI is not in proper section\n");
3341                 break;
3342             }
3343 
3344             offdiff -= peinfo->sections[i + 1].rva;
3345 
3346             if (!peinfo->sections[i + 1].rsz) {
3347                 cli_dbgmsg("cli_scanpe: MEW: mew section is empty\n");
3348                 break;
3349             }
3350 
3351             ssize = peinfo->sections[i + 1].vsz;
3352             dsize = peinfo->sections[i].vsz;
3353 
3354             /* Guard against integer overflow */
3355             if ((ssize + dsize < ssize) || (ssize + dsize < dsize)) {
3356                 cli_dbgmsg("cli_scanpe: MEW: section size (%08x) + diff size (%08x) exceeds max size of unsigned int (%08x)\n", ssize, dsize, UINT32_MAX);
3357                 break;
3358             }
3359 
3360             /* Verify that offdiff does not exceed the ssize + sdiff */
3361             if (offdiff >= ssize + dsize) {
3362                 cli_dbgmsg("cli_scanpe: MEW: offdiff (%08x) exceeds section size + diff size (%08x)\n", offdiff, ssize + dsize);
3363                 break;
3364             }
3365 
3366             cli_dbgmsg("cli_scanpe: MEW: ssize %08x dsize %08x offdiff: %08x\n", ssize, dsize, offdiff);
3367 
3368             CLI_UNPSIZELIMITS("cli_scanpe: MEW", MAX(ssize, dsize));
3369             CLI_UNPSIZELIMITS("cli_scanpe: MEW", MAX(ssize + dsize, peinfo->sections[i + 1].rsz));
3370 
3371             if (peinfo->sections[i + 1].rsz < offdiff + 12 || peinfo->sections[i + 1].rsz > ssize) {
3372                 cli_dbgmsg("cli_scanpe: MEW: Size mismatch: %08x\n", peinfo->sections[i + 1].rsz);
3373                 break;
3374             }
3375 
3376             /* allocate needed buffer */
3377             if (!(src = cli_calloc(ssize + dsize, sizeof(char)))) {
3378                 cli_exe_info_destroy(peinfo);
3379                 return CL_EMEM;
3380             }
3381 
3382             bytes = fmap_readn(map, src + dsize, peinfo->sections[i + 1].raw, peinfo->sections[i + 1].rsz);
3383             if (bytes != peinfo->sections[i + 1].rsz) {
3384                 cli_dbgmsg("cli_scanpe: MEW: Can't read %u bytes [read: %zu]\n", peinfo->sections[i + 1].rsz, bytes);
3385                 cli_exe_info_destroy(peinfo);
3386                 free(src);
3387                 return CL_EREAD;
3388             }
3389 
3390             cli_dbgmsg("cli_scanpe: MEW: %zu (%08zx) bytes read\n", bytes, bytes);
3391 
3392             /* count offset to lzma proc, if lzma used, 0xe8 -> call */
3393             if (tbuff[0x7b] == '\xe8') {
3394                 if (!CLI_ISCONTAINED(peinfo->sections[1].rva, peinfo->sections[1].vsz, cli_readint32(tbuff + 0x7c) + fileoffset + 0x80, 4)) {
3395                     cli_dbgmsg("cli_scanpe: MEW: lzma proc out of bounds!\n");
3396                     free(src);
3397                     break; /* to next unpacker in chain */
3398                 }
3399 
3400                 uselzma = cli_readint32(tbuff + 0x7c) - (peinfo->sections[0].rva - fileoffset - 0x80);
3401             } else {
3402                 uselzma = 0;
3403             }
3404 
3405 #if HAVE_JSON
3406             if (pe_json != NULL)
3407                 cli_jsonstr(pe_json, "Packer", "MEW");
3408 #endif
3409 
3410             CLI_UNPTEMP("cli_scanpe: MEW", (src, 0));
3411             CLI_UNPRESULTS("cli_scanpe: MEW", (unmew11(src, offdiff, ssize, dsize, EC32(peinfo->pe_opt.opt32.ImageBase), peinfo->sections[0].rva, uselzma, ndesc)), 1, (src, 0));
3412             break;
3413         }
3414     }
3415 
3416     // TODO Why do we bail here
3417     if (epsize < 168) {
3418         cli_exe_info_destroy(peinfo);
3419         return CL_CLEAN;
3420     }
3421 
3422     if (found || upack) {
3423         /* Check EP for UPX vs. FSG vs. Upack */
3424 
3425         /* Upack 0.39 produces 2 types of executables
3426          * 3 sections:           | 2 sections (one empty, I don't check found if !upack, since it's in OR above):
3427          *   mov esi, value      |   pusha
3428          *   lodsd               |   call $+0x9
3429          *   push eax            |
3430          *
3431          * Upack 1.1/1.2 Beta produces [based on 2 samples (sUx) provided by aCaB]:
3432          * 2 sections
3433          *   mov esi, value
3434          *   loads
3435          *   mov edi, eax
3436          *
3437          * Upack unknown [sample 0297729]
3438          * 3 sections
3439          *   mov esi, value
3440          *   push [esi]
3441          *   jmp
3442          *
3443          */
3444         /* upack 0.39-3s + sample 0151477*/
3445         while (((upack && peinfo->nsections == 3) && /* 3 sections */
3446                 ((
3447                      epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase) > peinfo->min && /* mov esi */
3448                      epbuff[5] == '\xad' && epbuff[6] == '\x50'                                                               /* lodsd; push eax */
3449                      ) ||
3450                  /* based on 0297729 sample from aCaB */
3451                  (epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase) > peinfo->min && /* mov esi */
3452                   epbuff[5] == '\xff' && epbuff[6] == '\x36'                                                               /* push [esi] */
3453                   ))) ||
3454                ((!upack && peinfo->nsections == 2) &&                                            /* 2 sections */
3455                 ((                                                                               /* upack 0.39-2s */
3456                   epbuff[0] == '\x60' && epbuff[1] == '\xe8' && cli_readint32(epbuff + 2) == 0x9 /* pusha; call+9 */
3457                   ) ||
3458                  (                                                                                                         /* upack 1.1/1.2, based on 2 samples */
3459                   epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase) < peinfo->min && /* mov esi */
3460                   cli_readint32(epbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase) > 0 &&
3461                   epbuff[5] == '\xad' && epbuff[6] == '\x8b' && epbuff[7] == '\xf8' /* loads;  mov edi, eax */
3462                   )))) {
3463             uint32_t vma, off;
3464             int a, b, c;
3465 
3466             cli_dbgmsg("cli_scanpe: Upack characteristics found.\n");
3467             a = peinfo->sections[0].vsz;
3468             b = peinfo->sections[1].vsz;
3469             if (upack) {
3470                 cli_dbgmsg("cli_scanpe: Upack: var set\n");
3471 
3472                 c     = peinfo->sections[2].vsz;
3473                 ssize = peinfo->sections[0].ursz + peinfo->sections[0].uraw;
3474                 off   = peinfo->sections[0].rva;
3475                 vma   = EC32(peinfo->pe_opt.opt32.ImageBase) + peinfo->sections[0].rva;
3476             } else {
3477                 cli_dbgmsg("cli_scanpe: Upack: var NOT set\n");
3478                 c     = peinfo->sections[1].rva;
3479                 ssize = peinfo->sections[1].uraw;
3480                 off   = 0;
3481                 vma   = peinfo->sections[1].rva - peinfo->sections[1].uraw;
3482             }
3483 
3484             dsize = a + b + c;
3485 
3486             CLI_UNPSIZELIMITS("cli_scanpe: Upack", MAX(MAX(dsize, ssize), peinfo->sections[1].ursz));
3487 
3488             if (!CLI_ISCONTAINED_0_TO(dsize, peinfo->sections[1].rva - off, peinfo->sections[1].ursz) || (upack && !CLI_ISCONTAINED_0_TO(dsize, peinfo->sections[2].rva - peinfo->sections[0].rva, ssize)) || ssize > dsize) {
3489                 cli_dbgmsg("cli_scanpe: Upack: probably malformed pe-header, skipping to next unpacker\n");
3490                 break;
3491             }
3492 
3493             if ((dest = (char *)cli_calloc(dsize, sizeof(char))) == NULL) {
3494                 cli_exe_info_destroy(peinfo);
3495                 return CL_EMEM;
3496             }
3497 
3498             if (fmap_readn(map, dest, 0, ssize) != ssize) {
3499                 cli_dbgmsg("cli_scanpe: Upack: Can't read raw data of section 0\n");
3500                 free(dest);
3501                 break;
3502             }
3503 
3504             if (upack)
3505                 memmove(dest + peinfo->sections[2].rva - peinfo->sections[0].rva, dest, ssize);
3506 
3507             if (fmap_readn(map, dest + peinfo->sections[1].rva - off, peinfo->sections[1].uraw, peinfo->sections[1].ursz) != peinfo->sections[1].ursz) {
3508                 cli_dbgmsg("cli_scanpe: Upack: Can't read raw data of section 1\n");
3509                 free(dest);
3510                 break;
3511             }
3512 
3513 #if HAVE_JSON
3514             if (pe_json != NULL)
3515                 cli_jsonstr(pe_json, "Packer", "Upack");
3516 #endif
3517 
3518             CLI_UNPTEMP("cli_scanpe: Upack", (dest, 0));
3519             CLI_UNPRESULTS("cli_scanpe: Upack", (unupack(upack, dest, dsize, epbuff, vma, peinfo->ep, EC32(peinfo->pe_opt.opt32.ImageBase), peinfo->sections[0].rva, ndesc)), 1, (dest, 0));
3520 
3521             break;
3522         }
3523     }
3524 
3525     while (found && (DCONF & PE_CONF_FSG) && epbuff[0] == '\x87' && epbuff[1] == '\x25') {
3526         const char *dst;
3527         uint32_t newesi, newedi, newebx, newedx;
3528 
3529         /* FSG v2.0 support - thanks to aCaB ! */
3530 
3531         ssize = peinfo->sections[i + 1].rsz;
3532         dsize = peinfo->sections[i].vsz;
3533 
3534         CLI_UNPSIZELIMITS("cli_scanpe: FSG", MAX(dsize, ssize));
3535 
3536         if (ssize <= 0x19 || dsize <= ssize) {
3537             cli_dbgmsg("cli_scanpe: FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
3538             cli_exe_info_destroy(peinfo);
3539             return CL_CLEAN;
3540         }
3541 
3542         newedx = cli_readint32(epbuff + 2) - EC32(peinfo->pe_opt.opt32.ImageBase);
3543         if (!CLI_ISCONTAINED(peinfo->sections[i + 1].rva, peinfo->sections[i + 1].rsz, newedx, 4)) {
3544             cli_dbgmsg("cli_scanpe: FSG: xchg out of bounds (%x), giving up\n", newedx);
3545             break;
3546         }
3547 
3548         if (!peinfo->sections[i + 1].rsz || !(src = fmap_need_off_once(map, peinfo->sections[i + 1].raw, ssize))) {
3549             cli_dbgmsg("cli_scanpe: Can't read raw data of section %d\n", i + 1);
3550             cli_exe_info_destroy(peinfo);
3551             return CL_ESEEK;
3552         }
3553 
3554         dst = src + newedx - peinfo->sections[i + 1].rva;
3555         if (newedx < peinfo->sections[i + 1].rva || !CLI_ISCONTAINED(src, ssize, dst, 4)) {
3556             cli_dbgmsg("cli_scanpe: FSG: New ESP out of bounds\n");
3557             break;
3558         }
3559 
3560         newedx = cli_readint32(dst) - EC32(peinfo->pe_opt.opt32.ImageBase);
3561         if (!CLI_ISCONTAINED(peinfo->sections[i + 1].rva, peinfo->sections[i + 1].rsz, newedx, 4)) {
3562             cli_dbgmsg("cli_scanpe: FSG: New ESP (%x) is wrong\n", newedx);
3563             break;
3564         }
3565 
3566         dst = src + newedx - peinfo->sections[i + 1].rva;
3567         if (!CLI_ISCONTAINED(src, ssize, dst, 32)) {
3568             cli_dbgmsg("cli_scanpe: FSG: New stack out of bounds\n");
3569             break;
3570         }
3571 
3572         newedi = cli_readint32(dst) - EC32(peinfo->pe_opt.opt32.ImageBase);
3573         newesi = cli_readint32(dst + 4) - EC32(peinfo->pe_opt.opt32.ImageBase);
3574         newebx = cli_readint32(dst + 16) - EC32(peinfo->pe_opt.opt32.ImageBase);
3575         newedx = cli_readint32(dst + 20);
3576 
3577         if (newedi != peinfo->sections[i].rva) {
3578             cli_dbgmsg("cli_scanpe: FSG: Bad destination buffer (edi is %x should be %x)\n", newedi, peinfo->sections[i].rva);
3579             break;
3580         }
3581 
3582         if (newesi < peinfo->sections[i + 1].rva || newesi - peinfo->sections[i + 1].rva >= peinfo->sections[i + 1].rsz) {
3583             cli_dbgmsg("cli_scanpe: FSG: Source buffer out of section bounds\n");
3584             break;
3585         }
3586 
3587         if (!CLI_ISCONTAINED(peinfo->sections[i + 1].rva, peinfo->sections[i + 1].rsz, newebx, 16)) {
3588             cli_dbgmsg("cli_scanpe: FSG: Array of functions out of bounds\n");
3589             break;
3590         }
3591 
3592         newedx = cli_readint32(newebx + 12 - peinfo->sections[i + 1].rva + src) - EC32(peinfo->pe_opt.opt32.ImageBase);
3593         cli_dbgmsg("cli_scanpe: FSG: found old EP @%x\n", newedx);
3594 
3595         if ((dest = (char *)cli_calloc(dsize, sizeof(char))) == NULL) {
3596             cli_exe_info_destroy(peinfo);
3597             return CL_EMEM;
3598         }
3599 
3600 #if HAVE_JSON
3601         if (pe_json != NULL)
3602             cli_jsonstr(pe_json, "Packer", "FSG");
3603 #endif
3604 
3605         CLI_UNPTEMP("cli_scanpe: FSG", (dest, 0));
3606         CLI_UNPRESULTSFSG2("cli_scanpe: FSG", (unfsg_200(newesi - peinfo->sections[i + 1].rva + src, dest, ssize + peinfo->sections[i + 1].rva - newesi, dsize, newedi, EC32(peinfo->pe_opt.opt32.ImageBase), newedx, ndesc)), 1, (dest, 0));
3607         break;
3608     }
3609 
3610     while (found && (DCONF & PE_CONF_FSG) && epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase) < peinfo->min) {
3611         int sectcnt = 0;
3612         const char *support;
3613         uint32_t newesi, newedi, oldep, gp, t;
3614         struct cli_exe_section *sections;
3615 
3616         /* FSG support - v. 1.33 (thx trog for the many samples) */
3617 
3618         ssize = peinfo->sections[i + 1].rsz;
3619         dsize = peinfo->sections[i].vsz;
3620 
3621         CLI_UNPSIZELIMITS("cli_scanpe: FSG", MAX(dsize, ssize));
3622 
3623         if (ssize <= 0x19 || dsize <= ssize) {
3624             cli_dbgmsg("cli_scanpe: FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
3625             cli_exe_info_destroy(peinfo);
3626             return CL_CLEAN;
3627         }
3628 
3629         if (!(t = cli_rawaddr(cli_readint32(epbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase), NULL, 0, &err, fsize, peinfo->hdr_size)) && err) {
3630             cli_dbgmsg("cli_scanpe: FSG: Support data out of padding area\n");
3631             break;
3632         }
3633 
3634         gp = peinfo->sections[i + 1].raw - t;
3635 
3636         CLI_UNPSIZELIMITS("cli_scanpe: FSG", gp);
3637 
3638         if (!(support = fmap_need_off_once(map, t, gp))) {
3639             cli_dbgmsg("cli_scanpe: Can't read %d bytes from padding area\n", gp);
3640             cli_exe_info_destroy(peinfo);
3641             return CL_EREAD;
3642         }
3643 
3644         /* newebx = cli_readint32(support) - EC32(peinfo->pe_opt.opt32.ImageBase);  Unused */
3645         newedi = cli_readint32(support + 4) - EC32(peinfo->pe_opt.opt32.ImageBase); /* 1st dest */
3646         newesi = cli_readint32(support + 8) - EC32(peinfo->pe_opt.opt32.ImageBase); /* Source */
3647 
3648         if (newesi < peinfo->sections[i + 1].rva || newesi - peinfo->sections[i + 1].rva >= peinfo->sections[i + 1].rsz) {
3649             cli_dbgmsg("cli_scanpe: FSG: Source buffer out of section bounds\n");
3650             break;
3651         }
3652 
3653         if (newedi != peinfo->sections[i].rva) {
3654             cli_dbgmsg("cli_scanpe: FSG: Bad destination (is %x should be %x)\n", newedi, peinfo->sections[i].rva);
3655             break;
3656         }
3657 
3658         /* Counting original sections */
3659         for (t = 12; t < gp - 4; t += 4) {
3660             uint32_t rva = cli_readint32(support + t);
3661 
3662             if (!rva)
3663                 break;
3664 
3665             rva -= EC32(peinfo->pe_opt.opt32.ImageBase) + 1;
3666             sectcnt++;
3667 
3668             if (rva % 0x1000)
3669                 cli_dbgmsg("cli_scanpe: FSG: Original section %d is misaligned\n", sectcnt);
3670 
3671             if (rva < peinfo->sections[i].rva || rva - peinfo->sections[i].rva >= peinfo->sections[i].vsz) {
3672                 cli_dbgmsg("cli_scanpe: FSG: Original section %d is out of bounds\n", sectcnt);
3673                 break;
3674             }
3675         }
3676 
3677         if (t >= gp - 4 || cli_readint32(support + t)) {
3678             break;
3679         }
3680 
3681         if ((sections = (struct cli_exe_section *)cli_malloc((sectcnt + 1) * sizeof(struct cli_exe_section))) == NULL) {
3682             cli_errmsg("cli_scanpe: FSG: Unable to allocate memory for sections %llu\n", (long long unsigned)((sectcnt + 1) * sizeof(struct cli_exe_section)));
3683             cli_exe_info_destroy(peinfo);
3684             return CL_EMEM;
3685         }
3686 
3687         sections[0].rva = newedi;
3688         for (t = 1; t <= (uint32_t)sectcnt; t++)
3689             sections[t].rva = cli_readint32(support + 8 + t * 4) - 1 - EC32(peinfo->pe_opt.opt32.ImageBase);
3690 
3691         if (!peinfo->sections[i + 1].rsz || !(src = fmap_need_off_once(map, peinfo->sections[i + 1].raw, ssize))) {
3692             cli_dbgmsg("cli_scanpe: Can't read raw data of section %d\n", i);
3693             cli_exe_info_destroy(peinfo);
3694             free(sections);
3695             return CL_EREAD;
3696         }
3697 
3698         if ((dest = (char *)cli_calloc(dsize, sizeof(char))) == NULL) {
3699             cli_exe_info_destroy(peinfo);
3700             free(sections);
3701             return CL_EMEM;
3702         }
3703 
3704         oldep = peinfo->vep + 161 + 6 + cli_readint32(epbuff + 163);
3705         cli_dbgmsg("cli_scanpe: FSG: found old EP @%x\n", oldep);
3706 
3707 #if HAVE_JSON
3708         if (pe_json != NULL)
3709             cli_jsonstr(pe_json, "Packer", "FSG");
3710 #endif
3711 
3712         CLI_UNPTEMP("cli_scanpe: FSG", (dest, sections, 0));
3713         CLI_UNPRESULTSFSG1("cli_scanpe: FSG", (unfsg_133(src + newesi - peinfo->sections[i + 1].rva, dest, ssize + peinfo->sections[i + 1].rva - newesi, dsize, sections, sectcnt, EC32(peinfo->pe_opt.opt32.ImageBase), oldep, ndesc)), 1, (dest, sections, 0));
3714         break; /* were done with 1.33 */
3715     }
3716 
3717     while (found && (DCONF & PE_CONF_FSG) && epbuff[0] == '\xbb' && cli_readint32(epbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase) < peinfo->min && epbuff[5] == '\xbf' && epbuff[10] == '\xbe' && peinfo->vep >= peinfo->sections[i + 1].rva && peinfo->vep - peinfo->sections[i + 1].rva > peinfo->sections[i + 1].rva - 0xe0) {
3718         int sectcnt = 0;
3719         uint32_t gp, t = cli_rawaddr(cli_readint32(epbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase), NULL, 0, &err, fsize, peinfo->hdr_size);
3720         const char *support;
3721         uint32_t newesi = cli_readint32(epbuff + 11) - EC32(peinfo->pe_opt.opt32.ImageBase);
3722         uint32_t newedi = cli_readint32(epbuff + 6) - EC32(peinfo->pe_opt.opt32.ImageBase);
3723         uint32_t oldep  = peinfo->vep - peinfo->sections[i + 1].rva;
3724         struct cli_exe_section *sections;
3725 
3726         /* FSG support - v. 1.31 */
3727 
3728         ssize = peinfo->sections[i + 1].rsz;
3729         dsize = peinfo->sections[i].vsz;
3730 
3731         if (err) {
3732             cli_dbgmsg("cli_scanpe: FSG: Support data out of padding area\n");
3733             break;
3734         }
3735 
3736         if (newesi < peinfo->sections[i + 1].rva || newesi - peinfo->sections[i + 1].rva >= peinfo->sections[i + 1].raw) {
3737             cli_dbgmsg("cli_scanpe: FSG: Source buffer out of section bounds\n");
3738             break;
3739         }
3740 
3741         if (newedi != peinfo->sections[i].rva) {
3742             cli_dbgmsg("cli_scanpe: FSG: Bad destination (is %x should be %x)\n", newedi, peinfo->sections[i].rva);
3743             break;
3744         }
3745 
3746         CLI_UNPSIZELIMITS("cli_scanpe: FSG", MAX(dsize, ssize));
3747 
3748         if (ssize <= 0x19 || dsize <= ssize) {
3749             cli_dbgmsg("cli_scanpe: FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
3750             cli_exe_info_destroy(peinfo);
3751             return CL_CLEAN;
3752         }
3753 
3754         gp = peinfo->sections[i + 1].raw - t;
3755 
3756         CLI_UNPSIZELIMITS("cli_scanpe: FSG", gp)
3757 
3758         if (!(support = fmap_need_off_once(map, t, gp))) {
3759             cli_dbgmsg("cli_scanpe: Can't read %d bytes from padding area\n", gp);
3760             cli_exe_info_destroy(peinfo);
3761             return CL_EREAD;
3762         }
3763 
3764         /* Counting original sections */
3765         for (t = 0; t < gp - 2; t += 2) {
3766             uint32_t rva = support[t] | (support[t + 1] << 8);
3767 
3768             if (rva == 2 || rva == 1)
3769                 break;
3770 
3771             rva = ((rva - 2) << 12) - EC32(peinfo->pe_opt.opt32.ImageBase);
3772             sectcnt++;
3773 
3774             if (rva < peinfo->sections[i].rva || rva - peinfo->sections[i].rva >= peinfo->sections[i].vsz) {
3775                 cli_dbgmsg("cli_scanpe: FSG: Original section %d is out of bounds\n", sectcnt);
3776                 break;
3777             }
3778         }
3779 
3780         if (t >= gp - 10 || cli_readint32(support + t + 6) != 2)
3781             break;
3782 
3783         if ((sections = (struct cli_exe_section *)cli_malloc((sectcnt + 1) * sizeof(struct cli_exe_section))) == NULL) {
3784             cli_errmsg("cli_scanpe: FSG: Unable to allocate memory for sections %llu\n", (long long unsigned)((sectcnt + 1) * sizeof(struct cli_exe_section)));
3785             cli_exe_info_destroy(peinfo);
3786             return CL_EMEM;
3787         }
3788 
3789         sections[0].rva = newedi;
3790         for (t = 0; t <= (uint32_t)sectcnt - 1; t++)
3791             sections[t + 1].rva = (((support[t * 2] | (support[t * 2 + 1] << 8)) - 2) << 12) - EC32(peinfo->pe_opt.opt32.ImageBase);
3792 
3793         if (!peinfo->sections[i + 1].rsz || !(src = fmap_need_off_once(map, peinfo->sections[i + 1].raw, ssize))) {
3794             cli_dbgmsg("cli_scanpe: FSG: Can't read raw data of section %d\n", i);
3795             cli_exe_info_destroy(peinfo);
3796             free(sections);
3797             return CL_EREAD;
3798         }
3799 
3800         if ((dest = (char *)cli_calloc(dsize, sizeof(char))) == NULL) {
3801             cli_exe_info_destroy(peinfo);
3802             free(sections);
3803             return CL_EMEM;
3804         }
3805 
3806         gp    = 0xda + 6 * (epbuff[16] == '\xe8');
3807         oldep = peinfo->vep + gp + 6 + cli_readint32(src + gp + 2 + oldep);
3808         cli_dbgmsg("cli_scanpe: FSG: found old EP @%x\n", oldep);
3809 
3810 #if HAVE_JSON
3811         if (pe_json != NULL)
3812             cli_jsonstr(pe_json, "Packer", "FSG");
3813 #endif
3814 
3815         CLI_UNPTEMP("cli_scanpe: FSG", (dest, sections, 0));
3816         CLI_UNPRESULTSFSG1("cli_scanpe: FSG", (unfsg_133(src + newesi - peinfo->sections[i + 1].rva, dest, ssize + peinfo->sections[i + 1].rva - newesi, dsize, sections, sectcnt, EC32(peinfo->pe_opt.opt32.ImageBase), oldep, ndesc)), 1, (dest, sections, 0));
3817 
3818         break; /* were done with 1.31 */
3819     }
3820 
3821     if (found && (DCONF & PE_CONF_UPX)) {
3822         ssize = peinfo->sections[i + 1].rsz;
3823         dsize = peinfo->sections[i].vsz + peinfo->sections[i + 1].vsz;
3824 
3825         /*
3826          * UPX support
3827          * we assume (i + 1) is UPX1
3828          */
3829 
3830         /* cli_dbgmsg("UPX: ssize %u dsize %u\n", ssize, dsize); */
3831 
3832         CLI_UNPSIZELIMITS("cli_scanpe: UPX", MAX(dsize, ssize));
3833 
3834         if (ssize <= 0x19 || dsize <= ssize || dsize > CLI_MAX_ALLOCATION) {
3835             cli_dbgmsg("cli_scanpe: UPX: Size mismatch or dsize too big (ssize: %d, dsize: %d)\n", ssize, dsize);
3836             cli_exe_info_destroy(peinfo);
3837             return CL_CLEAN;
3838         }
3839 
3840         if (!peinfo->sections[i + 1].rsz || !(src = fmap_need_off_once(map, peinfo->sections[i + 1].raw, ssize))) {
3841             cli_dbgmsg("cli_scanpe: UPX: Can't read raw data of section %d\n", i + 1);
3842             cli_exe_info_destroy(peinfo);
3843             return CL_EREAD;
3844         }
3845 
3846         if ((dest = (char *)cli_calloc(dsize + 8192, sizeof(char))) == NULL) {
3847             cli_exe_info_destroy(peinfo);
3848             return CL_EMEM;
3849         }
3850 
3851         /* try to detect UPX code */
3852         if (cli_memstr(UPX_NRV2B, 24, epbuff + 0x69, 13) || cli_memstr(UPX_NRV2B, 24, epbuff + 0x69 + 8, 13)) {
3853             cli_dbgmsg("cli_scanpe: UPX: Looks like a NRV2B decompression routine\n");
3854             upxfn = upx_inflate2b;
3855         } else if (cli_memstr(UPX_NRV2D, 24, epbuff + 0x69, 13) || cli_memstr(UPX_NRV2D, 24, epbuff + 0x69 + 8, 13)) {
3856             cli_dbgmsg("cli_scanpe: UPX: Looks like a NRV2D decompression routine\n");
3857             upxfn = upx_inflate2d;
3858         } else if (cli_memstr(UPX_NRV2E, 24, epbuff + 0x69, 13) || cli_memstr(UPX_NRV2E, 24, epbuff + 0x69 + 8, 13)) {
3859             cli_dbgmsg("cli_scanpe: UPX: Looks like a NRV2E decompression routine\n");
3860             upxfn = upx_inflate2e;
3861         }
3862 
3863         if (upxfn) {
3864             int skew = cli_readint32(epbuff + 2) - EC32(peinfo->pe_opt.opt32.ImageBase) - peinfo->sections[i + 1].rva;
3865 
3866             if (epbuff[1] != '\xbe' || skew <= 0 || skew > 0xfff) {
3867                 /* FIXME: legit skews?? */
3868                 skew = 0;
3869             } else if ((unsigned int)skew > ssize) {
3870                 /* Ignore suggested skew larger than section size */
3871                 skew = 0;
3872             } else {
3873                 cli_dbgmsg("cli_scanpe: UPX: UPX1 seems skewed by %d bytes\n", skew);
3874             }
3875 
3876             /* Try skewed first (skew may be zero) */
3877             if (upxfn(src + skew, ssize - skew, dest, &dsize, peinfo->sections[i].rva, peinfo->sections[i + 1].rva, peinfo->vep - skew) >= 0) {
3878                 upx_success = 1;
3879             }
3880             /* If skew not successful and non-zero, try no skew */
3881             else if (skew && (upxfn(src, ssize, dest, &dsize, peinfo->sections[i].rva, peinfo->sections[i + 1].rva, peinfo->vep) >= 0)) {
3882                 upx_success = 1;
3883             }
3884 
3885             if (upx_success)
3886                 cli_dbgmsg("cli_scanpe: UPX: Successfully decompressed\n");
3887             else
3888                 cli_dbgmsg("cli_scanpe: UPX: Preferred decompressor failed\n");
3889         }
3890 
3891         if (!upx_success && upxfn != upx_inflate2b) {
3892             if (upx_inflate2b(src, ssize, dest, &dsize, peinfo->sections[i].rva, peinfo->sections[i + 1].rva, peinfo->vep) == -1 && upx_inflate2b(src + 0x15, ssize - 0x15, dest, &dsize, peinfo->sections[i].rva, peinfo->sections[i + 1].rva, peinfo->vep - 0x15) == -1) {
3893 
3894                 cli_dbgmsg("cli_scanpe: UPX: NRV2B decompressor failed\n");
3895             } else {
3896                 upx_success = 1;
3897                 cli_dbgmsg("cli_scanpe: UPX: Successfully decompressed with NRV2B\n");
3898             }
3899         }
3900 
3901         if (!upx_success && upxfn != upx_inflate2d) {
3902             if (upx_inflate2d(src, ssize, dest, &dsize, peinfo->sections[i].rva, peinfo->sections[i + 1].rva, peinfo->vep) == -1 && upx_inflate2d(src + 0x15, ssize - 0x15, dest, &dsize, peinfo->sections[i].rva, peinfo->sections[i + 1].rva, peinfo->vep - 0x15) == -1) {
3903 
3904                 cli_dbgmsg("cli_scanpe: UPX: NRV2D decompressor failed\n");
3905             } else {
3906                 upx_success = 1;
3907                 cli_dbgmsg("cli_scanpe: UPX: Successfully decompressed with NRV2D\n");
3908             }
3909         }
3910 
3911         if (!upx_success && upxfn != upx_inflate2e) {
3912             if (upx_inflate2e(src, ssize, dest, &dsize, peinfo->sections[i].rva, peinfo->sections[i + 1].rva, peinfo->vep) == -1 && upx_inflate2e(src + 0x15, ssize - 0x15, dest, &dsize, peinfo->sections[i].rva, peinfo->sections[i + 1].rva, peinfo->vep - 0x15) == -1) {
3913                 cli_dbgmsg("cli_scanpe: UPX: NRV2E decompressor failed\n");
3914             } else {
3915                 upx_success = 1;
3916                 cli_dbgmsg("cli_scanpe: UPX: Successfully decompressed with NRV2E\n");
3917             }
3918         }
3919 
3920         if (cli_memstr(UPX_LZMA2, 20, epbuff + 0x2f, 20)) {
3921             uint32_t strictdsize = cli_readint32(epbuff + 0x21), skew = 0;
3922             if (ssize > 0x15 && epbuff[0] == '\x60' && epbuff[1] == '\xbe') {
3923                 // TODO Add EC32
3924                 skew = cli_readint32(epbuff + 2) - peinfo->sections[i + 1].rva - peinfo->pe_opt.opt32.ImageBase;
3925                 if (skew != 0x15)
3926                     skew = 0;
3927             }
3928 
3929             if (strictdsize <= dsize)
3930                 upx_success = upx_inflatelzma(src + skew, ssize - skew, dest, &strictdsize, peinfo->sections[i].rva, peinfo->sections[i + 1].rva, peinfo->vep, 0x20003) >= 0;
3931         } else if (cli_memstr(UPX_LZMA1_FIRST, 8, epbuff + 0x39, 8) && cli_memstr(UPX_LZMA1_SECOND, 8, epbuff + 0x45, 8)) {
3932             uint32_t strictdsize = cli_readint32(epbuff + 0x2b), skew = 0;
3933             uint32_t properties = cli_readint32(epbuff + 0x41);
3934             if (ssize > 0x15 && epbuff[0] == '\x60' && epbuff[1] == '\xbe') {
3935                 // TODO Add EC32
3936                 skew = cli_readint32(epbuff + 2) - peinfo->sections[i + 1].rva - peinfo->pe_opt.opt32.ImageBase;
3937                 if (skew != 0x15)
3938                     skew = 0;
3939             }
3940 
3941             if (strictdsize <= dsize)
3942                 upx_success = upx_inflatelzma(src + skew, ssize - skew, dest, &strictdsize, peinfo->sections[i].rva, peinfo->sections[i + 1].rva, peinfo->vep, properties) >= 0;
3943         }
3944 
3945         if (!upx_success) {
3946             cli_dbgmsg("cli_scanpe: UPX: All decompressors failed\n");
3947             free(dest);
3948         }
3949     }
3950 
3951     if (upx_success) {
3952         cli_exe_info_destroy(peinfo);
3953 
3954         CLI_UNPTEMP("cli_scanpe: UPX/FSG", (dest, 0));
3955 #if HAVE_JSON
3956         if (pe_json != NULL)
3957             cli_jsonstr(pe_json, "Packer", "UPX");
3958 #endif
3959 
3960         if ((unsigned int)write(ndesc, dest, dsize) != dsize) {
3961             cli_dbgmsg("cli_scanpe: UPX/FSG: Can't write %d bytes\n", dsize);
3962             free(tempfile);
3963             free(dest);
3964             close(ndesc);
3965             return CL_EWRITE;
3966         }
3967 
3968         free(dest);
3969         if (lseek(ndesc, 0, SEEK_SET) == -1) {
3970             cli_dbgmsg("cli_scanpe: UPX/FSG: lseek() failed\n");
3971             close(ndesc);
3972             SHA_RESET;
3973             CLI_TMPUNLK();
3974             free(tempfile);
3975             return CL_ESEEK;
3976         }
3977 
3978         if (ctx->engine->keeptmp)
3979             cli_dbgmsg("cli_scanpe: UPX/FSG: Decompressed data saved in %s\n", tempfile);
3980 
3981         cli_dbgmsg("***** Scanning decompressed file *****\n");
3982         SHA_OFF;
3983         if ((ret = cli_magic_scan_desc(ndesc, tempfile, ctx, NULL)) == CL_VIRUS) {
3984             close(ndesc);
3985             SHA_RESET;
3986             CLI_TMPUNLK();
3987             free(tempfile);
3988             return CL_VIRUS;
3989         }
3990 
3991         SHA_RESET;
3992         close(ndesc);
3993         CLI_TMPUNLK();
3994         free(tempfile);
3995         return ret;
3996     }
3997 
3998     /* Petite */
3999 
4000     if (epsize < 200) {
4001         cli_exe_info_destroy(peinfo);
4002         return CL_CLEAN;
4003     }
4004 
4005     found = 2;
4006 
4007     if (epbuff[0] != '\xb8' || (uint32_t)cli_readint32(epbuff + 1) != peinfo->sections[peinfo->nsections - 1].rva + EC32(peinfo->pe_opt.opt32.ImageBase)) {
4008         if (peinfo->nsections < 2 || epbuff[0] != '\xb8' || (uint32_t)cli_readint32(epbuff + 1) != peinfo->sections[peinfo->nsections - 2].rva + EC32(peinfo->pe_opt.opt32.ImageBase))
4009             found = 0;
4010         else
4011             found = 1;
4012     }
4013 
4014     if (found && (DCONF & PE_CONF_PETITE)) {
4015         cli_dbgmsg("cli_scanpe: Petite: v2.%d compression detected\n", found);
4016 
4017         if (cli_readint32(epbuff + 0x80) == 0x163c988d) {
4018             cli_dbgmsg("cli_scanpe: Petite: level zero compression is not supported yet\n");
4019         } else {
4020             dsize = peinfo->max - peinfo->min;
4021 
4022             CLI_UNPSIZELIMITS("cli_scanpe: Petite", dsize);
4023 
4024             if ((dest = (char *)cli_calloc(dsize, sizeof(char))) == NULL) {
4025                 cli_dbgmsg("cli_scanpe: Petite: Can't allocate %d bytes\n", dsize);
4026                 cli_exe_info_destroy(peinfo);
4027                 return CL_EMEM;
4028             }
4029 
4030             for (i = 0; i < peinfo->nsections; i++) {
4031                 if (peinfo->sections[i].raw) {
4032                     unsigned int r_ret;
4033 
4034                     if (!peinfo->sections[i].rsz)
4035                         goto out_no_petite;
4036 
4037                     if (!CLI_ISCONTAINED(dest, dsize,
4038                                          dest + peinfo->sections[i].rva - peinfo->min,
4039                                          peinfo->sections[i].ursz))
4040                         goto out_no_petite;
4041 
4042                     r_ret = fmap_readn(map, dest + peinfo->sections[i].rva - peinfo->min,
4043                                        peinfo->sections[i].raw,
4044                                        peinfo->sections[i].ursz);
4045                     if (r_ret != peinfo->sections[i].ursz) {
4046                     out_no_petite:
4047                         cli_exe_info_destroy(peinfo);
4048                         free(dest);
4049                         return CL_CLEAN;
4050                     }
4051                 }
4052             }
4053 
4054 #if HAVE_JSON
4055             if (pe_json != NULL)
4056                 cli_jsonstr(pe_json, "Packer", "Petite");
4057 #endif
4058 
4059             CLI_UNPTEMP("cli_scanpe: Petite", (dest, 0));
4060             CLI_UNPRESULTS("Petite", (petite_inflate2x_1to9(dest, peinfo->min, peinfo->max - peinfo->min, peinfo->sections, peinfo->nsections - (found == 1 ? 1 : 0), EC32(peinfo->pe_opt.opt32.ImageBase), peinfo->vep, ndesc, found, EC32(peinfo->dirs[2].VirtualAddress), EC32(peinfo->dirs[2].Size))), 0, (dest, 0));
4061         }
4062     }
4063 
4064     /* PESpin 1.1 */
4065 
4066     if ((DCONF & PE_CONF_PESPIN) && peinfo->nsections > 1 &&
4067         peinfo->vep >= peinfo->sections[peinfo->nsections - 1].rva &&
4068         0x3217 - 4 <= peinfo->sections[peinfo->nsections - 1].rva + peinfo->sections[peinfo->nsections - 1].rsz &&
4069         peinfo->vep < peinfo->sections[peinfo->nsections - 1].rva + peinfo->sections[peinfo->nsections - 1].rsz - 0x3217 - 4 &&
4070         memcmp(epbuff + 4, "\xe8\x00\x00\x00\x00\x8b\x1c\x24\x83\xc3", 10) == 0) {
4071 
4072         char *spinned;
4073 
4074         CLI_UNPSIZELIMITS("cli_scanpe: PEspin", fsize);
4075 
4076         if ((spinned = (char *)cli_malloc(fsize)) == NULL) {
4077             cli_errmsg("cli_scanpe: PESping: Unable to allocate memory for spinned %lu\n", (unsigned long)fsize);
4078             cli_exe_info_destroy(peinfo);
4079             return CL_EMEM;
4080         }
4081 
4082         if (fmap_readn(map, spinned, 0, fsize) != fsize) {
4083             cli_dbgmsg("cli_scanpe: PESpin: Can't read %lu bytes\n", (unsigned long)fsize);
4084             free(spinned);
4085             cli_exe_info_destroy(peinfo);
4086             return CL_EREAD;
4087         }
4088 
4089 #if HAVE_JSON
4090         if (pe_json != NULL)
4091             cli_jsonstr(pe_json, "Packer", "PEspin");
4092 #endif
4093 
4094         CLI_UNPTEMP("cli_scanpe: PESpin", (spinned, 0));
4095         CLI_UNPRESULTS_("cli_scanpe: PEspin", SPINCASE(), (unspin(spinned, fsize, peinfo->sections, peinfo->nsections - 1, peinfo->vep, ndesc, ctx)), 0, (spinned, 0));
4096     }
4097 
4098     /* yC 1.3 & variants */
4099     if ((DCONF & PE_CONF_YC) && peinfo->nsections > 1 &&
4100         (EC32(peinfo->pe_opt.opt32.AddressOfEntryPoint) == peinfo->sections[peinfo->nsections - 1].rva + 0x60)) {
4101 
4102         uint32_t ecx = 0;
4103         int16_t offset;
4104 
4105         /* yC 1.3 */
4106         if (!memcmp(epbuff, "\x55\x8B\xEC\x53\x56\x57\x60\xE8\x00\x00\x00\x00\x5D\x81\xED", 15) &&
4107             !memcmp(epbuff + 0x26, "\x8D\x3A\x8B\xF7\x33\xC0\xEB\x04\x90\xEB\x01\xC2\xAC", 13) &&
4108             ((uint8_t)epbuff[0x13] == 0xB9) &&
4109             ((uint16_t)(cli_readint16(epbuff + 0x18)) == 0xE981) &&
4110             !memcmp(epbuff + 0x1e, "\x8B\xD5\x81\xC2", 4)) {
4111 
4112             offset = 0;
4113             if (0x6c - cli_readint32(epbuff + 0xf) + cli_readint32(epbuff + 0x22) == 0xC6)
4114                 ecx = cli_readint32(epbuff + 0x14) - cli_readint32(epbuff + 0x1a);
4115         }
4116 
4117         /* yC 1.3 variant */
4118         if (!ecx && !memcmp(epbuff, "\x55\x8B\xEC\x83\xEC\x40\x53\x56\x57", 9) &&
4119             !memcmp(epbuff + 0x17, "\xe8\x00\x00\x00\x00\x5d\x81\xed", 8) &&
4120             ((uint8_t)epbuff[0x23] == 0xB9)) {
4121 
4122             offset = 0x10;
4123             if (0x6c - cli_readint32(epbuff + 0x1f) + cli_readint32(epbuff + 0x32) == 0xC6)
4124                 ecx = cli_readint32(epbuff + 0x24) - cli_readint32(epbuff + 0x2a);
4125         }
4126 
4127         /* yC 1.x/modified */
4128         if (!ecx && !memcmp(epbuff, "\x60\xe8\x00\x00\x00\x00\x5d\x81\xed", 9) &&
4129             ((uint8_t)epbuff[0xd] == 0xb9) &&
4130             ((uint16_t)cli_readint16(epbuff + 0x12) == 0xbd8d) &&
4131             !memcmp(epbuff + 0x18, "\x8b\xf7\xac", 3)) {
4132 
4133             offset = -0x18;
4134             if (0x66 - cli_readint32(epbuff + 0x9) + cli_readint32(epbuff + 0x14) == 0xae)
4135                 ecx = cli_readint32(epbuff + 0xe);
4136         }
4137 
4138         if (ecx > 0x800 && ecx < 0x2000 &&
4139             !memcmp(epbuff + 0x63 + offset, "\xaa\xe2\xcc", 3) &&
4140             (fsize >= peinfo->sections[peinfo->nsections - 1].raw + 0xC6 + ecx + offset)) {
4141 
4142             char *spinned;
4143 
4144             if ((spinned = (char *)cli_malloc(fsize)) == NULL) {
4145                 cli_errmsg("cli_scanpe: yC: Unable to allocate memory for spinned %lu\n", (unsigned long)fsize);
4146                 cli_exe_info_destroy(peinfo);
4147                 return CL_EMEM;
4148             }
4149 
4150             if (fmap_readn(map, spinned, 0, fsize) != fsize) {
4151                 cli_dbgmsg("cli_scanpe: yC: Can't read %lu bytes\n", (unsigned long)fsize);
4152                 free(spinned);
4153                 cli_exe_info_destroy(peinfo);
4154                 return CL_EREAD;
4155             }
4156 
4157 #if HAVE_JSON
4158             if (pe_json != NULL)
4159                 cli_jsonstr(pe_json, "Packer", "yC");
4160 #endif
4161 
4162             do {
4163                 unsigned int yc_unp_num_viruses = ctx->num_viruses;
4164                 const char *yc_unp_virname      = NULL;
4165 
4166                 if (ctx->virname)
4167                     yc_unp_virname = ctx->virname[0];
4168 
4169                 cli_dbgmsg("%d,%d,%d,%d\n", peinfo->nsections - 1, peinfo->e_lfanew, ecx, offset);
4170                 CLI_UNPTEMP("cli_scanpe: yC", (spinned, 0));
4171                 CLI_UNPRESULTS("cli_scanpe: yC", (yc_decrypt(ctx, spinned, fsize, peinfo->sections, peinfo->nsections - 1, peinfo->e_lfanew, ndesc, ecx, offset)), 0, (spinned, 0));
4172 
4173                 if (SCAN_ALLMATCHES && yc_unp_num_viruses != ctx->num_viruses) {
4174                     cli_exe_info_destroy(peinfo);
4175                     return CL_VIRUS;
4176                 } else if (ctx->virname && yc_unp_virname != ctx->virname[0]) {
4177                     cli_exe_info_destroy(peinfo);
4178                     return CL_VIRUS;
4179                 }
4180             } while (0);
4181         }
4182     }
4183 
4184     /* WWPack */
4185 
4186     while ((DCONF & PE_CONF_WWPACK) && peinfo->nsections > 1 &&
4187            peinfo->vep == peinfo->sections[peinfo->nsections - 1].rva &&
4188            memcmp(epbuff, "\x53\x55\x8b\xe8\x33\xdb\xeb", 7) == 0 &&
4189            memcmp(epbuff + 0x68, "\xe8\x00\x00\x00\x00\x58\x2d\x6d\x00\x00\x00\x50\x60\x33\xc9\x50\x58\x50\x50", 19) == 0) {
4190         uint32_t head = peinfo->sections[peinfo->nsections - 1].raw;
4191         uint8_t *packer;
4192         char *src;
4193 
4194         ssize = 0;
4195         for (i = 0;; i++) {
4196             if (peinfo->sections[i].raw < head)
4197                 head = peinfo->sections[i].raw;
4198 
4199             if (i + 1 == peinfo->nsections)
4200                 break;
4201 
4202             if (ssize < peinfo->sections[i].rva + peinfo->sections[i].vsz)
4203                 ssize = peinfo->sections[i].rva + peinfo->sections[i].vsz;
4204         }
4205 
4206         if (!head || !ssize || head > ssize)
4207             break;
4208 
4209         CLI_UNPSIZELIMITS("cli_scanpe: WWPack", ssize);
4210 
4211         if (!(src = (char *)cli_calloc(ssize, sizeof(char)))) {
4212             cli_exe_info_destroy(peinfo);
4213             return CL_EMEM;
4214         }
4215 
4216         if (fmap_readn(map, src, 0, head) != head) {
4217             cli_dbgmsg("cli_scanpe: WWPack: Can't read %d bytes from headers\n", head);
4218             free(src);
4219             cli_exe_info_destroy(peinfo);
4220             return CL_EREAD;
4221         }
4222 
4223         for (i = 0; i < (unsigned int)peinfo->nsections - 1; i++) {
4224             if (!peinfo->sections[i].rsz)
4225                 continue;
4226 
4227             if (!CLI_ISCONTAINED(src, ssize, src + peinfo->sections[i].rva, peinfo->sections[i].rsz))
4228                 break;
4229 
4230             if (fmap_readn(map, src + peinfo->sections[i].rva, peinfo->sections[i].raw, peinfo->sections[i].rsz) != peinfo->sections[i].rsz)
4231                 break;
4232         }
4233 
4234         if (i + 1 != peinfo->nsections) {
4235             cli_dbgmsg("cli_scanpe: WWpack: Probably hacked/damaged file.\n");
4236             free(src);
4237             break;
4238         }
4239 
4240         if ((packer = (uint8_t *)cli_calloc(peinfo->sections[peinfo->nsections - 1].rsz, sizeof(char))) == NULL) {
4241             free(src);
4242             cli_exe_info_destroy(peinfo);
4243             return CL_EMEM;
4244         }
4245 
4246         if (!peinfo->sections[peinfo->nsections - 1].rsz || fmap_readn(map, packer, peinfo->sections[peinfo->nsections - 1].raw, peinfo->sections[peinfo->nsections - 1].rsz) != peinfo->sections[peinfo->nsections - 1].rsz) {
4247             cli_dbgmsg("cli_scanpe: WWPack: Can't read %d bytes from wwpack sect\n", peinfo->sections[peinfo->nsections - 1].rsz);
4248             free(src);
4249             free(packer);
4250             cli_exe_info_destroy(peinfo);
4251             return CL_EREAD;
4252         }
4253 
4254 #if HAVE_JSON
4255         if (pe_json != NULL)
4256             cli_jsonstr(pe_json, "Packer", "WWPack");
4257 #endif
4258 
4259         CLI_UNPTEMP("cli_scanpe: WWPack", (src, packer, 0));
4260         CLI_UNPRESULTS("cli_scanpe: WWPack", (wwunpack((uint8_t *)src, ssize, packer, peinfo->sections, peinfo->nsections - 1, peinfo->e_lfanew, ndesc)), 0, (src, packer, 0));
4261         break;
4262     }
4263 
4264     /* ASPACK support */
4265     while ((DCONF & PE_CONF_ASPACK) &&
4266            ((peinfo->ep + ASPACK_EP_OFFSET_212 < fsize) ||
4267             (peinfo->ep + ASPACK_EP_OFFSET_OTHER < fsize) ||
4268             (peinfo->ep + ASPACK_EP_OFFSET_242 < fsize)) &&
4269            (!memcmp(epbuff, "\x60\xe8\x03\x00\x00\x00\xe9\xeb", 8))) {
4270         char *src;
4271         aspack_version_t aspack_ver = ASPACK_VER_NONE;
4272 
4273         if (epsize < 0x3bf)
4274             break;
4275 
4276         if (0 == memcmp(epbuff + ASPACK_EPBUFF_OFFSET_212, "\x68\x00\x00\x00\x00\xc3", 6)) {
4277             aspack_ver = ASPACK_VER_212;
4278         } else if (0 == memcmp(epbuff + ASPACK_EPBUFF_OFFSET_OTHER, "\x68\x00\x00\x00\x00\xc3", 6)) {
4279             aspack_ver = ASPACK_VER_OTHER;
4280         } else if (0 == memcmp(epbuff + ASPACK_EPBUFF_OFFSET_242, "\x68\x00\x00\x00\x00\xc3", 6)) {
4281             aspack_ver = ASPACK_VER_242;
4282         } else {
4283             break;
4284         }
4285         ssize = 0;
4286         for (i = 0; i < peinfo->nsections; i++)
4287             if (ssize < peinfo->sections[i].rva + peinfo->sections[i].vsz)
4288                 ssize = peinfo->sections[i].rva + peinfo->sections[i].vsz;
4289 
4290         if (!ssize)
4291             break;
4292 
4293         CLI_UNPSIZELIMITS("cli_scanpe: Aspack", ssize);
4294 
4295         if (!(src = (char *)cli_calloc(ssize, sizeof(char)))) {
4296             cli_exe_info_destroy(peinfo);
4297             return CL_EMEM;
4298         }
4299         for (i = 0; i < (unsigned int)peinfo->nsections; i++) {
4300             if (!peinfo->sections[i].rsz)
4301                 continue;
4302 
4303             if (!CLI_ISCONTAINED(src, ssize, src + peinfo->sections[i].rva, peinfo->sections[i].rsz))
4304                 break;
4305 
4306             if (fmap_readn(map, src + peinfo->sections[i].rva, peinfo->sections[i].raw, peinfo->sections[i].rsz) != peinfo->sections[i].rsz)
4307                 break;
4308         }
4309 
4310         if (i != peinfo->nsections) {
4311             cli_dbgmsg("cli_scanpe: Aspack: Probably hacked/damaged Aspack file.\n");
4312             free(src);
4313             break;
4314         }
4315 
4316 #if HAVE_JSON
4317         if (pe_json != NULL)
4318             cli_jsonstr(pe_json, "Packer", "Aspack");
4319 #endif
4320 
4321         CLI_UNPTEMP("cli_scanpe: Aspack", (src, 0));
4322         CLI_UNPRESULTS("cli_scanpe: Aspack", (unaspack((uint8_t *)src, ssize, peinfo->sections, peinfo->nsections, peinfo->vep - 1, EC32(peinfo->pe_opt.opt32.ImageBase), ndesc, aspack_ver)), 1, (src, 0));
4323         break;
4324     }
4325 
4326     /* NsPack */
4327 
4328     while (DCONF & PE_CONF_NSPACK) {
4329         uint32_t eprva = peinfo->vep;
4330         uint32_t start_of_stuff, rep = peinfo->ep;
4331         unsigned int nowinldr;
4332         const char *nbuff;
4333 
4334         src = epbuff;
4335         if (*epbuff == '\xe9') { /* bitched headers */
4336             eprva = cli_readint32(epbuff + 1) + peinfo->vep + 5;
4337             if (!(rep = cli_rawaddr(eprva, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size)) && err)
4338                 break;
4339 
4340             if (!(nbuff = fmap_need_off_once(map, rep, 24)))
4341                 break;
4342 
4343             src = nbuff;
4344         }
4345 
4346         if (memcmp(src, "\x9c\x60\xe8\x00\x00\x00\x00\x5d\xb8\x07\x00\x00\x00", 13))
4347             break;
4348 
4349         nowinldr = 0x54 - cli_readint32(src + 17);
4350         cli_dbgmsg("cli_scanpe: NsPack: Found *start_of_stuff @delta-%x\n", nowinldr);
4351 
4352         if (!(nbuff = fmap_need_off_once(map, rep - nowinldr, 4)))
4353             break;
4354 
4355         start_of_stuff = rep + cli_readint32(nbuff);
4356         if (!(nbuff = fmap_need_off_once(map, start_of_stuff, 20)))
4357             break;
4358 
4359         src = nbuff;
4360         if (!cli_readint32(nbuff)) {
4361             start_of_stuff += 4; /* FIXME: more to do */
4362             src += 4;
4363         }
4364 
4365         ssize = cli_readint32(src + 5) | 0xff;
4366         dsize = cli_readint32(src + 9);
4367 
4368         CLI_UNPSIZELIMITS("cli_scanpe: NsPack", MAX(ssize, dsize));
4369 
4370         if (!ssize || !dsize || dsize != peinfo->sections[0].vsz)
4371             break;
4372 
4373         if (!(dest = cli_malloc(dsize))) {
4374             cli_errmsg("cli_scanpe: NsPack: Unable to allocate memory for dest %u\n", dsize);
4375             break;
4376         }
4377         /* memset(dest, 0xfc, dsize); */
4378 
4379         if (!(src = fmap_need_off(map, start_of_stuff, ssize))) {
4380             free(dest);
4381             break;
4382         }
4383         /* memset(src, 0x00, ssize); */
4384 
4385         eprva += 0x27a;
4386         if (!(rep = cli_rawaddr(eprva, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size)) && err) {
4387             free(dest);
4388             break;
4389         }
4390 
4391         if (!(nbuff = fmap_need_off_once(map, rep, 5))) {
4392             free(dest);
4393             break;
4394         }
4395 
4396         fmap_unneed_off(map, start_of_stuff, ssize);
4397         eprva = eprva + 5 + cli_readint32(nbuff + 1);
4398         cli_dbgmsg("cli_scanpe: NsPack: OEP = %08x\n", eprva);
4399 
4400 #if HAVE_JSON
4401         if (pe_json != NULL)
4402             cli_jsonstr(pe_json, "Packer", "NsPack");
4403 #endif
4404 
4405         CLI_UNPTEMP("cli_scanpe: NsPack", (dest, 0));
4406         CLI_UNPRESULTS("cli_scanpe: NsPack", (unspack(src, dest, ctx, peinfo->sections[0].rva, EC32(peinfo->pe_opt.opt32.ImageBase), eprva, ndesc)), 0, (dest, 0));
4407         break;
4408     }
4409 
4410     /* to be continued ... */
4411 
4412     /* !!!!!!!!!!!!!!    PACKERS END HERE    !!!!!!!!!!!!!! */
4413     ctx->corrupted_input = corrupted_cur;
4414 
4415     /* Bytecode BC_PE_UNPACKER hook */
4416     bc_ctx = cli_bytecode_context_alloc();
4417     if (!bc_ctx) {
4418         cli_errmsg("cli_scanpe: can't allocate memory for bc_ctx\n");
4419         return CL_EMEM;
4420     }
4421 
4422     cli_bytecode_context_setpe(bc_ctx, &pedata, peinfo->sections);
4423     cli_bytecode_context_setctx(bc_ctx, ctx);
4424 
4425     ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_UNPACKER, map);
4426     switch (ret) {
4427         case CL_VIRUS:
4428             cli_exe_info_destroy(peinfo);
4429             cli_bytecode_context_destroy(bc_ctx);
4430             // TODO Handle allmatch
4431             return CL_VIRUS;
4432         case CL_SUCCESS:
4433             ndesc = cli_bytecode_context_getresult_file(bc_ctx, &tempfile);
4434             cli_bytecode_context_destroy(bc_ctx);
4435             if (ndesc != -1 && tempfile) {
4436                 CLI_UNPRESULTS("cli_scanpe: bytecode PE hook", 1, 1, (0));
4437             }
4438 
4439             break;
4440         default:
4441             cli_bytecode_context_destroy(bc_ctx);
4442     }
4443 
4444     cli_exe_info_destroy(peinfo);
4445 
4446 #if HAVE_JSON
4447     if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS)
4448         return CL_ETIMEOUT;
4449 #endif
4450 
4451     if (SCAN_ALLMATCHES && viruses_found)
4452         return CL_VIRUS;
4453 
4454     return CL_CLEAN;
4455 }
4456 
4457 int cli_pe_targetinfo(cli_ctx *ctx, struct cli_exe_info *peinfo)
4458 {
4459     return cli_peheader(ctx->fmap, peinfo, CLI_PEHEADER_OPT_EXTRACT_VINFO, NULL);
4460 }
4461 
4462 /** Parse the PE header and, if successful, populate peinfo
4463  *
4464  * @param map The fmap_t backing the file being scanned
4465  * @param peinfo A structure to populate with info from the PE header. This
4466  *               MUST be initialized via cli_exe_info_init prior to calling
4467  * @param opts A bitfield indicating various options related to PE header
4468  *             parsing.  The options are (prefixed with CLI_PEHEADER_OPT_):
4469  *              - NONE - Do default parsing
4470  *              - COLLECT_JSON - Populate ctx's json obj with PE header
4471  *                               info
4472  *              - DBG_PRINT_INFO - Print debug information about the
4473  *                                 PE file. Right now, cli_peheader is
4474  *                                 called multiple times for a given PE,
4475  *                                 so you don't want to print out the
4476  *                                 same info each time.
4477  *              - EXTRACT_VINFO - Parse the PEs VERSION_INFO metadata
4478  *                                and store it in peinfo->vinfo
4479  *              - STRICT_ON_PE_ERRORS - If specified, some cases that
4480  *                                      might be considered a broken
4481  *                                      executable cause RET_BROKEN_PE
4482  *                                      to be returned, but otherwise
4483  *                                      these will be tolerated.
4484  *              - REMOVE_MISSING_SECTIONS - If a section exists outside of the
4485  *                                          file, remove it from
4486  *                                          peinfo->sections. Otherwise, the
4487  *                                          rsz is just set to 0 for it.
4488  * @param ctx The overaching cli_ctx.  This is required with certain opts, but
4489  *            optional otherwise.
4490  * @return If the PE header is parsed successfully, CLI_PEHEADER_RET_SUCCESS
4491  *         is returned. If it seems like the PE is broken,
4492  *         CLI_PEHEADER_RET_BROKEN_PE is returned.  Otherwise, one of the
4493  *         other error codes is returned.
4494  *         The caller MUST destroy peinfo, regardless of what this function
4495  *         returns.
4496  *
4497  * TODO What constitutes a "broken PE" seems somewhat arbitrary in places.
4498  * I think a PE should only be considered broken if it will not run on
4499  * any version of Windows.  We should invest more time to ensure that our
4500  * broken PE detection more closely aligns with this.
4501  *
4502  * TODO Simplify and get rid of CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS if
4503  * possible.  We should either fail always or ignore always, IMO.
4504  *
4505  * TODO Simplify and get rid of CLI_PEHEADER_OPT_REMOVE_MISSING_SECTIONS if
4506  * possible.  I don't think it makes sense to have pieces of the code work
4507  * off of incomplete representations of the sections (for instance, I wonder
4508  * if this makes any of the bytecode APIs return unexpected values).  This
4509  * appears to have been implemented to prevent ClamAV from crashing, though,
4510  * (bb11155) so we need to ensure the underlying issues are addressed.
4511  *
4512  * TODO Consolidate when information about the PE is printed (after successful
4513  * PE parsing).  This will allow us to simplify the code.  Some fail cases,
4514  * then, will cause PE info to not be printed at all, but I think this is
4515  * acceptable.  The debug messages generated in the fail cases should point to
4516  * what happened, and that's enough to track down the cause of any issues.
4517  *
4518  * TODO Same as above but with JSON creation
4519  */
4520 int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ctx *ctx)
4521 {
4522     uint16_t e_magic; /* DOS signature ("MZ") */
4523     const char *archtype = NULL, *subsystem = NULL;
4524     time_t timestamp;
4525     char timestr[32];
4526     uint32_t data_dirs_size;
4527     uint16_t opt_hdr_size;
4528     uint32_t stored_opt_hdr_size;
4529     struct pe_image_file_hdr *file_hdr;
4530     struct pe_image_optional_hdr32 *opt32;
4531     struct pe_image_optional_hdr64 *opt64;
4532     struct pe_image_section_hdr *section_hdrs = NULL;
4533     unsigned int i, j, section_pe_idx;
4534     unsigned int err;
4535     uint32_t salign, falign;
4536     size_t fsize;
4537     ssize_t at;
4538     uint32_t is_dll = 0;
4539     uint32_t is_exe = 0;
4540     int native      = 0;
4541     size_t read;
4542 
4543     int ret = CLI_PEHEADER_RET_GENERIC_ERROR;
4544 #if HAVE_JSON
4545     int toval                   = 0;
4546     struct json_object *pe_json = NULL;
4547     char jsonbuf[128];
4548 #endif
4549 
4550     if (ctx == NULL &&
4551         (opts & CLI_PEHEADER_OPT_COLLECT_JSON ||
4552          opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO)) {
4553         cli_errmsg("cli_peheader: ctx can't be NULL for options specified\n");
4554         goto done;
4555     }
4556 
4557 #if HAVE_JSON
4558     if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) {
4559         pe_json = get_pe_property(ctx);
4560     }
4561 #endif
4562 
4563     fsize = map->len - peinfo->offset;
4564     if (fmap_readn(map, &e_magic, peinfo->offset, sizeof(e_magic)) != sizeof(e_magic)) {
4565         cli_dbgmsg("cli_peheader: Can't read DOS signature\n");
4566         goto done;
4567     }
4568 
4569     if (EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE && EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE_OLD) {
4570         cli_dbgmsg("cli_peheader: Invalid DOS signature\n");
4571         goto done;
4572     }
4573 
4574     if (fmap_readn(map, &(peinfo->e_lfanew), peinfo->offset + 58 + sizeof(e_magic), sizeof(peinfo->e_lfanew)) != sizeof(peinfo->e_lfanew)) {
4575         /* truncated header? */
4576         cli_dbgmsg("cli_peheader: Unable to read e_lfanew - truncated header?\n");
4577         ret = CLI_PEHEADER_RET_BROKEN_PE;
4578         goto done;
4579     }
4580 
4581     peinfo->e_lfanew = EC32(peinfo->e_lfanew);
4582     if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) {
4583         cli_dbgmsg("e_lfanew == %d\n", peinfo->e_lfanew);
4584     }
4585     if (!peinfo->e_lfanew) {
4586         cli_dbgmsg("cli_peheader: Not a PE file - e_lfanew == 0\n");
4587         goto done;
4588     }
4589 
4590     if (fmap_readn(map, &(peinfo->file_hdr), peinfo->offset + peinfo->e_lfanew, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) {
4591         /* bad information in e_lfanew - probably not a PE file */
4592         cli_dbgmsg("cli_peheader: Can't read file header\n");
4593         goto done;
4594     }
4595 
4596     file_hdr = &(peinfo->file_hdr);
4597 
4598     if (EC32(file_hdr->Magic) != PE_IMAGE_NT_SIGNATURE) {
4599         cli_dbgmsg("cli_peheader: Invalid PE signature (probably NE file)\n");
4600         goto done;
4601     }
4602 
4603     if (EC16(file_hdr->Characteristics) & 0x2000) {
4604 
4605 #if HAVE_JSON
4606         if (opts & CLI_PEHEADER_OPT_COLLECT_JSON)
4607             cli_jsonstr(pe_json, "Type", "DLL");
4608 #endif
4609         if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) {
4610             cli_dbgmsg("File type: DLL\n");
4611         }
4612 
4613         is_dll = 1;
4614     } else if (EC16(file_hdr->Characteristics) & 0x0002) {
4615 
4616 #if HAVE_JSON
4617         if (opts & CLI_PEHEADER_OPT_COLLECT_JSON)
4618             cli_jsonstr(pe_json, "Type", "EXE");
4619 #endif
4620         if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) {
4621             cli_dbgmsg("File type: Executable\n");
4622         }
4623 
4624         is_exe = 1;
4625     }
4626 
4627     if (!is_dll && !is_exe) {
4628         cli_dbgmsg("cli_peheader: Assumption Violated: PE is not a DLL or EXE\n");
4629         // TODO Don't continue if not an exe or dll?
4630     }
4631 
4632     peinfo->is_dll = is_dll;
4633 
4634     if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO ||
4635         opts & CLI_PEHEADER_OPT_COLLECT_JSON) {
4636         switch (EC16(file_hdr->Machine)) {
4637             case 0x0:
4638                 archtype = "Unknown";
4639                 break;
4640             case 0x1:
4641                 // New as of Windows 10, version 1607 and Windows Server 2016
4642                 archtype = "Target Host";
4643                 break;
4644             case 0x14c:
4645                 archtype = "80386";
4646                 break;
4647             case 0x14d:
4648                 archtype = "80486";
4649                 break;
4650             case 0x14e:
4651                 archtype = "80586";
4652                 break;
4653             case 0x160:
4654                 archtype = "R3000 MIPS BE";
4655                 break;
4656             case 0x162:
4657                 archtype = "R3000 MIPS LE";
4658                 break;
4659             case 0x166:
4660                 archtype = "R4000 MIPS LE";
4661                 break;
4662             case 0x168:
4663                 archtype = "R10000 MIPS LE";
4664                 break;
4665             case 0x169:
4666                 archtype = "WCE MIPS LE";
4667                 break;
4668             case 0x184:
4669                 archtype = "DEC Alpha AXP";
4670                 break;
4671             case 0x1a2:
4672                 archtype = "Hitachi SH3 LE";
4673                 break;
4674             case 0x1a3:
4675                 archtype = "Hitachi SH3-DSP";
4676                 break;
4677             case 0x1a4:
4678                 archtype = "Hitachi SH3-E LE";
4679                 break;
4680             case 0x1a6:
4681                 archtype = "Hitachi SH4 LE";
4682                 break;
4683             case 0x1a8:
4684                 archtype = "Hitachi SH5";
4685                 break;
4686             case 0x1c0:
4687                 archtype = "ARM LE";
4688                 break;
4689             case 0x1c2:
4690                 archtype = "ARM Thumb/Thumb-2 LE";
4691                 break;
4692             case 0x1c4:
4693                 archtype = "ARM Thumb-2 LE";
4694                 break;
4695             case 0x1d3:
4696                 archtype = "AM33";
4697                 break;
4698             case 0x1f0:
4699                 archtype = "PowerPC LE";
4700                 break;
4701             case 0x1f1:
4702                 archtype = "PowerPC FP";
4703                 break;
4704             case 0x200:
4705                 archtype = "IA64";
4706                 break;
4707             case 0x266:
4708                 archtype = "MIPS16";
4709                 break;
4710             case 0x268:
4711                 archtype = "M68k";
4712                 break;
4713             case 0x284:
4714                 archtype = "DEC Alpha AXP 64bit";
4715                 break;
4716             case 0x366:
4717                 archtype = "MIPS+FPU";
4718                 break;
4719             case 0x466:
4720                 archtype = "MIPS16+FPU";
4721                 break;
4722             case 0x520:
4723                 archtype = "Infineon TriCore";
4724                 break;
4725             case 0xcef:
4726                 archtype = "CEF";
4727                 break;
4728             case 0xebc:
4729                 archtype = "EFI Byte Code";
4730                 break;
4731             case 0x8664:
4732                 archtype = "AMD64";
4733                 break;
4734             case 0x9041:
4735                 archtype = "M32R";
4736                 break;
4737             case 0xaa64:
4738                 archtype = "ARM64 LE";
4739                 break;
4740             case 0xc0ee:
4741                 archtype = "CEE";
4742                 break;
4743             default:
4744                 archtype = "Unknown";
4745         }
4746 
4747         if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO)
4748             cli_dbgmsg("Machine type: %s\n", archtype);
4749 
4750 #if HAVE_JSON
4751         if (opts & CLI_PEHEADER_OPT_COLLECT_JSON)
4752             cli_jsonstr(pe_json, "ArchType", archtype);
4753 #endif
4754     }
4755 
4756     peinfo->nsections = EC16(file_hdr->NumberOfSections);
4757     if (peinfo->nsections == 0 || peinfo->nsections > PE_MAXSECTIONS) {
4758 
4759 #if HAVE_JSON
4760         if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) {
4761             pe_add_heuristic_property(ctx, "BadNumberOfSections");
4762         }
4763 #endif
4764         // TODO Investigate how corrupted_input is set and whether this
4765         // check is needed
4766         if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO &&
4767             !ctx->corrupted_input) {
4768             if (peinfo->nsections == 0) {
4769                 cli_dbgmsg("cli_peheader: Invalid NumberOfSections (0)\n");
4770             } else {
4771                 cli_dbgmsg("cli_peheader: Invalid NumberOfSections (>%d)\n", PE_MAXSECTIONS);
4772             }
4773         }
4774         ret = CLI_PEHEADER_RET_BROKEN_PE;
4775         goto done;
4776     }
4777 
4778     timestamp    = (time_t)EC32(file_hdr->TimeDateStamp);
4779     opt_hdr_size = EC16(file_hdr->SizeOfOptionalHeader);
4780 
4781     if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) {
4782         cli_dbgmsg("NumberOfSections: %d\n", peinfo->nsections);
4783         cli_dbgmsg("TimeDateStamp: %s", cli_ctime(&timestamp, timestr, sizeof(timestr)));
4784         cli_dbgmsg("SizeOfOptionalHeader: 0x%x\n", opt_hdr_size);
4785     }
4786 
4787 #if HAVE_JSON
4788     if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) {
4789         cli_jsonint(pe_json, "NumberOfSections", peinfo->nsections);
4790         /* NOTE: the TimeDateStamp value will look like "Wed Dec 31 19:00:00 1969\n" */
4791         cli_jsonstr(pe_json, "TimeDateStamp", cli_ctime(&timestamp, timestr, sizeof(timestr)));
4792         cli_jsonint(pe_json, "SizeOfOptionalHeader", opt_hdr_size);
4793     }
4794 #endif
4795 
4796     // Ensure there are enough bytes to cover the full optional header,
4797     // not including the data directory entries (which aren't all gauranteed
4798     // to be there)
4799     if (opt_hdr_size < sizeof(struct pe_image_optional_hdr32)) {
4800         cli_dbgmsg("cli_peheader: SizeOfOptionalHeader too small\n");
4801 
4802 #if HAVE_JSON
4803         if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) {
4804             pe_add_heuristic_property(ctx, "BadOptionalHeaderSize");
4805         }
4806 #endif
4807         ret = CLI_PEHEADER_RET_BROKEN_PE;
4808         goto done;
4809     }
4810 
4811     at = peinfo->offset + peinfo->e_lfanew + sizeof(struct pe_image_file_hdr);
4812     if (fmap_readn(map, &(peinfo->pe_opt.opt32), at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) {
4813         cli_dbgmsg("cli_peheader: Can't read optional file header\n");
4814         ret = CLI_PEHEADER_RET_BROKEN_PE;
4815         goto done;
4816     }
4817     stored_opt_hdr_size = sizeof(struct pe_image_optional_hdr32);
4818     at += stored_opt_hdr_size;
4819 
4820     opt32 = &(peinfo->pe_opt.opt32);
4821 
4822     if (EC16(opt32->Magic) == PE32P_SIGNATURE) { /* PE+ */
4823         // The PE32+ optional header is bigger by 16 bytes, so map in the
4824         // additional bytes here
4825 
4826         if (opt_hdr_size < sizeof(struct pe_image_optional_hdr64)) {
4827             cli_dbgmsg("cli_peheader: Incorrect SizeOfOptionalHeader for PE32+\n");
4828 #if HAVE_JSON
4829             if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) {
4830                 pe_add_heuristic_property(ctx, "BadOptionalHeaderSizePE32Plus");
4831             }
4832 #endif
4833             ret = CLI_PEHEADER_RET_BROKEN_PE;
4834             goto done;
4835         }
4836 
4837         if (fmap_readn(map, (void *)(((size_t) & (peinfo->pe_opt.opt64)) + sizeof(struct pe_image_optional_hdr32)), at, OPT_HDR_SIZE_DIFF) != OPT_HDR_SIZE_DIFF) {
4838             cli_dbgmsg("cli_peheader: Can't read additional optional file header bytes\n");
4839             ret = CLI_PEHEADER_RET_BROKEN_PE;
4840             goto done;
4841         }
4842 
4843         stored_opt_hdr_size += OPT_HDR_SIZE_DIFF;
4844         at += OPT_HDR_SIZE_DIFF;
4845         peinfo->is_pe32plus = 1;
4846 
4847         opt64 = &(peinfo->pe_opt.opt64);
4848 
4849         peinfo->vep       = EC32(opt64->AddressOfEntryPoint);
4850         peinfo->hdr_size  = EC32(opt64->SizeOfHeaders);
4851         peinfo->ndatadirs = EC32(opt64->NumberOfRvaAndSizes);
4852 
4853         if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) {
4854             cli_dbgmsg("File format: PE32+\n");
4855             cli_dbgmsg("MajorLinkerVersion: %d\n", opt64->MajorLinkerVersion);
4856             cli_dbgmsg("MinorLinkerVersion: %d\n", opt64->MinorLinkerVersion);
4857             cli_dbgmsg("SizeOfCode: 0x%x\n", EC32(opt64->SizeOfCode));
4858             cli_dbgmsg("SizeOfInitializedData: 0x%x\n", EC32(opt64->SizeOfInitializedData));
4859             cli_dbgmsg("SizeOfUninitializedData: 0x%x\n", EC32(opt64->SizeOfUninitializedData));
4860             cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", peinfo->vep);
4861             cli_dbgmsg("BaseOfCode: 0x%x\n", EC32(opt64->BaseOfCode));
4862             cli_dbgmsg("SectionAlignment: 0x%x\n", EC32(opt64->SectionAlignment));
4863             cli_dbgmsg("FileAlignment: 0x%x\n", EC32(opt64->FileAlignment));
4864             cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(opt64->MajorSubsystemVersion));
4865             cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(opt64->MinorSubsystemVersion));
4866             cli_dbgmsg("SizeOfImage: 0x%x\n", EC32(opt64->SizeOfImage));
4867             cli_dbgmsg("SizeOfHeaders: 0x%x\n", peinfo->hdr_size);
4868             cli_dbgmsg("NumberOfRvaAndSizes: %u\n", peinfo->ndatadirs);
4869         }
4870 
4871 #if HAVE_JSON
4872         if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) {
4873             cli_jsonint(pe_json, "MajorLinkerVersion", opt64->MajorLinkerVersion);
4874             cli_jsonint(pe_json, "MinorLinkerVersion", opt64->MinorLinkerVersion);
4875             cli_jsonint(pe_json, "SizeOfCode", EC32(opt64->SizeOfCode));
4876             cli_jsonint(pe_json, "SizeOfInitializedData", EC32(opt64->SizeOfInitializedData));
4877             cli_jsonint(pe_json, "SizeOfUninitializedData", EC32(opt64->SizeOfUninitializedData));
4878             cli_jsonint(pe_json, "NumberOfRvaAndSizes", EC32(opt64->NumberOfRvaAndSizes));
4879             cli_jsonint(pe_json, "MajorSubsystemVersion", EC16(opt64->MajorSubsystemVersion));
4880             cli_jsonint(pe_json, "MinorSubsystemVersion", EC16(opt64->MinorSubsystemVersion));
4881 
4882             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", peinfo->vep);
4883             cli_jsonstr(pe_json, "EntryPoint", jsonbuf);
4884 
4885             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(opt64->BaseOfCode));
4886             cli_jsonstr(pe_json, "BaseOfCode", jsonbuf);
4887 
4888             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(opt64->SectionAlignment));
4889             cli_jsonstr(pe_json, "SectionAlignment", jsonbuf);
4890 
4891             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(opt64->FileAlignment));
4892             cli_jsonstr(pe_json, "FileAlignment", jsonbuf);
4893 
4894             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(opt64->SizeOfImage));
4895             cli_jsonstr(pe_json, "SizeOfImage", jsonbuf);
4896 
4897             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", peinfo->hdr_size);
4898             cli_jsonstr(pe_json, "SizeOfHeaders", jsonbuf);
4899         }
4900 #endif
4901 
4902     } else { /* PE */
4903         peinfo->is_pe32plus = 0;
4904         peinfo->vep         = EC32(opt32->AddressOfEntryPoint);
4905         peinfo->hdr_size    = EC32(opt32->SizeOfHeaders);
4906         peinfo->ndatadirs   = EC32(opt32->NumberOfRvaAndSizes);
4907 
4908         if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) {
4909             cli_dbgmsg("File format: PE\n");
4910             cli_dbgmsg("MajorLinkerVersion: %d\n", opt32->MajorLinkerVersion);
4911             cli_dbgmsg("MinorLinkerVersion: %d\n", opt32->MinorLinkerVersion);
4912             cli_dbgmsg("SizeOfCode: 0x%x\n", EC32(opt32->SizeOfCode));
4913             cli_dbgmsg("SizeOfInitializedData: 0x%x\n", EC32(opt32->SizeOfInitializedData));
4914             cli_dbgmsg("SizeOfUninitializedData: 0x%x\n", EC32(opt32->SizeOfUninitializedData));
4915             cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", peinfo->vep);
4916             cli_dbgmsg("BaseOfCode: 0x%x\n", EC32(opt32->BaseOfCode));
4917             cli_dbgmsg("SectionAlignment: 0x%x\n", EC32(opt32->SectionAlignment));
4918             cli_dbgmsg("FileAlignment: 0x%x\n", EC32(opt32->FileAlignment));
4919             cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(opt32->MajorSubsystemVersion));
4920             cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(opt32->MinorSubsystemVersion));
4921             cli_dbgmsg("SizeOfImage: 0x%x\n", EC32(opt32->SizeOfImage));
4922             cli_dbgmsg("SizeOfHeaders: 0x%x\n", peinfo->hdr_size);
4923             cli_dbgmsg("NumberOfRvaAndSizes: %u\n", peinfo->ndatadirs);
4924         }
4925 
4926 #if HAVE_JSON
4927         if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) {
4928             cli_jsonint(pe_json, "MajorLinkerVersion", opt32->MajorLinkerVersion);
4929             cli_jsonint(pe_json, "MinorLinkerVersion", opt32->MinorLinkerVersion);
4930             cli_jsonint(pe_json, "SizeOfCode", EC32(opt32->SizeOfCode));
4931             cli_jsonint(pe_json, "SizeOfInitializedData", EC32(opt32->SizeOfInitializedData));
4932             cli_jsonint(pe_json, "SizeOfUninitializedData", EC32(opt32->SizeOfUninitializedData));
4933             cli_jsonint(pe_json, "NumberOfRvaAndSizes", EC32(opt32->NumberOfRvaAndSizes));
4934             cli_jsonint(pe_json, "MajorSubsystemVersion", EC16(opt32->MajorSubsystemVersion));
4935             cli_jsonint(pe_json, "MinorSubsystemVersion", EC16(opt32->MinorSubsystemVersion));
4936 
4937             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", peinfo->vep);
4938             cli_jsonstr(pe_json, "EntryPoint", jsonbuf);
4939 
4940             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(opt32->BaseOfCode));
4941             cli_jsonstr(pe_json, "BaseOfCode", jsonbuf);
4942 
4943             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(opt32->SectionAlignment));
4944             cli_jsonstr(pe_json, "SectionAlignment", jsonbuf);
4945 
4946             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(opt32->FileAlignment));
4947             cli_jsonstr(pe_json, "FileAlignment", jsonbuf);
4948 
4949             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(opt32->SizeOfImage));
4950             cli_jsonstr(pe_json, "SizeOfImage", jsonbuf);
4951 
4952             snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", peinfo->hdr_size);
4953             cli_jsonstr(pe_json, "SizeOfHeaders", jsonbuf);
4954         }
4955 #endif
4956     }
4957 
4958     salign = (peinfo->is_pe32plus) ? EC32(opt64->SectionAlignment) : EC32(opt32->SectionAlignment);
4959     falign = (peinfo->is_pe32plus) ? EC32(opt64->FileAlignment) : EC32(opt32->FileAlignment);
4960 
4961     switch (peinfo->is_pe32plus ? EC16(opt64->Subsystem) : EC16(opt32->Subsystem)) {
4962         case 0:
4963             subsystem = "Unknown";
4964             break;
4965         case 1:
4966             subsystem = "Native (svc)";
4967             native    = 1;
4968             break;
4969         case 2:
4970             subsystem = "Win32 GUI";
4971             break;
4972         case 3:
4973             subsystem = "Win32 console";
4974             break;
4975         case 5:
4976             subsystem = "OS/2 console";
4977             break;
4978         case 7:
4979             subsystem = "POSIX console";
4980             break;
4981         case 8:
4982             subsystem = "Native Win9x driver";
4983             break;
4984         case 9:
4985             subsystem = "WinCE GUI";
4986             break;
4987         case 10:
4988             subsystem = "EFI application";
4989             break;
4990         case 11:
4991             subsystem = "EFI driver";
4992             break;
4993         case 12:
4994             subsystem = "EFI runtime driver";
4995             break;
4996         case 13:
4997             subsystem = "EFI ROM image";
4998             break;
4999         case 14:
5000             subsystem = "Xbox";
5001             break;
5002         case 16:
5003             subsystem = "Boot application";
5004             break;
5005         default:
5006             subsystem = "Unknown";
5007     }
5008 
5009     if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) {
5010         cli_dbgmsg("Subsystem: %s\n", subsystem);
5011         cli_dbgmsg("------------------------------------\n");
5012     }
5013 
5014 #if HAVE_JSON
5015     if (opts & CLI_PEHEADER_OPT_COLLECT_JSON)
5016         cli_jsonstr(pe_json, "Subsystem", subsystem);
5017 #endif
5018 
5019     if (!native && (!salign || (salign % 0x1000))) {
5020         cli_dbgmsg("cli_peheader: Bad section alignment\n");
5021         if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) {
5022             ret = CLI_PEHEADER_RET_BROKEN_PE;
5023             goto done;
5024         }
5025     }
5026 
5027     if (!native && (!falign || (falign % 0x200))) {
5028         cli_dbgmsg("cli_peheader: Bad file alignment\n");
5029         if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) {
5030             ret = CLI_PEHEADER_RET_BROKEN_PE;
5031             goto done;
5032         }
5033     }
5034 
5035     // Map in the optional header data directories.  The spec defines 16
5036     // directory entries, but NumberOfRvaAndSizes can be less than that
5037     // and the Windows loader will pretend that the data directory does
5038     // not exist. NumberOfRvaAndSizes can be larger than that too, which
5039     // the Windows loader is OK with.  To populate peinfo->dirs, we will
5040     // copy in as many data dirs are specified but for a max of 16 (and
5041     // adjust peinfo->ndatadirs accordingly)
5042 
5043     if (peinfo->ndatadirs > 0x10) {
5044         cli_dbgmsg("cli_peheader: Encountered NumberOfRvaAndSizes > 16 (suspicious)\n");
5045     }
5046 
5047     // In the case where we won't fully populate dirs with file data,
5048     // ensure that the underlying memory is zero so that existing code
5049     // can interact with peinfo->dirs without using peinfo->ndatadirs
5050     if (peinfo->ndatadirs < sizeof(peinfo->dirs) / sizeof(peinfo->dirs[0])) {
5051         memset(&(peinfo->dirs), '\0', sizeof(peinfo->dirs));
5052     }
5053 
5054     peinfo->ndatadirs = MIN(peinfo->ndatadirs, sizeof(peinfo->dirs) / sizeof(peinfo->dirs[0]));
5055 
5056     data_dirs_size = sizeof(struct pe_image_data_dir) * peinfo->ndatadirs;
5057 
5058     if (opt_hdr_size < (stored_opt_hdr_size + data_dirs_size)) {
5059         cli_dbgmsg("cli_peheader: SizeOfOptionalHeader too small (doesn't include data dir size)\n");
5060         ret = CLI_PEHEADER_RET_BROKEN_PE;
5061         goto done;
5062     }
5063 
5064     read = fmap_readn(map, peinfo->dirs, at, data_dirs_size);
5065     if ((read == (size_t)-1) || (read != data_dirs_size)) {
5066         cli_dbgmsg("cli_peheader: Can't read optional file header data dirs\n");
5067         goto done;
5068     }
5069     at += data_dirs_size;
5070 
5071     if (opt_hdr_size != (stored_opt_hdr_size + data_dirs_size)) {
5072         /* Seek to the end of the long header */
5073         cli_dbgmsg("cli_peheader: Encountered case where SizeOfOptionalHeader appears bigger than required\n");
5074         at += opt_hdr_size - (stored_opt_hdr_size + data_dirs_size);
5075     }
5076 
5077     // TODO This level of processing might not be needed in all cases
5078 
5079     // Sanity checks
5080     // TODO Also check that salign >= falign
5081     if (peinfo->hdr_size != PESALIGN(peinfo->hdr_size, salign)) {
5082         cli_dbgmsg("cli_peheader: SizeOfHeader is not aligned to the SectionAlignment\n");
5083     }
5084     if (peinfo->hdr_size != PESALIGN(peinfo->hdr_size, falign)) {
5085         cli_dbgmsg("cli_peheader: SizeOfHeader is not aligned to the FileAlignment\n");
5086     }
5087 
5088     // TODO Why align here? -- /* Aligned headers virtual size */
5089     // hdr_size should already be rounded up
5090     // to a multiple of the file alignment.
5091     // TODO in cli_checkpe_fp this aligned to falign, elsewhere it aligned to salign
5092     peinfo->hdr_size = PESALIGN(peinfo->hdr_size, salign);
5093 
5094     peinfo->sections = (struct cli_exe_section *)cli_calloc(peinfo->nsections, sizeof(struct cli_exe_section));
5095 
5096     if (!peinfo->sections) {
5097         cli_dbgmsg("cli_peheader: Can't allocate memory for section headers\n");
5098         goto done;
5099     }
5100 
5101     section_hdrs = (struct pe_image_section_hdr *)cli_calloc(peinfo->nsections, sizeof(struct pe_image_section_hdr));
5102 
5103     if (!section_hdrs) {
5104         cli_dbgmsg("cli_peheader: Can't allocate memory for section headers\n");
5105         goto done;
5106     }
5107 
5108     read = fmap_readn(map, section_hdrs, at, peinfo->nsections * sizeof(struct pe_image_section_hdr));
5109     if ((read == (size_t)-1) || (read != peinfo->nsections * sizeof(struct pe_image_section_hdr))) {
5110         cli_dbgmsg("cli_peheader: Can't read section header - possibly broken PE file\n");
5111         ret = CLI_PEHEADER_RET_BROKEN_PE;
5112         goto done;
5113     }
5114     at += sizeof(struct pe_image_section_hdr) * peinfo->nsections;
5115 
5116     // TODO Verify that this performs correctly
5117     // TODO I'm not sure why this is necessary since the specification says
5118     // that PointerToRawData is expected to be a multiple of the file
5119     // alignment.  Should we report this is as a PE with an error?
5120 
5121     for (i = 0; falign != 0x200 && i < peinfo->nsections; i++) {
5122         /* file alignment fallback mode - blah */
5123         if (falign && section_hdrs[i].SizeOfRawData && EC32(section_hdrs[i].PointerToRawData) % falign && !(EC32(section_hdrs[i].PointerToRawData) % 0x200)) {
5124             cli_dbgmsg("cli_peheader: Encountered section with unexpected alignment - triggering fallback mode\n");
5125             falign = 0x200;
5126         }
5127     }
5128 
5129     fsize = (map->len - peinfo->offset);
5130 
5131     // TODO Why do we fix up these alignments?  This shouldn't be needed?
5132     for (i = 0, section_pe_idx = 0; i < peinfo->nsections; i++, section_pe_idx++) {
5133 
5134         struct cli_exe_section *section          = &(peinfo->sections[i]);
5135         struct pe_image_section_hdr *section_hdr = &(section_hdrs[i]);
5136         char sname[9];
5137 
5138         // TODO I don't see any documentation that says VirtualAddress and VirtualSize must be aligned
5139         section->rva  = PEALIGN(EC32(section_hdr->VirtualAddress), salign);
5140         section->vsz  = PESALIGN(EC32(section_hdr->VirtualSize), salign);
5141         section->raw  = PEALIGN(EC32(section_hdr->PointerToRawData), falign);
5142         section->rsz  = PESALIGN(EC32(section_hdr->SizeOfRawData), falign);
5143         section->chr  = EC32(section_hdr->Characteristics);
5144         section->urva = EC32(section_hdr->VirtualAddress); /* Just in case */
5145         section->uvsz = EC32(section_hdr->VirtualSize);
5146         section->uraw = EC32(section_hdr->PointerToRawData);
5147         section->ursz = EC32(section_hdr->SizeOfRawData);
5148 
5149         /* First, if a section exists totally outside of a file, remove the
5150          * section from the list or zero out it's size. */
5151         if (section->rsz) { /* Don't bother with virtual only sections */
5152             if (section->raw >= fsize || section->uraw >= fsize) {
5153                 cli_dbgmsg("cli_peheader: Broken PE file - Section %d starts or exists beyond the end of file (Offset@ %lu, Total filesize %lu)\n", section_pe_idx, (unsigned long)section->raw, (unsigned long)fsize);
5154 
5155                 if (opts & CLI_PEHEADER_OPT_REMOVE_MISSING_SECTIONS) {
5156                     if (peinfo->nsections == 1) {
5157                         ret = CLI_PEHEADER_RET_BROKEN_PE;
5158                         goto done;
5159                     }
5160 
5161                     for (j = i; j < peinfo->nsections - 1; j++)
5162                         memcpy(&(peinfo->sections[j]), &(peinfo->sections[j + 1]), sizeof(struct cli_exe_section));
5163 
5164                     for (j = i; j < peinfo->nsections - 1; j++)
5165                         memcpy(&section_hdrs[j], &section_hdrs[j + 1], sizeof(struct pe_image_section_hdr));
5166 
5167                     peinfo->nsections--;
5168 
5169                     // Adjust i since we removed a section and continue on
5170                     i--;
5171                     continue;
5172 
5173                 } else {
5174                     section->rsz  = 0;
5175                     section->ursz = 0;
5176                 }
5177             } else {
5178 
5179                 /* If a section is truncated, adjust it's size value */
5180                 if (!CLI_ISCONTAINED_0_TO(fsize, section->raw, section->rsz)) {
5181                     cli_dbgmsg("cli_peheader: PE Section %d raw+rsz extends past the end of the file by %lu bytes\n", section_pe_idx, (section->raw + section->rsz) - fsize);
5182                     section->rsz = fsize - section->raw;
5183                 }
5184 
5185                 if (!CLI_ISCONTAINED_0_TO(fsize, section->uraw, section->ursz)) {
5186                     cli_dbgmsg("cli_peheader: PE Section %d uraw+ursz extends past the end of the file by %lu bytes\n", section_pe_idx, (section->uraw + section->ursz) - fsize);
5187                     section->ursz = fsize - section->uraw;
5188                 }
5189             }
5190         }
5191 
5192         strncpy(sname, (char *)section_hdr->Name, 8);
5193         sname[8] = '\0';
5194 
5195 #if HAVE_JSON
5196         if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) {
5197             add_section_info(ctx, &peinfo->sections[i]);
5198 
5199             if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) {
5200                 ret = CLI_PEHEADER_RET_JSON_TIMEOUT;
5201                 goto done;
5202             }
5203         }
5204 #endif
5205 
5206         // TODO Why do we do this
5207         // TODO Should this be done before we dump the json
5208         if (!section->vsz && section->rsz)
5209             section->vsz = PESALIGN(section->ursz, salign);
5210 
5211         if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) {
5212             cli_dbgmsg("Section %d\n", section_pe_idx);
5213             cli_dbgmsg("Section name: %s\n", sname);
5214             cli_dbgmsg("Section data (from headers - in memory)\n");
5215             cli_dbgmsg("VirtualSize: 0x%x 0x%x\n", section->uvsz, section->vsz);
5216             cli_dbgmsg("VirtualAddress: 0x%x 0x%x\n", section->urva, section->rva);
5217             cli_dbgmsg("SizeOfRawData: 0x%x 0x%x\n", section->ursz, section->rsz);
5218             cli_dbgmsg("PointerToRawData: 0x%x 0x%x\n", section->uraw, section->raw);
5219 
5220             if (section->chr & 0x20) {
5221                 cli_dbgmsg("Section contains executable code\n");
5222             }
5223 
5224             if (section->vsz < section->rsz) {
5225                 cli_dbgmsg("Section contains free space\n");
5226                 /*
5227                 cli_dbgmsg("Dumping %d bytes\n", section_hdr.SizeOfRawData - section_hdr.VirtualSize);
5228                 ddump(desc, section_hdr.PointerToRawData + section_hdr.VirtualSize, section_hdr.SizeOfRawData - section_hdr.VirtualSize, cli_gentemp(NULL));
5229                 */
5230             }
5231 
5232             if (section->chr & 0x20000000)
5233                 cli_dbgmsg("Section's memory is executable\n");
5234 
5235             if (section->chr & 0x80000000)
5236                 cli_dbgmsg("Section's memory is writeable\n");
5237 
5238             cli_dbgmsg("------------------------------------\n");
5239         }
5240 
5241         if (!salign || (section->urva % salign)) { /* Bad section alignment */
5242             cli_dbgmsg("cli_peheader: Broken PE - section's VirtualAddress is misaligned\n");
5243             if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) {
5244                 ret = CLI_PEHEADER_RET_BROKEN_PE;
5245                 goto done;
5246             }
5247         }
5248 
5249         // TODO should we skip all of these checks if it's an empty
5250         // section? Why the exception for uraw?
5251         if (section->urva >> 31 || section->uvsz >> 31 || (section->rsz && section->uraw >> 31) || peinfo->sections[i].ursz >> 31) {
5252             cli_dbgmsg("cli_peheader: Found PE values with sign bit set\n");
5253             ret = CLI_PEHEADER_RET_BROKEN_PE;
5254             goto done;
5255         }
5256 
5257         if (!i) {
5258             if (section->urva != peinfo->hdr_size) { /* Bad first section RVA */
5259                 cli_dbgmsg("cli_peheader: First section doesn't start immediately after the header\n");
5260                 if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) {
5261                     ret = CLI_PEHEADER_RET_BROKEN_PE;
5262                     goto done;
5263                 }
5264             }
5265 
5266             peinfo->min = section->rva;
5267             peinfo->max = section->rva + section->rsz;
5268         } else {
5269             if (section->urva - peinfo->sections[i - 1].urva != peinfo->sections[i - 1].vsz) { /* No holes, no overlapping, no virtual disorder */
5270                 cli_dbgmsg("cli_peheader: Virtually misplaced section (wrong order, overlapping, non contiguous)\n");
5271                 if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) {
5272                     ret = CLI_PEHEADER_RET_BROKEN_PE;
5273                     goto done;
5274                 }
5275             }
5276 
5277             if (section->rva < peinfo->min)
5278                 peinfo->min = section->rva;
5279 
5280             if (section->rva + section->rsz > peinfo->max) {
5281                 peinfo->max           = section->rva + section->rsz;
5282                 peinfo->overlay_start = section->raw + section->rsz;
5283             }
5284 
5285             // TODO This case might be possible, which would lead to us
5286             // mislabelling the overlay
5287             if (section->raw + section->rsz > peinfo->max) {
5288                 cli_dbgmsg("cli_peheader: Assumption Violated: Last section end RVA isn't tied to the last section\n");
5289             }
5290         }
5291     }
5292 
5293     peinfo->overlay_size = fsize - peinfo->overlay_start;
5294 
5295     // NOTE: For DLLs the entrypoint is likely to be zero
5296     // TODO Should this offset include peinfo->offset?
5297     if (!(peinfo->ep = cli_rawaddr(peinfo->vep, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size)) && err) {
5298         cli_dbgmsg("cli_peheader: Broken PE file - Can't map EntryPoint to a file offset\n");
5299         ret = CLI_PEHEADER_RET_BROKEN_PE;
5300         goto done;
5301     }
5302 
5303 #if HAVE_JSON
5304     if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) {
5305         cli_jsonint(pe_json, "EntryPointOffset", peinfo->ep);
5306 
5307         if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) {
5308             ret = CLI_PEHEADER_RET_JSON_TIMEOUT;
5309             goto done;
5310         }
5311     }
5312 #endif
5313 
5314     if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) {
5315         cli_dbgmsg("EntryPoint offset: 0x%x (%d)\n", peinfo->ep, peinfo->ep);
5316     }
5317 
5318     if (is_dll || peinfo->ndatadirs < 3 || !peinfo->dirs[2].Size)
5319         peinfo->res_addr = 0;
5320     else
5321         peinfo->res_addr = EC32(peinfo->dirs[2].VirtualAddress);
5322 
5323     while (opts & CLI_PEHEADER_OPT_EXTRACT_VINFO &&
5324            peinfo->ndatadirs >= 3 && peinfo->dirs[2].Size) {
5325         struct vinfo_list vlist;
5326         const uint8_t *vptr, *baseptr;
5327         uint32_t rva, res_sz;
5328 
5329         // TODO This code assumes peinfo->offset == 0, which might not always
5330         // be the case.
5331         if (0 != peinfo->offset) {
5332             cli_dbgmsg("cli_peheader: Assumption Violated: Looking for version info when peinfo->offset != 0\n");
5333         }
5334 
5335         memset(&vlist, 0, sizeof(vlist));
5336         findres(0x10, 0xffffffff, map, peinfo, versioninfo_cb, &vlist);
5337         if (!vlist.count)
5338             break; /* No version_information */
5339 
5340         if (cli_hashset_init(&peinfo->vinfo, 32, 80)) {
5341             cli_errmsg("cli_peheader: Unable to init vinfo hashset\n");
5342             goto done;
5343         }
5344 
5345         err = 0;
5346         for (i = 0; i < vlist.count; i++) { /* enum all version_information res - RESUMABLE */
5347             cli_dbgmsg("cli_peheader: parsing version info @ rva %x (%u/%u)\n", vlist.rvas[i], i + 1, vlist.count);
5348             rva = cli_rawaddr(vlist.rvas[i], peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size);
5349             if (err)
5350                 continue;
5351 
5352             if (!(vptr = fmap_need_off_once(map, rva, 16)))
5353                 continue;
5354 
5355             baseptr = vptr - rva;
5356             /* parse resource */
5357             rva    = cli_readint32(vptr);     /* ptr to version_info */
5358             res_sz = cli_readint32(vptr + 4); /* sizeof(resource) */
5359             rva    = cli_rawaddr(rva, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size);
5360             if (err)
5361                 continue;
5362             if (!(vptr = fmap_need_off_once(map, rva, res_sz)))
5363                 continue;
5364 
5365             while (res_sz > 4) { /* look for version_info - NOT RESUMABLE (expecting exactly one versioninfo) */
5366                 uint32_t vinfo_sz, vinfo_val_sz, got_varfileinfo = 0;
5367 
5368                 vinfo_sz = vinfo_val_sz = cli_readint32(vptr);
5369                 vinfo_sz &= 0xffff;
5370                 if (vinfo_sz > res_sz)
5371                     break; /* the content is larger than the container */
5372 
5373                 vinfo_val_sz >>= 16;
5374                 if (vinfo_sz <= 6 + 0x20 + 2 + 0x34 ||
5375                     vinfo_val_sz != 0x34 ||
5376                     memcmp(vptr + 6, "V\0S\0_\0V\0E\0R\0S\0I\0O\0N\0_\0I\0N\0F\0O\0\0\0", 0x20) ||
5377                     (unsigned int)cli_readint32(vptr + 0x28) != 0xfeef04bd) {
5378                     /* - there should be enough room for the header(6), the key "VS_VERSION_INFO"(20), the padding(2) and the value(34)
5379                      * - the value should be sizeof(fixedfileinfo)
5380                      * - the key should match
5381                      * - there should be some proper magic for fixedfileinfo */
5382                     break; /* there's no point in looking further */
5383                 }
5384 
5385                 /* move to the end of fixedfileinfo where the child elements are located */
5386                 vptr += 6 + 0x20 + 2 + 0x34;
5387                 vinfo_sz -= 6 + 0x20 + 2 + 0x34;
5388 
5389                 while (vinfo_sz > 6) { /* look for stringfileinfo - NOT RESUMABLE (expecting at most one stringfileinfo) */
5390                     uint32_t sfi_sz = cli_readint32(vptr) & 0xffff;
5391 
5392                     if (sfi_sz > vinfo_sz)
5393                         break; /* the content is larger than the container */
5394 
5395                     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)) {
5396                         /* skip varfileinfo as it sometimes appear before stringtableinfo */
5397                         vptr += sfi_sz;
5398                         vinfo_sz -= sfi_sz;
5399                         got_varfileinfo = 1;
5400                         continue;
5401                     }
5402 
5403                     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)) {
5404                         /* - there should be enough room for the header(6) and the key "StringFileInfo"(1e)
5405                          * - the key should match */
5406                         break; /* this is an implicit hard fail: parent is not resumable */
5407                     }
5408 
5409                     /* move to the end of stringfileinfo where the child elements are located */
5410                     vptr += 6 + 0x1e;
5411                     sfi_sz -= 6 + 0x1e;
5412 
5413                     while (sfi_sz > 6) { /* enum all stringtables - RESUMABLE */
5414                         uint32_t st_sz           = cli_readint32(vptr) & 0xffff;
5415                         const uint8_t *next_vptr = vptr + st_sz;
5416                         uint32_t next_sfi_sz     = sfi_sz - st_sz;
5417 
5418                         if (st_sz > sfi_sz || st_sz <= 24) {
5419                             /* - the content is larger than the container
5420                                - there's no room for a stringtables (headers(6) + key(16) + padding(2)) */
5421                             break; /* this is an implicit hard fail: parent is not resumable */
5422                         }
5423 
5424                         /* move to the end of stringtable where the child elements are located */
5425                         vptr += 24;
5426                         st_sz -= 24;
5427 
5428                         while (st_sz > 6) { /* enum all strings - RESUMABLE */
5429                             uint32_t s_sz, s_key_sz, s_val_sz;
5430 
5431                             s_sz = (cli_readint32(vptr) & 0xffff) + 3;
5432                             s_sz &= ~3;
5433                             if (s_sz > st_sz || s_sz <= 6 + 2 + 8) {
5434                                 /* - the content is larger than the container
5435                                  * - there's no room for a minimal string
5436                                  * - there's no room for the value */
5437                                 st_sz  = 0;
5438                                 sfi_sz = 0;
5439                                 break; /* force a hard fail */
5440                             }
5441 
5442                             /* ~wcstrlen(key) */
5443                             for (s_key_sz = 6; s_key_sz + 1 < s_sz; s_key_sz += 2) {
5444                                 if (vptr[s_key_sz] || vptr[s_key_sz + 1])
5445                                     continue;
5446 
5447                                 s_key_sz += 2;
5448                                 break;
5449                             }
5450 
5451                             s_key_sz += 3;
5452                             s_key_sz &= ~3;
5453 
5454                             if (s_key_sz >= s_sz) {
5455                                 /* key overflow */
5456                                 vptr += s_sz;
5457                                 st_sz -= s_sz;
5458                                 continue;
5459                             }
5460 
5461                             s_val_sz = s_sz - s_key_sz;
5462                             s_key_sz -= 6;
5463 
5464                             if (s_val_sz <= 2) {
5465                                 /* skip unset value */
5466                                 vptr += s_sz;
5467                                 st_sz -= s_sz;
5468                                 continue;
5469                             }
5470 
5471                             if (cli_hashset_addkey(&peinfo->vinfo, (uint32_t)(vptr - baseptr + 6))) {
5472                                 cli_errmsg("cli_peheader: Unable to add rva to vinfo hashset\n");
5473                                 goto done;
5474                             }
5475 
5476                             if (cli_debug_flag) {
5477                                 char *k, *v, *s;
5478 
5479                                 /* FIXME: skip too long strings */
5480                                 k = cli_utf16toascii((const char *)vptr + 6, s_key_sz);
5481                                 if (k) {
5482                                     v = cli_utf16toascii((const char *)vptr + s_key_sz + 6, s_val_sz);
5483                                     if (v) {
5484                                         s = cli_str2hex((const char *)vptr + 6, s_key_sz + s_val_sz);
5485                                         if (s) {
5486                                             cli_dbgmsg("VersionInfo (%x): '%s'='%s' - VI:%s\n", (uint32_t)(vptr - baseptr + 6), k, v, s);
5487                                             free(s);
5488                                         }
5489                                         free(v);
5490                                     }
5491                                     free(k);
5492                                 }
5493                             }
5494                             vptr += s_sz;
5495                             st_sz -= s_sz;
5496                         } /* enum all strings - RESUMABLE */
5497                         vptr   = next_vptr;
5498                         sfi_sz = next_sfi_sz * (sfi_sz != 0);
5499                     } /* enum all stringtables - RESUMABLE */
5500                     break;
5501                 } /* look for stringfileinfo - NOT RESUMABLE */
5502                 break;
5503             } /* look for version_info - NOT RESUMABLE */
5504         }     /* enum all version_information res - RESUMABLE */
5505         break;
5506     } /* while(dirs[2].Size) */
5507 
5508     // Do final preperations for peinfo to be passed back
5509     peinfo->is_dll = is_dll;
5510 
5511     ret = CLI_PEHEADER_RET_SUCCESS;
5512 
5513 done:
5514     /* In the fail case, peinfo will get destroyed by the caller */
5515 
5516     if (NULL != section_hdrs) {
5517         free(section_hdrs);
5518     }
5519 
5520     return ret;
5521 }
5522 
5523 // TODO We should sort based on VirtualAddress instead, since PointerToRawData
5524 // will be zero for sections where SizeOfRawData is zero.  This also aligns
5525 // with what tools like pefile do.
5526 static int sort_sects(const void *first, const void *second)
5527 {
5528     const struct cli_exe_section *a = first, *b = second;
5529     return (a->raw - b->raw);
5530 }
5531 
5532 /* Check the given PE file for an authenticode signature and return CL_CLEAN if
5533  * the signature is valid.  There are two cases that this function should
5534  * handle:
5535  * - A PE file has an embedded Authenticode section
5536  * - The PE file has no embedded Authenticode section but is covered by a
5537  *   catalog file that was loaded in via a -d
5538  *
5539  * If peinfo is NULL, one will be created internally and used
5540  *
5541  * CL_VERIFIED will be returned if the file was whitelisted based on its
5542  * signature.  CL_VIRUS will be returned if the file was blacklisted based on
5543  * its signature.  Otherwise, a cl_error_t error value will be returned.
5544  *
5545  * If CL_VIRUS is returned, cli_append_virus will get called, adding the
5546  * name associated with the blacklist CRB rules to the list of found viruses.*/
5547 cl_error_t cli_check_auth_header(cli_ctx *ctx, struct cli_exe_info *peinfo)
5548 {
5549     size_t at;
5550     unsigned int i, hlen;
5551     size_t fsize;
5552     fmap_t *map   = ctx->fmap;
5553     void *hashctx = NULL;
5554     struct pe_certificate_hdr cert_hdr;
5555     struct cli_mapped_region *regions = NULL;
5556     unsigned int nregions;
5557     cl_error_t ret = CL_EVERIFY;
5558     uint8_t authsha1[SHA1_HASH_SIZE];
5559     uint32_t sec_dir_offset;
5560     uint32_t sec_dir_size;
5561     struct cli_exe_info _peinfo;
5562 
5563     // If Authenticode parsing has been disabled via DCONF or an engine
5564     // option, then don't continue on.
5565     if (!(DCONF & PE_CONF_CERTS))
5566         return CL_EVERIFY;
5567 
5568     if (ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_PE_CERTS)
5569         return CL_EVERIFY;
5570 
5571     // If peinfo is NULL, initialize one.  This makes it so that this function
5572     // can be used easily by sigtool
5573     if (NULL == peinfo) {
5574         peinfo = &_peinfo;
5575         cli_exe_info_init(peinfo, 0);
5576 
5577         if (cli_peheader(ctx->fmap, peinfo, CLI_PEHEADER_OPT_NONE, NULL) != CLI_PEHEADER_RET_SUCCESS) {
5578             cli_exe_info_destroy(peinfo);
5579             return CL_EFORMAT;
5580         }
5581     }
5582 
5583     sec_dir_offset = EC32(peinfo->dirs[4].VirtualAddress);
5584     sec_dir_size   = EC32(peinfo->dirs[4].Size);
5585 
5586     // As an optimization, check the security DataDirectory here and if
5587     // it's less than 8-bytes (and we aren't relying on this code to compute
5588     // the section hashes), bail out if we don't have any Authenticode hashes
5589     // loaded from .cat files
5590     if (sec_dir_size < 8 && !cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, 2)) {
5591         ret = CL_BREAK;
5592         goto finish;
5593     }
5594     fsize = map->len;
5595 
5596     // We'll build a list of the regions that need to be hashed and pass it to
5597     // asn1_check_mscat to do hash verification there (the hash algorithm is
5598     // specified in the PKCS7 structure).  We need to hash up to 4 regions
5599     regions = (struct cli_mapped_region *)cli_calloc(4, sizeof(struct cli_mapped_region));
5600     if (!regions) {
5601         ret = CL_EMEM;
5602         goto finish;
5603     }
5604     nregions = 0;
5605 
5606 #define add_chunk_to_hash_list(_offset, _size) \
5607     do {                                       \
5608         regions[nregions].offset = (_offset);  \
5609         regions[nregions].size   = (_size);    \
5610         nregions++;                            \
5611     } while (0)
5612 
5613     // Pretty much every case below should return CL_EFORMAT
5614     ret = CL_EFORMAT;
5615 
5616     /* MZ to checksum */
5617     at   = 0;
5618     hlen = peinfo->e_lfanew + sizeof(struct pe_image_file_hdr) + (peinfo->is_pe32plus ? offsetof(struct pe_image_optional_hdr64, CheckSum) : offsetof(struct pe_image_optional_hdr32, CheckSum));
5619     add_chunk_to_hash_list(0, hlen);
5620     at = hlen + 4;
5621 
5622     /* Checksum to security */
5623     if (peinfo->is_pe32plus)
5624         hlen = sizeof(struct pe_image_optional_hdr64) - offsetof(struct pe_image_optional_hdr64, CheckSum) - 4;
5625     else
5626         hlen = sizeof(struct pe_image_optional_hdr32) - offsetof(struct pe_image_optional_hdr32, CheckSum) - 4;
5627 
5628     hlen += sizeof(struct pe_image_data_dir) * 4;
5629     add_chunk_to_hash_list(at, hlen);
5630     at += hlen + 8;
5631 
5632     if (at > peinfo->hdr_size) {
5633         goto finish;
5634     }
5635 
5636     if (sec_dir_offset) {
5637 
5638         // Verify that we have all the bytes we expect in the authenticode sig
5639         // and that the certificate table is the last thing in the file
5640         // (according to the MS13-098 bulletin, this is a requirement)
5641         if (fsize != sec_dir_size + sec_dir_offset) {
5642             cli_dbgmsg("cli_check_auth_header: expected authenticode data at the end of the file\n");
5643             goto finish;
5644         }
5645 
5646         // Hash everything else up to the start of the security section. Allow
5647         // the case where at == sec_dir_offset without adding another region
5648         // to hash, since this could technically be valid (although I haven't
5649         // verified this).
5650         if (at < sec_dir_offset) {
5651             hlen = sec_dir_offset - at;
5652             add_chunk_to_hash_list(at, hlen);
5653         } else if (at > sec_dir_offset) {
5654             cli_dbgmsg("cli_check_auth_header: security directory offset appears to overlap with the PE header\n");
5655             goto finish;
5656         }
5657 
5658         // Parse the security directory header
5659 
5660         if (fmap_readn(map, &cert_hdr, sec_dir_offset, sizeof(cert_hdr)) != sizeof(cert_hdr)) {
5661             goto finish;
5662         }
5663 
5664         if (EC16(cert_hdr.revision) != WIN_CERT_REV_2) {
5665             cli_dbgmsg("cli_check_auth_header: unsupported authenticode data revision\n");
5666             goto finish;
5667         }
5668 
5669         if (EC16(cert_hdr.type) != WIN_CERT_TYPE_PKCS7) {
5670             cli_dbgmsg("cli_check_auth_header: unsupported authenticode data type\n");
5671             goto finish;
5672         }
5673 
5674         hlen = sec_dir_size;
5675 
5676         if (EC32(cert_hdr.length) != hlen) {
5677             /* This is the case that MS13-098 aimed to address, but it got
5678                  * pushback to where the fix (not allowing additional, non-zero
5679                  * bytes in the security directory) is now opt-in via a registry
5680                  * key.  Given that most machines will treat these binaries as
5681                  * valid, we'll still parse the signature and just trust that
5682                  * our whitelist signatures are tailored enough to where any
5683                  * instances of this are reasonable (for instance, I saw one
5684                  * binary that appeared to use this to embed a license key.) */
5685             cli_dbgmsg("cli_check_auth_header: MS13-098 violation detected, but continuing on to verify certificate\n");
5686         }
5687 
5688         at = sec_dir_offset + sizeof(cert_hdr);
5689         hlen -= sizeof(cert_hdr);
5690 
5691         ret = asn1_check_mscat((struct cl_engine *)(ctx->engine), map, at, hlen, regions, nregions, ctx);
5692 
5693         if (CL_VERIFIED == ret) {
5694             // We validated the embedded signature.  Hooray!
5695             goto finish;
5696         } else if (CL_VIRUS == ret) {
5697             // A blacklist rule hit - don't continue on to check hm_fp for a match
5698             goto finish;
5699         }
5700 
5701         // Otherwise, we still need to check to see whether this file is
5702         // covered by a .cat file (it's common these days for driver files
5703         // to have .cat files covering PEs with embedded signatures)
5704 
5705     } else {
5706 
5707         // Hash everything else
5708         if (at < fsize) {
5709             hlen = fsize - at;
5710             add_chunk_to_hash_list(at, hlen);
5711         }
5712     }
5713 
5714     // At this point we should compute the SHA1 authenticode hash to see
5715     // whether we've had any hashes added from external catalog files
5716     // TODO Is it gauranteed that the hashing algorithm will be SHA1?  If
5717     // not, figure out how to handle that case
5718     hashctx = cl_hash_init("sha1");
5719     if (NULL == hashctx) {
5720         ret = CL_EMEM;
5721         goto finish;
5722     }
5723 
5724     for (i = 0; i < nregions; i++) {
5725         const uint8_t *hptr;
5726         if (0 == regions[i].size) {
5727             continue;
5728         }
5729         if (!(hptr = fmap_need_off_once(map, regions[i].offset, regions[i].size))) {
5730             break;
5731         }
5732 
5733         cl_update_hash(hashctx, hptr, regions[i].size);
5734     }
5735 
5736     if (i != nregions) {
5737         goto finish;
5738     }
5739 
5740     cl_finish_hash(hashctx, authsha1);
5741     hashctx = NULL;
5742 
5743     if (cli_hm_scan(authsha1, 2, NULL, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS) {
5744         cli_dbgmsg("cli_check_auth_header: PE file whitelisted by catalog file\n");
5745         ret = CL_CLEAN;
5746         goto finish;
5747     }
5748 
5749     ret = CL_EVERIFY;
5750 
5751 finish:
5752     if (NULL != hashctx) {
5753         cl_hash_destroy(hashctx);
5754     }
5755 
5756     if (NULL != regions) {
5757         free(regions);
5758     }
5759 
5760     // If we created the peinfo, then destroy it.  Otherwise we don't own it
5761     if (&_peinfo == peinfo) {
5762         cli_exe_info_destroy(peinfo);
5763     }
5764     return ret;
5765 }
5766 
5767 /* Print out either the MD5, SHA1, or SHA256 associated with the imphash or
5768  * the individual sections. Also, this function computes the hashes of each
5769  * section (sorted based on the RVAs of the sections) if hashes is non-NULL.
5770  *
5771  * If the section hashes are to be computed and returned, this function
5772  * allocates memory for the section hashes, and it's up to the caller to free
5773  * it.  hashes->sections will be initialized to NULL at the beginning of the
5774  * function, and if after the call it's value is non-NULL, the memory should be
5775  * freed.  Furthermore, if hashes->sections is non-NULL, the hashes can assume
5776  * to be valid regardless of the return code.
5777  *
5778  * Also, a few other notes:
5779  *  - If a section has a virtual size of zero, it's corresponding hash value
5780  *    will not be computed and the hash contents will be all zeroes.
5781  *  - If a section extends beyond the end of the file, the section data and
5782  *    length will be truncated, and the hash generated accordingly
5783  *  - If a section exists completely outside of the file, it won't be included
5784  *    in the list of sections, and nsections will be adjusted accordingly.
5785  */
5786 cl_error_t cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type, stats_section_t *hashes)
5787 {
5788     unsigned int i;
5789     struct cli_exe_info _peinfo;
5790     struct cli_exe_info *peinfo = &_peinfo;
5791 
5792     unsigned char *hash, *hashset[CLI_HASH_AVAIL_TYPES];
5793     int genhash[CLI_HASH_AVAIL_TYPES];
5794     int hlen = 0;
5795 
5796     if (hashes) {
5797         hashes->sections = NULL;
5798 
5799         if (class != CL_GENHASH_PE_CLASS_SECTION || type != 1) {
5800             cli_dbgmsg("`hashes` can only be populated with MD5 PE section data\n");
5801             return CL_EARG;
5802         }
5803     }
5804 
5805     if (class >= CL_GENHASH_PE_CLASS_LAST)
5806         return CL_EARG;
5807 
5808     // TODO see if peinfo can be passed in (or lives in ctx or something) and
5809     // if so, use that to avoid having to re-parse the header
5810     cli_exe_info_init(peinfo, 0);
5811 
5812     if (cli_peheader(ctx->fmap, peinfo, CLI_PEHEADER_OPT_NONE, NULL) != CLI_PEHEADER_RET_SUCCESS) {
5813         cli_exe_info_destroy(peinfo);
5814         return CL_EFORMAT;
5815     }
5816 
5817     cli_qsort(peinfo->sections, peinfo->nsections, sizeof(*(peinfo->sections)), sort_sects);
5818 
5819     /* pick hashtypes to generate */
5820     memset(genhash, 0, sizeof(genhash));
5821     memset(hashset, 0, sizeof(hashset));
5822     switch (type) {
5823         case 1:
5824             genhash[CLI_HASH_MD5] = 1;
5825             hlen                  = hashlen[CLI_HASH_MD5];
5826             hash = hashset[CLI_HASH_MD5] = cli_calloc(hlen, sizeof(char));
5827             break;
5828         case 2:
5829             genhash[CLI_HASH_SHA1] = 1;
5830             hlen                   = hashlen[CLI_HASH_SHA1];
5831             hash = hashset[CLI_HASH_SHA1] = cli_calloc(hlen, sizeof(char));
5832             break;
5833         default:
5834             genhash[CLI_HASH_SHA256] = 1;
5835             hlen                     = hashlen[CLI_HASH_SHA256];
5836             hash = hashset[CLI_HASH_SHA256] = cli_calloc(hlen, sizeof(char));
5837             break;
5838     }
5839 
5840     if (!hash) {
5841         cli_errmsg("cli_genhash_pe: cli_malloc failed!\n");
5842         cli_exe_info_destroy(peinfo);
5843         return CL_EMEM;
5844     }
5845 
5846     if (hashes) {
5847         hashes->nsections = peinfo->nsections;
5848         hashes->sections  = cli_calloc(peinfo->nsections, sizeof(struct cli_section_hash));
5849 
5850         if (!(hashes->sections)) {
5851             cli_exe_info_destroy(peinfo);
5852             free(hash);
5853             return CL_EMEM;
5854         }
5855     }
5856 
5857     if (class == CL_GENHASH_PE_CLASS_SECTION) {
5858         char *dstr;
5859 
5860         for (i = 0; i < peinfo->nsections; i++) {
5861             /* Generate hashes */
5862             if (cli_hashsect(ctx->fmap, &peinfo->sections[i], hashset, genhash, genhash) == 1) {
5863                 if (cli_debug_flag) {
5864                     dstr = cli_str2hex((char *)hash, hlen);
5865                     cli_dbgmsg("Section{%u}: %u:%s\n", i, peinfo->sections[i].rsz, dstr ? (char *)dstr : "(NULL)");
5866                     if (dstr != NULL) {
5867                         free(dstr);
5868                     }
5869                 }
5870                 if (hashes) {
5871                     memcpy(hashes->sections[i].md5, hash, sizeof(hashes->sections[i].md5));
5872                     hashes->sections[i].len = peinfo->sections[i].rsz;
5873                 }
5874             } else if (peinfo->sections[i].rsz) {
5875                 cli_dbgmsg("Section{%u}: failed to generate hash for section\n", i);
5876             } else {
5877                 cli_dbgmsg("Section{%u}: section contains no data\n", i);
5878             }
5879         }
5880     } else if (class == CL_GENHASH_PE_CLASS_IMPTBL) {
5881         char *dstr;
5882         uint32_t impsz = 0;
5883         cl_error_t ret;
5884 
5885         /* Generate hash */
5886         ret = hash_imptbl(ctx, hashset, &impsz, genhash, peinfo);
5887         if (ret == CL_SUCCESS) {
5888             if (cli_debug_flag) {
5889                 dstr = cli_str2hex((char *)hash, hlen);
5890                 cli_dbgmsg("Imphash: %s:%u\n", dstr ? (char *)dstr : "(NULL)", impsz);
5891                 if (dstr != NULL) {
5892                     free(dstr);
5893                 }
5894             }
5895         } else {
5896             cli_dbgmsg("Imphash: failed to generate hash for import table (%d)\n", ret);
5897         }
5898     } else {
5899         cli_dbgmsg("cli_genhash_pe: unknown pe genhash class: %u\n", class);
5900     }
5901 
5902     free(hash);
5903     cli_exe_info_destroy(peinfo);
5904     return CL_SUCCESS;
5905 }
5906