diff --git a/libclamav/asn1.c b/libclamav/asn1.c index c71b1d235..b8e8ddff9 100644 --- a/libclamav/asn1.c +++ b/libclamav/asn1.c @@ -96,7 +96,7 @@ struct cli_asn1 { const void *next; }; -static int map_sha1(fmap_t *map, void *data, unsigned int len, uint8_t sha1[SHA1_HASH_SIZE]) { +static int map_sha1(fmap_t *map, const void *data, unsigned int len, uint8_t sha1[SHA1_HASH_SIZE]) { SHA1Context ctx; if(!fmap_need_ptr_once(map, data, len)) { cli_dbgmsg("map_sha1: failed to read hash data\n"); @@ -464,7 +464,7 @@ static int asn1_get_x509(fmap_t *map, const void **asn1data, unsigned int *size, unsigned int avail, tbssize, issuersize; cli_crt_hashtype hashtype1, hashtype2; cli_crt x509; - uint8_t *tbsdata; + const uint8_t *tbsdata; const void *next, *issuer; if(cli_crt_init(&x509)) @@ -577,7 +577,7 @@ static int asn1_get_x509(fmap_t *map, const void **asn1data, unsigned int *size, exts.size = 1; break; } - crit = (uint8_t *)(value.content); + crit = ((uint8_t *)(value.content))[0]; if(asn1_get_obj(map, value.next, &ext.size, &value)) { exts.size = 1; break; @@ -602,7 +602,7 @@ static int asn1_get_x509(fmap_t *map, const void **asn1data, unsigned int *size, } if(!memcmp("\x55\x1d\x0f", id.content, 3)) { /* KeyUsage 2.5.29.15 */ - uint8_t *keyusage = value.content; + const uint8_t *keyusage = value.content; uint32_t usage; if(value.size < 4 || value.size > 5) { cli_dbgmsg("asn1_get_x509: bad KeyUsage\n"); @@ -624,7 +624,7 @@ static int asn1_get_x509(fmap_t *map, const void **asn1data, unsigned int *size, usage |= keyusage[4]; } usage >>= keyusage[2]; - x509.certSign = (usage & (1<<5) != 0); + x509.certSign = ((usage & (1<<5)) != 0); continue; } if(!memcmp("\x55\x1d\x25", id.content, 3)) { @@ -724,7 +724,8 @@ static int asn1_get_x509(fmap_t *map, const void **asn1data, unsigned int *size, static int asn1_parse_mscat(fmap_t *map, const void *start, unsigned int size, crtmgr *cmgr, int embedded, const void **hashes, unsigned int *hashes_size) { struct cli_asn1 asn1, deep, deeper; - uint8_t sha1[SHA1_HASH_SIZE], issuer[SHA1_HASH_SIZE], md[SHA1_HASH_SIZE], *message, *attrs; + uint8_t sha1[SHA1_HASH_SIZE], issuer[SHA1_HASH_SIZE], md[SHA1_HASH_SIZE]; + const uint8_t *message, *attrs; unsigned int dsize, message_size, attrs_size; cli_crt_hashtype hashtype; SHA1Context ctx; diff --git a/libclamav/autoit.c b/libclamav/autoit.c index 54fdde36b..8dd0328ab 100644 --- a/libclamav/autoit.c +++ b/libclamav/autoit.c @@ -176,7 +176,7 @@ static uint32_t getbits(struct UNP *UNP, uint32_t size) { *********************/ -static int ea05(cli_ctx *ctx, uint8_t *base, char *tmpd) { +static int ea05(cli_ctx *ctx, const uint8_t *base, char *tmpd) { uint8_t b[300], comp; uint32_t s, m4sum=0; int i, ret; @@ -480,7 +480,7 @@ static void LAME_decrypt (uint8_t *cypher, uint32_t size, uint16_t seed) { autoit3 EA06 handler *********************/ -static int ea06(cli_ctx *ctx, uint8_t *base, char *tmpd) { +static int ea06(cli_ctx *ctx, const uint8_t *base, char *tmpd) { uint8_t b[600], comp, script, *buf; uint32_t s; int i, ret; @@ -916,7 +916,7 @@ static int ea06(cli_ctx *ctx, uint8_t *base, char *tmpd) { *********************/ int cli_scanautoit(cli_ctx *ctx, off_t offset) { - uint8_t *version; + const uint8_t *version; int r; char *tmpd; fmap_t *map = *ctx->fmap; diff --git a/libclamav/binhex.c b/libclamav/binhex.c index dfa74b249..1d7e3915f 100644 --- a/libclamav/binhex.c +++ b/libclamav/binhex.c @@ -48,7 +48,8 @@ static const uint8_t hqxtbl[] = { int cli_binhex(cli_ctx *ctx) { fmap_t *map = *ctx->fmap; - uint8_t *encoded, decoded[BUFSIZ], spare_bits, last_byte=0, this_byte, offset=0; + const uint8_t *encoded; + uint8_t decoded[BUFSIZ], spare_bits, last_byte=0, this_byte, offset=0; size_t enc_done=0, enc_todo=map->len; unsigned int dec_done=0, chunksz = 0, chunkoff=0; uint32_t datalen, reslen; diff --git a/libclamav/bytecode_api.c b/libclamav/bytecode_api.c index 927a765d3..67f8ad537 100644 --- a/libclamav/bytecode_api.c +++ b/libclamav/bytecode_api.c @@ -534,7 +534,7 @@ int32_t cli_bcapi_extract_new(struct cli_bc_ctx *ctx, int32_t id) int32_t cli_bcapi_read_number(struct cli_bc_ctx *ctx, uint32_t radix) { unsigned i; - char *p; + const char *p; int32_t result; if ((radix != 10 && radix != 16) || !ctx->fmap) @@ -705,7 +705,7 @@ uint32_t cli_bcapi_buffer_pipe_read_avail(struct cli_bc_ctx *ctx , int32_t id) return ctx->file_size - b->read_cursor; } -uint8_t* cli_bcapi_buffer_pipe_read_get(struct cli_bc_ctx *ctx , int32_t id, uint32_t size) +const uint8_t* cli_bcapi_buffer_pipe_read_get(struct cli_bc_ctx *ctx , int32_t id, uint32_t size) { struct bc_buffer *b = get_buffer(ctx, id); if (!b || size > cli_bcapi_buffer_pipe_read_avail(ctx, id) || !size) @@ -843,7 +843,7 @@ int32_t cli_bcapi_inflate_process(struct cli_bc_ctx *ctx , int32_t id) b->stream.avail_in = avail_in_orig = cli_bcapi_buffer_pipe_read_avail(ctx, b->from); - b->stream.next_in = cli_bcapi_buffer_pipe_read_get(ctx, b->from, + b->stream.next_in = (void*)cli_bcapi_buffer_pipe_read_get(ctx, b->from, b->stream.avail_in); b->stream.avail_out = avail_out_orig = @@ -959,7 +959,7 @@ static struct bc_jsnorm *get_jsnorm(struct cli_bc_ctx *ctx, int32_t id) int32_t cli_bcapi_jsnorm_process(struct cli_bc_ctx *ctx, int32_t id) { unsigned avail; - unsigned char *in; + const unsigned char *in; cli_ctx *cctx = ctx->ctx; struct bc_jsnorm *b = get_jsnorm(ctx, id); if (!b || b->from == -1 || !b->state) @@ -1448,7 +1448,7 @@ uint32_t cli_bcapi_pdf_getobjsize(struct cli_bc_ctx *ctx , int32_t objidx) return ctx->pdf_objs[objidx+1].start - ctx->pdf_objs[objidx].start - 4; } -uint8_t* cli_bcapi_pdf_getobj(struct cli_bc_ctx *ctx , int32_t objidx, uint32_t amount) +const uint8_t* cli_bcapi_pdf_getobj(struct cli_bc_ctx *ctx , int32_t objidx, uint32_t amount) { uint32_t size = cli_bcapi_pdf_getobjsize(ctx, objidx); if (amount > size) diff --git a/libclamav/bytecode_api_decl.c b/libclamav/bytecode_api_decl.c index c25bdeb04..6e26130b7 100644 --- a/libclamav/bytecode_api_decl.c +++ b/libclamav/bytecode_api_decl.c @@ -65,7 +65,7 @@ int32_t cli_bcapi_hashset_empty(struct cli_bc_ctx *ctx , int32_t); int32_t cli_bcapi_buffer_pipe_new(struct cli_bc_ctx *ctx , uint32_t); int32_t cli_bcapi_buffer_pipe_new_fromfile(struct cli_bc_ctx *ctx , uint32_t); uint32_t cli_bcapi_buffer_pipe_read_avail(struct cli_bc_ctx *ctx , int32_t); -uint8_t* cli_bcapi_buffer_pipe_read_get(struct cli_bc_ctx *ctx , int32_t, uint32_t); +const uint8_t* cli_bcapi_buffer_pipe_read_get(struct cli_bc_ctx *ctx , int32_t, uint32_t); int32_t cli_bcapi_buffer_pipe_read_stopped(struct cli_bc_ctx *ctx , int32_t, uint32_t); uint32_t cli_bcapi_buffer_pipe_write_avail(struct cli_bc_ctx *ctx , int32_t); uint8_t* cli_bcapi_buffer_pipe_write_get(struct cli_bc_ctx *ctx , int32_t, uint32_t); @@ -114,7 +114,7 @@ int32_t cli_bcapi_pdf_get_flags(struct cli_bc_ctx *ctx ); int32_t cli_bcapi_pdf_set_flags(struct cli_bc_ctx *ctx , int32_t); int32_t cli_bcapi_pdf_lookupobj(struct cli_bc_ctx *ctx , uint32_t); uint32_t cli_bcapi_pdf_getobjsize(struct cli_bc_ctx *ctx , int32_t); -uint8_t* cli_bcapi_pdf_getobj(struct cli_bc_ctx *ctx , int32_t, uint32_t); +const uint8_t* cli_bcapi_pdf_getobj(struct cli_bc_ctx *ctx , int32_t, uint32_t); int32_t cli_bcapi_pdf_getobjid(struct cli_bc_ctx *ctx , int32_t); int32_t cli_bcapi_pdf_getobjflags(struct cli_bc_ctx *ctx , int32_t); int32_t cli_bcapi_pdf_setobjflags(struct cli_bc_ctx *ctx , int32_t, int32_t); diff --git a/libclamav/bytecode_api_impl.h b/libclamav/bytecode_api_impl.h index 4c85abdcf..0b2cc8db1 100644 --- a/libclamav/bytecode_api_impl.h +++ b/libclamav/bytecode_api_impl.h @@ -63,7 +63,7 @@ int32_t cli_bcapi_hashset_empty(struct cli_bc_ctx *ctx , int32_t); int32_t cli_bcapi_buffer_pipe_new(struct cli_bc_ctx *ctx , uint32_t); int32_t cli_bcapi_buffer_pipe_new_fromfile(struct cli_bc_ctx *ctx , uint32_t); uint32_t cli_bcapi_buffer_pipe_read_avail(struct cli_bc_ctx *ctx , int32_t); -uint8_t* cli_bcapi_buffer_pipe_read_get(struct cli_bc_ctx *ctx , int32_t, uint32_t); +const uint8_t* cli_bcapi_buffer_pipe_read_get(struct cli_bc_ctx *ctx , int32_t, uint32_t); int32_t cli_bcapi_buffer_pipe_read_stopped(struct cli_bc_ctx *ctx , int32_t, uint32_t); uint32_t cli_bcapi_buffer_pipe_write_avail(struct cli_bc_ctx *ctx , int32_t); uint8_t* cli_bcapi_buffer_pipe_write_get(struct cli_bc_ctx *ctx , int32_t, uint32_t); @@ -112,7 +112,7 @@ int32_t cli_bcapi_pdf_get_flags(struct cli_bc_ctx *ctx ); int32_t cli_bcapi_pdf_set_flags(struct cli_bc_ctx *ctx , int32_t); int32_t cli_bcapi_pdf_lookupobj(struct cli_bc_ctx *ctx , uint32_t); uint32_t cli_bcapi_pdf_getobjsize(struct cli_bc_ctx *ctx , int32_t); -uint8_t* cli_bcapi_pdf_getobj(struct cli_bc_ctx *ctx , int32_t, uint32_t); +const uint8_t* cli_bcapi_pdf_getobj(struct cli_bc_ctx *ctx , int32_t, uint32_t); int32_t cli_bcapi_pdf_getobjid(struct cli_bc_ctx *ctx , int32_t); int32_t cli_bcapi_pdf_getobjflags(struct cli_bc_ctx *ctx , int32_t); int32_t cli_bcapi_pdf_setobjflags(struct cli_bc_ctx *ctx , int32_t, int32_t); diff --git a/libclamav/cab.c b/libclamav/cab.c index 73b92597d..a9f0b2ad3 100644 --- a/libclamav/cab.c +++ b/libclamav/cab.c @@ -95,7 +95,8 @@ struct cab_block_hdr static char *cab_readstr(fmap_t *map, off_t *offset, int *ret) { int i; - char *str, *retstr; + const char *str; + char *retstr; if(!(str = fmap_need_offstr(map, *offset, 256))) { *ret = CL_EFORMAT; @@ -181,8 +182,8 @@ int cab_open(fmap_t *map, off_t offset, struct cab_archive *cab) unsigned int i, folders = 0; struct cab_file *file, *lfile = NULL; struct cab_folder *folder, *lfolder = NULL; - struct cab_hdr *hdr; - struct cab_hdr_opt *hdr_opt; + const struct cab_hdr *hdr; + const struct cab_hdr_opt *hdr_opt; uint16_t fidx; uint32_t coffFiles; char *pt; @@ -305,7 +306,7 @@ int cab_open(fmap_t *map, off_t offset, struct cab_archive *cab) /* folders */ for(i = 0; i < cab->nfolders; i++) { - struct cab_folder_hdr *folder_hdr; + const struct cab_folder_hdr *folder_hdr; if(!(folder_hdr = fmap_need_off_once(map, cur_offset, sizeof(*folder_hdr)))) { cli_dbgmsg("cab_open: Can't read header for folder %u\n", i); @@ -360,7 +361,7 @@ int cab_open(fmap_t *map, off_t offset, struct cab_archive *cab) cur_offset = coffFiles; } for(i = 0; i < cab->nfiles; i++) { - struct cab_file_hdr *file_hdr; + const struct cab_file_hdr *file_hdr; if(!(file_hdr = fmap_need_off_once(map, cur_offset, sizeof(*file_hdr)))) { cli_dbgmsg("cab_open: Can't read file %u header\n", i); @@ -379,8 +380,8 @@ int cab_open(fmap_t *map, off_t offset, struct cab_archive *cab) cab->map = map; file->offset = EC32(file_hdr->uoffFolderStart); file->length = EC32(file_hdr->cbFile); - file->attribs = EC32(file_hdr->attribs); - fidx = EC32(file_hdr->iFolder); + file->attribs = EC16(file_hdr->attribs); + fidx = EC16(file_hdr->iFolder); file->error = CL_SUCCESS; file->name = cab_readstr(map, &cur_offset, &ret); @@ -449,7 +450,7 @@ int cab_open(fmap_t *map, off_t offset, struct cab_archive *cab) static int cab_read_block(struct cab_file *file) { - struct cab_block_hdr *block_hdr; + const struct cab_block_hdr *block_hdr; struct cab_state *state = file->cab->state; if(!(block_hdr = fmap_need_off_once(file->cab->map, file->cab->cur_offset, sizeof(*block_hdr)))) { diff --git a/libclamav/cache.c b/libclamav/cache.c index 3e947fca5..60e242d82 100644 --- a/libclamav/cache.c +++ b/libclamav/cache.c @@ -703,7 +703,7 @@ int cache_check(unsigned char *hash, cli_ctx *ctx) { cli_md5_init(&md5); while(todo) { - void *buf; + const void *buf; size_t readme = todo < FILEBUFF ? todo : FILEBUFF; if(!(buf = fmap_need_off_once(map, at, readme))) return CL_VIRUS; diff --git a/libclamav/chmunpack.c b/libclamav/chmunpack.c index 511276b8b..6b071d2e8 100644 --- a/libclamav/chmunpack.c +++ b/libclamav/chmunpack.c @@ -105,7 +105,7 @@ typedef struct lzx_content_tag { /* Read in a block of data from either the mmap area or the given fd */ static int chm_read_data(fmap_t *map, char *dest, off_t offset, off_t len) { - void *src = fmap_need_off_once(map, offset, len); + const void *src = fmap_need_off_once(map, offset, len); if(!src) return FALSE; memcpy(dest, src, len); return TRUE; @@ -233,10 +233,10 @@ static int itsp_read_header(chm_metadata_t *metadata, off_t offset) return TRUE; } -static uint64_t read_enc_int(char **start, char *end) +static uint64_t read_enc_int(const char **start, const char *end) { uint64_t retval=0; - char *current; + const char *current; current = *start; @@ -258,7 +258,7 @@ static uint64_t read_enc_int(char **start, char *end) /* Read control entries */ static int read_control_entries(chm_metadata_t *metadata) { - char *name; + const char *name; uint64_t name_len, section, offset, length; while (metadata->chunk_entries--) { diff --git a/libclamav/chmunpack.h b/libclamav/chmunpack.h index f0bffd592..7864386b9 100644 --- a/libclamav/chmunpack.h +++ b/libclamav/chmunpack.h @@ -108,9 +108,9 @@ typedef struct chm_metadata_tag { int ofd; uint32_t num_chunks; off_t chunk_offset; - char *chunk_data; - char *chunk_current; - char *chunk_end; + const char *chunk_data; + const char *chunk_current; + const char *chunk_end; fmap_t *map; uint16_t chunk_entries; } chm_metadata_t; diff --git a/libclamav/crtmgr.c b/libclamav/crtmgr.c index c572e9f03..93bf4235b 100644 --- a/libclamav/crtmgr.c +++ b/libclamav/crtmgr.c @@ -25,8 +25,6 @@ #include "crtmgr.h" #include "others.h" -/* TODO split certs into verified and tbs */ - int cli_crt_init(cli_crt *x509) { int ret; if((ret = mp_init_multi(&x509->n, &x509->e, &x509->sig, NULL))) { diff --git a/libclamav/filetypes.c b/libclamav/filetypes.c index 019d1dd86..ebe157d29 100644 --- a/libclamav/filetypes.c +++ b/libclamav/filetypes.c @@ -155,11 +155,12 @@ cli_file_t cli_filetype(const unsigned char *buf, size_t buflen, const struct cl return cli_texttype(buf, buflen); } -int is_tar(unsigned char *buf, unsigned int nbytes); +int is_tar(const unsigned char *buf, unsigned int nbytes); cli_file_t cli_filetype2(fmap_t *map, const struct cl_engine *engine) { - unsigned char *buff, *decoded; + const unsigned char *buff; + unsigned char *decoded; int bread = MIN(map->len, MAGIC_BUFFER_SIZE), sret; cli_file_t ret = CL_TYPE_BINARY_DATA; struct cli_matcher *root; diff --git a/libclamav/fmap.h b/libclamav/fmap.h index 761e7f80a..83235caa0 100644 --- a/libclamav/fmap.h +++ b/libclamav/fmap.h @@ -107,12 +107,12 @@ static inline size_t fmap_ptr2off(const fmap_t *m, const void *ptr) :(const char*)ptr - (const char*)m - m->hdrsz; } -static inline const void *fmap_need_ptr(fmap_t *m, void *ptr, size_t len) +static inline const void *fmap_need_ptr(fmap_t *m, const void *ptr, size_t len) { return m->need(m, fmap_ptr2off(m, ptr), len, 1); } -static inline const void *fmap_need_ptr_once(fmap_t *m, void *ptr, size_t len) +static inline const void *fmap_need_ptr_once(fmap_t *m, const void *ptr, size_t len) { return m->need(m, fmap_ptr2off(m, ptr), len, 0); } @@ -122,7 +122,7 @@ static inline void fmap_unneed_off(fmap_t *m, size_t at, size_t len) m->unneed_off(m, at, len); } -static inline void fmap_unneed_ptr(fmap_t *m, void *ptr, size_t len) +static inline void fmap_unneed_ptr(fmap_t *m, const void *ptr, size_t len) { fmap_unneed_off(m, fmap_ptr2off(m, ptr), len); } @@ -144,7 +144,7 @@ static inline int fmap_readn(fmap_t *m, void *dst, size_t at, size_t len) return len; } -static inline const void *fmap_need_str(fmap_t *m, void *ptr, size_t len_hint) +static inline const void *fmap_need_str(fmap_t *m, const void *ptr, size_t len_hint) { return m->need_offstr(m, fmap_ptr2off(m, ptr), len_hint); } diff --git a/libclamav/fsg.c b/libclamav/fsg.c index 87735a9a9..eba0e46ae 100644 --- a/libclamav/fsg.c +++ b/libclamav/fsg.c @@ -46,7 +46,7 @@ #include "packlibs.h" #include "fsg.h" -int unfsg_200(char *source, char *dest, int ssize, int dsize, uint32_t rva, uint32_t base, uint32_t ep, int file) { +int unfsg_200(const char *source, char *dest, int ssize, int dsize, uint32_t rva, uint32_t base, uint32_t ep, int file) { struct cli_exe_section section; /* Yup, just one ;) */ if ( cli_unfsg(source, dest, ssize, dsize, NULL, NULL) ) return -1; @@ -64,8 +64,9 @@ int unfsg_200(char *source, char *dest, int ssize, int dsize, uint32_t rva, uint } -int unfsg_133(char *source, char *dest, int ssize, int dsize, struct cli_exe_section *sections, int sectcount, uint32_t base, uint32_t ep, int file) { - char *tsrc=source, *tdst=dest; +int unfsg_133(const char *source, char *dest, int ssize, int dsize, struct cli_exe_section *sections, int sectcount, uint32_t base, uint32_t ep, int file) { + const char *tsrc=source; + char *tdst=dest; int i, upd=1, offs=0, lastsz=dsize; for (i = 0 ; i <= sectcount ; i++) { diff --git a/libclamav/fsg.h b/libclamav/fsg.h index b64d40d42..fd9fd2682 100644 --- a/libclamav/fsg.h +++ b/libclamav/fsg.h @@ -24,8 +24,8 @@ #include "cltypes.h" #include "execs.h" -int unfsg_200(char *, char *, int, int, uint32_t, uint32_t, uint32_t, int); -int unfsg_133(char *, char *, int , int, struct cli_exe_section *, int, uint32_t, uint32_t, int); +int unfsg_200(const char *, char *, int, int, uint32_t, uint32_t, uint32_t, int); +int unfsg_133(const char *, char *, int , int, struct cli_exe_section *, int, uint32_t, uint32_t, int); #endif diff --git a/libclamav/is_tar.c b/libclamav/is_tar.c index d696a7053..56d52fef4 100644 --- a/libclamav/is_tar.c +++ b/libclamav/is_tar.c @@ -32,7 +32,7 @@ static int from_oct(int digs, char *where); * 1 for old UNIX tar file, * 2 for Unix Std (POSIX) tar file. */ -int is_tar(unsigned char *buf, unsigned int nbytes) +int is_tar(const unsigned char *buf, unsigned int nbytes) { union record *header = (union record *)buf; int i; diff --git a/libclamav/is_tar.h b/libclamav/is_tar.h index 236362607..2a8f99f07 100644 --- a/libclamav/is_tar.h +++ b/libclamav/is_tar.h @@ -44,4 +44,4 @@ union record { /* The magic field is filled with this if uname and gname are valid. */ #define TMAGIC "ustar " /* 7 chars and a null */ -int is_tar(unsigned char *buf, unsigned int nbytes); +int is_tar(const unsigned char *buf, unsigned int nbytes); diff --git a/libclamav/ishield.c b/libclamav/ishield.c index ca4060f76..bf463fa27 100644 --- a/libclamav/ishield.c +++ b/libclamav/ishield.c @@ -193,7 +193,7 @@ static const uint8_t skey[] = { 0xec, 0xca, 0x79, 0xf8 }; /* ~0x13, ~0x35, ~0x86 /* Extracts the content of MSI based IS */ int cli_scanishield_msi(cli_ctx *ctx, off_t off) { - uint8_t *buf; + const uint8_t *buf; unsigned int fcount, scanned = 0; int ret; fmap_t *map = *ctx->fmap; @@ -337,7 +337,8 @@ static int is_extract_cab(cli_ctx *ctx, uint64_t off, uint64_t size, uint64_t cs /* Extract the content of older (non-MSI) IS */ int cli_scanishield(cli_ctx *ctx, off_t off, size_t sz) { - char *fname, *path, *version, *strsz, *eostr, *data; + const char *fname, *path, *version, *strsz, *data; + char *eostr; int ret = CL_CLEAN; long fsize; off_t coff = off; @@ -436,7 +437,8 @@ int cli_scanishield(cli_ctx *ctx, off_t off, size_t sz) { /* Utility func to scan a fd @ a given offset and size */ static int is_dump_and_scan(cli_ctx *ctx, off_t off, size_t fsize) { - char *fname, *buf; + char *fname; + const char *buf; int ofd, ret = CL_CLEAN; fmap_t *map = *ctx->fmap; @@ -486,7 +488,7 @@ static int is_parse_hdr(cli_ctx *ctx, struct IS_CABSTUFF *c) { char hash[33], *hdr; fmap_t *map = *ctx->fmap; - struct IS_HDR *h1; + const struct IS_HDR *h1; struct IS_OBJECTS *objs; /* struct IS_INSTTYPEHDR *typehdr; -- UNUSED */ @@ -675,7 +677,8 @@ static void md5str(uint8_t *sum) { #define IS_CABBUFSZ 65536 static int is_extract_cab(cli_ctx *ctx, uint64_t off, uint64_t size, uint64_t csize) { - uint8_t *inbuf, *outbuf; + const uint8_t *inbuf; + uint8_t *outbuf; char *tempfile; int ofd, ret = CL_CLEAN; z_stream z; diff --git a/libclamav/iso9660.c b/libclamav/iso9660.c index 0a5bc0b44..650ffbe51 100644 --- a/libclamav/iso9660.c +++ b/libclamav/iso9660.c @@ -37,7 +37,7 @@ typedef struct { } iso9660_t; -static void *needblock(const iso9660_t *iso, unsigned int block, int temp) { +static const void *needblock(const iso9660_t *iso, unsigned int block, int temp) { cli_ctx *ctx = iso->ctx; size_t loff; unsigned int blocks_per_sect = (2048 / iso->blocksz); @@ -59,7 +59,7 @@ static int iso_scan_file(const iso9660_t *iso, unsigned int block, unsigned int cli_dbgmsg("iso_scan_file: dumping to %s\n", tmpf); while(len) { - void *buf = needblock(iso, block, 1); + const void *buf = needblock(iso, block, 1); unsigned int todo = MIN(len, iso->blocksz); if(cli_writen(fd, buf, todo) != todo) { close(fd); @@ -88,7 +88,7 @@ static int iso_scan_file(const iso9660_t *iso, unsigned int block, unsigned int return ret; } -static char *iso_string(iso9660_t *iso, void *src, unsigned int len) { +static char *iso_string(iso9660_t *iso, const void *src, unsigned int len) { if(iso->joliet) { char *utf8; if(len > sizeof(iso->buf)) @@ -120,7 +120,7 @@ static int iso_parse_dir(iso9660_t *iso, unsigned int block, unsigned int len) { } for(; len && ret == CL_CLEAN; block++, len -= MIN(len, iso->blocksz)) { - uint8_t *dir, *dir_orig; + const uint8_t *dir, *dir_orig; unsigned int dirsz; if(iso->dir_blocks.count > 1024) { @@ -205,7 +205,7 @@ static int iso_parse_dir(iso9660_t *iso, unsigned int block, unsigned int len) { } int cli_scaniso(cli_ctx *ctx, size_t offset) { - uint8_t *privol, *next; + const uint8_t *privol, *next; iso9660_t iso; int i; diff --git a/libclamav/matcher.c b/libclamav/matcher.c index 1578b09bc..75db33d72 100644 --- a/libclamav/matcher.c +++ b/libclamav/matcher.c @@ -396,7 +396,7 @@ int cli_checkfp(unsigned char *digest, size_t size, cli_ctx *ctx) SHA1Context sha1; SHA256_CTX sha256; fmap_t *map; - char *ptr; + const char *ptr; uint8_t shash1[SHA1_HASH_SIZE*2+1]; uint8_t shash256[SHA256_HASH_SIZE*2+1]; int have_sha1, have_sha256; @@ -610,7 +610,7 @@ int cli_lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *ac int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, unsigned char *refhash) { - unsigned char *buff; + const unsigned char *buff; int ret = CL_CLEAN, type = CL_CLEAN, bytes, compute_hash[CLI_HASH_AVAIL_TYPES]; unsigned int i = 0, bm_offmode = 0; uint32_t maxpatlen, offset = 0; @@ -760,7 +760,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli } if(hdb) { - void *data = buff + maxpatlen * (offset!=0); + const void *data = buff + maxpatlen * (offset!=0); uint32_t data_len = bytes - maxpatlen * (offset!=0); if(compute_hash[CLI_HASH_MD5]) diff --git a/libclamav/mbox.c b/libclamav/mbox.c index 0fb7d7d01..6ac670368 100644 --- a/libclamav/mbox.c +++ b/libclamav/mbox.c @@ -656,7 +656,7 @@ parseEmailFile(fmap_t *map, size_t *at, const table_t *rfc821, const char *first bodyIsEmpty = TRUE; } else { char *ptr; - char *lookahead; + const char *lookahead; if(fullline == NULL) { char cmd[RFC2821LENGTH + 1], out[RFC2821LENGTH + 1]; @@ -3212,7 +3212,8 @@ usefulHeader(int commandNumber, const char *cmd) static char * getline_from_mbox(char *buffer, size_t buffer_len, fmap_t *map, size_t *at) { - char *src, *cursrc, *curbuf; + const char *src, *cursrc; + char *curbuf; size_t i; size_t input_len = MIN(map->len - *at, buffer_len + 1); src = cursrc = fmap_need_off_once(map, *at, input_len); diff --git a/libclamav/mew.c b/libclamav/mew.c index b029a797e..60cf7e290 100644 --- a/libclamav/mew.c +++ b/libclamav/mew.c @@ -64,7 +64,7 @@ /* northfox does this shitty way, * this should be done with just a bswap */ -static char *lzma_bswap_4861dc(struct lzmastate *p, char *old_edx) +static const char *lzma_bswap_4861dc(struct lzmastate *p, const char *old_edx) { /* dumb_dump_start * @@ -99,7 +99,7 @@ static char *lzma_bswap_4861dc(struct lzmastate *p, char *old_edx) return p->p0; } -static uint32_t lzma_486248 (struct lzmastate *p, char **old_ecx, char *src, uint32_t size) +static uint32_t lzma_486248 (struct lzmastate *p,const char **old_ecx, char *src, uint32_t size) { uint32_t loc_esi, loc_edi, loc_eax, loc_ecx, ret; if (!CLI_ISCONTAINED(src, size, *old_ecx, 4) || !CLI_ISCONTAINED(src, size, p->p0, 1)) @@ -152,11 +152,11 @@ static uint32_t lzma_486248 (struct lzmastate *p, char **old_ecx, char *src, uin } -static uint32_t lzma_48635C(uint8_t znaczek, char **old_ecx, struct lzmastate *p, uint32_t *retval, char *src, uint32_t size) +static uint32_t lzma_48635C(uint8_t znaczek, const char **old_ecx, struct lzmastate *p, uint32_t *retval, char *src, uint32_t size) { uint32_t loc_esi = (znaczek&0xff) >> 7, /* msb */ loc_ebx, ret; - char *loc_edi; + const char *loc_edi; znaczek <<= 1; ret = loc_esi << 9; loc_edi = *old_ecx; @@ -196,10 +196,10 @@ static uint32_t lzma_48635C(uint8_t znaczek, char **old_ecx, struct lzmastate *p return 0; } -static uint32_t lzma_4862e0 (struct lzmastate *p, char **old_ecx, uint32_t *old_edx, uint32_t *retval, char *src, uint32_t size) +static uint32_t lzma_4862e0 (struct lzmastate *p, const char **old_ecx, uint32_t *old_edx, uint32_t *retval, char *src, uint32_t size) { uint32_t loc_ebx, loc_esi, stack_ecx, ret; - char *loc_edi; + const char *loc_edi; loc_ebx = *old_edx; ret = 1; @@ -229,10 +229,10 @@ static uint32_t lzma_4862e0 (struct lzmastate *p, char **old_ecx, uint32_t *old_ } /* old_edx - write only */ -static uint32_t lzma_4863da (uint32_t var0, struct lzmastate *p, char **old_ecx, uint32_t *old_edx, uint32_t *retval, char *src, uint32_t size) +static uint32_t lzma_4863da (uint32_t var0, struct lzmastate *p, const char **old_ecx, uint32_t *old_edx, uint32_t *retval, char *src, uint32_t size) { uint32_t ret; - char *loc_esi = *old_ecx; + const char *loc_esi = *old_ecx; if ((ret = lzma_486248 (p, old_ecx, src, size)) == 0xffffffff) return -1; @@ -274,7 +274,7 @@ static uint32_t lzma_4863da (uint32_t var0, struct lzmastate *p, char **old_ecx static uint32_t lzma_486204 (struct lzmastate *p, uint32_t old_edx, uint32_t *retval, char *src, uint32_t size) { uint32_t loc_esi, loc_edi, loc_ebx, loc_eax; - char *loc_edx; + const char *loc_edx; loc_esi = p->p1; loc_edi = p->p2; loc_eax = 0; @@ -311,11 +311,11 @@ static uint32_t lzma_486204 (struct lzmastate *p, uint32_t old_edx, uint32_t *re return 0; } -static uint32_t lzma_48631a (struct lzmastate *p, char **old_ecx, uint32_t *old_edx, uint32_t *retval, char *src, uint32_t size) +static uint32_t lzma_48631a (struct lzmastate *p, const char **old_ecx, uint32_t *old_edx, uint32_t *retval, char *src, uint32_t size) { uint32_t copy1, copy2; uint32_t loc_esi, loc_edi, ret; - char *loc_ebx; + const char *loc_ebx; copy1 = *old_edx; loc_edi = 0; @@ -347,7 +347,7 @@ static uint32_t lzma_48631a (struct lzmastate *p, char **old_ecx, uint32_t *old_ } -int mew_lzma(char *orgsource, char *buf, uint32_t size_sum, uint32_t vma, uint32_t special) +int mew_lzma(char *orgsource, const char *buf, uint32_t size_sum, uint32_t vma, uint32_t special) { uint32_t var08, var0C, var10, var14, var20, var24, var28, var34; struct lzmastate var40; @@ -355,8 +355,12 @@ int mew_lzma(char *orgsource, char *buf, uint32_t size_sum, uint32_t vma, uint32 int i, mainloop; char var1, var30; - char *source = buf, *dest, *new_ebx, *new_ecx, *var0C_ecxcopy, *var2C; - char *pushed_esi = NULL, *pushed_ebx = NULL; + const char *source = buf; + char *dest, *new_ebx; + const char *new_ecx, *var0C_ecxcopy; + const char *var2C; + char *pushed_esi = NULL; + const char *pushed_ebx = NULL; uint32_t pushed_edx=0; uint32_t loc_esi, loc_edi; @@ -774,8 +778,10 @@ int unmew11(char *src, int off, int ssize, int dsize, uint32_t base, uint32_t va { uint32_t entry_point, newedi, loc_ds=dsize, loc_ss=ssize; char *source = src + dsize + off; - char *lesi = source + 12, *ledi; - char *f1, *f2; + const char *lesi = source + 12; + char *ledi; + const char *f1; + char *f2; int i; struct cli_exe_section *section = NULL; uint32_t vma = base + vadd, size_sum = ssize + dsize; diff --git a/libclamav/mew.h b/libclamav/mew.h index 7f86b38a8..51ae3d77e 100644 --- a/libclamav/mew.h +++ b/libclamav/mew.h @@ -28,11 +28,11 @@ #include "cltypes.h" struct lzmastate { - char *p0; + const char *p0; uint32_t p1, p2; }; -int mew_lzma(char *, char *, uint32_t, uint32_t, uint32_t); +int mew_lzma(char *, const char *, uint32_t, uint32_t, uint32_t); uint32_t lzma_upack_esi_00(struct lzmastate *, char *, char *, uint32_t); uint32_t lzma_upack_esi_50(struct lzmastate *, uint32_t, uint32_t, char **, char *, uint32_t *, char *, uint32_t); diff --git a/libclamav/msexpand.c b/libclamav/msexpand.c index ccb204999..3b7ef8f3c 100644 --- a/libclamav/msexpand.c +++ b/libclamav/msexpand.c @@ -94,7 +94,7 @@ struct msexp_hdr { int cli_msexpand(cli_ctx *ctx, int ofd) { - struct msexp_hdr *hdr; + const struct msexp_hdr *hdr; uint8_t i, mask, bits; unsigned char buff[B_SIZE], wbuff[RW_SIZE]; const unsigned char *rbuff; diff --git a/libclamav/nsis/nulsft.c b/libclamav/nsis/nulsft.c index b416f5381..2be03f679 100644 --- a/libclamav/nsis/nulsft.c +++ b/libclamav/nsis/nulsft.c @@ -70,7 +70,7 @@ struct nsis_st { struct CLI_LZMA lz; /* z_stream z; */ nsis_z_stream z; - unsigned char *freeme; + const unsigned char *freeme; fmap_t *map; char ofn[1024]; }; @@ -183,7 +183,7 @@ static int nsis_decomp(struct nsis_st *n) { } static int nsis_unpack_next(struct nsis_st *n, cli_ctx *ctx) { - unsigned char *ibuf; + const unsigned char *ibuf; uint32_t size, loops; int ret, gotsome=0; unsigned char obuf[BUFSIZ]; @@ -258,7 +258,7 @@ static int nsis_unpack_next(struct nsis_st *n, cli_ctx *ctx) { } n->nsis.avail_in = size; - n->nsis.next_in = ibuf; + n->nsis.next_in = (void*)ibuf; n->nsis.next_out = obuf; n->nsis.avail_out = BUFSIZ; loops=0; @@ -325,7 +325,7 @@ static int nsis_unpack_next(struct nsis_st *n, cli_ctx *ctx) { close(n->ofd); return CL_EREAD; } - n->nsis.next_in = n->freeme; + n->nsis.next_in = (void*)n->freeme; n->nsis.avail_in = n->asz; } diff --git a/libclamav/ole2_extract.c b/libclamav/ole2_extract.c index c60ac921d..b10c324f0 100644 --- a/libclamav/ole2_extract.c +++ b/libclamav/ole2_extract.c @@ -276,7 +276,7 @@ static void print_ole2_header(ole2_header_t *hdr) static int ole2_read_block(ole2_header_t *hdr, void *buff, unsigned int size, int32_t blockno) { off_t offset, offend; - void *pblock; + const void *pblock; if (blockno < 0) { return FALSE; @@ -872,7 +872,7 @@ int cli_ole2_extract(const char *dirname, cli_ctx *ctx, struct uniq **vba) int hdr_size, ret=CL_CLEAN; unsigned int file_count=0; unsigned long scansize, scansize2; - void *phdr; + const void *phdr; cli_dbgmsg("in cli_ole2_extract()\n"); diff --git a/libclamav/packlibs.c b/libclamav/packlibs.c index adfcbbb3f..f5aaa30e5 100644 --- a/libclamav/packlibs.c +++ b/libclamav/packlibs.c @@ -27,7 +27,7 @@ #include "pe.h" #include "packlibs.h" -static int doubledl(char **scur, uint8_t *mydlptr, char *buffer, uint32_t buffersize) +static int doubledl(const char **scur, uint8_t *mydlptr, const char *buffer, uint32_t buffersize) { unsigned char mydl = *mydlptr; unsigned char olddl = mydl; @@ -45,10 +45,11 @@ static int doubledl(char **scur, uint8_t *mydlptr, char *buffer, uint32_t buffer } -int cli_unfsg(char *source, char *dest, int ssize, int dsize, char **endsrc, char **enddst) { +int cli_unfsg(const char *source, char *dest, int ssize, int dsize, const char **endsrc, char **enddst) { uint8_t mydl=0x80; uint32_t backbytes, backsize, oldback = 0; - char *csrc = source, *cdst = dest; + const char *csrc = source; + char *cdst = dest; int oob, lostbit = 1; if (ssize<=0 || dsize<=0) return -1; @@ -170,10 +171,11 @@ int cli_unfsg(char *source, char *dest, int ssize, int dsize, char **endsrc, cha return 0; } -int unmew(char *source, char *dest, int ssize, int dsize, char **endsrc, char **enddst) { +int unmew(const char *source, char *dest, int ssize, int dsize, const char **endsrc, char **enddst) { uint8_t mydl=0x80; uint32_t myeax_backbytes, myecx_backsize, oldback = 0; - char *csrc = source, *cdst = dest; + const char *csrc = source; + char *cdst = dest; int oob, lostbit = 1; *cdst++=*csrc++; diff --git a/libclamav/packlibs.h b/libclamav/packlibs.h index 9ed1b4846..5962e4663 100644 --- a/libclamav/packlibs.h +++ b/libclamav/packlibs.h @@ -28,8 +28,8 @@ #include "cltypes.h" #include "rebuildpe.h" -int cli_unfsg(char *, char *, int, int, char **, char **); +int cli_unfsg(const char *, char *, int, int, const char **, char **); -int unmew(char *, char *, int, int, char **, char **); +int unmew(const char *, char *, int, int, const char **, char **); #endif diff --git a/libclamav/pe.c b/libclamav/pe.c index 5fda2baaf..2f5eea027 100644 --- a/libclamav/pe.c +++ b/libclamav/pe.c @@ -58,8 +58,6 @@ #include "disasm.h" #include "special.h" #include "ishield.h" -#include "sha1.h" -#include "asn1.h" #define DCONF ctx->dconf->pe @@ -72,11 +70,6 @@ #define optional_hdr64 pe_opt.opt64 #define optional_hdr32 pe_opt.opt32 -typedef union { - struct pe_image_optional_hdr64 opt64; - struct pe_image_optional_hdr32 opt32; -} pe_opt_t; - #define UPX_NRV2B "\x11\xdb\x11\xc9\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9\x11\xc9\x75\x20\x41\x01\xdb" #define UPX_NRV2D "\x83\xf0\xff\x74\x78\xd1\xf8\x89\xc5\xeb\x0b\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9" #define UPX_NRV2E "\xeb\x52\x31\xc9\x83\xe8\x03\x72\x11\xc1\xe0\x08\x8a\x06\x46\x83\xf0\xff\x74\x75\xd1\xf8\x89\xc5" @@ -90,7 +83,8 @@ typedef union { #define PESALIGN(o,a) (((a))?(((o)/(a)+((o)%(a)!=0))*(a)):(o)) #define CLI_UNPSIZELIMITS(NAME,CHK) \ -if(cli_checklimits(NAME, ctx, (CHK), 0, 0)!=CL_CLEAN) { \ +if(cli_checklimits(NAME, ctx, (CHK), 0, 0)!=CL_CLEAN) { \ + free(exe_sections); \ return CL_CLEAN; \ } @@ -126,6 +120,7 @@ if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) { \ cli_dbgmsg(NAME": Successfully decompressed\n"); \ close(ndesc); \ if (cli_unlink(tempfile)) { \ + free(exe_sections); \ free(tempfile); \ FREESEC; \ return CL_EUNLINK; \ @@ -141,6 +136,7 @@ if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) { \ free(spinned); \ close(ndesc); \ if (cli_unlink(tempfile)) { \ + free(exe_sections); \ free(tempfile); \ return CL_EUNLINK; \ } \ @@ -156,6 +152,7 @@ if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) { \ else \ cli_dbgmsg(NAME": Unpacked and rebuilt executable\n"); \ cli_multifree FREEME; \ + free(exe_sections); \ lseek(ndesc, 0, SEEK_SET); \ cli_dbgmsg("***** Scanning rebuilt PE file *****\n"); \ SHA_OFF; \ @@ -178,6 +175,7 @@ FSGSTUFF; \ cli_dbgmsg(NAME": Unpacking failed\n"); \ close(ndesc); \ if (cli_unlink(tempfile)) { \ + free(exe_sections); \ free(tempfile); \ cli_multifree FREEME; \ return CL_EUNLINK; \ @@ -327,7 +325,7 @@ static int cli_ddump(int desc, int offset, int size, const char *file) { 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) { unsigned int err = 0; uint32_t type, type_offs, name, name_offs, lang, lang_offs; - uint8_t *resdir, *type_entry, *name_entry, *lang_entry ; + const uint8_t *resdir, *type_entry, *name_entry, *lang_entry ; uint16_t type_cnt, name_cnt, lang_cnt; if (!(resdir = fmap_need_off_once(map, cli_rawaddr(res_rva, exe_sections, nsections, &err, map->len, hdr_size), 16)) || err) @@ -391,7 +389,7 @@ void findres(uint32_t by_type, uint32_t by_name, uint32_t res_rva, fmap_t *map, } static unsigned int cli_md5sect(fmap_t *map, struct cli_exe_section *s, unsigned char *digest) { - void *hashme; + const void *hashme; cli_md5_ctx md5; if (s->rsz > CLI_MAX_ALLOCATION) { @@ -413,8 +411,8 @@ static unsigned int cli_md5sect(fmap_t *map, struct cli_exe_section *s, unsigned 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) { unsigned int err = 0, i; - uint8_t *resdir; - uint8_t *entry, *oentry; + const uint8_t *resdir; + const uint8_t *entry, *oentry; uint16_t named, unnamed; uint32_t rawaddr = cli_rawaddr(rva, exe_sections, nsections, &err, fsize, hdr_size); uint32_t entries; @@ -483,7 +481,7 @@ static void cli_parseres_special(uint32_t base, uint32_t rva, fmap_t *map, struc rawaddr = cli_rawaddr(base + offs, exe_sections, nsections, &err, fsize, hdr_size); if (!err && (resdir = fmap_need_off_once(map, rawaddr, 16))) { uint32_t isz = cli_readint32(resdir+4); - uint8_t *str; + const uint8_t *str; rawaddr = cli_rawaddr(cli_readint32(resdir), exe_sections, nsections, &err, fsize, hdr_size); if (err || !isz || isz >= fsize || rawaddr+isz >= fsize) { cli_dbgmsg("cli_parseres_special: invalid resource table entry: %lu + %lu\n", @@ -502,1563 +500,42 @@ static void cli_parseres_special(uint32_t base, uint32_t rva, fmap_t *map, struc fmap_unneed_ptr(map, oentry, entries*8); } -static inline int cli_real_scanpe(cli_ctx *ctx, uint32_t ep, struct cli_exe_section *exe_sections, uint16_t nsections, struct pe_image_file_hdr *file_hdr, uint32_t e_lfanew, struct pe_image_data_dir *dirs, unsigned int overlays, unsigned int polipos, unsigned int dll, uint32_t hdr_size, uint32_t vep, unsigned int min, unsigned int max, pe_opt_t pe_opt) +int cli_scanpe(cli_ctx *ctx) { - char epbuff[4096], *tempfile; + uint16_t e_magic; /* DOS signature ("MZ") */ + uint16_t nsections; + uint32_t e_lfanew; /* address of new exe header */ + uint32_t ep, vep; /* entry point (raw, virtual) */ + uint8_t polipos = 0; + time_t timestamp; + struct pe_image_file_hdr file_hdr; + union { + struct pe_image_optional_hdr64 opt64; + struct pe_image_optional_hdr32 opt32; + } pe_opt; + struct pe_image_section_hdr *section_hdr; + char sname[9], epbuff[4096], *tempfile; uint32_t epsize; - ssize_t bytes; - unsigned int i, found, upx_success = 0, err; - unsigned int ssize = 0, dsize = 0, corrupted_cur; - int (*upxfn)(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t) = NULL; - char *src = NULL, *dest = NULL; - int ndesc, ret = CL_CLEAN, upack = 0; + ssize_t bytes, at; + unsigned int i, found, upx_success = 0, min = 0, max = 0, err, overlays = 0; + unsigned int ssize = 0, dsize = 0, dll = 0, pe_plus = 0, corrupted_cur; + int (*upxfn)(const char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t) = NULL; + const char *src = NULL; + char *dest = NULL; + int ndesc, ret = CL_CLEAN, upack = 0, native=0; + size_t fsize; + uint32_t valign, falign, hdr_size, j; + struct cli_exe_section *exe_sections; + struct cli_matcher *md5_sect; + char timestr[32]; + struct pe_image_data_dir *dirs; struct cli_bc_ctx *bc_ctx; - fmap_t *map = *ctx->fmap; - size_t fsize = map->len; + fmap_t *map; struct cli_pe_hook_data pedata; - - /* FIXME */ #ifdef HAVE__INTERNAL__SHA_COLLECT int sha_collect = ctx->sha_collect; #endif - - if(DCONF & PE_CONF_UPACK) - upack = (EC16(file_hdr->SizeOfOptionalHeader)==0x148); - - epsize = fmap_readn(map, epbuff, ep, 4096); - - - /* Disasm scan disabled since it's now handled by the bytecode */ - - /* CLI_UNPTEMP("DISASM",(exe_sections,0)); */ - /* if(disasmbuf((unsigned char*)epbuff, epsize, ndesc)) */ - /* ret = cli_scandesc(ndesc, ctx, CL_TYPE_PE_DISASM, 1, NULL, AC_SCAN_VIR); */ - /* close(ndesc); */ - /* CLI_TMPUNLK(); */ - /* free(tempfile); */ - /* if(ret == CL_VIRUS) { */ - /* free(exe_sections); */ - /* return ret; */ - /* } */ - - if(overlays) { - int overlays_sz = fsize - overlays; - if(overlays_sz > 0) { - ret = cli_scanishield(ctx, overlays, overlays_sz); - if(ret != CL_CLEAN) - return ret; - } - } - - pedata.nsections = nsections; - pedata.ep = ep; - pedata.offset = 0; - memcpy(&pedata.file_hdr, file_hdr, sizeof(*file_hdr)); - memcpy(&pedata.opt32, &pe_opt.opt32, sizeof(pe_opt.opt32)); - memcpy(&pedata.opt64, &pe_opt.opt64, sizeof(pe_opt.opt64)); - memcpy(&pedata.dirs, dirs, sizeof(pedata.dirs)); - pedata.e_lfanew = e_lfanew; - pedata.overlays = overlays; - pedata.overlays_sz = fsize - overlays; - pedata.hdr_size = hdr_size; - - /* Bytecode BC_PE_ALL hook */ - bc_ctx = cli_bytecode_context_alloc(); - if (!bc_ctx) { - cli_errmsg("cli_scanpe: can't allocate memory for bc_ctx\n"); - return CL_EMEM; - } - cli_bytecode_context_setpe(bc_ctx, &pedata, exe_sections); - cli_bytecode_context_setctx(bc_ctx, ctx); - ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_ALL, map, ctx->virname); - if (ret == CL_VIRUS || ret == CL_BREAK) { - cli_bytecode_context_destroy(bc_ctx); - return ret == CL_VIRUS ? CL_VIRUS : CL_CLEAN; - } - cli_bytecode_context_destroy(bc_ctx); - - /* Attempt to detect some popular polymorphic viruses */ - - /* W32.Parite.B */ - if(SCAN_ALGO && (DCONF & PE_CONF_PARITE) && !dll && epsize == 4096 && ep == exe_sections[nsections - 1].raw) { - const char *pt = cli_memstr(epbuff, 4040, "\x47\x65\x74\x50\x72\x6f\x63\x41\x64\x64\x72\x65\x73\x73\x00", 15); - if(pt) { - pt += 15; - if((((uint32_t)cli_readint32(pt) ^ (uint32_t)cli_readint32(pt + 4)) == 0x505a4f) && (((uint32_t)cli_readint32(pt + 8) ^ (uint32_t)cli_readint32(pt + 12)) == 0xffffb) && (((uint32_t)cli_readint32(pt + 16) ^ (uint32_t)cli_readint32(pt + 20)) == 0xb8)) { - *ctx->virname = "Heuristics.W32.Parite.B"; - return CL_VIRUS; - } - } - } - - /* Kriz */ - if(SCAN_ALGO && (DCONF & PE_CONF_KRIZ) && epsize >= 200 && CLI_ISCONTAINED(exe_sections[nsections - 1].raw, exe_sections[nsections - 1].rsz, ep, 0x0fd2) && epbuff[1]=='\x9c' && epbuff[2]=='\x60') { - enum {KZSTRASH,KZSCDELTA,KZSPDELTA,KZSGETSIZE,KZSXORPRFX,KZSXOR,KZSDDELTA,KZSLOOP,KZSTOP}; - uint8_t kzs[] = {KZSTRASH,KZSCDELTA,KZSPDELTA,KZSGETSIZE,KZSTRASH,KZSXORPRFX,KZSXOR,KZSTRASH,KZSDDELTA,KZSTRASH,KZSLOOP,KZSTOP}; - uint8_t *kzstate = kzs; - uint8_t *kzcode = (uint8_t *)epbuff + 3; - uint8_t kzdptr=0xff, kzdsize=0xff; - int kzlen = 197, kzinitlen=0xffff, kzxorlen=-1; - cli_dbgmsg("in kriz\n"); - - while(*kzstate!=KZSTOP) { - uint8_t op; - if(kzlen<=6) break; - op = *kzcode++; - kzlen--; - switch (*kzstate) { - case KZSTRASH: case KZSGETSIZE: { - int opsz=0; - switch(op) { - case 0x81: - kzcode+=5; - kzlen-=5; - break; - case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbd: case 0xbe: case 0xbf: - if(*kzstate==KZSGETSIZE && cli_readint32(kzcode)==0x0fd2) { - kzinitlen = kzlen-5; - kzdsize=op-0xb8; - kzstate++; - op=4; /* fake the register to avoid breaking out */ - cli_dbgmsg("kriz: using #%d as size counter\n", kzdsize); - } - opsz=4; - case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4d: case 0x4e: case 0x4f: - op&=7; - if(op!=kzdptr && op!=kzdsize) { - kzcode+=opsz; - kzlen-=opsz; - break; - } - default: - kzcode--; - kzlen++; - kzstate++; - } - break; - } - case KZSCDELTA: - if(op==0xe8 && (uint32_t)cli_readint32(kzcode) < 0xff) { - kzlen-=*kzcode+4; - kzcode+=*kzcode+4; - kzstate++; - } else *kzstate=KZSTOP; - break; - case KZSPDELTA: - if((op&0xf8)==0x58 && (kzdptr=op-0x58)!=4) { - kzstate++; - cli_dbgmsg("kriz: using #%d as pointer\n", kzdptr); - } else *kzstate=KZSTOP; - break; - case KZSXORPRFX: - kzstate++; - if(op==0x3e) break; - case KZSXOR: - if (op==0x80 && *kzcode==kzdptr+0xb0) { - kzxorlen=kzlen; - kzcode+=+6; - kzlen-=+6; - kzstate++; - } else *kzstate=KZSTOP; - break; - case KZSDDELTA: - if (op==kzdptr+0x48) kzstate++; - else *kzstate=KZSTOP; - break; - case KZSLOOP: - if (op==kzdsize+0x48 && *kzcode==0x75 && kzlen-(int8_t)kzcode[1]-3<=kzinitlen && kzlen-(int8_t)kzcode[1]>=kzxorlen) { - *ctx->virname = "Heuristics.W32.Kriz"; - return CL_VIRUS; - } - cli_dbgmsg("kriz: loop out of bounds, corrupted sample?\n"); - kzstate++; - } - } - } - - /* W32.Magistr.A/B */ - if(SCAN_ALGO && (DCONF & PE_CONF_MAGISTR) && !dll && (nsections>1) && (exe_sections[nsections - 1].chr & 0x80000000)) { - uint32_t rsize, vsize, dam = 0; - - vsize = exe_sections[nsections - 1].uvsz; - rsize = exe_sections[nsections - 1].rsz; - if(rsize < exe_sections[nsections - 1].ursz) { - rsize = exe_sections[nsections - 1].ursz; - dam = 1; - } - - if(vsize >= 0x612c && rsize >= 0x612c && ((vsize & 0xff) == 0xec)) { - int bw = rsize < 0x7000 ? rsize : 0x7000; - char *tbuff; - - if((tbuff = fmap_need_off_once(map, exe_sections[nsections - 1].raw + rsize - bw, 4096))) { - if(cli_memstr(tbuff, 4091, "\xe8\x2c\x61\x00\x00", 5)) { - *ctx->virname = dam ? "Heuristics.W32.Magistr.A.dam" : "Heuristics.W32.Magistr.A"; - return CL_VIRUS; - } - } - - } else if(rsize >= 0x7000 && vsize >= 0x7000 && ((vsize & 0xff) == 0xed)) { - int bw = rsize < 0x8000 ? rsize : 0x8000; - char *tbuff; - - if((tbuff = fmap_need_off_once(map, exe_sections[nsections - 1].raw + rsize - bw, 4096))) { - if(cli_memstr(tbuff, 4091, "\xe8\x04\x72\x00\x00", 5)) { - *ctx->virname = dam ? "Heuristics.W32.Magistr.B.dam" : "Heuristics.W32.Magistr.B"; - return CL_VIRUS; - } - } - } - } - - /* W32.Polipos.A */ - 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) { - uint32_t jump, jold, *jumps = NULL; - uint8_t *code; - unsigned int xsjs = 0; - - if(exe_sections[0].rsz > CLI_MAX_ALLOCATION) break; - - if(!exe_sections[0].rsz) break; - if(!(code=fmap_need_off_once(map, exe_sections[0].raw, exe_sections[0].rsz))) break; - for(i=0; i 1) continue; - jump = cli_rawaddr(exe_sections[0].rva+i+5+cli_readint32(&code[i+1]), exe_sections, nsections, &err, fsize, hdr_size); - if(err || !CLI_ISCONTAINED(exe_sections[polipos].raw, exe_sections[polipos].rsz, jump, 9)) continue; - if(xsjs % 128 == 0) { - if(xsjs == 1280) break; - if(!(jumps=(uint32_t *)cli_realloc2(jumps, (xsjs+128)*sizeof(uint32_t)))) - return CL_EMEM; - } - for(j=0; jvirname = "Heuristics.W32.Polipos.A"; - free(jumps); - return CL_VIRUS; - } - } - free(jumps); - break; - } - - /* Trojan.Swizzor.Gen */ - if (SCAN_ALGO && (DCONF & PE_CONF_SWIZZOR) && nsections > 1 && fsize > 64*1024 && fsize < 4*1024*1024) { - if(dirs[2].Size) { - struct swizz_stats *stats = cli_calloc(1, sizeof(*stats)); - unsigned int m = 1000; - ret = CL_CLEAN; - - if (!stats) - ret = CL_EMEM; - else { - cli_parseres_special(EC32(dirs[2].VirtualAddress), EC32(dirs[2].VirtualAddress), map, exe_sections, nsections, fsize, hdr_size, 0, 0, &m, stats); - if ((ret = cli_detect_swizz(stats)) == CL_VIRUS) { - *ctx->virname = "Heuristics.Trojan.Swizzor.Gen"; - } - free(stats); - } - if (ret != CL_CLEAN) - return ret; - } - } - - - /* !!!!!!!!!!!!!! PACKERS START HERE !!!!!!!!!!!!!! */ - corrupted_cur = ctx->corrupted_input; - ctx->corrupted_input = 2; /* caller will reset on return */ - - - /* UPX, FSG, MEW support */ - - /* try to find the first section with physical size == 0 */ - found = 0; - if(DCONF & (PE_CONF_UPX | PE_CONF_FSG | PE_CONF_MEW)) { - for(i = 0; i < (unsigned int) nsections - 1; i++) { - if(!exe_sections[i].rsz && exe_sections[i].vsz && exe_sections[i + 1].rsz && exe_sections[i + 1].vsz) { - found = 1; - cli_dbgmsg("UPX/FSG/MEW: empty section found - assuming compression\n"); - break; - } - } - } - - /* MEW support */ - if (found && (DCONF & PE_CONF_MEW) && epsize>=16 && epbuff[0]=='\xe9') { - uint32_t fileoffset; - char *tbuff; - - fileoffset = (vep + cli_readint32(epbuff + 1) + 5); - while (fileoffset == 0x154 || fileoffset == 0x158) { - uint32_t offdiff, uselzma; - - cli_dbgmsg ("MEW: found MEW characteristics %08X + %08X + 5 = %08X\n", - cli_readint32(epbuff + 1), vep, cli_readint32(epbuff + 1) + vep + 5); - - if(!(tbuff = fmap_need_off_once(map, fileoffset, 0xb0))) - break; - if (fileoffset == 0x154) cli_dbgmsg("MEW: Win9x compatibility was set!\n"); - else cli_dbgmsg("MEW: Win9x compatibility was NOT set!\n"); - - if((offdiff = cli_readint32(tbuff+1) - EC32(optional_hdr32.ImageBase)) <= exe_sections[i + 1].rva || offdiff >= exe_sections[i + 1].rva + exe_sections[i + 1].raw - 4) { - cli_dbgmsg("MEW: ESI is not in proper section\n"); - break; - } - offdiff -= exe_sections[i + 1].rva; - - if(!exe_sections[i + 1].rsz) { - cli_dbgmsg("MEW: mew section is empty\n"); - break; - } - ssize = exe_sections[i + 1].vsz; - dsize = exe_sections[i].vsz; - - cli_dbgmsg("MEW: ssize %08x dsize %08x offdiff: %08x\n", ssize, dsize, offdiff); - - CLI_UNPSIZELIMITS("MEW", MAX(ssize, dsize)); - CLI_UNPSIZELIMITS("MEW", MAX(ssize + dsize, exe_sections[i + 1].rsz)); - - if (exe_sections[i + 1].rsz < offdiff + 12 || exe_sections[i + 1].rsz > ssize) { - cli_dbgmsg("MEW: Size mismatch: %08x\n", exe_sections[i + 1].rsz); - break; - } - - /* allocate needed buffer */ - if (!(src = cli_calloc (ssize + dsize, sizeof(char)))) - return CL_EMEM; - - if((bytes = fmap_readn(map, src + dsize, exe_sections[i + 1].raw, exe_sections[i + 1].rsz)) != exe_sections[i + 1].rsz) { - cli_dbgmsg("MEW: Can't read %d bytes [read: %lu]\n", exe_sections[i + 1].rsz, (unsigned long)bytes); - free(src); - return CL_EREAD; - } - cli_dbgmsg("MEW: %u (%08x) bytes read\n", (unsigned int)bytes, (unsigned int)bytes); - - /* count offset to lzma proc, if lzma used, 0xe8 -> call */ - if (tbuff[0x7b] == '\xe8') { - if (!CLI_ISCONTAINED(exe_sections[1].rva, exe_sections[1].vsz, cli_readint32(tbuff + 0x7c) + fileoffset + 0x80, 4)) { - cli_dbgmsg("MEW: lzma proc out of bounds!\n"); - free(src); - break; /* to next unpacker in chain */ - } - uselzma = cli_readint32(tbuff + 0x7c) - (exe_sections[0].rva - fileoffset - 0x80); - } else { - uselzma = 0; - } - - CLI_UNPTEMP("MEW",(src,0)); - CLI_UNPRESULTS("MEW",(unmew11(src, offdiff, ssize, dsize, EC32(optional_hdr32.ImageBase), exe_sections[0].rva, uselzma, ndesc)),1,(src,0)); - break; - } - } - - if(epsize<168) - return CL_CLEAN; - - if (found || upack) { - /* Check EP for UPX vs. FSG vs. Upack */ - - /* Upack 0.39 produces 2 types of executables - * 3 sections: | 2 sections (one empty, I don't chech found if !upack, since it's in OR above): - * mov esi, value | pusha - * lodsd | call $+0x9 - * push eax | - * - * Upack 1.1/1.2 Beta produces [based on 2 samples (sUx) provided by aCaB]: - * 2 sections - * mov esi, value - * loads - * mov edi, eax - * - * Upack unknown [sample 0297729] - * 3 sections - * mov esi, value - * push [esi] - * jmp - * - */ - /* upack 0.39-3s + sample 0151477*/ - while(((upack && nsections == 3) && /* 3 sections */ - (( - epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) > min && /* mov esi */ - epbuff[5] == '\xad' && epbuff[6] == '\x50' /* lodsd; push eax */ - ) - || - /* based on 0297729 sample from aCaB */ - (epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) > min && /* mov esi */ - epbuff[5] == '\xff' && epbuff[6] == '\x36' /* push [esi] */ - ) - )) - || - ((!upack && nsections == 2) && /* 2 sections */ - (( /* upack 0.39-2s */ - epbuff[0] == '\x60' && epbuff[1] == '\xe8' && cli_readint32(epbuff+2) == 0x9 /* pusha; call+9 */ - ) - || - ( /* upack 1.1/1.2, based on 2 samples */ - epbuff[0] == '\xbe' && cli_readint32(epbuff+1) - EC32(optional_hdr32.ImageBase) < min && /* mov esi */ - cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) > 0 && - epbuff[5] == '\xad' && epbuff[6] == '\x8b' && epbuff[7] == '\xf8' /* loads; mov edi, eax */ - ) - )) - ) { - uint32_t vma, off; - int a,b,c; - - cli_dbgmsg("Upack characteristics found.\n"); - a = exe_sections[0].vsz; - b = exe_sections[1].vsz; - if (upack) { - cli_dbgmsg("Upack: var set\n"); - c = exe_sections[2].vsz; - ssize = exe_sections[0].ursz + exe_sections[0].uraw; - off = exe_sections[0].rva; - vma = EC32(optional_hdr32.ImageBase) + exe_sections[0].rva; - } else { - cli_dbgmsg("Upack: var NOT set\n"); - c = exe_sections[1].rva; - ssize = exe_sections[1].uraw; - off = 0; - vma = exe_sections[1].rva - exe_sections[1].uraw; - } - - dsize = a+b+c; - - CLI_UNPSIZELIMITS("Upack", MAX(MAX(dsize, ssize), exe_sections[1].ursz)); - - if (!CLI_ISCONTAINED(0, dsize, exe_sections[1].rva - off, exe_sections[1].ursz) || (upack && !CLI_ISCONTAINED(0, dsize, exe_sections[2].rva - exe_sections[0].rva, ssize)) || ssize > dsize) { - cli_dbgmsg("Upack: probably malformed pe-header, skipping to next unpacker\n"); - break; - } - - if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) - return CL_EMEM; - - if(fmap_readn(map, dest, 0, ssize) != ssize) { - cli_dbgmsg("Upack: Can't read raw data of section 0\n"); - free(dest); - break; - } - - if(upack) memmove(dest + exe_sections[2].rva - exe_sections[0].rva, dest, ssize); - - if(fmap_readn(map, dest + exe_sections[1].rva - off, exe_sections[1].uraw, exe_sections[1].ursz) != exe_sections[1].ursz) { - cli_dbgmsg("Upack: Can't read raw data of section 1\n"); - free(dest); - break; - } - - CLI_UNPTEMP("Upack",(dest,0)); - CLI_UNPRESULTS("Upack",(unupack(upack, dest, dsize, epbuff, vma, ep, EC32(optional_hdr32.ImageBase), exe_sections[0].rva, ndesc)),1,(dest,0)); - break; - } - } - - - while(found && (DCONF & PE_CONF_FSG) && epbuff[0] == '\x87' && epbuff[1] == '\x25') { - - /* FSG v2.0 support - thanks to aCaB ! */ - - uint32_t newesi, newedi, newebx, newedx; - - ssize = exe_sections[i + 1].rsz; - dsize = exe_sections[i].vsz; - - CLI_UNPSIZELIMITS("FSG", MAX(dsize, ssize)); - - if(ssize <= 0x19 || dsize <= ssize) { - cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); - return CL_CLEAN; - } - - newedx = cli_readint32(epbuff + 2) - EC32(optional_hdr32.ImageBase); - if(!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newedx, 4)) { - cli_dbgmsg("FSG: xchg out of bounds (%x), giving up\n", newedx); - break; - } - - if(!exe_sections[i + 1].rsz || !(src = fmap_need_off_once(map, exe_sections[i + 1].raw, ssize))) { - cli_dbgmsg("Can't read raw data of section %d\n", i + 1); - return CL_ESEEK; - } - - dest = src + newedx - exe_sections[i + 1].rva; - if(newedx < exe_sections[i + 1].rva || !CLI_ISCONTAINED(src, ssize, dest, 4)) { - cli_dbgmsg("FSG: New ESP out of bounds\n"); - break; - } - - newedx = cli_readint32(dest) - EC32(optional_hdr32.ImageBase); - if(!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newedx, 4)) { - cli_dbgmsg("FSG: New ESP (%x) is wrong\n", newedx); - break; - } - - dest = src + newedx - exe_sections[i + 1].rva; - if(!CLI_ISCONTAINED(src, ssize, dest, 32)) { - cli_dbgmsg("FSG: New stack out of bounds\n"); - break; - } - - newedi = cli_readint32(dest) - EC32(optional_hdr32.ImageBase); - newesi = cli_readint32(dest + 4) - EC32(optional_hdr32.ImageBase); - newebx = cli_readint32(dest + 16) - EC32(optional_hdr32.ImageBase); - newedx = cli_readint32(dest + 20); - - if(newedi != exe_sections[i].rva) { - cli_dbgmsg("FSG: Bad destination buffer (edi is %x should be %x)\n", newedi, exe_sections[i].rva); - break; - } - - if(newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].rsz) { - cli_dbgmsg("FSG: Source buffer out of section bounds\n"); - break; - } - - if(!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newebx, 16)) { - cli_dbgmsg("FSG: Array of functions out of bounds\n"); - break; - } - - newedx=cli_readint32(newebx + 12 - exe_sections[i + 1].rva + src) - EC32(optional_hdr32.ImageBase); - cli_dbgmsg("FSG: found old EP @%x\n",newedx); - - if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { - free(src); - return CL_EMEM; - } - - CLI_UNPTEMP("FSG",(dest,0)); - CLI_UNPRESULTSFSG2("FSG",(unfsg_200(newesi - exe_sections[i + 1].rva + src, dest, ssize + exe_sections[i + 1].rva - newesi, dsize, newedi, EC32(optional_hdr32.ImageBase), newedx, ndesc)),1,(dest,0)); - break; - } - - - while(found && (DCONF & PE_CONF_FSG) && epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) < min) { - - /* FSG support - v. 1.33 (thx trog for the many samples) */ - - int sectcnt = 0; - char *support; - uint32_t newesi, newedi, oldep, gp, t; - struct cli_exe_section *sections; - - ssize = exe_sections[i + 1].rsz; - dsize = exe_sections[i].vsz; - - CLI_UNPSIZELIMITS("FSG", MAX(dsize, ssize)); - - if(ssize <= 0x19 || dsize <= ssize) { - cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); - return CL_CLEAN; - } - - if(!(t = cli_rawaddr(cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase), NULL, 0 , &err, fsize, hdr_size)) && err ) { - cli_dbgmsg("FSG: Support data out of padding area\n"); - break; - } - - gp = exe_sections[i + 1].raw - t; - - CLI_UNPSIZELIMITS("FSG", gp); - - if(!(support = fmap_need_off_once(map, t, gp))) { - cli_dbgmsg("Can't read %d bytes from padding area\n", gp); - return CL_EREAD; - } - - /* newebx = cli_readint32(support) - EC32(optional_hdr32.ImageBase); Unused */ - newedi = cli_readint32(support + 4) - EC32(optional_hdr32.ImageBase); /* 1st dest */ - newesi = cli_readint32(support + 8) - EC32(optional_hdr32.ImageBase); /* Source */ - - if(newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].rsz) { - cli_dbgmsg("FSG: Source buffer out of section bounds\n"); - break; - } - - if(newedi != exe_sections[i].rva) { - cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, exe_sections[i].rva); - break; - } - - /* Counting original sections */ - for(t = 12; t < gp - 4; t += 4) { - uint32_t rva = cli_readint32(support+t); - - if(!rva) - break; - - rva -= EC32(optional_hdr32.ImageBase)+1; - sectcnt++; - - if(rva % 0x1000) cli_dbgmsg("FSG: Original section %d is misaligned\n", sectcnt); - - if(rva < exe_sections[i].rva || rva - exe_sections[i].rva >= exe_sections[i].vsz) { - cli_dbgmsg("FSG: Original section %d is out of bounds\n", sectcnt); - break; - } - } - - if(t >= gp - 4 || cli_readint32(support + t)) { - break; - } - - if((sections = (struct cli_exe_section *) cli_malloc((sectcnt + 1) * sizeof(struct cli_exe_section))) == NULL) - return CL_EMEM; - - sections[0].rva = newedi; - for(t = 1; t <= (uint32_t)sectcnt; t++) - sections[t].rva = cli_readint32(support + 8 + t * 4) - 1 - EC32(optional_hdr32.ImageBase); - - if(!exe_sections[i + 1].rsz || !(src = fmap_need_off_once(map, exe_sections[i + 1].raw, ssize))) { - cli_dbgmsg("Can't read raw data of section %d\n", i); - free(sections); - return CL_EREAD; - } - - if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { - free(sections); - return CL_EMEM; - } - - oldep = vep + 161 + 6 + cli_readint32(epbuff+163); - cli_dbgmsg("FSG: found old EP @%x\n", oldep); - - CLI_UNPTEMP("FSG",(dest,sections,0)); - CLI_UNPRESULTSFSG1("FSG",(unfsg_133(src + newesi - exe_sections[i + 1].rva, dest, ssize + exe_sections[i + 1].rva - newesi, dsize, sections, sectcnt, EC32(optional_hdr32.ImageBase), oldep, ndesc)),1,(dest,sections,0)); - break; /* were done with 1.33 */ - } - - - 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 ) { - - /* FSG support - v. 1.31 */ - - int sectcnt = 0; - uint32_t gp, t = cli_rawaddr(cli_readint32(epbuff+1) - EC32(optional_hdr32.ImageBase), NULL, 0 , &err, fsize, hdr_size); - char *support; - uint32_t newesi = cli_readint32(epbuff+11) - EC32(optional_hdr32.ImageBase); - uint32_t newedi = cli_readint32(epbuff+6) - EC32(optional_hdr32.ImageBase); - uint32_t oldep = vep - exe_sections[i + 1].rva; - struct cli_exe_section *sections; - - ssize = exe_sections[i + 1].rsz; - dsize = exe_sections[i].vsz; - - if(err) { - cli_dbgmsg("FSG: Support data out of padding area\n"); - break; - } - - if(newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].raw) { - cli_dbgmsg("FSG: Source buffer out of section bounds\n"); - break; - } - - if(newedi != exe_sections[i].rva) { - cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, exe_sections[i].rva); - break; - } - - CLI_UNPSIZELIMITS("FSG", MAX(dsize, ssize)); - - if(ssize <= 0x19 || dsize <= ssize) { - cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); - return CL_CLEAN; - } - - gp = exe_sections[i + 1].raw - t; - - CLI_UNPSIZELIMITS("FSG", gp) - - if(!(support = fmap_need_off_once(map, t, gp))) { - cli_dbgmsg("Can't read %d bytes from padding area\n", gp); - return CL_EREAD; - } - - /* Counting original sections */ - for(t = 0; t < gp - 2; t += 2) { - uint32_t rva = support[t]|(support[t+1]<<8); - - if (rva == 2 || rva == 1) - break; - - rva = ((rva-2)<<12) - EC32(optional_hdr32.ImageBase); - sectcnt++; - - if(rva < exe_sections[i].rva || rva - exe_sections[i].rva >= exe_sections[i].vsz) { - cli_dbgmsg("FSG: Original section %d is out of bounds\n", sectcnt); - break; - } - } - - if(t >= gp-10 || cli_readint32(support + t + 6) != 2) { - break; - } - - if((sections = (struct cli_exe_section *) cli_malloc((sectcnt + 1) * sizeof(struct cli_exe_section))) == NULL) - return CL_EMEM; - - sections[0].rva = newedi; - for(t = 0; t <= (uint32_t)sectcnt - 1; t++) { - sections[t+1].rva = (((support[t*2]|(support[t*2+1]<<8))-2)<<12)-EC32(optional_hdr32.ImageBase); - } - - if(!exe_sections[i + 1].rsz || !(src = fmap_need_off_once(map, exe_sections[i + 1].raw, ssize))) { - cli_dbgmsg("FSG: Can't read raw data of section %d\n", i); - free(sections); - return CL_EREAD; - } - - if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { - free(sections); - return CL_EMEM; - } - - gp = 0xda + 6*(epbuff[16]=='\xe8'); - oldep = vep + gp + 6 + cli_readint32(src+gp+2+oldep); - cli_dbgmsg("FSG: found old EP @%x\n", oldep); - - CLI_UNPTEMP("FSG",(dest,sections,0)); - CLI_UNPRESULTSFSG1("FSG",(unfsg_133(src + newesi - exe_sections[i + 1].rva, dest, ssize + exe_sections[i + 1].rva - newesi, dsize, sections, sectcnt, EC32(optional_hdr32.ImageBase), oldep, ndesc)),1,(dest,sections,0)); - break; /* were done with 1.31 */ - } - - - if(found && (DCONF & PE_CONF_UPX)) { - - /* UPX support */ - - /* we assume (i + 1) is UPX1 */ - ssize = exe_sections[i + 1].rsz; - dsize = exe_sections[i].vsz + exe_sections[i + 1].vsz; - - CLI_UNPSIZELIMITS("UPX", MAX(dsize, ssize)); - - if(ssize <= 0x19 || dsize <= ssize || dsize > CLI_MAX_ALLOCATION ) { - cli_dbgmsg("UPX: Size mismatch or dsize too big (ssize: %d, dsize: %d)\n", ssize, dsize); - return CL_CLEAN; - } - - if(!exe_sections[i + 1].rsz || !(src = fmap_need_off_once(map, exe_sections[i + 1].raw, ssize))) { - cli_dbgmsg("UPX: Can't read raw data of section %d\n", i+1); - return CL_EREAD; - } - - if((dest = (char *) cli_calloc(dsize + 8192, sizeof(char))) == NULL) - return CL_EMEM; - - /* try to detect UPX code */ - if(cli_memstr(UPX_NRV2B, 24, epbuff + 0x69, 13) || cli_memstr(UPX_NRV2B, 24, epbuff + 0x69 + 8, 13)) { - cli_dbgmsg("UPX: Looks like a NRV2B decompression routine\n"); - upxfn = upx_inflate2b; - } else if(cli_memstr(UPX_NRV2D, 24, epbuff + 0x69, 13) || cli_memstr(UPX_NRV2D, 24, epbuff + 0x69 + 8, 13)) { - cli_dbgmsg("UPX: Looks like a NRV2D decompression routine\n"); - upxfn = upx_inflate2d; - } else if(cli_memstr(UPX_NRV2E, 24, epbuff + 0x69, 13) || cli_memstr(UPX_NRV2E, 24, epbuff + 0x69 + 8, 13)) { - cli_dbgmsg("UPX: Looks like a NRV2E decompression routine\n"); - upxfn = upx_inflate2e; - } - - if(upxfn) { - int skew = cli_readint32(epbuff + 2) - EC32(optional_hdr32.ImageBase) - exe_sections[i + 1].rva; - - if(epbuff[1] != '\xbe' || skew <= 0 || skew > 0xfff) { /* FIXME: legit skews?? */ - skew = 0; - if(upxfn(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) >= 0) - upx_success = 1; - - } else { - cli_dbgmsg("UPX: UPX1 seems skewed by %d bytes\n", skew); - if(upxfn(src + skew, ssize - skew, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep-skew) >= 0 || upxfn(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) >= 0) - upx_success = 1; - } - - if(upx_success) - cli_dbgmsg("UPX: Successfully decompressed\n"); - else - cli_dbgmsg("UPX: Preferred decompressor failed\n"); - } - - if(!upx_success && upxfn != upx_inflate2b) { - if(upx_inflate2b(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2b(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) { - - cli_dbgmsg("UPX: NRV2B decompressor failed\n"); - } else { - upx_success = 1; - cli_dbgmsg("UPX: Successfully decompressed with NRV2B\n"); - } - } - - if(!upx_success && upxfn != upx_inflate2d) { - if(upx_inflate2d(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2d(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) { - - cli_dbgmsg("UPX: NRV2D decompressor failed\n"); - } else { - upx_success = 1; - cli_dbgmsg("UPX: Successfully decompressed with NRV2D\n"); - } - } - - if(!upx_success && upxfn != upx_inflate2e) { - if(upx_inflate2e(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2e(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) { - cli_dbgmsg("UPX: NRV2E decompressor failed\n"); - } else { - upx_success = 1; - cli_dbgmsg("UPX: Successfully decompressed with NRV2E\n"); - } - } - - if(cli_memstr(UPX_LZMA2, 20, epbuff + 0x2f, 20)) { - uint32_t strictdsize=cli_readint32(epbuff+0x21), skew = 0; - if(ssize > 0x15 && epbuff[0] == '\x60' && epbuff[1] == '\xbe') { - skew = cli_readint32(epbuff+2) - exe_sections[i + 1].rva - optional_hdr32.ImageBase; - if(skew!=0x15) skew = 0; - } - if(strictdsize<=dsize) - upx_success = upx_inflatelzma(src+skew, ssize-skew, dest, &strictdsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) >=0; - } else if (cli_memstr(UPX_LZMA1, 20, epbuff + 0x39, 20)) { - uint32_t strictdsize=cli_readint32(epbuff+0x2b), skew = 0; - if(ssize > 0x15 && epbuff[0] == '\x60' && epbuff[1] == '\xbe') { - skew = cli_readint32(epbuff+2) - exe_sections[i + 1].rva - optional_hdr32.ImageBase; - if(skew!=0x15) skew = 0; - } - if(strictdsize<=dsize) - upx_success = upx_inflatelzma(src+skew, ssize-skew, dest, &strictdsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) >=0; - } - - if(!upx_success) { - cli_dbgmsg("UPX: All decompressors failed\n"); - free(dest); - } - } - - if(upx_success) { - CLI_UNPTEMP("UPX/FSG",(dest,0)); - - if((unsigned int) write(ndesc, dest, dsize) != dsize) { - cli_dbgmsg("UPX/FSG: Can't write %d bytes\n", dsize); - free(tempfile); - free(dest); - close(ndesc); - return CL_EWRITE; - } - - free(dest); - lseek(ndesc, 0, SEEK_SET); - - if(ctx->engine->keeptmp) - cli_dbgmsg("UPX/FSG: Decompressed data saved in %s\n", tempfile); - - cli_dbgmsg("***** Scanning decompressed file *****\n"); - SHA_OFF; - if((ret = cli_magic_scandesc(ndesc, ctx)) == CL_VIRUS) { - close(ndesc); - CLI_TMPUNLK(); - free(tempfile); - SHA_RESET; - return CL_VIRUS; - } - - SHA_RESET; - close(ndesc); - CLI_TMPUNLK(); - free(tempfile); - return ret; - } - - - /* Petite */ - - if(epsize<200) - return CL_CLEAN; - - found = 2; - - if(epbuff[0] != '\xb8' || (uint32_t) cli_readint32(epbuff + 1) != exe_sections[nsections - 1].rva + EC32(optional_hdr32.ImageBase)) { - if(nsections < 2 || epbuff[0] != '\xb8' || (uint32_t) cli_readint32(epbuff + 1) != exe_sections[nsections - 2].rva + EC32(optional_hdr32.ImageBase)) - found = 0; - else - found = 1; - } - - if(found && (DCONF & PE_CONF_PETITE)) { - cli_dbgmsg("Petite: v2.%d compression detected\n", found); - - if(cli_readint32(epbuff + 0x80) == 0x163c988d) { - cli_dbgmsg("Petite: level zero compression is not supported yet\n"); - } else { - dsize = max - min; - - CLI_UNPSIZELIMITS("Petite", dsize); - - if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { - cli_dbgmsg("Petite: Can't allocate %d bytes\n", dsize); - return CL_EMEM; - } - - for(i = 0 ; i < nsections; i++) { - if(exe_sections[i].raw) { - if(!exe_sections[i].rsz || fmap_readn(map, dest + exe_sections[i].rva - min, exe_sections[i].raw, exe_sections[i].ursz) != exe_sections[i].ursz) { - free(dest); - return CL_CLEAN; - } - } - } - - CLI_UNPTEMP("Petite",(dest,0)); - CLI_UNPRESULTS("Petite",(petite_inflate2x_1to9(dest, min, max - min, exe_sections, nsections - (found == 1 ? 1 : 0), EC32(optional_hdr32.ImageBase),vep, ndesc, found, EC32(optional_hdr32.DataDirectory[2].VirtualAddress),EC32(optional_hdr32.DataDirectory[2].Size))),0,(dest,0)); - } - } - - /* PESpin 1.1 */ - - if((DCONF & PE_CONF_PESPIN) && nsections > 1 && - vep >= exe_sections[nsections - 1].rva && - vep < exe_sections[nsections - 1].rva + exe_sections[nsections - 1].rsz - 0x3217 - 4 && - memcmp(epbuff+4, "\xe8\x00\x00\x00\x00\x8b\x1c\x24\x83\xc3", 10) == 0) { - - char *spinned; - - CLI_UNPSIZELIMITS("PEspin", fsize); - - if((spinned = (char *) cli_malloc(fsize)) == NULL) - return CL_EMEM; - - if((size_t) fmap_readn(map, spinned, 0, fsize) != fsize) { - cli_dbgmsg("PESpin: Can't read %lu bytes\n", (unsigned long)fsize); - free(spinned); - return CL_EREAD; - } - - CLI_UNPTEMP("PESpin",(spinned,0)); - CLI_UNPRESULTS_("PEspin",SPINCASE(),(unspin(spinned, fsize, exe_sections, nsections - 1, vep, ndesc, ctx)),0,(spinned,0)); - } - - - /* yC 1.3 & variants */ - if((DCONF & PE_CONF_YC) && nsections > 1 && - (EC32(optional_hdr32.AddressOfEntryPoint) == exe_sections[nsections - 1].rva + 0x60)) { - - uint32_t ecx = 0; - int16_t offset; - - /* yC 1.3 */ - if (!memcmp(epbuff, "\x55\x8B\xEC\x53\x56\x57\x60\xE8\x00\x00\x00\x00\x5D\x81\xED", 15) && - !memcmp(epbuff+0x26, "\x8D\x3A\x8B\xF7\x33\xC0\xEB\x04\x90\xEB\x01\xC2\xAC", 13) && - ((uint8_t)epbuff[0x13] == 0xB9) && - ((uint16_t)(cli_readint16(epbuff+0x18)) == 0xE981) && - !memcmp(epbuff+0x1e,"\x8B\xD5\x81\xC2", 4)) { - - offset = 0; - if (0x6c - cli_readint32(epbuff+0xf) + cli_readint32(epbuff+0x22) == 0xC6) - ecx = cli_readint32(epbuff+0x14) - cli_readint32(epbuff+0x1a); - } - - /* yC 1.3 variant */ - if (!ecx && !memcmp(epbuff, "\x55\x8B\xEC\x83\xEC\x40\x53\x56\x57", 9) && - !memcmp(epbuff+0x17, "\xe8\x00\x00\x00\x00\x5d\x81\xed", 8) && - ((uint8_t)epbuff[0x23] == 0xB9)) { - - offset = 0x10; - if (0x6c - cli_readint32(epbuff+0x1f) + cli_readint32(epbuff+0x32) == 0xC6) - ecx = cli_readint32(epbuff+0x24) - cli_readint32(epbuff+0x2a); - } - - /* yC 1.x/modified */ - if (!ecx && !memcmp(epbuff, "\x60\xe8\x00\x00\x00\x00\x5d\x81\xed",9) && - ((uint8_t)epbuff[0xd] == 0xb9) && - ((uint16_t)cli_readint16(epbuff + 0x12)== 0xbd8d) && - !memcmp(epbuff+0x18, "\x8b\xf7\xac", 3)) { - - offset = -0x18; - if (0x66 - cli_readint32(epbuff+0x9) + cli_readint32(epbuff+0x14) == 0xae) - ecx = cli_readint32(epbuff+0xe); - } - - if (ecx > 0x800 && ecx < 0x2000 && - !memcmp(epbuff+0x63+offset, "\xaa\xe2\xcc", 3) && - (fsize >= exe_sections[nsections-1].raw + 0xC6 + ecx + offset)) { - - char *spinned; - - if((spinned = (char *) cli_malloc(fsize)) == NULL) - return CL_EMEM; - - if((size_t) fmap_readn(map, spinned, 0, fsize) != fsize) { - cli_dbgmsg("yC: Can't read %lu bytes\n", (unsigned long)fsize); - free(spinned); - return CL_EREAD; - } - - cli_dbgmsg("%d,%d,%d,%d\n", nsections-1, e_lfanew, ecx, offset); - CLI_UNPTEMP("yC",(spinned,0)); - CLI_UNPRESULTS("yC",(yc_decrypt(spinned, fsize, exe_sections, nsections-1, e_lfanew, ndesc, ecx, offset)),0,(spinned,0)); - } - } - - /* WWPack */ - - while ((DCONF & PE_CONF_WWPACK) && nsections > 1 && - vep == exe_sections[nsections - 1].rva && - memcmp(epbuff, "\x53\x55\x8b\xe8\x33\xdb\xeb", 7) == 0 && - memcmp(epbuff+0x68, "\xe8\x00\x00\x00\x00\x58\x2d\x6d\x00\x00\x00\x50\x60\x33\xc9\x50\x58\x50\x50", 19) == 0) { - uint32_t head = exe_sections[nsections - 1].raw; - uint8_t *packer; - - ssize = 0; - for(i=0 ; ; i++) { - if(exe_sections[i].rawssize) break; - - CLI_UNPSIZELIMITS("WWPack", ssize); - - if(!(src=(char *)cli_calloc(ssize, sizeof(char)))) - return CL_EMEM; - if((size_t) fmap_readn(map, src, 0, head) != head) { - cli_dbgmsg("WWPack: Can't read %d bytes from headers\n", head); - free(src); - return CL_EREAD; - } - for(i = 0 ; i < (unsigned int)nsections-1; i++) { - if(!exe_sections[i].rsz) continue; - if(!CLI_ISCONTAINED(src, ssize, src+exe_sections[i].rva, exe_sections[i].rsz)) break; - if(fmap_readn(map, src+exe_sections[i].rva, exe_sections[i].raw, exe_sections[i].rsz)!=exe_sections[i].rsz) break; - } - if(i+1!=nsections) { - cli_dbgmsg("WWpack: Probably hacked/damaged file.\n"); - free(src); - break; - } - if((packer = (uint8_t *) cli_calloc(exe_sections[nsections - 1].rsz, sizeof(char))) == NULL) { - free(src); - return CL_EMEM; - } - if(!exe_sections[nsections - 1].rsz || (size_t) fmap_readn(map, packer, exe_sections[nsections - 1].raw, exe_sections[nsections - 1].rsz) != exe_sections[nsections - 1].rsz) { - cli_dbgmsg("WWPack: Can't read %d bytes from wwpack sect\n", exe_sections[nsections - 1].rsz); - free(src); - free(packer); - return CL_EREAD; - } - - CLI_UNPTEMP("WWPack",(src,packer,0)); - CLI_UNPRESULTS("WWPack",(wwunpack((uint8_t *)src, ssize, packer, exe_sections, nsections-1, e_lfanew, ndesc)),0,(src,packer,0)); - break; - } - - - /* ASPACK support */ - while((DCONF & PE_CONF_ASPACK) && ep+58+0x70e < fsize && !memcmp(epbuff,"\x60\xe8\x03\x00\x00\x00\xe9\xeb",8)) { - - if(epsize<0x3bf || memcmp(epbuff+0x3b9, "\x68\x00\x00\x00\x00\xc3",6)) break; - ssize = 0; - for(i=0 ; i< nsections ; i++) - if(ssizecorrupted_input = corrupted_cur; - - /* Bytecode BC_PE_UNPACKER hook */ - bc_ctx = cli_bytecode_context_alloc(); - if (!bc_ctx) { - cli_errmsg("cli_scanpe: can't allocate memory for bc_ctx\n"); - return CL_EMEM; - } - cli_bytecode_context_setpe(bc_ctx, &pedata, exe_sections); - cli_bytecode_context_setctx(bc_ctx, ctx); - ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_UNPACKER, map, ctx->virname); - switch (ret) { - case CL_VIRUS: - cli_bytecode_context_destroy(bc_ctx); - return CL_VIRUS; - case CL_SUCCESS: - ndesc = cli_bytecode_context_getresult_file(bc_ctx, &tempfile); - cli_bytecode_context_destroy(bc_ctx); - if (ndesc != -1 && tempfile) { - CLI_UNPRESULTS("bytecode PE hook", 1, 1, (0)); - } - break; - default: - cli_bytecode_context_destroy(bc_ctx); - } - return CL_CLEAN; -} - -int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo) -{ - uint16_t e_magic; /* DOS signature ("MZ") */ - uint32_t e_lfanew; /* address of new exe header */ - /* Obsolete - see below - uint32_t min = 0, max = 0; - */ - struct pe_image_file_hdr file_hdr; - pe_opt_t pe_opt; - struct pe_image_section_hdr *section_hdr; - int i; - unsigned int err, pe_plus = 0; - uint32_t valign, falign, hdr_size; - size_t fsize; - ssize_t at; - struct pe_image_data_dir *dirs; - - cli_dbgmsg("in cli_peheader\n"); - - fsize = map->len - peinfo->offset; - if(fmap_readn(map, &e_magic, peinfo->offset, sizeof(e_magic)) != sizeof(e_magic)) { - cli_dbgmsg("Can't read DOS signature\n"); - return CL_CLEAN; - } - - if(EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE && EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE_OLD) { - cli_dbgmsg("Invalid DOS signature\n"); - return -1; - } - - if(fmap_readn(map, &e_lfanew, peinfo->offset + 58 + sizeof(e_magic), sizeof(e_lfanew)) != sizeof(e_lfanew)) { - /* truncated header? */ - return -1; - } - - e_lfanew = EC32(e_lfanew); - if(!e_lfanew) { - cli_dbgmsg("Not a PE file\n"); - return -1; - } - - if(fmap_readn(map, &file_hdr, peinfo->offset + e_lfanew, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) { - /* bad information in e_lfanew - probably not a PE file */ - cli_dbgmsg("Can't read file header\n"); - return -1; - } - - if(EC32(file_hdr.Magic) != PE_IMAGE_NT_SIGNATURE) { - cli_dbgmsg("Invalid PE signature (probably NE file)\n"); - return -1; - } - - if ( (peinfo->nsections = EC16(file_hdr.NumberOfSections)) < 1 || peinfo->nsections > 96 ) return -1; - - if (EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) { - cli_dbgmsg("SizeOfOptionalHeader too small\n"); - return -1; - } - - at = peinfo->offset + e_lfanew + sizeof(struct pe_image_file_hdr); - if(fmap_readn(map, &optional_hdr32, at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) { - cli_dbgmsg("Can't read optional file header\n"); - return -1; - } - at += sizeof(struct pe_image_optional_hdr32); - - if(EC16(optional_hdr64.Magic)==PE32P_SIGNATURE) { /* PE+ */ - if(EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr64)) { - cli_dbgmsg("Incorrect SizeOfOptionalHeader for PE32+\n"); - return -1; - } - if(fmap_readn(map, &optional_hdr32 + 1, at, sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) { - cli_dbgmsg("Can't read optional file header\n"); - return -1; - } - at += sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32); - hdr_size = EC32(optional_hdr64.SizeOfHeaders); - pe_plus=1; - } else { /* PE */ - if (EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr32)) { - /* Seek to the end of the long header */ - at += EC16(file_hdr.SizeOfOptionalHeader)-sizeof(struct pe_image_optional_hdr32); - } - hdr_size = EC32(optional_hdr32.SizeOfHeaders); - } - - valign = (pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment); - falign = (pe_plus)?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment); - - peinfo->hdr_size = hdr_size = PESALIGN(hdr_size, valign); - - peinfo->section = (struct cli_exe_section *) cli_calloc(peinfo->nsections, sizeof(struct cli_exe_section)); - - if(!peinfo->section) { - cli_dbgmsg("Can't allocate memory for section headers\n"); - return -1; - } - - section_hdr = (struct pe_image_section_hdr *) cli_calloc(peinfo->nsections, sizeof(struct pe_image_section_hdr)); - - if(!section_hdr) { - cli_dbgmsg("Can't allocate memory for section headers\n"); - free(peinfo->section); - peinfo->section = NULL; - return -1; - } - - if(fmap_readn(map, section_hdr, at, peinfo->nsections * sizeof(struct pe_image_section_hdr)) != peinfo->nsections * sizeof(struct pe_image_section_hdr)) { - cli_dbgmsg("Can't read section header\n"); - cli_dbgmsg("Possibly broken PE file\n"); - free(section_hdr); - free(peinfo->section); - peinfo->section = NULL; - return -1; - } - at += sizeof(struct pe_image_section_hdr)*peinfo->nsections; - - for(i = 0; falign!=0x200 && insections; i++) { - /* file alignment fallback mode - blah */ - if (falign && section_hdr[i].SizeOfRawData && EC32(section_hdr[i].PointerToRawData)%falign && !(EC32(section_hdr[i].PointerToRawData)%0x200)) { - falign = 0x200; - } - } - - for(i = 0; i < peinfo->nsections; i++) { - peinfo->section[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign); - peinfo->section[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign); - peinfo->section[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign); - peinfo->section[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign); - - if (!peinfo->section[i].vsz && peinfo->section[i].rsz) - peinfo->section[i].vsz=PESALIGN(EC32(section_hdr[i].SizeOfRawData), valign); - - if (peinfo->section[i].rsz && !CLI_ISCONTAINED(0, (uint32_t) fsize, peinfo->section[i].raw, peinfo->section[i].rsz)) - peinfo->section[i].rsz = (fsize - peinfo->section[i].raw)*(fsize>peinfo->section[i].raw); - } - - if(pe_plus) { - peinfo->ep = EC32(optional_hdr64.AddressOfEntryPoint); - dirs = optional_hdr64.DataDirectory; - } else { - peinfo->ep = EC32(optional_hdr32.AddressOfEntryPoint); - dirs = optional_hdr32.DataDirectory; - } - - if(!(peinfo->ep = cli_rawaddr(peinfo->ep, peinfo->section, peinfo->nsections, &err, fsize, hdr_size)) && err) { - cli_dbgmsg("Broken PE file\n"); - free(section_hdr); - free(peinfo->section); - peinfo->section = NULL; - return -1; - } - - if(EC16(file_hdr.Characteristics) & 0x2000 || !dirs[2].Size) - peinfo->res_addr = 0; - else - peinfo->res_addr = EC32(dirs[2].VirtualAddress); - - while(dirs[2].Size) { - struct vinfo_list vlist; - uint8_t *vptr, *baseptr; - uint32_t rva, res_sz; - - memset(&vlist, 0, sizeof(vlist)); - findres(0x10, 0xffffffff, EC32(dirs[2].VirtualAddress), map, peinfo->section, peinfo->nsections, hdr_size, versioninfo_cb, &vlist); - if(!vlist.count) break; /* No version_information */ - if(cli_hashset_init(&peinfo->vinfo, 32, 80)) { - cli_errmsg("cli_peheader: Unable to init vinfo hashset\n"); - free(section_hdr); - free(peinfo->section); - peinfo->section = NULL; - return -1; - } - - err = 0; - for(i=0; isection, peinfo->nsections, &err, fsize, hdr_size); - if(err) - continue; - - if(!(vptr = fmap_need_off_once(map, rva, 16))) - continue; - - baseptr = vptr - rva; - /* parse resource */ - rva = cli_readint32(vptr); /* ptr to version_info */ - res_sz = cli_readint32(vptr+4); /* sizeof(resource) */ - rva = cli_rawaddr(rva, peinfo->section, peinfo->nsections, &err, fsize, hdr_size); - if(err) - continue; - if(!(vptr = fmap_need_off_once(map, rva, res_sz))) - continue; - - while(res_sz>4) { /* look for version_info - NOT RESUMABLE (expecting exactly one versioninfo) */ - uint32_t vinfo_sz, vinfo_val_sz, got_varfileinfo = 0; - - vinfo_sz = vinfo_val_sz = cli_readint32(vptr); - vinfo_sz &= 0xffff; - if(vinfo_sz > res_sz) - break; /* the content is larger than the container */ - - vinfo_val_sz >>= 16; - if(vinfo_sz <= 6 + 0x20 + 2 + 0x34 || - vinfo_val_sz != 0x34 || - memcmp(vptr+6, "V\0S\0_\0V\0E\0R\0S\0I\0O\0N\0_\0I\0N\0F\0O\0\0\0", 0x20) || - cli_readint32(vptr + 0x28) != 0xfeef04bd) { - /* - there should be enough room for the header(6), the key "VS_VERSION_INFO"(20), the padding(2) and the value(34) - * - the value should be sizeof(fixedfileinfo) - * - the key should match - * - there should be some proper magic for fixedfileinfo */ - break; /* there's no point in looking further */ - } - - /* move to the end of fixedfileinfo where the child elements are located */ - vptr += 6 + 0x20 + 2 + 0x34; - vinfo_sz -= 6 + 0x20 + 2 + 0x34; - - while(vinfo_sz > 6) { /* look for stringfileinfo - NOT RESUMABLE (expecting at most one stringfileinfo) */ - uint32_t sfi_sz = cli_readint32(vptr) & 0xffff; - - if(sfi_sz > vinfo_sz) - break; /* the content is larger than the container */ - - if(!got_varfileinfo && sfi_sz > 6 + 0x18 && !memcmp(vptr+6, "V\0a\0r\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0", 0x18)) { - /* skip varfileinfo as it sometimes appear before stringtableinfo */ - vptr += sfi_sz; - vinfo_sz -= sfi_sz; - got_varfileinfo = 1; - continue; - } - - if(sfi_sz <= 6 + 0x1e || memcmp(vptr+6, "S\0t\0r\0i\0n\0g\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0", 0x1e)) { - /* - there should be enough room for the header(6) and the key "StringFileInfo"(1e) - * - the key should match */ - break; /* this is an implicit hard fail: parent is not resumable */ - } - - /* move to the end of stringfileinfo where the child elements are located */ - vptr += 6 + 0x1e; - sfi_sz -= 6 + 0x1e; - - while(sfi_sz > 6) { /* enum all stringtables - RESUMABLE */ - uint32_t st_sz = cli_readint32(vptr) & 0xffff; - uint8_t *next_vptr = vptr + st_sz; - uint32_t next_sfi_sz = sfi_sz - st_sz; - - if(st_sz > sfi_sz || st_sz <= 24) { - /* - the content is larger than the container - - there's no room for a stringtables (headers(6) + key(16) + padding(2)) */ - break; /* this is an implicit hard fail: parent is not resumable */ - } - - /* move to the end of stringtable where the child elements are located */ - vptr += 24; - st_sz -= 24; - - while(st_sz > 6) { /* enum all strings - RESUMABLE */ - uint32_t s_sz, s_key_sz, s_val_sz; - - s_sz = (cli_readint32(vptr) & 0xffff) + 3; - s_sz &= ~3; - if(s_sz > st_sz || s_sz <= 6 + 2 + 8) { - /* - the content is larger than the container - * - there's no room for a minimal string - * - there's no room for the value */ - st_sz = 0; - sfi_sz = 0; - break; /* force a hard fail */ - } - - /* ~wcstrlen(key) */ - for(s_key_sz = 6; s_key_sz+1 < s_sz; s_key_sz += 2) { - if(vptr[s_key_sz] || vptr[s_key_sz+1]) continue; - s_key_sz += 2; - break; - } - - s_key_sz += 3; - s_key_sz &= ~3; - - if(s_key_sz >= s_sz) { - /* key overflow */ - vptr += s_sz; - st_sz -= s_sz; - continue; - } - - s_val_sz = s_sz - s_key_sz; - s_key_sz -= 6; - - if(s_val_sz <= 2) { - /* skip unset value */ - vptr += s_sz; - st_sz -= s_sz; - continue; - } - - if(cli_hashset_addkey(&peinfo->vinfo, (uint32_t)(vptr - baseptr + 6))) { - cli_errmsg("cli_peheader: Unable to add rva to vinfo hashset\n"); - cli_hashset_destroy(&peinfo->vinfo); - free(section_hdr); - free(peinfo->section); - peinfo->section = NULL; - return -1; - } - - if(cli_debug_flag) { - char *k, *v, *s; - - /* FIXME: skip too long strings */ - k = cli_utf16toascii((const char*)vptr + 6, s_key_sz); - if(k) { - v = cli_utf16toascii((const char*)vptr + s_key_sz + 6, s_val_sz); - if(v) { - s = cli_str2hex((const char*)vptr + 6, s_key_sz + s_val_sz - 6); - if(s) { - cli_dbgmsg("VersionInfo (%x): '%s'='%s' - VI:%s\n", (uint32_t)(vptr - baseptr + 6), k, v, s); - free(s); - } - free(v); - } - free(k); - } - } - vptr += s_sz; - st_sz -= s_sz; - } /* enum all strings - RESUMABLE */ - vptr = next_vptr; - sfi_sz = next_sfi_sz * (sfi_sz != 0); - } /* enum all stringtables - RESUMABLE */ - break; - } /* look for stringfileinfo - NOT RESUMABLE */ - break; - } /* look for version_info - NOT RESUMABLE */ - } /* enum all version_information res - RESUMABLE */ - break; - } /* while(dirs[2].Size) */ - - free(section_hdr); - return 0; -} - - -int cli_scanpe(cli_ctx *ctx) { - uint16_t e_magic; /* DOS signature ("MZ") */ - uint16_t nsections; - uint32_t e_lfanew; /* address of new exe header */ - uint32_t ep, vep; /* entry point (raw, virtual) */ - struct pe_image_file_hdr file_hdr; - pe_opt_t pe_opt; - struct pe_image_section_hdr *section_hdr; - struct cli_exe_section *exe_sections; - struct pe_image_data_dir *dirs; - struct cli_matcher *md5_sect; - unsigned int i, err, dll = 0, pe_plus = 0, native=0, polipos=0, min = 0, max = 0, overlays = 0; - uint32_t valign, falign, hdr_size; - time_t timestamp; - char timestr[32], sname[9]; - fmap_t *map; - size_t fsize; - ssize_t at; - if(!ctx) { cli_errmsg("cli_scanpe: ctx == NULL\n"); return CL_ENULLARG; @@ -2286,6 +763,9 @@ int cli_scanpe(cli_ctx *ctx) { at += EC16(file_hdr.SizeOfOptionalHeader)-sizeof(struct pe_image_optional_hdr32); } + if(DCONF & PE_CONF_UPACK) + upack = (EC16(file_hdr.SizeOfOptionalHeader)==0x148); + vep = EC32(optional_hdr32.AddressOfEntryPoint); hdr_size = EC32(optional_hdr32.SizeOfHeaders); cli_dbgmsg("File format: PE\n"); @@ -2599,63 +1079,1581 @@ int cli_scanpe(cli_ctx *ctx) { return CL_CLEAN; } - { - int ret = cli_real_scanpe(ctx, ep, exe_sections, nsections, &file_hdr, e_lfanew, dirs, overlays, polipos, dll, hdr_size, vep, min, max, pe_opt); - SHA1Context sha1; - uint8_t shash1[SHA1_HASH_SIZE]; - char shatxt[SHA1_HASH_SIZE*2+1]; - unsigned int hlen; - uint8_t *hptr; - uint32_t hsize = hdr_size; + epsize = fmap_readn(map, epbuff, ep, 4096); - SHA1Init(&sha1); - /* MZ to checksum */ - hlen = e_lfanew + sizeof(struct pe_image_file_hdr) + offsetof(struct pe_image_optional_hdr32, CheckSum); - hptr = fmap_need_off_once(map, 0, hlen); - SHA1Update(&sha1, hptr, hlen); - hsize -= hlen + 4; - /* Checksum to security */ - hptr += hlen + 4; - hlen = offsetof(struct pe_image_optional_hdr32, DataDirectory[4]) - offsetof(struct pe_image_optional_hdr32, CheckSum) - 4; - hptr = fmap_need_ptr_once(map, hptr, hlen); - SHA1Update(&sha1, hptr, hlen); - hsize -= hlen + 8; + /* Disasm scan disabled since it's now handled by the bytecode */ - /* Security to End of header */ - hptr += hlen + 8; - hptr = fmap_need_ptr_once(map, hptr, hsize); - SHA1Update(&sha1, hptr, hsize); + /* CLI_UNPTEMP("DISASM",(exe_sections,0)); */ + /* if(disasmbuf((unsigned char*)epbuff, epsize, ndesc)) */ + /* ret = cli_scandesc(ndesc, ctx, CL_TYPE_PE_DISASM, 1, NULL, AC_SCAN_VIR); */ + /* close(ndesc); */ + /* CLI_TMPUNLK(); */ + /* free(tempfile); */ + /* if(ret == CL_VIRUS) { */ + /* free(exe_sections); */ + /* return ret; */ + /* } */ - /* Sections */ - hsize = hdr_size; - for(i = 0; i < nsections; i++) { - if(!exe_sections[i].rsz) - continue; - hptr = fmap_need_off_once(map, exe_sections[i].raw, exe_sections[i].rsz); - SHA1Update(&sha1, hptr, exe_sections[i].rsz); - hsize += exe_sections[i].rsz; + if(overlays) { + int overlays_sz = fsize - overlays; + if(overlays_sz > 0) { + ret = cli_scanishield(ctx, overlays, overlays_sz); + if(ret != CL_CLEAN) { + free(exe_sections); + return ret; + } } + } - /* Overlays minus digital sig */ - if(overlays < fsize - optional_hdr32.DataDirectory[4].Size) { - hlen = fsize - hsize - optional_hdr32.DataDirectory[4].Size; - hptr = fmap_need_off_once(map, hsize, hlen); - SHA1Update(&sha1, hptr, hlen); - } - SHA1Final(&sha1, shash1); - - for(i=0; iengine, bc_ctx, BC_PE_ALL, map, ctx->virname); + if (ret == CL_VIRUS || ret == CL_BREAK) { free(exe_sections); + cli_bytecode_context_destroy(bc_ctx); + return ret == CL_VIRUS ? CL_VIRUS : CL_CLEAN; + } + cli_bytecode_context_destroy(bc_ctx); + + /* Attempt to detect some popular polymorphic viruses */ + + /* W32.Parite.B */ + if(SCAN_ALGO && (DCONF & PE_CONF_PARITE) && !dll && epsize == 4096 && ep == exe_sections[nsections - 1].raw) { + const char *pt = cli_memstr(epbuff, 4040, "\x47\x65\x74\x50\x72\x6f\x63\x41\x64\x64\x72\x65\x73\x73\x00", 15); + if(pt) { + pt += 15; + if((((uint32_t)cli_readint32(pt) ^ (uint32_t)cli_readint32(pt + 4)) == 0x505a4f) && (((uint32_t)cli_readint32(pt + 8) ^ (uint32_t)cli_readint32(pt + 12)) == 0xffffb) && (((uint32_t)cli_readint32(pt + 16) ^ (uint32_t)cli_readint32(pt + 20)) == 0xb8)) { + *ctx->virname = "Heuristics.W32.Parite.B"; + free(exe_sections); + return CL_VIRUS; + } + } + } + + /* Kriz */ + if(SCAN_ALGO && (DCONF & PE_CONF_KRIZ) && epsize >= 200 && CLI_ISCONTAINED(exe_sections[nsections - 1].raw, exe_sections[nsections - 1].rsz, ep, 0x0fd2) && epbuff[1]=='\x9c' && epbuff[2]=='\x60') { + enum {KZSTRASH,KZSCDELTA,KZSPDELTA,KZSGETSIZE,KZSXORPRFX,KZSXOR,KZSDDELTA,KZSLOOP,KZSTOP}; + uint8_t kzs[] = {KZSTRASH,KZSCDELTA,KZSPDELTA,KZSGETSIZE,KZSTRASH,KZSXORPRFX,KZSXOR,KZSTRASH,KZSDDELTA,KZSTRASH,KZSLOOP,KZSTOP}; + uint8_t *kzstate = kzs; + uint8_t *kzcode = (uint8_t *)epbuff + 3; + uint8_t kzdptr=0xff, kzdsize=0xff; + int kzlen = 197, kzinitlen=0xffff, kzxorlen=-1; + cli_dbgmsg("in kriz\n"); + + while(*kzstate!=KZSTOP) { + uint8_t op; + if(kzlen<=6) break; + op = *kzcode++; + kzlen--; + switch (*kzstate) { + case KZSTRASH: case KZSGETSIZE: { + int opsz=0; + switch(op) { + case 0x81: + kzcode+=5; + kzlen-=5; + break; + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbd: case 0xbe: case 0xbf: + if(*kzstate==KZSGETSIZE && cli_readint32(kzcode)==0x0fd2) { + kzinitlen = kzlen-5; + kzdsize=op-0xb8; + kzstate++; + op=4; /* fake the register to avoid breaking out */ + cli_dbgmsg("kriz: using #%d as size counter\n", kzdsize); + } + opsz=4; + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4d: case 0x4e: case 0x4f: + op&=7; + if(op!=kzdptr && op!=kzdsize) { + kzcode+=opsz; + kzlen-=opsz; + break; + } + default: + kzcode--; + kzlen++; + kzstate++; + } + break; + } + case KZSCDELTA: + if(op==0xe8 && (uint32_t)cli_readint32(kzcode) < 0xff) { + kzlen-=*kzcode+4; + kzcode+=*kzcode+4; + kzstate++; + } else *kzstate=KZSTOP; + break; + case KZSPDELTA: + if((op&0xf8)==0x58 && (kzdptr=op-0x58)!=4) { + kzstate++; + cli_dbgmsg("kriz: using #%d as pointer\n", kzdptr); + } else *kzstate=KZSTOP; + break; + case KZSXORPRFX: + kzstate++; + if(op==0x3e) break; + case KZSXOR: + if (op==0x80 && *kzcode==kzdptr+0xb0) { + kzxorlen=kzlen; + kzcode+=+6; + kzlen-=+6; + kzstate++; + } else *kzstate=KZSTOP; + break; + case KZSDDELTA: + if (op==kzdptr+0x48) kzstate++; + else *kzstate=KZSTOP; + break; + case KZSLOOP: + if (op==kzdsize+0x48 && *kzcode==0x75 && kzlen-(int8_t)kzcode[1]-3<=kzinitlen && kzlen-(int8_t)kzcode[1]>=kzxorlen) { + *ctx->virname = "Heuristics.W32.Kriz"; + free(exe_sections); + return CL_VIRUS; + } + cli_dbgmsg("kriz: loop out of bounds, corrupted sample?\n"); + kzstate++; + } + } + } + + /* W32.Magistr.A/B */ + if(SCAN_ALGO && (DCONF & PE_CONF_MAGISTR) && !dll && (nsections>1) && (exe_sections[nsections - 1].chr & 0x80000000)) { + uint32_t rsize, vsize, dam = 0; + + vsize = exe_sections[nsections - 1].uvsz; + rsize = exe_sections[nsections - 1].rsz; + if(rsize < exe_sections[nsections - 1].ursz) { + rsize = exe_sections[nsections - 1].ursz; + dam = 1; + } + + if(vsize >= 0x612c && rsize >= 0x612c && ((vsize & 0xff) == 0xec)) { + int bw = rsize < 0x7000 ? rsize : 0x7000; + const char *tbuff; + + if((tbuff = fmap_need_off_once(map, exe_sections[nsections - 1].raw + rsize - bw, 4096))) { + if(cli_memstr(tbuff, 4091, "\xe8\x2c\x61\x00\x00", 5)) { + *ctx->virname = dam ? "Heuristics.W32.Magistr.A.dam" : "Heuristics.W32.Magistr.A"; + free(exe_sections); + return CL_VIRUS; + } + } + + } else if(rsize >= 0x7000 && vsize >= 0x7000 && ((vsize & 0xff) == 0xed)) { + int bw = rsize < 0x8000 ? rsize : 0x8000; + const char *tbuff; + + if((tbuff = fmap_need_off_once(map, exe_sections[nsections - 1].raw + rsize - bw, 4096))) { + if(cli_memstr(tbuff, 4091, "\xe8\x04\x72\x00\x00", 5)) { + *ctx->virname = dam ? "Heuristics.W32.Magistr.B.dam" : "Heuristics.W32.Magistr.B"; + free(exe_sections); + return CL_VIRUS; + } + } + } + } + + /* W32.Polipos.A */ + 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) { + uint32_t jump, jold, *jumps = NULL; + const uint8_t *code; + unsigned int xsjs = 0; + + if(exe_sections[0].rsz > CLI_MAX_ALLOCATION) break; + + if(!exe_sections[0].rsz) break; + if(!(code=fmap_need_off_once(map, exe_sections[0].raw, exe_sections[0].rsz))) break; + for(i=0; i 1) continue; + jump = cli_rawaddr(exe_sections[0].rva+i+5+cli_readint32(&code[i+1]), exe_sections, nsections, &err, fsize, hdr_size); + if(err || !CLI_ISCONTAINED(exe_sections[polipos].raw, exe_sections[polipos].rsz, jump, 9)) continue; + if(xsjs % 128 == 0) { + if(xsjs == 1280) break; + if(!(jumps=(uint32_t *)cli_realloc2(jumps, (xsjs+128)*sizeof(uint32_t)))) { + free(exe_sections); + return CL_EMEM; + } + } + j=0; + for(; jvirname = "Heuristics.W32.Polipos.A"; + free(jumps); + free(exe_sections); + return CL_VIRUS; + } + } + free(jumps); + break; + } + + /* Trojan.Swizzor.Gen */ + if (SCAN_ALGO && (DCONF & PE_CONF_SWIZZOR) && nsections > 1 && fsize > 64*1024 && fsize < 4*1024*1024) { + if(dirs[2].Size) { + struct swizz_stats *stats = cli_calloc(1, sizeof(*stats)); + unsigned int m = 1000; + ret = CL_CLEAN; + + if (!stats) + ret = CL_EMEM; + else { + cli_parseres_special(EC32(dirs[2].VirtualAddress), EC32(dirs[2].VirtualAddress), map, exe_sections, nsections, fsize, hdr_size, 0, 0, &m, stats); + if ((ret = cli_detect_swizz(stats)) == CL_VIRUS) { + *ctx->virname = "Heuristics.Trojan.Swizzor.Gen"; + } + free(stats); + } + if (ret != CL_CLEAN) { + free(exe_sections); + return ret; + } + } + } + + + /* !!!!!!!!!!!!!! PACKERS START HERE !!!!!!!!!!!!!! */ + corrupted_cur = ctx->corrupted_input; + ctx->corrupted_input = 2; /* caller will reset on return */ + + + /* UPX, FSG, MEW support */ + + /* try to find the first section with physical size == 0 */ + found = 0; + if(DCONF & (PE_CONF_UPX | PE_CONF_FSG | PE_CONF_MEW)) { + for(i = 0; i < (unsigned int) nsections - 1; i++) { + if(!exe_sections[i].rsz && exe_sections[i].vsz && exe_sections[i + 1].rsz && exe_sections[i + 1].vsz) { + found = 1; + cli_dbgmsg("UPX/FSG/MEW: empty section found - assuming compression\n"); + break; + } + } + } + + /* MEW support */ + if (found && (DCONF & PE_CONF_MEW) && epsize>=16 && epbuff[0]=='\xe9') { + uint32_t fileoffset; + const char *tbuff; + + fileoffset = (vep + cli_readint32(epbuff + 1) + 5); + while (fileoffset == 0x154 || fileoffset == 0x158) { + char *src; + uint32_t offdiff, uselzma; + + cli_dbgmsg ("MEW: found MEW characteristics %08X + %08X + 5 = %08X\n", + cli_readint32(epbuff + 1), vep, cli_readint32(epbuff + 1) + vep + 5); + + if(!(tbuff = fmap_need_off_once(map, fileoffset, 0xb0))) + break; + if (fileoffset == 0x154) cli_dbgmsg("MEW: Win9x compatibility was set!\n"); + else cli_dbgmsg("MEW: Win9x compatibility was NOT set!\n"); + + if((offdiff = cli_readint32(tbuff+1) - EC32(optional_hdr32.ImageBase)) <= exe_sections[i + 1].rva || offdiff >= exe_sections[i + 1].rva + exe_sections[i + 1].raw - 4) { + cli_dbgmsg("MEW: ESI is not in proper section\n"); + break; + } + offdiff -= exe_sections[i + 1].rva; + + if(!exe_sections[i + 1].rsz) { + cli_dbgmsg("MEW: mew section is empty\n"); + break; + } + ssize = exe_sections[i + 1].vsz; + dsize = exe_sections[i].vsz; + + cli_dbgmsg("MEW: ssize %08x dsize %08x offdiff: %08x\n", ssize, dsize, offdiff); + + CLI_UNPSIZELIMITS("MEW", MAX(ssize, dsize)); + CLI_UNPSIZELIMITS("MEW", MAX(ssize + dsize, exe_sections[i + 1].rsz)); + + if (exe_sections[i + 1].rsz < offdiff + 12 || exe_sections[i + 1].rsz > ssize) { + cli_dbgmsg("MEW: Size mismatch: %08x\n", exe_sections[i + 1].rsz); + break; + } + + /* allocate needed buffer */ + if (!(src = cli_calloc (ssize + dsize, sizeof(char)))) { + free(exe_sections); + return CL_EMEM; + } + + if((bytes = fmap_readn(map, src + dsize, exe_sections[i + 1].raw, exe_sections[i + 1].rsz)) != exe_sections[i + 1].rsz) { + cli_dbgmsg("MEW: Can't read %d bytes [read: %lu]\n", exe_sections[i + 1].rsz, (unsigned long)bytes); + free(exe_sections); + free(src); + return CL_EREAD; + } + cli_dbgmsg("MEW: %u (%08x) bytes read\n", (unsigned int)bytes, (unsigned int)bytes); + + /* count offset to lzma proc, if lzma used, 0xe8 -> call */ + if (tbuff[0x7b] == '\xe8') { + if (!CLI_ISCONTAINED(exe_sections[1].rva, exe_sections[1].vsz, cli_readint32(tbuff + 0x7c) + fileoffset + 0x80, 4)) { + cli_dbgmsg("MEW: lzma proc out of bounds!\n"); + free(src); + break; /* to next unpacker in chain */ + } + uselzma = cli_readint32(tbuff + 0x7c) - (exe_sections[0].rva - fileoffset - 0x80); + } else { + uselzma = 0; + } + + CLI_UNPTEMP("MEW",(src,exe_sections,0)); + CLI_UNPRESULTS("MEW",(unmew11(src, offdiff, ssize, dsize, EC32(optional_hdr32.ImageBase), exe_sections[0].rva, uselzma, ndesc)),1,(src,0)); + break; + } + } + + if(epsize<168) { + free(exe_sections); + return CL_CLEAN; + } + + if (found || upack) { + /* Check EP for UPX vs. FSG vs. Upack */ + + /* Upack 0.39 produces 2 types of executables + * 3 sections: | 2 sections (one empty, I don't chech found if !upack, since it's in OR above): + * mov esi, value | pusha + * lodsd | call $+0x9 + * push eax | + * + * Upack 1.1/1.2 Beta produces [based on 2 samples (sUx) provided by aCaB]: + * 2 sections + * mov esi, value + * loads + * mov edi, eax + * + * Upack unknown [sample 0297729] + * 3 sections + * mov esi, value + * push [esi] + * jmp + * + */ + /* upack 0.39-3s + sample 0151477*/ + while(((upack && nsections == 3) && /* 3 sections */ + (( + epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) > min && /* mov esi */ + epbuff[5] == '\xad' && epbuff[6] == '\x50' /* lodsd; push eax */ + ) + || + /* based on 0297729 sample from aCaB */ + (epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) > min && /* mov esi */ + epbuff[5] == '\xff' && epbuff[6] == '\x36' /* push [esi] */ + ) + )) + || + ((!upack && nsections == 2) && /* 2 sections */ + (( /* upack 0.39-2s */ + epbuff[0] == '\x60' && epbuff[1] == '\xe8' && cli_readint32(epbuff+2) == 0x9 /* pusha; call+9 */ + ) + || + ( /* upack 1.1/1.2, based on 2 samples */ + epbuff[0] == '\xbe' && cli_readint32(epbuff+1) - EC32(optional_hdr32.ImageBase) < min && /* mov esi */ + cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) > 0 && + epbuff[5] == '\xad' && epbuff[6] == '\x8b' && epbuff[7] == '\xf8' /* loads; mov edi, eax */ + ) + )) + ) { + uint32_t vma, off; + int a,b,c; + + cli_dbgmsg("Upack characteristics found.\n"); + a = exe_sections[0].vsz; + b = exe_sections[1].vsz; + if (upack) { + cli_dbgmsg("Upack: var set\n"); + c = exe_sections[2].vsz; + ssize = exe_sections[0].ursz + exe_sections[0].uraw; + off = exe_sections[0].rva; + vma = EC32(optional_hdr32.ImageBase) + exe_sections[0].rva; + } else { + cli_dbgmsg("Upack: var NOT set\n"); + c = exe_sections[1].rva; + ssize = exe_sections[1].uraw; + off = 0; + vma = exe_sections[1].rva - exe_sections[1].uraw; + } + + dsize = a+b+c; + + CLI_UNPSIZELIMITS("Upack", MAX(MAX(dsize, ssize), exe_sections[1].ursz)); + + if (!CLI_ISCONTAINED(0, dsize, exe_sections[1].rva - off, exe_sections[1].ursz) || (upack && !CLI_ISCONTAINED(0, dsize, exe_sections[2].rva - exe_sections[0].rva, ssize)) || ssize > dsize) { + cli_dbgmsg("Upack: probably malformed pe-header, skipping to next unpacker\n"); + break; + } + + if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { + free(exe_sections); + return CL_EMEM; + } + + if(fmap_readn(map, dest, 0, ssize) != ssize) { + cli_dbgmsg("Upack: Can't read raw data of section 0\n"); + free(dest); + break; + } + + if(upack) memmove(dest + exe_sections[2].rva - exe_sections[0].rva, dest, ssize); + + if(fmap_readn(map, dest + exe_sections[1].rva - off, exe_sections[1].uraw, exe_sections[1].ursz) != exe_sections[1].ursz) { + cli_dbgmsg("Upack: Can't read raw data of section 1\n"); + free(dest); + break; + } + + CLI_UNPTEMP("Upack",(dest,exe_sections,0)); + CLI_UNPRESULTS("Upack",(unupack(upack, dest, dsize, epbuff, vma, ep, EC32(optional_hdr32.ImageBase), exe_sections[0].rva, ndesc)),1,(dest,0)); + break; + } + } + + + while(found && (DCONF & PE_CONF_FSG) && epbuff[0] == '\x87' && epbuff[1] == '\x25') { + const char *dst; + + /* FSG v2.0 support - thanks to aCaB ! */ + + uint32_t newesi, newedi, newebx, newedx; + + ssize = exe_sections[i + 1].rsz; + dsize = exe_sections[i].vsz; + + CLI_UNPSIZELIMITS("FSG", MAX(dsize, ssize)); + + if(ssize <= 0x19 || dsize <= ssize) { + cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); + free(exe_sections); + return CL_CLEAN; + } + + newedx = cli_readint32(epbuff + 2) - EC32(optional_hdr32.ImageBase); + if(!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newedx, 4)) { + cli_dbgmsg("FSG: xchg out of bounds (%x), giving up\n", newedx); + break; + } + + if(!exe_sections[i + 1].rsz || !(src = fmap_need_off_once(map, exe_sections[i + 1].raw, ssize))) { + cli_dbgmsg("Can't read raw data of section %d\n", i + 1); + free(exe_sections); + return CL_ESEEK; + } + + dst = src + newedx - exe_sections[i + 1].rva; + if(newedx < exe_sections[i + 1].rva || !CLI_ISCONTAINED(src, ssize, dst, 4)) { + cli_dbgmsg("FSG: New ESP out of bounds\n"); + break; + } + + newedx = cli_readint32(dst) - EC32(optional_hdr32.ImageBase); + if(!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newedx, 4)) { + cli_dbgmsg("FSG: New ESP (%x) is wrong\n", newedx); + break; + } + + dst = src + newedx - exe_sections[i + 1].rva; + if(!CLI_ISCONTAINED(src, ssize, dst, 32)) { + cli_dbgmsg("FSG: New stack out of bounds\n"); + break; + } + + newedi = cli_readint32(dst) - EC32(optional_hdr32.ImageBase); + newesi = cli_readint32(dst + 4) - EC32(optional_hdr32.ImageBase); + newebx = cli_readint32(dst + 16) - EC32(optional_hdr32.ImageBase); + newedx = cli_readint32(dst + 20); + + if(newedi != exe_sections[i].rva) { + cli_dbgmsg("FSG: Bad destination buffer (edi is %x should be %x)\n", newedi, exe_sections[i].rva); + break; + } + + if(newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].rsz) { + cli_dbgmsg("FSG: Source buffer out of section bounds\n"); + break; + } + + if(!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newebx, 16)) { + cli_dbgmsg("FSG: Array of functions out of bounds\n"); + break; + } + + newedx=cli_readint32(newebx + 12 - exe_sections[i + 1].rva + src) - EC32(optional_hdr32.ImageBase); + cli_dbgmsg("FSG: found old EP @%x\n",newedx); + + if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { + free(exe_sections); + return CL_EMEM; + } + + CLI_UNPTEMP("FSG",(dest,exe_sections,0)); + CLI_UNPRESULTSFSG2("FSG",(unfsg_200(newesi - exe_sections[i + 1].rva + src, dest, ssize + exe_sections[i + 1].rva - newesi, dsize, newedi, EC32(optional_hdr32.ImageBase), newedx, ndesc)),1,(dest,0)); + break; + } + + + while(found && (DCONF & PE_CONF_FSG) && epbuff[0] == '\xbe' && cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase) < min) { + + /* FSG support - v. 1.33 (thx trog for the many samples) */ + + int sectcnt = 0; + const char *support; + uint32_t newesi, newedi, oldep, gp, t; + struct cli_exe_section *sections; + + ssize = exe_sections[i + 1].rsz; + dsize = exe_sections[i].vsz; + + CLI_UNPSIZELIMITS("FSG", MAX(dsize, ssize)); + + if(ssize <= 0x19 || dsize <= ssize) { + cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); + free(exe_sections); + return CL_CLEAN; + } + + if(!(t = cli_rawaddr(cli_readint32(epbuff + 1) - EC32(optional_hdr32.ImageBase), NULL, 0 , &err, fsize, hdr_size)) && err ) { + cli_dbgmsg("FSG: Support data out of padding area\n"); + break; + } + + gp = exe_sections[i + 1].raw - t; + + CLI_UNPSIZELIMITS("FSG", gp); + + if(!(support = fmap_need_off_once(map, t, gp))) { + cli_dbgmsg("Can't read %d bytes from padding area\n", gp); + free(exe_sections); + return CL_EREAD; + } + + /* newebx = cli_readint32(support) - EC32(optional_hdr32.ImageBase); Unused */ + newedi = cli_readint32(support + 4) - EC32(optional_hdr32.ImageBase); /* 1st dest */ + newesi = cli_readint32(support + 8) - EC32(optional_hdr32.ImageBase); /* Source */ + + if(newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].rsz) { + cli_dbgmsg("FSG: Source buffer out of section bounds\n"); + break; + } + + if(newedi != exe_sections[i].rva) { + cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, exe_sections[i].rva); + break; + } + + /* Counting original sections */ + for(t = 12; t < gp - 4; t += 4) { + uint32_t rva = cli_readint32(support+t); + + if(!rva) + break; + + rva -= EC32(optional_hdr32.ImageBase)+1; + sectcnt++; + + if(rva % 0x1000) cli_dbgmsg("FSG: Original section %d is misaligned\n", sectcnt); + + if(rva < exe_sections[i].rva || rva - exe_sections[i].rva >= exe_sections[i].vsz) { + cli_dbgmsg("FSG: Original section %d is out of bounds\n", sectcnt); + break; + } + } + + if(t >= gp - 4 || cli_readint32(support + t)) { + break; + } + + if((sections = (struct cli_exe_section *) cli_malloc((sectcnt + 1) * sizeof(struct cli_exe_section))) == NULL) { + free(exe_sections); + return CL_EMEM; + } + + sections[0].rva = newedi; + for(t = 1; t <= (uint32_t)sectcnt; t++) + sections[t].rva = cli_readint32(support + 8 + t * 4) - 1 - EC32(optional_hdr32.ImageBase); + + if(!exe_sections[i + 1].rsz || !(src = fmap_need_off_once(map, exe_sections[i + 1].raw, ssize))) { + cli_dbgmsg("Can't read raw data of section %d\n", i); + free(exe_sections); + free(sections); + return CL_EREAD; + } + + if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { + free(exe_sections); + free(sections); + return CL_EMEM; + } + + oldep = vep + 161 + 6 + cli_readint32(epbuff+163); + cli_dbgmsg("FSG: found old EP @%x\n", oldep); + + CLI_UNPTEMP("FSG",(dest,sections,exe_sections,0)); + CLI_UNPRESULTSFSG1("FSG",(unfsg_133(src + newesi - exe_sections[i + 1].rva, dest, ssize + exe_sections[i + 1].rva - newesi, dsize, sections, sectcnt, EC32(optional_hdr32.ImageBase), oldep, ndesc)),1,(dest,sections,0)); + break; /* were done with 1.33 */ + } + + + 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 ) { + + /* FSG support - v. 1.31 */ + + int sectcnt = 0; + uint32_t gp, t = cli_rawaddr(cli_readint32(epbuff+1) - EC32(optional_hdr32.ImageBase), NULL, 0 , &err, fsize, hdr_size); + const char *support; + uint32_t newesi = cli_readint32(epbuff+11) - EC32(optional_hdr32.ImageBase); + uint32_t newedi = cli_readint32(epbuff+6) - EC32(optional_hdr32.ImageBase); + uint32_t oldep = vep - exe_sections[i + 1].rva; + struct cli_exe_section *sections; + + ssize = exe_sections[i + 1].rsz; + dsize = exe_sections[i].vsz; + + if(err) { + cli_dbgmsg("FSG: Support data out of padding area\n"); + break; + } + + if(newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].raw) { + cli_dbgmsg("FSG: Source buffer out of section bounds\n"); + break; + } + + if(newedi != exe_sections[i].rva) { + cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, exe_sections[i].rva); + break; + } + + CLI_UNPSIZELIMITS("FSG", MAX(dsize, ssize)); + + if(ssize <= 0x19 || dsize <= ssize) { + cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); + free(exe_sections); + return CL_CLEAN; + } + + gp = exe_sections[i + 1].raw - t; + + CLI_UNPSIZELIMITS("FSG", gp) + + if(!(support = fmap_need_off_once(map, t, gp))) { + cli_dbgmsg("Can't read %d bytes from padding area\n", gp); + free(exe_sections); + return CL_EREAD; + } + + /* Counting original sections */ + for(t = 0; t < gp - 2; t += 2) { + uint32_t rva = support[t]|(support[t+1]<<8); + + if (rva == 2 || rva == 1) + break; + + rva = ((rva-2)<<12) - EC32(optional_hdr32.ImageBase); + sectcnt++; + + if(rva < exe_sections[i].rva || rva - exe_sections[i].rva >= exe_sections[i].vsz) { + cli_dbgmsg("FSG: Original section %d is out of bounds\n", sectcnt); + break; + } + } + + if(t >= gp-10 || cli_readint32(support + t + 6) != 2) { + break; + } + + if((sections = (struct cli_exe_section *) cli_malloc((sectcnt + 1) * sizeof(struct cli_exe_section))) == NULL) { + free(exe_sections); + return CL_EMEM; + } + + sections[0].rva = newedi; + for(t = 0; t <= (uint32_t)sectcnt - 1; t++) { + sections[t+1].rva = (((support[t*2]|(support[t*2+1]<<8))-2)<<12)-EC32(optional_hdr32.ImageBase); + } + + if(!exe_sections[i + 1].rsz || !(src = fmap_need_off_once(map, exe_sections[i + 1].raw, ssize))) { + cli_dbgmsg("FSG: Can't read raw data of section %d\n", i); + free(exe_sections); + free(sections); + return CL_EREAD; + } + + if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { + free(exe_sections); + free(sections); + return CL_EMEM; + } + + gp = 0xda + 6*(epbuff[16]=='\xe8'); + oldep = vep + gp + 6 + cli_readint32(src+gp+2+oldep); + cli_dbgmsg("FSG: found old EP @%x\n", oldep); + + CLI_UNPTEMP("FSG",(dest,sections,exe_sections,0)); + CLI_UNPRESULTSFSG1("FSG",(unfsg_133(src + newesi - exe_sections[i + 1].rva, dest, ssize + exe_sections[i + 1].rva - newesi, dsize, sections, sectcnt, EC32(optional_hdr32.ImageBase), oldep, ndesc)),1,(dest,sections,0)); + break; /* were done with 1.31 */ + } + + + if(found && (DCONF & PE_CONF_UPX)) { + + /* UPX support */ + + /* we assume (i + 1) is UPX1 */ + ssize = exe_sections[i + 1].rsz; + dsize = exe_sections[i].vsz + exe_sections[i + 1].vsz; + + CLI_UNPSIZELIMITS("UPX", MAX(dsize, ssize)); + + if(ssize <= 0x19 || dsize <= ssize || dsize > CLI_MAX_ALLOCATION ) { + cli_dbgmsg("UPX: Size mismatch or dsize too big (ssize: %d, dsize: %d)\n", ssize, dsize); + free(exe_sections); + return CL_CLEAN; + } + + if(!exe_sections[i + 1].rsz || !(src = fmap_need_off_once(map, exe_sections[i + 1].raw, ssize))) { + cli_dbgmsg("UPX: Can't read raw data of section %d\n", i+1); + free(exe_sections); + return CL_EREAD; + } + + if((dest = (char *) cli_calloc(dsize + 8192, sizeof(char))) == NULL) { + free(exe_sections); + return CL_EMEM; + } + + /* try to detect UPX code */ + if(cli_memstr(UPX_NRV2B, 24, epbuff + 0x69, 13) || cli_memstr(UPX_NRV2B, 24, epbuff + 0x69 + 8, 13)) { + cli_dbgmsg("UPX: Looks like a NRV2B decompression routine\n"); + upxfn = upx_inflate2b; + } else if(cli_memstr(UPX_NRV2D, 24, epbuff + 0x69, 13) || cli_memstr(UPX_NRV2D, 24, epbuff + 0x69 + 8, 13)) { + cli_dbgmsg("UPX: Looks like a NRV2D decompression routine\n"); + upxfn = upx_inflate2d; + } else if(cli_memstr(UPX_NRV2E, 24, epbuff + 0x69, 13) || cli_memstr(UPX_NRV2E, 24, epbuff + 0x69 + 8, 13)) { + cli_dbgmsg("UPX: Looks like a NRV2E decompression routine\n"); + upxfn = upx_inflate2e; + } + + if(upxfn) { + int skew = cli_readint32(epbuff + 2) - EC32(optional_hdr32.ImageBase) - exe_sections[i + 1].rva; + + if(epbuff[1] != '\xbe' || skew <= 0 || skew > 0xfff) { /* FIXME: legit skews?? */ + skew = 0; + if(upxfn(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) >= 0) + upx_success = 1; + + } else { + cli_dbgmsg("UPX: UPX1 seems skewed by %d bytes\n", skew); + if(upxfn(src + skew, ssize - skew, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep-skew) >= 0 || upxfn(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) >= 0) + upx_success = 1; + } + + if(upx_success) + cli_dbgmsg("UPX: Successfully decompressed\n"); + else + cli_dbgmsg("UPX: Preferred decompressor failed\n"); + } + + if(!upx_success && upxfn != upx_inflate2b) { + if(upx_inflate2b(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2b(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) { + + cli_dbgmsg("UPX: NRV2B decompressor failed\n"); + } else { + upx_success = 1; + cli_dbgmsg("UPX: Successfully decompressed with NRV2B\n"); + } + } + + if(!upx_success && upxfn != upx_inflate2d) { + if(upx_inflate2d(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2d(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) { + + cli_dbgmsg("UPX: NRV2D decompressor failed\n"); + } else { + upx_success = 1; + cli_dbgmsg("UPX: Successfully decompressed with NRV2D\n"); + } + } + + if(!upx_success && upxfn != upx_inflate2e) { + if(upx_inflate2e(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2e(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) { + cli_dbgmsg("UPX: NRV2E decompressor failed\n"); + } else { + upx_success = 1; + cli_dbgmsg("UPX: Successfully decompressed with NRV2E\n"); + } + } + + if(cli_memstr(UPX_LZMA2, 20, epbuff + 0x2f, 20)) { + uint32_t strictdsize=cli_readint32(epbuff+0x21), skew = 0; + if(ssize > 0x15 && epbuff[0] == '\x60' && epbuff[1] == '\xbe') { + skew = cli_readint32(epbuff+2) - exe_sections[i + 1].rva - optional_hdr32.ImageBase; + if(skew!=0x15) skew = 0; + } + if(strictdsize<=dsize) + upx_success = upx_inflatelzma(src+skew, ssize-skew, dest, &strictdsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) >=0; + } else if (cli_memstr(UPX_LZMA1, 20, epbuff + 0x39, 20)) { + uint32_t strictdsize=cli_readint32(epbuff+0x2b), skew = 0; + if(ssize > 0x15 && epbuff[0] == '\x60' && epbuff[1] == '\xbe') { + skew = cli_readint32(epbuff+2) - exe_sections[i + 1].rva - optional_hdr32.ImageBase; + if(skew!=0x15) skew = 0; + } + if(strictdsize<=dsize) + upx_success = upx_inflatelzma(src+skew, ssize-skew, dest, &strictdsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) >=0; + } + + if(!upx_success) { + cli_dbgmsg("UPX: All decompressors failed\n"); + free(dest); + } + } + + if(upx_success) { + free(exe_sections); + + CLI_UNPTEMP("UPX/FSG",(dest,0)); + + if((unsigned int) write(ndesc, dest, dsize) != dsize) { + cli_dbgmsg("UPX/FSG: Can't write %d bytes\n", dsize); + free(tempfile); + free(dest); + close(ndesc); + return CL_EWRITE; + } + + free(dest); + lseek(ndesc, 0, SEEK_SET); + + if(ctx->engine->keeptmp) + cli_dbgmsg("UPX/FSG: Decompressed data saved in %s\n", tempfile); + + cli_dbgmsg("***** Scanning decompressed file *****\n"); + SHA_OFF; + if((ret = cli_magic_scandesc(ndesc, ctx)) == CL_VIRUS) { + close(ndesc); + CLI_TMPUNLK(); + free(tempfile); + SHA_RESET; + return CL_VIRUS; + } + + SHA_RESET; + close(ndesc); + CLI_TMPUNLK(); + free(tempfile); return ret; } + + + /* Petite */ + + if(epsize<200) { + free(exe_sections); + return CL_CLEAN; + } + + found = 2; + + if(epbuff[0] != '\xb8' || (uint32_t) cli_readint32(epbuff + 1) != exe_sections[nsections - 1].rva + EC32(optional_hdr32.ImageBase)) { + if(nsections < 2 || epbuff[0] != '\xb8' || (uint32_t) cli_readint32(epbuff + 1) != exe_sections[nsections - 2].rva + EC32(optional_hdr32.ImageBase)) + found = 0; + else + found = 1; + } + + if(found && (DCONF & PE_CONF_PETITE)) { + cli_dbgmsg("Petite: v2.%d compression detected\n", found); + + if(cli_readint32(epbuff + 0x80) == 0x163c988d) { + cli_dbgmsg("Petite: level zero compression is not supported yet\n"); + } else { + dsize = max - min; + + CLI_UNPSIZELIMITS("Petite", dsize); + + if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { + cli_dbgmsg("Petite: Can't allocate %d bytes\n", dsize); + free(exe_sections); + return CL_EMEM; + } + + for(i = 0 ; i < nsections; i++) { + if(exe_sections[i].raw) { + if(!exe_sections[i].rsz || fmap_readn(map, dest + exe_sections[i].rva - min, exe_sections[i].raw, exe_sections[i].ursz) != exe_sections[i].ursz) { + free(exe_sections); + free(dest); + return CL_CLEAN; + } + } + } + + CLI_UNPTEMP("Petite",(dest,exe_sections,0)); + CLI_UNPRESULTS("Petite",(petite_inflate2x_1to9(dest, min, max - min, exe_sections, nsections - (found == 1 ? 1 : 0), EC32(optional_hdr32.ImageBase),vep, ndesc, found, EC32(optional_hdr32.DataDirectory[2].VirtualAddress),EC32(optional_hdr32.DataDirectory[2].Size))),0,(dest,0)); + } + } + + /* PESpin 1.1 */ + + if((DCONF & PE_CONF_PESPIN) && nsections > 1 && + vep >= exe_sections[nsections - 1].rva && + vep < exe_sections[nsections - 1].rva + exe_sections[nsections - 1].rsz - 0x3217 - 4 && + memcmp(epbuff+4, "\xe8\x00\x00\x00\x00\x8b\x1c\x24\x83\xc3", 10) == 0) { + + char *spinned; + + CLI_UNPSIZELIMITS("PEspin", fsize); + + if((spinned = (char *) cli_malloc(fsize)) == NULL) { + free(exe_sections); + return CL_EMEM; + } + + if((size_t) fmap_readn(map, spinned, 0, fsize) != fsize) { + cli_dbgmsg("PESpin: Can't read %lu bytes\n", (unsigned long)fsize); + free(spinned); + free(exe_sections); + return CL_EREAD; + } + + CLI_UNPTEMP("PESpin",(spinned,exe_sections,0)); + CLI_UNPRESULTS_("PEspin",SPINCASE(),(unspin(spinned, fsize, exe_sections, nsections - 1, vep, ndesc, ctx)),0,(spinned,0)); + } + + + /* yC 1.3 & variants */ + if((DCONF & PE_CONF_YC) && nsections > 1 && + (EC32(optional_hdr32.AddressOfEntryPoint) == exe_sections[nsections - 1].rva + 0x60)) { + + uint32_t ecx = 0; + int16_t offset; + + /* yC 1.3 */ + if (!memcmp(epbuff, "\x55\x8B\xEC\x53\x56\x57\x60\xE8\x00\x00\x00\x00\x5D\x81\xED", 15) && + !memcmp(epbuff+0x26, "\x8D\x3A\x8B\xF7\x33\xC0\xEB\x04\x90\xEB\x01\xC2\xAC", 13) && + ((uint8_t)epbuff[0x13] == 0xB9) && + ((uint16_t)(cli_readint16(epbuff+0x18)) == 0xE981) && + !memcmp(epbuff+0x1e,"\x8B\xD5\x81\xC2", 4)) { + + offset = 0; + if (0x6c - cli_readint32(epbuff+0xf) + cli_readint32(epbuff+0x22) == 0xC6) + ecx = cli_readint32(epbuff+0x14) - cli_readint32(epbuff+0x1a); + } + + /* yC 1.3 variant */ + if (!ecx && !memcmp(epbuff, "\x55\x8B\xEC\x83\xEC\x40\x53\x56\x57", 9) && + !memcmp(epbuff+0x17, "\xe8\x00\x00\x00\x00\x5d\x81\xed", 8) && + ((uint8_t)epbuff[0x23] == 0xB9)) { + + offset = 0x10; + if (0x6c - cli_readint32(epbuff+0x1f) + cli_readint32(epbuff+0x32) == 0xC6) + ecx = cli_readint32(epbuff+0x24) - cli_readint32(epbuff+0x2a); + } + + /* yC 1.x/modified */ + if (!ecx && !memcmp(epbuff, "\x60\xe8\x00\x00\x00\x00\x5d\x81\xed",9) && + ((uint8_t)epbuff[0xd] == 0xb9) && + ((uint16_t)cli_readint16(epbuff + 0x12)== 0xbd8d) && + !memcmp(epbuff+0x18, "\x8b\xf7\xac", 3)) { + + offset = -0x18; + if (0x66 - cli_readint32(epbuff+0x9) + cli_readint32(epbuff+0x14) == 0xae) + ecx = cli_readint32(epbuff+0xe); + } + + if (ecx > 0x800 && ecx < 0x2000 && + !memcmp(epbuff+0x63+offset, "\xaa\xe2\xcc", 3) && + (fsize >= exe_sections[nsections-1].raw + 0xC6 + ecx + offset)) { + + char *spinned; + + if((spinned = (char *) cli_malloc(fsize)) == NULL) { + free(exe_sections); + return CL_EMEM; + } + + if((size_t) fmap_readn(map, spinned, 0, fsize) != fsize) { + cli_dbgmsg("yC: Can't read %lu bytes\n", (unsigned long)fsize); + free(spinned); + free(exe_sections); + return CL_EREAD; + } + + cli_dbgmsg("%d,%d,%d,%d\n", nsections-1, e_lfanew, ecx, offset); + CLI_UNPTEMP("yC",(spinned,exe_sections,0)); + CLI_UNPRESULTS("yC",(yc_decrypt(spinned, fsize, exe_sections, nsections-1, e_lfanew, ndesc, ecx, offset)),0,(spinned,0)); + } + } + + /* WWPack */ + + while ((DCONF & PE_CONF_WWPACK) && nsections > 1 && + vep == exe_sections[nsections - 1].rva && + memcmp(epbuff, "\x53\x55\x8b\xe8\x33\xdb\xeb", 7) == 0 && + memcmp(epbuff+0x68, "\xe8\x00\x00\x00\x00\x58\x2d\x6d\x00\x00\x00\x50\x60\x33\xc9\x50\x58\x50\x50", 19) == 0) { + uint32_t head = exe_sections[nsections - 1].raw; + uint8_t *packer; + char *src; + + ssize = 0; + for(i=0 ; ; i++) { + if(exe_sections[i].rawssize) break; + + CLI_UNPSIZELIMITS("WWPack", ssize); + + if(!(src=(char *)cli_calloc(ssize, sizeof(char)))) { + free(exe_sections); + return CL_EMEM; + } + if((size_t) fmap_readn(map, src, 0, head) != head) { + cli_dbgmsg("WWPack: Can't read %d bytes from headers\n", head); + free(src); + free(exe_sections); + return CL_EREAD; + } + for(i = 0 ; i < (unsigned int)nsections-1; i++) { + if(!exe_sections[i].rsz) continue; + if(!CLI_ISCONTAINED(src, ssize, src+exe_sections[i].rva, exe_sections[i].rsz)) break; + if(fmap_readn(map, src+exe_sections[i].rva, exe_sections[i].raw, exe_sections[i].rsz)!=exe_sections[i].rsz) break; + } + if(i+1!=nsections) { + cli_dbgmsg("WWpack: Probably hacked/damaged file.\n"); + free(src); + break; + } + if((packer = (uint8_t *) cli_calloc(exe_sections[nsections - 1].rsz, sizeof(char))) == NULL) { + free(src); + free(exe_sections); + return CL_EMEM; + } + if(!exe_sections[nsections - 1].rsz || (size_t) fmap_readn(map, packer, exe_sections[nsections - 1].raw, exe_sections[nsections - 1].rsz) != exe_sections[nsections - 1].rsz) { + cli_dbgmsg("WWPack: Can't read %d bytes from wwpack sect\n", exe_sections[nsections - 1].rsz); + free(src); + free(packer); + free(exe_sections); + return CL_EREAD; + } + + CLI_UNPTEMP("WWPack",(src,packer,exe_sections,0)); + CLI_UNPRESULTS("WWPack",(wwunpack((uint8_t *)src, ssize, packer, exe_sections, nsections-1, e_lfanew, ndesc)),0,(src,packer,0)); + break; + } + + + /* ASPACK support */ + while((DCONF & PE_CONF_ASPACK) && ep+58+0x70e < fsize && !memcmp(epbuff,"\x60\xe8\x03\x00\x00\x00\xe9\xeb",8)) { + char *src; + + if(epsize<0x3bf || memcmp(epbuff+0x3b9, "\x68\x00\x00\x00\x00\xc3",6)) break; + ssize = 0; + for(i=0 ; i< nsections ; i++) + if(ssizecorrupted_input = corrupted_cur; + + /* Bytecode BC_PE_UNPACKER hook */ + bc_ctx = cli_bytecode_context_alloc(); + if (!bc_ctx) { + cli_errmsg("cli_scanpe: can't allocate memory for bc_ctx\n"); + return CL_EMEM; + } + cli_bytecode_context_setpe(bc_ctx, &pedata, exe_sections); + cli_bytecode_context_setctx(bc_ctx, ctx); + ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_UNPACKER, map, ctx->virname); + switch (ret) { + case CL_VIRUS: + free(exe_sections); + cli_bytecode_context_destroy(bc_ctx); + return CL_VIRUS; + case CL_SUCCESS: + ndesc = cli_bytecode_context_getresult_file(bc_ctx, &tempfile); + cli_bytecode_context_destroy(bc_ctx); + if (ndesc != -1 && tempfile) { + CLI_UNPRESULTS("bytecode PE hook", 1, 1, (0)); + } + break; + default: + cli_bytecode_context_destroy(bc_ctx); + } + + free(exe_sections); + return CL_CLEAN; +} + +int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo) +{ + uint16_t e_magic; /* DOS signature ("MZ") */ + uint32_t e_lfanew; /* address of new exe header */ + /* Obsolete - see below + uint32_t min = 0, max = 0; + */ + struct pe_image_file_hdr file_hdr; + union { + struct pe_image_optional_hdr64 opt64; + struct pe_image_optional_hdr32 opt32; + } pe_opt; + struct pe_image_section_hdr *section_hdr; + int i; + unsigned int err, pe_plus = 0; + uint32_t valign, falign, hdr_size; + size_t fsize; + ssize_t at; + struct pe_image_data_dir *dirs; + + cli_dbgmsg("in cli_peheader\n"); + + fsize = map->len - peinfo->offset; + if(fmap_readn(map, &e_magic, peinfo->offset, sizeof(e_magic)) != sizeof(e_magic)) { + cli_dbgmsg("Can't read DOS signature\n"); + return CL_CLEAN; + } + + if(EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE && EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE_OLD) { + cli_dbgmsg("Invalid DOS signature\n"); + return -1; + } + + if(fmap_readn(map, &e_lfanew, peinfo->offset + 58 + sizeof(e_magic), sizeof(e_lfanew)) != sizeof(e_lfanew)) { + /* truncated header? */ + return -1; + } + + e_lfanew = EC32(e_lfanew); + if(!e_lfanew) { + cli_dbgmsg("Not a PE file\n"); + return -1; + } + + if(fmap_readn(map, &file_hdr, peinfo->offset + e_lfanew, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) { + /* bad information in e_lfanew - probably not a PE file */ + cli_dbgmsg("Can't read file header\n"); + return -1; + } + + if(EC32(file_hdr.Magic) != PE_IMAGE_NT_SIGNATURE) { + cli_dbgmsg("Invalid PE signature (probably NE file)\n"); + return -1; + } + + if ( (peinfo->nsections = EC16(file_hdr.NumberOfSections)) < 1 || peinfo->nsections > 96 ) return -1; + + if (EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) { + cli_dbgmsg("SizeOfOptionalHeader too small\n"); + return -1; + } + + at = peinfo->offset + e_lfanew + sizeof(struct pe_image_file_hdr); + if(fmap_readn(map, &optional_hdr32, at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) { + cli_dbgmsg("Can't read optional file header\n"); + return -1; + } + at += sizeof(struct pe_image_optional_hdr32); + + if(EC16(optional_hdr64.Magic)==PE32P_SIGNATURE) { /* PE+ */ + if(EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr64)) { + cli_dbgmsg("Incorrect SizeOfOptionalHeader for PE32+\n"); + return -1; + } + if(fmap_readn(map, &optional_hdr32 + 1, at, sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) { + cli_dbgmsg("Can't read optional file header\n"); + return -1; + } + at += sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32); + hdr_size = EC32(optional_hdr64.SizeOfHeaders); + pe_plus=1; + } else { /* PE */ + if (EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr32)) { + /* Seek to the end of the long header */ + at += EC16(file_hdr.SizeOfOptionalHeader)-sizeof(struct pe_image_optional_hdr32); + } + hdr_size = EC32(optional_hdr32.SizeOfHeaders); + } + + valign = (pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment); + falign = (pe_plus)?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment); + + peinfo->hdr_size = hdr_size = PESALIGN(hdr_size, valign); + + peinfo->section = (struct cli_exe_section *) cli_calloc(peinfo->nsections, sizeof(struct cli_exe_section)); + + if(!peinfo->section) { + cli_dbgmsg("Can't allocate memory for section headers\n"); + return -1; + } + + section_hdr = (struct pe_image_section_hdr *) cli_calloc(peinfo->nsections, sizeof(struct pe_image_section_hdr)); + + if(!section_hdr) { + cli_dbgmsg("Can't allocate memory for section headers\n"); + free(peinfo->section); + peinfo->section = NULL; + return -1; + } + + if(fmap_readn(map, section_hdr, at, peinfo->nsections * sizeof(struct pe_image_section_hdr)) != peinfo->nsections * sizeof(struct pe_image_section_hdr)) { + cli_dbgmsg("Can't read section header\n"); + cli_dbgmsg("Possibly broken PE file\n"); + free(section_hdr); + free(peinfo->section); + peinfo->section = NULL; + return -1; + } + at += sizeof(struct pe_image_section_hdr)*peinfo->nsections; + + for(i = 0; falign!=0x200 && insections; i++) { + /* file alignment fallback mode - blah */ + if (falign && section_hdr[i].SizeOfRawData && EC32(section_hdr[i].PointerToRawData)%falign && !(EC32(section_hdr[i].PointerToRawData)%0x200)) { + falign = 0x200; + } + } + + for(i = 0; i < peinfo->nsections; i++) { + peinfo->section[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign); + peinfo->section[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign); + peinfo->section[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign); + peinfo->section[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign); + + if (!peinfo->section[i].vsz && peinfo->section[i].rsz) + peinfo->section[i].vsz=PESALIGN(EC32(section_hdr[i].SizeOfRawData), valign); + + if (peinfo->section[i].rsz && !CLI_ISCONTAINED(0, (uint32_t) fsize, peinfo->section[i].raw, peinfo->section[i].rsz)) + peinfo->section[i].rsz = (fsize - peinfo->section[i].raw)*(fsize>peinfo->section[i].raw); + } + + if(pe_plus) { + peinfo->ep = EC32(optional_hdr64.AddressOfEntryPoint); + dirs = optional_hdr64.DataDirectory; + } else { + peinfo->ep = EC32(optional_hdr32.AddressOfEntryPoint); + dirs = optional_hdr32.DataDirectory; + } + + if(!(peinfo->ep = cli_rawaddr(peinfo->ep, peinfo->section, peinfo->nsections, &err, fsize, hdr_size)) && err) { + cli_dbgmsg("Broken PE file\n"); + free(section_hdr); + free(peinfo->section); + peinfo->section = NULL; + return -1; + } + + if(EC16(file_hdr.Characteristics) & 0x2000 || !dirs[2].Size) + peinfo->res_addr = 0; + else + peinfo->res_addr = EC32(dirs[2].VirtualAddress); + + while(dirs[2].Size) { + struct vinfo_list vlist; + const uint8_t *vptr, *baseptr; + uint32_t rva, res_sz; + + memset(&vlist, 0, sizeof(vlist)); + findres(0x10, 0xffffffff, EC32(dirs[2].VirtualAddress), map, peinfo->section, peinfo->nsections, hdr_size, versioninfo_cb, &vlist); + if(!vlist.count) break; /* No version_information */ + if(cli_hashset_init(&peinfo->vinfo, 32, 80)) { + cli_errmsg("cli_peheader: Unable to init vinfo hashset\n"); + free(section_hdr); + free(peinfo->section); + peinfo->section = NULL; + return -1; + } + + err = 0; + for(i=0; isection, peinfo->nsections, &err, fsize, hdr_size); + if(err) + continue; + + if(!(vptr = fmap_need_off_once(map, rva, 16))) + continue; + + baseptr = vptr - rva; + /* parse resource */ + rva = cli_readint32(vptr); /* ptr to version_info */ + res_sz = cli_readint32(vptr+4); /* sizeof(resource) */ + rva = cli_rawaddr(rva, peinfo->section, peinfo->nsections, &err, fsize, hdr_size); + if(err) + continue; + if(!(vptr = fmap_need_off_once(map, rva, res_sz))) + continue; + + while(res_sz>4) { /* look for version_info - NOT RESUMABLE (expecting exactly one versioninfo) */ + uint32_t vinfo_sz, vinfo_val_sz, got_varfileinfo = 0; + + vinfo_sz = vinfo_val_sz = cli_readint32(vptr); + vinfo_sz &= 0xffff; + if(vinfo_sz > res_sz) + break; /* the content is larger than the container */ + + vinfo_val_sz >>= 16; + if(vinfo_sz <= 6 + 0x20 + 2 + 0x34 || + vinfo_val_sz != 0x34 || + memcmp(vptr+6, "V\0S\0_\0V\0E\0R\0S\0I\0O\0N\0_\0I\0N\0F\0O\0\0\0", 0x20) || + cli_readint32(vptr + 0x28) != 0xfeef04bd) { + /* - there should be enough room for the header(6), the key "VS_VERSION_INFO"(20), the padding(2) and the value(34) + * - the value should be sizeof(fixedfileinfo) + * - the key should match + * - there should be some proper magic for fixedfileinfo */ + break; /* there's no point in looking further */ + } + + /* move to the end of fixedfileinfo where the child elements are located */ + vptr += 6 + 0x20 + 2 + 0x34; + vinfo_sz -= 6 + 0x20 + 2 + 0x34; + + while(vinfo_sz > 6) { /* look for stringfileinfo - NOT RESUMABLE (expecting at most one stringfileinfo) */ + uint32_t sfi_sz = cli_readint32(vptr) & 0xffff; + + if(sfi_sz > vinfo_sz) + break; /* the content is larger than the container */ + + if(!got_varfileinfo && sfi_sz > 6 + 0x18 && !memcmp(vptr+6, "V\0a\0r\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0", 0x18)) { + /* skip varfileinfo as it sometimes appear before stringtableinfo */ + vptr += sfi_sz; + vinfo_sz -= sfi_sz; + got_varfileinfo = 1; + continue; + } + + if(sfi_sz <= 6 + 0x1e || memcmp(vptr+6, "S\0t\0r\0i\0n\0g\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0", 0x1e)) { + /* - there should be enough room for the header(6) and the key "StringFileInfo"(1e) + * - the key should match */ + break; /* this is an implicit hard fail: parent is not resumable */ + } + + /* move to the end of stringfileinfo where the child elements are located */ + vptr += 6 + 0x1e; + sfi_sz -= 6 + 0x1e; + + while(sfi_sz > 6) { /* enum all stringtables - RESUMABLE */ + uint32_t st_sz = cli_readint32(vptr) & 0xffff; + const uint8_t *next_vptr = vptr + st_sz; + uint32_t next_sfi_sz = sfi_sz - st_sz; + + if(st_sz > sfi_sz || st_sz <= 24) { + /* - the content is larger than the container + - there's no room for a stringtables (headers(6) + key(16) + padding(2)) */ + break; /* this is an implicit hard fail: parent is not resumable */ + } + + /* move to the end of stringtable where the child elements are located */ + vptr += 24; + st_sz -= 24; + + while(st_sz > 6) { /* enum all strings - RESUMABLE */ + uint32_t s_sz, s_key_sz, s_val_sz; + + s_sz = (cli_readint32(vptr) & 0xffff) + 3; + s_sz &= ~3; + if(s_sz > st_sz || s_sz <= 6 + 2 + 8) { + /* - the content is larger than the container + * - there's no room for a minimal string + * - there's no room for the value */ + st_sz = 0; + sfi_sz = 0; + break; /* force a hard fail */ + } + + /* ~wcstrlen(key) */ + for(s_key_sz = 6; s_key_sz+1 < s_sz; s_key_sz += 2) { + if(vptr[s_key_sz] || vptr[s_key_sz+1]) continue; + s_key_sz += 2; + break; + } + + s_key_sz += 3; + s_key_sz &= ~3; + + if(s_key_sz >= s_sz) { + /* key overflow */ + vptr += s_sz; + st_sz -= s_sz; + continue; + } + + s_val_sz = s_sz - s_key_sz; + s_key_sz -= 6; + + if(s_val_sz <= 2) { + /* skip unset value */ + vptr += s_sz; + st_sz -= s_sz; + continue; + } + + if(cli_hashset_addkey(&peinfo->vinfo, (uint32_t)(vptr - baseptr + 6))) { + cli_errmsg("cli_peheader: Unable to add rva to vinfo hashset\n"); + cli_hashset_destroy(&peinfo->vinfo); + free(section_hdr); + free(peinfo->section); + peinfo->section = NULL; + return -1; + } + + if(cli_debug_flag) { + char *k, *v, *s; + + /* FIXME: skip too long strings */ + k = cli_utf16toascii((const char*)vptr + 6, s_key_sz); + if(k) { + v = cli_utf16toascii((const char*)vptr + s_key_sz + 6, s_val_sz); + if(v) { + s = cli_str2hex((const char*)vptr + 6, s_key_sz + s_val_sz - 6); + if(s) { + cli_dbgmsg("VersionInfo (%x): '%s'='%s' - VI:%s\n", (uint32_t)(vptr - baseptr + 6), k, v, s); + free(s); + } + free(v); + } + free(k); + } + } + vptr += s_sz; + st_sz -= s_sz; + } /* enum all strings - RESUMABLE */ + vptr = next_vptr; + sfi_sz = next_sfi_sz * (sfi_sz != 0); + } /* enum all stringtables - RESUMABLE */ + break; + } /* look for stringfileinfo - NOT RESUMABLE */ + break; + } /* look for version_info - NOT RESUMABLE */ + } /* enum all version_information res - RESUMABLE */ + break; + } /* while(dirs[2].Size) */ + + free(section_hdr); + return 0; } diff --git a/libclamav/pe_icons.c b/libclamav/pe_icons.c index fb822392c..8fb21c34f 100644 --- a/libclamav/pe_icons.c +++ b/libclamav/pe_icons.c @@ -88,7 +88,7 @@ int cli_scanicon(icon_groupset *set, uint32_t resdir_rva, cli_ctx *ctx, struct c findres(14, 0xffffffff, resdir_rva, map, exe_sections, nsections, hdr_size, groupicon_cb, &gicons); for(curicon=0; curiconlen, hdr_size), 16); + const uint8_t *grp = fmap_need_off_once(map, cli_rawaddr(gicons.rvas[curicon], exe_sections, nsections, &err, map->len, hdr_size), 16); if(grp && !err) { uint32_t gsz = cli_readint32(grp + 4); if(gsz>6) { @@ -1192,9 +1192,10 @@ static int parseicon(icon_groupset *set, uint32_t rva, cli_ctx *ctx, struct cli_ unsigned int important; } bmphdr; struct icomtr metrics; - unsigned char *rawimage; + const unsigned char *rawimage; const char *tempd; - uint32_t *palette = NULL, *imagedata; + const uint32_t *palette = NULL; + uint32_t *imagedata; unsigned int scanlinesz, andlinesz; unsigned int width, height, depth, x, y; unsigned int err, scalemode = 2, enginesize; @@ -1210,12 +1211,12 @@ static int parseicon(icon_groupset *set, uint32_t rva, cli_ctx *ctx, struct cli_ icoff = cli_rawaddr(rva, exe_sections, nsections, &err, map->len, hdr_size); /* read the bitmap header */ - if(err || !(imagedata = fmap_need_off_once(map, icoff, 4))) { + if(err || !(rawimage = fmap_need_off_once(map, icoff, 4))) { cli_dbgmsg("parseicon: offset to icon is out of file\n"); return CL_SUCCESS; } - rva = cli_readint32(imagedata); + rva = cli_readint32(rawimage); icoff = cli_rawaddr(rva, exe_sections, nsections, &err, map->len, hdr_size); if(err || fmap_readn(map, &bmphdr, icoff, sizeof(bmphdr)) != sizeof(bmphdr)) { cli_dbgmsg("parseicon: bmp header is out of file\n"); diff --git a/libclamav/scanners.c b/libclamav/scanners.c index 4f614d8ae..3fbc52769 100644 --- a/libclamav/scanners.c +++ b/libclamav/scanners.c @@ -488,7 +488,7 @@ static int cli_scangzip(cli_ctx *ctx) while (at < map->len) { unsigned int bytes = MIN(map->len - at, map->pgsz); - if(!(z.next_in = fmap_need_off_once(map, at, bytes))) { + if(!(z.next_in = (void*)fmap_need_off_once(map, at, bytes))) { cli_dbgmsg("GZip: Can't read %u bytes @ %lu.\n", bytes, (long unsigned)at); inflateEnd(&z); close(fd); @@ -1050,7 +1050,7 @@ static int cli_scanhtml(cli_ctx *ctx) static int cli_scanscript(cli_ctx *ctx) { - unsigned char *buff; + const unsigned char *buff; unsigned char* normalized; struct text_norm_state state; char *tmpname = NULL; @@ -1147,7 +1147,8 @@ static int cli_scanscript(cli_ctx *ctx) static int cli_scanhtml_utf16(cli_ctx *ctx) { - char *tempname, *decoded, *buff; + char *tempname, *decoded; + const char *buff; int ret = CL_CLEAN, fd, bytes; size_t at = 0; fmap_t *map = *ctx->fmap; @@ -1640,7 +1641,7 @@ static int cli_scanembpe(cli_ctx *ctx, off_t offset) { int fd, bytes, ret = CL_CLEAN; unsigned long int size = 0, todo; - char *buff; + const char *buff; char *tmpname; fmap_t *map = *ctx->fmap; unsigned int corrupted_input; @@ -2261,7 +2262,7 @@ static int magic_scandesc(cli_ctx *ctx, cli_file_t type) break; } do { - char *b; + const char *b; len = 0; b = fmap_need_off_once_len(*ctx->fmap, pos, BUFSIZ, &len); diff --git a/libclamav/sis.c b/libclamav/sis.c index a3074723f..908331aaf 100644 --- a/libclamav/sis.c +++ b/libclamav/sis.c @@ -283,7 +283,7 @@ static int real_scansis(cli_ctx *ctx, const char *tmpd) { return CL_CLEAN; } for (i = 0; i< sis.langs; i++) - alangs[i]=EC32(llangs[i])=0xe1) return 1; @@ -170,7 +170,7 @@ uint32_t unspack(char *start_of_stuff, char *dest, cli_ctx *ctx, uint32_t rva, u } -uint32_t very_real_unpack(uint16_t *table, uint32_t tablesz, uint32_t tre, uint32_t allocsz, uint32_t firstbyte, char *src, uint32_t ssize, char *dst, uint32_t dsize) { +uint32_t very_real_unpack(uint16_t *table, uint32_t tablesz, uint32_t tre, uint32_t allocsz, uint32_t firstbyte, const char *src, uint32_t ssize, char *dst, uint32_t dsize) { struct UNSP read_struct; uint32_t i = (0x300<<((allocsz+tre)&0xff)) + 0x736; diff --git a/libclamav/unsp.h b/libclamav/unsp.h index fc8e8385d..59b432958 100644 --- a/libclamav/unsp.h +++ b/libclamav/unsp.h @@ -25,8 +25,8 @@ #include "others.h" struct UNSP { - char *src_curr; - char *src_end; + const char *src_curr; + const char *src_end; uint32_t bitmap; uint32_t oldval; int error; @@ -35,8 +35,8 @@ struct UNSP { char *table; }; -uint32_t unspack(char *, char *, cli_ctx *, uint32_t, uint32_t, uint32_t, int); -uint32_t very_real_unpack(uint16_t *, uint32_t, uint32_t, uint32_t, uint32_t, char *, uint32_t, char *, uint32_t); +uint32_t unspack(const char *, char *, cli_ctx *, uint32_t, uint32_t, uint32_t, int); +uint32_t very_real_unpack(uint16_t *, uint32_t, uint32_t, uint32_t, uint32_t,const char *, uint32_t, char *, uint32_t); uint32_t get_byte(struct UNSP *); int getbit_from_table(uint16_t *, struct UNSP *); uint32_t get_100_bits_from_tablesize(uint16_t *, struct UNSP *, uint32_t); diff --git a/libclamav/unzip.c b/libclamav/unzip.c index 0b3ce8437..caa752f91 100644 --- a/libclamav/unzip.c +++ b/libclamav/unzip.c @@ -56,7 +56,7 @@ static int wrap_inflateinit2(void *a, int b) { return inflateInit2(a, b); } -static int unz(uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, uint16_t flags, unsigned int *fu, cli_ctx *ctx, char *tmpd) { +static int unz(const uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, uint16_t flags, unsigned int *fu, cli_ctx *ctx, char *tmpd) { char name[1024], obuf[BUFSIZ]; char *tempfile = name; int of, ret=CL_CLEAN; @@ -134,7 +134,7 @@ static int unz(uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, ui memset(&strm, 0, sizeof(strm)); - *next_in = src; + *next_in = (void*) src; *next_out = obuf; *avail_in = csize; *avail_out = sizeof(obuf); @@ -216,7 +216,7 @@ static int unz(uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, ui case ALG_IMPLODE: { struct xplstate strm; - strm.next_in = src; + strm.next_in = (void*)src; strm.next_out = (uint8_t *)obuf; strm.avail_in = csize; strm.avail_out = sizeof(obuf); @@ -297,8 +297,8 @@ static int unz(uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, ui return ret; } -static unsigned int lhdr(fmap_t *map, uint32_t loff,uint32_t zsize, unsigned int *fu, unsigned int fc, uint8_t *ch, int *ret, cli_ctx *ctx, char *tmpd, int detect_encrypted) { - uint8_t *lh, *zip; +static unsigned int lhdr(fmap_t *map, uint32_t loff,uint32_t zsize, unsigned int *fu, unsigned int fc, const uint8_t *ch, int *ret, cli_ctx *ctx, char *tmpd, int detect_encrypted) { + const uint8_t *lh, *zip; char name[256]; uint32_t csize, usize; @@ -323,7 +323,7 @@ static unsigned int lhdr(fmap_t *map, uint32_t loff,uint32_t zsize, unsigned int } if(ctx->engine->cdb || cli_debug_flag) { uint32_t nsize = (LH_flen>=sizeof(name))?sizeof(name)-1:LH_flen; - char *src; + const char *src; if(nsize && (src = fmap_need_ptr_once(map, zip, nsize))) { memcpy(name, zip, nsize); name[nsize]='\0'; @@ -416,7 +416,7 @@ static unsigned int lhdr(fmap_t *map, uint32_t loff,uint32_t zsize, unsigned int static unsigned int chdr(fmap_t *map, uint32_t coff, uint32_t zsize, unsigned int *fu, unsigned int fc, int *ret, cli_ctx *ctx, char *tmpd) { char name[256]; int last = 0; - uint8_t *ch; + const uint8_t *ch; if(!(ch = fmap_need_off(map, coff, SIZEOF_CH)) || CH_magic != 0x02014b50) { if(ch) fmap_unneed_ptr(map, ch, SIZEOF_CH); @@ -433,7 +433,7 @@ static unsigned int chdr(fmap_t *map, uint32_t coff, uint32_t zsize, unsigned in } if(cli_debug_flag && !last) { unsigned int size = (CH_flen>=sizeof(name))?sizeof(name)-1:CH_flen; - char *src = fmap_need_off_once(map, coff, size); + const char *src = fmap_need_off_once(map, coff, size); if(src) { memcpy(name, src, size); name[size]='\0'; @@ -467,7 +467,8 @@ int cli_unzip(cli_ctx *ctx) { int ret=CL_CLEAN; uint32_t fsize, lhoff = 0, coff = 0; fmap_t *map = *ctx->fmap; - char *tmpd, *ptr; + char *tmpd; + const char *ptr; cli_dbgmsg("in cli_unzip\n"); fsize = (uint32_t)map->len; diff --git a/libclamav/upx.c b/libclamav/upx.c index 066ad7ca2..bfa0e2751 100644 --- a/libclamav/upx.c +++ b/libclamav/upx.c @@ -116,7 +116,7 @@ static char *checkpe(char *dst, uint32_t dsize, char *pehdr, uint32_t *valign, u /* PE from UPX */ -static int pefromupx (char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0, uint32_t upx1, uint32_t *magic, uint32_t dend) +static int pefromupx (const char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0, uint32_t upx1, uint32_t *magic, uint32_t dend) { char *imports, *sections=NULL, *pehdr=NULL, *newbuf; unsigned int sectcnt=0, upd=1; @@ -259,7 +259,7 @@ static int pefromupx (char *src, uint32_t ssize, char *dst, uint32_t *dsize, uin /* [doubleebx] */ -static int doubleebx(char *src, uint32_t *myebx, uint32_t *scur, uint32_t ssize) +static int doubleebx(const char *src, uint32_t *myebx, uint32_t *scur, uint32_t ssize) { uint32_t oldebx = *myebx; @@ -276,7 +276,7 @@ static int doubleebx(char *src, uint32_t *myebx, uint32_t *scur, uint32_t ssize) /* [inflate] */ -int upx_inflate2b(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep) +int upx_inflate2b(const char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep) { int32_t backbytes, unp_offset = -1; uint32_t backsize, myebx = 0, scur=0, dcur=0, i, magic[]={0x108,0x110,0xd5,0}; @@ -351,7 +351,7 @@ int upx_inflate2b(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_ return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur); } -int upx_inflate2d(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep) +int upx_inflate2d(const char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep) { int32_t backbytes, unp_offset = -1; uint32_t backsize, myebx = 0, scur=0, dcur=0, i, magic[]={0x11c,0x124,0}; @@ -433,7 +433,7 @@ int upx_inflate2d(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_ return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur); } -int upx_inflate2e(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep) +int upx_inflate2e(const char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep) { int32_t backbytes, unp_offset = -1; uint32_t backsize, myebx = 0, scur=0, dcur=0, i, magic[]={0x128,0x130,0}; @@ -522,7 +522,7 @@ int upx_inflate2e(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_ return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur); } -int upx_inflatelzma(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep) { +int upx_inflatelzma(const char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep) { struct CLI_LZMA l; uint32_t magic[]={0xb16,0xb1e,0}; unsigned char fake_lzmahdr[5]; diff --git a/libclamav/upx.h b/libclamav/upx.h index 88c9dceb7..e30148492 100644 --- a/libclamav/upx.h +++ b/libclamav/upx.h @@ -23,9 +23,9 @@ #include "cltypes.h" -int upx_inflate2b(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t); -int upx_inflate2d(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t); -int upx_inflate2e(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t); -int upx_inflatelzma(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t); +int upx_inflate2b(const char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t); +int upx_inflate2d(const char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t); +int upx_inflate2e(const char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t); +int upx_inflatelzma(const char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t); #endif diff --git a/unit_tests/check_clamav.c b/unit_tests/check_clamav.c index 4f0551050..a1e2766d0 100644 --- a/unit_tests/check_clamav.c +++ b/unit_tests/check_clamav.c @@ -336,6 +336,7 @@ static int get_test_file(int i, char *file, unsigned fsize, unsigned long *size) *size = st.st_size; return fd; } +#ifdef CHECK_HAVE_LOOPS static ssize_t pread_cb(void *handle, void *buf, size_t count, off_t offset) { @@ -396,7 +397,7 @@ START_TEST (test_cl_scanmap_callback_mem) munmap(mem, size); } END_TEST - +#endif static Suite *test_cl_suite(void) {