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", §ion)) {
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(×tamp, 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(×tamp, 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(§ion_hdrs[j], §ion_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