Beispiel #1
0
static void targetinfo(struct cli_target_info *info, unsigned int target, fmap_t *map)
{
    cli_infomsg(NULL,"DEBUG: in targetinfo with target=%d\n",target);//CHR
	int (*einfo)(fmap_t *, struct cli_exe_info *) = NULL;


    memset(info, 0, sizeof(struct cli_target_info));
    info->fsize = map->len;
    cli_hashset_init_noalloc(&info->exeinfo.vinfo);

    if(target == 1)
	einfo = cli_peheader;
    else if(target == 6)
	einfo = cli_elfheader;
    else if(target == 9)
	einfo = cli_machoheader;
    else {
    cli_infomsg(NULL,"DEBUG: target!=(1,6,9), do nothing and return\n");//CHR
    return;
    }

    if(einfo(map, &info->exeinfo))
	info->status = -1;
    else
	info->status = 1;
}
Beispiel #2
0
void cli_pcre_perf_print()
{
    struct sigperf_elem stats[MAX_TRACKED_PCRE], *elem = stats;
    int i, elems = 0, max_name_len = 0, name_len;

    if (!p_sigid || !p_sigevents) {
        cli_warnmsg("cli_pcre_perf_print: statistics requested but no PCREs were loaded!\n");
        return;
    }

    memset(stats, 0, sizeof(stats));
    for (i=0;i<MAX_TRACKED_PCRE;i++) {
        union ev_val val;
        uint32_t count;
        const char * name = cli_event_get_name(p_sigevents, i*PCRE_EVENTS_PER_SIG);
        cli_event_get(p_sigevents, i*PCRE_EVENTS_PER_SIG, &val, &count);
        if (!count) {
            if (name)
                cli_dbgmsg("No event triggered for %s\n", name);
            continue;
        }
        if (name)
            name_len = strlen(name);
        else
            name_len = 0;
        if (name_len > max_name_len)
            max_name_len = name_len;
        elem->name = name?name:"\"noname\"";
        elem->usecs = val.v_int;
        elem->run_count = count;
        cli_event_get(p_sigevents, i*PCRE_EVENTS_PER_SIG+1, &val, &count);
        elem->match_count = count;
        elem++;
        elems++;
    }
    if (max_name_len < strlen("PCRE Expression"))
        max_name_len = strlen("PCRE Expression");

    cli_qsort(stats, elems, sizeof(struct sigperf_elem), sigelem_comp);

    elem = stats;
    /* name runs matches microsecs avg */
    cli_infomsg (NULL, "%-*s %*s %*s %*s %*s\n", max_name_len, "PCRE Expression",
                 8, "#runs", 8, "#matches", 12, "usecs total", 9, "usecs avg");
    cli_infomsg (NULL, "%-*s %*s %*s %*s %*s\n", max_name_len, "===============",
                 8, "=====", 8, "========", 12, "===========", 9, "=========");
    while (elem->run_count) {
        cli_infomsg (NULL, "%-*s %*lu %*lu %*llu %*.2f\n", max_name_len, elem->name,
                     8, elem->run_count, 8, elem->match_count,
                     12, (long long unsigned)elem->usecs, 9, (double)elem->usecs/elem->run_count);
        elem++;
    }
}
Beispiel #3
0
static inline int matcher_run(const struct cli_matcher *root,
			      const unsigned char *buffer, uint32_t length,
			      const char **virname, struct cli_ac_data *mdata,
			      uint32_t offset,
			      const struct cli_target_info *tinfo,
			      cli_file_t ftype,
			      struct cli_matched_type **ftoffset,
			      unsigned int acmode,
			      struct cli_ac_result **acres,
			      fmap_t *map,
			      struct cli_bm_off *offdata,
			      uint32_t *viroffset,
			      cli_ctx *ctx)
{
    cli_infomsg(NULL,"DEBUG: in matcher_run\n");//CHR
    int ret;
    int32_t pos = 0;
    struct filter_match_info info;
    uint32_t orig_length, orig_offset;
    const unsigned char* orig_buffer;
    unsigned int viruses_found = 0;

    if (root->filter) {
    cli_infomsg(NULL,"DEBUG: has filter\n");//CHR
    // CHR function filter_search_ext will do pre-matchon prefix for a given pattern
	if(filter_search_ext(root->filter, buffer, length, &info) == -1) {
        cli_infomsg(NULL,"DEBUG: filter and in if\n");//CHR
	    /*  for safety always scan last maxpatlen bytes */
	    pos = length - root->maxpatlen - 1;
	    if (pos < 0) pos = 0;
	    PERF_LOG_FILTER(pos, length, root->type);
	} else { // CHR FSM match
        cli_infomsg(NULL,"DEBUG: filter and in else\n");//CHR
	    /* must not cut buffer for 64[4-4]6161, because we must be able to check
	     * 64! */
        //CHR if first_match is far more beyond max pattern length
        //CHR we need to move forward a little bit to speed up the following scan
	    pos = info.first_match - root->maxpatlen - 1;
        cli_infomsg(NULL,"DEBUG: pos=%d\n",pos);//CHR
	    if (pos < 0) pos = 0;
	    PERF_LOG_FILTER(pos, length, root->type);
	}
    } else {
	PERF_LOG_FILTER(0, length, root->type);
    }

    orig_length = length;
    orig_buffer = buffer;
    orig_offset = offset;
    //CHR pos is 0 in this case
    length -= pos;
    buffer += pos;
    offset += pos;
    if (!root->ac_only) {
    cli_infomsg(NULL,"DEBUG: !ac_only, bm scan first\n");//CHR
	PERF_LOG_TRIES(0, 1, length);
	if (root->bm_offmode) {
	    /* Don't use prefiltering for BM offset mode, since BM keeps tracks
	     * of offsets itself, and doesn't work if we skip chunks of input
	     * data */
         cli_infomsg(NULL,"DEBUG: scan in bm_offmode=1 mode\n"); //CHR
	    ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, tinfo, offdata, viroffset);
	} else {
        cli_infomsg(NULL,"DEBUG: scan in bm_offmode=0 mode\n"); //CHR
        cli_infomsg(NULL,"DEBUG: pass into cli_bm_scanbuff with length=%d,offset=%d\n",length,offset);//CHR
	    ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, tinfo, offdata, viroffset);
	}
	if (ret == CL_VIRUS) {
        cli_infomsg(NULL,"DEBUG: bm scan find virus, won't do ac scan\n");//CHR
	    if (ctx) {
		cli_append_virus(ctx, *virname);
		if (SCAN_ALL)
		    viruses_found++;
		else
		    return ret;
	    }
	}
    }
    PERF_LOG_TRIES(acmode, 0, length);
    cli_infomsg(NULL,"DEBUG: ac scan\n");//CHR
    ret = cli_ac_scanbuff(buffer, length, virname, NULL, acres, root, mdata, offset, ftype, ftoffset, acmode, NULL);

    if (ctx && ret == CL_VIRUS)
	cli_append_virus(ctx, *virname);
    if (ctx && SCAN_ALL && viruses_found)
	return CL_VIRUS;

    return ret;
}
Beispiel #4
0
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)
{
    //CHR ftype => type == CL_TYPE_TEXT_ASCII ? 0 : type
    //CHR ftonly => 0
    cli_infomsg(NULL,"DEBUG: in cli_fmap_scandesc\n");//CHR
	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;
	struct cli_ac_data gdata, tdata;
	struct cli_bm_off toff;
	cli_md5_ctx md5ctx;
	SHA256_CTX sha256ctx;
	SHA1Context sha1ctx;
	unsigned char digest[CLI_HASH_AVAIL_TYPES][32];
	struct cli_matcher *groot = NULL, *troot = NULL;
	struct cli_target_info info;
	fmap_t *map = *ctx->fmap;
	struct cli_matcher *hdb, *fp;
	const char *virname = NULL;
	uint32_t viroffset = 0;
	uint32_t viruses_found = 0;

    if(!ctx->engine) {
	cli_errmsg("cli_scandesc: engine == NULL\n");
	return CL_ENULLARG;
    }

    cli_infomsg(NULL,"DEBUG: ftype=%d, ftonly=%d(using generic signatures for groot)\n",ftype,ftonly);//CHR

    if(!ftonly)
	groot = ctx->engine->root[0]; /* generic signatures */

    //CHR in test.txt case, ftype=0, troot is for sepcific types: from 1 to CLI_MTARGETS
    if(ftype) {
	for(i = 1; i < CLI_MTARGETS; i++) {
	    if(cli_mtargets[i].target == ftype) {
		troot = ctx->engine->root[i];
		break;
	    }
	}
    }

    if(ftonly) {
	if(!troot)
	    return CL_CLEAN;

	maxpatlen = troot->maxpatlen;
    } else {
	if(troot)
	    maxpatlen = MAX(troot->maxpatlen, groot->maxpatlen);
	else{
	    maxpatlen = groot->maxpatlen;
        cli_infomsg(NULL,"DEBUG: no troot, maxpatlen using groot->maxpatlen=%d\n",groot->maxpatlen);//CHR
        }
    }

    targetinfo(&info, i, map);

    if(!ftonly)
    // CHR init AC scan structure?
	if((ret = cli_ac_initdata(&gdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) || (ret = cli_ac_caloff(groot, &gdata, &info))) {
	    if(info.exeinfo.section)
		free(info.exeinfo.section);
	    cli_hashset_destroy(&info.exeinfo.vinfo);
	    return ret;
	}

    // not run in this case test.txt
    if(troot) { 
	if((ret = cli_ac_initdata(&tdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) || (ret = cli_ac_caloff(troot, &tdata, &info))) {
	    if(!ftonly)
		cli_ac_freedata(&gdata);
	    if(info.exeinfo.section)
		free(info.exeinfo.section);
	    cli_hashset_destroy(&info.exeinfo.vinfo);
	    return ret;
	}
	if(troot->bm_offmode) {// CHR offset mode
	    if(map->len >= CLI_DEFAULT_BM_OFFMODE_FSIZE) {
		if((ret = cli_bm_initoff(troot, &toff, &info))) {
		    if(!ftonly)
			cli_ac_freedata(&gdata);
		    cli_ac_freedata(&tdata);
		    if(info.exeinfo.section)
			free(info.exeinfo.section);
		    cli_hashset_destroy(&info.exeinfo.vinfo);
		    return ret;
		}
		bm_offmode = 1;
	    }
	}
    }

    hdb = ctx->engine->hm_hdb;
    fp = ctx->engine->hm_fp;

    // hdb related
    if(!ftonly && hdb) { //CHR if have hdb should init mn5 contex
	if(!refhash) {
	    if(cli_hm_have_size(hdb, CLI_HASH_MD5, map->len) || cli_hm_have_size(fp, CLI_HASH_MD5, map->len)) {
		cli_md5_init(&md5ctx);
		compute_hash[CLI_HASH_MD5] = 1;
	    } else
		compute_hash[CLI_HASH_MD5] = 0;
	} else {
	    compute_hash[CLI_HASH_MD5] = 0;
	    memcpy(digest[CLI_HASH_MD5], refhash, 16);
	}

	if(cli_hm_have_size(hdb, CLI_HASH_SHA1, map->len) || cli_hm_have_size(fp, CLI_HASH_SHA1, map->len)) {
	    SHA1Init(&sha1ctx);
	    compute_hash[CLI_HASH_SHA1] = 1;
	} else
	    compute_hash[CLI_HASH_SHA1] = 0;

	if(cli_hm_have_size(hdb, CLI_HASH_SHA256, map->len) || cli_hm_have_size(fp, CLI_HASH_SHA256, map->len)) {
	    sha256_init(&sha256ctx);
	    compute_hash[CLI_HASH_SHA256] = 1;
	} else
	    compute_hash[CLI_HASH_SHA256] = 0;
    }

    while(offset < map->len) {
	bytes = MIN(map->len - offset, SCANBUFF);
	if(!(buff = fmap_need_off_once(map, offset, bytes)))
	    break;
	if(ctx->scanned)
	    *ctx->scanned += bytes / CL_COUNT_PRECISION;

    // CHR not troot for this case
	if(troot) {
            cli_infomsg(NULL,"DEBUG: not troot, should not show this msg\n");//CHR
            virname = NULL;
            viroffset = 0;
            // CHR run match
	    ret = matcher_run(troot, buff, bytes, &virname, &tdata, offset, &info, ftype, ftoffset, acmode, acres, map, bm_offmode ? &toff : NULL, &viroffset, ctx);

	    if (virname) {
		viruses_found++;
	    }
	    if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) {
		if(!ftonly)
		    cli_ac_freedata(&gdata);
		cli_ac_freedata(&tdata);
		if(bm_offmode)
		    cli_bm_freeoff(&toff);
		if(info.exeinfo.section)
		    free(info.exeinfo.section);
		cli_hashset_destroy(&info.exeinfo.vinfo);
		return ret;
	    }
	}

	if(!ftonly) {
        cli_infomsg(NULL,"DEBUG: !ftonly=true, will run matcher_run with groot with generic sigs\n");//CHR
	    virname = NULL;
	    viroffset = 0;
	    ret = matcher_run(groot, buff, bytes, &virname, &gdata, offset, &info, ftype, ftoffset, acmode, acres, map, NULL, &viroffset, ctx);

            if (virname) {
		viruses_found++;
	    }
	    if((ret == CL_VIRUS && !SCAN_ALL) || ret == CL_EMEM) {
		cli_ac_freedata(&gdata);
		if(troot) {
		    cli_ac_freedata(&tdata);
		    if(bm_offmode)
			cli_bm_freeoff(&toff);
		}
		if(info.exeinfo.section)
		    free(info.exeinfo.section);
		cli_hashset_destroy(&info.exeinfo.vinfo);
		return ret;
	    } else if((acmode & AC_SCAN_FT) && ret >= CL_TYPENO) {
		if(ret > type)
		    type = ret;
	    }

	    if(hdb && !SCAN_ALL) {
		const void *data = buff + maxpatlen * (offset!=0);
		uint32_t data_len = bytes - maxpatlen * (offset!=0);

		if(compute_hash[CLI_HASH_MD5])
		    cli_md5_update(&md5ctx, data, data_len);
		if(compute_hash[CLI_HASH_SHA1])
		    SHA1Update(&sha1ctx, data, data_len);
		if(compute_hash[CLI_HASH_SHA256])
		    sha256_update(&sha256ctx, data, data_len);
	    }
	}

	if(SCAN_ALL && viroffset) {
	    offset = viroffset;
	    continue;
	}
	if(bytes < SCANBUFF) break;
	offset += bytes - maxpatlen;
    }

    if(!ftonly && hdb) {
	enum CLI_HASH_TYPE hashtype, hashtype2;

	if(compute_hash[CLI_HASH_MD5])
	    cli_md5_final(digest[CLI_HASH_MD5], &md5ctx);
	if(refhash)
	    compute_hash[CLI_HASH_MD5] = 1;
	if(compute_hash[CLI_HASH_SHA1])
	    SHA1Final(&sha1ctx, digest[CLI_HASH_SHA1]);
	if(compute_hash[CLI_HASH_SHA256])
	    sha256_final(&sha256ctx, digest[CLI_HASH_SHA256]);

	virname = NULL;
	for(hashtype = CLI_HASH_MD5; hashtype < CLI_HASH_AVAIL_TYPES; hashtype++) {
	    if(compute_hash[hashtype] &&
	       (ret = cli_hm_scan(digest[hashtype], map->len, &virname, hdb, hashtype)) == CL_VIRUS) {
		if(fp) {
		    for(hashtype2 = CLI_HASH_MD5; hashtype2 < CLI_HASH_AVAIL_TYPES; hashtype2++) {
			if(compute_hash[hashtype2] &&
			   cli_hm_scan(digest[hashtype2], map->len, NULL, fp, hashtype2) == CL_VIRUS) {
			    ret = CL_CLEAN;
			    break;
			}
		    }
		}
		if (ret == CL_VIRUS) {
		    viruses_found++;
		    cli_append_virus(ctx, virname);
		    if (!SCAN_ALL)
			break;
		}
		virname = NULL;
	    }
	}
    }

    if(troot) {
	if(ret != CL_VIRUS || SCAN_ALL)
	    ret = cli_lsig_eval(ctx, troot, &tdata, &info, refhash);
	if (ret == CL_VIRUS)
	    viruses_found++;
	cli_ac_freedata(&tdata);
	if(bm_offmode)
	    cli_bm_freeoff(&toff);
    }

    if(groot) {
	if(ret != CL_VIRUS || SCAN_ALL)
	    ret = cli_lsig_eval(ctx, groot, &gdata, &info, refhash);
	cli_ac_freedata(&gdata);
    }

    if(info.exeinfo.section)
	free(info.exeinfo.section);
    cli_hashset_destroy(&info.exeinfo.vinfo);

    if (SCAN_ALL && viruses_found)
	return CL_VIRUS;
    if(ret == CL_VIRUS)
	return CL_VIRUS;

    return (acmode & AC_SCAN_FT) ? type : CL_CLEAN;
}
Beispiel #5
0
static int scancws(cli_ctx *ctx, struct swf_file_hdr *hdr)
{
        z_stream stream;
        char inbuff[FILEBUFF], outbuff[FILEBUFF];
        fmap_t *map = *ctx->fmap;
        int offset = 8, ret, zret, outsize = 8, count, zend;
        char *tmpname;
        int fd;

    if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
        cli_errmsg("scancws: Can't generate temporary file\n");
        return ret;
    }

    hdr->signature[0] = 'F';
    if(cli_writen(fd, hdr, sizeof(struct swf_file_hdr)) != sizeof(struct swf_file_hdr)) {
        cli_errmsg("scancws: Can't write to file %s\n", tmpname);
        close(fd);
        if(cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
        free(tmpname);
        return CL_EWRITE;
    }

    stream.avail_in = 0;
    stream.next_in = (Bytef *)inbuff;
    stream.next_out = (Bytef *)outbuff;
    stream.zalloc = (alloc_func) NULL;
    stream.zfree = (free_func) NULL;
    stream.opaque = (voidpf) 0;
    stream.avail_out = FILEBUFF;

    zret = inflateInit(&stream);
    if(zret != Z_OK) {
        cli_errmsg("scancws: inflateInit() failed\n");
        close(fd);
        if(cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
        free(tmpname);
        return CL_EUNPACK;
    }

    do {
        if(stream.avail_in == 0) {
            stream.next_in = (Bytef *)inbuff;
            ret = fmap_readn(map, inbuff, offset, FILEBUFF);
            if(ret < 0) {
                cli_errmsg("scancws: Error reading SWF file\n");
                close(fd);
                inflateEnd(&stream);
                if(cli_unlink(tmpname)) {
                    free(tmpname);
                    return CL_EUNLINK;
                }
                free(tmpname);
                return CL_EUNPACK;
            }
            if(!ret)
                break;
            stream.avail_in = ret;
            offset += ret;
        }
        zret = inflate(&stream, Z_SYNC_FLUSH);
        count = FILEBUFF - stream.avail_out;
        if(count) {
            if(cli_checklimits("SWF", ctx, outsize + count, 0, 0) != CL_SUCCESS)
                break;
            if(cli_writen(fd, outbuff, count) != count) {
                cli_errmsg("scancws: Can't write to file %s\n", tmpname);
                inflateEnd(&stream);
                close(fd);
                if(cli_unlink(tmpname)) {
                    free(tmpname);
                    return CL_EUNLINK;
                }
                free(tmpname);
                return CL_EWRITE;
            }
            outsize += count;
        }
        stream.next_out = (Bytef *)outbuff;
        stream.avail_out = FILEBUFF;
    } while(zret == Z_OK);

    zend = inflateEnd(&stream);

    if((zret != Z_STREAM_END && zret != Z_OK) || zend != Z_OK) {
        /*
         * outsize is initialized to 8, it being 8 here means that we couldn't even read a single byte.
         * If outsize > 8, then we have data. Let's scan what we have.
         */
        if (outsize == 8) {
            cli_infomsg(ctx, "scancws: Error decompressing SWF file. No data decompressed.\n");
            close(fd);
            if(cli_unlink(tmpname)) {
                free(tmpname);
                return CL_EUNLINK;
            }
            free(tmpname);
            return CL_EUNPACK;
        }
        cli_infomsg(ctx, "scancws: Error decompressing SWF file. Scanning what was decompressed.\n");
    }
    cli_dbgmsg("SWF: Decompressed[zlib] to %s, size %d\n", tmpname, outsize);

    /* check if declared output size matches actual output size */
    if (hdr->filesize != outsize) {
        cli_warnmsg("SWF: declared output length != inflated stream size, %u != %llu\n",
                    hdr->filesize, (long long unsigned)outsize);
    } else {
        cli_dbgmsg("SWF: declared output length == inflated stream size, %u == %llu\n",
                   hdr->filesize, (long long unsigned)outsize);
    }

    ret = cli_magic_scandesc(fd, ctx);

    close(fd);
    if(!ctx->engine->keeptmp) {
        if(cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
    }
    free(tmpname);
    return ret;
}
Beispiel #6
0
static int scanzws(cli_ctx *ctx, struct swf_file_hdr *hdr)
{
        struct CLI_LZMA lz;
        unsigned char inbuff[FILEBUFF], outbuff[FILEBUFF];
        fmap_t *map = *ctx->fmap;
        /* strip off header */
        off_t offset = 8;
        uint32_t d_insize;
        size_t outsize = 8;
        int ret, lret, count;
        char *tmpname;
        int fd;

    if((ret = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
        cli_errmsg("scanzws: Can't generate temporary file\n");
        return ret;
    }

    hdr->signature[0] = 'F';
    if(cli_writen(fd, hdr, sizeof(struct swf_file_hdr)) != sizeof(struct swf_file_hdr)) {
        cli_errmsg("scanzws: Can't write to file %s\n", tmpname);
        close(fd);
        if(cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
        free(tmpname);
        return CL_EWRITE;
    }

    /* read 4 bytes (for compressed 32-bit filesize) [not used for LZMA] */
    if (fmap_readn(map, &d_insize, offset, sizeof(d_insize)) != sizeof(d_insize)) {
        cli_errmsg("scanzws: Error reading SWF file\n");
        close(fd);
        if (cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
        free(tmpname);
        return CL_EREAD;
    }
    offset += sizeof(d_insize);

    /* check if declared input size matches actual output size */
    /* map->len = header (8 bytes) + d_insize (4 bytes) + flags (5 bytes) + compressed stream */
    if (d_insize != (map->len - 17)) {
        cli_warnmsg("SWF: declared input length != compressed stream size, %u != %llu\n",
                    d_insize, (long long unsigned)(map->len - 17));
    } else {
        cli_dbgmsg("SWF: declared input length == compressed stream size, %u == %llu\n",
                    d_insize, (long long unsigned)(map->len - 17));
    }

    /* first buffer required for initializing LZMA */
    ret = fmap_readn(map, inbuff, offset, FILEBUFF);
    if (ret < 0) {
        cli_errmsg("scanzws: Error reading SWF file\n");
        close(fd);
        if (cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
        free(tmpname);
        return CL_EUNPACK;
    }
    /* nothing written, likely truncated */
    if (!ret) {
        cli_errmsg("scanzws: possibly truncated file\n");
        close(fd);
        if (cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
        free(tmpname);
        return CL_EFORMAT;
    }
    offset += ret;

    memset(&lz, 0, sizeof(lz));
    lz.next_in = inbuff;
    lz.next_out = outbuff;
    lz.avail_in = ret;
    lz.avail_out = FILEBUFF;

    lret = cli_LzmaInit(&lz, hdr->filesize);
    if (lret != LZMA_RESULT_OK) {
        cli_errmsg("scanzws: LzmaInit() failed\n");
        close(fd);
        if (cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
        free(tmpname);
        return CL_EUNPACK;
    }

    while (lret == LZMA_RESULT_OK) {
        if (lz.avail_in == 0) {
            lz.next_in = inbuff;

            ret = fmap_readn(map, inbuff, offset, FILEBUFF);
            if (ret < 0) {
                cli_errmsg("scanzws: Error reading SWF file\n");
                cli_LzmaShutdown(&lz);
                close(fd);
                if (cli_unlink(tmpname)) {
                    free(tmpname);
                    return CL_EUNLINK;
                }
                free(tmpname);
                return CL_EUNPACK;
            }
            if (!ret)
                break;
            lz.avail_in = ret;
            offset += ret;
        }
        lret = cli_LzmaDecode(&lz);
        count = FILEBUFF - lz.avail_out;
        if (count) {
            if (cli_checklimits("SWF", ctx, outsize + count, 0, 0) != CL_SUCCESS)
                break;
            if (cli_writen(fd, outbuff, count) != count) {
                cli_errmsg("scanzws: Can't write to file %s\n", tmpname);
                cli_LzmaShutdown(&lz);
                close(fd);
                if (cli_unlink(tmpname)) {
                    free(tmpname);
                    return CL_EUNLINK;
                }
                free(tmpname);
                return CL_EWRITE;
            }
            outsize += count;
        }
        lz.next_out = outbuff;
        lz.avail_out = FILEBUFF;
    }

    cli_LzmaShutdown(&lz);

    if (lret != LZMA_STREAM_END && lret != LZMA_RESULT_OK) {
        /* outsize starts at 8, therefore, if its still 8, nothing was decompressed */
        if (outsize == 8) {
            cli_infomsg(ctx, "scanzws: Error decompressing SWF file. No data decompressed.\n");
            close(fd);
            if (cli_unlink(tmpname)) {
                free(tmpname);
                return CL_EUNLINK;
            }
            free(tmpname);
            return CL_EUNPACK;
        }
        cli_infomsg(ctx, "scanzws: Error decompressing SWF file. Scanning what was decompressed.\n");
    }
    cli_dbgmsg("SWF: Decompressed[LZMA] to %s, size %llu\n", tmpname, (long long unsigned)outsize);

    /* check if declared output size matches actual output size */
    if (hdr->filesize != outsize) {
        cli_warnmsg("SWF: declared output length != inflated stream size, %u != %llu\n",
                    hdr->filesize, (long long unsigned)outsize);
    } else {
        cli_dbgmsg("SWF: declared output length == inflated stream size, %u == %llu\n",
                   hdr->filesize, (long long unsigned)outsize);
    }

    ret = cli_magic_scandesc(fd, ctx);

    close(fd);
    if (!(ctx->engine->keeptmp)) {
        if (cli_unlink(tmpname)) {
            free(tmpname);
            return CL_EUNLINK;
        }
    }
    free(tmpname);
    return ret;
}