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 |