Consolidate the PE parsing code into one function. I tried to preserve all existing functionality from the previous, distinct implementations to a large extent (with the exceptions mentioned below). If I noticed potential bugs/improvements, I added a TODO statement about those so that they can be fixed in a smaller commit later. Also, there are more TODOs in places where I'm not entirely sure why certain actions are performed - more research is needed for these.
I'm submitting a pull request now so that regression testing can be done, and because merging what I have thus far now will likely have fewer conflicts than if I try to merge later
PE parsing code improvements:
- PEs without all 16 data directories are parsed more appropriately now
- Added lots more debug statements
Also:
- Allow MAX_BC and MAX_TRACKED_PCRE to be specified via CFLAGS
When doing performance testing with the latest CVD, MAX_BC and
MAX_TRACKED_PCRE need to be raised to track all the events.
Allow these to be specified via CFLAGS by not redefining them
if they are already defined
- Fix an issue preventing wildcard sizes in .MDB/.MSB rules
I'm not sure what the original intent of the check I removed was,
but it prevents using wildcard sizes in .MDB/.MSB rules. AFAICT
these wildcard sizes should be handled appropriately by the MD5
section hash computation code, so I don't think a check on that
is needed.
- Fix several issues related to db loading
- .imp files will now get loaded if they exist in a directory passed
via clamscan's '-d' flag
- .pwdb files will now get loaded if they exist in a directory passed
via clamscan's '-d' flag even when compiling without yara support
- Changes to .imp, .ign, and .ign2 files will now be reflected in calls
to cl_statinidir and cl_statchkdir (and also .pwdb files, even when
compiling without yara support)
- The contents of .sfp files won't be included in some of the signature
counts, and the contents of .cud files will be
- Any local.gdb files will no longer be loaded twice
- For .imp files, you are no longer required to specify a minimum flevel for wildcard rules, since this isn't needed
... | ... |
@@ -318,6 +318,7 @@ libclamav_la_SOURCES = \ |
318 | 318 |
pe.h \ |
319 | 319 |
pe_icons.c \ |
320 | 320 |
pe_icons.h \ |
321 |
+ pe_structs.h \ |
|
321 | 322 |
disasm.c \ |
322 | 323 |
disasm.h \ |
323 | 324 |
disasm-common.h \ |
... | ... |
@@ -391,6 +392,7 @@ libclamav_la_SOURCES = \ |
391 | 391 |
elf.c \ |
392 | 392 |
elf.h \ |
393 | 393 |
execs.h \ |
394 |
+ execs.c \ |
|
394 | 395 |
sis.c \ |
395 | 396 |
sis.h \ |
396 | 397 |
uuencode.c \ |
... | ... |
@@ -257,20 +257,21 @@ am__libclamav_la_SOURCES_DIST = matcher-ac.c matcher-ac.h matcher-bm.c \ |
257 | 257 |
filetypes.h filetypes_int.h rtf.c rtf.h blob.c blob.h mbox.c \ |
258 | 258 |
mbox.h message.c message.h table.c table.h text.c text.h \ |
259 | 259 |
ole2_extract.c ole2_extract.h vba_extract.c vba_extract.h \ |
260 |
- msexpand.c msexpand.h pe.c pe.h pe_icons.c pe_icons.h disasm.c \ |
|
261 |
- disasm.h disasm-common.h disasmpriv.h upx.c upx.h htmlnorm.c \ |
|
262 |
- htmlnorm.h libmspack.c libmspack.h rebuildpe.c rebuildpe.h \ |
|
263 |
- petite.c petite.h wwunpack.c wwunpack.h unsp.c unsp.h aspack.c \ |
|
264 |
- aspack.h packlibs.c packlibs.h fsg.c fsg.h mew.c mew.h upack.c \ |
|
265 |
- upack.h line.c line.h untar.c untar.h unzip.c unzip.h ooxml.c \ |
|
266 |
- ooxml.h inflate64.c inflate64.h inffixed64.h inflate64_priv.h \ |
|
260 |
+ msexpand.c msexpand.h pe.c pe.h pe_icons.c \ |
|
261 |
+ pe_icons.h pe_structs.h disasm.c disasm.h disasm-common.h \ |
|
262 |
+ disasmpriv.h upx.c upx.h htmlnorm.c htmlnorm.h libmspack.c \ |
|
263 |
+ libmspack.h rebuildpe.c rebuildpe.h petite.c petite.h \ |
|
264 |
+ wwunpack.c wwunpack.h unsp.c unsp.h aspack.c aspack.h \ |
|
265 |
+ packlibs.c packlibs.h fsg.c fsg.h mew.c mew.h upack.c upack.h \ |
|
266 |
+ line.c line.h untar.c untar.h unzip.c unzip.h ooxml.c ooxml.h \ |
|
267 |
+ inflate64.c inflate64.h inffixed64.h inflate64_priv.h \ |
|
267 | 268 |
special.c special.h binhex.c binhex.h is_tar.c is_tar.h tnef.c \ |
268 | 269 |
tnef.h autoit.c autoit.h unarj.c unarj.h nsis/bzlib.c \ |
269 | 270 |
nsis/bzlib_private.h nsis/nsis_bzlib.h nsis/nulsft.c \ |
270 | 271 |
nsis/nulsft.h nsis/infblock.c nsis/nsis_zconf.h \ |
271 | 272 |
nsis/nsis_zlib.h nsis/nsis_zutil.h pdf.c pdf.h pdfng.c \ |
272 | 273 |
pdfdecode.c pdfdecode.h spin.c spin.h yc.c yc.h elf.c elf.h \ |
273 |
- execs.h sis.c sis.h uuencode.c uuencode.h phishcheck.c \ |
|
274 |
+ execs.h execs.c sis.c sis.h uuencode.c uuencode.h phishcheck.c \ |
|
274 | 275 |
phishcheck.h phish_domaincheck_db.c phish_domaincheck_db.h \ |
275 | 276 |
phish_whitelist.c phish_whitelist.h iana_cctld.h iana_tld.h \ |
276 | 277 |
regex_list.c regex_list.h regex_suffix.c regex_suffix.h \ |
... | ... |
@@ -406,8 +407,9 @@ am_libclamav_la_OBJECTS = libclamav_la-matcher-ac.lo \ |
406 | 406 |
libclamav_la-nulsft.lo libclamav_la-infblock.lo \ |
407 | 407 |
libclamav_la-pdf.lo libclamav_la-pdfng.lo \ |
408 | 408 |
libclamav_la-pdfdecode.lo libclamav_la-spin.lo \ |
409 |
- libclamav_la-yc.lo libclamav_la-elf.lo libclamav_la-sis.lo \ |
|
410 |
- libclamav_la-uuencode.lo libclamav_la-phishcheck.lo \ |
|
409 |
+ libclamav_la-yc.lo libclamav_la-elf.lo libclamav_la-execs.lo \ |
|
410 |
+ libclamav_la-sis.lo libclamav_la-uuencode.lo \ |
|
411 |
+ libclamav_la-phishcheck.lo \ |
|
411 | 412 |
libclamav_la-phish_domaincheck_db.lo \ |
412 | 413 |
libclamav_la-phish_whitelist.lo libclamav_la-regex_list.lo \ |
413 | 414 |
libclamav_la-regex_suffix.lo libclamav_la-entconv.lo \ |
... | ... |
@@ -1308,20 +1310,21 @@ libclamav_la_SOURCES = matcher-ac.c matcher-ac.h matcher-bm.c \ |
1308 | 1308 |
filetypes.h filetypes_int.h rtf.c rtf.h blob.c blob.h mbox.c \ |
1309 | 1309 |
mbox.h message.c message.h table.c table.h text.c text.h \ |
1310 | 1310 |
ole2_extract.c ole2_extract.h vba_extract.c vba_extract.h \ |
1311 |
- msexpand.c msexpand.h pe.c pe.h pe_icons.c pe_icons.h disasm.c \ |
|
1312 |
- disasm.h disasm-common.h disasmpriv.h upx.c upx.h htmlnorm.c \ |
|
1313 |
- htmlnorm.h libmspack.c libmspack.h rebuildpe.c rebuildpe.h \ |
|
1314 |
- petite.c petite.h wwunpack.c wwunpack.h unsp.c unsp.h aspack.c \ |
|
1315 |
- aspack.h packlibs.c packlibs.h fsg.c fsg.h mew.c mew.h upack.c \ |
|
1316 |
- upack.h line.c line.h untar.c untar.h unzip.c unzip.h ooxml.c \ |
|
1317 |
- ooxml.h inflate64.c inflate64.h inffixed64.h inflate64_priv.h \ |
|
1311 |
+ msexpand.c msexpand.h pe.c pe.h pe_icons.c \ |
|
1312 |
+ pe_icons.h pe_structs.h disasm.c disasm.h disasm-common.h \ |
|
1313 |
+ disasmpriv.h upx.c upx.h htmlnorm.c htmlnorm.h libmspack.c \ |
|
1314 |
+ libmspack.h rebuildpe.c rebuildpe.h petite.c petite.h \ |
|
1315 |
+ wwunpack.c wwunpack.h unsp.c unsp.h aspack.c aspack.h \ |
|
1316 |
+ packlibs.c packlibs.h fsg.c fsg.h mew.c mew.h upack.c upack.h \ |
|
1317 |
+ line.c line.h untar.c untar.h unzip.c unzip.h ooxml.c ooxml.h \ |
|
1318 |
+ inflate64.c inflate64.h inffixed64.h inflate64_priv.h \ |
|
1318 | 1319 |
special.c special.h binhex.c binhex.h is_tar.c is_tar.h tnef.c \ |
1319 | 1320 |
tnef.h autoit.c autoit.h unarj.c unarj.h nsis/bzlib.c \ |
1320 | 1321 |
nsis/bzlib_private.h nsis/nsis_bzlib.h nsis/nulsft.c \ |
1321 | 1322 |
nsis/nulsft.h nsis/infblock.c nsis/nsis_zconf.h \ |
1322 | 1323 |
nsis/nsis_zlib.h nsis/nsis_zutil.h pdf.c pdf.h pdfng.c \ |
1323 | 1324 |
pdfdecode.c pdfdecode.h spin.c spin.h yc.c yc.h elf.c elf.h \ |
1324 |
- execs.h sis.c sis.h uuencode.c uuencode.h phishcheck.c \ |
|
1325 |
+ execs.h execs.c sis.c sis.h uuencode.c uuencode.h phishcheck.c \ |
|
1325 | 1326 |
phishcheck.h phish_domaincheck_db.c phish_domaincheck_db.h \ |
1326 | 1327 |
phish_whitelist.c phish_whitelist.h iana_cctld.h iana_tld.h \ |
1327 | 1328 |
regex_list.c regex_list.h regex_suffix.c regex_suffix.h \ |
... | ... |
@@ -1612,6 +1615,7 @@ distclean-compile: |
1612 | 1612 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-elf.Plo@am__quote@ |
1613 | 1613 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-entconv.Plo@am__quote@ |
1614 | 1614 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-events.Plo@am__quote@ |
1615 |
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-execs.Plo@am__quote@ |
|
1615 | 1616 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-explode.Plo@am__quote@ |
1616 | 1617 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-filetypes.Plo@am__quote@ |
1617 | 1618 |
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-filtering.Plo@am__quote@ |
... | ... |
@@ -2276,6 +2280,13 @@ libclamav_la-elf.lo: elf.c |
2276 | 2276 |
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
2277 | 2277 |
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-elf.lo `test -f 'elf.c' || echo '$(srcdir)/'`elf.c |
2278 | 2278 |
|
2279 |
+libclamav_la-execs.lo: execs.c |
|
2280 |
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-execs.lo -MD -MP -MF $(DEPDIR)/libclamav_la-execs.Tpo -c -o libclamav_la-execs.lo `test -f 'execs.c' || echo '$(srcdir)/'`execs.c |
|
2281 |
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-execs.Tpo $(DEPDIR)/libclamav_la-execs.Plo |
|
2282 |
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='execs.c' object='libclamav_la-execs.lo' libtool=yes @AMDEPBACKSLASH@ |
|
2283 |
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ |
|
2284 |
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-execs.lo `test -f 'execs.c' || echo '$(srcdir)/'`execs.c |
|
2285 |
+ |
|
2279 | 2286 |
libclamav_la-sis.lo: sis.c |
2280 | 2287 |
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-sis.lo -MD -MP -MF $(DEPDIR)/libclamav_la-sis.Tpo -c -o libclamav_la-sis.lo `test -f 'sis.c' || echo '$(srcdir)/'`sis.c |
2281 | 2288 |
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-sis.Tpo $(DEPDIR)/libclamav_la-sis.Plo |
... | ... |
@@ -2036,7 +2036,6 @@ int asn1_load_mscat(fmap_t *map, struct cl_engine *engine) |
2036 | 2036 |
{ |
2037 | 2037 |
struct cli_asn1 c; |
2038 | 2038 |
unsigned int size; |
2039 |
- struct cli_matcher *db; |
|
2040 | 2039 |
int i; |
2041 | 2040 |
|
2042 | 2041 |
// TODO As currently implemented, loading in a .cat file with -d requires |
... | ... |
@@ -2172,7 +2171,7 @@ int asn1_load_mscat(fmap_t *map, struct cl_engine *engine) |
2172 | 2172 |
cli_dbgmsg("asn1_load_mscat: got hash %s (%s)\n", sha1, (hashtype == 2) ? "PE" : "CAB"); |
2173 | 2173 |
} |
2174 | 2174 |
if (!engine->hm_fp) { |
2175 |
- if (!(engine->hm_fp = mpool_calloc(engine->mempool, 1, sizeof(*db)))) { |
|
2175 |
+ if (!(engine->hm_fp = mpool_calloc(engine->mempool, 1, sizeof(*(engine->hm_fp))))) { |
|
2176 | 2176 |
tag.size = 1; |
2177 | 2177 |
return 1; |
2178 | 2178 |
} |
... | ... |
@@ -45,7 +45,9 @@ |
45 | 45 |
#include "json.h" |
46 | 46 |
#endif |
47 | 47 |
|
48 |
+#ifndef MAX_BC |
|
48 | 49 |
#define MAX_BC 64 |
50 |
+#endif |
|
49 | 51 |
#define BC_EVENTS_PER_SIG 2 |
50 | 52 |
#define MAX_BC_SIGEVENT_ID MAX_BC *BC_EVENTS_PER_SIG |
51 | 53 |
|
... | ... |
@@ -2776,7 +2778,7 @@ int cli_bytecode_runlsig(cli_ctx *cctx, struct cli_target_info *tinfo, |
2776 | 2776 |
cli_bytecode_context_setctx(&ctx, cctx); |
2777 | 2777 |
cli_bytecode_context_setfile(&ctx, map); |
2778 | 2778 |
if (tinfo && tinfo->status == 1) { |
2779 |
- ctx.sections = tinfo->exeinfo.section; |
|
2779 |
+ ctx.sections = tinfo->exeinfo.sections; |
|
2780 | 2780 |
memset(&pehookdata, 0, sizeof(pehookdata)); |
2781 | 2781 |
pehookdata.offset = tinfo->exeinfo.offset; |
2782 | 2782 |
pehookdata.ep = tinfo->exeinfo.ep; |
... | ... |
@@ -339,7 +339,7 @@ static int cli_tgzload(int fd, struct cl_engine *engine, unsigned int *signo, un |
339 | 339 |
else |
340 | 340 |
off = ftell(dbio->fs); |
341 | 341 |
|
342 |
- if ((!dbinfo && cli_strbcasestr(name, ".info")) || (dbinfo && (CLI_DBEXT(name) || cli_strbcasestr(name, ".ign") || cli_strbcasestr(name, ".ign2")))) { |
|
342 |
+ if ((!dbinfo && cli_strbcasestr(name, ".info")) || (dbinfo && CLI_DBEXT(name))) { |
|
343 | 343 |
ret = cli_load(name, engine, signo, options, dbio); |
344 | 344 |
if (ret) { |
345 | 345 |
cli_errmsg("cli_tgzload: Can't load %s\n", name); |
... | ... |
@@ -444,8 +444,8 @@ static int cli_elf_sh32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo, |
444 | 444 |
cli_dbgmsg("ELF: Section header table offset: %d\n", shoff); |
445 | 445 |
|
446 | 446 |
if (elfinfo) { |
447 |
- elfinfo->section = (struct cli_exe_section *)cli_calloc(shnum, sizeof(struct cli_exe_section)); |
|
448 |
- if (!elfinfo->section) { |
|
447 |
+ elfinfo->sections = (struct cli_exe_section *)cli_calloc(shnum, sizeof(struct cli_exe_section)); |
|
448 |
+ if (!elfinfo->sections) { |
|
449 | 449 |
cli_dbgmsg("ELF: Can't allocate memory for section headers\n"); |
450 | 450 |
return CL_EMEM; |
451 | 451 |
} |
... | ... |
@@ -455,10 +455,7 @@ static int cli_elf_sh32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo, |
455 | 455 |
section_hdr = (struct elf_section_hdr32 *)cli_calloc(shnum, shentsize); |
456 | 456 |
if (!section_hdr) { |
457 | 457 |
cli_errmsg("ELF: Can't allocate memory for section headers\n"); |
458 |
- if (elfinfo) { |
|
459 |
- free(elfinfo->section); |
|
460 |
- elfinfo->section = NULL; |
|
461 |
- } |
|
458 |
+ cli_exe_info_destroy(elfinfo); |
|
462 | 459 |
return CL_EMEM; |
463 | 460 |
} |
464 | 461 |
if (ctx) { |
... | ... |
@@ -476,10 +473,7 @@ static int cli_elf_sh32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo, |
476 | 476 |
cli_dbgmsg("ELF: Possibly broken ELF file\n"); |
477 | 477 |
} |
478 | 478 |
free(section_hdr); |
479 |
- if (elfinfo) { |
|
480 |
- free(elfinfo->section); |
|
481 |
- elfinfo->section = NULL; |
|
482 |
- } |
|
479 |
+ cli_exe_info_destroy(elfinfo); |
|
483 | 480 |
if (ctx && SCAN_HEURISTIC_BROKEN) { |
484 | 481 |
cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
485 | 482 |
return CL_VIRUS; |
... | ... |
@@ -490,9 +484,9 @@ static int cli_elf_sh32(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo, |
490 | 490 |
shoff += sizeof(struct elf_section_hdr32); |
491 | 491 |
|
492 | 492 |
if (elfinfo) { |
493 |
- elfinfo->section[i].rva = EC32(section_hdr[i].sh_addr, conv); |
|
494 |
- elfinfo->section[i].raw = EC32(section_hdr[i].sh_offset, conv); |
|
495 |
- elfinfo->section[i].rsz = EC32(section_hdr[i].sh_size, conv); |
|
493 |
+ elfinfo->sections[i].rva = EC32(section_hdr[i].sh_addr, conv); |
|
494 |
+ elfinfo->sections[i].raw = EC32(section_hdr[i].sh_offset, conv); |
|
495 |
+ elfinfo->sections[i].rsz = EC32(section_hdr[i].sh_size, conv); |
|
496 | 496 |
} |
497 | 497 |
if (ctx) { |
498 | 498 |
cli_dbgmsg("ELF: Section %u\n", i); |
... | ... |
@@ -553,8 +547,8 @@ static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo, |
553 | 553 |
cli_dbgmsg("ELF: Section header table offset: " STDu64 "\n", shoff); |
554 | 554 |
|
555 | 555 |
if (elfinfo) { |
556 |
- elfinfo->section = (struct cli_exe_section *)cli_calloc(shnum, sizeof(struct cli_exe_section)); |
|
557 |
- if (!elfinfo->section) { |
|
556 |
+ elfinfo->sections = (struct cli_exe_section *)cli_calloc(shnum, sizeof(struct cli_exe_section)); |
|
557 |
+ if (!elfinfo->sections) { |
|
558 | 558 |
cli_dbgmsg("ELF: Can't allocate memory for section headers\n"); |
559 | 559 |
return CL_EMEM; |
560 | 560 |
} |
... | ... |
@@ -564,10 +558,7 @@ static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo, |
564 | 564 |
section_hdr = (struct elf_section_hdr64 *)cli_calloc(shnum, shentsize); |
565 | 565 |
if (!section_hdr) { |
566 | 566 |
cli_errmsg("ELF: Can't allocate memory for section headers\n"); |
567 |
- if (elfinfo) { |
|
568 |
- free(elfinfo->section); |
|
569 |
- elfinfo->section = NULL; |
|
570 |
- } |
|
567 |
+ cli_exe_info_destroy(elfinfo); |
|
571 | 568 |
return CL_EMEM; |
572 | 569 |
} |
573 | 570 |
if (ctx) { |
... | ... |
@@ -585,10 +576,7 @@ static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo, |
585 | 585 |
cli_dbgmsg("ELF: Possibly broken ELF file\n"); |
586 | 586 |
} |
587 | 587 |
free(section_hdr); |
588 |
- if (elfinfo) { |
|
589 |
- free(elfinfo->section); |
|
590 |
- elfinfo->section = NULL; |
|
591 |
- } |
|
588 |
+ cli_exe_info_destroy(elfinfo); |
|
592 | 589 |
if (ctx && SCAN_HEURISTIC_BROKEN) { |
593 | 590 |
cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
594 | 591 |
return CL_VIRUS; |
... | ... |
@@ -599,9 +587,9 @@ static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo, |
599 | 599 |
shoff += sizeof(struct elf_section_hdr64); |
600 | 600 |
|
601 | 601 |
if (elfinfo) { |
602 |
- elfinfo->section[i].rva = EC64(section_hdr[i].sh_addr, conv); |
|
603 |
- elfinfo->section[i].raw = EC64(section_hdr[i].sh_offset, conv); |
|
604 |
- elfinfo->section[i].rsz = EC64(section_hdr[i].sh_size, conv); |
|
602 |
+ elfinfo->sections[i].rva = EC64(section_hdr[i].sh_addr, conv); |
|
603 |
+ elfinfo->sections[i].raw = EC64(section_hdr[i].sh_offset, conv); |
|
604 |
+ elfinfo->sections[i].rsz = EC64(section_hdr[i].sh_size, conv); |
|
605 | 605 |
} |
606 | 606 |
if (ctx) { |
607 | 607 |
cli_dbgmsg("ELF: Section " STDu32 "\n", (uint32_t)i); |
608 | 608 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,50 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * |
|
3 |
+ * Authors: Andrew Williams |
|
4 |
+ * |
|
5 |
+ * This program is free software; you can redistribute it and/or modify |
|
6 |
+ * it under the terms of the GNU General Public License version 2 as |
|
7 |
+ * published by the Free Software Foundation. |
|
8 |
+ * |
|
9 |
+ * This program is distributed in the hope that it will be useful, |
|
10 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
+ * GNU General Public License for more details. |
|
13 |
+ * |
|
14 |
+ * You should have received a copy of the GNU General Public License |
|
15 |
+ * along with this program; if not, write to the Free Software |
|
16 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
17 |
+ * MA 02110-1301, USA. |
|
18 |
+ */ |
|
19 |
+ |
|
20 |
+#include "execs.h" |
|
21 |
+#include <string.h> |
|
22 |
+ |
|
23 |
+void cli_exe_info_init(struct cli_exe_info *exeinfo, uint32_t offset) |
|
24 |
+{ |
|
25 |
+ |
|
26 |
+ if (NULL == exeinfo) { |
|
27 |
+ return; |
|
28 |
+ } |
|
29 |
+ // TODO the memset below might not be needed. Instead, replace with: |
|
30 |
+ // exeinfo->sections = NULL; |
|
31 |
+ // memset(&exeinfo->vinfo, '\0', sizeof(exeinfo->vinfo)); |
|
32 |
+ memset(exeinfo, '\0', sizeof(*exeinfo)); |
|
33 |
+ exeinfo->offset = offset; |
|
34 |
+} |
|
35 |
+ |
|
36 |
+void cli_exe_info_destroy(struct cli_exe_info *exeinfo) |
|
37 |
+{ |
|
38 |
+ |
|
39 |
+ if (NULL == exeinfo) { |
|
40 |
+ return; |
|
41 |
+ } |
|
42 |
+ |
|
43 |
+ if (NULL != exeinfo->sections) { |
|
44 |
+ free(exeinfo->sections); |
|
45 |
+ exeinfo->sections = NULL; |
|
46 |
+ } |
|
47 |
+ |
|
48 |
+ cli_hashset_destroy(&(exeinfo->vinfo)); |
|
49 |
+} |
|
0 | 50 |
\ No newline at end of file |
... | ... |
@@ -25,10 +25,25 @@ |
25 | 25 |
#include "clamav-types.h" |
26 | 26 |
#include "hashtab.h" |
27 | 27 |
#include "bcfeatures.h" |
28 |
+#include "pe_structs.h" |
|
28 | 29 |
|
29 | 30 |
/** @file */ |
30 | 31 |
/** Section of executable file. |
31 | 32 |
\group_pe |
33 |
+ * NOTE: This is used to store PE, MachO, and ELF section information. Not |
|
34 |
+ * all members are populated by the respective parsing functions. |
|
35 |
+ * |
|
36 |
+ * NOTE: This structure MUST stay in-sync with the ones defined within the |
|
37 |
+ * clamav-bytecode-compiler source at: |
|
38 |
+ * - clang/lib/Headers/bytecode_execs.h |
|
39 |
+ * - llvm/tools/clang/lib/Headers/bytecode_execs.h |
|
40 |
+ * We allocate space for an array of these and pass it directly to the |
|
41 |
+ * bytecode sig runtime for use. |
|
42 |
+ * |
|
43 |
+ * TODO Next time we are making changes to the clamav-bytecode-compiler |
|
44 |
+ * source, modify this structure to also include the section name (here and |
|
45 |
+ * there). Then, populate this field in the PE/MachO/ELF header parsing |
|
46 |
+ * functions. Choose a length that's reasonable for all platforms |
|
32 | 47 |
*/ |
33 | 48 |
struct cli_exe_section { |
34 | 49 |
uint32_t rva; /**< Relative VirtualAddress */ |
... | ... |
@@ -43,25 +58,111 @@ struct cli_exe_section { |
43 | 43 |
}; |
44 | 44 |
|
45 | 45 |
/** Executable file information |
46 |
- \group_pe |
|
46 |
+ * NOTE: This is used to store PE, MachO, and ELF executable information, |
|
47 |
+ * but it predominantly has fields for PE info. Not all members are |
|
48 |
+ * populated by the respective parsing functions. |
|
49 |
+ * |
|
50 |
+ * TODO: Document which fields are PE only (maybe put those into a union of |
|
51 |
+ * structs containing the various type-specific members) |
|
52 |
+ |
|
53 |
+ * NOTE: This structure is also defined in the clamav-bytecode-compiler |
|
54 |
+ * source at: |
|
55 |
+ * - clang/lib/Headers/bytecode_execs.h |
|
56 |
+ * - llvm/tools/clang/lib/Headers/bytecode_execs.h |
|
57 |
+ * Based on how we use it, though, it doesn't need to stay in-sync |
|
58 |
+ * |
|
59 |
+ * TODO Next time we are making changes to the clamav-bytecode-compiler |
|
60 |
+ * source, remove this structure definition there so it's not confusing |
|
47 | 61 |
*/ |
48 | 62 |
struct cli_exe_info { |
49 | 63 |
/** Information about all the sections of this file. |
50 | 64 |
* This array has \p nsection elements */ |
51 |
- struct cli_exe_section *section; |
|
52 |
- /** Offset where this executable start in file (nonzero if embedded) */ |
|
65 |
+ struct cli_exe_section *sections; |
|
66 |
+ |
|
67 |
+ /** Offset where this executable starts in file (nonzero if embedded) */ |
|
53 | 68 |
uint32_t offset; |
54 |
- /** Entrypoint of executable */ |
|
69 |
+ |
|
70 |
+ /** File offset to the entrypoint of the executable. */ |
|
55 | 71 |
uint32_t ep; |
56 |
- /** Number of sections*/ |
|
72 |
+ |
|
73 |
+ /** Number of sections. |
|
74 |
+ * NOTE: If a section is determined to be invalid (exists outside of the |
|
75 |
+ * file) then it will not be included in this count (at least for PE). |
|
76 |
+ */ |
|
57 | 77 |
uint16_t nsections; |
78 |
+ |
|
79 |
+ // TODO Remove - not required |
|
58 | 80 |
void *dummy; /* for compat - preserve offset */ |
81 |
+ |
|
59 | 82 |
/** Resources RVA - PE ONLY */ |
83 |
+ // TODO Maybe get rid of this - it looks like it's only used by the |
|
84 |
+ // icon matching code (and maybe the bytecode API more broadly?) |
|
60 | 85 |
uint32_t res_addr; |
61 |
- /** Address size - PE ONLY */ |
|
86 |
+ |
|
87 |
+ /** Size of the header (aligned) - PE ONLY. This corresponds to |
|
88 |
+ * SizeOfHeaders in the optional header |
|
89 |
+ */ |
|
62 | 90 |
uint32_t hdr_size; |
91 |
+ |
|
63 | 92 |
/** Hashset for versioninfo matching */ |
64 | 93 |
struct cli_hashset vinfo; |
94 |
+ |
|
95 |
+ /** Entry point RVA */ |
|
96 |
+ uint32_t vep; |
|
97 |
+ |
|
98 |
+ /** Number of data directory entries at the end of the optional header. |
|
99 |
+ * This also corresponds to the number of entries in dirs that has |
|
100 |
+ * been populated with information. |
|
101 |
+ */ |
|
102 |
+ uint32_t ndatadirs; |
|
103 |
+ |
|
104 |
+ /** Whether this file is a DLL */ |
|
105 |
+ uint32_t is_dll; |
|
106 |
+ |
|
107 |
+ /** Whether this file is a PE32+ exe (64-bit) */ |
|
108 |
+ uint32_t is_pe32plus; |
|
109 |
+ |
|
110 |
+ /**< address of new exe header */ |
|
111 |
+ uint32_t e_lfanew; |
|
112 |
+ |
|
113 |
+ /** The lowest section RVA */ |
|
114 |
+ uint32_t min; |
|
115 |
+ |
|
116 |
+ /** The RVA of the highest byte contained within a section */ |
|
117 |
+ uint32_t max; |
|
118 |
+ |
|
119 |
+ /** Offset of any file overlays, as determined by parsing the PE header */ |
|
120 |
+ uint32_t overlay_start; |
|
121 |
+ |
|
122 |
+ /**< size of overlay */ |
|
123 |
+ uint32_t overlay_size; |
|
124 |
+ |
|
125 |
+ /* Raw data copied in from the EXE directly. |
|
126 |
+ * |
|
127 |
+ * NOTE: The data in the members below haven't been converted to host |
|
128 |
+ * endianness, so all field accesses most account for this to ensure |
|
129 |
+ * proper functionality on big endian systems (the PE header is always |
|
130 |
+ * little-endian) |
|
131 |
+ */ |
|
132 |
+ |
|
133 |
+ /** Image File Header for this PE file */ |
|
134 |
+ struct pe_image_file_hdr file_hdr; |
|
135 |
+ |
|
136 |
+ /** PE optional header. Use is_pe32plus to determine whether the 32-bit |
|
137 |
+ * or 64-bit union member should be used. */ |
|
138 |
+ union { |
|
139 |
+ struct pe_image_optional_hdr64 opt64; |
|
140 |
+ struct pe_image_optional_hdr32 opt32; |
|
141 |
+ } pe_opt; |
|
142 |
+ |
|
143 |
+ /**< PE data directory header. If ndatadirs is less than 16, |
|
144 |
+ * the unpopulated entries will be memset'd to zero. |
|
145 |
+ */ |
|
146 |
+ struct pe_image_data_dir dirs[16]; |
|
65 | 147 |
}; |
66 | 148 |
|
149 |
+// TODO Document |
|
150 |
+void cli_exe_info_init(struct cli_exe_info *exeinfo, uint32_t offset); |
|
151 |
+void cli_exe_info_destroy(struct cli_exe_info *exeinfo); |
|
152 |
+ |
|
67 | 153 |
#endif |
... | ... |
@@ -483,7 +483,7 @@ int cli_scanmacho(cli_ctx *ctx, struct cli_exe_info *fileinfo) |
483 | 483 |
if (matcher) { |
484 | 484 |
fileinfo->ep = ep; |
485 | 485 |
fileinfo->nsections = sect; |
486 |
- fileinfo->section = sections; |
|
486 |
+ fileinfo->sections = sections; |
|
487 | 487 |
return 0; |
488 | 488 |
} else { |
489 | 489 |
free(sections); |
... | ... |
@@ -445,8 +445,12 @@ int cli_caloff(const char *offstr, const struct cli_target_info *info, unsigned |
445 | 445 |
*offset_min = CLI_OFF_NONE; |
446 | 446 |
if (offset_max) |
447 | 447 |
*offset_max = CLI_OFF_NONE; |
448 |
- if (info->status == -1) |
|
448 |
+ if (info->status == -1) { |
|
449 |
+ // TODO I wonder if this means that sigs with these types won't |
|
450 |
+ // work (which kinda makes sense). Warn the user of this for now |
|
451 |
+ cli_dbgmsg("cli_caloff: cli_target_info is invalid - unable to determine offsets for ndb/ldb subsigs using EOF-n/EP+n/EP-n/Sx+n/SEx/SL+n\n"); |
|
449 | 452 |
return CL_SUCCESS; |
453 |
+ } |
|
450 | 454 |
|
451 | 455 |
switch (offdata[0]) { |
452 | 456 |
case CLI_OFF_EOF_MINUS: |
... | ... |
@@ -462,23 +466,26 @@ int cli_caloff(const char *offstr, const struct cli_target_info *info, unsigned |
462 | 462 |
break; |
463 | 463 |
|
464 | 464 |
case CLI_OFF_SL_PLUS: |
465 |
- *offset_min = info->exeinfo.section[info->exeinfo.nsections - 1].raw + offdata[1]; |
|
465 |
+ *offset_min = info->exeinfo.sections[info->exeinfo.nsections - 1].raw + offdata[1]; |
|
466 | 466 |
break; |
467 | 467 |
|
468 | 468 |
case CLI_OFF_SX_PLUS: |
469 | 469 |
if (offdata[3] >= info->exeinfo.nsections) |
470 | 470 |
*offset_min = CLI_OFF_NONE; |
471 | 471 |
else |
472 |
- *offset_min = info->exeinfo.section[offdata[3]].raw + offdata[1]; |
|
472 |
+ *offset_min = info->exeinfo.sections[offdata[3]].raw + offdata[1]; |
|
473 | 473 |
break; |
474 | 474 |
|
475 | 475 |
case CLI_OFF_SE: |
476 | 476 |
if (offdata[3] >= info->exeinfo.nsections) { |
477 | 477 |
*offset_min = CLI_OFF_NONE; |
478 | 478 |
} else { |
479 |
- *offset_min = info->exeinfo.section[offdata[3]].raw; |
|
479 |
+ *offset_min = info->exeinfo.sections[offdata[3]].raw; |
|
480 | 480 |
if (offset_max) |
481 |
- *offset_max = *offset_min + info->exeinfo.section[offdata[3]].rsz + offdata[2]; |
|
481 |
+ *offset_max = *offset_min + info->exeinfo.sections[offdata[3]].rsz + offdata[2]; |
|
482 |
+ // TODO offdata[2] == MaxShift. Won't this make offset_max |
|
483 |
+ // extend beyond the end of the section? This doesn't seem like |
|
484 |
+ // what we want... |
|
482 | 485 |
} |
483 | 486 |
break; |
484 | 487 |
|
... | ... |
@@ -498,16 +505,31 @@ int cli_caloff(const char *offstr, const struct cli_target_info *info, unsigned |
498 | 498 |
return CL_SUCCESS; |
499 | 499 |
} |
500 | 500 |
|
501 |
+void cli_targetinfo_init(struct cli_target_info *info) |
|
502 |
+{ |
|
503 |
+ |
|
504 |
+ if (NULL == info) { |
|
505 |
+ return; |
|
506 |
+ } |
|
507 |
+ // Things that must be initialized here: |
|
508 |
+ // - status (set to 0) |
|
509 |
+ // - vinfo |
|
510 |
+ // Maybe other things. |
|
511 |
+ // TODO Consider replacing with just the required member assignments |
|
512 |
+ // for performance |
|
513 |
+ memset(info, 0, sizeof(struct cli_target_info)); |
|
514 |
+ |
|
515 |
+ cli_hashset_init_noalloc(&info->exeinfo.vinfo); |
|
516 |
+} |
|
517 |
+ |
|
501 | 518 |
void cli_targetinfo(struct cli_target_info *info, unsigned int target, fmap_t *map) |
502 | 519 |
{ |
503 | 520 |
int (*einfo)(fmap_t *, struct cli_exe_info *) = NULL; |
504 | 521 |
|
505 |
- memset(info, 0, sizeof(struct cli_target_info)); |
|
506 | 522 |
info->fsize = map->len; |
507 |
- cli_hashset_init_noalloc(&info->exeinfo.vinfo); |
|
508 | 523 |
|
509 | 524 |
if (target == 1) |
510 |
- einfo = cli_peheader; |
|
525 |
+ einfo = cli_pe_targetinfo; |
|
511 | 526 |
else if (target == 6) |
512 | 527 |
einfo = cli_elfheader; |
513 | 528 |
else if (target == 9) |
... | ... |
@@ -521,6 +543,16 @@ void cli_targetinfo(struct cli_target_info *info, unsigned int target, fmap_t *m |
521 | 521 |
info->status = 1; |
522 | 522 |
} |
523 | 523 |
|
524 |
+void cli_targetinfo_destroy(struct cli_target_info *info) |
|
525 |
+{ |
|
526 |
+ |
|
527 |
+ if (NULL == info || info->status != 1) { |
|
528 |
+ return; |
|
529 |
+ } |
|
530 |
+ |
|
531 |
+ cli_exe_info_destroy(&(info->exeinfo)); |
|
532 |
+} |
|
533 |
+ |
|
524 | 534 |
int cli_checkfp(unsigned char *digest, size_t size, cli_ctx *ctx) |
525 | 535 |
{ |
526 | 536 |
return cli_checkfp_virus(digest, size, ctx, NULL); |
... | ... |
@@ -667,7 +699,7 @@ static int matchicon(cli_ctx *ctx, struct cli_exe_info *exeinfo, const char *grp |
667 | 667 |
cli_icongroupset_init(&iconset); |
668 | 668 |
cli_icongroupset_add(grp1 ? grp1 : "*", &iconset, 0, ctx); |
669 | 669 |
cli_icongroupset_add(grp2 ? grp2 : "*", &iconset, 1, ctx); |
670 |
- return cli_scanicon(&iconset, exeinfo->res_addr, ctx, exeinfo->section, exeinfo->nsections, exeinfo->hdr_size); |
|
670 |
+ return cli_scanicon(&iconset, ctx, exeinfo); |
|
671 | 671 |
} |
672 | 672 |
|
673 | 673 |
int32_t cli_bcapi_matchicon(struct cli_bc_ctx *ctx, const uint8_t *grp1, int32_t grp1len, |
... | ... |
@@ -700,7 +732,7 @@ int32_t cli_bcapi_matchicon(struct cli_bc_ctx *ctx, const uint8_t *grp1, int32_t |
700 | 700 |
info.res_addr = le32_to_host(ctx->hooks.pedata->dirs[2].VirtualAddress); |
701 | 701 |
} else |
702 | 702 |
info.res_addr = ctx->resaddr; /* from target_info */ |
703 |
- info.section = (struct cli_exe_section *)ctx->sections; |
|
703 |
+ info.sections = (struct cli_exe_section *)ctx->sections; |
|
704 | 704 |
info.nsections = ctx->hooks.pedata->nsections; |
705 | 705 |
info.hdr_size = ctx->hooks.pedata->hdr_size; |
706 | 706 |
cli_dbgmsg("bytecode matchicon %s %s\n", group1, group2); |
... | ... |
@@ -939,14 +971,12 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
939 | 939 |
maxpatlen = groot->maxpatlen; |
940 | 940 |
} |
941 | 941 |
|
942 |
+ cli_targetinfo_init(&info); |
|
942 | 943 |
cli_targetinfo(&info, i, map); |
943 | 944 |
|
944 | 945 |
if (!ftonly) { |
945 | 946 |
if ((ret = cli_ac_initdata(&gdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) || (ret = cli_ac_caloff(groot, &gdata, &info))) { |
946 |
- if (info.exeinfo.section) |
|
947 |
- free(info.exeinfo.section); |
|
948 |
- |
|
949 |
- cli_hashset_destroy(&info.exeinfo.vinfo); |
|
947 |
+ cli_targetinfo_destroy(&info); |
|
950 | 948 |
cl_hash_destroy(md5ctx); |
951 | 949 |
cl_hash_destroy(sha1ctx); |
952 | 950 |
cl_hash_destroy(sha256ctx); |
... | ... |
@@ -954,10 +984,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
954 | 954 |
} |
955 | 955 |
if ((ret = cli_pcre_recaloff(groot, &gpoff, &info, ctx))) { |
956 | 956 |
cli_ac_freedata(&gdata); |
957 |
- if (info.exeinfo.section) |
|
958 |
- free(info.exeinfo.section); |
|
959 |
- |
|
960 |
- cli_hashset_destroy(&info.exeinfo.vinfo); |
|
957 |
+ cli_targetinfo_destroy(&info); |
|
961 | 958 |
cl_hash_destroy(md5ctx); |
962 | 959 |
cl_hash_destroy(sha1ctx); |
963 | 960 |
cl_hash_destroy(sha256ctx); |
... | ... |
@@ -971,10 +998,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
971 | 971 |
cli_ac_freedata(&gdata); |
972 | 972 |
cli_pcre_freeoff(&gpoff); |
973 | 973 |
} |
974 |
- if (info.exeinfo.section) |
|
975 |
- free(info.exeinfo.section); |
|
976 |
- |
|
977 |
- cli_hashset_destroy(&info.exeinfo.vinfo); |
|
974 |
+ cli_targetinfo_destroy(&info); |
|
978 | 975 |
cl_hash_destroy(md5ctx); |
979 | 976 |
cl_hash_destroy(sha1ctx); |
980 | 977 |
cl_hash_destroy(sha256ctx); |
... | ... |
@@ -989,10 +1013,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
989 | 989 |
} |
990 | 990 |
|
991 | 991 |
cli_ac_freedata(&tdata); |
992 |
- if (info.exeinfo.section) |
|
993 |
- free(info.exeinfo.section); |
|
994 |
- |
|
995 |
- cli_hashset_destroy(&info.exeinfo.vinfo); |
|
992 |
+ cli_targetinfo_destroy(&info); |
|
996 | 993 |
cl_hash_destroy(md5ctx); |
997 | 994 |
cl_hash_destroy(sha1ctx); |
998 | 995 |
cl_hash_destroy(sha256ctx); |
... | ... |
@@ -1011,10 +1032,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
1011 | 1011 |
cli_ac_freedata(&tdata); |
1012 | 1012 |
if (bm_offmode) |
1013 | 1013 |
cli_bm_freeoff(&toff); |
1014 |
- if (info.exeinfo.section) |
|
1015 |
- free(info.exeinfo.section); |
|
1016 |
- |
|
1017 |
- cli_hashset_destroy(&info.exeinfo.vinfo); |
|
1014 |
+ cli_targetinfo_destroy(&info); |
|
1018 | 1015 |
cl_hash_destroy(md5ctx); |
1019 | 1016 |
cl_hash_destroy(sha1ctx); |
1020 | 1017 |
cl_hash_destroy(sha256ctx); |
... | ... |
@@ -1076,10 +1094,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
1076 | 1076 |
cli_bm_freeoff(&toff); |
1077 | 1077 |
cli_pcre_freeoff(&tpoff); |
1078 | 1078 |
|
1079 |
- if (info.exeinfo.section) |
|
1080 |
- free(info.exeinfo.section); |
|
1081 |
- |
|
1082 |
- cli_hashset_destroy(&info.exeinfo.vinfo); |
|
1079 |
+ cli_targetinfo_destroy(&info); |
|
1083 | 1080 |
cl_hash_destroy(md5ctx); |
1084 | 1081 |
cl_hash_destroy(sha1ctx); |
1085 | 1082 |
cl_hash_destroy(sha256ctx); |
... | ... |
@@ -1105,10 +1120,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
1105 | 1105 |
cli_pcre_freeoff(&tpoff); |
1106 | 1106 |
} |
1107 | 1107 |
|
1108 |
- if (info.exeinfo.section) |
|
1109 |
- free(info.exeinfo.section); |
|
1110 |
- |
|
1111 |
- cli_hashset_destroy(&info.exeinfo.vinfo); |
|
1108 |
+ cli_targetinfo_destroy(&info); |
|
1112 | 1109 |
cl_hash_destroy(md5ctx); |
1113 | 1110 |
cl_hash_destroy(sha1ctx); |
1114 | 1111 |
cl_hash_destroy(sha256ctx); |
... | ... |
@@ -1233,10 +1245,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli |
1233 | 1233 |
cli_pcre_freeoff(&gpoff); |
1234 | 1234 |
} |
1235 | 1235 |
|
1236 |
- if (info.exeinfo.section) |
|
1237 |
- free(info.exeinfo.section); |
|
1238 |
- |
|
1239 |
- cli_hashset_destroy(&info.exeinfo.vinfo); |
|
1236 |
+ cli_targetinfo_destroy(&info); |
|
1240 | 1237 |
|
1241 | 1238 |
if (SCAN_ALLMATCHES && viruses_found) { |
1242 | 1239 |
return CL_VIRUS; |
... | ... |
@@ -35,6 +35,9 @@ struct cli_target_info { |
35 | 35 |
int status; /* 0 == not initialised, 1 == initialised OK, -1 == error */ |
36 | 36 |
}; |
37 | 37 |
|
38 |
+void cli_targetinfo_init(struct cli_target_info *info); |
|
39 |
+void cli_targetinfo_destroy(struct cli_target_info *info); |
|
40 |
+ |
|
38 | 41 |
#include "matcher-ac.h" |
39 | 42 |
#include "matcher-bm.h" |
40 | 43 |
#include "matcher-hash.h" |
... | ... |
@@ -94,9 +94,7 @@ |
94 | 94 |
#define PE_IMAGE_NT_SIGNATURE 0x00004550 |
95 | 95 |
#define PE32_SIGNATURE 0x010b |
96 | 96 |
#define PE32P_SIGNATURE 0x020b |
97 |
- |
|
98 |
-#define optional_hdr64 pe_opt.opt64 |
|
99 |
-#define optional_hdr32 pe_opt.opt32 |
|
97 |
+#define OPT_HDR_SIZE_DIFF (sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) |
|
100 | 98 |
|
101 | 99 |
#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" |
102 | 100 |
#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" |
... | ... |
@@ -119,20 +117,23 @@ |
119 | 119 |
#define PEALIGN(o, a) (((a)) ? (((o) / (a)) * (a)) : (o)) |
120 | 120 |
#define PESALIGN(o, a) (((a)) ? (((o) / (a) + ((o) % (a) != 0)) * (a)) : (o)) |
121 | 121 |
|
122 |
+// TODO Replace all of these with static inline functions |
|
122 | 123 |
#define CLI_UNPSIZELIMITS(NAME, CHK) \ |
123 | 124 |
if (cli_checklimits(NAME, ctx, (CHK), 0, 0) != CL_CLEAN) { \ |
124 |
- free(exe_sections); \ |
|
125 |
+ cli_exe_info_destroy(peinfo); \ |
|
125 | 126 |
return CL_CLEAN; \ |
126 | 127 |
} |
127 | 128 |
|
128 | 129 |
#define CLI_UNPTEMP(NAME, FREEME) \ |
129 | 130 |
if (!(tempfile = cli_gentemp(ctx->engine->tmpdir))) { \ |
131 |
+ cli_exe_info_destroy(peinfo); \ |
|
130 | 132 |
cli_multifree FREEME; \ |
131 | 133 |
return CL_EMEM; \ |
132 | 134 |
} \ |
133 | 135 |
if ((ndesc = open(tempfile, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, S_IRWXU)) < 0) { \ |
134 | 136 |
cli_dbgmsg(NAME ": Can't create file %s\n", tempfile); \ |
135 | 137 |
free(tempfile); \ |
138 |
+ cli_exe_info_destroy(peinfo); \ |
|
136 | 139 |
cli_multifree FREEME; \ |
137 | 140 |
return CL_ECREAT; \ |
138 | 141 |
} |
... | ... |
@@ -168,7 +169,7 @@ |
168 | 168 |
cli_dbgmsg(NAME ": Successfully decompressed\n"); \ |
169 | 169 |
close(ndesc); \ |
170 | 170 |
if (cli_unlink(tempfile)) { \ |
171 |
- free(exe_sections); \ |
|
171 |
+ cli_exe_info_destroy(peinfo); \ |
|
172 | 172 |
free(tempfile); \ |
173 | 173 |
FREESEC; \ |
174 | 174 |
return CL_EUNLINK; \ |
... | ... |
@@ -179,17 +180,17 @@ |
179 | 179 |
upx_success = 1; \ |
180 | 180 |
break; /* FSG ONLY! - scan raw data after upx block */ |
181 | 181 |
|
182 |
-#define SPINCASE() \ |
|
183 |
- case 2: \ |
|
184 |
- free(spinned); \ |
|
185 |
- close(ndesc); \ |
|
186 |
- if (cli_unlink(tempfile)) { \ |
|
187 |
- free(exe_sections); \ |
|
188 |
- free(tempfile); \ |
|
189 |
- return CL_EUNLINK; \ |
|
190 |
- } \ |
|
191 |
- cli_dbgmsg("PESpin: Size exceeded\n"); \ |
|
192 |
- free(tempfile); \ |
|
182 |
+#define SPINCASE() \ |
|
183 |
+ case 2: \ |
|
184 |
+ free(spinned); \ |
|
185 |
+ close(ndesc); \ |
|
186 |
+ if (cli_unlink(tempfile)) { \ |
|
187 |
+ cli_exe_info_destroy(peinfo); \ |
|
188 |
+ free(tempfile); \ |
|
189 |
+ return CL_EUNLINK; \ |
|
190 |
+ } \ |
|
191 |
+ cli_dbgmsg("cli_scanpe: PESpin: Size exceeded\n"); \ |
|
192 |
+ free(tempfile); \ |
|
193 | 193 |
break; |
194 | 194 |
|
195 | 195 |
#define CLI_UNPRESULTS_(NAME, FSGSTUFF, EXPR, GOOD, FREEME) \ |
... | ... |
@@ -200,15 +201,15 @@ |
200 | 200 |
else \ |
201 | 201 |
cli_dbgmsg(NAME ": Unpacked and rebuilt executable\n"); \ |
202 | 202 |
cli_multifree FREEME; \ |
203 |
- free(exe_sections); \ |
|
203 |
+ cli_exe_info_destroy(peinfo); \ |
|
204 | 204 |
lseek(ndesc, 0, SEEK_SET); \ |
205 | 205 |
cli_dbgmsg("***** Scanning rebuilt PE file *****\n"); \ |
206 | 206 |
SHA_OFF; \ |
207 | 207 |
if (cli_magic_scandesc(ndesc, tempfile, ctx) == CL_VIRUS) { \ |
208 | 208 |
close(ndesc); \ |
209 |
+ SHA_RESET; \ |
|
209 | 210 |
CLI_TMPUNLK(); \ |
210 | 211 |
free(tempfile); \ |
211 |
- SHA_RESET; \ |
|
212 | 212 |
return CL_VIRUS; \ |
213 | 213 |
} \ |
214 | 214 |
SHA_RESET; \ |
... | ... |
@@ -223,7 +224,7 @@ |
223 | 223 |
cli_dbgmsg(NAME ": Unpacking failed\n"); \ |
224 | 224 |
close(ndesc); \ |
225 | 225 |
if (cli_unlink(tempfile)) { \ |
226 |
- free(exe_sections); \ |
|
226 |
+ cli_exe_info_destroy(peinfo); \ |
|
227 | 227 |
free(tempfile); \ |
228 | 228 |
cli_multifree FREEME; \ |
229 | 229 |
return CL_EUNLINK; \ |
... | ... |
@@ -233,6 +234,9 @@ |
233 | 233 |
} |
234 | 234 |
|
235 | 235 |
#define CLI_UNPRESULTS(NAME, EXPR, GOOD, FREEME) CLI_UNPRESULTS_(NAME, (void)0, EXPR, GOOD, FREEME) |
236 |
+// TODO The second argument to FSGCASE below should match what gets freed as |
|
237 |
+// indicated by FREEME, otherwise a memory leak can occur (as currently used, |
|
238 |
+// it looks like dest can get leaked by these macros). |
|
236 | 239 |
#define CLI_UNPRESULTSFSG1(NAME, EXPR, GOOD, FREEME) CLI_UNPRESULTS_(NAME, FSGCASE(NAME, free(sections)), EXPR, GOOD, FREEME) |
237 | 240 |
#define CLI_UNPRESULTSFSG2(NAME, EXPR, GOOD, FREEME) CLI_UNPRESULTS_(NAME, FSGCASE(NAME, (void)0), EXPR, GOOD, FREEME) |
238 | 241 |
|
... | ... |
@@ -308,6 +312,8 @@ static int versioninfo_cb(void *opaque, uint32_t type, uint32_t name, uint32_t l |
308 | 308 |
return 0; |
309 | 309 |
} |
310 | 310 |
|
311 |
+/* Given an RVA (relative to the ImageBase), return the file offset of the |
|
312 |
+ * corresponding data */ |
|
311 | 313 |
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) |
312 | 314 |
{ |
313 | 315 |
int i, found = 0; |
... | ... |
@@ -324,7 +330,7 @@ uint32_t cli_rawaddr(uint32_t rva, const struct cli_exe_section *shp, uint16_t n |
324 | 324 |
} |
325 | 325 |
|
326 | 326 |
for (i = nos - 1; i >= 0; i--) { |
327 |
- if (shp[i].rsz && shp[i].rva <= rva && shp[i].rsz > rva - shp[i].rva) { |
|
327 |
+ if (shp[i].rsz && shp[i].rva <= rva && shp[i].rsz > (rva - shp[i].rva)) { |
|
328 | 328 |
found = 1; |
329 | 329 |
break; |
330 | 330 |
} |
... | ... |
@@ -335,19 +341,19 @@ uint32_t cli_rawaddr(uint32_t rva, const struct cli_exe_section *shp, uint16_t n |
335 | 335 |
return 0; |
336 | 336 |
} |
337 | 337 |
|
338 |
- ret = rva - shp[i].rva + shp[i].raw; |
|
338 |
+ ret = (rva - shp[i].rva) + shp[i].raw; |
|
339 | 339 |
*err = 0; |
340 | 340 |
return ret; |
341 | 341 |
} |
342 | 342 |
|
343 | 343 |
/* |
344 |
- void findres(uint32_t by_type, uint32_t by_name, uint32_t res_rva, cli_ctx *ctx, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size, int (*cb)(void *, uint32_t, uint32_t, uint32_t, uint32_t), void *opaque) |
|
344 |
+ 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) |
|
345 | 345 |
callback based res lookup |
346 | 346 |
|
347 | 347 |
by_type: lookup type |
348 | 348 |
by_name: lookup name or (unsigned)-1 to look for any name |
349 | 349 |
res_rva: base resource rva (i.e. dirs[2].VirtualAddress) |
350 |
- ctx, exe_sections, nsections, hdr_size: same as in scanpe |
|
350 |
+ map, peinfo: same as in scanpe |
|
351 | 351 |
cb: the callback function executed on each successful match |
352 | 352 |
opaque: an opaque pointer passed to the callback |
353 | 353 |
|
... | ... |
@@ -355,14 +361,21 @@ uint32_t cli_rawaddr(uint32_t rva, const struct cli_exe_section *shp, uint16_t n |
355 | 355 |
int pe_res_cballback (void *opaque, uint32_t type, uint32_t name, uint32_t lang, uint32_t rva); |
356 | 356 |
the callback shall return 0 to continue the lookup or 1 to abort |
357 | 357 |
*/ |
358 |
-void findres(uint32_t by_type, uint32_t by_name, uint32_t res_rva, fmap_t *map, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size, int (*cb)(void *, uint32_t, uint32_t, uint32_t, uint32_t), void *opaque) |
|
358 |
+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) |
|
359 | 359 |
{ |
360 | 360 |
unsigned int err = 0; |
361 | 361 |
uint32_t type, type_offs, name, name_offs, lang, lang_offs; |
362 | 362 |
const uint8_t *resdir, *type_entry, *name_entry, *lang_entry; |
363 | 363 |
uint16_t type_cnt, name_cnt, lang_cnt; |
364 |
+ uint32_t res_rva; |
|
365 |
+ |
|
366 |
+ if (NULL == peinfo || peinfo->ndatadirs < 3) { |
|
367 |
+ return; |
|
368 |
+ } |
|
364 | 369 |
|
365 |
- if (!(resdir = fmap_need_off_once(map, cli_rawaddr(res_rva, exe_sections, nsections, &err, map->len, hdr_size), 16)) || err) |
|
370 |
+ res_rva = EC32(peinfo->dirs[2].VirtualAddress); |
|
371 |
+ |
|
372 |
+ if (!(resdir = fmap_need_off_once(map, cli_rawaddr(res_rva, peinfo->sections, peinfo->nsections, &err, map->len, peinfo->hdr_size), 16)) || err) |
|
366 | 373 |
return; |
367 | 374 |
|
368 | 375 |
type_cnt = (uint16_t)cli_readint16(resdir + 12); |
... | ... |
@@ -379,7 +392,7 @@ void findres(uint32_t by_type, uint32_t by_name, uint32_t res_rva, fmap_t *map, |
379 | 379 |
type_offs = cli_readint32(type_entry + 4); |
380 | 380 |
if (type == by_type && (type_offs >> 31)) { |
381 | 381 |
type_offs &= 0x7fffffff; |
382 |
- if (!(resdir = fmap_need_off_once(map, cli_rawaddr(res_rva + type_offs, exe_sections, nsections, &err, map->len, hdr_size), 16)) || err) |
|
382 |
+ 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) |
|
383 | 383 |
return; |
384 | 384 |
|
385 | 385 |
name_cnt = (uint16_t)cli_readint16(resdir + 12); |
... | ... |
@@ -397,7 +410,7 @@ void findres(uint32_t by_type, uint32_t by_name, uint32_t res_rva, fmap_t *map, |
397 | 397 |
name_offs = cli_readint32(name_entry + 4); |
398 | 398 |
if ((by_name == 0xffffffff || name == by_name) && (name_offs >> 31)) { |
399 | 399 |
name_offs &= 0x7fffffff; |
400 |
- if (!(resdir = fmap_need_off_once(map, cli_rawaddr(res_rva + name_offs, exe_sections, nsections, &err, map->len, hdr_size), 16)) || err) |
|
400 |
+ 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) |
|
401 | 401 |
return; |
402 | 402 |
|
403 | 403 |
lang_cnt = (uint16_t)cli_readint16(resdir + 12) + (uint16_t)cli_readint16(resdir + 14); |
... | ... |
@@ -422,13 +435,13 @@ void findres(uint32_t by_type, uint32_t by_name, uint32_t res_rva, fmap_t *map, |
422 | 422 |
} |
423 | 423 |
} |
424 | 424 |
|
425 |
-static void cli_parseres_special(uint32_t base, uint32_t rva, fmap_t *map, struct cli_exe_section *exe_sections, uint16_t nsections, size_t fsize, uint32_t hdr_size, unsigned int level, uint32_t type, unsigned int *maxres, struct swizz_stats *stats) |
|
425 |
+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) |
|
426 | 426 |
{ |
427 | 427 |
unsigned int err = 0, i; |
428 | 428 |
const uint8_t *resdir; |
429 | 429 |
const uint8_t *entry, *oentry; |
430 | 430 |
uint16_t named, unnamed; |
431 |
- uint32_t rawaddr = cli_rawaddr(rva, exe_sections, nsections, &err, fsize, hdr_size); |
|
431 |
+ uint32_t rawaddr = cli_rawaddr(rva, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size); |
|
432 | 432 |
uint32_t entries; |
433 | 433 |
|
434 | 434 |
if (level > 2 || !*maxres) return; |
... | ... |
@@ -453,7 +466,7 @@ static void cli_parseres_special(uint32_t base, uint32_t rva, fmap_t *map, struc |
453 | 453 |
id = cli_readint32(entry); |
454 | 454 |
offs = cli_readint32(entry+4); |
455 | 455 |
if(offs>>31) |
456 |
- cli_parseres( base, base + (offs&0x7fffffff), srcfd, exe_sections, nsections, fsize, hdr_size, level+1, type, maxres, stats); |
|
456 |
+ cli_parseres( base, base + (offs&0x7fffffff), srcfd, peinfo, fsize, level+1, type, maxres, stats); |
|
457 | 457 |
entry+=8; |
458 | 458 |
}*/ |
459 | 459 |
for (i = 0; i < unnamed; i++, entry += 8) { |
... | ... |
@@ -489,14 +502,14 @@ static void cli_parseres_special(uint32_t base, uint32_t rva, fmap_t *map, struc |
489 | 489 |
} |
490 | 490 |
offs = cli_readint32(entry + 4); |
491 | 491 |
if (offs >> 31) |
492 |
- cli_parseres_special(base, base + (offs & 0x7fffffff), map, exe_sections, nsections, fsize, hdr_size, level + 1, type, maxres, stats); |
|
492 |
+ cli_parseres_special(base, base + (offs & 0x7fffffff), map, peinfo, fsize, level + 1, type, maxres, stats); |
|
493 | 493 |
else { |
494 | 494 |
offs = cli_readint32(entry + 4); |
495 |
- rawaddr = cli_rawaddr(base + offs, exe_sections, nsections, &err, fsize, hdr_size); |
|
495 |
+ rawaddr = cli_rawaddr(base + offs, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size); |
|
496 | 496 |
if (!err && (resdir = fmap_need_off_once(map, rawaddr, 16))) { |
497 | 497 |
uint32_t isz = cli_readint32(resdir + 4); |
498 | 498 |
const uint8_t *str; |
499 |
- rawaddr = cli_rawaddr(cli_readint32(resdir), exe_sections, nsections, &err, fsize, hdr_size); |
|
499 |
+ rawaddr = cli_rawaddr(cli_readint32(resdir), peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size); |
|
500 | 500 |
if (err || !isz || isz >= fsize || rawaddr + isz >= fsize) { |
501 | 501 |
cli_dbgmsg("cli_parseres_special: invalid resource table entry: %lu + %lu\n", |
502 | 502 |
(unsigned long)rawaddr, |
... | ... |
@@ -558,7 +571,7 @@ static int scan_pe_mdb(cli_ctx *ctx, struct cli_exe_section *exe_section) |
558 | 558 |
if (foundsize[type] || foundwild[type]) { |
559 | 559 |
hashset[type] = cli_malloc(hashlen[type]); |
560 | 560 |
if (!hashset[type]) { |
561 |
- cli_errmsg("scan_pe: cli_malloc failed!\n"); |
|
561 |
+ cli_errmsg("scan_pe_mdb: cli_malloc failed!\n"); |
|
562 | 562 |
for (; type > 0;) |
563 | 563 |
free(hashset[--type]); |
564 | 564 |
return CL_EMEM; |
... | ... |
@@ -2228,7 +2241,7 @@ static int validate_impname(const char *name, uint32_t length, int dll) |
2228 | 2228 |
return 1; |
2229 | 2229 |
} |
2230 | 2230 |
|
2231 |
-static inline int hash_impfns(cli_ctx *ctx, void **hashctx, uint32_t *impsz, struct pe_image_import_descriptor *image, const char *dllname, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size, int pe_plus, int *first) |
|
2231 |
+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) |
|
2232 | 2232 |
{ |
2233 | 2233 |
uint32_t thuoff = 0, offset; |
2234 | 2234 |
fmap_t *map = *ctx->fmap; |
... | ... |
@@ -2244,9 +2257,9 @@ static inline int hash_impfns(cli_ctx *ctx, void **hashctx, uint32_t *impsz, str |
2244 | 2244 |
#endif |
2245 | 2245 |
|
2246 | 2246 |
if (image->u.OriginalFirstThunk) |
2247 |
- thuoff = cli_rawaddr(image->u.OriginalFirstThunk, exe_sections, nsections, &err, fsize, hdr_size); |
|
2247 |
+ thuoff = cli_rawaddr(image->u.OriginalFirstThunk, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size); |
|
2248 | 2248 |
if (err || thuoff == 0) |
2249 |
- thuoff = cli_rawaddr(image->FirstThunk, exe_sections, nsections, &err, fsize, hdr_size); |
|
2249 |
+ thuoff = cli_rawaddr(image->FirstThunk, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size); |
|
2250 | 2250 |
if (err) { |
2251 | 2251 |
cli_dbgmsg("scan_pe: invalid rva for image first thunk\n"); |
2252 | 2252 |
return CL_EFORMAT; |
... | ... |
@@ -2316,7 +2329,7 @@ static inline int hash_impfns(cli_ctx *ctx, void **hashctx, uint32_t *impsz, str |
2316 | 2316 |
} \ |
2317 | 2317 |
} while (0) |
2318 | 2318 |
|
2319 |
- if (!pe_plus) { |
|
2319 |
+ if (!peinfo->is_pe32plus) { |
|
2320 | 2320 |
struct pe_image_thunk32 thunk32; |
2321 | 2321 |
|
2322 | 2322 |
while ((num_fns < PE_MAXIMPORTS) && (fmap_readn(map, &thunk32, thuoff, sizeof(struct pe_image_thunk32)) == sizeof(struct pe_image_thunk32)) && (thunk32.u.Ordinal != 0)) { |
... | ... |
@@ -2326,7 +2339,7 @@ static inline int hash_impfns(cli_ctx *ctx, void **hashctx, uint32_t *impsz, str |
2326 | 2326 |
thunk32.u.Ordinal = EC32(thunk32.u.Ordinal); |
2327 | 2327 |
|
2328 | 2328 |
if (!(thunk32.u.Ordinal & PE_IMAGEDIR_ORDINAL_FLAG32)) { |
2329 |
- offset = cli_rawaddr(thunk32.u.Function, exe_sections, nsections, &err, fsize, hdr_size); |
|
2329 |
+ offset = cli_rawaddr(thunk32.u.Function, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size); |
|
2330 | 2330 |
|
2331 | 2331 |
if (!ret) { |
2332 | 2332 |
/* Hint field is a uint16_t and precedes the Name field */ |
... | ... |
@@ -2362,7 +2375,7 @@ static inline int hash_impfns(cli_ctx *ctx, void **hashctx, uint32_t *impsz, str |
2362 | 2362 |
thunk64.u.Ordinal = EC64(thunk64.u.Ordinal); |
2363 | 2363 |
|
2364 | 2364 |
if (!(thunk64.u.Ordinal & PE_IMAGEDIR_ORDINAL_FLAG64)) { |
2365 |
- offset = cli_rawaddr(thunk64.u.Function, exe_sections, nsections, &err, fsize, hdr_size); |
|
2365 |
+ offset = cli_rawaddr(thunk64.u.Function, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size); |
|
2366 | 2366 |
|
2367 | 2367 |
if (!err) { |
2368 | 2368 |
/* Hint field is a uint16_t and precedes the Name field */ |
... | ... |
@@ -2393,7 +2406,7 @@ static inline int hash_impfns(cli_ctx *ctx, void **hashctx, uint32_t *impsz, str |
2393 | 2393 |
return CL_SUCCESS; |
2394 | 2394 |
} |
2395 | 2395 |
|
2396 |
-static unsigned int hash_imptbl(cli_ctx *ctx, unsigned char **digest, uint32_t *impsz, int *genhash, struct pe_image_data_dir *datadir, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size, int pe_plus) |
|
2396 |
+static unsigned int hash_imptbl(cli_ctx *ctx, unsigned char **digest, uint32_t *impsz, int *genhash, struct cli_exe_info *peinfo) |
|
2397 | 2397 |
{ |
2398 | 2398 |
struct pe_image_import_descriptor *image; |
2399 | 2399 |
fmap_t *map = *ctx->fmap; |
... | ... |
@@ -2406,43 +2419,45 @@ static unsigned int hash_imptbl(cli_ctx *ctx, unsigned char **digest, uint32_t * |
2406 | 2406 |
unsigned int err; |
2407 | 2407 |
int first = 1; |
2408 | 2408 |
|
2409 |
- if (datadir->VirtualAddress == 0 || datadir->Size == 0) { |
|
2409 |
+ if (peinfo->dirs[1].VirtualAddress == 0 || peinfo->dirs[1].Size == 0) { |
|
2410 | 2410 |
cli_errmsg("scan_pe: import table data directory does not exist\n"); |
2411 | 2411 |
return CL_SUCCESS; |
2412 | 2412 |
} |
2413 | 2413 |
|
2414 |
- impoff = cli_rawaddr(datadir->VirtualAddress, exe_sections, nsections, &err, fsize, hdr_size); |
|
2415 |
- if (err || impoff + datadir->Size > fsize) { |
|
2414 |
+ // TODO Add EC32 wrappers |
|
2415 |
+ impoff = cli_rawaddr(peinfo->dirs[1].VirtualAddress, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size); |
|
2416 |
+ if (err || impoff + peinfo->dirs[1].Size > fsize) { |
|
2416 | 2417 |
cli_dbgmsg("scan_pe: invalid rva for import table data\n"); |
2417 | 2418 |
return CL_SUCCESS; |
2418 | 2419 |
} |
2419 | 2420 |
|
2420 |
- impdes = fmap_need_off(map, impoff, datadir->Size); |
|
2421 |
+ // TODO Add EC32 wrapper |
|
2422 |
+ impdes = fmap_need_off(map, impoff, peinfo->dirs[1].Size); |
|
2421 | 2423 |
if (impdes == NULL) { |
2422 | 2424 |
cli_dbgmsg("scan_pe: failed to acquire fmap buffer\n"); |
2423 | 2425 |
return CL_EREAD; |
2424 | 2426 |
} |
2425 |
- left = datadir->Size; |
|
2427 |
+ left = peinfo->dirs[1].Size; |
|
2426 | 2428 |
|
2427 | 2429 |
memset(hashctx, 0, sizeof(hashctx)); |
2428 | 2430 |
if (genhash[CLI_HASH_MD5]) { |
2429 | 2431 |
hashctx[CLI_HASH_MD5] = cl_hash_init("md5"); |
2430 | 2432 |
if (hashctx[CLI_HASH_MD5] == NULL) { |
2431 |
- fmap_unneed_off(map, impoff, datadir->Size); |
|
2433 |
+ fmap_unneed_off(map, impoff, peinfo->dirs[1].Size); |
|
2432 | 2434 |
return CL_EMEM; |
2433 | 2435 |
} |
2434 | 2436 |
} |
2435 | 2437 |
if (genhash[CLI_HASH_SHA1]) { |
2436 | 2438 |
hashctx[CLI_HASH_SHA1] = cl_hash_init("sha1"); |
2437 | 2439 |
if (hashctx[CLI_HASH_SHA1] == NULL) { |
2438 |
- fmap_unneed_off(map, impoff, datadir->Size); |
|
2440 |
+ fmap_unneed_off(map, impoff, peinfo->dirs[1].Size); |
|
2439 | 2441 |
return CL_EMEM; |
2440 | 2442 |
} |
2441 | 2443 |
} |
2442 | 2444 |
if (genhash[CLI_HASH_SHA256]) { |
2443 | 2445 |
hashctx[CLI_HASH_SHA256] = cl_hash_init("sha256"); |
2444 | 2446 |
if (hashctx[CLI_HASH_SHA256] == NULL) { |
2445 |
- fmap_unneed_off(map, impoff, datadir->Size); |
|
2447 |
+ fmap_unneed_off(map, impoff, peinfo->dirs[1].Size); |
|
2446 | 2448 |
return CL_EMEM; |
2447 | 2449 |
} |
2448 | 2450 |
} |
... | ... |
@@ -2462,7 +2477,7 @@ static unsigned int hash_imptbl(cli_ctx *ctx, unsigned char **digest, uint32_t * |
2462 | 2462 |
image->FirstThunk = EC32(image->FirstThunk); |
2463 | 2463 |
|
2464 | 2464 |
/* DLL name acquisition */ |
2465 |
- offset = cli_rawaddr(image->Name, exe_sections, nsections, &err, fsize, hdr_size); |
|
2465 |
+ offset = cli_rawaddr(image->Name, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size); |
|
2466 | 2466 |
if (err || offset > fsize) { |
2467 | 2467 |
cli_dbgmsg("scan_pe: invalid rva for dll name\n"); |
2468 | 2468 |
/* TODO: ignore or return? */ |
... | ... |
@@ -2495,7 +2510,7 @@ static unsigned int hash_imptbl(cli_ctx *ctx, unsigned char **digest, uint32_t * |
2495 | 2495 |
} |
2496 | 2496 |
|
2497 | 2497 |
/* DLL function handling - inline function */ |
2498 |
- ret = hash_impfns(ctx, hashctx, impsz, image, dllname, exe_sections, nsections, hdr_size, pe_plus, &first); |
|
2498 |
+ ret = hash_impfns(ctx, hashctx, impsz, image, dllname, peinfo, &first); |
|
2499 | 2499 |
free(dllname); |
2500 | 2500 |
dllname = NULL; |
2501 | 2501 |
if (ret != CL_SUCCESS) |
... | ... |
@@ -2505,13 +2520,13 @@ static unsigned int hash_imptbl(cli_ctx *ctx, unsigned char **digest, uint32_t * |
2505 | 2505 |
} |
2506 | 2506 |
|
2507 | 2507 |
hash_imptbl_end: |
2508 |
- fmap_unneed_off(map, impoff, datadir->Size); |
|
2508 |
+ fmap_unneed_off(map, impoff, peinfo->dirs[1].Size); |
|
2509 | 2509 |
for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) |
2510 | 2510 |
cl_finish_hash(hashctx[type], digest[type]); |
2511 | 2511 |
return ret; |
2512 | 2512 |
} |
2513 | 2513 |
|
2514 |
-static int scan_pe_imp(cli_ctx *ctx, struct pe_image_data_dir *dirs, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size, int pe_plus) |
|
2514 |
+static int scan_pe_imp(cli_ctx *ctx, struct cli_exe_info *peinfo) |
|
2515 | 2515 |
{ |
2516 | 2516 |
struct cli_matcher *imp = ctx->engine->hm_imp; |
2517 | 2517 |
unsigned char *hashset[CLI_HASH_AVAIL_TYPES]; |
... | ... |
@@ -2554,7 +2569,7 @@ static int scan_pe_imp(cli_ctx *ctx, struct pe_image_data_dir *dirs, struct cli_ |
2554 | 2554 |
} |
2555 | 2555 |
|
2556 | 2556 |
/* Generate hashes */ |
2557 |
- ret = hash_imptbl(ctx, hashset, &impsz, genhash, &dirs[1], exe_sections, nsections, hdr_size, pe_plus); |
|
2557 |
+ ret = hash_imptbl(ctx, hashset, &impsz, genhash, peinfo); |
|
2558 | 2558 |
if (ret != CL_SUCCESS) { |
2559 | 2559 |
for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) |
2560 | 2560 |
free(hashset[type]); |
... | ... |
@@ -2719,44 +2734,27 @@ static void add_section_info(cli_ctx *ctx, struct cli_exe_section *s) |
2719 | 2719 |
|
2720 | 2720 |
int cli_scanpe(cli_ctx *ctx) |
2721 | 2721 |
{ |
2722 |
- uint16_t e_magic; /* DOS signature ("MZ") */ |
|
2723 |
- uint16_t nsections; |
|
2724 |
- uint32_t e_lfanew; /* address of new exe header */ |
|
2725 |
- uint32_t ep, vep; /* entry point (raw, virtual) */ |
|
2726 | 2722 |
uint8_t polipos = 0; |
2727 |
- time_t timestamp; |
|
2728 |
- struct pe_image_file_hdr file_hdr; |
|
2729 |
- union { |
|
2730 |
- struct pe_image_optional_hdr64 opt64; |
|
2731 |
- struct pe_image_optional_hdr32 opt32; |
|
2732 |
- } pe_opt; |
|
2733 |
- struct pe_image_section_hdr *section_hdr; |
|
2734 |
- char sname[9], epbuff[4096], *tempfile; |
|
2723 |
+ char epbuff[4096], *tempfile; |
|
2735 | 2724 |
uint32_t epsize; |
2736 |
- ssize_t bytes, at; |
|
2737 |
- unsigned int i, j, found, upx_success = 0, min = 0, max = 0, err, overlays = 0, rescan = 1; |
|
2738 |
- unsigned int ssize = 0, dsize = 0, dll = 0, pe_plus = 0, corrupted_cur; |
|
2725 |
+ ssize_t bytes; |
|
2726 |
+ unsigned int i, j, found, upx_success = 0, err; |
|
2727 |
+ unsigned int ssize = 0, dsize = 0, corrupted_cur; |
|
2739 | 2728 |
int (*upxfn)(const char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t) = NULL; |
2740 | 2729 |
const char *src = NULL; |
2741 | 2730 |
char *dest = NULL; |
2742 |
- int ndesc, ret = CL_CLEAN, upack = 0, native = 0; |
|
2731 |
+ int ndesc, ret = CL_CLEAN, upack = 0; |
|
2743 | 2732 |
size_t fsize; |
2744 |
- uint32_t valign, falign, hdr_size; |
|
2745 |
- struct cli_exe_section *exe_sections; |
|
2746 |
- char timestr[32]; |
|
2747 |
- struct pe_image_data_dir *dirs; |
|
2748 | 2733 |
struct cli_bc_ctx *bc_ctx; |
2749 | 2734 |
fmap_t *map; |
2750 | 2735 |
struct cli_pe_hook_data pedata; |
2751 | 2736 |
#ifdef HAVE__INTERNAL__SHA_COLLECT |
2752 | 2737 |
int sha_collect = ctx->sha_collect; |
2753 | 2738 |
#endif |
2754 |
- const char *archtype = NULL, *subsystem = NULL; |
|
2755 | 2739 |
uint32_t viruses_found = 0; |
2756 | 2740 |
#if HAVE_JSON |
2757 | 2741 |
int toval = 0; |
2758 | 2742 |
struct json_object *pe_json = NULL; |
2759 |
- char jsonbuf[128]; |
|
2760 | 2743 |
#endif |
2761 | 2744 |
|
2762 | 2745 |
if (!ctx) { |
... | ... |
@@ -2773,729 +2771,142 @@ int cli_scanpe(cli_ctx *ctx) |
2773 | 2773 |
pe_json = get_pe_property(ctx); |
2774 | 2774 |
} |
2775 | 2775 |
#endif |
2776 |
- map = *ctx->fmap; |
|
2777 |
- if (fmap_readn(map, &e_magic, 0, sizeof(e_magic)) != sizeof(e_magic)) { |
|
2778 |
- cli_dbgmsg("Can't read DOS signature\n"); |
|
2779 |
- return CL_CLEAN; |
|
2780 |
- } |
|
2781 |
- |
|
2782 |
- if (EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE && EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE_OLD) { |
|
2783 |
- cli_dbgmsg("Invalid DOS signature\n"); |
|
2784 |
- return CL_CLEAN; |
|
2785 |
- } |
|
2786 |
- |
|
2787 |
- if (fmap_readn(map, &e_lfanew, 58 + sizeof(e_magic), sizeof(e_lfanew)) != sizeof(e_lfanew)) { |
|
2788 |
- cli_dbgmsg("Can't read new header address\n"); |
|
2789 |
- /* truncated header? */ |
|
2790 |
- if (DETECT_BROKEN_PE) { |
|
2791 |
- ret = cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
|
2792 |
- return ret; |
|
2793 |
- } |
|
2794 |
- |
|
2795 |
- return CL_CLEAN; |
|
2796 |
- } |
|
2776 |
+ map = *ctx->fmap; |
|
2777 |
+ fsize = map->len; |
|
2797 | 2778 |
|
2798 |
- e_lfanew = EC32(e_lfanew); |
|
2799 |
- cli_dbgmsg("e_lfanew == %d\n", e_lfanew); |
|
2800 |
- if (!e_lfanew) { |
|
2801 |
- cli_dbgmsg("Not a PE file\n"); |
|
2802 |
- return CL_CLEAN; |
|
2803 |
- } |
|
2779 |
+ struct cli_exe_info _peinfo; |
|
2780 |
+ struct cli_exe_info *peinfo = &_peinfo; |
|
2804 | 2781 |
|
2805 |
- if (fmap_readn(map, &file_hdr, e_lfanew, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) { |
|
2806 |
- /* bad information in e_lfanew - probably not a PE file */ |
|
2807 |
- cli_dbgmsg("cli_scanpe: Can't read file header\n"); |
|
2808 |
- return CL_CLEAN; |
|
2809 |
- } |
|
2782 |
+ uint32_t opts = CLI_PEHEADER_OPT_DBG_PRINT_INFO; |
|
2783 |
+ ; |
|
2810 | 2784 |
|
2811 |
- if (EC32(file_hdr.Magic) != PE_IMAGE_NT_SIGNATURE) { |
|
2812 |
- cli_dbgmsg("Invalid PE signature (probably NE file)\n"); |
|
2813 |
- return CL_CLEAN; |
|
2814 |
- } |
|
2815 |
- |
|
2816 |
- if (EC16(file_hdr.Characteristics) & 0x2000) { |
|
2817 | 2785 |
#if HAVE_JSON |
2818 |
- if (pe_json != NULL) |
|
2819 |
- cli_jsonstr(pe_json, "Type", "DLL"); |
|
2820 |
-#endif |
|
2821 |
- cli_dbgmsg("File type: DLL\n"); |
|
2822 |
- dll = 1; |
|
2823 |
- } else if (EC16(file_hdr.Characteristics) & 0x01) { |
|
2824 |
-#if HAVE_JSON |
|
2825 |
- if (pe_json != NULL) |
|
2826 |
- cli_jsonstr(pe_json, "Type", "EXE"); |
|
2827 |
-#endif |
|
2828 |
- cli_dbgmsg("File type: Executable\n"); |
|
2829 |
- } |
|
2830 |
- |
|
2831 |
- switch (EC16(file_hdr.Machine)) { |
|
2832 |
- case 0x0: |
|
2833 |
- archtype = "Unknown"; |
|
2834 |
- break; |
|
2835 |
- case 0x14c: |
|
2836 |
- archtype = "80386"; |
|
2837 |
- break; |
|
2838 |
- case 0x14d: |
|
2839 |
- archtype = "80486"; |
|
2840 |
- break; |
|
2841 |
- case 0x14e: |
|
2842 |
- archtype = "80586"; |
|
2843 |
- break; |
|
2844 |
- case 0x160: |
|
2845 |
- archtype = "R30000 (big-endian)"; |
|
2846 |
- break; |
|
2847 |
- case 0x162: |
|
2848 |
- archtype = "R3000"; |
|
2849 |
- break; |
|
2850 |
- case 0x166: |
|
2851 |
- archtype = "R4000"; |
|
2852 |
- break; |
|
2853 |
- case 0x168: |
|
2854 |
- archtype = "R10000"; |
|
2855 |
- break; |
|
2856 |
- case 0x184: |
|
2857 |
- archtype = "DEC Alpha AXP"; |
|
2858 |
- break; |
|
2859 |
- case 0x284: |
|
2860 |
- archtype = "DEC Alpha AXP 64bit"; |
|
2861 |
- break; |
|
2862 |
- case 0x1f0: |
|
2863 |
- archtype = "PowerPC"; |
|
2864 |
- break; |
|
2865 |
- case 0x200: |
|
2866 |
- archtype = "IA64"; |
|
2867 |
- break; |
|
2868 |
- case 0x268: |
|
2869 |
- archtype = "M68k"; |
|
2870 |
- break; |
|
2871 |
- case 0x266: |
|
2872 |
- archtype = "MIPS16"; |
|
2873 |
- break; |
|
2874 |
- case 0x366: |
|
2875 |
- archtype = "MIPS+FPU"; |
|
2876 |
- break; |
|
2877 |
- case 0x466: |
|
2878 |
- archtype = "MIPS16+FPU"; |
|
2879 |
- break; |
|
2880 |
- case 0x1a2: |
|
2881 |
- archtype = "Hitachi SH3"; |
|
2882 |
- break; |
|
2883 |
- case 0x1a3: |
|
2884 |
- archtype = "Hitachi SH3-DSP"; |
|
2885 |
- break; |
|
2886 |
- case 0x1a4: |
|
2887 |
- archtype = "Hitachi SH3-E"; |
|
2888 |
- break; |
|
2889 |
- case 0x1a6: |
|
2890 |
- archtype = "Hitachi SH4"; |
|
2891 |
- break; |
|
2892 |
- case 0x1a8: |
|
2893 |
- archtype = "Hitachi SH5"; |
|
2894 |
- break; |
|
2895 |
- case 0x1c0: |
|
2896 |
- archtype = "ARM"; |
|
2897 |
- break; |
|
2898 |
- case 0x1c2: |
|
2899 |
- archtype = "THUMB"; |
|
2900 |
- break; |
|
2901 |
- case 0x1d3: |
|
2902 |
- archtype = "AM33"; |
|
2903 |
- break; |
|
2904 |
- case 0x520: |
|
2905 |
- archtype = "Infineon TriCore"; |
|
2906 |
- break; |
|
2907 |
- case 0xcef: |
|
2908 |
- archtype = "CEF"; |
|
2909 |
- break; |
|
2910 |
- case 0xebc: |
|
2911 |
- archtype = "EFI Byte Code"; |
|
2912 |
- break; |
|
2913 |
- case 0x9041: |
|
2914 |
- archtype = "M32R"; |
|
2915 |
- break; |
|
2916 |
- case 0xc0ee: |
|
2917 |
- archtype = "CEEE"; |
|
2918 |
- break; |
|
2919 |
- case 0x8664: |
|
2920 |
- archtype = "AMD64"; |
|
2921 |
- break; |
|
2922 |
- default: |
|
2923 |
- archtype = "Unknown"; |
|
2924 |
- } |
|
2925 |
- |
|
2926 |
- if ((archtype)) { |
|
2927 |
- cli_dbgmsg("Machine type: %s\n", archtype); |
|
2928 |
-#if HAVE_JSON |
|
2929 |
- if (pe_json != NULL) |
|
2930 |
- cli_jsonstr(pe_json, "ArchType", archtype); |
|
2931 |
-#endif |
|
2786 |
+ if (SCAN_COLLECT_METADATA) { |
|
2787 |
+ opts |= CLI_PEHEADER_OPT_COLLECT_JSON; |
|
2932 | 2788 |
} |
2933 |
- |
|
2934 |
- nsections = EC16(file_hdr.NumberOfSections); |
|
2935 |
- if (nsections < 1 || nsections > PE_MAXSECTIONS) { |
|
2936 |
-#if HAVE_JSON |
|
2937 |
- pe_add_heuristic_property(ctx, "BadNumberOfSections"); |
|
2938 | 2789 |
#endif |
2939 |
- if (DETECT_BROKEN_PE) { |
|
2940 |
- ret = cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
|
2941 |
- return ret; |
|
2942 |
- } |
|
2943 |
- |
|
2944 |
- if (!ctx->corrupted_input) { |
|
2945 |
- if (nsections) |
|
2946 |
- cli_warnmsg("PE file contains %d sections\n", nsections); |
|
2947 |
- else |
|
2948 |
- cli_warnmsg("PE file contains no sections\n"); |
|
2949 |
- } |
|
2950 | 2790 |
|
2951 |
- return CL_CLEAN; |
|
2791 |
+ if (DETECT_BROKEN_PE) { |
|
2792 |
+ opts |= CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS; |
|
2952 | 2793 |
} |
2953 | 2794 |
|
2954 |
- cli_dbgmsg("NumberOfSections: %d\n", nsections); |
|
2795 |
+ cli_exe_info_init(peinfo, 0); |
|
2955 | 2796 |
|
2956 |
- timestamp = (time_t)EC32(file_hdr.TimeDateStamp); |
|
2957 |
- cli_dbgmsg("TimeDateStamp: %s", cli_ctime(×tamp, timestr, sizeof(timestr))); |
|
2958 |
- |
|
2959 |
-#if HAVE_JSON |
|
2960 |
- if (pe_json != NULL) |
|
2961 |
- cli_jsonstr(pe_json, "TimeDateStamp", cli_ctime(×tamp, timestr, sizeof(timestr))); |
|
2962 |
-#endif |
|
2797 |
+ ret = cli_peheader(map, peinfo, opts, ctx); |
|
2963 | 2798 |
|
2964 |
- cli_dbgmsg("SizeOfOptionalHeader: %x\n", EC16(file_hdr.SizeOfOptionalHeader)); |
|
2799 |
+ // Warn the user if PE header parsing failed - if it's a binary that runs |
|
2800 |
+ // successfully on Windows, we need to relax our PE parsing standards so |
|
2801 |
+ // that we make sure the executable gets scanned appropriately |
|
2965 | 2802 |
|
2966 |
-#if HAVE_JSON |
|
2967 |
- if (pe_json != NULL) |
|
2968 |
- cli_jsonint(pe_json, "SizeOfOptionalHeader", EC16(file_hdr.SizeOfOptionalHeader)); |
|
2969 |
-#endif |
|
2803 |
+#define PE_HDR_PARSE_FAIL_CONSEQUENCE "won't attempt .mdb / .imp / PE-specific BC rule matching or exe unpacking\n" |
|
2970 | 2804 |
|
2971 |
- if (EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) { |
|
2972 |
-#if HAVE_JSON |
|
2973 |
- pe_add_heuristic_property(ctx, "BadOptionalHeaderSize"); |
|
2974 |
-#endif |
|
2975 |
- cli_dbgmsg("SizeOfOptionalHeader too small\n"); |
|
2805 |
+ if (CLI_PEHEADER_RET_BROKEN_PE == ret) { |
|
2976 | 2806 |
if (DETECT_BROKEN_PE) { |
2807 |
+ // TODO Handle allmatch |
|
2977 | 2808 |
ret = cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
2978 | 2809 |
return ret; |
2979 | 2810 |
} |
2980 |
- |
|
2811 |
+ cli_dbgmsg("cli_scanpe: PE header appears broken - " PE_HDR_PARSE_FAIL_CONSEQUENCE); |
|
2981 | 2812 |
return CL_CLEAN; |
2982 |
- } |
|
2983 |
- |
|
2984 |
- at = e_lfanew + sizeof(struct pe_image_file_hdr); |
|
2985 |
- if (fmap_readn(map, &optional_hdr32, at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) { |
|
2986 |
- cli_dbgmsg("Can't read optional file header\n"); |
|
2987 |
- if (DETECT_BROKEN_PE) { |
|
2988 |
- ret = cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
|
2989 |
- return ret; |
|
2990 |
- } |
|
2991 | 2813 |
|
2814 |
+ } else if (CLI_PEHEADER_RET_JSON_TIMEOUT == ret) { |
|
2815 |
+ cli_dbgmsg("cli_scanpe: JSON creation timed out - " PE_HDR_PARSE_FAIL_CONSEQUENCE); |
|
2816 |
+ return CL_ETIMEOUT; |
|
2817 |
+ } else if (CLI_PEHEADER_RET_GENERIC_ERROR == ret) { |
|
2818 |
+ cli_dbgmsg("cli_scanpe: An error occurred when parsing the PE header - " PE_HDR_PARSE_FAIL_CONSEQUENCE); |
|
2992 | 2819 |
return CL_CLEAN; |
2993 | 2820 |
} |
2994 |
- at += sizeof(struct pe_image_optional_hdr32); |
|
2995 |
- |
|
2996 |
- /* This will be a chicken and egg problem until we drop 9x */ |
|
2997 |
- if (EC16(optional_hdr64.Magic) == PE32P_SIGNATURE) { |
|
2998 |
-#if HAVE_JSON |
|
2999 |
- pe_add_heuristic_property(ctx, "BadOptionalHeaderSizePE32Plus"); |
|
3000 |
-#endif |
|
3001 |
- if (EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr64)) { |
|
3002 |
- /* FIXME: need to play around a bit more with xp64 */ |
|
3003 |
- cli_dbgmsg("Incorrect SizeOfOptionalHeader for PE32+\n"); |
|
3004 |
- |
|
3005 |
- if (DETECT_BROKEN_PE) { |
|
3006 |
- ret = cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
|
3007 |
- return ret; |
|
3008 |
- } |
|
3009 |
- |
|
3010 |
- return CL_CLEAN; |
|
3011 |
- } |
|
3012 |
- pe_plus = 1; |
|
3013 |
- } |
|
3014 |
- |
|
3015 |
- if (!pe_plus) { /* PE */ |
|
3016 |
- if (EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr32)) { |
|
3017 |
- /* Seek to the end of the long header */ |
|
3018 |
- at += EC16(file_hdr.SizeOfOptionalHeader) - sizeof(struct pe_image_optional_hdr32); |
|
3019 |
- } |
|
3020 | 2821 |
|
2822 |
+ if (!peinfo->is_pe32plus) { /* PE */ |
|
3021 | 2823 |
if (DCONF & PE_CONF_UPACK) |
3022 |
- upack = (EC16(file_hdr.SizeOfOptionalHeader) == 0x148); |
|
3023 |
- |
|
3024 |
- vep = EC32(optional_hdr32.AddressOfEntryPoint); |
|
3025 |
- hdr_size = EC32(optional_hdr32.SizeOfHeaders); |
|
3026 |
- cli_dbgmsg("File format: PE\n"); |
|
3027 |
- |
|
3028 |
- cli_dbgmsg("MajorLinkerVersion: %d\n", optional_hdr32.MajorLinkerVersion); |
|
3029 |
- cli_dbgmsg("MinorLinkerVersion: %d\n", optional_hdr32.MinorLinkerVersion); |
|
3030 |
- cli_dbgmsg("SizeOfCode: 0x%x\n", EC32(optional_hdr32.SizeOfCode)); |
|
3031 |
- cli_dbgmsg("SizeOfInitializedData: 0x%x\n", EC32(optional_hdr32.SizeOfInitializedData)); |
|
3032 |
- cli_dbgmsg("SizeOfUninitializedData: 0x%x\n", EC32(optional_hdr32.SizeOfUninitializedData)); |
|
3033 |
- cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", vep); |
|
3034 |
- cli_dbgmsg("BaseOfCode: 0x%x\n", EC32(optional_hdr32.BaseOfCode)); |
|
3035 |
- cli_dbgmsg("SectionAlignment: 0x%x\n", EC32(optional_hdr32.SectionAlignment)); |
|
3036 |
- cli_dbgmsg("FileAlignment: 0x%x\n", EC32(optional_hdr32.FileAlignment)); |
|
3037 |
- cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(optional_hdr32.MajorSubsystemVersion)); |
|
3038 |
- cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(optional_hdr32.MinorSubsystemVersion)); |
|
3039 |
- cli_dbgmsg("SizeOfImage: 0x%x\n", EC32(optional_hdr32.SizeOfImage)); |
|
3040 |
- cli_dbgmsg("SizeOfHeaders: 0x%x\n", hdr_size); |
|
3041 |
- cli_dbgmsg("NumberOfRvaAndSizes: %d\n", EC32(optional_hdr32.NumberOfRvaAndSizes)); |
|
3042 |
- dirs = optional_hdr32.DataDirectory; |
|
3043 |
-#if HAVE_JSON |
|
3044 |
- if (pe_json != NULL) { |
|
3045 |
- cli_jsonint(pe_json, "MajorLinkerVersion", optional_hdr32.MajorLinkerVersion); |
|
3046 |
- cli_jsonint(pe_json, "MinorLinkerVersion", optional_hdr32.MinorLinkerVersion); |
|
3047 |
- cli_jsonint(pe_json, "SizeOfCode", EC32(optional_hdr32.SizeOfCode)); |
|
3048 |
- cli_jsonint(pe_json, "SizeOfInitializedData", EC32(optional_hdr32.SizeOfInitializedData)); |
|
3049 |
- cli_jsonint(pe_json, "SizeOfUninitializedData", EC32(optional_hdr32.SizeOfUninitializedData)); |
|
3050 |
- cli_jsonint(pe_json, "NumberOfRvaAndSizes", EC32(optional_hdr32.NumberOfRvaAndSizes)); |
|
3051 |
- cli_jsonint(pe_json, "MajorSubsystemVersion", EC16(optional_hdr32.MajorSubsystemVersion)); |
|
3052 |
- cli_jsonint(pe_json, "MinorSubsystemVersion", EC16(optional_hdr32.MinorSubsystemVersion)); |
|
3053 |
- |
|
3054 |
- snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(optional_hdr32.BaseOfCode)); |
|
3055 |
- cli_jsonstr(pe_json, "BaseOfCode", jsonbuf); |
|
3056 |
- |
|
3057 |
- snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(optional_hdr32.SectionAlignment)); |
|
3058 |
- cli_jsonstr(pe_json, "SectionAlignment", jsonbuf); |
|
3059 |
- |
|
3060 |
- snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(optional_hdr32.FileAlignment)); |
|
3061 |
- cli_jsonstr(pe_json, "FileAlignment", jsonbuf); |
|
3062 |
- |
|
3063 |
- snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(optional_hdr32.SizeOfImage)); |
|
3064 |
- cli_jsonstr(pe_json, "SizeOfImage", jsonbuf); |
|
3065 |
- |
|
3066 |
- snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", hdr_size); |
|
3067 |
- cli_jsonstr(pe_json, "SizeOfHeaders", jsonbuf); |
|
3068 |
- } |
|
3069 |
-#endif |
|
3070 |
- |
|
3071 |
- } else { /* PE+ */ |
|
3072 |
- /* read the remaining part of the header */ |
|
3073 |
- if (fmap_readn(map, &optional_hdr32 + 1, at, sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) { |
|
3074 |
- cli_dbgmsg("Can't read optional file header\n"); |
|
3075 |
- if (DETECT_BROKEN_PE) { |
|
3076 |
- ret = cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
|
3077 |
- return ret; |
|
3078 |
- } |
|
3079 |
- |
|
3080 |
- return CL_CLEAN; |
|
3081 |
- } |
|
3082 |
- |
|
3083 |
- at += sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32); |
|
3084 |
- vep = EC32(optional_hdr64.AddressOfEntryPoint); |
|
3085 |
- hdr_size = EC32(optional_hdr64.SizeOfHeaders); |
|
3086 |
- cli_dbgmsg("File format: PE32+\n"); |
|
3087 |
- |
|
3088 |
- cli_dbgmsg("MajorLinkerVersion: %d\n", optional_hdr64.MajorLinkerVersion); |
|
3089 |
- cli_dbgmsg("MinorLinkerVersion: %d\n", optional_hdr64.MinorLinkerVersion); |
|
3090 |
- cli_dbgmsg("SizeOfCode: 0x%x\n", EC32(optional_hdr64.SizeOfCode)); |
|
3091 |
- cli_dbgmsg("SizeOfInitializedData: 0x%x\n", EC32(optional_hdr64.SizeOfInitializedData)); |
|
3092 |
- cli_dbgmsg("SizeOfUninitializedData: 0x%x\n", EC32(optional_hdr64.SizeOfUninitializedData)); |
|
3093 |
- cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", vep); |
|
3094 |
- cli_dbgmsg("BaseOfCode: 0x%x\n", EC32(optional_hdr64.BaseOfCode)); |
|
3095 |
- cli_dbgmsg("SectionAlignment: 0x%x\n", EC32(optional_hdr64.SectionAlignment)); |
|
3096 |
- cli_dbgmsg("FileAlignment: 0x%x\n", EC32(optional_hdr64.FileAlignment)); |
|
3097 |
- cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(optional_hdr64.MajorSubsystemVersion)); |
|
3098 |
- cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(optional_hdr64.MinorSubsystemVersion)); |
|
3099 |
- cli_dbgmsg("SizeOfImage: 0x%x\n", EC32(optional_hdr64.SizeOfImage)); |
|
3100 |
- cli_dbgmsg("SizeOfHeaders: 0x%x\n", hdr_size); |
|
3101 |
- cli_dbgmsg("NumberOfRvaAndSizes: %d\n", EC32(optional_hdr64.NumberOfRvaAndSizes)); |
|
3102 |
- dirs = optional_hdr64.DataDirectory; |
|
3103 |
-#if HAVE_JSON |
|
3104 |
- if (pe_json != NULL) { |
|
3105 |
- cli_jsonint(pe_json, "MajorLinkerVersion", optional_hdr64.MajorLinkerVersion); |
|
3106 |
- cli_jsonint(pe_json, "MinorLinkerVersion", optional_hdr64.MinorLinkerVersion); |
|
3107 |
- cli_jsonint(pe_json, "SizeOfCode", EC32(optional_hdr64.SizeOfCode)); |
|
3108 |
- cli_jsonint(pe_json, "SizeOfInitializedData", EC32(optional_hdr64.SizeOfInitializedData)); |
|
3109 |
- cli_jsonint(pe_json, "SizeOfUninitializedData", EC32(optional_hdr64.SizeOfUninitializedData)); |
|
3110 |
- cli_jsonint(pe_json, "NumberOfRvaAndSizes", EC32(optional_hdr64.NumberOfRvaAndSizes)); |
|
3111 |
- cli_jsonint(pe_json, "MajorSubsystemVersion", EC16(optional_hdr64.MajorSubsystemVersion)); |
|
3112 |
- cli_jsonint(pe_json, "MinorSubsystemVersion", EC16(optional_hdr64.MinorSubsystemVersion)); |
|
3113 |
- |
|
3114 |
- snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(optional_hdr64.BaseOfCode)); |
|
3115 |
- cli_jsonstr(pe_json, "BaseOfCode", jsonbuf); |
|
3116 |
- |
|
3117 |
- snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(optional_hdr64.SectionAlignment)); |
|
3118 |
- cli_jsonstr(pe_json, "SectionAlignment", jsonbuf); |
|
3119 |
- |
|
3120 |
- snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(optional_hdr64.FileAlignment)); |
|
3121 |
- cli_jsonstr(pe_json, "FileAlignment", jsonbuf); |
|
3122 |
- |
|
3123 |
- snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(optional_hdr64.SizeOfImage)); |
|
3124 |
- cli_jsonstr(pe_json, "SizeOfImage", jsonbuf); |
|
3125 |
- |
|
3126 |
- snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", hdr_size); |
|
3127 |
- cli_jsonstr(pe_json, "SizeOfHeaders", jsonbuf); |
|
3128 |
- } |
|
3129 |
-#endif |
|
3130 |
- } |
|
3131 |
- |
|
3132 |
-#if HAVE_JSON |
|
3133 |
- if (SCAN_COLLECT_METADATA) { |
|
3134 |
- snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", vep); |
|
3135 |
- if (pe_json != NULL) |
|
3136 |
- cli_jsonstr(pe_json, "EntryPoint", jsonbuf); |
|
3137 |
- } |
|
3138 |
-#endif |
|
3139 |
- |
|
3140 |
- switch (pe_plus ? EC16(optional_hdr64.Subsystem) : EC16(optional_hdr32.Subsystem)) { |
|
3141 |
- case 0: |
|
3142 |
- subsystem = "Unknown"; |
|
3143 |
- break; |
|
3144 |
- case 1: |
|
3145 |
- subsystem = "Native (svc)"; |
|
3146 |
- native = 1; |
|
3147 |
- break; |
|
3148 |
- case 2: |
|
3149 |
- subsystem = "Win32 GUI"; |
|
3150 |
- break; |
|
3151 |
- case 3: |
|
3152 |
- subsystem = "Win32 console"; |
|
3153 |
- break; |
|
3154 |
- case 5: |
|
3155 |
- subsystem = "OS/2 console"; |
|
3156 |
- break; |
|
3157 |
- case 7: |
|
3158 |
- subsystem = "POSIX console"; |
|
3159 |
- break; |
|
3160 |
- case 8: |
|
3161 |
- subsystem = "Native Win9x driver"; |
|
3162 |
- break; |
|
3163 |
- case 9: |
|
3164 |
- subsystem = "WinCE GUI"; |
|
3165 |
- break; |
|
3166 |
- case 10: |
|
3167 |
- subsystem = "EFI application"; |
|
3168 |
- break; |
|
3169 |
- case 11: |
|
3170 |
- subsystem = "EFI driver"; |
|
3171 |
- break; |
|
3172 |
- case 12: |
|
3173 |
- subsystem = "EFI runtime driver"; |
|
3174 |
- break; |
|
3175 |
- case 13: |
|
3176 |
- subsystem = "EFI ROM image"; |
|
3177 |
- break; |
|
3178 |
- case 14: |
|
3179 |
- subsystem = "Xbox"; |
|
3180 |
- break; |
|
3181 |
- case 16: |
|
3182 |
- subsystem = "Boot application"; |
|
3183 |
- break; |
|
3184 |
- default: |
|
3185 |
- subsystem = "Unknown"; |
|
2824 |
+ upack = (EC16(peinfo->file_hdr.SizeOfOptionalHeader) == 0x148); |
|
3186 | 2825 |
} |
2826 |
+ for (i = 0; i < peinfo->nsections; i++) { |
|
3187 | 2827 |
|
3188 |
- cli_dbgmsg("Subsystem: %s\n", subsystem); |
|
3189 |
- |
|
3190 |
-#if HAVE_JSON |
|
3191 |
- if (pe_json != NULL) |
|
3192 |
- cli_jsonstr(pe_json, "Subsystem", subsystem); |
|
3193 |
-#endif |
|
3194 |
- |
|
3195 |
- cli_dbgmsg("------------------------------------\n"); |
|
3196 |
- |
|
3197 |
- if (DETECT_BROKEN_PE && !native && (!(pe_plus ? EC32(optional_hdr64.SectionAlignment) : EC32(optional_hdr32.SectionAlignment)) || (pe_plus ? EC32(optional_hdr64.SectionAlignment) : EC32(optional_hdr32.SectionAlignment)) % 0x1000)) { |
|
3198 |
- cli_dbgmsg("Bad virtual alignment\n"); |
|
3199 |
- ret = cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
|
3200 |
- return ret; |
|
3201 |
- } |
|
3202 |
- |
|
3203 |
- if (DETECT_BROKEN_PE && !native && (!(pe_plus ? EC32(optional_hdr64.FileAlignment) : EC32(optional_hdr32.FileAlignment)) || (pe_plus ? EC32(optional_hdr64.FileAlignment) : EC32(optional_hdr32.FileAlignment)) % 0x200)) { |
|
3204 |
- cli_dbgmsg("Bad file alignment\n"); |
|
3205 |
- ret = cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
|
3206 |
- return ret; |
|
3207 |
- } |
|
3208 |
- |
|
3209 |
- fsize = map->len; |
|
3210 |
- |
|
3211 |
- section_hdr = (struct pe_image_section_hdr *)cli_calloc(nsections, sizeof(struct pe_image_section_hdr)); |
|
3212 |
- |
|
3213 |
- if (!section_hdr) { |
|
3214 |
- cli_dbgmsg("Can't allocate memory for section headers\n"); |
|
3215 |
- return CL_EMEM; |
|
3216 |
- } |
|
3217 |
- |
|
3218 |
- exe_sections = (struct cli_exe_section *)cli_calloc(nsections, sizeof(struct cli_exe_section)); |
|
3219 |
- |
|
3220 |
- if (!exe_sections) { |
|
3221 |
- cli_dbgmsg("Can't allocate memory for section headers\n"); |
|
3222 |
- free(section_hdr); |
|
3223 |
- return CL_EMEM; |
|
3224 |
- } |
|
3225 |
- |
|
3226 |
- valign = (pe_plus) ? EC32(optional_hdr64.SectionAlignment) : EC32(optional_hdr32.SectionAlignment); |
|
3227 |
- falign = (pe_plus) ? EC32(optional_hdr64.FileAlignment) : EC32(optional_hdr32.FileAlignment); |
|
3228 |
- |
|
3229 |
- if (fmap_readn(map, section_hdr, at, sizeof(struct pe_image_section_hdr) * nsections) != (int)(nsections * sizeof(struct pe_image_section_hdr))) { |
|
3230 |
- cli_dbgmsg("Can't read section header\n"); |
|
3231 |
- cli_dbgmsg("Possibly broken PE file\n"); |
|
3232 |
- |
|
3233 |
- free(section_hdr); |
|
3234 |
- free(exe_sections); |
|
3235 |
- |
|
3236 |
- if (DETECT_BROKEN_PE) { |
|
3237 |
- ret = cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
|
3238 |
- return ret; |
|
3239 |
- } |
|
3240 |
- |
|
3241 |
- return CL_CLEAN; |
|
3242 |
- } |
|
3243 |
- |
|
3244 |
- at += sizeof(struct pe_image_section_hdr) * nsections; |
|
3245 |
- |
|
3246 |
- for (i = 0; falign != 0x200 && i < nsections; i++) { |
|
3247 |
- /* file alignment fallback mode - blah */ |
|
3248 |
- if (falign && section_hdr[i].SizeOfRawData && EC32(section_hdr[i].PointerToRawData) % falign && !(EC32(section_hdr[i].PointerToRawData) % 0x200)) { |
|
3249 |
- cli_dbgmsg("Found misaligned section, using 0x200\n"); |
|
3250 |
- falign = 0x200; |
|
3251 |
- } |
|
3252 |
- } |
|
3253 |
- |
|
3254 |
- hdr_size = PESALIGN(hdr_size, valign); /* Aligned headers virtual size */ |
|
3255 |
- |
|
3256 |
-#if HAVE_JSON |
|
3257 |
- if (pe_json != NULL) |
|
3258 |
- cli_jsonint(pe_json, "NumberOfSections", nsections); |
|
3259 |
-#endif |
|
3260 |
- |
|
3261 |
- while (rescan == 1) { |
|
3262 |
- rescan = 0; |
|
3263 |
- for (i = 0; i < nsections; i++) { |
|
3264 |
- exe_sections[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign); |
|
3265 |
- exe_sections[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign); |
|
3266 |
- exe_sections[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign); |
|
3267 |
- exe_sections[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign); |
|
3268 |
- exe_sections[i].chr = EC32(section_hdr[i].Characteristics); |
|
3269 |
- exe_sections[i].urva = EC32(section_hdr[i].VirtualAddress); /* Just in case */ |
|
3270 |
- exe_sections[i].uvsz = EC32(section_hdr[i].VirtualSize); |
|
3271 |
- exe_sections[i].uraw = EC32(section_hdr[i].PointerToRawData); |
|
3272 |
- exe_sections[i].ursz = EC32(section_hdr[i].SizeOfRawData); |
|
3273 |
- |
|
3274 |
- if (exe_sections[i].rsz) { /* Don't bother with virtual only sections */ |
|
3275 |
- if (exe_sections[i].raw >= fsize || exe_sections[i].uraw > fsize) { |
|
3276 |
- cli_dbgmsg("Broken PE file - Section %d starts or exists beyond the end of file (Offset@ %lu, Total filesize %lu)\n", i, (unsigned long)exe_sections[i].raw, (unsigned long)fsize); |
|
3277 |
- if (nsections == 1) { |
|
3278 |
- free(section_hdr); |
|
3279 |
- free(exe_sections); |
|
3280 |
- |
|
3281 |
- if (DETECT_BROKEN_PE) { |
|
3282 |
- ret = cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
|
3283 |
- return ret; |
|
3284 |
- } |
|
3285 |
- |
|
3286 |
- return CL_CLEAN; /* no ninjas to see here! move along! */ |
|
3287 |
- } |
|
3288 |
- |
|
3289 |
- for (j = i; j < nsections - 1; j++) |
|
3290 |
- memcpy(&exe_sections[j], &exe_sections[j + 1], sizeof(struct cli_exe_section)); |
|
3291 |
- |
|
3292 |
- for (j = i; j < nsections - 1; j++) |
|
3293 |
- memcpy(§ion_hdr[j], §ion_hdr[j + 1], sizeof(struct pe_image_section_hdr)); |
|
3294 |
- |
|
3295 |
- nsections--; |
|
3296 |
- rescan = 1; |
|
3297 |
- break; |
|
3298 |
- } |
|
3299 |
- |
|
3300 |
- if (!CLI_ISCONTAINED(0, (uint32_t)fsize, exe_sections[i].raw, exe_sections[i].rsz)) |
|
3301 |
- exe_sections[i].rsz = fsize - exe_sections[i].raw; |
|
3302 |
- |
|
3303 |
- if (!CLI_ISCONTAINED(0, fsize, exe_sections[i].uraw, exe_sections[i].ursz)) |
|
3304 |
- exe_sections[i].ursz = fsize - exe_sections[i].uraw; |
|
3305 |
- } |
|
3306 |
- } |
|
3307 |
- } |
|
3308 |
- |
|
3309 |
- for (i = 0; i < nsections; i++) { |
|
3310 |
- strncpy(sname, (char *)section_hdr[i].Name, 8); |
|
3311 |
- sname[8] = 0; |
|
3312 |
- |
|
3313 |
-#if HAVE_JSON |
|
3314 |
- add_section_info(ctx, &exe_sections[i]); |
|
3315 |
- |
|
3316 |
- if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) { |
|
3317 |
- free(section_hdr); |
|
3318 |
- free(exe_sections); |
|
3319 |
- return CL_ETIMEOUT; |
|
3320 |
- } |
|
3321 |
-#endif |
|
3322 |
- |
|
3323 |
- if (!exe_sections[i].vsz && exe_sections[i].rsz) |
|
3324 |
- exe_sections[i].vsz = PESALIGN(exe_sections[i].ursz, valign); |
|
3325 |
- |
|
3326 |
- cli_dbgmsg("Section %d\n", i); |
|
3327 |
- cli_dbgmsg("Section name: %s\n", sname); |
|
3328 |
- cli_dbgmsg("Section data (from headers - in memory)\n"); |
|
3329 |
- cli_dbgmsg("VirtualSize: 0x%x 0x%x\n", exe_sections[i].uvsz, exe_sections[i].vsz); |
|
3330 |
- cli_dbgmsg("VirtualAddress: 0x%x 0x%x\n", exe_sections[i].urva, exe_sections[i].rva); |
|
3331 |
- cli_dbgmsg("SizeOfRawData: 0x%x 0x%x\n", exe_sections[i].ursz, exe_sections[i].rsz); |
|
3332 |
- cli_dbgmsg("PointerToRawData: 0x%x 0x%x\n", exe_sections[i].uraw, exe_sections[i].raw); |
|
3333 |
- |
|
3334 |
- if (exe_sections[i].chr & 0x20) { |
|
3335 |
- cli_dbgmsg("Section contains executable code\n"); |
|
3336 |
- |
|
3337 |
- if (exe_sections[i].vsz < exe_sections[i].rsz) { |
|
3338 |
- cli_dbgmsg("Section contains free space\n"); |
|
3339 |
- /* |
|
3340 |
- cli_dbgmsg("Dumping %d bytes\n", section_hdr.SizeOfRawData - section_hdr.VirtualSize); |
|
3341 |
- ddump(desc, section_hdr.PointerToRawData + section_hdr.VirtualSize, section_hdr.SizeOfRawData - section_hdr.VirtualSize, cli_gentemp(NULL)); |
|
3342 |
- */ |
|
3343 |
- } |
|
3344 |
- } |
|
3345 |
- |
|
3346 |
- if (exe_sections[i].chr & 0x20000000) |
|
3347 |
- cli_dbgmsg("Section's memory is executable\n"); |
|
3348 |
- |
|
3349 |
- if (exe_sections[i].chr & 0x80000000) |
|
3350 |
- cli_dbgmsg("Section's memory is writeable\n"); |
|
3351 |
- |
|
3352 |
- if (DETECT_BROKEN_PE && (!valign || (exe_sections[i].urva % valign))) { /* Bad virtual alignment */ |
|
3353 |
- cli_dbgmsg("VirtualAddress is misaligned\n"); |
|
3354 |
- cli_dbgmsg("------------------------------------\n"); |
|
3355 |
- ret = cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
|
3356 |
- free(section_hdr); |
|
3357 |
- free(exe_sections); |
|
3358 |
- return ret; |
|
3359 |
- } |
|
3360 |
- |
|
3361 |
- if (exe_sections[i].rsz) { /* Don't bother with virtual only sections */ |
|
3362 |
- if (SCAN_HEURISTICS && (DCONF & PE_CONF_POLIPOS) && !*sname && exe_sections[i].vsz > 40000 && exe_sections[i].vsz < 70000 && exe_sections[i].chr == 0xe0000060) polipos = i; |
|
2828 |
+ if (peinfo->sections[i].rsz) { /* Don't bother with virtual only sections */ |
|
2829 |
+ // TODO Regarding the commented out check below: |
|
2830 |
+ // This used to check that the section name was NULL, but now that |
|
2831 |
+ // header parsing is done in cli_peheader (and since we don't yet |
|
2832 |
+ // make the section name availabe via peinfo->sections[]) it would |
|
2833 |
+ // be a pain to fetch the name here. Since this is the only place |
|
2834 |
+ // in cli_scanpe that needs the section name, and since I verified |
|
2835 |
+ // that detection still occurs for Polipos without this check, |
|
2836 |
+ // let's leave it commented out for now. |
|
2837 |
+ 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; |
|
3363 | 2838 |
|
3364 | 2839 |
/* check hash section sigs */ |
3365 | 2840 |
if ((DCONF & PE_CONF_MD5SECT) && ctx->engine->hm_mdb) { |
3366 |
- ret = scan_pe_mdb(ctx, &exe_sections[i]); |
|
2841 |
+ ret = scan_pe_mdb(ctx, &(peinfo->sections[i])); |
|
3367 | 2842 |
if (ret != CL_CLEAN) { |
2843 |
+ // TODO Handle allmatch |
|
3368 | 2844 |
if (ret != CL_VIRUS) |
3369 |
- cli_errmsg("scan_pe: scan_pe_mdb failed: %s!\n", cl_strerror(ret)); |
|
2845 |
+ cli_errmsg("cli_scanpe: scan_pe_mdb failed: %s!\n", cl_strerror(ret)); |
|
3370 | 2846 |
|
3371 | 2847 |
cli_dbgmsg("------------------------------------\n"); |
3372 |
- free(section_hdr); |
|
3373 |
- free(exe_sections); |
|
2848 |
+ cli_exe_info_destroy(peinfo); |
|
3374 | 2849 |
return ret; |
3375 | 2850 |
} |
3376 | 2851 |
} |
3377 | 2852 |
} |
3378 |
- cli_dbgmsg("------------------------------------\n"); |
|
3379 |
- |
|
3380 |
- if (exe_sections[i].urva >> 31 || exe_sections[i].uvsz >> 31 || (exe_sections[i].rsz && exe_sections[i].uraw >> 31) || exe_sections[i].ursz >> 31) { |
|
3381 |
- cli_dbgmsg("Found PE values with sign bit set\n"); |
|
3382 |
- |
|
3383 |
- free(section_hdr); |
|
3384 |
- free(exe_sections); |
|
3385 |
- if (DETECT_BROKEN_PE) { |
|
3386 |
- ret = cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
|
3387 |
- return ret; |
|
3388 |
- } |
|
3389 |
- |
|
3390 |
- return CL_CLEAN; |
|
3391 |
- } |
|
3392 |
- |
|
3393 |
- if (!i) { |
|
3394 |
- if (DETECT_BROKEN_PE && exe_sections[i].urva != hdr_size) { /* Bad first section RVA */ |
|
3395 |
- cli_dbgmsg("First section is in the wrong place\n"); |
|
3396 |
- ret = cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
|
3397 |
- free(section_hdr); |
|
3398 |
- free(exe_sections); |
|
3399 |
- return ret; |
|
3400 |
- } |
|
3401 |
- |
|
3402 |
- min = exe_sections[i].rva; |
|
3403 |
- max = exe_sections[i].rva + exe_sections[i].rsz; |
|
3404 |
- } else { |
|
3405 |
- if (DETECT_BROKEN_PE && exe_sections[i].urva - exe_sections[i - 1].urva != exe_sections[i - 1].vsz) { /* No holes, no overlapping, no virtual disorder */ |
|
3406 |
- cli_dbgmsg("Virtually misplaced section (wrong order, overlapping, non contiguous)\n"); |
|
3407 |
- ret = cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
|
3408 |
- free(section_hdr); |
|
3409 |
- free(exe_sections); |
|
3410 |
- return ret; |
|
3411 |
- } |
|
3412 |
- |
|
3413 |
- if (exe_sections[i].rva < min) |
|
3414 |
- min = exe_sections[i].rva; |
|
3415 |
- |
|
3416 |
- if (exe_sections[i].rva + exe_sections[i].rsz > max) { |
|
3417 |
- max = exe_sections[i].rva + exe_sections[i].rsz; |
|
3418 |
- overlays = exe_sections[i].raw + exe_sections[i].rsz; |
|
3419 |
- } |
|
3420 |
- } |
|
3421 | 2853 |
} |
3422 | 2854 |
|
3423 |
- free(section_hdr); |
|
3424 |
- |
|
3425 |
- if (!(ep = cli_rawaddr(vep, exe_sections, nsections, &err, fsize, hdr_size)) && err) { |
|
3426 |
- cli_dbgmsg("EntryPoint out of file\n"); |
|
3427 |
- free(exe_sections); |
|
3428 |
- if (DETECT_BROKEN_PE) { |
|
3429 |
- ret = cli_append_virus(ctx, "Heuristics.Broken.Executable"); |
|
3430 |
- return ret; |
|
3431 |
- } |
|
3432 |
- |
|
2855 |
+ // TODO Don't bail out here |
|
2856 |
+ if (peinfo->is_pe32plus) { /* Do not continue for PE32+ files */ |
|
2857 |
+ cli_exe_info_destroy(peinfo); |
|
3433 | 2858 |
return CL_CLEAN; |
3434 | 2859 |
} |
3435 | 2860 |
|
3436 |
-#if HAVE_JSON |
|
3437 |
- if (pe_json != NULL) |
|
3438 |
- cli_jsonint(pe_json, "EntryPointOffset", ep); |
|
3439 |
- |
|
3440 |
- if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) { |
|
3441 |
- return CL_ETIMEOUT; |
|
3442 |
- } |
|
3443 |
-#endif |
|
3444 |
- |
|
3445 |
- cli_dbgmsg("EntryPoint offset: 0x%x (%d)\n", ep, ep); |
|
3446 |
- |
|
3447 |
- if (pe_plus) { /* Do not continue for PE32+ files */ |
|
3448 |
- free(exe_sections); |
|
3449 |
- return CL_CLEAN; |
|
3450 |
- } |
|
3451 |
- |
|
3452 |
- epsize = fmap_readn(map, epbuff, ep, 4096); |
|
2861 |
+ epsize = fmap_readn(map, epbuff, peinfo->ep, 4096); |
|
3453 | 2862 |
|
3454 | 2863 |
/* Disasm scan disabled since it's now handled by the bytecode */ |
3455 | 2864 |
|
3456 |
- /* CLI_UNPTEMP("DISASM",(exe_sections,0)); */ |
|
2865 |
+ /* CLI_UNPTEMP("cli_scanpe: DISASM",(peinfo->sections,0)); */ |
|
3457 | 2866 |
/* if(disasmbuf((unsigned char*)epbuff, epsize, ndesc)) */ |
3458 | 2867 |
/* ret = cli_scandesc(ndesc, ctx, CL_TYPE_PE_DISASM, 1, NULL, AC_SCAN_VIR); */ |
3459 | 2868 |
/* close(ndesc); */ |
3460 |
- /* CLI_TMPUNLK(); */ |
|
3461 |
- /* free(tempfile); */ |
|
3462 | 2869 |
/* if(ret == CL_VIRUS) { */ |
3463 |
- /* free(exe_sections); */ |
|
2870 |
+ /* cli_exe_info_destroy(peinfo); */ |
|
2871 |
+ /* CLI_TMPUNLK(); */ |
|
2872 |
+ /* free(tempfile); */ |
|
3464 | 2873 |
/* return ret; */ |
3465 | 2874 |
/* } */ |
2875 |
+ /* CLI_TMPUNLK(); */ |
|
2876 |
+ /* free(tempfile); */ |
|
3466 | 2877 |
|
3467 |
- if (overlays) { |
|
3468 |
- int overlays_sz = fsize - overlays; |
|
3469 |
- if (overlays_sz > 0) { |
|
3470 |
- ret = cli_scanishield(ctx, overlays, overlays_sz); |
|
3471 |
- if (ret != CL_CLEAN) { |
|
3472 |
- free(exe_sections); |
|
3473 |
- return ret; |
|
3474 |
- } |
|
2878 |
+ if (peinfo->overlay_start && peinfo->overlay_size > 0) { |
|
2879 |
+ ret = cli_scanishield(ctx, peinfo->overlay_start, peinfo->overlay_size); |
|
2880 |
+ if (ret != CL_CLEAN) { |
|
2881 |
+ // TODO Handle allmatch |
|
2882 |
+ cli_exe_info_destroy(peinfo); |
|
2883 |
+ return ret; |
|
3475 | 2884 |
} |
3476 | 2885 |
} |
3477 | 2886 |
|
3478 |
- pedata.nsections = nsections; |
|
3479 |
- pedata.ep = ep; |
|
2887 |
+ pedata.nsections = peinfo->nsections; |
|
2888 |
+ pedata.ep = peinfo->ep; |
|
3480 | 2889 |
pedata.offset = 0; |
3481 |
- memcpy(&pedata.file_hdr, &file_hdr, sizeof(file_hdr)); |
|
3482 |
- memcpy(&pedata.opt32, &pe_opt.opt32, sizeof(pe_opt.opt32)); |
|
3483 |
- memcpy(&pedata.opt64, &pe_opt.opt64, sizeof(pe_opt.opt64)); |
|
3484 |
- memcpy(&pedata.dirs, dirs, sizeof(pedata.dirs)); |
|
3485 |
- pedata.e_lfanew = e_lfanew; |
|
3486 |
- pedata.overlays = overlays; |
|
3487 |
- pedata.overlays_sz = fsize - overlays; |
|
3488 |
- pedata.hdr_size = hdr_size; |
|
2890 |
+ memcpy(&pedata.file_hdr, &(peinfo->file_hdr), sizeof(peinfo->file_hdr)); |
|
2891 |
+ // TODO no need to copy both of these for each binary |
|
2892 |
+ memcpy(&pedata.opt32, &(peinfo->pe_opt.opt32), sizeof(peinfo->pe_opt.opt32)); |
|
2893 |
+ memcpy(&pedata.opt64, &(peinfo->pe_opt.opt64), sizeof(peinfo->pe_opt.opt64)); |
|
2894 |
+ memcpy(&pedata.dirs, &(peinfo->dirs), sizeof(peinfo->dirs)); |
|
2895 |
+ // Gross |
|
2896 |
+ memcpy(&pedata.opt32_dirs, &(peinfo->dirs), sizeof(peinfo->dirs)); |
|
2897 |
+ memcpy(&pedata.opt64_dirs, &(peinfo->dirs), sizeof(peinfo->dirs)); |
|
2898 |
+ pedata.e_lfanew = peinfo->e_lfanew; |
|
2899 |
+ pedata.overlays = peinfo->overlay_start; |
|
2900 |
+ pedata.overlays_sz = peinfo->overlay_size; |
|
2901 |
+ pedata.hdr_size = peinfo->hdr_size; |
|
3489 | 2902 |
|
3490 | 2903 |
/* Bytecode BC_PE_ALL hook */ |
3491 | 2904 |
bc_ctx = cli_bytecode_context_alloc(); |
3492 | 2905 |
if (!bc_ctx) { |
3493 | 2906 |
cli_errmsg("cli_scanpe: can't allocate memory for bc_ctx\n"); |
3494 |
- free(exe_sections); |
|
2907 |
+ cli_exe_info_destroy(peinfo); |
|
3495 | 2908 |
return CL_EMEM; |
3496 | 2909 |
} |
3497 | 2910 |
|
3498 |
- cli_bytecode_context_setpe(bc_ctx, &pedata, exe_sections); |
|
2911 |
+ cli_bytecode_context_setpe(bc_ctx, &pedata, peinfo->sections); |
|
3499 | 2912 |
cli_bytecode_context_setctx(bc_ctx, ctx); |
3500 | 2913 |
ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_ALL, map); |
3501 | 2914 |
switch (ret) { |
... | ... |
@@ -3504,7 +2915,8 @@ int cli_scanpe(cli_ctx *ctx) |
3504 | 3504 |
break; |
3505 | 3505 |
case CL_VIRUS: |
3506 | 3506 |
case CL_BREAK: |
3507 |
- free(exe_sections); |
|
3507 |
+ // TODO Handle allmatch |
|
3508 |
+ cli_exe_info_destroy(peinfo); |
|
3508 | 3509 |
cli_bytecode_context_destroy(bc_ctx); |
3509 | 3510 |
return ret == CL_VIRUS ? CL_VIRUS : CL_CLEAN; |
3510 | 3511 |
} |
... | ... |
@@ -3517,7 +2929,7 @@ int cli_scanpe(cli_ctx *ctx) |
3517 | 3517 |
#else |
3518 | 3518 |
if (DCONF & PE_CONF_IMPTBL && ctx->engine->hm_imp) { |
3519 | 3519 |
#endif |
3520 |
- ret = scan_pe_imp(ctx, dirs, exe_sections, nsections, hdr_size, pe_plus); |
|
3520 |
+ ret = scan_pe_imp(ctx, peinfo); |
|
3521 | 3521 |
switch (ret) { |
3522 | 3522 |
case CL_SUCCESS: |
3523 | 3523 |
break; |
... | ... |
@@ -3529,17 +2941,17 @@ int cli_scanpe(cli_ctx *ctx) |
3529 | 3529 |
break; |
3530 | 3530 |
/* intentional fall-through */ |
3531 | 3531 |
case CL_BREAK: |
3532 |
- free(exe_sections); |
|
3532 |
+ cli_exe_info_destroy(peinfo); |
|
3533 | 3533 |
return ret == CL_VIRUS ? CL_VIRUS : CL_CLEAN; |
3534 | 3534 |
default: |
3535 |
- free(exe_sections); |
|
3535 |
+ cli_exe_info_destroy(peinfo); |
|
3536 | 3536 |
return ret; |
3537 | 3537 |
} |
3538 | 3538 |
} |
3539 | 3539 |
/* Attempt to detect some popular polymorphic viruses */ |
3540 | 3540 |
|
3541 | 3541 |
/* W32.Parite.B */ |
3542 |
- if (SCAN_HEURISTICS && (DCONF & PE_CONF_PARITE) && !dll && epsize == 4096 && ep == exe_sections[nsections - 1].raw) { |
|
3542 |
+ if (SCAN_HEURISTICS && (DCONF & PE_CONF_PARITE) && !peinfo->is_dll && epsize == 4096 && peinfo->ep == peinfo->sections[peinfo->nsections - 1].raw) { |
|
3543 | 3543 |
const char *pt = cli_memstr(epbuff, 4040, "\x47\x65\x74\x50\x72\x6f\x63\x41\x64\x64\x72\x65\x73\x73\x00", 15); |
3544 | 3544 |
if (pt) { |
3545 | 3545 |
pt += 15; |
... | ... |
@@ -3548,12 +2960,12 @@ int cli_scanpe(cli_ctx *ctx) |
3548 | 3548 |
if (ret != CL_CLEAN) { |
3549 | 3549 |
if (ret == CL_VIRUS) { |
3550 | 3550 |
if (!SCAN_ALLMATCHES) { |
3551 |
- free(exe_sections); |
|
3551 |
+ cli_exe_info_destroy(peinfo); |
|
3552 | 3552 |
return ret; |
3553 | 3553 |
} else |
3554 | 3554 |
viruses_found++; |
3555 | 3555 |
} else { |
3556 |
- free(exe_sections); |
|
3556 |
+ cli_exe_info_destroy(peinfo); |
|
3557 | 3557 |
return ret; |
3558 | 3558 |
} |
3559 | 3559 |
} |
... | ... |
@@ -3562,7 +2974,7 @@ int cli_scanpe(cli_ctx *ctx) |
3562 | 3562 |
} |
3563 | 3563 |
|
3564 | 3564 |
/* Kriz */ |
3565 |
- if (SCAN_HEURISTICS && (DCONF & PE_CONF_KRIZ) && epsize >= 200 && CLI_ISCONTAINED(exe_sections[nsections - 1].raw, exe_sections[nsections - 1].rsz, ep, 0x0fd2) && epbuff[1] == '\x9c' && epbuff[2] == '\x60') { |
|
3565 |
+ 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') { |
|
3566 | 3566 |
enum { KZSTRASH, |
3567 | 3567 |
KZSCDELTA, |
3568 | 3568 |
KZSPDELTA, |
... | ... |
@@ -3577,7 +2989,7 @@ int cli_scanpe(cli_ctx *ctx) |
3577 | 3577 |
uint8_t *kzcode = (uint8_t *)epbuff + 3; |
3578 | 3578 |
uint8_t kzdptr = 0xff, kzdsize = 0xff; |
3579 | 3579 |
int kzlen = 197, kzinitlen = 0xffff, kzxorlen = -1; |
3580 |
- cli_dbgmsg("in kriz\n"); |
|
3580 |
+ cli_dbgmsg("cli_scanpe: in kriz\n"); |
|
3581 | 3581 |
|
3582 | 3582 |
while (*kzstate != KZSTOP) { |
3583 | 3583 |
uint8_t op; |
... | ... |
@@ -3609,7 +3021,7 @@ int cli_scanpe(cli_ctx *ctx) |
3609 | 3609 |
kzstate++; |
3610 | 3610 |
op = 4; /* fake the register to avoid breaking out */ |
3611 | 3611 |
|
3612 |
- cli_dbgmsg("kriz: using #%d as size counter\n", kzdsize); |
|
3612 |
+ cli_dbgmsg("cli_scanpe: kriz: using #%d as size counter\n", kzdsize); |
|
3613 | 3613 |
} |
3614 | 3614 |
opsz = 4; |
3615 | 3615 |
case 0x48: |
... | ... |
@@ -3646,7 +3058,7 @@ int cli_scanpe(cli_ctx *ctx) |
3646 | 3646 |
case KZSPDELTA: |
3647 | 3647 |
if ((op & 0xf8) == 0x58 && (kzdptr = op - 0x58) != 4) { |
3648 | 3648 |
kzstate++; |
3649 |
- cli_dbgmsg("kriz: using #%d as pointer\n", kzdptr); |
|
3649 |
+ cli_dbgmsg("cli_scanpe: kriz: using #%d as pointer\n", kzdptr); |
|
3650 | 3650 |
} else { |
3651 | 3651 |
*kzstate = KZSTOP; |
3652 | 3652 |
} |
... | ... |
@@ -3680,30 +3092,30 @@ int cli_scanpe(cli_ctx *ctx) |
3680 | 3680 |
if (ret != CL_CLEAN) { |
3681 | 3681 |
if (ret == CL_VIRUS) { |
3682 | 3682 |
if (!SCAN_ALLMATCHES) { |
3683 |
- free(exe_sections); |
|
3683 |
+ cli_exe_info_destroy(peinfo); |
|
3684 | 3684 |
return ret; |
3685 | 3685 |
} else |
3686 | 3686 |
viruses_found++; |
3687 | 3687 |
} else { |
3688 |
- free(exe_sections); |
|
3688 |
+ cli_exe_info_destroy(peinfo); |
|
3689 | 3689 |
return ret; |
3690 | 3690 |
} |
3691 | 3691 |
} |
3692 | 3692 |
} |
3693 |
- cli_dbgmsg("kriz: loop out of bounds, corrupted sample?\n"); |
|
3693 |
+ cli_dbgmsg("cli_scanpe: kriz: loop out of bounds, corrupted sample?\n"); |
|
3694 | 3694 |
kzstate++; |
3695 | 3695 |
} |
3696 | 3696 |
} |
3697 | 3697 |
} |
3698 | 3698 |
|
3699 | 3699 |
/* W32.Magistr.A/B */ |
3700 |
- if (SCAN_HEURISTICS && (DCONF & PE_CONF_MAGISTR) && !dll && (nsections > 1) && (exe_sections[nsections - 1].chr & 0x80000000)) { |
|
3700 |
+ if (SCAN_HEURISTICS && (DCONF & PE_CONF_MAGISTR) && !peinfo->is_dll && (peinfo->nsections > 1) && (peinfo->sections[peinfo->nsections - 1].chr & 0x80000000)) { |
|
3701 | 3701 |
uint32_t rsize, vsize, dam = 0; |
3702 | 3702 |
|
3703 |
- vsize = exe_sections[nsections - 1].uvsz; |
|
3704 |
- rsize = exe_sections[nsections - 1].rsz; |
|
3705 |
- if (rsize < exe_sections[nsections - 1].ursz) { |
|
3706 |
- rsize = exe_sections[nsections - 1].ursz; |
|
3703 |
+ vsize = peinfo->sections[peinfo->nsections - 1].uvsz; |
|
3704 |
+ rsize = peinfo->sections[peinfo->nsections - 1].rsz; |
|
3705 |
+ if (rsize < peinfo->sections[peinfo->nsections - 1].ursz) { |
|
3706 |
+ rsize = peinfo->sections[peinfo->nsections - 1].ursz; |
|
3707 | 3707 |
dam = 1; |
3708 | 3708 |
} |
3709 | 3709 |
|
... | ... |
@@ -3711,18 +3123,18 @@ int cli_scanpe(cli_ctx *ctx) |
3711 | 3711 |
int bw = rsize < 0x7000 ? rsize : 0x7000; |
3712 | 3712 |
const char *tbuff; |
3713 | 3713 |
|
3714 |
- if ((tbuff = fmap_need_off_once(map, exe_sections[nsections - 1].raw + rsize - bw, 4096))) { |
|
3714 |
+ if ((tbuff = fmap_need_off_once(map, peinfo->sections[peinfo->nsections - 1].raw + rsize - bw, 4096))) { |
|
3715 | 3715 |
if (cli_memstr(tbuff, 4091, "\xe8\x2c\x61\x00\x00", 5)) { |
3716 | 3716 |
ret = cli_append_virus(ctx, dam ? "Heuristics.W32.Magistr.A.dam" : "Heuristics.W32.Magistr.A"); |
3717 | 3717 |
if (ret != CL_CLEAN) { |
3718 | 3718 |
if (ret == CL_VIRUS) { |
3719 | 3719 |
if (!SCAN_ALLMATCHES) { |
3720 |
- free(exe_sections); |
|
3720 |
+ cli_exe_info_destroy(peinfo); |
|
3721 | 3721 |
return ret; |
3722 | 3722 |
} else |
3723 | 3723 |
viruses_found++; |
3724 | 3724 |
} else { |
3725 |
- free(exe_sections); |
|
3725 |
+ cli_exe_info_destroy(peinfo); |
|
3726 | 3726 |
return ret; |
3727 | 3727 |
} |
3728 | 3728 |
} |
... | ... |
@@ -3732,18 +3144,18 @@ int cli_scanpe(cli_ctx *ctx) |
3732 | 3732 |
int bw = rsize < 0x8000 ? rsize : 0x8000; |
3733 | 3733 |
const char *tbuff; |
3734 | 3734 |
|
3735 |
- if ((tbuff = fmap_need_off_once(map, exe_sections[nsections - 1].raw + rsize - bw, 4096))) { |
|
3735 |
+ if ((tbuff = fmap_need_off_once(map, peinfo->sections[peinfo->nsections - 1].raw + rsize - bw, 4096))) { |
|
3736 | 3736 |
if (cli_memstr(tbuff, 4091, "\xe8\x04\x72\x00\x00", 5)) { |
3737 | 3737 |
ret = cli_append_virus(ctx, dam ? "Heuristics.W32.Magistr.B.dam" : "Heuristics.W32.Magistr.B"); |
3738 | 3738 |
if (ret != CL_CLEAN) { |
3739 | 3739 |
if (ret == CL_VIRUS) { |
3740 | 3740 |
if (!SCAN_ALLMATCHES) { |
3741 |
- free(exe_sections); |
|
3741 |
+ cli_exe_info_destroy(peinfo); |
|
3742 | 3742 |
return ret; |
3743 | 3743 |
} else |
3744 | 3744 |
viruses_found++; |
3745 | 3745 |
} else { |
3746 |
- free(exe_sections); |
|
3746 |
+ cli_exe_info_destroy(peinfo); |
|
3747 | 3747 |
return ret; |
3748 | 3748 |
} |
3749 | 3749 |
} |
... | ... |
@@ -3753,24 +3165,25 @@ int cli_scanpe(cli_ctx *ctx) |
3753 | 3753 |
} |
3754 | 3754 |
|
3755 | 3755 |
/* W32.Polipos.A */ |
3756 |
- while (polipos && !dll && nsections > 2 && nsections < 13 && e_lfanew <= 0x800 && (EC16(optional_hdr32.Subsystem) == 2 || EC16(optional_hdr32.Subsystem) == 3) && EC16(file_hdr.Machine) == 0x14c && optional_hdr32.SizeOfStackReserve >= 0x80000) { |
|
3756 |
+ // TODO Add endianness correction to SizeOfStackReserve access |
|
3757 |
+ 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) { |
|
3757 | 3758 |
uint32_t jump, jold, *jumps = NULL; |
3758 | 3759 |
const uint8_t *code; |
3759 | 3760 |
unsigned int xsjs = 0; |
3760 | 3761 |
|
3761 |
- if (exe_sections[0].rsz > CLI_MAX_ALLOCATION) |
|
3762 |
+ if (peinfo->sections[0].rsz > CLI_MAX_ALLOCATION) |
|
3762 | 3763 |
break; |
3763 |
- if (exe_sections[0].rsz < 5) |
|
3764 |
+ if (peinfo->sections[0].rsz < 5) |
|
3764 | 3765 |
break; |
3765 |
- if (!(code = fmap_need_off_once(map, exe_sections[0].raw, exe_sections[0].rsz))) |
|
3766 |
+ if (!(code = fmap_need_off_once(map, peinfo->sections[0].raw, peinfo->sections[0].rsz))) |
|
3766 | 3767 |
break; |
3767 | 3768 |
|
3768 |
- for (i = 0; i < exe_sections[0].rsz - 5; i++) { |
|
3769 |
+ for (i = 0; i < peinfo->sections[0].rsz - 5; i++) { |
|
3769 | 3770 |
if ((uint8_t)(code[i] - 0xe8) > 1) |
3770 | 3771 |
continue; |
3771 | 3772 |
|
3772 |
- jump = cli_rawaddr(exe_sections[0].rva + i + 5 + cli_readint32(&code[i + 1]), exe_sections, nsections, &err, fsize, hdr_size); |
|
3773 |
- if (err || !CLI_ISCONTAINED(exe_sections[polipos].raw, exe_sections[polipos].rsz, jump, 9)) |
|
3773 |
+ jump = cli_rawaddr(peinfo->sections[0].rva + i + 5 + cli_readint32(&code[i + 1]), peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size); |
|
3774 |
+ if (err || !CLI_ISCONTAINED(peinfo->sections[polipos].raw, peinfo->sections[polipos].rsz, jump, 9)) |
|
3774 | 3775 |
continue; |
3775 | 3776 |
|
3776 | 3777 |
if (xsjs % 128 == 0) { |
... | ... |
@@ -3778,7 +3191,7 @@ int cli_scanpe(cli_ctx *ctx) |
3778 | 3778 |
break; |
3779 | 3779 |
|
3780 | 3780 |
if (!(jumps = (uint32_t *)cli_realloc2(jumps, (xsjs + 128) * sizeof(uint32_t)))) { |
3781 |
- free(exe_sections); |
|
3781 |
+ cli_exe_info_destroy(peinfo); |
|
3782 | 3782 |
return CL_EMEM; |
3783 | 3783 |
} |
3784 | 3784 |
} |
... | ... |
@@ -3804,7 +3217,7 @@ int cli_scanpe(cli_ctx *ctx) |
3804 | 3804 |
if (!xsjs) |
3805 | 3805 |
break; |
3806 | 3806 |
|
3807 |
- cli_dbgmsg("Polipos: Checking %d xsect jump(s)\n", xsjs); |
|
3807 |
+ cli_dbgmsg("cli_scanpe: Polipos: Checking %d xsect jump(s)\n", xsjs); |
|
3808 | 3808 |
for (i = 0; i < xsjs; i++) { |
3809 | 3809 |
if (!(code = fmap_need_off_once(map, jumps[i], 9))) |
3810 | 3810 |
continue; |
... | ... |
@@ -3815,13 +3228,13 @@ int cli_scanpe(cli_ctx *ctx) |
3815 | 3815 |
if (ret == CL_VIRUS) { |
3816 | 3816 |
if (!SCAN_ALLMATCHES) { |
3817 | 3817 |
free(jumps); |
3818 |
- free(exe_sections); |
|
3818 |
+ cli_exe_info_destroy(peinfo); |
|
3819 | 3819 |
return ret; |
3820 | 3820 |
} else |
3821 | 3821 |
viruses_found++; |
3822 | 3822 |
} else { |
3823 | 3823 |
free(jumps); |
3824 |
- free(exe_sections); |
|
3824 |
+ cli_exe_info_destroy(peinfo); |
|
3825 | 3825 |
return ret; |
3826 | 3826 |
} |
3827 | 3827 |
} |
... | ... |
@@ -3833,30 +3246,30 @@ int cli_scanpe(cli_ctx *ctx) |
3833 | 3833 |
} |
3834 | 3834 |
|
3835 | 3835 |
/* Trojan.Swizzor.Gen */ |
3836 |
- if (SCAN_HEURISTICS && (DCONF & PE_CONF_SWIZZOR) && nsections > 1 && fsize > 64 * 1024 && fsize < 4 * 1024 * 1024) { |
|
3837 |
- if (dirs[2].Size) { |
|
3836 |
+ if (SCAN_HEURISTICS && (DCONF & PE_CONF_SWIZZOR) && peinfo->nsections > 1 && fsize > 64 * 1024 && fsize < 4 * 1024 * 1024) { |
|
3837 |
+ if (peinfo->dirs[2].Size) { |
|
3838 | 3838 |
struct swizz_stats *stats = cli_calloc(1, sizeof(*stats)); |
3839 | 3839 |
unsigned int m = 1000; |
3840 | 3840 |
ret = CL_CLEAN; |
3841 | 3841 |
|
3842 | 3842 |
if (!stats) { |
3843 |
- free(exe_sections); |
|
3843 |
+ cli_exe_info_destroy(peinfo); |
|
3844 | 3844 |
return CL_EMEM; |
3845 | 3845 |
} else { |
3846 |
- cli_parseres_special(EC32(dirs[2].VirtualAddress), EC32(dirs[2].VirtualAddress), map, exe_sections, nsections, fsize, hdr_size, 0, 0, &m, stats); |
|
3846 |
+ cli_parseres_special(EC32(peinfo->dirs[2].VirtualAddress), EC32(peinfo->dirs[2].VirtualAddress), map, peinfo, fsize, 0, 0, &m, stats); |
|
3847 | 3847 |
if ((ret = cli_detect_swizz(stats)) == CL_VIRUS) { |
3848 | 3848 |
ret = cli_append_virus(ctx, "Heuristics.Trojan.Swizzor.Gen"); |
3849 | 3849 |
if (ret != CL_CLEAN) { |
3850 | 3850 |
if (ret == CL_VIRUS) { |
3851 | 3851 |
if (!SCAN_ALLMATCHES) { |
3852 | 3852 |
free(stats); |
3853 |
- free(exe_sections); |
|
3853 |
+ cli_exe_info_destroy(peinfo); |
|
3854 | 3854 |
return ret; |
3855 | 3855 |
} else |
3856 | 3856 |
viruses_found++; |
3857 | 3857 |
} else { |
3858 | 3858 |
free(stats); |
3859 |
- free(exe_sections); |
|
3859 |
+ cli_exe_info_destroy(peinfo); |
|
3860 | 3860 |
return ret; |
3861 | 3861 |
} |
3862 | 3862 |
} |
... | ... |
@@ -3874,10 +3287,10 @@ int cli_scanpe(cli_ctx *ctx) |
3874 | 3874 |
/* try to find the first section with physical size == 0 */ |
3875 | 3875 |
found = 0; |
3876 | 3876 |
if (DCONF & (PE_CONF_UPX | PE_CONF_FSG | PE_CONF_MEW)) { |
3877 |
- for (i = 0; i < (unsigned int)nsections - 1; i++) { |
|
3878 |
- if (!exe_sections[i].rsz && exe_sections[i].vsz && exe_sections[i + 1].rsz && exe_sections[i + 1].vsz) { |
|
3877 |
+ for (i = 0; i < (unsigned int)peinfo->nsections - 1; i++) { |
|
3878 |
+ if (!peinfo->sections[i].rsz && peinfo->sections[i].vsz && peinfo->sections[i + 1].rsz && peinfo->sections[i + 1].vsz) { |
|
3879 | 3879 |
found = 1; |
3880 |
- cli_dbgmsg("UPX/FSG/MEW: empty section found - assuming compression\n"); |
|
3880 |
+ cli_dbgmsg("cli_scanpe: UPX/FSG/MEW: empty section found - assuming compression\n"); |
|
3881 | 3881 |
#if HAVE_JSON |
3882 | 3882 |
if (pe_json != NULL) |
3883 | 3883 |
cli_jsonbool(pe_json, "HasEmptySection", 1); |
... | ... |
@@ -3892,85 +3305,85 @@ int cli_scanpe(cli_ctx *ctx) |
3892 | 3892 |
uint32_t fileoffset; |
3893 | 3893 |
const char *tbuff; |
3894 | 3894 |
|
3895 |
- fileoffset = (vep + cli_readint32(epbuff + 1) + 5); |
|
3895 |
+ fileoffset = (peinfo->vep + cli_readint32(epbuff + 1) + 5); |
|
3896 | 3896 |
while (fileoffset == 0x154 || fileoffset == 0x158) { |
3897 | 3897 |
char *src; |
3898 | 3898 |
uint32_t offdiff, uselzma; |
3899 | 3899 |
|
3900 |
- cli_dbgmsg("MEW: found MEW characteristics %08X + %08X + 5 = %08X\n", |
|
3901 |
- cli_readint32(epbuff + 1), vep, cli_readint32(epbuff + 1) + vep + 5); |
|
3900 |
+ cli_dbgmsg("cli_scanpe: MEW: found MEW characteristics %08X + %08X + 5 = %08X\n", |
|
3901 |
+ cli_readint32(epbuff + 1), peinfo->vep, cli_readint32(epbuff + 1) + peinfo->vep + 5); |
|
3902 | 3902 |
|
3903 | 3903 |
if (!(tbuff = fmap_need_off_once(map, fileoffset, 0xb0))) |
3904 | 3904 |
break; |
3905 | 3905 |
|
3906 | 3906 |
if (fileoffset == 0x154) |
3907 |
- cli_dbgmsg("MEW: Win9x compatibility was set!\n"); |
|
3907 |
+ cli_dbgmsg("cli_scanpe: MEW: Win9x compatibility was set!\n"); |
|
3908 | 3908 |
else |
3909 |
- cli_dbgmsg("MEW: Win9x compatibility was NOT set!\n"); |
|
3909 |
+ cli_dbgmsg("cli_scanpe: MEW: Win9x compatibility was NOT set!\n"); |
|
3910 | 3910 |
|
3911 |
- offdiff = cli_readint32(tbuff + 1) - EC32(optional_hdr32.ImageBase); |
|
3912 |
- if ((offdiff <= exe_sections[i + 1].rva) || |
|
3913 |
- (offdiff >= exe_sections[i + 1].rva + exe_sections[i + 1].raw - 4)) { |
|
3914 |
- cli_dbgmsg("MEW: ESI is not in proper section\n"); |
|
3911 |
+ offdiff = cli_readint32(tbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase); |
|
3912 |
+ if ((offdiff <= peinfo->sections[i + 1].rva) || |
|
3913 |
+ (offdiff >= peinfo->sections[i + 1].rva + peinfo->sections[i + 1].raw - 4)) { |
|
3914 |
+ cli_dbgmsg("cli_scanpe: MEW: ESI is not in proper section\n"); |
|
3915 | 3915 |
break; |
3916 | 3916 |
} |
3917 | 3917 |
|
3918 |
- offdiff -= exe_sections[i + 1].rva; |
|
3918 |
+ offdiff -= peinfo->sections[i + 1].rva; |
|
3919 | 3919 |
|
3920 |
- if (!exe_sections[i + 1].rsz) { |
|
3921 |
- cli_dbgmsg("MEW: mew section is empty\n"); |
|
3920 |
+ if (!peinfo->sections[i + 1].rsz) { |
|
3921 |
+ cli_dbgmsg("cli_scanpe: MEW: mew section is empty\n"); |
|
3922 | 3922 |
break; |
3923 | 3923 |
} |
3924 | 3924 |
|
3925 |
- ssize = exe_sections[i + 1].vsz; |
|
3926 |
- dsize = exe_sections[i].vsz; |
|
3925 |
+ ssize = peinfo->sections[i + 1].vsz; |
|
3926 |
+ dsize = peinfo->sections[i].vsz; |
|
3927 | 3927 |
|
3928 | 3928 |
/* Guard against integer overflow */ |
3929 | 3929 |
if ((ssize + dsize < ssize) || (ssize + dsize < dsize)) { |
3930 |
- cli_dbgmsg("MEW: section size (%08x) + diff size (%08x) exceeds max size of unsigned int (%08x)\n", ssize, dsize, UINT32_MAX); |
|
3930 |
+ cli_dbgmsg("cli_scanpe: MEW: section size (%08x) + diff size (%08x) exceeds max size of unsigned int (%08x)\n", ssize, dsize, UINT32_MAX); |
|
3931 | 3931 |
break; |
3932 | 3932 |
} |
3933 | 3933 |
|
3934 | 3934 |
/* Verify that offdiff does not exceed the ssize + sdiff */ |
3935 | 3935 |
if (offdiff >= ssize + dsize) { |
3936 |
- cli_dbgmsg("MEW: offdiff (%08x) exceeds section size + diff size (%08x)\n", offdiff, ssize + dsize); |
|
3936 |
+ cli_dbgmsg("cli_scanpe: MEW: offdiff (%08x) exceeds section size + diff size (%08x)\n", offdiff, ssize + dsize); |
|
3937 | 3937 |
break; |
3938 | 3938 |
} |
3939 | 3939 |
|
3940 |
- cli_dbgmsg("MEW: ssize %08x dsize %08x offdiff: %08x\n", ssize, dsize, offdiff); |
|
3940 |
+ cli_dbgmsg("cli_scanpe: MEW: ssize %08x dsize %08x offdiff: %08x\n", ssize, dsize, offdiff); |
|
3941 | 3941 |
|
3942 |
- CLI_UNPSIZELIMITS("MEW", MAX(ssize, dsize)); |
|
3943 |
- CLI_UNPSIZELIMITS("MEW", MAX(ssize + dsize, exe_sections[i + 1].rsz)); |
|
3942 |
+ CLI_UNPSIZELIMITS("cli_scanpe: MEW", MAX(ssize, dsize)); |
|
3943 |
+ CLI_UNPSIZELIMITS("cli_scanpe: MEW", MAX(ssize + dsize, peinfo->sections[i + 1].rsz)); |
|
3944 | 3944 |
|
3945 |
- if (exe_sections[i + 1].rsz < offdiff + 12 || exe_sections[i + 1].rsz > ssize) { |
|
3946 |
- cli_dbgmsg("MEW: Size mismatch: %08x\n", exe_sections[i + 1].rsz); |
|
3945 |
+ if (peinfo->sections[i + 1].rsz < offdiff + 12 || peinfo->sections[i + 1].rsz > ssize) { |
|
3946 |
+ cli_dbgmsg("cli_scanpe: MEW: Size mismatch: %08x\n", peinfo->sections[i + 1].rsz); |
|
3947 | 3947 |
break; |
3948 | 3948 |
} |
3949 | 3949 |
|
3950 | 3950 |
/* allocate needed buffer */ |
3951 | 3951 |
if (!(src = cli_calloc(ssize + dsize, sizeof(char)))) { |
3952 |
- free(exe_sections); |
|
3952 |
+ cli_exe_info_destroy(peinfo); |
|
3953 | 3953 |
return CL_EMEM; |
3954 | 3954 |
} |
3955 | 3955 |
|
3956 |
- if ((bytes = fmap_readn(map, src + dsize, exe_sections[i + 1].raw, exe_sections[i + 1].rsz)) != exe_sections[i + 1].rsz) { |
|
3957 |
- cli_dbgmsg("MEW: Can't read %d bytes [read: %lu]\n", exe_sections[i + 1].rsz, (unsigned long)bytes); |
|
3958 |
- free(exe_sections); |
|
3956 |
+ if ((bytes = fmap_readn(map, src + dsize, peinfo->sections[i + 1].raw, peinfo->sections[i + 1].rsz)) != peinfo->sections[i + 1].rsz) { |
|
3957 |
+ cli_dbgmsg("cli_scanpe: MEW: Can't read %d bytes [read: %lu]\n", peinfo->sections[i + 1].rsz, (unsigned long)bytes); |
|
3958 |
+ cli_exe_info_destroy(peinfo); |
|
3959 | 3959 |
free(src); |
3960 | 3960 |
return CL_EREAD; |
3961 | 3961 |
} |
3962 | 3962 |
|
3963 |
- cli_dbgmsg("MEW: %u (%08x) bytes read\n", (unsigned int)bytes, (unsigned int)bytes); |
|
3963 |
+ cli_dbgmsg("cli_scanpe: MEW: %u (%08x) bytes read\n", (unsigned int)bytes, (unsigned int)bytes); |
|
3964 | 3964 |
|
3965 | 3965 |
/* count offset to lzma proc, if lzma used, 0xe8 -> call */ |
3966 | 3966 |
if (tbuff[0x7b] == '\xe8') { |
3967 |
- if (!CLI_ISCONTAINED(exe_sections[1].rva, exe_sections[1].vsz, cli_readint32(tbuff + 0x7c) + fileoffset + 0x80, 4)) { |
|
3968 |
- cli_dbgmsg("MEW: lzma proc out of bounds!\n"); |
|
3967 |
+ if (!CLI_ISCONTAINED(peinfo->sections[1].rva, peinfo->sections[1].vsz, cli_readint32(tbuff + 0x7c) + fileoffset + 0x80, 4)) { |
|
3968 |
+ cli_dbgmsg("cli_scanpe: MEW: lzma proc out of bounds!\n"); |
|
3969 | 3969 |
free(src); |
3970 | 3970 |
break; /* to next unpacker in chain */ |
3971 | 3971 |
} |
3972 | 3972 |
|
3973 |
- uselzma = cli_readint32(tbuff + 0x7c) - (exe_sections[0].rva - fileoffset - 0x80); |
|
3973 |
+ uselzma = cli_readint32(tbuff + 0x7c) - (peinfo->sections[0].rva - fileoffset - 0x80); |
|
3974 | 3974 |
} else { |
3975 | 3975 |
uselzma = 0; |
3976 | 3976 |
} |
... | ... |
@@ -3980,14 +3393,15 @@ int cli_scanpe(cli_ctx *ctx) |
3980 | 3980 |
cli_jsonstr(pe_json, "Packer", "MEW"); |
3981 | 3981 |
#endif |
3982 | 3982 |
|
3983 |
- CLI_UNPTEMP("MEW", (src, exe_sections, 0)); |
|
3984 |
- CLI_UNPRESULTS("MEW", (unmew11(src, offdiff, ssize, dsize, EC32(optional_hdr32.ImageBase), exe_sections[0].rva, uselzma, ndesc)), 1, (src, 0)); |
|
3983 |
+ CLI_UNPTEMP("cli_scanpe: MEW", (src, 0)); |
|
3984 |
+ 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)); |
|
3985 | 3985 |
break; |
3986 | 3986 |
} |
3987 | 3987 |
} |
3988 | 3988 |
|
3989 |
+ // TODO Why do we bail here |
|
3989 | 3990 |
if (epsize < 168) { |
3990 |
- free(exe_sections); |
|
3991 |
+ cli_exe_info_destroy(peinfo); |
|
3991 | 3992 |
return CL_CLEAN; |
3992 | 3993 |
} |
3993 | 3994 |
|
... | ... |
@@ -4014,70 +3428,70 @@ int cli_scanpe(cli_ctx *ctx) |
4014 | 4014 |
* |
4015 | 4015 |
*/ |
4016 | 4016 |
/* upack 0.39-3s + sample 0151477*/ |
4017 |
- while (((upack && nsections == 3) && /* 3 sections */ |
|
4017 |
+ while (((upack && peinfo->nsections == 3) && /* 3 sections */ |
|
4018 | 4018 |
(( |
4019 |
- epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) > min && /* mov esi */ |
|
4020 |
- epbuff[5] == '\xad' && epbuff[6] == '\x50' /* lodsd; push eax */ |
|
4019 |
+ epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase) > peinfo->min && /* mov esi */ |
|
4020 |
+ epbuff[5] == '\xad' && epbuff[6] == '\x50' /* lodsd; push eax */ |
|
4021 | 4021 |
) || |
4022 | 4022 |
/* based on 0297729 sample from aCaB */ |
4023 |
- (epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) > min && /* mov esi */ |
|
4024 |
- epbuff[5] == '\xff' && epbuff[6] == '\x36' /* push [esi] */ |
|
4023 |
+ (epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase) > peinfo->min && /* mov esi */ |
|
4024 |
+ epbuff[5] == '\xff' && epbuff[6] == '\x36' /* push [esi] */ |
|
4025 | 4025 |
))) || |
4026 |
- ((!upack && nsections == 2) && /* 2 sections */ |
|
4026 |
+ ((!upack && peinfo->nsections == 2) && /* 2 sections */ |
|
4027 | 4027 |
(( /* upack 0.39-2s */ |
4028 | 4028 |
epbuff[0] == '\x60' && epbuff[1] == '\xe8' && cli_readint32(epbuff + 2) == 0x9 /* pusha; call+9 */ |
4029 | 4029 |
) || |
4030 |
- ( /* upack 1.1/1.2, based on 2 samples */ |
|
4031 |
- epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) < min && /* mov esi */ |
|
4032 |
- cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) > 0 && |
|
4030 |
+ ( /* upack 1.1/1.2, based on 2 samples */ |
|
4031 |
+ epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase) < peinfo->min && /* mov esi */ |
|
4032 |
+ cli_readint32(epbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase) > 0 && |
|
4033 | 4033 |
epbuff[5] == '\xad' && epbuff[6] == '\x8b' && epbuff[7] == '\xf8' /* loads; mov edi, eax */ |
4034 | 4034 |
)))) { |
4035 | 4035 |
uint32_t vma, off; |
4036 | 4036 |
int a, b, c; |
4037 | 4037 |
|
4038 |
- cli_dbgmsg("Upack characteristics found.\n"); |
|
4039 |
- a = exe_sections[0].vsz; |
|
4040 |
- b = exe_sections[1].vsz; |
|
4038 |
+ cli_dbgmsg("cli_scanpe: Upack characteristics found.\n"); |
|
4039 |
+ a = peinfo->sections[0].vsz; |
|
4040 |
+ b = peinfo->sections[1].vsz; |
|
4041 | 4041 |
if (upack) { |
4042 |
- cli_dbgmsg("Upack: var set\n"); |
|
4042 |
+ cli_dbgmsg("cli_scanpe: Upack: var set\n"); |
|
4043 | 4043 |
|
4044 |
- c = exe_sections[2].vsz; |
|
4045 |
- ssize = exe_sections[0].ursz + exe_sections[0].uraw; |
|
4046 |
- off = exe_sections[0].rva; |
|
4047 |
- vma = EC32(optional_hdr32.ImageBase) + exe_sections[0].rva; |
|
4044 |
+ c = peinfo->sections[2].vsz; |
|
4045 |
+ ssize = peinfo->sections[0].ursz + peinfo->sections[0].uraw; |
|
4046 |
+ off = peinfo->sections[0].rva; |
|
4047 |
+ vma = EC32(peinfo->pe_opt.opt32.ImageBase) + peinfo->sections[0].rva; |
|
4048 | 4048 |
} else { |
4049 |
- cli_dbgmsg("Upack: var NOT set\n"); |
|
4050 |
- c = exe_sections[1].rva; |
|
4051 |
- ssize = exe_sections[1].uraw; |
|
4049 |
+ cli_dbgmsg("cli_scanpe: Upack: var NOT set\n"); |
|
4050 |
+ c = peinfo->sections[1].rva; |
|
4051 |
+ ssize = peinfo->sections[1].uraw; |
|
4052 | 4052 |
off = 0; |
4053 |
- vma = exe_sections[1].rva - exe_sections[1].uraw; |
|
4053 |
+ vma = peinfo->sections[1].rva - peinfo->sections[1].uraw; |
|
4054 | 4054 |
} |
4055 | 4055 |
|
4056 | 4056 |
dsize = a + b + c; |
4057 | 4057 |
|
4058 |
- CLI_UNPSIZELIMITS("Upack", MAX(MAX(dsize, ssize), exe_sections[1].ursz)); |
|
4058 |
+ CLI_UNPSIZELIMITS("cli_scanpe: Upack", MAX(MAX(dsize, ssize), peinfo->sections[1].ursz)); |
|
4059 | 4059 |
|
4060 |
- if (!CLI_ISCONTAINED(0, dsize, exe_sections[1].rva - off, exe_sections[1].ursz) || (upack && !CLI_ISCONTAINED(0, dsize, exe_sections[2].rva - exe_sections[0].rva, ssize)) || ssize > dsize) { |
|
4061 |
- cli_dbgmsg("Upack: probably malformed pe-header, skipping to next unpacker\n"); |
|
4060 |
+ if (!CLI_ISCONTAINED(0, dsize, peinfo->sections[1].rva - off, peinfo->sections[1].ursz) || (upack && !CLI_ISCONTAINED(0, dsize, peinfo->sections[2].rva - peinfo->sections[0].rva, ssize)) || ssize > dsize) { |
|
4061 |
+ cli_dbgmsg("cli_scanpe: Upack: probably malformed pe-header, skipping to next unpacker\n"); |
|
4062 | 4062 |
break; |
4063 | 4063 |
} |
4064 | 4064 |
|
4065 | 4065 |
if ((dest = (char *)cli_calloc(dsize, sizeof(char))) == NULL) { |
4066 |
- free(exe_sections); |
|
4066 |
+ cli_exe_info_destroy(peinfo); |
|
4067 | 4067 |
return CL_EMEM; |
4068 | 4068 |
} |
4069 | 4069 |
|
4070 | 4070 |
if ((unsigned int)fmap_readn(map, dest, 0, ssize) != ssize) { |
4071 |
- cli_dbgmsg("Upack: Can't read raw data of section 0\n"); |
|
4071 |
+ cli_dbgmsg("cli_scanpe: Upack: Can't read raw data of section 0\n"); |
|
4072 | 4072 |
free(dest); |
4073 | 4073 |
break; |
4074 | 4074 |
} |
4075 | 4075 |
|
4076 | 4076 |
if (upack) |
4077 |
- memmove(dest + exe_sections[2].rva - exe_sections[0].rva, dest, ssize); |
|
4077 |
+ memmove(dest + peinfo->sections[2].rva - peinfo->sections[0].rva, dest, ssize); |
|
4078 | 4078 |
|
4079 |
- if ((unsigned int)fmap_readn(map, dest + exe_sections[1].rva - off, exe_sections[1].uraw, exe_sections[1].ursz) != exe_sections[1].ursz) { |
|
4080 |
- cli_dbgmsg("Upack: Can't read raw data of section 1\n"); |
|
4079 |
+ if ((unsigned int)fmap_readn(map, dest + peinfo->sections[1].rva - off, peinfo->sections[1].uraw, peinfo->sections[1].ursz) != peinfo->sections[1].ursz) { |
|
4080 |
+ cli_dbgmsg("cli_scanpe: Upack: Can't read raw data of section 1\n"); |
|
4081 | 4081 |
free(dest); |
4082 | 4082 |
break; |
4083 | 4083 |
} |
... | ... |
@@ -4087,8 +3501,8 @@ int cli_scanpe(cli_ctx *ctx) |
4087 | 4087 |
cli_jsonstr(pe_json, "Packer", "Upack"); |
4088 | 4088 |
#endif |
4089 | 4089 |
|
4090 |
- CLI_UNPTEMP("Upack", (dest, exe_sections, 0)); |
|
4091 |
- CLI_UNPRESULTS("Upack", (unupack(upack, dest, dsize, epbuff, vma, ep, EC32(optional_hdr32.ImageBase), exe_sections[0].rva, ndesc)), 1, (dest, 0)); |
|
4090 |
+ CLI_UNPTEMP("cli_scanpe: Upack", (dest, 0)); |
|
4091 |
+ 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)); |
|
4092 | 4092 |
|
4093 | 4093 |
break; |
4094 | 4094 |
} |
... | ... |
@@ -4100,72 +3514,72 @@ int cli_scanpe(cli_ctx *ctx) |
4100 | 4100 |
|
4101 | 4101 |
/* FSG v2.0 support - thanks to aCaB ! */ |
4102 | 4102 |
|
4103 |
- ssize = exe_sections[i + 1].rsz; |
|
4104 |
- dsize = exe_sections[i].vsz; |
|
4103 |
+ ssize = peinfo->sections[i + 1].rsz; |
|
4104 |
+ dsize = peinfo->sections[i].vsz; |
|
4105 | 4105 |
|
4106 |
- CLI_UNPSIZELIMITS("FSG", MAX(dsize, ssize)); |
|
4106 |
+ CLI_UNPSIZELIMITS("cli_scanpe: FSG", MAX(dsize, ssize)); |
|
4107 | 4107 |
|
4108 | 4108 |
if (ssize <= 0x19 || dsize <= ssize) { |
4109 |
- cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); |
|
4110 |
- free(exe_sections); |
|
4109 |
+ cli_dbgmsg("cli_scanpe: FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); |
|
4110 |
+ cli_exe_info_destroy(peinfo); |
|
4111 | 4111 |
return CL_CLEAN; |
4112 | 4112 |
} |
4113 | 4113 |
|
4114 |
- newedx = cli_readint32(epbuff + 2) - EC32(optional_hdr32.ImageBase); |
|
4115 |
- if (!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newedx, 4)) { |
|
4116 |
- cli_dbgmsg("FSG: xchg out of bounds (%x), giving up\n", newedx); |
|
4114 |
+ newedx = cli_readint32(epbuff + 2) - EC32(peinfo->pe_opt.opt32.ImageBase); |
|
4115 |
+ if (!CLI_ISCONTAINED(peinfo->sections[i + 1].rva, peinfo->sections[i + 1].rsz, newedx, 4)) { |
|
4116 |
+ cli_dbgmsg("cli_scanpe: FSG: xchg out of bounds (%x), giving up\n", newedx); |
|
4117 | 4117 |
break; |
4118 | 4118 |
} |
4119 | 4119 |
|
4120 |
- if (!exe_sections[i + 1].rsz || !(src = fmap_need_off_once(map, exe_sections[i + 1].raw, ssize))) { |
|
4121 |
- cli_dbgmsg("Can't read raw data of section %d\n", i + 1); |
|
4122 |
- free(exe_sections); |
|
4120 |
+ if (!peinfo->sections[i + 1].rsz || !(src = fmap_need_off_once(map, peinfo->sections[i + 1].raw, ssize))) { |
|
4121 |
+ cli_dbgmsg("cli_scanpe: Can't read raw data of section %d\n", i + 1); |
|
4122 |
+ cli_exe_info_destroy(peinfo); |
|
4123 | 4123 |
return CL_ESEEK; |
4124 | 4124 |
} |
4125 | 4125 |
|
4126 |
- dst = src + newedx - exe_sections[i + 1].rva; |
|
4127 |
- if (newedx < exe_sections[i + 1].rva || !CLI_ISCONTAINED(src, ssize, dst, 4)) { |
|
4128 |
- cli_dbgmsg("FSG: New ESP out of bounds\n"); |
|
4126 |
+ dst = src + newedx - peinfo->sections[i + 1].rva; |
|
4127 |
+ if (newedx < peinfo->sections[i + 1].rva || !CLI_ISCONTAINED(src, ssize, dst, 4)) { |
|
4128 |
+ cli_dbgmsg("cli_scanpe: FSG: New ESP out of bounds\n"); |
|
4129 | 4129 |
break; |
4130 | 4130 |
} |
4131 | 4131 |
|
4132 |
- newedx = cli_readint32(dst) - EC32(optional_hdr32.ImageBase); |
|
4133 |
- if (!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newedx, 4)) { |
|
4134 |
- cli_dbgmsg("FSG: New ESP (%x) is wrong\n", newedx); |
|
4132 |
+ newedx = cli_readint32(dst) - EC32(peinfo->pe_opt.opt32.ImageBase); |
|
4133 |
+ if (!CLI_ISCONTAINED(peinfo->sections[i + 1].rva, peinfo->sections[i + 1].rsz, newedx, 4)) { |
|
4134 |
+ cli_dbgmsg("cli_scanpe: FSG: New ESP (%x) is wrong\n", newedx); |
|
4135 | 4135 |
break; |
4136 | 4136 |
} |
4137 | 4137 |
|
4138 |
- dst = src + newedx - exe_sections[i + 1].rva; |
|
4138 |
+ dst = src + newedx - peinfo->sections[i + 1].rva; |
|
4139 | 4139 |
if (!CLI_ISCONTAINED(src, ssize, dst, 32)) { |
4140 |
- cli_dbgmsg("FSG: New stack out of bounds\n"); |
|
4140 |
+ cli_dbgmsg("cli_scanpe: FSG: New stack out of bounds\n"); |
|
4141 | 4141 |
break; |
4142 | 4142 |
} |
4143 | 4143 |
|
4144 |
- newedi = cli_readint32(dst) - EC32(optional_hdr32.ImageBase); |
|
4145 |
- newesi = cli_readint32(dst + 4) - EC32(optional_hdr32.ImageBase); |
|
4146 |
- newebx = cli_readint32(dst + 16) - EC32(optional_hdr32.ImageBase); |
|
4144 |
+ newedi = cli_readint32(dst) - EC32(peinfo->pe_opt.opt32.ImageBase); |
|
4145 |
+ newesi = cli_readint32(dst + 4) - EC32(peinfo->pe_opt.opt32.ImageBase); |
|
4146 |
+ newebx = cli_readint32(dst + 16) - EC32(peinfo->pe_opt.opt32.ImageBase); |
|
4147 | 4147 |
newedx = cli_readint32(dst + 20); |
4148 | 4148 |
|
4149 |
- if (newedi != exe_sections[i].rva) { |
|
4150 |
- cli_dbgmsg("FSG: Bad destination buffer (edi is %x should be %x)\n", newedi, exe_sections[i].rva); |
|
4149 |
+ if (newedi != peinfo->sections[i].rva) { |
|
4150 |
+ cli_dbgmsg("cli_scanpe: FSG: Bad destination buffer (edi is %x should be %x)\n", newedi, peinfo->sections[i].rva); |
|
4151 | 4151 |
break; |
4152 | 4152 |
} |
4153 | 4153 |
|
4154 |
- if (newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].rsz) { |
|
4155 |
- cli_dbgmsg("FSG: Source buffer out of section bounds\n"); |
|
4154 |
+ if (newesi < peinfo->sections[i + 1].rva || newesi - peinfo->sections[i + 1].rva >= peinfo->sections[i + 1].rsz) { |
|
4155 |
+ cli_dbgmsg("cli_scanpe: FSG: Source buffer out of section bounds\n"); |
|
4156 | 4156 |
break; |
4157 | 4157 |
} |
4158 | 4158 |
|
4159 |
- if (!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newebx, 16)) { |
|
4160 |
- cli_dbgmsg("FSG: Array of functions out of bounds\n"); |
|
4159 |
+ if (!CLI_ISCONTAINED(peinfo->sections[i + 1].rva, peinfo->sections[i + 1].rsz, newebx, 16)) { |
|
4160 |
+ cli_dbgmsg("cli_scanpe: FSG: Array of functions out of bounds\n"); |
|
4161 | 4161 |
break; |
4162 | 4162 |
} |
4163 | 4163 |
|
4164 |
- newedx = cli_readint32(newebx + 12 - exe_sections[i + 1].rva + src) - EC32(optional_hdr32.ImageBase); |
|
4165 |
- cli_dbgmsg("FSG: found old EP @%x\n", newedx); |
|
4164 |
+ newedx = cli_readint32(newebx + 12 - peinfo->sections[i + 1].rva + src) - EC32(peinfo->pe_opt.opt32.ImageBase); |
|
4165 |
+ cli_dbgmsg("cli_scanpe: FSG: found old EP @%x\n", newedx); |
|
4166 | 4166 |
|
4167 | 4167 |
if ((dest = (char *)cli_calloc(dsize, sizeof(char))) == NULL) { |
4168 |
- free(exe_sections); |
|
4168 |
+ cli_exe_info_destroy(peinfo); |
|
4169 | 4169 |
return CL_EMEM; |
4170 | 4170 |
} |
4171 | 4171 |
|
... | ... |
@@ -4174,12 +3588,12 @@ int cli_scanpe(cli_ctx *ctx) |
4174 | 4174 |
cli_jsonstr(pe_json, "Packer", "FSG"); |
4175 | 4175 |
#endif |
4176 | 4176 |
|
4177 |
- CLI_UNPTEMP("FSG", (dest, exe_sections, 0)); |
|
4178 |
- CLI_UNPRESULTSFSG2("FSG", (unfsg_200(newesi - exe_sections[i + 1].rva + src, dest, ssize + exe_sections[i + 1].rva - newesi, dsize, newedi, EC32(optional_hdr32.ImageBase), newedx, ndesc)), 1, (dest, 0)); |
|
4177 |
+ CLI_UNPTEMP("cli_scanpe: FSG", (dest, 0)); |
|
4178 |
+ 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)); |
|
4179 | 4179 |
break; |
4180 | 4180 |
} |
4181 | 4181 |
|
4182 |
- while (found && (DCONF & PE_CONF_FSG) && epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) < min) { |
|
4182 |
+ while (found && (DCONF & PE_CONF_FSG) && epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase) < peinfo->min) { |
|
4183 | 4183 |
int sectcnt = 0; |
4184 | 4184 |
const char *support; |
4185 | 4185 |
uint32_t newesi, newedi, oldep, gp, t; |
... | ... |
@@ -4187,43 +3601,43 @@ int cli_scanpe(cli_ctx *ctx) |
4187 | 4187 |
|
4188 | 4188 |
/* FSG support - v. 1.33 (thx trog for the many samples) */ |
4189 | 4189 |
|
4190 |
- ssize = exe_sections[i + 1].rsz; |
|
4191 |
- dsize = exe_sections[i].vsz; |
|
4190 |
+ ssize = peinfo->sections[i + 1].rsz; |
|
4191 |
+ dsize = peinfo->sections[i].vsz; |
|
4192 | 4192 |
|
4193 |
- CLI_UNPSIZELIMITS("FSG", MAX(dsize, ssize)); |
|
4193 |
+ CLI_UNPSIZELIMITS("cli_scanpe: FSG", MAX(dsize, ssize)); |
|
4194 | 4194 |
|
4195 | 4195 |
if (ssize <= 0x19 || dsize <= ssize) { |
4196 |
- cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); |
|
4197 |
- free(exe_sections); |
|
4196 |
+ cli_dbgmsg("cli_scanpe: FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); |
|
4197 |
+ cli_exe_info_destroy(peinfo); |
|
4198 | 4198 |
return CL_CLEAN; |
4199 | 4199 |
} |
4200 | 4200 |
|
4201 |
- if (!(t = cli_rawaddr(cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase), NULL, 0, &err, fsize, hdr_size)) && err) { |
|
4202 |
- cli_dbgmsg("FSG: Support data out of padding area\n"); |
|
4201 |
+ if (!(t = cli_rawaddr(cli_readint32(epbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase), NULL, 0, &err, fsize, peinfo->hdr_size)) && err) { |
|
4202 |
+ cli_dbgmsg("cli_scanpe: FSG: Support data out of padding area\n"); |
|
4203 | 4203 |
break; |
4204 | 4204 |
} |
4205 | 4205 |
|
4206 |
- gp = exe_sections[i + 1].raw - t; |
|
4206 |
+ gp = peinfo->sections[i + 1].raw - t; |
|
4207 | 4207 |
|
4208 |
- CLI_UNPSIZELIMITS("FSG", gp); |
|
4208 |
+ CLI_UNPSIZELIMITS("cli_scanpe: FSG", gp); |
|
4209 | 4209 |
|
4210 | 4210 |
if (!(support = fmap_need_off_once(map, t, gp))) { |
4211 |
- cli_dbgmsg("Can't read %d bytes from padding area\n", gp); |
|
4212 |
- free(exe_sections); |
|
4211 |
+ cli_dbgmsg("cli_scanpe: Can't read %d bytes from padding area\n", gp); |
|
4212 |
+ cli_exe_info_destroy(peinfo); |
|
4213 | 4213 |
return CL_EREAD; |
4214 | 4214 |
} |
4215 | 4215 |
|
4216 |
- /* newebx = cli_readint32(support) - EC32(optional_hdr32.ImageBase); Unused */ |
|
4217 |
- newedi = cli_readint32(support + 4) - EC32(optional_hdr32.ImageBase); /* 1st dest */ |
|
4218 |
- newesi = cli_readint32(support + 8) - EC32(optional_hdr32.ImageBase); /* Source */ |
|
4216 |
+ /* newebx = cli_readint32(support) - EC32(peinfo->pe_opt.opt32.ImageBase); Unused */ |
|
4217 |
+ newedi = cli_readint32(support + 4) - EC32(peinfo->pe_opt.opt32.ImageBase); /* 1st dest */ |
|
4218 |
+ newesi = cli_readint32(support + 8) - EC32(peinfo->pe_opt.opt32.ImageBase); /* Source */ |
|
4219 | 4219 |
|
4220 |
- if (newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].rsz) { |
|
4221 |
- cli_dbgmsg("FSG: Source buffer out of section bounds\n"); |
|
4220 |
+ if (newesi < peinfo->sections[i + 1].rva || newesi - peinfo->sections[i + 1].rva >= peinfo->sections[i + 1].rsz) { |
|
4221 |
+ cli_dbgmsg("cli_scanpe: FSG: Source buffer out of section bounds\n"); |
|
4222 | 4222 |
break; |
4223 | 4223 |
} |
4224 | 4224 |
|
4225 |
- if (newedi != exe_sections[i].rva) { |
|
4226 |
- cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, exe_sections[i].rva); |
|
4225 |
+ if (newedi != peinfo->sections[i].rva) { |
|
4226 |
+ cli_dbgmsg("cli_scanpe: FSG: Bad destination (is %x should be %x)\n", newedi, peinfo->sections[i].rva); |
|
4227 | 4227 |
break; |
4228 | 4228 |
} |
4229 | 4229 |
|
... | ... |
@@ -4234,14 +3648,14 @@ int cli_scanpe(cli_ctx *ctx) |
4234 | 4234 |
if (!rva) |
4235 | 4235 |
break; |
4236 | 4236 |
|
4237 |
- rva -= EC32(optional_hdr32.ImageBase) + 1; |
|
4237 |
+ rva -= EC32(peinfo->pe_opt.opt32.ImageBase) + 1; |
|
4238 | 4238 |
sectcnt++; |
4239 | 4239 |
|
4240 | 4240 |
if (rva % 0x1000) |
4241 |
- cli_dbgmsg("FSG: Original section %d is misaligned\n", sectcnt); |
|
4241 |
+ cli_dbgmsg("cli_scanpe: FSG: Original section %d is misaligned\n", sectcnt); |
|
4242 | 4242 |
|
4243 |
- if (rva < exe_sections[i].rva || rva - exe_sections[i].rva >= exe_sections[i].vsz) { |
|
4244 |
- cli_dbgmsg("FSG: Original section %d is out of bounds\n", sectcnt); |
|
4243 |
+ if (rva < peinfo->sections[i].rva || rva - peinfo->sections[i].rva >= peinfo->sections[i].vsz) { |
|
4244 |
+ cli_dbgmsg("cli_scanpe: FSG: Original section %d is out of bounds\n", sectcnt); |
|
4245 | 4245 |
break; |
4246 | 4246 |
} |
4247 | 4247 |
} |
... | ... |
@@ -4251,85 +3665,85 @@ int cli_scanpe(cli_ctx *ctx) |
4251 | 4251 |
} |
4252 | 4252 |
|
4253 | 4253 |
if ((sections = (struct cli_exe_section *)cli_malloc((sectcnt + 1) * sizeof(struct cli_exe_section))) == NULL) { |
4254 |
- cli_errmsg("FSG: Unable to allocate memory for sections %llu\n", (long long unsigned)((sectcnt + 1) * sizeof(struct cli_exe_section))); |
|
4255 |
- free(exe_sections); |
|
4254 |
+ cli_errmsg("cli_scanpe: FSG: Unable to allocate memory for sections %llu\n", (long long unsigned)((sectcnt + 1) * sizeof(struct cli_exe_section))); |
|
4255 |
+ cli_exe_info_destroy(peinfo); |
|
4256 | 4256 |
return CL_EMEM; |
4257 | 4257 |
} |
4258 | 4258 |
|
4259 | 4259 |
sections[0].rva = newedi; |
4260 | 4260 |
for (t = 1; t <= (uint32_t)sectcnt; t++) |
4261 |
- sections[t].rva = cli_readint32(support + 8 + t * 4) - 1 - EC32(optional_hdr32.ImageBase); |
|
4261 |
+ sections[t].rva = cli_readint32(support + 8 + t * 4) - 1 - EC32(peinfo->pe_opt.opt32.ImageBase); |
|
4262 | 4262 |
|
4263 |
- if (!exe_sections[i + 1].rsz || !(src = fmap_need_off_once(map, exe_sections[i + 1].raw, ssize))) { |
|
4264 |
- cli_dbgmsg("Can't read raw data of section %d\n", i); |
|
4265 |
- free(exe_sections); |
|
4263 |
+ if (!peinfo->sections[i + 1].rsz || !(src = fmap_need_off_once(map, peinfo->sections[i + 1].raw, ssize))) { |
|
4264 |
+ cli_dbgmsg("cli_scanpe: Can't read raw data of section %d\n", i); |
|
4265 |
+ cli_exe_info_destroy(peinfo); |
|
4266 | 4266 |
free(sections); |
4267 | 4267 |
return CL_EREAD; |
4268 | 4268 |
} |
4269 | 4269 |
|
4270 | 4270 |
if ((dest = (char *)cli_calloc(dsize, sizeof(char))) == NULL) { |
4271 |
- free(exe_sections); |
|
4271 |
+ cli_exe_info_destroy(peinfo); |
|
4272 | 4272 |
free(sections); |
4273 | 4273 |
return CL_EMEM; |
4274 | 4274 |
} |
4275 | 4275 |
|
4276 |
- oldep = vep + 161 + 6 + cli_readint32(epbuff + 163); |
|
4277 |
- cli_dbgmsg("FSG: found old EP @%x\n", oldep); |
|
4276 |
+ oldep = peinfo->vep + 161 + 6 + cli_readint32(epbuff + 163); |
|
4277 |
+ cli_dbgmsg("cli_scanpe: FSG: found old EP @%x\n", oldep); |
|
4278 | 4278 |
|
4279 | 4279 |
#if HAVE_JSON |
4280 | 4280 |
if (pe_json != NULL) |
4281 | 4281 |
cli_jsonstr(pe_json, "Packer", "FSG"); |
4282 | 4282 |
#endif |
4283 | 4283 |
|
4284 |
- CLI_UNPTEMP("FSG", (dest, sections, exe_sections, 0)); |
|
4285 |
- CLI_UNPRESULTSFSG1("FSG", (unfsg_133(src + newesi - exe_sections[i + 1].rva, dest, ssize + exe_sections[i + 1].rva - newesi, dsize, sections, sectcnt, EC32(optional_hdr32.ImageBase), oldep, ndesc)), 1, (dest, sections, 0)); |
|
4284 |
+ CLI_UNPTEMP("cli_scanpe: FSG", (dest, sections, 0)); |
|
4285 |
+ 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)); |
|
4286 | 4286 |
break; /* were done with 1.33 */ |
4287 | 4287 |
} |
4288 | 4288 |
|
4289 |
- while (found && (DCONF & PE_CONF_FSG) && epbuff[0] == '\xbb' && cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) < min && epbuff[5] == '\xbf' && epbuff[10] == '\xbe' && vep >= exe_sections[i + 1].rva && vep - exe_sections[i + 1].rva > exe_sections[i + 1].rva - 0xe0) { |
|
4289 |
+ 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) { |
|
4290 | 4290 |
int sectcnt = 0; |
4291 |
- uint32_t gp, t = cli_rawaddr(cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase), NULL, 0, &err, fsize, hdr_size); |
|
4291 |
+ uint32_t gp, t = cli_rawaddr(cli_readint32(epbuff + 1) - EC32(peinfo->pe_opt.opt32.ImageBase), NULL, 0, &err, fsize, peinfo->hdr_size); |
|
4292 | 4292 |
const char *support; |
4293 |
- uint32_t newesi = cli_readint32(epbuff + 11) - EC32(optional_hdr32.ImageBase); |
|
4294 |
- uint32_t newedi = cli_readint32(epbuff + 6) - EC32(optional_hdr32.ImageBase); |
|
4295 |
- uint32_t oldep = vep - exe_sections[i + 1].rva; |
|
4293 |
+ uint32_t newesi = cli_readint32(epbuff + 11) - EC32(peinfo->pe_opt.opt32.ImageBase); |
|
4294 |
+ uint32_t newedi = cli_readint32(epbuff + 6) - EC32(peinfo->pe_opt.opt32.ImageBase); |
|
4295 |
+ uint32_t oldep = peinfo->vep - peinfo->sections[i + 1].rva; |
|
4296 | 4296 |
struct cli_exe_section *sections; |
4297 | 4297 |
|
4298 | 4298 |
/* FSG support - v. 1.31 */ |
4299 | 4299 |
|
4300 |
- ssize = exe_sections[i + 1].rsz; |
|
4301 |
- dsize = exe_sections[i].vsz; |
|
4300 |
+ ssize = peinfo->sections[i + 1].rsz; |
|
4301 |
+ dsize = peinfo->sections[i].vsz; |
|
4302 | 4302 |
|
4303 | 4303 |
if (err) { |
4304 |
- cli_dbgmsg("FSG: Support data out of padding area\n"); |
|
4304 |
+ cli_dbgmsg("cli_scanpe: FSG: Support data out of padding area\n"); |
|
4305 | 4305 |
break; |
4306 | 4306 |
} |
4307 | 4307 |
|
4308 |
- if (newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].raw) { |
|
4309 |
- cli_dbgmsg("FSG: Source buffer out of section bounds\n"); |
|
4308 |
+ if (newesi < peinfo->sections[i + 1].rva || newesi - peinfo->sections[i + 1].rva >= peinfo->sections[i + 1].raw) { |
|
4309 |
+ cli_dbgmsg("cli_scanpe: FSG: Source buffer out of section bounds\n"); |
|
4310 | 4310 |
break; |
4311 | 4311 |
} |
4312 | 4312 |
|
4313 |
- if (newedi != exe_sections[i].rva) { |
|
4314 |
- cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, exe_sections[i].rva); |
|
4313 |
+ if (newedi != peinfo->sections[i].rva) { |
|
4314 |
+ cli_dbgmsg("cli_scanpe: FSG: Bad destination (is %x should be %x)\n", newedi, peinfo->sections[i].rva); |
|
4315 | 4315 |
break; |
4316 | 4316 |
} |
4317 | 4317 |
|
4318 |
- CLI_UNPSIZELIMITS("FSG", MAX(dsize, ssize)); |
|
4318 |
+ CLI_UNPSIZELIMITS("cli_scanpe: FSG", MAX(dsize, ssize)); |
|
4319 | 4319 |
|
4320 | 4320 |
if (ssize <= 0x19 || dsize <= ssize) { |
4321 |
- cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); |
|
4322 |
- free(exe_sections); |
|
4321 |
+ cli_dbgmsg("cli_scanpe: FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); |
|
4322 |
+ cli_exe_info_destroy(peinfo); |
|
4323 | 4323 |
return CL_CLEAN; |
4324 | 4324 |
} |
4325 | 4325 |
|
4326 |
- gp = exe_sections[i + 1].raw - t; |
|
4326 |
+ gp = peinfo->sections[i + 1].raw - t; |
|
4327 | 4327 |
|
4328 |
- CLI_UNPSIZELIMITS("FSG", gp) |
|
4328 |
+ CLI_UNPSIZELIMITS("cli_scanpe: FSG", gp) |
|
4329 | 4329 |
|
4330 | 4330 |
if (!(support = fmap_need_off_once(map, t, gp))) { |
4331 |
- cli_dbgmsg("Can't read %d bytes from padding area\n", gp); |
|
4332 |
- free(exe_sections); |
|
4331 |
+ cli_dbgmsg("cli_scanpe: Can't read %d bytes from padding area\n", gp); |
|
4332 |
+ cli_exe_info_destroy(peinfo); |
|
4333 | 4333 |
return CL_EREAD; |
4334 | 4334 |
} |
4335 | 4335 |
|
... | ... |
@@ -4340,11 +3754,11 @@ int cli_scanpe(cli_ctx *ctx) |
4340 | 4340 |
if (rva == 2 || rva == 1) |
4341 | 4341 |
break; |
4342 | 4342 |
|
4343 |
- rva = ((rva - 2) << 12) - EC32(optional_hdr32.ImageBase); |
|
4343 |
+ rva = ((rva - 2) << 12) - EC32(peinfo->pe_opt.opt32.ImageBase); |
|
4344 | 4344 |
sectcnt++; |
4345 | 4345 |
|
4346 |
- if (rva < exe_sections[i].rva || rva - exe_sections[i].rva >= exe_sections[i].vsz) { |
|
4347 |
- cli_dbgmsg("FSG: Original section %d is out of bounds\n", sectcnt); |
|
4346 |
+ if (rva < peinfo->sections[i].rva || rva - peinfo->sections[i].rva >= peinfo->sections[i].vsz) { |
|
4347 |
+ cli_dbgmsg("cli_scanpe: FSG: Original section %d is out of bounds\n", sectcnt); |
|
4348 | 4348 |
break; |
4349 | 4349 |
} |
4350 | 4350 |
} |
... | ... |
@@ -4353,46 +3767,46 @@ int cli_scanpe(cli_ctx *ctx) |
4353 | 4353 |
break; |
4354 | 4354 |
|
4355 | 4355 |
if ((sections = (struct cli_exe_section *)cli_malloc((sectcnt + 1) * sizeof(struct cli_exe_section))) == NULL) { |
4356 |
- cli_errmsg("FSG: Unable to allocate memory for sections %llu\n", (long long unsigned)((sectcnt + 1) * sizeof(struct cli_exe_section))); |
|
4357 |
- free(exe_sections); |
|
4356 |
+ cli_errmsg("cli_scanpe: FSG: Unable to allocate memory for sections %llu\n", (long long unsigned)((sectcnt + 1) * sizeof(struct cli_exe_section))); |
|
4357 |
+ cli_exe_info_destroy(peinfo); |
|
4358 | 4358 |
return CL_EMEM; |
4359 | 4359 |
} |
4360 | 4360 |
|
4361 | 4361 |
sections[0].rva = newedi; |
4362 | 4362 |
for (t = 0; t <= (uint32_t)sectcnt - 1; t++) |
4363 |
- sections[t + 1].rva = (((support[t * 2] | (support[t * 2 + 1] << 8)) - 2) << 12) - EC32(optional_hdr32.ImageBase); |
|
4363 |
+ sections[t + 1].rva = (((support[t * 2] | (support[t * 2 + 1] << 8)) - 2) << 12) - EC32(peinfo->pe_opt.opt32.ImageBase); |
|
4364 | 4364 |
|
4365 |
- if (!exe_sections[i + 1].rsz || !(src = fmap_need_off_once(map, exe_sections[i + 1].raw, ssize))) { |
|
4366 |
- cli_dbgmsg("FSG: Can't read raw data of section %d\n", i); |
|
4367 |
- free(exe_sections); |
|
4365 |
+ if (!peinfo->sections[i + 1].rsz || !(src = fmap_need_off_once(map, peinfo->sections[i + 1].raw, ssize))) { |
|
4366 |
+ cli_dbgmsg("cli_scanpe: FSG: Can't read raw data of section %d\n", i); |
|
4367 |
+ cli_exe_info_destroy(peinfo); |
|
4368 | 4368 |
free(sections); |
4369 | 4369 |
return CL_EREAD; |
4370 | 4370 |
} |
4371 | 4371 |
|
4372 | 4372 |
if ((dest = (char *)cli_calloc(dsize, sizeof(char))) == NULL) { |
4373 |
- free(exe_sections); |
|
4373 |
+ cli_exe_info_destroy(peinfo); |
|
4374 | 4374 |
free(sections); |
4375 | 4375 |
return CL_EMEM; |
4376 | 4376 |
} |
4377 | 4377 |
|
4378 | 4378 |
gp = 0xda + 6 * (epbuff[16] == '\xe8'); |
4379 |
- oldep = vep + gp + 6 + cli_readint32(src + gp + 2 + oldep); |
|
4380 |
- cli_dbgmsg("FSG: found old EP @%x\n", oldep); |
|
4379 |
+ oldep = peinfo->vep + gp + 6 + cli_readint32(src + gp + 2 + oldep); |
|
4380 |
+ cli_dbgmsg("cli_scanpe: FSG: found old EP @%x\n", oldep); |
|
4381 | 4381 |
|
4382 | 4382 |
#if HAVE_JSON |
4383 | 4383 |
if (pe_json != NULL) |
4384 | 4384 |
cli_jsonstr(pe_json, "Packer", "FSG"); |
4385 | 4385 |
#endif |
4386 | 4386 |
|
4387 |
- CLI_UNPTEMP("FSG", (dest, sections, exe_sections, 0)); |
|
4388 |
- CLI_UNPRESULTSFSG1("FSG", (unfsg_133(src + newesi - exe_sections[i + 1].rva, dest, ssize + exe_sections[i + 1].rva - newesi, dsize, sections, sectcnt, EC32(optional_hdr32.ImageBase), oldep, ndesc)), 1, (dest, sections, 0)); |
|
4387 |
+ CLI_UNPTEMP("cli_scanpe: FSG", (dest, sections, 0)); |
|
4388 |
+ 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)); |
|
4389 | 4389 |
|
4390 | 4390 |
break; /* were done with 1.31 */ |
4391 | 4391 |
} |
4392 | 4392 |
|
4393 | 4393 |
if (found && (DCONF & PE_CONF_UPX)) { |
4394 |
- ssize = exe_sections[i + 1].rsz; |
|
4395 |
- dsize = exe_sections[i].vsz + exe_sections[i + 1].vsz; |
|
4394 |
+ ssize = peinfo->sections[i + 1].rsz; |
|
4395 |
+ dsize = peinfo->sections[i].vsz + peinfo->sections[i + 1].vsz; |
|
4396 | 4396 |
|
4397 | 4397 |
/* |
4398 | 4398 |
* UPX support |
... | ... |
@@ -4401,39 +3815,39 @@ int cli_scanpe(cli_ctx *ctx) |
4401 | 4401 |
|
4402 | 4402 |
/* cli_dbgmsg("UPX: ssize %u dsize %u\n", ssize, dsize); */ |
4403 | 4403 |
|
4404 |
- CLI_UNPSIZELIMITS("UPX", MAX(dsize, ssize)); |
|
4404 |
+ CLI_UNPSIZELIMITS("cli_scanpe: UPX", MAX(dsize, ssize)); |
|
4405 | 4405 |
|
4406 | 4406 |
if (ssize <= 0x19 || dsize <= ssize || dsize > CLI_MAX_ALLOCATION) { |
4407 |
- cli_dbgmsg("UPX: Size mismatch or dsize too big (ssize: %d, dsize: %d)\n", ssize, dsize); |
|
4408 |
- free(exe_sections); |
|
4407 |
+ cli_dbgmsg("cli_scanpe: UPX: Size mismatch or dsize too big (ssize: %d, dsize: %d)\n", ssize, dsize); |
|
4408 |
+ cli_exe_info_destroy(peinfo); |
|
4409 | 4409 |
return CL_CLEAN; |
4410 | 4410 |
} |
4411 | 4411 |
|
4412 |
- if (!exe_sections[i + 1].rsz || !(src = fmap_need_off_once(map, exe_sections[i + 1].raw, ssize))) { |
|
4413 |
- cli_dbgmsg("UPX: Can't read raw data of section %d\n", i + 1); |
|
4414 |
- free(exe_sections); |
|
4412 |
+ if (!peinfo->sections[i + 1].rsz || !(src = fmap_need_off_once(map, peinfo->sections[i + 1].raw, ssize))) { |
|
4413 |
+ cli_dbgmsg("cli_scanpe: UPX: Can't read raw data of section %d\n", i + 1); |
|
4414 |
+ cli_exe_info_destroy(peinfo); |
|
4415 | 4415 |
return CL_EREAD; |
4416 | 4416 |
} |
4417 | 4417 |
|
4418 | 4418 |
if ((dest = (char *)cli_calloc(dsize + 8192, sizeof(char))) == NULL) { |
4419 |
- free(exe_sections); |
|
4419 |
+ cli_exe_info_destroy(peinfo); |
|
4420 | 4420 |
return CL_EMEM; |
4421 | 4421 |
} |
4422 | 4422 |
|
4423 | 4423 |
/* try to detect UPX code */ |
4424 | 4424 |
if (cli_memstr(UPX_NRV2B, 24, epbuff + 0x69, 13) || cli_memstr(UPX_NRV2B, 24, epbuff + 0x69 + 8, 13)) { |
4425 |
- cli_dbgmsg("UPX: Looks like a NRV2B decompression routine\n"); |
|
4425 |
+ cli_dbgmsg("cli_scanpe: UPX: Looks like a NRV2B decompression routine\n"); |
|
4426 | 4426 |
upxfn = upx_inflate2b; |
4427 | 4427 |
} else if (cli_memstr(UPX_NRV2D, 24, epbuff + 0x69, 13) || cli_memstr(UPX_NRV2D, 24, epbuff + 0x69 + 8, 13)) { |
4428 |
- cli_dbgmsg("UPX: Looks like a NRV2D decompression routine\n"); |
|
4428 |
+ cli_dbgmsg("cli_scanpe: UPX: Looks like a NRV2D decompression routine\n"); |
|
4429 | 4429 |
upxfn = upx_inflate2d; |
4430 | 4430 |
} else if (cli_memstr(UPX_NRV2E, 24, epbuff + 0x69, 13) || cli_memstr(UPX_NRV2E, 24, epbuff + 0x69 + 8, 13)) { |
4431 |
- cli_dbgmsg("UPX: Looks like a NRV2E decompression routine\n"); |
|
4431 |
+ cli_dbgmsg("cli_scanpe: UPX: Looks like a NRV2E decompression routine\n"); |
|
4432 | 4432 |
upxfn = upx_inflate2e; |
4433 | 4433 |
} |
4434 | 4434 |
|
4435 | 4435 |
if (upxfn) { |
4436 |
- int skew = cli_readint32(epbuff + 2) - EC32(optional_hdr32.ImageBase) - exe_sections[i + 1].rva; |
|
4436 |
+ int skew = cli_readint32(epbuff + 2) - EC32(peinfo->pe_opt.opt32.ImageBase) - peinfo->sections[i + 1].rva; |
|
4437 | 4437 |
|
4438 | 4438 |
if (epbuff[1] != '\xbe' || skew <= 0 || skew > 0xfff) { |
4439 | 4439 |
/* FIXME: legit skews?? */ |
... | ... |
@@ -4442,93 +3856,95 @@ int cli_scanpe(cli_ctx *ctx) |
4442 | 4442 |
/* Ignore suggested skew larger than section size */ |
4443 | 4443 |
skew = 0; |
4444 | 4444 |
} else { |
4445 |
- cli_dbgmsg("UPX: UPX1 seems skewed by %d bytes\n", skew); |
|
4445 |
+ cli_dbgmsg("cli_scanpe: UPX: UPX1 seems skewed by %d bytes\n", skew); |
|
4446 | 4446 |
} |
4447 | 4447 |
|
4448 | 4448 |
/* Try skewed first (skew may be zero) */ |
4449 |
- if (upxfn(src + skew, ssize - skew, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - skew) >= 0) { |
|
4449 |
+ if (upxfn(src + skew, ssize - skew, dest, &dsize, peinfo->sections[i].rva, peinfo->sections[i + 1].rva, peinfo->vep - skew) >= 0) { |
|
4450 | 4450 |
upx_success = 1; |
4451 | 4451 |
} |
4452 | 4452 |
/* If skew not successful and non-zero, try no skew */ |
4453 |
- else if (skew && (upxfn(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) >= 0)) { |
|
4453 |
+ else if (skew && (upxfn(src, ssize, dest, &dsize, peinfo->sections[i].rva, peinfo->sections[i + 1].rva, peinfo->vep) >= 0)) { |
|
4454 | 4454 |
upx_success = 1; |
4455 | 4455 |
} |
4456 | 4456 |
|
4457 | 4457 |
if (upx_success) |
4458 |
- cli_dbgmsg("UPX: Successfully decompressed\n"); |
|
4458 |
+ cli_dbgmsg("cli_scanpe: UPX: Successfully decompressed\n"); |
|
4459 | 4459 |
else |
4460 |
- cli_dbgmsg("UPX: Preferred decompressor failed\n"); |
|
4460 |
+ cli_dbgmsg("cli_scanpe: UPX: Preferred decompressor failed\n"); |
|
4461 | 4461 |
} |
4462 | 4462 |
|
4463 | 4463 |
if (!upx_success && upxfn != upx_inflate2b) { |
4464 |
- if (upx_inflate2b(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2b(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) { |
|
4464 |
+ 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) { |
|
4465 | 4465 |
|
4466 |
- cli_dbgmsg("UPX: NRV2B decompressor failed\n"); |
|
4466 |
+ cli_dbgmsg("cli_scanpe: UPX: NRV2B decompressor failed\n"); |
|
4467 | 4467 |
} else { |
4468 | 4468 |
upx_success = 1; |
4469 |
- cli_dbgmsg("UPX: Successfully decompressed with NRV2B\n"); |
|
4469 |
+ cli_dbgmsg("cli_scanpe: UPX: Successfully decompressed with NRV2B\n"); |
|
4470 | 4470 |
} |
4471 | 4471 |
} |
4472 | 4472 |
|
4473 | 4473 |
if (!upx_success && upxfn != upx_inflate2d) { |
4474 |
- if (upx_inflate2d(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2d(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) { |
|
4474 |
+ 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) { |
|
4475 | 4475 |
|
4476 |
- cli_dbgmsg("UPX: NRV2D decompressor failed\n"); |
|
4476 |
+ cli_dbgmsg("cli_scanpe: UPX: NRV2D decompressor failed\n"); |
|
4477 | 4477 |
} else { |
4478 | 4478 |
upx_success = 1; |
4479 |
- cli_dbgmsg("UPX: Successfully decompressed with NRV2D\n"); |
|
4479 |
+ cli_dbgmsg("cli_scanpe: UPX: Successfully decompressed with NRV2D\n"); |
|
4480 | 4480 |
} |
4481 | 4481 |
} |
4482 | 4482 |
|
4483 | 4483 |
if (!upx_success && upxfn != upx_inflate2e) { |
4484 |
- if (upx_inflate2e(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2e(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) { |
|
4485 |
- cli_dbgmsg("UPX: NRV2E decompressor failed\n"); |
|
4484 |
+ 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) { |
|
4485 |
+ cli_dbgmsg("cli_scanpe: UPX: NRV2E decompressor failed\n"); |
|
4486 | 4486 |
} else { |
4487 | 4487 |
upx_success = 1; |
4488 |
- cli_dbgmsg("UPX: Successfully decompressed with NRV2E\n"); |
|
4488 |
+ cli_dbgmsg("cli_scanpe: UPX: Successfully decompressed with NRV2E\n"); |
|
4489 | 4489 |
} |
4490 | 4490 |
} |
4491 | 4491 |
|
4492 | 4492 |
if (cli_memstr(UPX_LZMA2, 20, epbuff + 0x2f, 20)) { |
4493 | 4493 |
uint32_t strictdsize = cli_readint32(epbuff + 0x21), skew = 0; |
4494 | 4494 |
if (ssize > 0x15 && epbuff[0] == '\x60' && epbuff[1] == '\xbe') { |
4495 |
- skew = cli_readint32(epbuff + 2) - exe_sections[i + 1].rva - optional_hdr32.ImageBase; |
|
4495 |
+ // TODO Add EC32 |
|
4496 |
+ skew = cli_readint32(epbuff + 2) - peinfo->sections[i + 1].rva - peinfo->pe_opt.opt32.ImageBase; |
|
4496 | 4497 |
if (skew != 0x15) |
4497 | 4498 |
skew = 0; |
4498 | 4499 |
} |
4499 | 4500 |
|
4500 | 4501 |
if (strictdsize <= dsize) |
4501 |
- upx_success = upx_inflatelzma(src + skew, ssize - skew, dest, &strictdsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep, 0x20003) >= 0; |
|
4502 |
+ upx_success = upx_inflatelzma(src + skew, ssize - skew, dest, &strictdsize, peinfo->sections[i].rva, peinfo->sections[i + 1].rva, peinfo->vep, 0x20003) >= 0; |
|
4502 | 4503 |
} else if (cli_memstr(UPX_LZMA1_FIRST, 8, epbuff + 0x39, 8) && cli_memstr(UPX_LZMA1_SECOND, 8, epbuff + 0x45, 8)) { |
4503 | 4504 |
uint32_t strictdsize = cli_readint32(epbuff + 0x2b), skew = 0; |
4504 | 4505 |
uint32_t properties = cli_readint32(epbuff + 0x41); |
4505 | 4506 |
if (ssize > 0x15 && epbuff[0] == '\x60' && epbuff[1] == '\xbe') { |
4506 |
- skew = cli_readint32(epbuff + 2) - exe_sections[i + 1].rva - optional_hdr32.ImageBase; |
|
4507 |
+ // TODO Add EC32 |
|
4508 |
+ skew = cli_readint32(epbuff + 2) - peinfo->sections[i + 1].rva - peinfo->pe_opt.opt32.ImageBase; |
|
4507 | 4509 |
if (skew != 0x15) |
4508 | 4510 |
skew = 0; |
4509 | 4511 |
} |
4510 | 4512 |
|
4511 | 4513 |
if (strictdsize <= dsize) |
4512 |
- upx_success = upx_inflatelzma(src + skew, ssize - skew, dest, &strictdsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep, properties) >= 0; |
|
4514 |
+ upx_success = upx_inflatelzma(src + skew, ssize - skew, dest, &strictdsize, peinfo->sections[i].rva, peinfo->sections[i + 1].rva, peinfo->vep, properties) >= 0; |
|
4513 | 4515 |
} |
4514 | 4516 |
|
4515 | 4517 |
if (!upx_success) { |
4516 |
- cli_dbgmsg("UPX: All decompressors failed\n"); |
|
4518 |
+ cli_dbgmsg("cli_scanpe: UPX: All decompressors failed\n"); |
|
4517 | 4519 |
free(dest); |
4518 | 4520 |
} |
4519 | 4521 |
} |
4520 | 4522 |
|
4521 | 4523 |
if (upx_success) { |
4522 |
- free(exe_sections); |
|
4524 |
+ cli_exe_info_destroy(peinfo); |
|
4523 | 4525 |
|
4524 |
- CLI_UNPTEMP("UPX/FSG", (dest, 0)); |
|
4526 |
+ CLI_UNPTEMP("cli_scanpe: UPX/FSG", (dest, 0)); |
|
4525 | 4527 |
#if HAVE_JSON |
4526 | 4528 |
if (pe_json != NULL) |
4527 | 4529 |
cli_jsonstr(pe_json, "Packer", "UPX"); |
4528 | 4530 |
#endif |
4529 | 4531 |
|
4530 | 4532 |
if ((unsigned int)write(ndesc, dest, dsize) != dsize) { |
4531 |
- cli_dbgmsg("UPX/FSG: Can't write %d bytes\n", dsize); |
|
4533 |
+ cli_dbgmsg("cli_scanpe: UPX/FSG: Can't write %d bytes\n", dsize); |
|
4532 | 4534 |
free(tempfile); |
4533 | 4535 |
free(dest); |
4534 | 4536 |
close(ndesc); |
... | ... |
@@ -4537,24 +3953,24 @@ int cli_scanpe(cli_ctx *ctx) |
4537 | 4537 |
|
4538 | 4538 |
free(dest); |
4539 | 4539 |
if (lseek(ndesc, 0, SEEK_SET) == -1) { |
4540 |
- cli_dbgmsg("UPX/FSG: lseek() failed\n"); |
|
4540 |
+ cli_dbgmsg("cli_scanpe: UPX/FSG: lseek() failed\n"); |
|
4541 | 4541 |
close(ndesc); |
4542 |
+ SHA_RESET; |
|
4542 | 4543 |
CLI_TMPUNLK(); |
4543 | 4544 |
free(tempfile); |
4544 |
- SHA_RESET; |
|
4545 | 4545 |
return CL_ESEEK; |
4546 | 4546 |
} |
4547 | 4547 |
|
4548 | 4548 |
if (ctx->engine->keeptmp) |
4549 |
- cli_dbgmsg("UPX/FSG: Decompressed data saved in %s\n", tempfile); |
|
4549 |
+ cli_dbgmsg("cli_scanpe: UPX/FSG: Decompressed data saved in %s\n", tempfile); |
|
4550 | 4550 |
|
4551 | 4551 |
cli_dbgmsg("***** Scanning decompressed file *****\n"); |
4552 | 4552 |
SHA_OFF; |
4553 | 4553 |
if ((ret = cli_magic_scandesc(ndesc, tempfile, ctx)) == CL_VIRUS) { |
4554 | 4554 |
close(ndesc); |
4555 |
+ SHA_RESET; |
|
4555 | 4556 |
CLI_TMPUNLK(); |
4556 | 4557 |
free(tempfile); |
4557 |
- SHA_RESET; |
|
4558 | 4558 |
return CL_VIRUS; |
4559 | 4559 |
} |
4560 | 4560 |
|
... | ... |
@@ -4568,53 +3984,53 @@ int cli_scanpe(cli_ctx *ctx) |
4568 | 4568 |
/* Petite */ |
4569 | 4569 |
|
4570 | 4570 |
if (epsize < 200) { |
4571 |
- free(exe_sections); |
|
4571 |
+ cli_exe_info_destroy(peinfo); |
|
4572 | 4572 |
return CL_CLEAN; |
4573 | 4573 |
} |
4574 | 4574 |
|
4575 | 4575 |
found = 2; |
4576 | 4576 |
|
4577 |
- if (epbuff[0] != '\xb8' || (uint32_t)cli_readint32(epbuff + 1) != exe_sections[nsections - 1].rva + EC32(optional_hdr32.ImageBase)) { |
|
4578 |
- if (nsections < 2 || epbuff[0] != '\xb8' || (uint32_t)cli_readint32(epbuff + 1) != exe_sections[nsections - 2].rva + EC32(optional_hdr32.ImageBase)) |
|
4577 |
+ if (epbuff[0] != '\xb8' || (uint32_t)cli_readint32(epbuff + 1) != peinfo->sections[peinfo->nsections - 1].rva + EC32(peinfo->pe_opt.opt32.ImageBase)) { |
|
4578 |
+ 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)) |
|
4579 | 4579 |
found = 0; |
4580 | 4580 |
else |
4581 | 4581 |
found = 1; |
4582 | 4582 |
} |
4583 | 4583 |
|
4584 | 4584 |
if (found && (DCONF & PE_CONF_PETITE)) { |
4585 |
- cli_dbgmsg("Petite: v2.%d compression detected\n", found); |
|
4585 |
+ cli_dbgmsg("cli_scanpe: Petite: v2.%d compression detected\n", found); |
|
4586 | 4586 |
|
4587 | 4587 |
if (cli_readint32(epbuff + 0x80) == 0x163c988d) { |
4588 |
- cli_dbgmsg("Petite: level zero compression is not supported yet\n"); |
|
4588 |
+ cli_dbgmsg("cli_scanpe: Petite: level zero compression is not supported yet\n"); |
|
4589 | 4589 |
} else { |
4590 |
- dsize = max - min; |
|
4590 |
+ dsize = peinfo->max - peinfo->min; |
|
4591 | 4591 |
|
4592 |
- CLI_UNPSIZELIMITS("Petite", dsize); |
|
4592 |
+ CLI_UNPSIZELIMITS("cli_scanpe: Petite", dsize); |
|
4593 | 4593 |
|
4594 | 4594 |
if ((dest = (char *)cli_calloc(dsize, sizeof(char))) == NULL) { |
4595 |
- cli_dbgmsg("Petite: Can't allocate %d bytes\n", dsize); |
|
4596 |
- free(exe_sections); |
|
4595 |
+ cli_dbgmsg("cli_scanpe: Petite: Can't allocate %d bytes\n", dsize); |
|
4596 |
+ cli_exe_info_destroy(peinfo); |
|
4597 | 4597 |
return CL_EMEM; |
4598 | 4598 |
} |
4599 | 4599 |
|
4600 |
- for (i = 0; i < nsections; i++) { |
|
4601 |
- if (exe_sections[i].raw) { |
|
4600 |
+ for (i = 0; i < peinfo->nsections; i++) { |
|
4601 |
+ if (peinfo->sections[i].raw) { |
|
4602 | 4602 |
unsigned int r_ret; |
4603 | 4603 |
|
4604 |
- if (!exe_sections[i].rsz) |
|
4604 |
+ if (!peinfo->sections[i].rsz) |
|
4605 | 4605 |
goto out_no_petite; |
4606 | 4606 |
|
4607 | 4607 |
if (!CLI_ISCONTAINED(dest, dsize, |
4608 |
- dest + exe_sections[i].rva - min, |
|
4609 |
- exe_sections[i].ursz)) |
|
4608 |
+ dest + peinfo->sections[i].rva - peinfo->min, |
|
4609 |
+ peinfo->sections[i].ursz)) |
|
4610 | 4610 |
goto out_no_petite; |
4611 | 4611 |
|
4612 |
- r_ret = fmap_readn(map, dest + exe_sections[i].rva - min, |
|
4613 |
- exe_sections[i].raw, |
|
4614 |
- exe_sections[i].ursz); |
|
4615 |
- if (r_ret != exe_sections[i].ursz) { |
|
4612 |
+ r_ret = fmap_readn(map, dest + peinfo->sections[i].rva - peinfo->min, |
|
4613 |
+ peinfo->sections[i].raw, |
|
4614 |
+ peinfo->sections[i].ursz); |
|
4615 |
+ if (r_ret != peinfo->sections[i].ursz) { |
|
4616 | 4616 |
out_no_petite: |
4617 |
- free(exe_sections); |
|
4617 |
+ cli_exe_info_destroy(peinfo); |
|
4618 | 4618 |
free(dest); |
4619 | 4619 |
return CL_CLEAN; |
4620 | 4620 |
} |
... | ... |
@@ -4626,33 +4042,33 @@ int cli_scanpe(cli_ctx *ctx) |
4626 | 4626 |
cli_jsonstr(pe_json, "Packer", "Petite"); |
4627 | 4627 |
#endif |
4628 | 4628 |
|
4629 |
- CLI_UNPTEMP("Petite", (dest, exe_sections, 0)); |
|
4630 |
- CLI_UNPRESULTS("Petite", (petite_inflate2x_1to9(dest, min, max - min, exe_sections, nsections - (found == 1 ? 1 : 0), EC32(optional_hdr32.ImageBase), vep, ndesc, found, EC32(optional_hdr32.DataDirectory[2].VirtualAddress), EC32(optional_hdr32.DataDirectory[2].Size))), 0, (dest, 0)); |
|
4629 |
+ CLI_UNPTEMP("cli_scanpe: Petite", (dest, 0)); |
|
4630 |
+ 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)); |
|
4631 | 4631 |
} |
4632 | 4632 |
} |
4633 | 4633 |
|
4634 | 4634 |
/* PESpin 1.1 */ |
4635 | 4635 |
|
4636 |
- if ((DCONF & PE_CONF_PESPIN) && nsections > 1 && |
|
4637 |
- vep >= exe_sections[nsections - 1].rva && |
|
4638 |
- 0x3217 - 4 <= exe_sections[nsections - 1].rva + exe_sections[nsections - 1].rsz && |
|
4639 |
- vep < exe_sections[nsections - 1].rva + exe_sections[nsections - 1].rsz - 0x3217 - 4 && |
|
4636 |
+ if ((DCONF & PE_CONF_PESPIN) && peinfo->nsections > 1 && |
|
4637 |
+ peinfo->vep >= peinfo->sections[peinfo->nsections - 1].rva && |
|
4638 |
+ 0x3217 - 4 <= peinfo->sections[peinfo->nsections - 1].rva + peinfo->sections[peinfo->nsections - 1].rsz && |
|
4639 |
+ peinfo->vep < peinfo->sections[peinfo->nsections - 1].rva + peinfo->sections[peinfo->nsections - 1].rsz - 0x3217 - 4 && |
|
4640 | 4640 |
memcmp(epbuff + 4, "\xe8\x00\x00\x00\x00\x8b\x1c\x24\x83\xc3", 10) == 0) { |
4641 | 4641 |
|
4642 | 4642 |
char *spinned; |
4643 | 4643 |
|
4644 |
- CLI_UNPSIZELIMITS("PEspin", fsize); |
|
4644 |
+ CLI_UNPSIZELIMITS("cli_scanpe: PEspin", fsize); |
|
4645 | 4645 |
|
4646 | 4646 |
if ((spinned = (char *)cli_malloc(fsize)) == NULL) { |
4647 |
- cli_errmsg("PESping: Unable to allocate memory for spinned %lu\n", (unsigned long)fsize); |
|
4648 |
- free(exe_sections); |
|
4647 |
+ cli_errmsg("cli_scanpe: PESping: Unable to allocate memory for spinned %lu\n", (unsigned long)fsize); |
|
4648 |
+ cli_exe_info_destroy(peinfo); |
|
4649 | 4649 |
return CL_EMEM; |
4650 | 4650 |
} |
4651 | 4651 |
|
4652 | 4652 |
if ((size_t)fmap_readn(map, spinned, 0, fsize) != fsize) { |
4653 |
- cli_dbgmsg("PESpin: Can't read %lu bytes\n", (unsigned long)fsize); |
|
4653 |
+ cli_dbgmsg("cli_scanpe: PESpin: Can't read %lu bytes\n", (unsigned long)fsize); |
|
4654 | 4654 |
free(spinned); |
4655 |
- free(exe_sections); |
|
4655 |
+ cli_exe_info_destroy(peinfo); |
|
4656 | 4656 |
return CL_EREAD; |
4657 | 4657 |
} |
4658 | 4658 |
|
... | ... |
@@ -4661,13 +4077,13 @@ int cli_scanpe(cli_ctx *ctx) |
4661 | 4661 |
cli_jsonstr(pe_json, "Packer", "PEspin"); |
4662 | 4662 |
#endif |
4663 | 4663 |
|
4664 |
- CLI_UNPTEMP("PESpin", (spinned, exe_sections, 0)); |
|
4665 |
- CLI_UNPRESULTS_("PEspin", SPINCASE(), (unspin(spinned, fsize, exe_sections, nsections - 1, vep, ndesc, ctx)), 0, (spinned, 0)); |
|
4664 |
+ CLI_UNPTEMP("cli_scanpe: PESpin", (spinned, 0)); |
|
4665 |
+ CLI_UNPRESULTS_("cli_scanpe: PEspin", SPINCASE(), (unspin(spinned, fsize, peinfo->sections, peinfo->nsections - 1, peinfo->vep, ndesc, ctx)), 0, (spinned, 0)); |
|
4666 | 4666 |
} |
4667 | 4667 |
|
4668 | 4668 |
/* yC 1.3 & variants */ |
4669 |
- if ((DCONF & PE_CONF_YC) && nsections > 1 && |
|
4670 |
- (EC32(optional_hdr32.AddressOfEntryPoint) == exe_sections[nsections - 1].rva + 0x60)) { |
|
4669 |
+ if ((DCONF & PE_CONF_YC) && peinfo->nsections > 1 && |
|
4670 |
+ (EC32(peinfo->pe_opt.opt32.AddressOfEntryPoint) == peinfo->sections[peinfo->nsections - 1].rva + 0x60)) { |
|
4671 | 4671 |
|
4672 | 4672 |
uint32_t ecx = 0; |
4673 | 4673 |
int16_t offset; |
... | ... |
@@ -4707,20 +4123,20 @@ int cli_scanpe(cli_ctx *ctx) |
4707 | 4707 |
|
4708 | 4708 |
if (ecx > 0x800 && ecx < 0x2000 && |
4709 | 4709 |
!memcmp(epbuff + 0x63 + offset, "\xaa\xe2\xcc", 3) && |
4710 |
- (fsize >= exe_sections[nsections - 1].raw + 0xC6 + ecx + offset)) { |
|
4710 |
+ (fsize >= peinfo->sections[peinfo->nsections - 1].raw + 0xC6 + ecx + offset)) { |
|
4711 | 4711 |
|
4712 | 4712 |
char *spinned; |
4713 | 4713 |
|
4714 | 4714 |
if ((spinned = (char *)cli_malloc(fsize)) == NULL) { |
4715 |
- cli_errmsg("yC: Unable to allocate memory for spinned %lu\n", (unsigned long)fsize); |
|
4716 |
- free(exe_sections); |
|
4715 |
+ cli_errmsg("cli_scanpe: yC: Unable to allocate memory for spinned %lu\n", (unsigned long)fsize); |
|
4716 |
+ cli_exe_info_destroy(peinfo); |
|
4717 | 4717 |
return CL_EMEM; |
4718 | 4718 |
} |
4719 | 4719 |
|
4720 | 4720 |
if ((size_t)fmap_readn(map, spinned, 0, fsize) != fsize) { |
4721 |
- cli_dbgmsg("yC: Can't read %lu bytes\n", (unsigned long)fsize); |
|
4721 |
+ cli_dbgmsg("cli_scanpe: yC: Can't read %lu bytes\n", (unsigned long)fsize); |
|
4722 | 4722 |
free(spinned); |
4723 |
- free(exe_sections); |
|
4723 |
+ cli_exe_info_destroy(peinfo); |
|
4724 | 4724 |
return CL_EREAD; |
4725 | 4725 |
} |
4726 | 4726 |
|
... | ... |
@@ -4736,15 +4152,15 @@ int cli_scanpe(cli_ctx *ctx) |
4736 | 4736 |
if (ctx->virname) |
4737 | 4737 |
yc_unp_virname = ctx->virname[0]; |
4738 | 4738 |
|
4739 |
- cli_dbgmsg("%d,%d,%d,%d\n", nsections - 1, e_lfanew, ecx, offset); |
|
4740 |
- CLI_UNPTEMP("yC", (spinned, exe_sections, 0)); |
|
4741 |
- CLI_UNPRESULTS("yC", (yc_decrypt(ctx, spinned, fsize, exe_sections, nsections - 1, e_lfanew, ndesc, ecx, offset)), 0, (spinned, 0)); |
|
4739 |
+ cli_dbgmsg("%d,%d,%d,%d\n", peinfo->nsections - 1, peinfo->e_lfanew, ecx, offset); |
|
4740 |
+ CLI_UNPTEMP("cli_scanpe: yC", (spinned, 0)); |
|
4741 |
+ CLI_UNPRESULTS("cli_scanpe: yC", (yc_decrypt(ctx, spinned, fsize, peinfo->sections, peinfo->nsections - 1, peinfo->e_lfanew, ndesc, ecx, offset)), 0, (spinned, 0)); |
|
4742 | 4742 |
|
4743 | 4743 |
if (SCAN_ALLMATCHES && yc_unp_num_viruses != ctx->num_viruses) { |
4744 |
- free(exe_sections); |
|
4744 |
+ cli_exe_info_destroy(peinfo); |
|
4745 | 4745 |
return CL_VIRUS; |
4746 | 4746 |
} else if (ctx->virname && yc_unp_virname != ctx->virname[0]) { |
4747 |
- free(exe_sections); |
|
4747 |
+ cli_exe_info_destroy(peinfo); |
|
4748 | 4748 |
return CL_VIRUS; |
4749 | 4749 |
} |
4750 | 4750 |
} while (0); |
... | ... |
@@ -4753,71 +4169,71 @@ int cli_scanpe(cli_ctx *ctx) |
4753 | 4753 |
|
4754 | 4754 |
/* WWPack */ |
4755 | 4755 |
|
4756 |
- while ((DCONF & PE_CONF_WWPACK) && nsections > 1 && |
|
4757 |
- vep == exe_sections[nsections - 1].rva && |
|
4756 |
+ while ((DCONF & PE_CONF_WWPACK) && peinfo->nsections > 1 && |
|
4757 |
+ peinfo->vep == peinfo->sections[peinfo->nsections - 1].rva && |
|
4758 | 4758 |
memcmp(epbuff, "\x53\x55\x8b\xe8\x33\xdb\xeb", 7) == 0 && |
4759 | 4759 |
memcmp(epbuff + 0x68, "\xe8\x00\x00\x00\x00\x58\x2d\x6d\x00\x00\x00\x50\x60\x33\xc9\x50\x58\x50\x50", 19) == 0) { |
4760 |
- uint32_t head = exe_sections[nsections - 1].raw; |
|
4760 |
+ uint32_t head = peinfo->sections[peinfo->nsections - 1].raw; |
|
4761 | 4761 |
uint8_t *packer; |
4762 | 4762 |
char *src; |
4763 | 4763 |
|
4764 | 4764 |
ssize = 0; |
4765 | 4765 |
for (i = 0;; i++) { |
4766 |
- if (exe_sections[i].raw < head) |
|
4767 |
- head = exe_sections[i].raw; |
|
4766 |
+ if (peinfo->sections[i].raw < head) |
|
4767 |
+ head = peinfo->sections[i].raw; |
|
4768 | 4768 |
|
4769 |
- if (i + 1 == nsections) |
|
4769 |
+ if (i + 1 == peinfo->nsections) |
|
4770 | 4770 |
break; |
4771 | 4771 |
|
4772 |
- if (ssize < exe_sections[i].rva + exe_sections[i].vsz) |
|
4773 |
- ssize = exe_sections[i].rva + exe_sections[i].vsz; |
|
4772 |
+ if (ssize < peinfo->sections[i].rva + peinfo->sections[i].vsz) |
|
4773 |
+ ssize = peinfo->sections[i].rva + peinfo->sections[i].vsz; |
|
4774 | 4774 |
} |
4775 | 4775 |
|
4776 | 4776 |
if (!head || !ssize || head > ssize) |
4777 | 4777 |
break; |
4778 | 4778 |
|
4779 |
- CLI_UNPSIZELIMITS("WWPack", ssize); |
|
4779 |
+ CLI_UNPSIZELIMITS("cli_scanpe: WWPack", ssize); |
|
4780 | 4780 |
|
4781 | 4781 |
if (!(src = (char *)cli_calloc(ssize, sizeof(char)))) { |
4782 |
- free(exe_sections); |
|
4782 |
+ cli_exe_info_destroy(peinfo); |
|
4783 | 4783 |
return CL_EMEM; |
4784 | 4784 |
} |
4785 | 4785 |
|
4786 | 4786 |
if ((size_t)fmap_readn(map, src, 0, head) != head) { |
4787 |
- cli_dbgmsg("WWPack: Can't read %d bytes from headers\n", head); |
|
4787 |
+ cli_dbgmsg("cli_scanpe: WWPack: Can't read %d bytes from headers\n", head); |
|
4788 | 4788 |
free(src); |
4789 |
- free(exe_sections); |
|
4789 |
+ cli_exe_info_destroy(peinfo); |
|
4790 | 4790 |
return CL_EREAD; |
4791 | 4791 |
} |
4792 | 4792 |
|
4793 |
- for (i = 0; i < (unsigned int)nsections - 1; i++) { |
|
4794 |
- if (!exe_sections[i].rsz) |
|
4793 |
+ for (i = 0; i < (unsigned int)peinfo->nsections - 1; i++) { |
|
4794 |
+ if (!peinfo->sections[i].rsz) |
|
4795 | 4795 |
continue; |
4796 | 4796 |
|
4797 |
- if (!CLI_ISCONTAINED(src, ssize, src + exe_sections[i].rva, exe_sections[i].rsz)) |
|
4797 |
+ if (!CLI_ISCONTAINED(src, ssize, src + peinfo->sections[i].rva, peinfo->sections[i].rsz)) |
|
4798 | 4798 |
break; |
4799 | 4799 |
|
4800 |
- if ((unsigned int)fmap_readn(map, src + exe_sections[i].rva, exe_sections[i].raw, exe_sections[i].rsz) != exe_sections[i].rsz) |
|
4800 |
+ if ((unsigned int)fmap_readn(map, src + peinfo->sections[i].rva, peinfo->sections[i].raw, peinfo->sections[i].rsz) != peinfo->sections[i].rsz) |
|
4801 | 4801 |
break; |
4802 | 4802 |
} |
4803 | 4803 |
|
4804 |
- if (i + 1 != nsections) { |
|
4805 |
- cli_dbgmsg("WWpack: Probably hacked/damaged file.\n"); |
|
4804 |
+ if (i + 1 != peinfo->nsections) { |
|
4805 |
+ cli_dbgmsg("cli_scanpe: WWpack: Probably hacked/damaged file.\n"); |
|
4806 | 4806 |
free(src); |
4807 | 4807 |
break; |
4808 | 4808 |
} |
4809 | 4809 |
|
4810 |
- if ((packer = (uint8_t *)cli_calloc(exe_sections[nsections - 1].rsz, sizeof(char))) == NULL) { |
|
4810 |
+ if ((packer = (uint8_t *)cli_calloc(peinfo->sections[peinfo->nsections - 1].rsz, sizeof(char))) == NULL) { |
|
4811 | 4811 |
free(src); |
4812 |
- free(exe_sections); |
|
4812 |
+ cli_exe_info_destroy(peinfo); |
|
4813 | 4813 |
return CL_EMEM; |
4814 | 4814 |
} |
4815 | 4815 |
|
4816 |
- if (!exe_sections[nsections - 1].rsz || (size_t)fmap_readn(map, packer, exe_sections[nsections - 1].raw, exe_sections[nsections - 1].rsz) != exe_sections[nsections - 1].rsz) { |
|
4817 |
- cli_dbgmsg("WWPack: Can't read %d bytes from wwpack sect\n", exe_sections[nsections - 1].rsz); |
|
4816 |
+ if (!peinfo->sections[peinfo->nsections - 1].rsz || (size_t)fmap_readn(map, packer, peinfo->sections[peinfo->nsections - 1].raw, peinfo->sections[peinfo->nsections - 1].rsz) != peinfo->sections[peinfo->nsections - 1].rsz) { |
|
4817 |
+ cli_dbgmsg("cli_scanpe: WWPack: Can't read %d bytes from wwpack sect\n", peinfo->sections[peinfo->nsections - 1].rsz); |
|
4818 | 4818 |
free(src); |
4819 | 4819 |
free(packer); |
4820 |
- free(exe_sections); |
|
4820 |
+ cli_exe_info_destroy(peinfo); |
|
4821 | 4821 |
return CL_EREAD; |
4822 | 4822 |
} |
4823 | 4823 |
|
... | ... |
@@ -4826,16 +4242,16 @@ int cli_scanpe(cli_ctx *ctx) |
4826 | 4826 |
cli_jsonstr(pe_json, "Packer", "WWPack"); |
4827 | 4827 |
#endif |
4828 | 4828 |
|
4829 |
- CLI_UNPTEMP("WWPack", (src, packer, exe_sections, 0)); |
|
4830 |
- CLI_UNPRESULTS("WWPack", (wwunpack((uint8_t *)src, ssize, packer, exe_sections, nsections - 1, e_lfanew, ndesc)), 0, (src, packer, 0)); |
|
4829 |
+ CLI_UNPTEMP("cli_scanpe: WWPack", (src, packer, 0)); |
|
4830 |
+ CLI_UNPRESULTS("cli_scanpe: WWPack", (wwunpack((uint8_t *)src, ssize, packer, peinfo->sections, peinfo->nsections - 1, peinfo->e_lfanew, ndesc)), 0, (src, packer, 0)); |
|
4831 | 4831 |
break; |
4832 | 4832 |
} |
4833 | 4833 |
|
4834 | 4834 |
/* ASPACK support */ |
4835 | 4835 |
while ((DCONF & PE_CONF_ASPACK) && |
4836 |
- ((ep + ASPACK_EP_OFFSET_212 < fsize) || |
|
4837 |
- (ep + ASPACK_EP_OFFSET_OTHER < fsize) || |
|
4838 |
- (ep + ASPACK_EP_OFFSET_242 < fsize)) && |
|
4836 |
+ ((peinfo->ep + ASPACK_EP_OFFSET_212 < fsize) || |
|
4837 |
+ (peinfo->ep + ASPACK_EP_OFFSET_OTHER < fsize) || |
|
4838 |
+ (peinfo->ep + ASPACK_EP_OFFSET_242 < fsize)) && |
|
4839 | 4839 |
(!memcmp(epbuff, "\x60\xe8\x03\x00\x00\x00\xe9\xeb", 8))) { |
4840 | 4840 |
char *src; |
4841 | 4841 |
aspack_version_t aspack_ver = ASPACK_VER_NONE; |
... | ... |
@@ -4853,32 +4269,32 @@ int cli_scanpe(cli_ctx *ctx) |
4853 | 4853 |
break; |
4854 | 4854 |
} |
4855 | 4855 |
ssize = 0; |
4856 |
- for (i = 0; i < nsections; i++) |
|
4857 |
- if (ssize < exe_sections[i].rva + exe_sections[i].vsz) |
|
4858 |
- ssize = exe_sections[i].rva + exe_sections[i].vsz; |
|
4856 |
+ for (i = 0; i < peinfo->nsections; i++) |
|
4857 |
+ if (ssize < peinfo->sections[i].rva + peinfo->sections[i].vsz) |
|
4858 |
+ ssize = peinfo->sections[i].rva + peinfo->sections[i].vsz; |
|
4859 | 4859 |
|
4860 | 4860 |
if (!ssize) |
4861 | 4861 |
break; |
4862 | 4862 |
|
4863 |
- CLI_UNPSIZELIMITS("Aspack", ssize); |
|
4863 |
+ CLI_UNPSIZELIMITS("cli_scanpe: Aspack", ssize); |
|
4864 | 4864 |
|
4865 | 4865 |
if (!(src = (char *)cli_calloc(ssize, sizeof(char)))) { |
4866 |
- free(exe_sections); |
|
4866 |
+ cli_exe_info_destroy(peinfo); |
|
4867 | 4867 |
return CL_EMEM; |
4868 | 4868 |
} |
4869 |
- for (i = 0; i < (unsigned int)nsections; i++) { |
|
4870 |
- if (!exe_sections[i].rsz) |
|
4869 |
+ for (i = 0; i < (unsigned int)peinfo->nsections; i++) { |
|
4870 |
+ if (!peinfo->sections[i].rsz) |
|
4871 | 4871 |
continue; |
4872 | 4872 |
|
4873 |
- if (!CLI_ISCONTAINED(src, ssize, src + exe_sections[i].rva, exe_sections[i].rsz)) |
|
4873 |
+ if (!CLI_ISCONTAINED(src, ssize, src + peinfo->sections[i].rva, peinfo->sections[i].rsz)) |
|
4874 | 4874 |
break; |
4875 | 4875 |
|
4876 |
- if ((unsigned int)fmap_readn(map, src + exe_sections[i].rva, exe_sections[i].raw, exe_sections[i].rsz) != exe_sections[i].rsz) |
|
4876 |
+ if ((unsigned int)fmap_readn(map, src + peinfo->sections[i].rva, peinfo->sections[i].raw, peinfo->sections[i].rsz) != peinfo->sections[i].rsz) |
|
4877 | 4877 |
break; |
4878 | 4878 |
} |
4879 | 4879 |
|
4880 |
- if (i != nsections) { |
|
4881 |
- cli_dbgmsg("Aspack: Probably hacked/damaged Aspack file.\n"); |
|
4880 |
+ if (i != peinfo->nsections) { |
|
4881 |
+ cli_dbgmsg("cli_scanpe: Aspack: Probably hacked/damaged Aspack file.\n"); |
|
4882 | 4882 |
free(src); |
4883 | 4883 |
break; |
4884 | 4884 |
} |
... | ... |
@@ -4888,23 +4304,23 @@ int cli_scanpe(cli_ctx *ctx) |
4888 | 4888 |
cli_jsonstr(pe_json, "Packer", "Aspack"); |
4889 | 4889 |
#endif |
4890 | 4890 |
|
4891 |
- CLI_UNPTEMP("Aspack", (src, exe_sections, 0)); |
|
4892 |
- CLI_UNPRESULTS("Aspack", (unaspack((uint8_t *)src, ssize, exe_sections, nsections, vep - 1, EC32(optional_hdr32.ImageBase), ndesc, aspack_ver)), 1, (src, 0)); |
|
4891 |
+ CLI_UNPTEMP("cli_scanpe: Aspack", (src, 0)); |
|
4892 |
+ 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)); |
|
4893 | 4893 |
break; |
4894 | 4894 |
} |
4895 | 4895 |
|
4896 | 4896 |
/* NsPack */ |
4897 | 4897 |
|
4898 | 4898 |
while (DCONF & PE_CONF_NSPACK) { |
4899 |
- uint32_t eprva = vep; |
|
4900 |
- uint32_t start_of_stuff, rep = ep; |
|
4899 |
+ uint32_t eprva = peinfo->vep; |
|
4900 |
+ uint32_t start_of_stuff, rep = peinfo->ep; |
|
4901 | 4901 |
unsigned int nowinldr; |
4902 | 4902 |
const char *nbuff; |
4903 | 4903 |
|
4904 | 4904 |
src = epbuff; |
4905 | 4905 |
if (*epbuff == '\xe9') { /* bitched headers */ |
4906 |
- eprva = cli_readint32(epbuff + 1) + vep + 5; |
|
4907 |
- if (!(rep = cli_rawaddr(eprva, exe_sections, nsections, &err, fsize, hdr_size)) && err) |
|
4906 |
+ eprva = cli_readint32(epbuff + 1) + peinfo->vep + 5; |
|
4907 |
+ if (!(rep = cli_rawaddr(eprva, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size)) && err) |
|
4908 | 4908 |
break; |
4909 | 4909 |
|
4910 | 4910 |
if (!(nbuff = fmap_need_off_once(map, rep, 24))) |
... | ... |
@@ -4917,7 +4333,7 @@ int cli_scanpe(cli_ctx *ctx) |
4917 | 4917 |
break; |
4918 | 4918 |
|
4919 | 4919 |
nowinldr = 0x54 - cli_readint32(src + 17); |
4920 |
- cli_dbgmsg("NsPack: Found *start_of_stuff @delta-%x\n", nowinldr); |
|
4920 |
+ cli_dbgmsg("cli_scanpe: NsPack: Found *start_of_stuff @delta-%x\n", nowinldr); |
|
4921 | 4921 |
|
4922 | 4922 |
if (!(nbuff = fmap_need_off_once(map, rep - nowinldr, 4))) |
4923 | 4923 |
break; |
... | ... |
@@ -4935,13 +4351,13 @@ int cli_scanpe(cli_ctx *ctx) |
4935 | 4935 |
ssize = cli_readint32(src + 5) | 0xff; |
4936 | 4936 |
dsize = cli_readint32(src + 9); |
4937 | 4937 |
|
4938 |
- CLI_UNPSIZELIMITS("NsPack", MAX(ssize, dsize)); |
|
4938 |
+ CLI_UNPSIZELIMITS("cli_scanpe: NsPack", MAX(ssize, dsize)); |
|
4939 | 4939 |
|
4940 |
- if (!ssize || !dsize || dsize != exe_sections[0].vsz) |
|
4940 |
+ if (!ssize || !dsize || dsize != peinfo->sections[0].vsz) |
|
4941 | 4941 |
break; |
4942 | 4942 |
|
4943 | 4943 |
if (!(dest = cli_malloc(dsize))) { |
4944 |
- cli_errmsg("NsPack: Unable to allocate memory for dest %u\n", dsize); |
|
4944 |
+ cli_errmsg("cli_scanpe: NsPack: Unable to allocate memory for dest %u\n", dsize); |
|
4945 | 4945 |
break; |
4946 | 4946 |
} |
4947 | 4947 |
/* memset(dest, 0xfc, dsize); */ |
... | ... |
@@ -4953,7 +4369,7 @@ int cli_scanpe(cli_ctx *ctx) |
4953 | 4953 |
/* memset(src, 0x00, ssize); */ |
4954 | 4954 |
|
4955 | 4955 |
eprva += 0x27a; |
4956 |
- if (!(rep = cli_rawaddr(eprva, exe_sections, nsections, &err, fsize, hdr_size)) && err) { |
|
4956 |
+ if (!(rep = cli_rawaddr(eprva, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size)) && err) { |
|
4957 | 4957 |
free(dest); |
4958 | 4958 |
break; |
4959 | 4959 |
} |
... | ... |
@@ -4965,15 +4381,15 @@ int cli_scanpe(cli_ctx *ctx) |
4965 | 4965 |
|
4966 | 4966 |
fmap_unneed_off(map, start_of_stuff, ssize); |
4967 | 4967 |
eprva = eprva + 5 + cli_readint32(nbuff + 1); |
4968 |
- cli_dbgmsg("NsPack: OEP = %08x\n", eprva); |
|
4968 |
+ cli_dbgmsg("cli_scanpe: NsPack: OEP = %08x\n", eprva); |
|
4969 | 4969 |
|
4970 | 4970 |
#if HAVE_JSON |
4971 | 4971 |
if (pe_json != NULL) |
4972 | 4972 |
cli_jsonstr(pe_json, "Packer", "NsPack"); |
4973 | 4973 |
#endif |
4974 | 4974 |
|
4975 |
- CLI_UNPTEMP("NsPack", (dest, exe_sections, 0)); |
|
4976 |
- CLI_UNPRESULTS("NsPack", (unspack(src, dest, ctx, exe_sections[0].rva, EC32(optional_hdr32.ImageBase), eprva, ndesc)), 0, (dest, 0)); |
|
4975 |
+ CLI_UNPTEMP("cli_scanpe: NsPack", (dest, 0)); |
|
4976 |
+ CLI_UNPRESULTS("cli_scanpe: NsPack", (unspack(src, dest, ctx, peinfo->sections[0].rva, EC32(peinfo->pe_opt.opt32.ImageBase), eprva, ndesc)), 0, (dest, 0)); |
|
4977 | 4977 |
break; |
4978 | 4978 |
} |
4979 | 4979 |
|
... | ... |
@@ -4989,20 +4405,21 @@ int cli_scanpe(cli_ctx *ctx) |
4989 | 4989 |
return CL_EMEM; |
4990 | 4990 |
} |
4991 | 4991 |
|
4992 |
- cli_bytecode_context_setpe(bc_ctx, &pedata, exe_sections); |
|
4992 |
+ cli_bytecode_context_setpe(bc_ctx, &pedata, peinfo->sections); |
|
4993 | 4993 |
cli_bytecode_context_setctx(bc_ctx, ctx); |
4994 | 4994 |
|
4995 | 4995 |
ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_UNPACKER, map); |
4996 | 4996 |
switch (ret) { |
4997 | 4997 |
case CL_VIRUS: |
4998 |
- free(exe_sections); |
|
4998 |
+ cli_exe_info_destroy(peinfo); |
|
4999 | 4999 |
cli_bytecode_context_destroy(bc_ctx); |
5000 |
+ // TODO Handle allmatch |
|
5000 | 5001 |
return CL_VIRUS; |
5001 | 5002 |
case CL_SUCCESS: |
5002 | 5003 |
ndesc = cli_bytecode_context_getresult_file(bc_ctx, &tempfile); |
5003 | 5004 |
cli_bytecode_context_destroy(bc_ctx); |
5004 | 5005 |
if (ndesc != -1 && tempfile) { |
5005 |
- CLI_UNPRESULTS("bytecode PE hook", 1, 1, (0)); |
|
5006 |
+ CLI_UNPRESULTS("cli_scanpe: bytecode PE hook", 1, 1, (0)); |
|
5006 | 5007 |
} |
5007 | 5008 |
|
5008 | 5009 |
break; |
... | ... |
@@ -5010,7 +4427,7 @@ int cli_scanpe(cli_ctx *ctx) |
5010 | 5010 |
cli_bytecode_context_destroy(bc_ctx); |
5011 | 5011 |
} |
5012 | 5012 |
|
5013 |
- free(exe_sections); |
|
5013 |
+ cli_exe_info_destroy(peinfo); |
|
5014 | 5014 |
|
5015 | 5015 |
#if HAVE_JSON |
5016 | 5016 |
if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) |
... | ... |
@@ -5023,192 +4440,888 @@ int cli_scanpe(cli_ctx *ctx) |
5023 | 5023 |
return CL_CLEAN; |
5024 | 5024 |
} |
5025 | 5025 |
|
5026 |
-int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo) |
|
5026 |
+int cli_pe_targetinfo(fmap_t *map, struct cli_exe_info *peinfo) |
|
5027 | 5027 |
{ |
5028 |
- uint16_t e_magic; /* DOS signature ("MZ") */ |
|
5029 |
- uint32_t e_lfanew; /* address of new exe header */ |
|
5030 |
- /* Obsolete - see below |
|
5031 |
- uint32_t min = 0, max = 0; |
|
5032 |
- */ |
|
5033 |
- struct pe_image_file_hdr file_hdr; |
|
5034 |
- union { |
|
5035 |
- struct pe_image_optional_hdr64 opt64; |
|
5036 |
- struct pe_image_optional_hdr32 opt32; |
|
5037 |
- } pe_opt; |
|
5038 |
- struct pe_image_section_hdr *section_hdr; |
|
5039 |
- unsigned int i; |
|
5040 |
- unsigned int err, pe_plus = 0; |
|
5041 |
- uint32_t valign, falign, hdr_size; |
|
5028 |
+ return cli_peheader(map, peinfo, CLI_PEHEADER_OPT_EXTRACT_VINFO, NULL); |
|
5029 |
+} |
|
5030 |
+ |
|
5031 |
+/** Parse the PE header and, if successful, populate peinfo |
|
5032 |
+ * |
|
5033 |
+ * @param map The fmap_t backing the file being scanned |
|
5034 |
+ * @param peinfo A structure to populate with info from the PE header. This |
|
5035 |
+ * MUST be initialized via cli_exe_info_init prior to calling |
|
5036 |
+ * being passed in. |
|
5037 |
+ * @param opts A bitfield indicating various options related to PE header |
|
5038 |
+ * parsing. The options are (prefixed with CLI_PEHEADER_OPT_): |
|
5039 |
+ * - NONE - Do default parsing |
|
5040 |
+ * - COLLECT_JSON - Populate ctx's json obj with PE header |
|
5041 |
+ * info |
|
5042 |
+ * - DBG_PRINT_INFO - Print debug information about the |
|
5043 |
+ * PE file. Right now, cli_peheader is |
|
5044 |
+ * called multiple times for a given PE, |
|
5045 |
+ * so you don't want to print out the |
|
5046 |
+ * same info each time. |
|
5047 |
+ * - EXTRACT_VINFO - Parse the PEs VERSION_INFO metadata |
|
5048 |
+ * and store it in peinfo->vinfo |
|
5049 |
+ * - STRICT_ON_PE_ERRORS - If specified, some cases that |
|
5050 |
+ * might be considered a broken |
|
5051 |
+ * executable cause RET_BROKEN_PE |
|
5052 |
+ * to be returned, but otherwise |
|
5053 |
+ * these will be tolerated. |
|
5054 |
+ * @param ctx The overaching cli_ctx. This is required with certain opts, but |
|
5055 |
+ * optional otherwise. |
|
5056 |
+ * @return If the PE header is parsed successfully, CLI_PEHEADER_RET_SUCCESS |
|
5057 |
+ * is returned. If it seems like the PE is broken, |
|
5058 |
+ * CLI_PEHEADER_RET_BROKEN_PE is returned. Otherwise, one of the |
|
5059 |
+ * other error codes is returned. |
|
5060 |
+ * If CLI_PEHEADER_RET_SUCCESS is returned, it is the caller's |
|
5061 |
+ * responsibility to destroy peinfo. Otherwise, it's safe to do |
|
5062 |
+ * so but not required. |
|
5063 |
+ * |
|
5064 |
+ * TODO What constitutes a "broken PE" seems somewhat arbitrary in places. |
|
5065 |
+ * I think a PE should only be considered broken if it will not run on |
|
5066 |
+ * any version of Windows. We should invest more time to ensure that our |
|
5067 |
+ * broken PE detection more closely aligns with this. |
|
5068 |
+ * |
|
5069 |
+ * TODO Simplify and get rid of CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS if |
|
5070 |
+ * possible. We should either fail always or ignore always, IMO. |
|
5071 |
+ * |
|
5072 |
+ * TODO Consolidate when information about the PE is printed (after successful |
|
5073 |
+ * PE parsing). This will allow us to simplify the code. Some fail cases, |
|
5074 |
+ * then, will cause PE info to not be printed at all, but I think this is |
|
5075 |
+ * acceptable. The debug messages generated in the fail cases should point to |
|
5076 |
+ * what happened, and that's enough to track down the cause of any issues. |
|
5077 |
+ * |
|
5078 |
+ * TODO Same as above but with JSON creation |
|
5079 |
+ */ |
|
5080 |
+int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ctx *ctx) |
|
5081 |
+{ |
|
5082 |
+ uint16_t e_magic; /* DOS signature ("MZ") */ |
|
5083 |
+ const char *archtype = NULL, *subsystem = NULL; |
|
5084 |
+ time_t timestamp; |
|
5085 |
+ char timestr[32]; |
|
5086 |
+ uint32_t data_dirs_size; |
|
5087 |
+ uint16_t opt_hdr_size; |
|
5088 |
+ uint32_t stored_opt_hdr_size; |
|
5089 |
+ struct pe_image_file_hdr *file_hdr; |
|
5090 |
+ struct pe_image_optional_hdr32 *opt32; |
|
5091 |
+ struct pe_image_optional_hdr64 *opt64; |
|
5092 |
+ struct pe_image_section_hdr *section_hdrs; |
|
5093 |
+ unsigned int i, j, section_pe_idx; |
|
5094 |
+ unsigned int err; |
|
5095 |
+ uint32_t salign, falign; |
|
5042 | 5096 |
size_t fsize; |
5043 | 5097 |
ssize_t at; |
5044 |
- struct pe_image_data_dir *dirs; |
|
5098 |
+ uint32_t is_dll = 0; |
|
5099 |
+ uint32_t is_exe = 0; |
|
5100 |
+ int native = 0; |
|
5101 |
+ int read; |
|
5102 |
+#if HAVE_JSON |
|
5103 |
+ int toval = 0; |
|
5104 |
+ struct json_object *pe_json = NULL; |
|
5105 |
+ char jsonbuf[128]; |
|
5106 |
+#endif |
|
5045 | 5107 |
|
5046 |
- cli_dbgmsg("in cli_peheader\n"); |
|
5108 |
+ if (ctx == NULL && |
|
5109 |
+ (opts & CLI_PEHEADER_OPT_COLLECT_JSON || |
|
5110 |
+ opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO)) { |
|
5111 |
+ cli_errmsg("cli_peheader: ctx can't be NULL for options specified\n"); |
|
5112 |
+ return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
5113 |
+ } |
|
5114 |
+ |
|
5115 |
+#if HAVE_JSON |
|
5116 |
+ if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) { |
|
5117 |
+ pe_json = get_pe_property(ctx); |
|
5118 |
+ } |
|
5119 |
+#endif |
|
5047 | 5120 |
|
5048 | 5121 |
fsize = map->len - peinfo->offset; |
5049 | 5122 |
if (fmap_readn(map, &e_magic, peinfo->offset, sizeof(e_magic)) != sizeof(e_magic)) { |
5050 |
- cli_dbgmsg("Can't read DOS signature\n"); |
|
5051 |
- return -1; |
|
5123 |
+ cli_dbgmsg("cli_peheader: Can't read DOS signature\n"); |
|
5124 |
+ return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
5052 | 5125 |
} |
5053 | 5126 |
|
5054 | 5127 |
if (EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE && EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE_OLD) { |
5055 |
- cli_dbgmsg("Invalid DOS signature\n"); |
|
5056 |
- return -1; |
|
5128 |
+ cli_dbgmsg("cli_peheader: Invalid DOS signature\n"); |
|
5129 |
+ return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
5057 | 5130 |
} |
5058 | 5131 |
|
5059 |
- if (fmap_readn(map, &e_lfanew, peinfo->offset + 58 + sizeof(e_magic), sizeof(e_lfanew)) != sizeof(e_lfanew)) { |
|
5132 |
+ if (fmap_readn(map, &(peinfo->e_lfanew), peinfo->offset + 58 + sizeof(e_magic), sizeof(peinfo->e_lfanew)) != sizeof(peinfo->e_lfanew)) { |
|
5060 | 5133 |
/* truncated header? */ |
5061 |
- return -1; |
|
5134 |
+ cli_dbgmsg("cli_peheader: Unable to read e_lfanew - truncated header?\n"); |
|
5135 |
+ return CLI_PEHEADER_RET_BROKEN_PE; |
|
5062 | 5136 |
} |
5063 | 5137 |
|
5064 |
- e_lfanew = EC32(e_lfanew); |
|
5065 |
- if (!e_lfanew) { |
|
5066 |
- cli_dbgmsg("Not a PE file\n"); |
|
5067 |
- return -1; |
|
5138 |
+ peinfo->e_lfanew = EC32(peinfo->e_lfanew); |
|
5139 |
+ if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) { |
|
5140 |
+ cli_dbgmsg("e_lfanew == %d\n", peinfo->e_lfanew); |
|
5141 |
+ } |
|
5142 |
+ if (!peinfo->e_lfanew) { |
|
5143 |
+ cli_dbgmsg("cli_peheader: Not a PE file - e_lfanew == 0\n"); |
|
5144 |
+ return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
5068 | 5145 |
} |
5069 | 5146 |
|
5070 |
- if (fmap_readn(map, &file_hdr, peinfo->offset + e_lfanew, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) { |
|
5147 |
+ if (fmap_readn(map, &(peinfo->file_hdr), peinfo->offset + peinfo->e_lfanew, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) { |
|
5071 | 5148 |
/* bad information in e_lfanew - probably not a PE file */ |
5072 | 5149 |
cli_dbgmsg("cli_peheader: Can't read file header\n"); |
5073 |
- return -1; |
|
5150 |
+ return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
5074 | 5151 |
} |
5075 | 5152 |
|
5076 |
- if (EC32(file_hdr.Magic) != PE_IMAGE_NT_SIGNATURE) { |
|
5077 |
- cli_dbgmsg("Invalid PE signature (probably NE file)\n"); |
|
5078 |
- return -1; |
|
5153 |
+ file_hdr = &(peinfo->file_hdr); |
|
5154 |
+ |
|
5155 |
+ if (EC32(file_hdr->Magic) != PE_IMAGE_NT_SIGNATURE) { |
|
5156 |
+ cli_dbgmsg("cli_peheader: Invalid PE signature (probably NE file)\n"); |
|
5157 |
+ return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
5079 | 5158 |
} |
5080 | 5159 |
|
5081 |
- if ((peinfo->nsections = EC16(file_hdr.NumberOfSections)) < 1 || peinfo->nsections > PE_MAXSECTIONS) return -1; |
|
5160 |
+ if (EC16(file_hdr->Characteristics) & 0x2000) { |
|
5082 | 5161 |
|
5083 |
- if (EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) { |
|
5084 |
- cli_dbgmsg("SizeOfOptionalHeader too small\n"); |
|
5085 |
- return -1; |
|
5162 |
+#if HAVE_JSON |
|
5163 |
+ if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) |
|
5164 |
+ cli_jsonstr(pe_json, "Type", "DLL"); |
|
5165 |
+#endif |
|
5166 |
+ if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) { |
|
5167 |
+ cli_dbgmsg("File type: DLL\n"); |
|
5168 |
+ } |
|
5169 |
+ |
|
5170 |
+ is_dll = 1; |
|
5171 |
+ } else if (EC16(file_hdr->Characteristics) & 0x0002) { |
|
5172 |
+ |
|
5173 |
+#if HAVE_JSON |
|
5174 |
+ if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) |
|
5175 |
+ cli_jsonstr(pe_json, "Type", "EXE"); |
|
5176 |
+#endif |
|
5177 |
+ if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) { |
|
5178 |
+ cli_dbgmsg("File type: Executable\n"); |
|
5179 |
+ } |
|
5180 |
+ |
|
5181 |
+ is_exe = 1; |
|
5086 | 5182 |
} |
5087 | 5183 |
|
5088 |
- at = peinfo->offset + e_lfanew + sizeof(struct pe_image_file_hdr); |
|
5089 |
- if (fmap_readn(map, &optional_hdr32, at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) { |
|
5090 |
- cli_dbgmsg("Can't read optional file header\n"); |
|
5091 |
- return -1; |
|
5184 |
+ if (!is_dll && !is_exe) { |
|
5185 |
+ cli_dbgmsg("cli_peheader: Assumption Violated: PE is not a DLL or EXE\n"); |
|
5186 |
+ // TODO Don't continue if not an exe or dll? |
|
5092 | 5187 |
} |
5093 |
- at += sizeof(struct pe_image_optional_hdr32); |
|
5094 | 5188 |
|
5095 |
- if (EC16(optional_hdr64.Magic) == PE32P_SIGNATURE) { /* PE+ */ |
|
5096 |
- if (EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr64)) { |
|
5097 |
- cli_dbgmsg("Incorrect SizeOfOptionalHeader for PE32+\n"); |
|
5098 |
- return -1; |
|
5189 |
+ peinfo->is_dll = is_dll; |
|
5190 |
+ |
|
5191 |
+ if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO || |
|
5192 |
+ opts & CLI_PEHEADER_OPT_COLLECT_JSON) { |
|
5193 |
+ switch (EC16(file_hdr->Machine)) { |
|
5194 |
+ case 0x0: |
|
5195 |
+ archtype = "Unknown"; |
|
5196 |
+ break; |
|
5197 |
+ case 0x1: |
|
5198 |
+ // New as of Windows 10, version 1607 and Windows Server 2016 |
|
5199 |
+ archtype = "Target Host"; |
|
5200 |
+ break; |
|
5201 |
+ case 0x14c: |
|
5202 |
+ archtype = "80386"; |
|
5203 |
+ break; |
|
5204 |
+ case 0x14d: |
|
5205 |
+ archtype = "80486"; |
|
5206 |
+ break; |
|
5207 |
+ case 0x14e: |
|
5208 |
+ archtype = "80586"; |
|
5209 |
+ break; |
|
5210 |
+ case 0x160: |
|
5211 |
+ archtype = "R3000 MIPS BE"; |
|
5212 |
+ break; |
|
5213 |
+ case 0x162: |
|
5214 |
+ archtype = "R3000 MIPS LE"; |
|
5215 |
+ break; |
|
5216 |
+ case 0x166: |
|
5217 |
+ archtype = "R4000 MIPS LE"; |
|
5218 |
+ break; |
|
5219 |
+ case 0x168: |
|
5220 |
+ archtype = "R10000 MIPS LE"; |
|
5221 |
+ break; |
|
5222 |
+ case 0x169: |
|
5223 |
+ archtype = "WCE MIPS LE"; |
|
5224 |
+ break; |
|
5225 |
+ case 0x184: |
|
5226 |
+ archtype = "DEC Alpha AXP"; |
|
5227 |
+ break; |
|
5228 |
+ case 0x1a2: |
|
5229 |
+ archtype = "Hitachi SH3 LE"; |
|
5230 |
+ break; |
|
5231 |
+ case 0x1a3: |
|
5232 |
+ archtype = "Hitachi SH3-DSP"; |
|
5233 |
+ break; |
|
5234 |
+ case 0x1a4: |
|
5235 |
+ archtype = "Hitachi SH3-E LE"; |
|
5236 |
+ break; |
|
5237 |
+ case 0x1a6: |
|
5238 |
+ archtype = "Hitachi SH4 LE"; |
|
5239 |
+ break; |
|
5240 |
+ case 0x1a8: |
|
5241 |
+ archtype = "Hitachi SH5"; |
|
5242 |
+ break; |
|
5243 |
+ case 0x1c0: |
|
5244 |
+ archtype = "ARM LE"; |
|
5245 |
+ break; |
|
5246 |
+ case 0x1c2: |
|
5247 |
+ archtype = "ARM Thumb/Thumb-2 LE"; |
|
5248 |
+ break; |
|
5249 |
+ case 0x1c4: |
|
5250 |
+ archtype = "ARM Thumb-2 LE"; |
|
5251 |
+ break; |
|
5252 |
+ case 0x1d3: |
|
5253 |
+ archtype = "AM33"; |
|
5254 |
+ break; |
|
5255 |
+ case 0x1f0: |
|
5256 |
+ archtype = "PowerPC LE"; |
|
5257 |
+ break; |
|
5258 |
+ case 0x1f1: |
|
5259 |
+ archtype = "PowerPC FP"; |
|
5260 |
+ break; |
|
5261 |
+ case 0x200: |
|
5262 |
+ archtype = "IA64"; |
|
5263 |
+ break; |
|
5264 |
+ case 0x266: |
|
5265 |
+ archtype = "MIPS16"; |
|
5266 |
+ break; |
|
5267 |
+ case 0x268: |
|
5268 |
+ archtype = "M68k"; |
|
5269 |
+ break; |
|
5270 |
+ case 0x284: |
|
5271 |
+ archtype = "DEC Alpha AXP 64bit"; |
|
5272 |
+ break; |
|
5273 |
+ case 0x366: |
|
5274 |
+ archtype = "MIPS+FPU"; |
|
5275 |
+ break; |
|
5276 |
+ case 0x466: |
|
5277 |
+ archtype = "MIPS16+FPU"; |
|
5278 |
+ break; |
|
5279 |
+ case 0x520: |
|
5280 |
+ archtype = "Infineon TriCore"; |
|
5281 |
+ break; |
|
5282 |
+ case 0xcef: |
|
5283 |
+ archtype = "CEF"; |
|
5284 |
+ break; |
|
5285 |
+ case 0xebc: |
|
5286 |
+ archtype = "EFI Byte Code"; |
|
5287 |
+ break; |
|
5288 |
+ case 0x8664: |
|
5289 |
+ archtype = "AMD64"; |
|
5290 |
+ break; |
|
5291 |
+ case 0x9041: |
|
5292 |
+ archtype = "M32R"; |
|
5293 |
+ break; |
|
5294 |
+ case 0xaa64: |
|
5295 |
+ archtype = "ARM64 LE"; |
|
5296 |
+ break; |
|
5297 |
+ case 0xc0ee: |
|
5298 |
+ archtype = "CEE"; |
|
5299 |
+ break; |
|
5300 |
+ default: |
|
5301 |
+ archtype = "Unknown"; |
|
5099 | 5302 |
} |
5100 | 5303 |
|
5101 |
- if (fmap_readn(map, &optional_hdr32 + 1, at, sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) { |
|
5102 |
- cli_dbgmsg("Can't read optional file header\n"); |
|
5103 |
- return -1; |
|
5304 |
+ if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) |
|
5305 |
+ cli_dbgmsg("Machine type: %s\n", archtype); |
|
5306 |
+ |
|
5307 |
+#if HAVE_JSON |
|
5308 |
+ if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) |
|
5309 |
+ cli_jsonstr(pe_json, "ArchType", archtype); |
|
5310 |
+#endif |
|
5311 |
+ } |
|
5312 |
+ |
|
5313 |
+ peinfo->nsections = EC16(file_hdr->NumberOfSections); |
|
5314 |
+ if (peinfo->nsections == 0 || peinfo->nsections > PE_MAXSECTIONS) { |
|
5315 |
+ |
|
5316 |
+#if HAVE_JSON |
|
5317 |
+ if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) { |
|
5318 |
+ pe_add_heuristic_property(ctx, "BadNumberOfSections"); |
|
5319 |
+ } |
|
5320 |
+#endif |
|
5321 |
+ // TODO Investigate how corrupted_input is set and whether this |
|
5322 |
+ // check is needed |
|
5323 |
+ if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO && |
|
5324 |
+ !ctx->corrupted_input) { |
|
5325 |
+ if (peinfo->nsections == 0) { |
|
5326 |
+ cli_dbgmsg("cli_peheader: Invalid NumberOfSections (0)\n"); |
|
5327 |
+ } else { |
|
5328 |
+ cli_dbgmsg("cli_peheader: Invalid NumberOfSections (>%d)\n", PE_MAXSECTIONS); |
|
5329 |
+ } |
|
5330 |
+ } |
|
5331 |
+ return CLI_PEHEADER_RET_BROKEN_PE; |
|
5332 |
+ } |
|
5333 |
+ |
|
5334 |
+ timestamp = (time_t)EC32(file_hdr->TimeDateStamp); |
|
5335 |
+ opt_hdr_size = EC16(file_hdr->SizeOfOptionalHeader); |
|
5336 |
+ |
|
5337 |
+ if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) { |
|
5338 |
+ cli_dbgmsg("NumberOfSections: %d\n", peinfo->nsections); |
|
5339 |
+ cli_dbgmsg("TimeDateStamp: %s\n", cli_ctime(×tamp, timestr, sizeof(timestr))); |
|
5340 |
+ cli_dbgmsg("SizeOfOptionalHeader: 0x%x\n", opt_hdr_size); |
|
5341 |
+ } |
|
5342 |
+ |
|
5343 |
+#if HAVE_JSON |
|
5344 |
+ if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) { |
|
5345 |
+ cli_jsonint(pe_json, "NumberOfSections", peinfo->nsections); |
|
5346 |
+ cli_jsonstr(pe_json, "TimeDateStamp", cli_ctime(×tamp, timestr, sizeof(timestr))); |
|
5347 |
+ cli_jsonint(pe_json, "SizeOfOptionalHeader", opt_hdr_size); |
|
5348 |
+ } |
|
5349 |
+#endif |
|
5350 |
+ |
|
5351 |
+ // Ensure there are enough bytes to cover the full optional header, |
|
5352 |
+ // not including the data directory entries (which aren't all gauranteed |
|
5353 |
+ // to be there) |
|
5354 |
+ if (opt_hdr_size < sizeof(struct pe_image_optional_hdr32)) { |
|
5355 |
+ cli_dbgmsg("cli_peheader: SizeOfOptionalHeader too small\n"); |
|
5356 |
+ |
|
5357 |
+#if HAVE_JSON |
|
5358 |
+ if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) { |
|
5359 |
+ pe_add_heuristic_property(ctx, "BadOptionalHeaderSize"); |
|
5360 |
+ } |
|
5361 |
+#endif |
|
5362 |
+ return CLI_PEHEADER_RET_BROKEN_PE; |
|
5363 |
+ } |
|
5364 |
+ |
|
5365 |
+ at = peinfo->offset + peinfo->e_lfanew + sizeof(struct pe_image_file_hdr); |
|
5366 |
+ if (fmap_readn(map, &(peinfo->pe_opt.opt32), at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) { |
|
5367 |
+ cli_dbgmsg("cli_peheader: Can't read optional file header\n"); |
|
5368 |
+ return CLI_PEHEADER_RET_BROKEN_PE; |
|
5369 |
+ } |
|
5370 |
+ stored_opt_hdr_size = sizeof(struct pe_image_optional_hdr32); |
|
5371 |
+ at += stored_opt_hdr_size; |
|
5372 |
+ |
|
5373 |
+ opt32 = &(peinfo->pe_opt.opt32); |
|
5374 |
+ |
|
5375 |
+ if (EC16(opt32->Magic) == PE32P_SIGNATURE) { /* PE+ */ |
|
5376 |
+ // The PE32+ optional header is bigger by 16 bytes, so map in the |
|
5377 |
+ // additional bytes here |
|
5378 |
+ |
|
5379 |
+ if (opt_hdr_size < sizeof(struct pe_image_optional_hdr64)) { |
|
5380 |
+ cli_dbgmsg("cli_peheader: Incorrect SizeOfOptionalHeader for PE32+\n"); |
|
5381 |
+#if HAVE_JSON |
|
5382 |
+ if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) { |
|
5383 |
+ pe_add_heuristic_property(ctx, "BadOptionalHeaderSizePE32Plus"); |
|
5384 |
+ } |
|
5385 |
+#endif |
|
5386 |
+ return CLI_PEHEADER_RET_BROKEN_PE; |
|
5387 |
+ } |
|
5388 |
+ |
|
5389 |
+ 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) { |
|
5390 |
+ cli_dbgmsg("cli_peheader: Can't read additional optional file header bytes\n"); |
|
5391 |
+ return CLI_PEHEADER_RET_BROKEN_PE; |
|
5392 |
+ } |
|
5393 |
+ |
|
5394 |
+ stored_opt_hdr_size += OPT_HDR_SIZE_DIFF; |
|
5395 |
+ at += OPT_HDR_SIZE_DIFF; |
|
5396 |
+ peinfo->is_pe32plus = 1; |
|
5397 |
+ |
|
5398 |
+ opt64 = &(peinfo->pe_opt.opt64); |
|
5399 |
+ |
|
5400 |
+ peinfo->vep = EC32(opt64->AddressOfEntryPoint); |
|
5401 |
+ peinfo->hdr_size = EC32(opt64->SizeOfHeaders); |
|
5402 |
+ peinfo->ndatadirs = EC32(opt64->NumberOfRvaAndSizes); |
|
5403 |
+ |
|
5404 |
+ if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) { |
|
5405 |
+ cli_dbgmsg("File format: PE32+\n"); |
|
5406 |
+ cli_dbgmsg("MajorLinkerVersion: %d\n", opt64->MajorLinkerVersion); |
|
5407 |
+ cli_dbgmsg("MinorLinkerVersion: %d\n", opt64->MinorLinkerVersion); |
|
5408 |
+ cli_dbgmsg("SizeOfCode: 0x%x\n", EC32(opt64->SizeOfCode)); |
|
5409 |
+ cli_dbgmsg("SizeOfInitializedData: 0x%x\n", EC32(opt64->SizeOfInitializedData)); |
|
5410 |
+ cli_dbgmsg("SizeOfUninitializedData: 0x%x\n", EC32(opt64->SizeOfUninitializedData)); |
|
5411 |
+ cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", peinfo->vep); |
|
5412 |
+ cli_dbgmsg("BaseOfCode: 0x%x\n", EC32(opt64->BaseOfCode)); |
|
5413 |
+ cli_dbgmsg("SectionAlignment: 0x%x\n", EC32(opt64->SectionAlignment)); |
|
5414 |
+ cli_dbgmsg("FileAlignment: 0x%x\n", EC32(opt64->FileAlignment)); |
|
5415 |
+ cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(opt64->MajorSubsystemVersion)); |
|
5416 |
+ cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(opt64->MinorSubsystemVersion)); |
|
5417 |
+ cli_dbgmsg("SizeOfImage: 0x%x\n", EC32(opt64->SizeOfImage)); |
|
5418 |
+ cli_dbgmsg("SizeOfHeaders: 0x%x\n", peinfo->hdr_size); |
|
5419 |
+ cli_dbgmsg("NumberOfRvaAndSizes: %u\n", peinfo->ndatadirs); |
|
5420 |
+ } |
|
5421 |
+ |
|
5422 |
+#if HAVE_JSON |
|
5423 |
+ if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) { |
|
5424 |
+ cli_jsonint(pe_json, "MajorLinkerVersion", opt64->MajorLinkerVersion); |
|
5425 |
+ cli_jsonint(pe_json, "MinorLinkerVersion", opt64->MinorLinkerVersion); |
|
5426 |
+ cli_jsonint(pe_json, "SizeOfCode", EC32(opt64->SizeOfCode)); |
|
5427 |
+ cli_jsonint(pe_json, "SizeOfInitializedData", EC32(opt64->SizeOfInitializedData)); |
|
5428 |
+ cli_jsonint(pe_json, "SizeOfUninitializedData", EC32(opt64->SizeOfUninitializedData)); |
|
5429 |
+ cli_jsonint(pe_json, "NumberOfRvaAndSizes", EC32(opt64->NumberOfRvaAndSizes)); |
|
5430 |
+ cli_jsonint(pe_json, "MajorSubsystemVersion", EC16(opt64->MajorSubsystemVersion)); |
|
5431 |
+ cli_jsonint(pe_json, "MinorSubsystemVersion", EC16(opt64->MinorSubsystemVersion)); |
|
5432 |
+ |
|
5433 |
+ snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", peinfo->vep); |
|
5434 |
+ cli_jsonstr(pe_json, "EntryPoint", jsonbuf); |
|
5435 |
+ |
|
5436 |
+ snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(opt64->BaseOfCode)); |
|
5437 |
+ cli_jsonstr(pe_json, "BaseOfCode", jsonbuf); |
|
5438 |
+ |
|
5439 |
+ snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(opt64->SectionAlignment)); |
|
5440 |
+ cli_jsonstr(pe_json, "SectionAlignment", jsonbuf); |
|
5441 |
+ |
|
5442 |
+ snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(opt64->FileAlignment)); |
|
5443 |
+ cli_jsonstr(pe_json, "FileAlignment", jsonbuf); |
|
5444 |
+ |
|
5445 |
+ snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(opt64->SizeOfImage)); |
|
5446 |
+ cli_jsonstr(pe_json, "SizeOfImage", jsonbuf); |
|
5447 |
+ |
|
5448 |
+ snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", peinfo->hdr_size); |
|
5449 |
+ cli_jsonstr(pe_json, "SizeOfHeaders", jsonbuf); |
|
5104 | 5450 |
} |
5451 |
+#endif |
|
5105 | 5452 |
|
5106 |
- at += sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32); |
|
5107 |
- hdr_size = EC32(optional_hdr64.SizeOfHeaders); |
|
5108 |
- pe_plus = 1; |
|
5109 | 5453 |
} else { /* PE */ |
5110 |
- if (EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr32)) { |
|
5111 |
- /* Seek to the end of the long header */ |
|
5112 |
- at += EC16(file_hdr.SizeOfOptionalHeader) - sizeof(struct pe_image_optional_hdr32); |
|
5454 |
+ peinfo->is_pe32plus = 0; |
|
5455 |
+ peinfo->vep = EC32(opt32->AddressOfEntryPoint); |
|
5456 |
+ peinfo->hdr_size = EC32(opt32->SizeOfHeaders); |
|
5457 |
+ peinfo->ndatadirs = EC32(opt32->NumberOfRvaAndSizes); |
|
5458 |
+ |
|
5459 |
+ if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) { |
|
5460 |
+ cli_dbgmsg("File format: PE\n"); |
|
5461 |
+ cli_dbgmsg("MajorLinkerVersion: %d\n", opt32->MajorLinkerVersion); |
|
5462 |
+ cli_dbgmsg("MinorLinkerVersion: %d\n", opt32->MinorLinkerVersion); |
|
5463 |
+ cli_dbgmsg("SizeOfCode: 0x%x\n", EC32(opt32->SizeOfCode)); |
|
5464 |
+ cli_dbgmsg("SizeOfInitializedData: 0x%x\n", EC32(opt32->SizeOfInitializedData)); |
|
5465 |
+ cli_dbgmsg("SizeOfUninitializedData: 0x%x\n", EC32(opt32->SizeOfUninitializedData)); |
|
5466 |
+ cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", peinfo->vep); |
|
5467 |
+ cli_dbgmsg("BaseOfCode: 0x%x\n", EC32(opt32->BaseOfCode)); |
|
5468 |
+ cli_dbgmsg("SectionAlignment: 0x%x\n", EC32(opt32->SectionAlignment)); |
|
5469 |
+ cli_dbgmsg("FileAlignment: 0x%x\n", EC32(opt32->FileAlignment)); |
|
5470 |
+ cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(opt32->MajorSubsystemVersion)); |
|
5471 |
+ cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(opt32->MinorSubsystemVersion)); |
|
5472 |
+ cli_dbgmsg("SizeOfImage: 0x%x\n", EC32(opt32->SizeOfImage)); |
|
5473 |
+ cli_dbgmsg("SizeOfHeaders: 0x%x\n", peinfo->hdr_size); |
|
5474 |
+ cli_dbgmsg("NumberOfRvaAndSizes: %u\n", peinfo->ndatadirs); |
|
5113 | 5475 |
} |
5114 | 5476 |
|
5115 |
- hdr_size = EC32(optional_hdr32.SizeOfHeaders); |
|
5477 |
+#if HAVE_JSON |
|
5478 |
+ if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) { |
|
5479 |
+ cli_jsonint(pe_json, "MajorLinkerVersion", opt32->MajorLinkerVersion); |
|
5480 |
+ cli_jsonint(pe_json, "MinorLinkerVersion", opt32->MinorLinkerVersion); |
|
5481 |
+ cli_jsonint(pe_json, "SizeOfCode", EC32(opt32->SizeOfCode)); |
|
5482 |
+ cli_jsonint(pe_json, "SizeOfInitializedData", EC32(opt32->SizeOfInitializedData)); |
|
5483 |
+ cli_jsonint(pe_json, "SizeOfUninitializedData", EC32(opt32->SizeOfUninitializedData)); |
|
5484 |
+ cli_jsonint(pe_json, "NumberOfRvaAndSizes", EC32(opt32->NumberOfRvaAndSizes)); |
|
5485 |
+ cli_jsonint(pe_json, "MajorSubsystemVersion", EC16(opt32->MajorSubsystemVersion)); |
|
5486 |
+ cli_jsonint(pe_json, "MinorSubsystemVersion", EC16(opt32->MinorSubsystemVersion)); |
|
5487 |
+ |
|
5488 |
+ snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", peinfo->vep); |
|
5489 |
+ cli_jsonstr(pe_json, "EntryPoint", jsonbuf); |
|
5490 |
+ |
|
5491 |
+ snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(opt32->BaseOfCode)); |
|
5492 |
+ cli_jsonstr(pe_json, "BaseOfCode", jsonbuf); |
|
5493 |
+ |
|
5494 |
+ snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(opt32->SectionAlignment)); |
|
5495 |
+ cli_jsonstr(pe_json, "SectionAlignment", jsonbuf); |
|
5496 |
+ |
|
5497 |
+ snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(opt32->FileAlignment)); |
|
5498 |
+ cli_jsonstr(pe_json, "FileAlignment", jsonbuf); |
|
5499 |
+ |
|
5500 |
+ snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", EC32(opt32->SizeOfImage)); |
|
5501 |
+ cli_jsonstr(pe_json, "SizeOfImage", jsonbuf); |
|
5502 |
+ |
|
5503 |
+ snprintf(jsonbuf, sizeof(jsonbuf), "0x%x", peinfo->hdr_size); |
|
5504 |
+ cli_jsonstr(pe_json, "SizeOfHeaders", jsonbuf); |
|
5505 |
+ } |
|
5506 |
+#endif |
|
5116 | 5507 |
} |
5117 | 5508 |
|
5118 |
- valign = (pe_plus) ? EC32(optional_hdr64.SectionAlignment) : EC32(optional_hdr32.SectionAlignment); |
|
5119 |
- falign = (pe_plus) ? EC32(optional_hdr64.FileAlignment) : EC32(optional_hdr32.FileAlignment); |
|
5509 |
+ salign = (peinfo->is_pe32plus) ? EC32(opt64->SectionAlignment) : EC32(opt32->SectionAlignment); |
|
5510 |
+ falign = (peinfo->is_pe32plus) ? EC32(opt64->FileAlignment) : EC32(opt32->FileAlignment); |
|
5120 | 5511 |
|
5121 |
- peinfo->hdr_size = hdr_size = PESALIGN(hdr_size, valign); |
|
5512 |
+ switch (peinfo->is_pe32plus ? EC16(opt64->Subsystem) : EC16(opt32->Subsystem)) { |
|
5513 |
+ case 0: |
|
5514 |
+ subsystem = "Unknown"; |
|
5515 |
+ break; |
|
5516 |
+ case 1: |
|
5517 |
+ subsystem = "Native (svc)"; |
|
5518 |
+ native = 1; |
|
5519 |
+ break; |
|
5520 |
+ case 2: |
|
5521 |
+ subsystem = "Win32 GUI"; |
|
5522 |
+ break; |
|
5523 |
+ case 3: |
|
5524 |
+ subsystem = "Win32 console"; |
|
5525 |
+ break; |
|
5526 |
+ case 5: |
|
5527 |
+ subsystem = "OS/2 console"; |
|
5528 |
+ break; |
|
5529 |
+ case 7: |
|
5530 |
+ subsystem = "POSIX console"; |
|
5531 |
+ break; |
|
5532 |
+ case 8: |
|
5533 |
+ subsystem = "Native Win9x driver"; |
|
5534 |
+ break; |
|
5535 |
+ case 9: |
|
5536 |
+ subsystem = "WinCE GUI"; |
|
5537 |
+ break; |
|
5538 |
+ case 10: |
|
5539 |
+ subsystem = "EFI application"; |
|
5540 |
+ break; |
|
5541 |
+ case 11: |
|
5542 |
+ subsystem = "EFI driver"; |
|
5543 |
+ break; |
|
5544 |
+ case 12: |
|
5545 |
+ subsystem = "EFI runtime driver"; |
|
5546 |
+ break; |
|
5547 |
+ case 13: |
|
5548 |
+ subsystem = "EFI ROM image"; |
|
5549 |
+ break; |
|
5550 |
+ case 14: |
|
5551 |
+ subsystem = "Xbox"; |
|
5552 |
+ break; |
|
5553 |
+ case 16: |
|
5554 |
+ subsystem = "Boot application"; |
|
5555 |
+ break; |
|
5556 |
+ default: |
|
5557 |
+ subsystem = "Unknown"; |
|
5558 |
+ } |
|
5559 |
+ |
|
5560 |
+ if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) { |
|
5561 |
+ cli_dbgmsg("Subsystem: %s\n", subsystem); |
|
5562 |
+ cli_dbgmsg("------------------------------------\n"); |
|
5563 |
+ } |
|
5564 |
+ |
|
5565 |
+#if HAVE_JSON |
|
5566 |
+ if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) |
|
5567 |
+ cli_jsonstr(pe_json, "Subsystem", subsystem); |
|
5568 |
+#endif |
|
5122 | 5569 |
|
5123 |
- peinfo->section = (struct cli_exe_section *)cli_calloc(peinfo->nsections, sizeof(struct cli_exe_section)); |
|
5570 |
+ if (!native && (!salign || (salign % 0x1000))) { |
|
5571 |
+ cli_dbgmsg("cli_peheader: Bad section alignment\n"); |
|
5572 |
+ if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) { |
|
5573 |
+ return CLI_PEHEADER_RET_BROKEN_PE; |
|
5574 |
+ } |
|
5575 |
+ } |
|
5124 | 5576 |
|
5125 |
- if (!peinfo->section) { |
|
5126 |
- cli_dbgmsg("Can't allocate memory for section headers\n"); |
|
5127 |
- return -1; |
|
5577 |
+ if (!native && (!falign || (falign % 0x200))) { |
|
5578 |
+ cli_dbgmsg("cli_peheader: Bad file alignment\n"); |
|
5579 |
+ if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) { |
|
5580 |
+ return CLI_PEHEADER_RET_BROKEN_PE; |
|
5581 |
+ } |
|
5128 | 5582 |
} |
5129 | 5583 |
|
5130 |
- section_hdr = (struct pe_image_section_hdr *)cli_calloc(peinfo->nsections, sizeof(struct pe_image_section_hdr)); |
|
5584 |
+ // Map in the optional header data directories. The spec defines 16 |
|
5585 |
+ // directory entries, but NumberOfRvaAndSizes can be less than that |
|
5586 |
+ // and the Windows loader will pretend that the data directory does |
|
5587 |
+ // not exist. NumberOfRvaAndSizes can be larger than that too, which |
|
5588 |
+ // the Windows loader is OK with. To populate peinfo->dirs, we will |
|
5589 |
+ // copy in as many data dirs are specified but for a max of 16 (and |
|
5590 |
+ // adjust peinfo->ndatadirs accordingly) |
|
5131 | 5591 |
|
5132 |
- if (!section_hdr) { |
|
5133 |
- cli_dbgmsg("Can't allocate memory for section headers\n"); |
|
5134 |
- free(peinfo->section); |
|
5135 |
- peinfo->section = NULL; |
|
5136 |
- return -1; |
|
5592 |
+ if (peinfo->ndatadirs > 0x10) { |
|
5593 |
+ cli_dbgmsg("cli_peheader: Encountered NumberOfRvaAndSizes > 16 (suspicious)\n"); |
|
5137 | 5594 |
} |
5138 | 5595 |
|
5139 |
- if (fmap_readn(map, section_hdr, at, peinfo->nsections * sizeof(struct pe_image_section_hdr)) != peinfo->nsections * sizeof(struct pe_image_section_hdr)) { |
|
5140 |
- cli_dbgmsg("Can't read section header\n"); |
|
5141 |
- cli_dbgmsg("Possibly broken PE file\n"); |
|
5142 |
- free(section_hdr); |
|
5143 |
- free(peinfo->section); |
|
5144 |
- peinfo->section = NULL; |
|
5145 |
- return -1; |
|
5596 |
+ // In the case where we won't fully populate dirs with file data, |
|
5597 |
+ // ensure that the underlying memory is zero so that existing code |
|
5598 |
+ // can interact with peinfo->dirs without using peinfo->ndatadirs |
|
5599 |
+ if (peinfo->ndatadirs < sizeof(peinfo->dirs) / sizeof(peinfo->dirs[0])) { |
|
5600 |
+ memset(&(peinfo->dirs), '\0', sizeof(peinfo->dirs)); |
|
5601 |
+ } |
|
5602 |
+ |
|
5603 |
+ peinfo->ndatadirs = MIN(peinfo->ndatadirs, sizeof(peinfo->dirs) / sizeof(peinfo->dirs[0])); |
|
5604 |
+ |
|
5605 |
+ data_dirs_size = sizeof(struct pe_image_data_dir) * peinfo->ndatadirs; |
|
5606 |
+ |
|
5607 |
+ if (opt_hdr_size < (stored_opt_hdr_size + data_dirs_size)) { |
|
5608 |
+ cli_dbgmsg("cli_peheader: SizeOfOptionalHeader too small (doesn't include data dir size)\n"); |
|
5609 |
+ return CLI_PEHEADER_RET_BROKEN_PE; |
|
5610 |
+ } |
|
5611 |
+ |
|
5612 |
+ read = fmap_readn(map, peinfo->dirs, at, data_dirs_size); |
|
5613 |
+ if (read < 0 || (uint32_t)read != data_dirs_size) { |
|
5614 |
+ cli_dbgmsg("cli_peheader: Can't read optional file header data dirs\n"); |
|
5615 |
+ return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
5616 |
+ } |
|
5617 |
+ at += data_dirs_size; |
|
5618 |
+ |
|
5619 |
+ if (opt_hdr_size != (stored_opt_hdr_size + data_dirs_size)) { |
|
5620 |
+ /* Seek to the end of the long header */ |
|
5621 |
+ cli_dbgmsg("cli_peheader: Encountered case where SizeOfOptionalHeader appears bigger than required\n"); |
|
5622 |
+ at += opt_hdr_size - (stored_opt_hdr_size + data_dirs_size); |
|
5623 |
+ } |
|
5624 |
+ |
|
5625 |
+ // TODO This level of processing might not be needed in all cases |
|
5626 |
+ |
|
5627 |
+ // Sanity checks |
|
5628 |
+ // TODO Also check that salign >= falign |
|
5629 |
+ if (peinfo->hdr_size != PESALIGN(peinfo->hdr_size, salign)) { |
|
5630 |
+ cli_dbgmsg("cli_peheader: SizeOfHeader is not aligned to the SectionAlignment\n"); |
|
5631 |
+ } |
|
5632 |
+ if (peinfo->hdr_size != PESALIGN(peinfo->hdr_size, falign)) { |
|
5633 |
+ cli_dbgmsg("cli_peheader: SizeOfHeader is not aligned to the FileAlignment\n"); |
|
5634 |
+ } |
|
5635 |
+ |
|
5636 |
+ // TODO Why align here? -- /* Aligned headers virtual size */ |
|
5637 |
+ // hdr_size should already be rounded up |
|
5638 |
+ // to a multiple of the file alignment. |
|
5639 |
+ // TODO in cli_checkpe_fp this aligned to falign, elsewhere it aligned to salign |
|
5640 |
+ peinfo->hdr_size = PESALIGN(peinfo->hdr_size, salign); |
|
5641 |
+ |
|
5642 |
+ peinfo->sections = (struct cli_exe_section *)cli_calloc(peinfo->nsections, sizeof(struct cli_exe_section)); |
|
5643 |
+ |
|
5644 |
+ if (!peinfo->sections) { |
|
5645 |
+ cli_dbgmsg("cli_peheader: Can't allocate memory for section headers\n"); |
|
5646 |
+ return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
5647 |
+ } |
|
5648 |
+ |
|
5649 |
+ section_hdrs = (struct pe_image_section_hdr *)cli_calloc(peinfo->nsections, sizeof(struct pe_image_section_hdr)); |
|
5650 |
+ |
|
5651 |
+ if (!section_hdrs) { |
|
5652 |
+ cli_dbgmsg("cli_peheader: Can't allocate memory for section headers\n"); |
|
5653 |
+ free(peinfo->sections); |
|
5654 |
+ peinfo->sections = NULL; |
|
5655 |
+ return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
5656 |
+ } |
|
5657 |
+ |
|
5658 |
+ read = fmap_readn(map, section_hdrs, at, peinfo->nsections * sizeof(struct pe_image_section_hdr)); |
|
5659 |
+ if (read < 0 || (uint32_t)read != peinfo->nsections * sizeof(struct pe_image_section_hdr)) { |
|
5660 |
+ cli_dbgmsg("cli_peheader: Can't read section header - possibly broken PE file\n"); |
|
5661 |
+ free(section_hdrs); |
|
5662 |
+ free(peinfo->sections); |
|
5663 |
+ peinfo->sections = NULL; |
|
5664 |
+ return CLI_PEHEADER_RET_BROKEN_PE; |
|
5146 | 5665 |
} |
5147 | 5666 |
at += sizeof(struct pe_image_section_hdr) * peinfo->nsections; |
5148 | 5667 |
|
5668 |
+ // TODO Verify that this performs correctly |
|
5669 |
+ // TODO I'm not sure why this is necessary since the specification says |
|
5670 |
+ // that PointerToRawData is expected to be a multiple of the file |
|
5671 |
+ // alignment. Should we report this is as a PE with an error? |
|
5672 |
+ |
|
5149 | 5673 |
for (i = 0; falign != 0x200 && i < peinfo->nsections; i++) { |
5150 | 5674 |
/* file alignment fallback mode - blah */ |
5151 |
- if (falign && section_hdr[i].SizeOfRawData && EC32(section_hdr[i].PointerToRawData) % falign && !(EC32(section_hdr[i].PointerToRawData) % 0x200)) { |
|
5675 |
+ if (falign && section_hdrs[i].SizeOfRawData && EC32(section_hdrs[i].PointerToRawData) % falign && !(EC32(section_hdrs[i].PointerToRawData) % 0x200)) { |
|
5676 |
+ cli_dbgmsg("cli_peheader: Encountered section with unexpected alignment - triggering fallback mode\n"); |
|
5152 | 5677 |
falign = 0x200; |
5153 | 5678 |
} |
5154 | 5679 |
} |
5155 | 5680 |
|
5156 |
- for (i = 0; i < peinfo->nsections; i++) { |
|
5157 |
- peinfo->section[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign); |
|
5158 |
- peinfo->section[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign); |
|
5159 |
- peinfo->section[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign); |
|
5160 |
- peinfo->section[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign); |
|
5681 |
+ fsize = (map->len - peinfo->offset); |
|
5682 |
+ |
|
5683 |
+ // TODO Why do we fix up these alignments? This shouldn't be needed? |
|
5684 |
+ for (i = 0, section_pe_idx = 0; i < peinfo->nsections; i++, section_pe_idx++) { |
|
5685 |
+ |
|
5686 |
+ struct cli_exe_section *section = &(peinfo->sections[i]); |
|
5687 |
+ struct pe_image_section_hdr *section_hdr = &(section_hdrs[i]); |
|
5688 |
+ char sname[9]; |
|
5689 |
+ |
|
5690 |
+ // TODO I don't see any documentation that says VirtualAddress and VirtualSize must be aligned |
|
5691 |
+ section->rva = PEALIGN(EC32(section_hdr->VirtualAddress), salign); |
|
5692 |
+ section->vsz = PESALIGN(EC32(section_hdr->VirtualSize), salign); |
|
5693 |
+ section->raw = PEALIGN(EC32(section_hdr->PointerToRawData), falign); |
|
5694 |
+ section->rsz = PESALIGN(EC32(section_hdr->SizeOfRawData), falign); |
|
5695 |
+ section->chr = EC32(section_hdr->Characteristics); |
|
5696 |
+ section->urva = EC32(section_hdr->VirtualAddress); /* Just in case */ |
|
5697 |
+ section->uvsz = EC32(section_hdr->VirtualSize); |
|
5698 |
+ section->uraw = EC32(section_hdr->PointerToRawData); |
|
5699 |
+ section->ursz = EC32(section_hdr->SizeOfRawData); |
|
5700 |
+ |
|
5701 |
+ // First, if a section exists totally outside of a file, remove the |
|
5702 |
+ // section from the list. |
|
5703 |
+ // TODO Document that this happens in the function documentation |
|
5704 |
+ if (section->rsz) { /* Don't bother with virtual only sections */ |
|
5705 |
+ if (section->raw >= fsize || section->uraw >= fsize) { |
|
5706 |
+ 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); |
|
5707 |
+ if (peinfo->nsections == 1) { |
|
5708 |
+ free(section_hdrs); |
|
5709 |
+ free(peinfo->sections); |
|
5710 |
+ peinfo->sections = NULL; |
|
5711 |
+ return CLI_PEHEADER_RET_BROKEN_PE; |
|
5712 |
+ } |
|
5713 |
+ |
|
5714 |
+ for (j = i; j < peinfo->nsections - 1; j++) |
|
5715 |
+ memcpy(&(peinfo->sections[j]), &(peinfo->sections[j + 1]), sizeof(struct cli_exe_section)); |
|
5716 |
+ |
|
5717 |
+ for (j = i; j < peinfo->nsections - 1; j++) |
|
5718 |
+ memcpy(§ion_hdrs[j], §ion_hdrs[j + 1], sizeof(struct pe_image_section_hdr)); |
|
5161 | 5719 |
|
5162 |
- if (!peinfo->section[i].vsz && peinfo->section[i].rsz) |
|
5163 |
- peinfo->section[i].vsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), valign); |
|
5720 |
+ peinfo->nsections--; |
|
5721 |
+ |
|
5722 |
+ // Adjust i since we removed a section and continue on |
|
5723 |
+ i--; |
|
5724 |
+ continue; |
|
5725 |
+ } |
|
5164 | 5726 |
|
5165 |
- if (peinfo->section[i].rsz && !CLI_ISCONTAINED(0, (uint32_t)fsize, peinfo->section[i].raw, peinfo->section[i].rsz)) |
|
5166 |
- peinfo->section[i].rsz = (fsize - peinfo->section[i].raw) * (fsize > peinfo->section[i].raw); |
|
5727 |
+ // Verify that the section is fully contained within the file |
|
5728 |
+ if (!CLI_ISCONTAINED(0, fsize, section->raw, section->rsz)) { |
|
5729 |
+ 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); |
|
5730 |
+ section->rsz = fsize - section->raw; |
|
5731 |
+ } |
|
5732 |
+ |
|
5733 |
+ if (!CLI_ISCONTAINED(0, fsize, section->uraw, section->ursz)) { |
|
5734 |
+ 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); |
|
5735 |
+ section->ursz = fsize - section->uraw; |
|
5736 |
+ } |
|
5737 |
+ } |
|
5738 |
+ |
|
5739 |
+ strncpy(sname, (char *)section_hdr->Name, 8); |
|
5740 |
+ sname[8] = '\0'; |
|
5741 |
+ |
|
5742 |
+#if HAVE_JSON |
|
5743 |
+ if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) { |
|
5744 |
+ add_section_info(ctx, &peinfo->sections[i]); |
|
5745 |
+ |
|
5746 |
+ if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) { |
|
5747 |
+ free(section_hdrs); |
|
5748 |
+ free(peinfo->sections); |
|
5749 |
+ peinfo->sections = NULL; |
|
5750 |
+ return CLI_PEHEADER_RET_JSON_TIMEOUT; |
|
5751 |
+ } |
|
5752 |
+ } |
|
5753 |
+#endif |
|
5754 |
+ |
|
5755 |
+ // TODO Why do we do this |
|
5756 |
+ // TODO Should this be done before we dump the json |
|
5757 |
+ if (!section->vsz && section->rsz) |
|
5758 |
+ section->vsz = PESALIGN(section->ursz, salign); |
|
5759 |
+ |
|
5760 |
+ if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) { |
|
5761 |
+ cli_dbgmsg("Section %d\n", section_pe_idx); |
|
5762 |
+ cli_dbgmsg("Section name: %s\n", sname); |
|
5763 |
+ cli_dbgmsg("Section data (from headers - in memory)\n"); |
|
5764 |
+ cli_dbgmsg("VirtualSize: 0x%x 0x%x\n", section->uvsz, section->vsz); |
|
5765 |
+ cli_dbgmsg("VirtualAddress: 0x%x 0x%x\n", section->urva, section->rva); |
|
5766 |
+ cli_dbgmsg("SizeOfRawData: 0x%x 0x%x\n", section->ursz, section->rsz); |
|
5767 |
+ cli_dbgmsg("PointerToRawData: 0x%x 0x%x\n", section->uraw, section->raw); |
|
5768 |
+ |
|
5769 |
+ if (section->chr & 0x20) { |
|
5770 |
+ cli_dbgmsg("Section contains executable code\n"); |
|
5771 |
+ } |
|
5772 |
+ |
|
5773 |
+ if (section->vsz < section->rsz) { |
|
5774 |
+ cli_dbgmsg("Section contains free space\n"); |
|
5775 |
+ /* |
|
5776 |
+ cli_dbgmsg("Dumping %d bytes\n", section_hdr.SizeOfRawData - section_hdr.VirtualSize); |
|
5777 |
+ ddump(desc, section_hdr.PointerToRawData + section_hdr.VirtualSize, section_hdr.SizeOfRawData - section_hdr.VirtualSize, cli_gentemp(NULL)); |
|
5778 |
+ */ |
|
5779 |
+ } |
|
5780 |
+ |
|
5781 |
+ if (section->chr & 0x20000000) |
|
5782 |
+ cli_dbgmsg("Section's memory is executable\n"); |
|
5783 |
+ |
|
5784 |
+ if (section->chr & 0x80000000) |
|
5785 |
+ cli_dbgmsg("Section's memory is writeable\n"); |
|
5786 |
+ |
|
5787 |
+ cli_dbgmsg("------------------------------------\n"); |
|
5788 |
+ } |
|
5789 |
+ |
|
5790 |
+ if (!salign || (section->urva % salign)) { /* Bad section alignment */ |
|
5791 |
+ cli_dbgmsg("cli_peheader: Broken PE - section's VirtualAddress is misaligned\n"); |
|
5792 |
+ if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) { |
|
5793 |
+ free(section_hdrs); |
|
5794 |
+ free(peinfo->sections); |
|
5795 |
+ peinfo->sections = NULL; |
|
5796 |
+ return CLI_PEHEADER_RET_BROKEN_PE; |
|
5797 |
+ } |
|
5798 |
+ } |
|
5799 |
+ |
|
5800 |
+ // TODO should we skip all of these checks if it's an empty |
|
5801 |
+ // section? Why the exception for uraw? |
|
5802 |
+ if (section->urva >> 31 || section->uvsz >> 31 || (section->rsz && section->uraw >> 31) || peinfo->sections[i].ursz >> 31) { |
|
5803 |
+ cli_dbgmsg("cli_peheader: Found PE values with sign bit set\n"); |
|
5804 |
+ |
|
5805 |
+ free(section_hdrs); |
|
5806 |
+ free(peinfo->sections); |
|
5807 |
+ peinfo->sections = NULL; |
|
5808 |
+ |
|
5809 |
+ return CLI_PEHEADER_RET_BROKEN_PE; |
|
5810 |
+ } |
|
5811 |
+ |
|
5812 |
+ if (!i) { |
|
5813 |
+ if (section->urva != peinfo->hdr_size) { /* Bad first section RVA */ |
|
5814 |
+ cli_dbgmsg("cli_peheader: First section doesn't start immediately after the header\n"); |
|
5815 |
+ if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) { |
|
5816 |
+ free(section_hdrs); |
|
5817 |
+ free(peinfo->sections); |
|
5818 |
+ peinfo->sections = NULL; |
|
5819 |
+ return CLI_PEHEADER_RET_BROKEN_PE; |
|
5820 |
+ } |
|
5821 |
+ } |
|
5822 |
+ |
|
5823 |
+ peinfo->min = section->rva; |
|
5824 |
+ peinfo->max = section->rva + section->rsz; |
|
5825 |
+ } else { |
|
5826 |
+ if (section->urva - peinfo->sections[i - 1].urva != peinfo->sections[i - 1].vsz) { /* No holes, no overlapping, no virtual disorder */ |
|
5827 |
+ cli_dbgmsg("cli_peheader: Virtually misplaced section (wrong order, overlapping, non contiguous)\n"); |
|
5828 |
+ if (opts & CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS) { |
|
5829 |
+ free(section_hdrs); |
|
5830 |
+ free(peinfo->sections); |
|
5831 |
+ peinfo->sections = NULL; |
|
5832 |
+ return CLI_PEHEADER_RET_BROKEN_PE; |
|
5833 |
+ } |
|
5834 |
+ } |
|
5835 |
+ |
|
5836 |
+ if (section->rva < peinfo->min) |
|
5837 |
+ peinfo->min = section->rva; |
|
5838 |
+ |
|
5839 |
+ if (section->rva + section->rsz > peinfo->max) { |
|
5840 |
+ peinfo->max = section->rva + section->rsz; |
|
5841 |
+ peinfo->overlay_start = section->raw + section->rsz; |
|
5842 |
+ } |
|
5843 |
+ |
|
5844 |
+ // TODO This case might be possible, which would lead to us |
|
5845 |
+ // mislabelling the overlay |
|
5846 |
+ if (section->raw + section->rsz > peinfo->max) { |
|
5847 |
+ cli_dbgmsg("cli_peheader: Assumption Violated: Last section end RVA isn't tied to the last section\n"); |
|
5848 |
+ } |
|
5849 |
+ } |
|
5167 | 5850 |
} |
5168 | 5851 |
|
5169 |
- if (pe_plus) { |
|
5170 |
- peinfo->ep = EC32(optional_hdr64.AddressOfEntryPoint); |
|
5171 |
- dirs = optional_hdr64.DataDirectory; |
|
5172 |
- } else { |
|
5173 |
- peinfo->ep = EC32(optional_hdr32.AddressOfEntryPoint); |
|
5174 |
- dirs = optional_hdr32.DataDirectory; |
|
5852 |
+ peinfo->overlay_size = fsize - peinfo->overlay_start; |
|
5853 |
+ |
|
5854 |
+ free(section_hdrs); |
|
5855 |
+ |
|
5856 |
+ // NOTE: For DLLs the entrypoint is likely to be zero |
|
5857 |
+ // TODO ^^^ Does this mean this doesn't work for DLLs? |
|
5858 |
+ if (!(peinfo->ep = cli_rawaddr(peinfo->vep, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size)) && err) { |
|
5859 |
+ cli_dbgmsg("cli_peheader: Broken PE file - Can't map EntryPoint to a file offset\n"); |
|
5860 |
+ free(peinfo->sections); |
|
5861 |
+ peinfo->sections = NULL; |
|
5862 |
+ return CLI_PEHEADER_RET_BROKEN_PE; |
|
5863 |
+ } |
|
5864 |
+ |
|
5865 |
+#if HAVE_JSON |
|
5866 |
+ if (opts & CLI_PEHEADER_OPT_COLLECT_JSON) { |
|
5867 |
+ cli_jsonint(pe_json, "EntryPointOffset", peinfo->ep); |
|
5868 |
+ |
|
5869 |
+ if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) { |
|
5870 |
+ free(peinfo->sections); |
|
5871 |
+ peinfo->sections = NULL; |
|
5872 |
+ return CLI_PEHEADER_RET_JSON_TIMEOUT; |
|
5873 |
+ } |
|
5175 | 5874 |
} |
5875 |
+#endif |
|
5176 | 5876 |
|
5177 |
- if (!(peinfo->ep = cli_rawaddr(peinfo->ep, peinfo->section, peinfo->nsections, &err, fsize, hdr_size)) && err) { |
|
5178 |
- cli_dbgmsg("Broken PE file\n"); |
|
5179 |
- free(section_hdr); |
|
5180 |
- free(peinfo->section); |
|
5181 |
- peinfo->section = NULL; |
|
5182 |
- return -1; |
|
5877 |
+ if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) { |
|
5878 |
+ cli_dbgmsg("EntryPoint offset: 0x%x (%d)\n", peinfo->ep, peinfo->ep); |
|
5183 | 5879 |
} |
5184 | 5880 |
|
5185 |
- if (EC16(file_hdr.Characteristics) & 0x2000 || !dirs[2].Size) |
|
5881 |
+ if (is_dll || peinfo->ndatadirs < 3 || !peinfo->dirs[2].Size) |
|
5186 | 5882 |
peinfo->res_addr = 0; |
5187 | 5883 |
else |
5188 |
- peinfo->res_addr = EC32(dirs[2].VirtualAddress); |
|
5884 |
+ peinfo->res_addr = EC32(peinfo->dirs[2].VirtualAddress); |
|
5189 | 5885 |
|
5190 |
- while (dirs[2].Size) { |
|
5886 |
+ while (opts & CLI_PEHEADER_OPT_EXTRACT_VINFO && |
|
5887 |
+ peinfo->ndatadirs >= 3 && peinfo->dirs[2].Size) { |
|
5191 | 5888 |
struct vinfo_list vlist; |
5192 | 5889 |
const uint8_t *vptr, *baseptr; |
5193 | 5890 |
uint32_t rva, res_sz; |
5194 | 5891 |
|
5195 | 5892 |
memset(&vlist, 0, sizeof(vlist)); |
5196 |
- findres(0x10, 0xffffffff, EC32(dirs[2].VirtualAddress), map, peinfo->section, peinfo->nsections, hdr_size, versioninfo_cb, &vlist); |
|
5893 |
+ findres(0x10, 0xffffffff, map, peinfo, versioninfo_cb, &vlist); |
|
5197 | 5894 |
if (!vlist.count) |
5198 | 5895 |
break; /* No version_information */ |
5199 | 5896 |
|
5200 | 5897 |
if (cli_hashset_init(&peinfo->vinfo, 32, 80)) { |
5201 | 5898 |
cli_errmsg("cli_peheader: Unable to init vinfo hashset\n"); |
5202 |
- free(section_hdr); |
|
5203 |
- free(peinfo->section); |
|
5204 |
- peinfo->section = NULL; |
|
5205 |
- return -1; |
|
5899 |
+ free(peinfo->sections); |
|
5900 |
+ peinfo->sections = NULL; |
|
5901 |
+ return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
5206 | 5902 |
} |
5207 | 5903 |
|
5208 | 5904 |
err = 0; |
5209 | 5905 |
for (i = 0; i < vlist.count; i++) { /* enum all version_information res - RESUMABLE */ |
5210 | 5906 |
cli_dbgmsg("cli_peheader: parsing version info @ rva %x (%u/%u)\n", vlist.rvas[i], i + 1, vlist.count); |
5211 |
- rva = cli_rawaddr(vlist.rvas[i], peinfo->section, peinfo->nsections, &err, fsize, hdr_size); |
|
5907 |
+ rva = cli_rawaddr(vlist.rvas[i], peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size); |
|
5212 | 5908 |
if (err) |
5213 | 5909 |
continue; |
5214 | 5910 |
|
... | ... |
@@ -5219,7 +5332,7 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo) |
5219 | 5219 |
/* parse resource */ |
5220 | 5220 |
rva = cli_readint32(vptr); /* ptr to version_info */ |
5221 | 5221 |
res_sz = cli_readint32(vptr + 4); /* sizeof(resource) */ |
5222 |
- rva = cli_rawaddr(rva, peinfo->section, peinfo->nsections, &err, fsize, hdr_size); |
|
5222 |
+ rva = cli_rawaddr(rva, peinfo->sections, peinfo->nsections, &err, fsize, peinfo->hdr_size); |
|
5223 | 5223 |
if (err) |
5224 | 5224 |
continue; |
5225 | 5225 |
if (!(vptr = fmap_need_off_once(map, rva, res_sz))) |
... | ... |
@@ -5334,10 +5447,9 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo) |
5334 | 5334 |
if (cli_hashset_addkey(&peinfo->vinfo, (uint32_t)(vptr - baseptr + 6))) { |
5335 | 5335 |
cli_errmsg("cli_peheader: Unable to add rva to vinfo hashset\n"); |
5336 | 5336 |
cli_hashset_destroy(&peinfo->vinfo); |
5337 |
- free(section_hdr); |
|
5338 |
- free(peinfo->section); |
|
5339 |
- peinfo->section = NULL; |
|
5340 |
- return -1; |
|
5337 |
+ free(peinfo->sections); |
|
5338 |
+ peinfo->sections = NULL; |
|
5339 |
+ return CLI_PEHEADER_RET_GENERIC_ERROR; |
|
5341 | 5340 |
} |
5342 | 5341 |
|
5343 | 5342 |
if (cli_debug_flag) { |
... | ... |
@@ -5372,10 +5484,15 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo) |
5372 | 5372 |
break; |
5373 | 5373 |
} /* while(dirs[2].Size) */ |
5374 | 5374 |
|
5375 |
- free(section_hdr); |
|
5376 |
- return 0; |
|
5375 |
+ // Do final preperations for peinfo to be passed back |
|
5376 |
+ peinfo->is_dll = is_dll; |
|
5377 |
+ |
|
5378 |
+ return CLI_PEHEADER_RET_SUCCESS; |
|
5377 | 5379 |
} |
5378 | 5380 |
|
5381 |
+// TODO We should sort based on VirtualAddress instead, since PointerToRawData |
|
5382 |
+// will be zero for sections where SizeOfRawData is zero. This also aligns |
|
5383 |
+// with what tools like pefile do. |
|
5379 | 5384 |
static int sort_sects(const void *first, const void *second) |
5380 | 5385 |
{ |
5381 | 5386 |
const struct cli_exe_section *a = first, *b = second; |
... | ... |
@@ -5415,21 +5532,9 @@ static int sort_sects(const void *first, const void *second) |
5415 | 5415 |
* sections? */ |
5416 | 5416 |
cl_error_t cli_checkfp_pe(cli_ctx *ctx, stats_section_t *hashes, uint32_t flags) |
5417 | 5417 |
{ |
5418 |
- uint16_t e_magic; /* DOS signature ("MZ") */ |
|
5419 |
- uint16_t nsections; |
|
5420 |
- uint32_t e_lfanew; /* address of new exe header */ |
|
5421 |
- struct pe_image_file_hdr file_hdr; |
|
5422 |
- union { |
|
5423 |
- struct pe_image_optional_hdr64 opt64; |
|
5424 |
- struct pe_image_optional_hdr32 opt32; |
|
5425 |
- } pe_opt; |
|
5426 |
- const struct pe_image_section_hdr *section_hdr; |
|
5427 |
- ssize_t at; |
|
5428 |
- unsigned int i, pe_plus = 0, hlen; |
|
5418 |
+ size_t at; |
|
5419 |
+ unsigned int i, hlen; |
|
5429 | 5420 |
size_t fsize; |
5430 |
- uint32_t valign, falign, hdr_size; |
|
5431 |
- struct cli_exe_section *exe_sections; |
|
5432 |
- struct pe_image_data_dir *dirs; |
|
5433 | 5421 |
fmap_t *map = *ctx->fmap; |
5434 | 5422 |
void *hashctx = NULL; |
5435 | 5423 |
struct pe_certificate_hdr cert_hdr; |
... | ... |
@@ -5439,6 +5544,15 @@ cl_error_t cli_checkfp_pe(cli_ctx *ctx, stats_section_t *hashes, uint32_t flags) |
5439 | 5439 |
uint8_t authsha1[SHA1_HASH_SIZE]; |
5440 | 5440 |
uint32_t sec_dir_offset; |
5441 | 5441 |
uint32_t sec_dir_size; |
5442 |
+ struct cli_exe_info _peinfo; |
|
5443 |
+ struct cli_exe_info *peinfo = &_peinfo; |
|
5444 |
+ |
|
5445 |
+ // If Authenticode parsing has been disabled via DCONF, then don't |
|
5446 |
+ // continue on. |
|
5447 |
+ // TODO This should probably be named PE_CONF_AUTHENTICODE instead |
|
5448 |
+ // of PE_CONF_CATALOG |
|
5449 |
+ if (!(DCONF & PE_CONF_CATALOG)) |
|
5450 |
+ return CL_EFORMAT; |
|
5442 | 5451 |
|
5443 | 5452 |
if (flags == CL_CHECKFP_PE_FLAG_NONE) |
5444 | 5453 |
return CL_BREAK; |
... | ... |
@@ -5449,77 +5563,16 @@ cl_error_t cli_checkfp_pe(cli_ctx *ctx, stats_section_t *hashes, uint32_t flags) |
5449 | 5449 |
hashes->sections = NULL; |
5450 | 5450 |
} |
5451 | 5451 |
|
5452 |
- // TODO What does this do? |
|
5453 |
- if (!(DCONF & PE_CONF_CATALOG)) |
|
5454 |
- return CL_EFORMAT; |
|
5455 |
- |
|
5456 |
- if (fmap_readn(map, &e_magic, 0, sizeof(e_magic)) != sizeof(e_magic)) |
|
5457 |
- return CL_EFORMAT; |
|
5458 |
- |
|
5459 |
- if (EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE && EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE_OLD) |
|
5460 |
- return CL_EFORMAT; |
|
5452 |
+ // TODO see if peinfo can be passed in (or lives in ctx or something) and |
|
5453 |
+ // if so, use that to avoid having to re-parse the header |
|
5454 |
+ cli_exe_info_init(peinfo, 0); |
|
5461 | 5455 |
|
5462 |
- if (fmap_readn(map, &e_lfanew, 58 + sizeof(e_magic), sizeof(e_lfanew)) != sizeof(e_lfanew)) |
|
5463 |
- return CL_EFORMAT; |
|
5464 |
- |
|
5465 |
- e_lfanew = EC32(e_lfanew); |
|
5466 |
- if (!e_lfanew) |
|
5467 |
- return CL_EFORMAT; |
|
5468 |
- |
|
5469 |
- if (fmap_readn(map, &file_hdr, e_lfanew, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) |
|
5470 |
- return CL_EFORMAT; |
|
5471 |
- |
|
5472 |
- if (EC32(file_hdr.Magic) != PE_IMAGE_NT_SIGNATURE) |
|
5473 |
- return CL_EFORMAT; |
|
5474 |
- |
|
5475 |
- nsections = EC16(file_hdr.NumberOfSections); |
|
5476 |
- if (nsections < 1 || nsections > PE_MAXSECTIONS) |
|
5477 |
- return CL_EFORMAT; |
|
5478 |
- |
|
5479 |
- // TODO the pe_image_optional_hdr32 structure includes space for all 16 |
|
5480 |
- // data directories, but these might not all exist in a given binary. |
|
5481 |
- // We need to check NumberOfRvaAndSizes instead, and allow through any |
|
5482 |
- // with at least 5 (the security DataDirectory) |
|
5483 |
- if (EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) { |
|
5484 |
- cli_dbgmsg("cli_checkfp_pe: SizeOfOptionalHeader < less than the size expected (%lu)\n", sizeof(struct pe_image_optional_hdr32)); |
|
5456 |
+ if (cli_peheader(*ctx->fmap, peinfo, CLI_PEHEADER_OPT_NONE, NULL) != CLI_PEHEADER_RET_SUCCESS) { |
|
5485 | 5457 |
return CL_EFORMAT; |
5486 | 5458 |
} |
5487 | 5459 |
|
5488 |
- at = e_lfanew + sizeof(struct pe_image_file_hdr); |
|
5489 |
- if (fmap_readn(map, &optional_hdr32, at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) |
|
5490 |
- return CL_EFORMAT; |
|
5491 |
- |
|
5492 |
- at += sizeof(struct pe_image_optional_hdr32); |
|
5493 |
- |
|
5494 |
- /* This will be a chicken and egg problem until we drop 9x */ |
|
5495 |
- if (EC16(optional_hdr64.Magic) == PE32P_SIGNATURE) { |
|
5496 |
- if (EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr64)) |
|
5497 |
- return CL_EFORMAT; |
|
5498 |
- |
|
5499 |
- pe_plus = 1; |
|
5500 |
- } |
|
5501 |
- |
|
5502 |
- if (!pe_plus) { /* PE */ |
|
5503 |
- if (EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr32)) { |
|
5504 |
- /* Seek to the end of the long header */ |
|
5505 |
- at += EC16(file_hdr.SizeOfOptionalHeader) - sizeof(struct pe_image_optional_hdr32); |
|
5506 |
- } |
|
5507 |
- |
|
5508 |
- hdr_size = EC32(optional_hdr32.SizeOfHeaders); |
|
5509 |
- dirs = optional_hdr32.DataDirectory; |
|
5510 |
- } else { /* PE+ */ |
|
5511 |
- size_t readlen = sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32); |
|
5512 |
- /* read the remaining part of the header */ |
|
5513 |
- if ((size_t)fmap_readn(map, &optional_hdr32 + 1, at, readlen) != readlen) |
|
5514 |
- return CL_EFORMAT; |
|
5515 |
- |
|
5516 |
- at += sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32); |
|
5517 |
- hdr_size = EC32(optional_hdr64.SizeOfHeaders); |
|
5518 |
- dirs = optional_hdr64.DataDirectory; |
|
5519 |
- } |
|
5520 |
- |
|
5521 |
- sec_dir_offset = EC32(dirs[4].VirtualAddress); |
|
5522 |
- sec_dir_size = EC32(dirs[4].Size); |
|
5460 |
+ sec_dir_offset = EC32(peinfo->dirs[4].VirtualAddress); |
|
5461 |
+ sec_dir_size = EC32(peinfo->dirs[4].Size); |
|
5523 | 5462 |
|
5524 | 5463 |
// As an optimization, check the security DataDirectory here and if |
5525 | 5464 |
// it's less than 8-bytes (and we aren't relying on this code to compute |
... | ... |
@@ -5530,42 +5583,18 @@ cl_error_t cli_checkfp_pe(cli_ctx *ctx, stats_section_t *hashes, uint32_t flags) |
5530 | 5530 |
/* If stats is enabled, continue parsing the sample */ |
5531 | 5531 |
flags ^= CL_CHECKFP_PE_FLAG_AUTHENTICODE; |
5532 | 5532 |
} else { |
5533 |
+ cli_exe_info_destroy(peinfo); |
|
5533 | 5534 |
return CL_BREAK; |
5534 | 5535 |
} |
5535 | 5536 |
} |
5536 | 5537 |
fsize = map->len; |
5537 | 5538 |
|
5538 |
- valign = (pe_plus) ? EC32(optional_hdr64.SectionAlignment) : EC32(optional_hdr32.SectionAlignment); |
|
5539 |
- falign = (pe_plus) ? EC32(optional_hdr64.FileAlignment) : EC32(optional_hdr32.FileAlignment); |
|
5540 |
- |
|
5541 |
- section_hdr = fmap_need_off_once(map, at, sizeof(*section_hdr) * nsections); |
|
5542 |
- if (!section_hdr) |
|
5543 |
- return CL_EFORMAT; |
|
5544 |
- |
|
5545 |
- at += sizeof(*section_hdr) * nsections; |
|
5546 |
- |
|
5547 |
- exe_sections = (struct cli_exe_section *)cli_calloc(nsections, sizeof(struct cli_exe_section)); |
|
5548 |
- if (!exe_sections) |
|
5549 |
- return CL_EMEM; |
|
5550 |
- |
|
5551 |
- // TODO I'm not sure why this is necessary since the specification says |
|
5552 |
- // that PointerToRawData is expected to be a multiple of the file |
|
5553 |
- // alignment. Should we report this is as a PE with an error? |
|
5554 |
- for (i = 0; falign != 0x200 && i < nsections; i++) { |
|
5555 |
- /* file alignment fallback mode - blah */ |
|
5556 |
- if (falign && section_hdr[i].SizeOfRawData && EC32(section_hdr[i].PointerToRawData) % falign && !(EC32(section_hdr[i].PointerToRawData) % 0x200)) |
|
5557 |
- falign = 0x200; |
|
5558 |
- } |
|
5559 |
- |
|
5560 |
- // TODO Why is this needed? hdr_size should already be rounded up |
|
5561 |
- // to a multiple of the file alignment. |
|
5562 |
- hdr_size = PESALIGN(hdr_size, falign); /* Aligned headers virtual size */ |
|
5563 |
- |
|
5564 | 5539 |
if (flags & CL_CHECKFP_PE_FLAG_STATS) { |
5565 |
- hashes->nsections = nsections; |
|
5566 |
- hashes->sections = cli_calloc(nsections, sizeof(struct cli_section_hash)); |
|
5540 |
+ hashes->nsections = peinfo->nsections; |
|
5541 |
+ hashes->sections = cli_calloc(peinfo->nsections, sizeof(struct cli_section_hash)); |
|
5542 |
+ ; |
|
5567 | 5543 |
if (!(hashes->sections)) { |
5568 |
- free(exe_sections); |
|
5544 |
+ cli_exe_info_destroy(peinfo); |
|
5569 | 5545 |
return CL_EMEM; |
5570 | 5546 |
} |
5571 | 5547 |
} |
... | ... |
@@ -5578,64 +5607,29 @@ cl_error_t cli_checkfp_pe(cli_ctx *ctx, stats_section_t *hashes, uint32_t flags) |
5578 | 5578 |
} \ |
5579 | 5579 |
} while (0) |
5580 | 5580 |
|
5581 |
- // TODO Why do we fix up these alignments? This shouldn't be needed? |
|
5582 |
- for (i = 0; i < nsections; i++) { |
|
5583 |
- exe_sections[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign); |
|
5584 |
- exe_sections[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign); |
|
5585 |
- exe_sections[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign); |
|
5586 |
- exe_sections[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign); |
|
5587 |
- |
|
5588 |
- // TODO exe_sections[i].ursz is not assigned to (will always be 0) |
|
5589 |
- // Figure out what this is meant to do and ensure that happens |
|
5590 |
- if (!exe_sections[i].vsz && exe_sections[i].rsz) |
|
5591 |
- exe_sections[i].vsz = PESALIGN(exe_sections[i].ursz, valign); |
|
5592 |
- |
|
5593 |
- if (exe_sections[i].rsz && fsize > exe_sections[i].raw && !CLI_ISCONTAINED(0, (uint32_t)fsize, exe_sections[i].raw, exe_sections[i].rsz)) { |
|
5594 |
- cli_dbgmsg("cli_checkfp_pe: encountered section not fully contained within the file\n"); |
|
5595 |
- free(exe_sections); |
|
5596 |
- free_section_hashes(); |
|
5597 |
- return CL_EFORMAT; |
|
5598 |
- } |
|
5599 |
- |
|
5600 |
- if (exe_sections[i].rsz && exe_sections[i].raw >= fsize) { |
|
5601 |
- cli_dbgmsg("cli_checkfp_pe: encountered section that doesn't exist within the file\n"); |
|
5602 |
- free(exe_sections); |
|
5603 |
- free_section_hashes(); |
|
5604 |
- return CL_EFORMAT; |
|
5605 |
- } |
|
5606 |
- |
|
5607 |
- // TODO These checks aren't needed because the u vars are never assigned (always 0) |
|
5608 |
- // Figure out what this is meant to do and ensure that happens |
|
5609 |
- if (exe_sections[i].urva >> 31 || exe_sections[i].uvsz >> 31 || (exe_sections[i].rsz && exe_sections[i].uraw >> 31) || exe_sections[i].ursz >> 31) { |
|
5610 |
- free(exe_sections); |
|
5611 |
- free_section_hashes(); |
|
5612 |
- return CL_EFORMAT; |
|
5613 |
- } |
|
5614 |
- } |
|
5615 |
- |
|
5616 | 5581 |
// TODO This likely isn't needed anymore, since we no longer compute |
5617 | 5582 |
// the authenticode hash like the 2008 spec doc says (sort sections |
5618 | 5583 |
// and use the section info to compute the hash) |
5619 |
- cli_qsort(exe_sections, nsections, sizeof(*exe_sections), sort_sects); |
|
5584 |
+ cli_qsort(peinfo->sections, peinfo->nsections, sizeof(*peinfo->sections), sort_sects); |
|
5620 | 5585 |
|
5621 | 5586 |
/* Hash the sections */ |
5622 | 5587 |
if (flags & CL_CHECKFP_PE_FLAG_STATS) { |
5623 | 5588 |
|
5624 |
- for (i = 0; i < nsections; i++) { |
|
5589 |
+ for (i = 0; i < peinfo->nsections; i++) { |
|
5625 | 5590 |
const uint8_t *hptr; |
5626 | 5591 |
void *md5ctx; |
5627 | 5592 |
|
5628 |
- if (!exe_sections[i].rsz) |
|
5593 |
+ if (!peinfo->sections[i].rsz) |
|
5629 | 5594 |
continue; |
5630 | 5595 |
|
5631 |
- if (!(hptr = fmap_need_off_once(map, exe_sections[i].raw, exe_sections[i].rsz))) { |
|
5632 |
- free(exe_sections); |
|
5596 |
+ if (!(hptr = fmap_need_off_once(map, peinfo->sections[i].raw, peinfo->sections[i].rsz))) { |
|
5597 |
+ cli_exe_info_destroy(peinfo); |
|
5633 | 5598 |
free_section_hashes(); |
5634 | 5599 |
return CL_EFORMAT; |
5635 | 5600 |
} |
5636 | 5601 |
md5ctx = cl_hash_init("md5"); |
5637 | 5602 |
if (md5ctx) { |
5638 |
- cl_update_hash(md5ctx, (void *)hptr, exe_sections[i].rsz); |
|
5603 |
+ cl_update_hash(md5ctx, (void *)hptr, peinfo->sections[i].rsz); |
|
5639 | 5604 |
cl_finish_hash(md5ctx, hashes->sections[i].md5); |
5640 | 5605 |
} |
5641 | 5606 |
} |
... | ... |
@@ -5644,7 +5638,6 @@ cl_error_t cli_checkfp_pe(cli_ctx *ctx, stats_section_t *hashes, uint32_t flags) |
5644 | 5644 |
/* After this point it's the caller's responsibility to free |
5645 | 5645 |
* hashes->sections. Also, in the case where we are just computing the |
5646 | 5646 |
* stats, we are finished */ |
5647 |
- free(exe_sections); |
|
5648 | 5647 |
|
5649 | 5648 |
while (flags & CL_CHECKFP_PE_FLAG_AUTHENTICODE) { |
5650 | 5649 |
|
... | ... |
@@ -5653,6 +5646,7 @@ cl_error_t cli_checkfp_pe(cli_ctx *ctx, stats_section_t *hashes, uint32_t flags) |
5653 | 5653 |
// specified in the PKCS7 structure). We need to hash up to 4 regions |
5654 | 5654 |
regions = (struct cli_mapped_region *)cli_calloc(4, sizeof(struct cli_mapped_region)); |
5655 | 5655 |
if (!regions) { |
5656 |
+ cli_exe_info_destroy(peinfo); |
|
5656 | 5657 |
return CL_EMEM; |
5657 | 5658 |
} |
5658 | 5659 |
nregions = 0; |
... | ... |
@@ -5671,24 +5665,26 @@ cl_error_t cli_checkfp_pe(cli_ctx *ctx, stats_section_t *hashes, uint32_t flags) |
5671 | 5671 |
|
5672 | 5672 |
/* MZ to checksum */ |
5673 | 5673 |
at = 0; |
5674 |
- hlen = e_lfanew + sizeof(struct pe_image_file_hdr) + (pe_plus ? offsetof(struct pe_image_optional_hdr64, CheckSum) : offsetof(struct pe_image_optional_hdr32, CheckSum)); |
|
5674 |
+ 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)); |
|
5675 | 5675 |
add_chunk_to_hash_list(0, hlen); |
5676 | 5676 |
at = hlen + 4; |
5677 | 5677 |
|
5678 | 5678 |
/* Checksum to security */ |
5679 |
- if (pe_plus) |
|
5680 |
- hlen = offsetof(struct pe_image_optional_hdr64, DataDirectory[4]) - offsetof(struct pe_image_optional_hdr64, CheckSum) - 4; |
|
5679 |
+ if (peinfo->is_pe32plus) |
|
5680 |
+ hlen = sizeof(struct pe_image_optional_hdr64) - offsetof(struct pe_image_optional_hdr64, CheckSum) - 4; |
|
5681 | 5681 |
else |
5682 |
- hlen = offsetof(struct pe_image_optional_hdr32, DataDirectory[4]) - offsetof(struct pe_image_optional_hdr32, CheckSum) - 4; |
|
5682 |
+ hlen = sizeof(struct pe_image_optional_hdr32) - offsetof(struct pe_image_optional_hdr32, CheckSum) - 4; |
|
5683 |
+ |
|
5684 |
+ hlen += sizeof(struct pe_image_data_dir) * 4; |
|
5683 | 5685 |
add_chunk_to_hash_list(at, hlen); |
5684 | 5686 |
at += hlen + 8; |
5685 | 5687 |
|
5686 |
- if (at > hdr_size) { |
|
5688 |
+ if (at > peinfo->hdr_size) { |
|
5687 | 5689 |
break; |
5688 | 5690 |
} |
5689 | 5691 |
|
5690 | 5692 |
/* Security to End of header */ |
5691 |
- hlen = hdr_size - at; |
|
5693 |
+ hlen = peinfo->hdr_size - at; |
|
5692 | 5694 |
add_chunk_to_hash_list(at, hlen); |
5693 | 5695 |
at += hlen; |
5694 | 5696 |
|
... | ... |
@@ -5815,27 +5811,16 @@ cl_error_t cli_checkfp_pe(cli_ctx *ctx, stats_section_t *hashes, uint32_t flags) |
5815 | 5815 |
if (NULL != regions) { |
5816 | 5816 |
free(regions); |
5817 | 5817 |
} |
5818 |
+ |
|
5819 |
+ cli_exe_info_destroy(peinfo); |
|
5818 | 5820 |
return ret; |
5819 | 5821 |
} |
5820 | 5822 |
|
5821 | 5823 |
int cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type) |
5822 | 5824 |
{ |
5823 |
- uint16_t e_magic; /* DOS signature ("MZ") */ |
|
5824 |
- uint16_t nsections; |
|
5825 |
- uint32_t e_lfanew; /* address of new exe header */ |
|
5826 |
- union { |
|
5827 |
- struct pe_image_optional_hdr64 opt64; |
|
5828 |
- struct pe_image_optional_hdr32 opt32; |
|
5829 |
- } pe_opt; |
|
5830 |
- const struct pe_image_section_hdr *section_hdr; |
|
5831 |
- ssize_t at; |
|
5832 |
- unsigned int i, pe_plus = 0; |
|
5833 |
- size_t fsize; |
|
5834 |
- uint32_t valign, falign, hdr_size; |
|
5835 |
- struct pe_image_file_hdr file_hdr; |
|
5836 |
- struct cli_exe_section *exe_sections; |
|
5837 |
- struct pe_image_data_dir *dirs; |
|
5838 |
- fmap_t *map = *ctx->fmap; |
|
5825 |
+ unsigned int i; |
|
5826 |
+ struct cli_exe_info _peinfo; |
|
5827 |
+ struct cli_exe_info *peinfo = &_peinfo; |
|
5839 | 5828 |
|
5840 | 5829 |
unsigned char *hash, *hashset[CLI_HASH_AVAIL_TYPES]; |
5841 | 5830 |
int genhash[CLI_HASH_AVAIL_TYPES]; |
... | ... |
@@ -5844,112 +5829,13 @@ int cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type) |
5844 | 5844 |
if (class >= CL_GENHASH_PE_CLASS_LAST) |
5845 | 5845 |
return CL_EARG; |
5846 | 5846 |
|
5847 |
- if (fmap_readn(map, &e_magic, 0, sizeof(e_magic)) != sizeof(e_magic)) |
|
5848 |
- return CL_EFORMAT; |
|
5849 |
- |
|
5850 |
- if (EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE && EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE_OLD) |
|
5851 |
- return CL_EFORMAT; |
|
5852 |
- |
|
5853 |
- if (fmap_readn(map, &e_lfanew, 58 + sizeof(e_magic), sizeof(e_lfanew)) != sizeof(e_lfanew)) |
|
5854 |
- return CL_EFORMAT; |
|
5855 |
- |
|
5856 |
- e_lfanew = EC32(e_lfanew); |
|
5857 |
- if (!e_lfanew) |
|
5858 |
- return CL_EFORMAT; |
|
5859 |
- |
|
5860 |
- if (fmap_readn(map, &file_hdr, e_lfanew, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) |
|
5861 |
- return CL_EFORMAT; |
|
5862 |
- |
|
5863 |
- if (EC32(file_hdr.Magic) != PE_IMAGE_NT_SIGNATURE) |
|
5864 |
- return CL_EFORMAT; |
|
5865 |
- |
|
5866 |
- nsections = EC16(file_hdr.NumberOfSections); |
|
5867 |
- if (nsections < 1 || nsections > PE_MAXSECTIONS) |
|
5868 |
- return CL_EFORMAT; |
|
5869 |
- |
|
5870 |
- if (EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) |
|
5871 |
- return CL_EFORMAT; |
|
5872 |
- |
|
5873 |
- at = e_lfanew + sizeof(struct pe_image_file_hdr); |
|
5874 |
- if (fmap_readn(map, &optional_hdr32, at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) |
|
5875 |
- return CL_EFORMAT; |
|
5876 |
- |
|
5877 |
- at += sizeof(struct pe_image_optional_hdr32); |
|
5878 |
- |
|
5879 |
- /* This will be a chicken and egg problem until we drop 9x */ |
|
5880 |
- if (EC16(optional_hdr64.Magic) == PE32P_SIGNATURE) { |
|
5881 |
- if (EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr64)) |
|
5882 |
- return CL_EFORMAT; |
|
5883 |
- |
|
5884 |
- pe_plus = 1; |
|
5885 |
- } |
|
5886 |
- |
|
5887 |
- if (!pe_plus) { /* PE */ |
|
5888 |
- if (EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr32)) { |
|
5889 |
- /* Seek to the end of the long header */ |
|
5890 |
- at += EC16(file_hdr.SizeOfOptionalHeader) - sizeof(struct pe_image_optional_hdr32); |
|
5891 |
- } |
|
5892 |
- |
|
5893 |
- hdr_size = EC32(optional_hdr32.SizeOfHeaders); |
|
5894 |
- dirs = optional_hdr32.DataDirectory; |
|
5895 |
- } else { /* PE+ */ |
|
5896 |
- size_t readlen = sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32); |
|
5897 |
- /* read the remaining part of the header */ |
|
5898 |
- if ((size_t)fmap_readn(map, &optional_hdr32 + 1, at, readlen) != readlen) |
|
5899 |
- return CL_EFORMAT; |
|
5900 |
- |
|
5901 |
- at += sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32); |
|
5902 |
- hdr_size = EC32(optional_hdr64.SizeOfHeaders); |
|
5903 |
- dirs = optional_hdr64.DataDirectory; |
|
5904 |
- } |
|
5905 |
- |
|
5906 |
- fsize = map->len; |
|
5907 |
- |
|
5908 |
- valign = (pe_plus) ? EC32(optional_hdr64.SectionAlignment) : EC32(optional_hdr32.SectionAlignment); |
|
5909 |
- falign = (pe_plus) ? EC32(optional_hdr64.FileAlignment) : EC32(optional_hdr32.FileAlignment); |
|
5847 |
+ cli_exe_info_init(peinfo, 0); |
|
5910 | 5848 |
|
5911 |
- section_hdr = fmap_need_off_once(map, at, sizeof(*section_hdr) * nsections); |
|
5912 |
- if (!section_hdr) |
|
5849 |
+ if (cli_peheader(*ctx->fmap, peinfo, CLI_PEHEADER_OPT_NONE, NULL) != CLI_PEHEADER_RET_SUCCESS) { |
|
5913 | 5850 |
return CL_EFORMAT; |
5914 |
- |
|
5915 |
- at += sizeof(*section_hdr) * nsections; |
|
5916 |
- |
|
5917 |
- exe_sections = (struct cli_exe_section *)cli_calloc(nsections, sizeof(struct cli_exe_section)); |
|
5918 |
- if (!exe_sections) |
|
5919 |
- return CL_EMEM; |
|
5920 |
- |
|
5921 |
- for (i = 0; falign != 0x200 && i < nsections; i++) { |
|
5922 |
- /* file alignment fallback mode - blah */ |
|
5923 |
- if (falign && section_hdr[i].SizeOfRawData && EC32(section_hdr[i].PointerToRawData) % falign && !(EC32(section_hdr[i].PointerToRawData) % 0x200)) |
|
5924 |
- falign = 0x200; |
|
5925 |
- } |
|
5926 |
- |
|
5927 |
- hdr_size = PESALIGN(hdr_size, falign); /* Aligned headers virtual size */ |
|
5928 |
- |
|
5929 |
- for (i = 0; i < nsections; i++) { |
|
5930 |
- exe_sections[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign); |
|
5931 |
- exe_sections[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign); |
|
5932 |
- exe_sections[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign); |
|
5933 |
- exe_sections[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign); |
|
5934 |
- |
|
5935 |
- if (!exe_sections[i].vsz && exe_sections[i].rsz) |
|
5936 |
- exe_sections[i].vsz = PESALIGN(exe_sections[i].ursz, valign); |
|
5937 |
- |
|
5938 |
- if (exe_sections[i].rsz && fsize > exe_sections[i].raw && !CLI_ISCONTAINED(0, (uint32_t)fsize, exe_sections[i].raw, exe_sections[i].rsz)) |
|
5939 |
- exe_sections[i].rsz = fsize - exe_sections[i].raw; |
|
5940 |
- |
|
5941 |
- if (exe_sections[i].rsz && exe_sections[i].raw >= fsize) { |
|
5942 |
- free(exe_sections); |
|
5943 |
- return CL_EFORMAT; |
|
5944 |
- } |
|
5945 |
- |
|
5946 |
- if (exe_sections[i].urva >> 31 || exe_sections[i].uvsz >> 31 || (exe_sections[i].rsz && exe_sections[i].uraw >> 31) || exe_sections[i].ursz >> 31) { |
|
5947 |
- free(exe_sections); |
|
5948 |
- return CL_EFORMAT; |
|
5949 |
- } |
|
5950 | 5851 |
} |
5951 | 5852 |
|
5952 |
- cli_qsort(exe_sections, nsections, sizeof(*exe_sections), sort_sects); |
|
5853 |
+ cli_qsort(peinfo->sections, peinfo->nsections, sizeof(*(peinfo->sections)), sort_sects); |
|
5953 | 5854 |
|
5954 | 5855 |
/* pick hashtypes to generate */ |
5955 | 5856 |
memset(genhash, 0, sizeof(genhash)); |
... | ... |
@@ -5974,18 +5860,18 @@ int cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type) |
5974 | 5974 |
|
5975 | 5975 |
if (!hash) { |
5976 | 5976 |
cli_errmsg("cli_genhash_pe: cli_malloc failed!\n"); |
5977 |
- free(exe_sections); |
|
5977 |
+ cli_exe_info_destroy(peinfo); |
|
5978 | 5978 |
return CL_EMEM; |
5979 | 5979 |
} |
5980 | 5980 |
|
5981 | 5981 |
if (class == CL_GENHASH_PE_CLASS_SECTION) { |
5982 | 5982 |
char *dstr = NULL; |
5983 | 5983 |
|
5984 |
- for (i = 0; i < nsections; i++) { |
|
5984 |
+ for (i = 0; i < peinfo->nsections; i++) { |
|
5985 | 5985 |
/* Generate hashes */ |
5986 |
- if (cli_hashsect(*ctx->fmap, &exe_sections[i], hashset, genhash, genhash) == 1) { |
|
5986 |
+ if (cli_hashsect(*ctx->fmap, &peinfo->sections[i], hashset, genhash, genhash) == 1) { |
|
5987 | 5987 |
dstr = cli_str2hex((char *)hash, hlen); |
5988 |
- cli_dbgmsg("Section{%u}: %u:%s\n", i, exe_sections[i].rsz, dstr ? (char *)dstr : "(NULL)"); |
|
5988 |
+ cli_dbgmsg("Section{%u}: %u:%s\n", i, peinfo->sections[i].rsz, dstr ? (char *)dstr : "(NULL)"); |
|
5989 | 5989 |
if (dstr != NULL) { |
5990 | 5990 |
free(dstr); |
5991 | 5991 |
dstr = NULL; |
... | ... |
@@ -6000,7 +5886,7 @@ int cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type) |
6000 | 6000 |
int ret; |
6001 | 6001 |
|
6002 | 6002 |
/* Generate hash */ |
6003 |
- ret = hash_imptbl(ctx, hashset, &impsz, genhash, &dirs[1], exe_sections, nsections, hdr_size, pe_plus); |
|
6003 |
+ ret = hash_imptbl(ctx, hashset, &impsz, genhash, peinfo); |
|
6004 | 6004 |
if (ret == CL_SUCCESS) { |
6005 | 6005 |
dstr = cli_str2hex((char *)hash, hlen); |
6006 | 6006 |
cli_dbgmsg("Imphash: %s:%u\n", dstr ? (char *)dstr : "(NULL)", impsz); |
... | ... |
@@ -6017,6 +5903,6 @@ int cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type) |
6017 | 6017 |
|
6018 | 6018 |
if (hash) |
6019 | 6019 |
free(hash); |
6020 |
- free(exe_sections); |
|
6020 |
+ cli_exe_info_destroy(peinfo); |
|
6021 | 6021 |
return CL_SUCCESS; |
6022 | 6022 |
} |
... | ... |
@@ -26,136 +26,29 @@ |
26 | 26 |
#define __PE_H |
27 | 27 |
|
28 | 28 |
#include "clamav.h" |
29 |
-#include "execs.h" |
|
30 | 29 |
#include "others.h" |
31 | 30 |
#include "fmap.h" |
32 | 31 |
#include "bcfeatures.h" |
33 |
-/** @file */ |
|
34 |
-/** Header for this PE file |
|
35 |
- \group_pe */ |
|
36 |
-struct pe_image_file_hdr { |
|
37 |
- uint32_t Magic; /**< PE magic header: PE\\0\\0 */ |
|
38 |
- uint16_t Machine; /**< CPU this executable runs on, see libclamav/pe.c for possible values */ |
|
39 |
- uint16_t NumberOfSections; /**< Number of sections in this executable */ |
|
40 |
- uint32_t TimeDateStamp; /**< Unreliable */ |
|
41 |
- uint32_t PointerToSymbolTable; /**< debug */ |
|
42 |
- uint32_t NumberOfSymbols; /**< debug */ |
|
43 |
- uint16_t SizeOfOptionalHeader; /**< == 224 */ |
|
44 |
- uint16_t Characteristics; |
|
45 |
-}; |
|
46 |
- |
|
47 |
-/** PE data directory header |
|
48 |
- \group_pe */ |
|
49 |
-struct pe_image_data_dir { |
|
50 |
- uint32_t VirtualAddress; |
|
51 |
- uint32_t Size; |
|
52 |
-}; |
|
53 |
- |
|
54 |
-/** 32-bit PE optional header |
|
55 |
- \group_pe */ |
|
56 |
-struct pe_image_optional_hdr32 { |
|
57 |
- uint16_t Magic; |
|
58 |
- uint8_t MajorLinkerVersion; /**< unreliable */ |
|
59 |
- uint8_t MinorLinkerVersion; /**< unreliable */ |
|
60 |
- uint32_t SizeOfCode; /**< unreliable */ |
|
61 |
- uint32_t SizeOfInitializedData; /**< unreliable */ |
|
62 |
- uint32_t SizeOfUninitializedData; /**< unreliable */ |
|
63 |
- uint32_t AddressOfEntryPoint; |
|
64 |
- uint32_t BaseOfCode; |
|
65 |
- uint32_t BaseOfData; |
|
66 |
- uint32_t ImageBase; /**< multiple of 64 KB */ |
|
67 |
- uint32_t SectionAlignment; /**< usually 32 or 4096 */ |
|
68 |
- uint32_t FileAlignment; /**< usually 32 or 512 */ |
|
69 |
- uint16_t MajorOperatingSystemVersion; /**< not used */ |
|
70 |
- uint16_t MinorOperatingSystemVersion; /**< not used */ |
|
71 |
- uint16_t MajorImageVersion; /**< unreliable */ |
|
72 |
- uint16_t MinorImageVersion; /**< unreliable */ |
|
73 |
- uint16_t MajorSubsystemVersion; |
|
74 |
- uint16_t MinorSubsystemVersion; |
|
75 |
- uint32_t Win32VersionValue; /*< ? */ |
|
76 |
- uint32_t SizeOfImage; |
|
77 |
- uint32_t SizeOfHeaders; |
|
78 |
- uint32_t CheckSum; /**< NT drivers only */ |
|
79 |
- uint16_t Subsystem; |
|
80 |
- uint16_t DllCharacteristics; |
|
81 |
- uint32_t SizeOfStackReserve; |
|
82 |
- uint32_t SizeOfStackCommit; |
|
83 |
- uint32_t SizeOfHeapReserve; |
|
84 |
- uint32_t SizeOfHeapCommit; |
|
85 |
- uint32_t LoaderFlags; /*< ? */ |
|
86 |
- uint32_t NumberOfRvaAndSizes; /**< unreliable */ |
|
87 |
- struct pe_image_data_dir DataDirectory[16]; |
|
88 |
-}; |
|
89 |
- |
|
90 |
-/** PE 64-bit optional header |
|
91 |
- \group_pe */ |
|
92 |
-struct pe_image_optional_hdr64 { |
|
93 |
- uint16_t Magic; |
|
94 |
- uint8_t MajorLinkerVersion; /**< unreliable */ |
|
95 |
- uint8_t MinorLinkerVersion; /**< unreliable */ |
|
96 |
- uint32_t SizeOfCode; /**< unreliable */ |
|
97 |
- uint32_t SizeOfInitializedData; /**< unreliable */ |
|
98 |
- uint32_t SizeOfUninitializedData; /**< unreliable */ |
|
99 |
- uint32_t AddressOfEntryPoint; |
|
100 |
- uint32_t BaseOfCode; |
|
101 |
- uint64_t ImageBase; /**< multiple of 64 KB */ |
|
102 |
- uint32_t SectionAlignment; /**< usually 32 or 4096 */ |
|
103 |
- uint32_t FileAlignment; /**< usually 32 or 512 */ |
|
104 |
- uint16_t MajorOperatingSystemVersion; /**< not used */ |
|
105 |
- uint16_t MinorOperatingSystemVersion; /**< not used */ |
|
106 |
- uint16_t MajorImageVersion; /**< unreliable */ |
|
107 |
- uint16_t MinorImageVersion; /**< unreliable */ |
|
108 |
- uint16_t MajorSubsystemVersion; |
|
109 |
- uint16_t MinorSubsystemVersion; |
|
110 |
- uint32_t Win32VersionValue; /* ? */ |
|
111 |
- uint32_t SizeOfImage; |
|
112 |
- uint32_t SizeOfHeaders; |
|
113 |
- uint32_t CheckSum; /**< NT drivers only */ |
|
114 |
- uint16_t Subsystem; |
|
115 |
- uint16_t DllCharacteristics; |
|
116 |
- uint64_t SizeOfStackReserve; |
|
117 |
- uint64_t SizeOfStackCommit; |
|
118 |
- uint64_t SizeOfHeapReserve; |
|
119 |
- uint64_t SizeOfHeapCommit; |
|
120 |
- uint32_t LoaderFlags; /* ? */ |
|
121 |
- uint32_t NumberOfRvaAndSizes; /**< unreliable */ |
|
122 |
- struct pe_image_data_dir DataDirectory[16]; |
|
123 |
-}; |
|
124 |
- |
|
125 |
-/** PE section header |
|
126 |
- \group_pe */ |
|
127 |
-struct pe_image_section_hdr { |
|
128 |
- uint8_t Name[8]; /**< may not end with NULL */ |
|
129 |
- /* |
|
130 |
- union { |
|
131 |
- uint32_t PhysicalAddress; |
|
132 |
- uint32_t VirtualSize; |
|
133 |
- } AddrSize; |
|
134 |
- */ |
|
135 |
- uint32_t VirtualSize; |
|
136 |
- uint32_t VirtualAddress; |
|
137 |
- uint32_t SizeOfRawData; /**< multiple of FileAlignment */ |
|
138 |
- uint32_t PointerToRawData; /**< offset to the section's data */ |
|
139 |
- uint32_t PointerToRelocations; /**< object files only */ |
|
140 |
- uint32_t PointerToLinenumbers; /**< object files only */ |
|
141 |
- uint16_t NumberOfRelocations; /**< object files only */ |
|
142 |
- uint16_t NumberOfLinenumbers; /**< object files only */ |
|
143 |
- uint32_t Characteristics; |
|
144 |
-}; |
|
145 |
- |
|
146 |
-#define WIN_CERT_REV_2 0x0200 |
|
147 |
-#define WIN_CERT_TYPE_PKCS7 0x0002 |
|
148 |
- |
|
149 |
-/** PE authenticode data header |
|
150 |
- \group_pe */ |
|
151 |
-struct pe_certificate_hdr { |
|
152 |
- uint32_t length; /** length of the certificate data, including the header */ |
|
153 |
- uint16_t revision; |
|
154 |
- uint16_t type; |
|
155 |
-}; |
|
32 |
+#include "pe_structs.h" |
|
33 |
+#include "execs.h" |
|
156 | 34 |
|
157 | 35 |
/** Data for the bytecode PE hook |
158 |
- \group_pe */ |
|
36 |
+ \group_pe |
|
37 |
+ * |
|
38 |
+ * NOTE: This structure must stay in-sync with the ones defined within the |
|
39 |
+ * clamav-bytecode-compiler source at: |
|
40 |
+ * - clang/lib/Headers/bytecode_pe.h |
|
41 |
+ * - llvm/tools/clang/lib/Headers/bytecode_pe.h |
|
42 |
+ * We allocate space for this, populate the values via cli_peheader, and pass |
|
43 |
+ * it to the bytecode sig runtime for use. |
|
44 |
+ * |
|
45 |
+ * TODO Next time we are making changes to the clamav-bytecode-compiler |
|
46 |
+ * source, update pe_image_optional_hdr32 and pe_image_optional_hdr64 to |
|
47 |
+ * remove DataDirectory from both (like with the definitions here). Then, |
|
48 |
+ * remove opt32_dirs and opt64_dirs below. There's no need to have these |
|
49 |
+ * bytes in 3 places! Also, consider using a union to hold opt32 and opt64, |
|
50 |
+ * since you never need more than one at a time. |
|
51 |
+ */ |
|
159 | 52 |
struct cli_pe_hook_data { |
160 | 53 |
uint32_t offset; |
161 | 54 |
uint32_t ep; /**< EntryPoint as file offset */ |
... | ... |
@@ -163,13 +56,18 @@ struct cli_pe_hook_data { |
163 | 163 |
uint16_t dummy; /* align */ |
164 | 164 |
struct pe_image_file_hdr file_hdr; /**< Header for this PE file */ |
165 | 165 |
struct pe_image_optional_hdr32 opt32; /**< 32-bit PE optional header */ |
166 |
- uint32_t dummy2; /* align */ |
|
167 |
- struct pe_image_optional_hdr64 opt64; /**< 64-bit PE optional header */ |
|
168 |
- struct pe_image_data_dir dirs[16]; /**< PE data directory header */ |
|
169 |
- uint32_t e_lfanew; /**< address of new exe header */ |
|
170 |
- uint32_t overlays; /**< number of overlays */ |
|
171 |
- int32_t overlays_sz; /**< size of overlays */ |
|
172 |
- uint32_t hdr_size; /**< internally needed by rawaddr */ |
|
166 |
+ /** Our opt32 no longer includes DataDirectory[16], but the one in the |
|
167 |
+ * bytecode compiler source still does. Add this here as a placeholder (and |
|
168 |
+ * it gets used, so we need to populate it also */ |
|
169 |
+ struct pe_image_data_dir opt32_dirs[16]; |
|
170 |
+ uint32_t dummy2; /* align */ |
|
171 |
+ struct pe_image_optional_hdr64 opt64; /**< 64-bit PE optional header */ |
|
172 |
+ struct pe_image_data_dir opt64_dirs[16]; /** See note about opt32_dirs */ |
|
173 |
+ struct pe_image_data_dir dirs[16]; /**< PE data directory header */ |
|
174 |
+ uint32_t e_lfanew; /**< address of new exe header */ |
|
175 |
+ uint32_t overlays; /**< number of overlays */ |
|
176 |
+ int32_t overlays_sz; /**< size of overlays */ |
|
177 |
+ uint32_t hdr_size; /**< internally needed by rawaddr */ |
|
173 | 178 |
}; |
174 | 179 |
|
175 | 180 |
int cli_scanpe(cli_ctx *ctx); |
... | ... |
@@ -185,11 +83,25 @@ enum { |
185 | 185 |
CL_GENHASH_PE_CLASS_LAST |
186 | 186 |
}; |
187 | 187 |
|
188 |
-int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo); |
|
188 |
+// For info about these, see the cli_peheader definition in pe.c |
|
189 |
+#define CLI_PEHEADER_OPT_NONE 0x0 |
|
190 |
+#define CLI_PEHEADER_OPT_COLLECT_JSON 0x1 |
|
191 |
+#define CLI_PEHEADER_OPT_DBG_PRINT_INFO 0x2 |
|
192 |
+#define CLI_PEHEADER_OPT_EXTRACT_VINFO 0x4 |
|
193 |
+#define CLI_PEHEADER_OPT_STRICT_ON_PE_ERRORS 0x8 |
|
194 |
+ |
|
195 |
+#define CLI_PEHEADER_RET_SUCCESS 0 |
|
196 |
+#define CLI_PEHEADER_RET_GENERIC_ERROR -1 |
|
197 |
+#define CLI_PEHEADER_RET_BROKEN_PE -2 |
|
198 |
+#define CLI_PEHEADER_RET_JSON_TIMEOUT -3 |
|
199 |
+ |
|
200 |
+int cli_pe_targetinfo(fmap_t *map, struct cli_exe_info *peinfo); |
|
201 |
+int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ctx *ctx); |
|
202 |
+ |
|
189 | 203 |
cl_error_t cli_checkfp_pe(cli_ctx *ctx, stats_section_t *hashes, uint32_t flags); |
190 | 204 |
int cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type); |
191 | 205 |
|
192 | 206 |
uint32_t cli_rawaddr(uint32_t, const struct cli_exe_section *, uint16_t, unsigned int *, size_t, uint32_t); |
193 |
-void findres(uint32_t, uint32_t, uint32_t, fmap_t *map, struct cli_exe_section *, uint16_t, uint32_t, int (*)(void *, uint32_t, uint32_t, uint32_t, uint32_t), void *); |
|
207 |
+void findres(uint32_t, uint32_t, fmap_t *map, struct cli_exe_info *, int (*)(void *, uint32_t, uint32_t, uint32_t, uint32_t), void *); |
|
194 | 208 |
|
195 | 209 |
#endif |
... | ... |
@@ -49,10 +49,7 @@ struct ICON_ENV { |
49 | 49 |
int result; |
50 | 50 |
|
51 | 51 |
icon_groupset *set; |
52 |
- uint32_t resdir_rva; |
|
53 |
- struct cli_exe_section *exe_sections; |
|
54 |
- uint16_t nsections; |
|
55 |
- uint32_t hdr_size; |
|
52 |
+ struct cli_exe_info *peinfo; |
|
56 | 53 |
|
57 | 54 |
uint32_t icnt; /* number of icon entries parsed, declared images */ |
58 | 55 |
uint32_t max_icons; |
... | ... |
@@ -110,7 +107,7 @@ static int icon_scan_cb(void *ptr, uint32_t type, uint32_t name, uint32_t lang, |
110 | 110 |
return 0; |
111 | 111 |
} |
112 | 112 |
|
113 |
-int cli_scanicon(icon_groupset *set, uint32_t resdir_rva, cli_ctx *ctx, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size) |
|
113 |
+int cli_scanicon(icon_groupset *set, cli_ctx *ctx, struct cli_exe_info *peinfo) |
|
114 | 114 |
{ |
115 | 115 |
struct ICON_ENV icon_env; |
116 | 116 |
fmap_t *map = *ctx->fmap; |
... | ... |
@@ -124,10 +121,7 @@ int cli_scanicon(icon_groupset *set, uint32_t resdir_rva, cli_ctx *ctx, struct c |
124 | 124 |
icon_env.result = CL_CLEAN; |
125 | 125 |
|
126 | 126 |
icon_env.set = set; |
127 |
- icon_env.resdir_rva = resdir_rva; |
|
128 |
- icon_env.exe_sections = exe_sections; |
|
129 |
- icon_env.nsections = nsections; |
|
130 |
- icon_env.hdr_size = hdr_size; |
|
127 |
+ icon_env.peinfo = peinfo; |
|
131 | 128 |
|
132 | 129 |
icon_env.max_icons = ctx->engine->maxiconspe; |
133 | 130 |
|
... | ... |
@@ -138,7 +132,7 @@ int cli_scanicon(icon_groupset *set, uint32_t resdir_rva, cli_ctx *ctx, struct c |
138 | 138 |
icon_env.err_insl = 0; |
139 | 139 |
|
140 | 140 |
/* icon group scan callback --> groupicon_scan_cb() */ |
141 |
- findres(14, 0xffffffff, resdir_rva, map, exe_sections, nsections, hdr_size, groupicon_scan_cb, &icon_env); |
|
141 |
+ findres(14, 0xffffffff, map, peinfo, groupicon_scan_cb, &icon_env); |
|
142 | 142 |
|
143 | 143 |
/* CL_EMAXSIZE is used to track the icon limit */ |
144 | 144 |
if (icon_env.result == CL_EMAXSIZE) |
... | ... |
@@ -173,15 +167,12 @@ int cli_scanicon(icon_groupset *set, uint32_t resdir_rva, cli_ctx *ctx, struct c |
173 | 173 |
int cli_groupiconscan(struct ICON_ENV *icon_env, uint32_t rva) |
174 | 174 |
{ |
175 | 175 |
/* import environment */ |
176 |
- uint32_t resdir_rva = icon_env->resdir_rva; |
|
177 | 176 |
cli_ctx *ctx = icon_env->ctx; |
178 |
- struct cli_exe_section *exe_sections = icon_env->exe_sections; |
|
179 |
- uint16_t nsections = icon_env->nsections; |
|
180 |
- uint32_t hdr_size = icon_env->hdr_size; |
|
177 |
+ struct cli_exe_info *peinfo = icon_env->peinfo; |
|
181 | 178 |
|
182 | 179 |
int err = 0; |
183 | 180 |
fmap_t *map = *ctx->fmap; |
184 |
- const uint8_t *grp = fmap_need_off_once(map, cli_rawaddr(rva, exe_sections, nsections, (unsigned int *)(&err), map->len, hdr_size), 16); |
|
181 |
+ const uint8_t *grp = fmap_need_off_once(map, cli_rawaddr(rva, peinfo->sections, peinfo->nsections, (unsigned int *)(&err), map->len, peinfo->hdr_size), 16); |
|
185 | 182 |
|
186 | 183 |
if (grp && !err) { |
187 | 184 |
uint32_t gsz = cli_readint32(grp + 4); |
... | ... |
@@ -199,7 +190,7 @@ int cli_groupiconscan(struct ICON_ENV *icon_env, uint32_t rva) |
199 | 199 |
uint16_t id; |
200 | 200 |
} * dir; |
201 | 201 |
|
202 |
- raddr = cli_rawaddr(cli_readint32(grp), exe_sections, nsections, (unsigned int *)(&err), map->len, hdr_size); |
|
202 |
+ raddr = cli_rawaddr(cli_readint32(grp), peinfo->sections, peinfo->nsections, (unsigned int *)(&err), map->len, peinfo->hdr_size); |
|
203 | 203 |
cli_dbgmsg("cli_scanicon: icon group @%x\n", raddr); |
204 | 204 |
grp = fmap_need_off_once(map, raddr, gsz); |
205 | 205 |
if (grp && !err) { |
... | ... |
@@ -215,7 +206,7 @@ int cli_groupiconscan(struct ICON_ENV *icon_env, uint32_t rva) |
215 | 215 |
cli_dbgmsg("cli_scanicon: Icongrp @%x - %ux%ux%u - (id=%x, rsvd=%u, planes=%u, palcnt=%u, sz=%x)\n", rva, dir->w, dir->h, cli_readint16(&dir->depth), cli_readint16(&dir->id), cli_readint16(&dir->planes), dir->palcnt, dir->rsvd, cli_readint32(&dir->sz)); |
216 | 216 |
|
217 | 217 |
/* icon scan callback --> icon_scan_cb() */ |
218 |
- findres(3, cli_readint16(&dir->id), resdir_rva, map, exe_sections, nsections, hdr_size, icon_scan_cb, icon_env); |
|
218 |
+ findres(3, cli_readint16(&dir->id), map, peinfo, icon_scan_cb, icon_env); |
|
219 | 219 |
if (icon_env->result != CL_CLEAN) |
220 | 220 |
return icon_env->result; |
221 | 221 |
|
... | ... |
@@ -1345,9 +1336,7 @@ static int parseicon(struct ICON_ENV *icon_env, uint32_t rva) |
1345 | 1345 |
{ |
1346 | 1346 |
icon_groupset *set = icon_env->set; |
1347 | 1347 |
cli_ctx *ctx = icon_env->ctx; |
1348 |
- struct cli_exe_section *exe_sections = icon_env->exe_sections; |
|
1349 |
- uint16_t nsections = icon_env->nsections; |
|
1350 |
- uint32_t hdr_size = icon_env->hdr_size; |
|
1348 |
+ struct cli_exe_info *peinfo = icon_env->peinfo; |
|
1351 | 1349 |
|
1352 | 1350 |
struct |
1353 | 1351 |
{ |
... | ... |
@@ -1381,7 +1370,7 @@ static int parseicon(struct ICON_ENV *icon_env, uint32_t rva) |
1381 | 1381 |
return CL_SUCCESS; |
1382 | 1382 |
map = *ctx->fmap; |
1383 | 1383 |
tempd = (cli_debug_flag && ctx->engine->keeptmp) ? (ctx->engine->tmpdir ? ctx->engine->tmpdir : cli_gettmpdir()) : NULL; |
1384 |
- icoff = cli_rawaddr(rva, exe_sections, nsections, &err, map->len, hdr_size); |
|
1384 |
+ icoff = cli_rawaddr(rva, peinfo->sections, peinfo->nsections, &err, map->len, peinfo->hdr_size); |
|
1385 | 1385 |
|
1386 | 1386 |
/* read the bitmap header */ |
1387 | 1387 |
if (err || !(rawimage = fmap_need_off_once(map, icoff, 4))) { |
... | ... |
@@ -1391,7 +1380,7 @@ static int parseicon(struct ICON_ENV *icon_env, uint32_t rva) |
1391 | 1391 |
} |
1392 | 1392 |
|
1393 | 1393 |
rva = cli_readint32(rawimage); |
1394 |
- icoff = cli_rawaddr(rva, exe_sections, nsections, &err, map->len, hdr_size); |
|
1394 |
+ icoff = cli_rawaddr(rva, peinfo->sections, peinfo->nsections, &err, map->len, peinfo->hdr_size); |
|
1395 | 1395 |
if (err || fmap_readn(map, &bmphdr, icoff, sizeof(bmphdr)) != sizeof(bmphdr)) { |
1396 | 1396 |
icon_env->err_bhoof++; |
1397 | 1397 |
//cli_dbgmsg("parseicon: bmp header is out of file\n"); |
... | ... |
@@ -23,7 +23,7 @@ |
23 | 23 |
#define __PE_ICONS_H |
24 | 24 |
#include "pe.h" |
25 | 25 |
|
26 |
-int cli_scanicon(icon_groupset *set, uint32_t resdir_rva, cli_ctx *ctx, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size); |
|
26 |
+int cli_scanicon(icon_groupset *set, cli_ctx *ctx, struct cli_exe_info *peinfo); |
|
27 | 27 |
|
28 | 28 |
void cli_icongroupset_add(const char *groupname, icon_groupset *set, unsigned int type, cli_ctx *ctx); |
29 | 29 |
static inline void cli_icongroupset_init(icon_groupset *set) |
30 | 30 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,154 @@ |
0 |
+/* |
|
1 |
+ * Copyright (C) 2015, 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * Copyright (C) 2007-2008 Sourcefire, Inc. |
|
3 |
+ * |
|
4 |
+ * Authors: Alberto Wu, Tomasz Kojm, Andrew Williams |
|
5 |
+ * |
|
6 |
+ * Acknowledgements: The header structures were based upon a PE format |
|
7 |
+ * analysis by B. Luevelsmeyer. |
|
8 |
+ * |
|
9 |
+ * This program is free software; you can redistribute it and/or modify |
|
10 |
+ * it under the terms of the GNU General Public License version 2 as |
|
11 |
+ * published by the Free Software Foundation. |
|
12 |
+ * |
|
13 |
+ * This program is distributed in the hope that it will be useful, |
|
14 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
16 |
+ * GNU General Public License for more details. |
|
17 |
+ * |
|
18 |
+ * You should have received a copy of the GNU General Public License |
|
19 |
+ * along with this program; if not, write to the Free Software |
|
20 |
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
21 |
+ * MA 02110-1301, USA. |
|
22 |
+ */ |
|
23 |
+ |
|
24 |
+#ifndef __PE_STRUCTS_H |
|
25 |
+#define __PE_STRUCTS_H |
|
26 |
+ |
|
27 |
+#include "clamav.h" |
|
28 |
+ |
|
29 |
+/** @file */ |
|
30 |
+/** Header for this PE file |
|
31 |
+ \group_pe */ |
|
32 |
+struct pe_image_file_hdr { |
|
33 |
+ uint32_t Magic; /**< PE magic header: PE\\0\\0 */ |
|
34 |
+ uint16_t Machine; /**< CPU this executable runs on, see libclamav/pe.c for possible values */ |
|
35 |
+ uint16_t NumberOfSections; /**< Number of sections in this executable */ |
|
36 |
+ uint32_t TimeDateStamp; /**< Unreliable */ |
|
37 |
+ uint32_t PointerToSymbolTable; /**< debug */ |
|
38 |
+ uint32_t NumberOfSymbols; /**< debug */ |
|
39 |
+ uint16_t SizeOfOptionalHeader; /**< == 224 */ |
|
40 |
+ uint16_t Characteristics; |
|
41 |
+}; |
|
42 |
+ |
|
43 |
+/** PE data directory header |
|
44 |
+ \group_pe */ |
|
45 |
+struct pe_image_data_dir { |
|
46 |
+ uint32_t VirtualAddress; |
|
47 |
+ uint32_t Size; |
|
48 |
+}; |
|
49 |
+ |
|
50 |
+/** 32-bit PE optional header |
|
51 |
+ \group_pe */ |
|
52 |
+struct pe_image_optional_hdr32 { |
|
53 |
+ uint16_t Magic; |
|
54 |
+ uint8_t MajorLinkerVersion; /**< unreliable */ |
|
55 |
+ uint8_t MinorLinkerVersion; /**< unreliable */ |
|
56 |
+ uint32_t SizeOfCode; /**< unreliable */ |
|
57 |
+ uint32_t SizeOfInitializedData; /**< unreliable */ |
|
58 |
+ uint32_t SizeOfUninitializedData; /**< unreliable */ |
|
59 |
+ uint32_t AddressOfEntryPoint; |
|
60 |
+ uint32_t BaseOfCode; |
|
61 |
+ uint32_t BaseOfData; |
|
62 |
+ uint32_t ImageBase; /**< multiple of 64 KB */ |
|
63 |
+ uint32_t SectionAlignment; /**< usually 32 or 4096 */ |
|
64 |
+ uint32_t FileAlignment; /**< usually 32 or 512 */ |
|
65 |
+ uint16_t MajorOperatingSystemVersion; /**< not used */ |
|
66 |
+ uint16_t MinorOperatingSystemVersion; /**< not used */ |
|
67 |
+ uint16_t MajorImageVersion; /**< unreliable */ |
|
68 |
+ uint16_t MinorImageVersion; /**< unreliable */ |
|
69 |
+ uint16_t MajorSubsystemVersion; |
|
70 |
+ uint16_t MinorSubsystemVersion; |
|
71 |
+ uint32_t Win32VersionValue; /*< ? */ |
|
72 |
+ uint32_t SizeOfImage; |
|
73 |
+ uint32_t SizeOfHeaders; |
|
74 |
+ uint32_t CheckSum; /**< NT drivers only */ |
|
75 |
+ uint16_t Subsystem; |
|
76 |
+ uint16_t DllCharacteristics; |
|
77 |
+ uint32_t SizeOfStackReserve; |
|
78 |
+ uint32_t SizeOfStackCommit; |
|
79 |
+ uint32_t SizeOfHeapReserve; |
|
80 |
+ uint32_t SizeOfHeapCommit; |
|
81 |
+ uint32_t LoaderFlags; /*< ? */ |
|
82 |
+ uint32_t NumberOfRvaAndSizes; |
|
83 |
+ //struct pe_image_data_dir DataDirectory[16]; |
|
84 |
+}; |
|
85 |
+ |
|
86 |
+/** PE 64-bit optional header |
|
87 |
+ \group_pe */ |
|
88 |
+struct pe_image_optional_hdr64 { |
|
89 |
+ uint16_t Magic; |
|
90 |
+ uint8_t MajorLinkerVersion; /**< unreliable */ |
|
91 |
+ uint8_t MinorLinkerVersion; /**< unreliable */ |
|
92 |
+ uint32_t SizeOfCode; /**< unreliable */ |
|
93 |
+ uint32_t SizeOfInitializedData; /**< unreliable */ |
|
94 |
+ uint32_t SizeOfUninitializedData; /**< unreliable */ |
|
95 |
+ uint32_t AddressOfEntryPoint; |
|
96 |
+ uint32_t BaseOfCode; |
|
97 |
+ uint64_t ImageBase; /**< multiple of 64 KB */ |
|
98 |
+ uint32_t SectionAlignment; /**< usually 32 or 4096 */ |
|
99 |
+ uint32_t FileAlignment; /**< usually 32 or 512 */ |
|
100 |
+ uint16_t MajorOperatingSystemVersion; /**< not used */ |
|
101 |
+ uint16_t MinorOperatingSystemVersion; /**< not used */ |
|
102 |
+ uint16_t MajorImageVersion; /**< unreliable */ |
|
103 |
+ uint16_t MinorImageVersion; /**< unreliable */ |
|
104 |
+ uint16_t MajorSubsystemVersion; |
|
105 |
+ uint16_t MinorSubsystemVersion; |
|
106 |
+ uint32_t Win32VersionValue; /* ? */ |
|
107 |
+ uint32_t SizeOfImage; |
|
108 |
+ uint32_t SizeOfHeaders; |
|
109 |
+ uint32_t CheckSum; /**< NT drivers only */ |
|
110 |
+ uint16_t Subsystem; |
|
111 |
+ uint16_t DllCharacteristics; |
|
112 |
+ uint64_t SizeOfStackReserve; |
|
113 |
+ uint64_t SizeOfStackCommit; |
|
114 |
+ uint64_t SizeOfHeapReserve; |
|
115 |
+ uint64_t SizeOfHeapCommit; |
|
116 |
+ uint32_t LoaderFlags; /* ? */ |
|
117 |
+ uint32_t NumberOfRvaAndSizes; |
|
118 |
+ //struct pe_image_data_dir DataDirectory[16]; |
|
119 |
+}; |
|
120 |
+ |
|
121 |
+/** PE section header |
|
122 |
+ \group_pe */ |
|
123 |
+struct pe_image_section_hdr { |
|
124 |
+ uint8_t Name[8]; /**< may not end with NULL */ |
|
125 |
+ /* |
|
126 |
+ union { |
|
127 |
+ uint32_t PhysicalAddress; |
|
128 |
+ uint32_t VirtualSize; |
|
129 |
+ } AddrSize; |
|
130 |
+ */ |
|
131 |
+ uint32_t VirtualSize; |
|
132 |
+ uint32_t VirtualAddress; |
|
133 |
+ uint32_t SizeOfRawData; /**< multiple of FileAlignment */ |
|
134 |
+ uint32_t PointerToRawData; /**< offset to the section's data */ |
|
135 |
+ uint32_t PointerToRelocations; /**< object files only */ |
|
136 |
+ uint32_t PointerToLinenumbers; /**< object files only */ |
|
137 |
+ uint16_t NumberOfRelocations; /**< object files only */ |
|
138 |
+ uint16_t NumberOfLinenumbers; /**< object files only */ |
|
139 |
+ uint32_t Characteristics; |
|
140 |
+}; |
|
141 |
+ |
|
142 |
+#define WIN_CERT_REV_2 0x0200 |
|
143 |
+#define WIN_CERT_TYPE_PKCS7 0x0002 |
|
144 |
+ |
|
145 |
+/** PE authenticode data header |
|
146 |
+ \group_pe */ |
|
147 |
+struct pe_certificate_hdr { |
|
148 |
+ uint32_t length; /** length of the certificate data, including the header */ |
|
149 |
+ uint16_t revision; |
|
150 |
+ uint16_t type; |
|
151 |
+}; |
|
152 |
+ |
|
153 |
+#endif |
|
0 | 154 |
\ No newline at end of file |
... | ... |
@@ -2513,7 +2513,7 @@ static int cli_loadhash(FILE *fs, struct cl_engine *engine, unsigned int *signo, |
2513 | 2513 |
} |
2514 | 2514 |
} |
2515 | 2515 |
|
2516 |
- if ((mode == MD5_MDB) || strcmp(tokens[size_field], "*")) { |
|
2516 |
+ if (strcmp(tokens[size_field], "*")) { |
|
2517 | 2517 |
size = strtoul(tokens[size_field], (char **)&pt, 10); |
2518 | 2518 |
if (*pt || !size || size >= 0xffffffff) { |
2519 | 2519 |
cli_errmsg("cli_loadhash: Invalid value for the size field\n"); |
... | ... |
@@ -2522,7 +2522,12 @@ static int cli_loadhash(FILE *fs, struct cl_engine *engine, unsigned int *signo, |
2522 | 2522 |
} |
2523 | 2523 |
} else { |
2524 | 2524 |
size = 0; |
2525 |
- if ((tokens_count < MD5_TOKENS - 1) || (req_fl < 73)) { |
|
2525 |
+ // The wildcard feature was added in FLEVEL 73, so for backwards |
|
2526 |
+ // compatibility with older clients, ensure that a minimum FLEVEL |
|
2527 |
+ // is specified. This check doesn't apply to .imp rules, though, |
|
2528 |
+ // since this rule category wasn't introduced until FLEVEL 90, and |
|
2529 |
+ // has always supported wildcard usage in rules. |
|
2530 |
+ if (mode != MD5_IMP && ((tokens_count < MD5_TOKENS - 1) || (req_fl < 73))) { |
|
2526 | 2531 |
cli_errmsg("cli_loadhash: Minimum FLEVEL field must be at least 73 for wildcard size hash signatures." |
2527 | 2532 |
" For reference, running FLEVEL is %d\n", |
2528 | 2533 |
cl_retflevel()); |
... | ... |
@@ -4600,7 +4605,16 @@ static int cli_loaddbdir(const char *dirname, struct cl_engine *engine, unsigned |
4600 | 4600 |
while ((dent = readdir(dd))) { |
4601 | 4601 |
#endif |
4602 | 4602 |
if (dent->d_ino) { |
4603 |
- if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..") && strcmp(dent->d_name, "daily.cvd") && strcmp(dent->d_name, "daily.cld") && strcmp(dent->d_name, "daily.cfg") && CLI_DBEXT(dent->d_name)) { |
|
4603 |
+ if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) { |
|
4604 |
+ continue; |
|
4605 |
+ } |
|
4606 |
+ |
|
4607 |
+ /* Skip everything that's already been loaded in or ignored */ |
|
4608 |
+ if (cli_strbcasestr(dent->d_name, ".ign") || cli_strbcasestr(dent->d_name, ".ign2") || !strcmp(dent->d_name, "daily.cvd") || !strcmp(dent->d_name, "daily.cld") || !strcmp(dent->d_name, "local.gdb") || !strcmp(dent->d_name, "daily.cfg")) { |
|
4609 |
+ continue; |
|
4610 |
+ } |
|
4611 |
+ |
|
4612 |
+ if (CLI_DBEXT(dent->d_name)) { |
|
4604 | 4613 |
if ((options & CL_DB_OFFICIAL_ONLY) && !strstr(dirname, "clamav-") && !cli_strbcasestr(dent->d_name, ".cld") && !cli_strbcasestr(dent->d_name, ".cvd")) { |
4605 | 4614 |
cli_dbgmsg("Skipping unofficial database %s\n", dent->d_name); |
4606 | 4615 |
continue; |
... | ... |
@@ -5286,13 +5300,30 @@ static int countsigs(const char *dbname, unsigned int options, unsigned int *sig |
5286 | 5286 |
*sigs += cvd->sigs; |
5287 | 5287 |
cl_cvdfree(cvd); |
5288 | 5288 |
} |
5289 |
+ } else if ((cli_strbcasestr(dbname, ".cud"))) { |
|
5290 |
+ if (options & CL_COUNTSIGS_UNOFFICIAL) { |
|
5291 |
+ struct cl_cvd *cvd = cl_cvdhead(dbname); |
|
5292 |
+ if (!cvd) { |
|
5293 |
+ cli_errmsg("countsigs: Can't parse %s\n", dbname); |
|
5294 |
+ return CL_ECVD; |
|
5295 |
+ } |
|
5296 |
+ *sigs += cvd->sigs; |
|
5297 |
+ cl_cvdfree(cvd); |
|
5298 |
+ } |
|
5289 | 5299 |
} else if (cli_strbcasestr(dbname, ".cbc")) { |
5290 | 5300 |
if (options & CL_COUNTSIGS_UNOFFICIAL) |
5291 | 5301 |
(*sigs)++; |
5292 | 5302 |
|
5293 |
- } else if (cli_strbcasestr(dbname, ".wdb") || cli_strbcasestr(dbname, ".fp") || cli_strbcasestr(dbname, ".ftm") || cli_strbcasestr(dbname, ".cfg") || cli_strbcasestr(dbname, ".cat")) { |
|
5294 |
- /* ignore */ |
|
5303 |
+ } else if (cli_strbcasestr(dbname, ".wdb") || cli_strbcasestr(dbname, ".fp") || cli_strbcasestr(dbname, ".sfp") || cli_strbcasestr(dbname, ".ign") || cli_strbcasestr(dbname, ".ign2") || cli_strbcasestr(dbname, ".ftm") || cli_strbcasestr(dbname, ".cfg") || cli_strbcasestr(dbname, ".cat")) { |
|
5304 |
+ /* ignore whitelist/FP signatures and metadata files */ |
|
5305 |
+ |
|
5306 |
+ // TODO .crb sigs can contain both whitelist and blacklist signatures. |
|
5307 |
+ // For now we will just include both in the count by not excluding this |
|
5308 |
+ // sig type here, but in the future we could extract just the number of |
|
5309 |
+ // blacklist rules manually so that the count is more accurate. |
|
5295 | 5310 |
|
5311 |
+ // NOTE: We implicitly ignore .info files because they aren't currently |
|
5312 |
+ // in the list of ones checked for by CLI_DBEXT |
|
5296 | 5313 |
} else if ((options & CL_COUNTSIGS_UNOFFICIAL) && CLI_DBEXT(dbname)) { |
5297 | 5314 |
return countentries(dbname, sigs); |
5298 | 5315 |
} |
... | ... |
@@ -28,6 +28,13 @@ |
28 | 28 |
#include "str.h" |
29 | 29 |
#include "cvd.h" |
30 | 30 |
|
31 |
+// TODO Is it safe to remove .db2 and .db3 from here? These strings aren't |
|
32 |
+// referenced anywhere else in the source. |
|
33 |
+ |
|
34 |
+// NOTE: We don't include .info in CLI_DBEXT because they are only used for |
|
35 |
+// one specific purpose - verifying the contents of database container files. |
|
36 |
+// This list is geared towards file extensions of files that users can provide |
|
37 |
+// to ClamAV directly. |
|
31 | 38 |
#ifdef HAVE_YARA |
32 | 39 |
#define CLI_DBEXT(ext) \ |
33 | 40 |
( \ |
... | ... |
@@ -67,7 +74,10 @@ |
67 | 67 |
cli_strbcasestr(ext, ".ioc") || \ |
68 | 68 |
cli_strbcasestr(ext, ".yar") || \ |
69 | 69 |
cli_strbcasestr(ext, ".yara") || \ |
70 |
- cli_strbcasestr(ext, ".pwdb")) |
|
70 |
+ cli_strbcasestr(ext, ".pwdb") || \ |
|
71 |
+ cli_strbcasestr(ext, ".ign") || \ |
|
72 |
+ cli_strbcasestr(ext, ".ign2") || \ |
|
73 |
+ cli_strbcasestr(ext, ".imp")) |
|
71 | 74 |
#else |
72 | 75 |
#define CLI_DBEXT(ext) \ |
73 | 76 |
( \ |
... | ... |
@@ -104,7 +114,11 @@ |
104 | 104 |
cli_strbcasestr(ext, ".cat") || \ |
105 | 105 |
cli_strbcasestr(ext, ".crb") || \ |
106 | 106 |
cli_strbcasestr(ext, ".idb") || \ |
107 |
- cli_strbcasestr(ext, ".ioc")) |
|
107 |
+ cli_strbcasestr(ext, ".ioc") || \ |
|
108 |
+ cli_strbcasestr(ext, ".pwdb") || \ |
|
109 |
+ cli_strbcasestr(ext, ".ign") || \ |
|
110 |
+ cli_strbcasestr(ext, ".ign2") || \ |
|
111 |
+ cli_strbcasestr(ext, ".imp")) |
|
108 | 112 |
#endif |
109 | 113 |
|
110 | 114 |
char *cli_virname(const char *virname, unsigned int official); |
... | ... |
@@ -109,6 +109,7 @@ |
109 | 109 |
#include "tiff.h" |
110 | 110 |
#include "hwp.h" |
111 | 111 |
#include "msdoc.h" |
112 |
+#include "execs.h" |
|
112 | 113 |
|
113 | 114 |
#ifdef HAVE_BZLIB_H |
114 | 115 |
#include <bzlib.h> |
... | ... |
@@ -1528,6 +1529,9 @@ static int cli_scanscript(cli_ctx *ctx) |
1528 | 1528 |
troot = ctx->engine->root[7]; |
1529 | 1529 |
maxpatlen = troot ? troot->maxpatlen : 0; |
1530 | 1530 |
|
1531 |
+ // Initialize info so it's safe to pass to destroy later |
|
1532 |
+ cli_targetinfo_init(&info); |
|
1533 |
+ |
|
1531 | 1534 |
cli_dbgmsg("in cli_scanscript()\n"); |
1532 | 1535 |
|
1533 | 1536 |
/* CL_ENGINE_MAX_SCRIPTNORMALIZE */ |
... | ... |
@@ -1657,6 +1661,7 @@ static int cli_scanscript(cli_ctx *ctx) |
1657 | 1657 |
} |
1658 | 1658 |
|
1659 | 1659 |
done: |
1660 |
+ cli_targetinfo_destroy(&info); |
|
1660 | 1661 |
free(normalized); |
1661 | 1662 |
cli_ac_freedata(&tmdata); |
1662 | 1663 |
cli_ac_freedata(&gmdata); |
... | ... |
@@ -2604,14 +2609,15 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_ |
2604 | 2604 |
break; |
2605 | 2605 |
} |
2606 | 2606 |
cli_set_container(ctx, CL_TYPE_MSEXE, csize); |
2607 |
- memset(&peinfo, 0, sizeof(struct cli_exe_info)); |
|
2608 |
- peinfo.offset = fpt->offset; |
|
2609 |
- if (cli_peheader(map, &peinfo) == 0) { |
|
2607 |
+ |
|
2608 |
+ cli_exe_info_init(&peinfo, fpt->offset); |
|
2609 |
+ // TODO We could probably substitute in a quicker |
|
2610 |
+ // method of determining whether a PE file exists |
|
2611 |
+ // at this offset. |
|
2612 |
+ if (cli_peheader(map, &peinfo, CLI_PEHEADER_OPT_NONE, NULL) == 0) { |
|
2610 | 2613 |
cli_dbgmsg("*** Detected embedded PE file at %u ***\n", |
2611 | 2614 |
(unsigned int)fpt->offset); |
2612 |
- if (peinfo.section) |
|
2613 |
- free(peinfo.section); |
|
2614 |
- cli_hashset_destroy(&peinfo.vinfo); |
|
2615 |
+ cli_exe_info_destroy(&peinfo); |
|
2615 | 2616 |
|
2616 | 2617 |
nret = cli_scanembpe(ctx, fpt->offset); |
2617 | 2618 |
break_loop = 1; /* we can stop here and other |