Пример #1
0
/* Read 64-bit program headers */
static int cli_elf_ph64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
    struct elf_file_hdr64 *file_hdr, uint8_t conv)
{
	struct elf_program_hdr64 *program_hdr = NULL;
	uint16_t phnum, phentsize;
	uint64_t entry, fentry = 0, phoff;
	uint32_t i;
	uint8_t err;

    /* Program headers and Entry */
    phnum = file_hdr->e_phnum;
    cli_dbgmsg("ELF: Number of program headers: %d\n", phnum);
    if(phnum > 128) {
        cli_dbgmsg("ELF: Suspicious number of program headers\n");
        if(ctx && SCAN_HEURISTIC_BROKEN) {
            cli_append_virus(ctx, "Heuristics.Broken.Executable");
            return CL_VIRUS;
        }
        return CL_EFORMAT;
    }
    entry = file_hdr->e_entry;

    if(phnum && entry) {
        phentsize = file_hdr->e_phentsize;
        /* Sanity check */
        if (phentsize != sizeof(struct elf_program_hdr64)) {
            cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr64)\n");
            if(ctx && SCAN_HEURISTIC_BROKEN) {
                cli_append_virus(ctx, "Heuristics.Broken.Executable");
                return CL_VIRUS;
            }
            return CL_EFORMAT;
        }

        phoff = file_hdr->e_phoff;
        if(ctx) {
            cli_dbgmsg("ELF: Program header table offset: " STDu64 "\n", phoff);
        }

        if(phnum) {
            program_hdr = (struct elf_program_hdr64 *) cli_calloc(phnum, sizeof(struct elf_program_hdr64));
            if(!program_hdr) {
                cli_errmsg("ELF: Can't allocate memory for program headers\n");
                return CL_EMEM;
            }
            if(ctx) {
                cli_dbgmsg("------------------------------------\n");
            }
        }

        for(i = 0; i < phnum; i++) {
            err = 0;
            if(fmap_readn(map, &program_hdr[i], phoff, sizeof(struct elf_program_hdr64)) != sizeof(struct elf_program_hdr64))
                err = 1;
            phoff += sizeof(struct elf_program_hdr64);

            if(err) {
                cli_dbgmsg("ELF: Can't read segment #%d\n", i);
                if(ctx) {
                    cli_dbgmsg("ELF: Possibly broken ELF file\n");
                }
                free(program_hdr);
                if(ctx && SCAN_HEURISTIC_BROKEN) {
                    cli_append_virus(ctx, "Heuristics.Broken.Executable");
                    return CL_VIRUS;
                }
                return CL_BREAK;
            }

            if(ctx) {
                cli_dbgmsg("ELF: Segment #%d\n", i);
                cli_dbgmsg("ELF: Segment type: 0x" STDx32 "\n", (uint32_t) EC32(program_hdr[i].p_type, conv));
                cli_dbgmsg("ELF: Segment offset: 0x" STDx64 "\n", (uint64_t) EC64(program_hdr[i].p_offset, conv));
                cli_dbgmsg("ELF: Segment virtual address: 0x" STDx64 "\n", (uint64_t) EC64(program_hdr[i].p_vaddr, conv));
                cli_dbgmsg("ELF: Segment real size: 0x" STDx64 "\n", (uint64_t) EC64(program_hdr[i].p_filesz, conv));
                cli_dbgmsg("ELF: Segment virtual size: 0x" STDx64 "\n", (uint64_t) EC64(program_hdr[i].p_memsz, conv));
                cli_dbgmsg("------------------------------------\n");
            }
        }

        fentry = cli_rawaddr64(entry, program_hdr, phnum, conv, &err);
        free(program_hdr);
        if(err) {
            cli_dbgmsg("ELF: Can't calculate file offset of entry point\n");
            if(ctx && SCAN_HEURISTIC_BROKEN) {
                cli_append_virus(ctx, "Heuristics.Broken.Executable");
                return CL_VIRUS;
            }
            return CL_EFORMAT;
        }
        if(ctx) {
            cli_dbgmsg("ELF: Entry point address: 0x%.16" PRIx64 "\n", entry);
            cli_dbgmsg("ELF: Entry point offset: 0x%.16" PRIx64 " (" STDi64 ")\n", fentry, fentry);
        }
    }

    if(elfinfo) {
        elfinfo->ep = fentry;
    }

    return CL_CLEAN;
}
Пример #2
0
/* 64-bit version of section header parsing */
static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo,
    struct elf_file_hdr64 *file_hdr, uint8_t conv)
{
	struct elf_section_hdr64 *section_hdr = NULL;
	uint16_t shnum, shentsize;
	uint32_t i;
	uint64_t shoff;

    shnum = file_hdr->e_shnum;
    cli_dbgmsg("ELF: Number of sections: %d\n", shnum);
    if(ctx && (shnum > 2048)) {
	cli_dbgmsg("ELF: Number of sections > 2048, skipping\n");
	return CL_BREAK;
    }
    else if(elfinfo && (shnum > 256)) {
	cli_dbgmsg("ELF: Suspicious number of sections\n");
	return CL_BREAK;
    }
    if(elfinfo) {
        elfinfo->nsections = shnum;
    }

    shentsize = file_hdr->e_shentsize;
    /* Sanity check */
    if(shentsize != sizeof(struct elf_section_hdr64)) {
	cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr64)\n");
        if(ctx && SCAN_HEURISTIC_BROKEN) {
	    cli_append_virus(ctx, "Heuristics.Broken.Executable");
	    return CL_VIRUS;
        }
	return CL_EFORMAT;
    }

    if(elfinfo && !shnum) {
        return CL_CLEAN;
    }

    shoff = file_hdr->e_shoff;
    if(ctx)
        cli_dbgmsg("ELF: Section header table offset: " STDu64 "\n", shoff);

    if(elfinfo) {
        elfinfo->section = (struct cli_exe_section *)cli_calloc(shnum, sizeof(struct cli_exe_section));
        if(!elfinfo->section) {
            cli_dbgmsg("ELF: Can't allocate memory for section headers\n");
            return CL_EMEM;
        }
    }

    if(shnum) {
	section_hdr = (struct elf_section_hdr64 *) cli_calloc(shnum, shentsize);
	if(!section_hdr) {
	    cli_errmsg("ELF: Can't allocate memory for section headers\n");
	    if(elfinfo) {
                free(elfinfo->section);
                elfinfo->section = NULL;
	    }
	    return CL_EMEM;
	}
	if(ctx) {
            cli_dbgmsg("------------------------------------\n");
	}
    }

    /* Loop over section headers */
    for(i = 0; i < shnum; i++) {
        uint32_t sh_type, sh_flags;

	if(fmap_readn(map, &section_hdr[i], shoff, sizeof(struct elf_section_hdr64)) != sizeof(struct elf_section_hdr64)) {
            cli_dbgmsg("ELF: Can't read section header\n");
            if(ctx) {
                cli_dbgmsg("ELF: Possibly broken ELF file\n");
            }
            free(section_hdr);
            if(elfinfo) {
                free(elfinfo->section);
                elfinfo->section = NULL;
	    }
            if(ctx && SCAN_HEURISTIC_BROKEN) {
                cli_append_virus(ctx, "Heuristics.Broken.Executable");
		return CL_VIRUS;
            }
            return CL_BREAK;
        }

	shoff += sizeof(struct elf_section_hdr64);

        if(elfinfo) {
            elfinfo->section[i].rva = EC64(section_hdr[i].sh_addr, conv);
            elfinfo->section[i].raw = EC64(section_hdr[i].sh_offset, conv);
            elfinfo->section[i].rsz = EC64(section_hdr[i].sh_size, conv);
        }
        if(ctx) {
	    cli_dbgmsg("ELF: Section " STDu32 "\n", (uint32_t) i);
	    cli_dbgmsg("ELF: Section offset: " STDu64 "\n", (uint64_t) EC64(section_hdr[i].sh_offset, conv));
	    cli_dbgmsg("ELF: Section size: " STDu64 "\n", (uint64_t) EC64(section_hdr[i].sh_size, conv));

            sh_type = EC32(section_hdr[i].sh_type, conv);
            sh_flags = (uint32_t)(EC64(section_hdr[i].sh_flags, conv) & ELF_SHF_MASK);
            cli_elf_sectionlog(sh_type, sh_flags);

	    cli_dbgmsg("------------------------------------\n");
        }
    }

    free(section_hdr);
    return CL_CLEAN;
}
Пример #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)
{
    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) {
	if(filter_search_ext(root->filter, buffer, length, &info) == -1) {
	    /*  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 {
	    /* must not cut buffer for 64[4-4]6161, because we must be able to check
	     * 64! */
	    pos = info.first_match - root->maxpatlen - 1;
	    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;
    length -= pos;
    buffer += pos;
    offset += pos;
    if (!root->ac_only) {
	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 */
	    ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, tinfo, offdata, viroffset);
	} else {
	    ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, tinfo, offdata, viroffset);
	}
	if (ret == CL_VIRUS) {
	    if (ctx) {
		cli_append_virus(ctx, *virname);
		if (SCAN_ALL)
		    viruses_found++;
		else
		    return ret;
	    }
	}
    }
    PERF_LOG_TRIES(acmode, 0, length);
    ret = cli_ac_scanbuff(buffer, length, virname, NULL, acres, root, mdata, offset, ftype, ftoffset, acmode, ctx);

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

    return ret;
}
Пример #4
0
int cli_7unz (cli_ctx *ctx, size_t offset) {
    CFileInStream archiveStream;
    CLookToRead lookStream;
    CSzArEx db;
    SRes res;
    UInt16 utf16buf[UTFBUFSZ], *utf16name = utf16buf;
    int namelen = UTFBUFSZ, found = CL_CLEAN;
    Int64 begin_of_archive = offset;
    UInt32 viruses_found = 0;

    /* Replacement for 
       FileInStream_CreateVTable(&archiveStream); */
    archiveStream.s.Read = FileInStream_fmap_Read;
    archiveStream.s.Seek = FileInStream_fmap_Seek;
    archiveStream.s.curpos = 0;
    archiveStream.file.fmap = *ctx->fmap;

    LookToRead_CreateVTable(&lookStream, False);
  
    if(archiveStream.s.Seek(&archiveStream.s, &begin_of_archive, SZ_SEEK_SET) != 0)
	return CL_CLEAN;

    lookStream.realStream = &archiveStream.s;
    LookToRead_Init(&lookStream);

    SzArEx_Init(&db);
    res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp);
    if(res == SZ_OK) {
	UInt32 i, blockIndex = 0xFFFFFFFF;
	Byte *outBuffer = 0;
	size_t outBufferSize = 0;
	unsigned int encrypted = 0;

	for (i = 0; i < db.db.NumFiles; i++) {
	    size_t offset = 0;
	    size_t outSizeProcessed = 0;
	    const CSzFileItem *f = db.db.Files + i;
	    char *name;
	    size_t j;
	    int newnamelen, fd;

	    if((found = cli_checklimits("7unz", ctx, 0, 0, 0)))
		break;

	    if (f->IsDir)
		continue;

	    if(cli_checklimits("7unz", ctx, f->Size, 0, 0))
		continue;

	    if (!db.FileNameOffsets)
		newnamelen = 0; /* no filename */
	    else {
		newnamelen = SzArEx_GetFileNameUtf16(&db, i, NULL);
		if (newnamelen > namelen) {
		    if(namelen > UTFBUFSZ)
			free(utf16name);
		    utf16name = cli_malloc(newnamelen*2);
		    if(!utf16name) {
			found = CL_EMEM;
			break;
		    }
		    namelen = newnamelen;
		}
		SzArEx_GetFileNameUtf16(&db, i, utf16name);
	    }

	    name = (char *)utf16name;
	    for(j=0; j<(size_t)newnamelen; j++) /* FIXME */
		name[j] = utf16name[j];
	    name[j] = 0;
	    cli_dbgmsg("cli_7unz: extracting %s\n", name);

	    res = SzArEx_Extract(&db, &lookStream.s, i, &blockIndex, &outBuffer, &outBufferSize, &offset, &outSizeProcessed, &allocImp, &allocTempImp);
	    if(res == SZ_ERROR_ENCRYPTED) {
		encrypted = 1;
		if(DETECT_ENCRYPTED) {
		    cli_dbgmsg("cli_7unz: Encrypted files found in archive.\n");
		    cli_append_virus(ctx, "Heuristics.Encrypted.7Zip");
		    viruses_found++;
		    if(!SCAN_ALL) {
			found = CL_VIRUS;
			break;
		    }
		}
	    }
	    if(cli_matchmeta(ctx, name, 0, f->Size, encrypted, i, f->CrcDefined ? f->Crc : 0, NULL)) {
		found = CL_VIRUS;
		viruses_found++;
		if (!SCAN_ALL)
		    break;
	    }
	    if (res != SZ_OK)
		cli_dbgmsg("cli_unz: extraction failed with %d\n", res);
	    else {
		if((found = cli_gentempfd(ctx->engine->tmpdir, &name, &fd)))
		    break;
		    
		cli_dbgmsg("cli_7unz: Saving to %s\n", name);
		if((size_t)cli_writen(fd, outBuffer + offset, outSizeProcessed) != outSizeProcessed)
		    found = CL_EWRITE;
		else
		    if ((found = cli_magic_scandesc(fd, ctx)) == CL_VIRUS)
			viruses_found++;
		close(fd);
		if(!ctx->engine->keeptmp && cli_unlink(name))
		    found = CL_EUNLINK;

		free(name);
		if(found != CL_CLEAN)
		    if (!(SCAN_ALL && found == CL_VIRUS))
			break;
	    }
	}
	IAlloc_Free(&allocImp, outBuffer);
    }
    SzArEx_Free(&db, &allocImp);
    if(namelen > UTFBUFSZ)
	free(utf16name);

    if (res == SZ_OK)
	cli_dbgmsg("cli_7unz: completed successfully\n");
    else if (res == SZ_ERROR_UNSUPPORTED)
	cli_dbgmsg("cli_7unz: unsupported\n");
    else if (res == SZ_ERROR_MEM)
	cli_dbgmsg("cli_7unz: oom\n");
    else if (res == SZ_ERROR_CRC)
	cli_dbgmsg("cli_7unz: crc mismatch\n");
    else
	cli_dbgmsg("cli_7unz: error %d\n", res);

    if (SCAN_ALL && viruses_found)
	return CL_VIRUS;
    return found;
}
Пример #5
0
int cli_lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash)
{
	unsigned int i, evalcnt;
	uint64_t evalids;
	fmap_t *map = *ctx->fmap;
	unsigned int viruses_found = 0;

    for(i = 0; i < root->ac_lsigs; i++) {
	evalcnt = 0;
	evalids = 0;
	cli_ac_chkmacro(root, acdata, i);
	if(cli_ac_chklsig(root->ac_lsigtable[i]->logic, root->ac_lsigtable[i]->logic + strlen(root->ac_lsigtable[i]->logic), acdata->lsigcnt[i], &evalcnt, &evalids, 0) == 1) {
	    if(root->ac_lsigtable[i]->tdb.container && root->ac_lsigtable[i]->tdb.container[0] != ctx->container_type)
		continue;
	    if(root->ac_lsigtable[i]->tdb.filesize && (root->ac_lsigtable[i]->tdb.filesize[0] > map->len || root->ac_lsigtable[i]->tdb.filesize[1] < map->len))
		continue;

	    if(root->ac_lsigtable[i]->tdb.ep || root->ac_lsigtable[i]->tdb.nos) {
		if(!target_info || target_info->status != 1)
		    continue;
		if(root->ac_lsigtable[i]->tdb.ep && (root->ac_lsigtable[i]->tdb.ep[0] > target_info->exeinfo.ep || root->ac_lsigtable[i]->tdb.ep[1] < target_info->exeinfo.ep))
		    continue;
		if(root->ac_lsigtable[i]->tdb.nos && (root->ac_lsigtable[i]->tdb.nos[0] > target_info->exeinfo.nsections || root->ac_lsigtable[i]->tdb.nos[1] < target_info->exeinfo.nsections))
		    continue;
	    }

	    if(hash && root->ac_lsigtable[i]->tdb.handlertype) {
		if(memcmp(ctx->handlertype_hash, hash, 16)) {
		    ctx->recursion++;
		    memcpy(ctx->handlertype_hash, hash, 16);
		    if(cli_magic_scandesc_type(ctx, root->ac_lsigtable[i]->tdb.handlertype[0]) == CL_VIRUS) {
			ctx->recursion--;
			if (SCAN_ALL) {
			    viruses_found++;
			    continue;
			}
			return CL_VIRUS;
		    }
		    ctx->recursion--;
		    continue;
		}
	    }

	    if(root->ac_lsigtable[i]->tdb.icongrp1 || root->ac_lsigtable[i]->tdb.icongrp2) {
		if(!target_info || target_info->status != 1)
		    continue;
		if(matchicon(ctx, &target_info->exeinfo, root->ac_lsigtable[i]->tdb.icongrp1, root->ac_lsigtable[i]->tdb.icongrp2) == CL_VIRUS) {
		    if(!root->ac_lsigtable[i]->bc_idx) {
			cli_append_virus(ctx, root->ac_lsigtable[i]->virname);
			if (SCAN_ALL) {
                            viruses_found++;
                            continue;
                        }
			return CL_VIRUS;
		    } else if(cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, acdata->lsigcnt[i], acdata->lsigsuboff_first[i], map) == CL_VIRUS) {
			if (SCAN_ALL) {
                            viruses_found++;
                            continue;
                        }
			return CL_VIRUS;
		    }
		}
		continue;
	    }
	    if(!root->ac_lsigtable[i]->bc_idx) {
		cli_append_virus(ctx, root->ac_lsigtable[i]->virname);
		if (SCAN_ALL) {
		    viruses_found++;
		    continue;
		}
 		return CL_VIRUS;
	    }
	    if(cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, acdata->lsigcnt[i], acdata->lsigsuboff_first[i], map) == CL_VIRUS) {
		if (SCAN_ALL) {
		    viruses_found++;
		    continue;
		}
 		return CL_VIRUS;
	    }
	}
    }
    if (SCAN_ALL && viruses_found)
	return CL_VIRUS;
    return CL_CLEAN;
}
Пример #6
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)
{
	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;
    }

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

    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;
    }

    targetinfo(&info, i, map);

    if(!ftonly)
	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;
	}

    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) {
	    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;

    if(!ftonly && hdb) {
	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_wild(hdb, CLI_HASH_SHA1)
		|| cli_hm_have_size(fp, CLI_HASH_SHA1, map->len) || cli_hm_have_wild(fp, CLI_HASH_SHA1) ) {
	    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_wild(hdb, CLI_HASH_SHA256)
		|| cli_hm_have_size(fp, CLI_HASH_SHA256, map->len) || cli_hm_have_wild(fp, CLI_HASH_SHA256)) {
	    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;

    if (ctx->engine->cb_progress && map->handle_is_fd && !ctx->engine->cb_progress((ssize_t) map->handle, bytes, ctx->engine->cb_progress_ctx))
        return CL_BREAK;

	if(troot) {
            virname = NULL;
            viroffset = 0;
	    ret = matcher_run(troot, buff, bytes, &virname, &tdata, offset, &info, ftype, ftoffset, acmode, acres, map, bm_offmode ? &toff : NULL, &viroffset, ctx);

	    if (virname) {
		/* virname already appended by matcher_run */
		viruses_found = 1;
	    }
	    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) {
	    virname = NULL;
	    viroffset = 0;
	    ret = matcher_run(groot, buff, bytes, &virname, &gdata, offset, &info, ftype, ftoffset, acmode, acres, map, NULL, &viroffset, ctx);

            if (virname) {
		/* virname already appended by matcher_run */
		viruses_found = 1;
	    }
	    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++) {
	    const char * virname_w = NULL;
	    int found = 0;

	    /* If no hash, skip to next type */
	    if(!compute_hash[hashtype])
		continue;

	    /* Do hash scan */
	    if((ret = cli_hm_scan(digest[hashtype], map->len, &virname, hdb, hashtype)) == CL_VIRUS) {
		found += 1;
	    }
	    if(!found || SCAN_ALL) {
		if ((ret = cli_hm_scan_wild(digest[hashtype], &virname_w, hdb, hashtype)) == CL_VIRUS)
		    found += 2;
	    }

	    /* If found, do immediate hash-only FP check */
	    if (found && fp) {
		for(hashtype2 = CLI_HASH_MD5; hashtype2 < CLI_HASH_AVAIL_TYPES; hashtype2++) {
		    if(!compute_hash[hashtype2])
			continue;
		    if(cli_hm_scan(digest[hashtype2], map->len, NULL, fp, hashtype2) == CL_VIRUS) {
			found = 0;
			ret = CL_CLEAN;
			break;
		    }
		    else if(cli_hm_scan_wild(digest[hashtype2], NULL, fp, hashtype2) == CL_VIRUS) {
			found = 0;
			ret = CL_CLEAN;
			break;
		    }
		}
	    }

	    /* If matched size-based hash ... */
	    if (found % 2) {
		viruses_found = 1;
		cli_append_virus(ctx, virname);
		if (!SCAN_ALL)
		    break;
		virname = NULL;
	    }
	    /* If matched size-agnostic hash ... */
	    if (found > 1) {
		viruses_found = 1;
		cli_append_virus(ctx, virname_w);
		if (!SCAN_ALL)
		    break;
	    }
	}
    }

    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;
}
Пример #7
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;
}
Пример #8
0
static int apm_prtn_intxn(cli_ctx *ctx, struct apm_partition_info *aptable, size_t sectorsize, int old_school)
{
    prtn_intxn_list_t prtncheck;
    struct apm_partition_info apentry;
    unsigned i, pitxn;
    int ret = CL_CLEAN, tmp = CL_CLEAN;
    off_t pos;
    uint32_t max_prtns = 0;

    prtn_intxn_list_init(&prtncheck);

    /* check engine maxpartitions limit */
    if (aptable->numPartitions < ctx->engine->maxpartitions) {
        max_prtns = aptable->numPartitions;
    }
    else {
        max_prtns = ctx->engine->maxpartitions;
    }

    for (i = 1; i <= max_prtns; ++i) {
        /* read partition table entry */
        pos = i * sectorsize;
        if (fmap_readn(*ctx->fmap, &apentry, pos, sizeof(apentry)) != sizeof(apentry)) {
            cli_dbgmsg("cli_scanapm: Invalid Apple partition entry\n");
            prtn_intxn_list_free(&prtncheck);
            return CL_EFORMAT;
        }

        /* convert necessary info big endian to host */
        apentry.pBlockStart = be32_to_host(apentry.pBlockStart);
        apentry.pBlockCount = be32_to_host(apentry.pBlockCount);
        /* re-calculate if old_school and aligned [512 * 4 => 2048] */
        if (old_school && ((i % 4) == 0)) {
            if (!strncmp((char*)apentry.type, "Apple_Driver",       32) ||
                    !strncmp((char*)apentry.type, "Apple_Driver43",     32) ||
                    !strncmp((char*)apentry.type, "Apple_Driver43_CD",  32) ||
                    !strncmp((char*)apentry.type, "Apple_Driver_ATA",   32) ||
                    !strncmp((char*)apentry.type, "Apple_Driver_ATAPI", 32) ||
                    !strncmp((char*)apentry.type, "Apple_Patches",      32)) {

                apentry.pBlockCount = apentry.pBlockCount * 4;;
            }
        }

        tmp = prtn_intxn_list_check(&prtncheck, &pitxn, apentry.pBlockStart, apentry.pBlockCount);
        if (tmp != CL_CLEAN) {
            if ((ctx->options & CL_SCAN_ALLMATCHES) && (tmp == CL_VIRUS)) {
                apm_parsemsg("Name: %s\n", (char*)aptable.name);
                apm_parsemsg("Type: %s\n", (char*)aptable.type);

                cli_dbgmsg("cli_scanapm: detected intersection with partitions "
                           "[%u, %u]\n", pitxn, i);
                cli_append_virus(ctx, PRTN_INTXN_DETECTION);
                ret = tmp;
                tmp = 0;
            }
            else if (tmp == CL_VIRUS) {
                apm_parsemsg("Name: %s\n", (char*)aptable.name);
                apm_parsemsg("Type: %s\n", (char*)aptable.type);

                cli_dbgmsg("cli_scanapm: detected intersection with partitions "
                           "[%u, %u]\n", pitxn, i);
                cli_append_virus(ctx, PRTN_INTXN_DETECTION);
                prtn_intxn_list_free(&prtncheck);
                return CL_VIRUS;
            }
            else {
                prtn_intxn_list_free(&prtncheck);
                return tmp;
            }
        }

        pos += sectorsize;
    }

    prtn_intxn_list_free(&prtncheck);
    return ret;
}
Пример #9
0
/* checks internal logical partitions */
static int mbr_extended_prtn_intxn(cli_ctx *ctx, unsigned *prtncount, off_t extlba, size_t sectorsize)
{
    struct mbr_boot_record ebr;
    prtn_intxn_list_t prtncheck;
    unsigned i, pitxn;
    int ret = CL_CLEAN, tmp = CL_CLEAN, mbr_base = 0;
    off_t pos = 0, logiclba = 0;

    mbr_base = sectorsize - sizeof(struct mbr_boot_record);

    prtn_intxn_list_init(&prtncheck);

    logiclba = 0; i = 0;
    do {
        pos = extlba * sectorsize; /* start of extended partition */

        /* read the extended boot record */
        pos += (logiclba * sectorsize) + mbr_base;
        if (fmap_readn(*ctx->fmap, &ebr, pos, sizeof(ebr)) != sizeof(ebr)) {
            cli_dbgmsg("cli_scanebr: Invalid extended boot record\n");
            prtn_intxn_list_free(&prtncheck);
            return CL_EFORMAT;
        }

        /* convert the little endian to host */
        mbr_convert_to_host(&ebr);

        /* update state */
        (*prtncount)++;

        /* assume that logical record is first and extended is second */
        tmp = prtn_intxn_list_check(&prtncheck, &pitxn, logiclba, ebr.entries[0].numLBA);
        if (tmp != CL_CLEAN) {
            if ((ctx->options & CL_SCAN_ALLMATCHES) && (tmp == CL_VIRUS)) {
                cli_dbgmsg("cli_scanebr: detected intersection with partitions "
                           "[%u, %u]\n", pitxn, i);
                cli_append_virus(ctx, PRTN_INTXN_DETECTION);
                ret = tmp;
                tmp = 0;
            }
            else if (tmp == CL_VIRUS) {
                cli_dbgmsg("cli_scanebr: detected intersection with partitions "
                           "[%u, %u]\n", pitxn, i);
                cli_append_virus(ctx, PRTN_INTXN_DETECTION);
                prtn_intxn_list_free(&prtncheck);
                return CL_VIRUS;
            }
            else {
                prtn_intxn_list_free(&prtncheck);
                return tmp;
            }
        }

        /* assume extended is second entry */
        if (ebr.entries[1].type != MBR_EXTENDED) {
            cli_dbgmsg("cli_scanebr: second entry for EBR is not an extended partition\n");
            break;
        }

        logiclba = ebr.entries[1].firstLBA;

        ++i;
    } while (logiclba != 0 && (*prtncount) < ctx->engine->maxpartitions);

    prtn_intxn_list_free(&prtncheck);    
    return ret;
}
Пример #10
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;
}
Пример #11
0
/* this includes the overall bounds of extended partitions */
static int mbr_primary_prtn_intxn(cli_ctx *ctx, struct mbr_boot_record mbr, size_t sectorsize)
{
    prtn_intxn_list_t prtncheck;
    unsigned i = 0, pitxn = 0, prtncount = 0;
    int ret = CL_CLEAN, tmp = CL_CLEAN;

    prtn_intxn_list_init(&prtncheck);

    for (i = 0; i < MBR_MAX_PARTITION_ENTRIES && prtncount < ctx->engine->maxpartitions; ++i) {
        if (mbr.entries[i].type == MBR_EMPTY) {
            /* empty partiton entry */
            prtncount++;
        }
        else {
            tmp = prtn_intxn_list_check(&prtncheck, &pitxn, mbr.entries[i].firstLBA,
                                        mbr.entries[i].numLBA);
            if (tmp != CL_CLEAN) {
                if ((ctx->options & CL_SCAN_ALLMATCHES) && (tmp == CL_VIRUS)) {
                    cli_dbgmsg("cli_scanmbr: detected intersection with partitions "
                               "[%u, %u]\n", pitxn, i);
                    cli_append_virus(ctx, PRTN_INTXN_DETECTION);
                    ret = tmp;
                    tmp = 0;
                }
                else if (tmp == CL_VIRUS) {
                    cli_dbgmsg("cli_scanmbr: detected intersection with partitions "
                               "[%u, %u]\n", pitxn, i);
                    cli_append_virus(ctx, PRTN_INTXN_DETECTION);
                    prtn_intxn_list_free(&prtncheck);
                    return CL_VIRUS;
                }
                else {
                    prtn_intxn_list_free(&prtncheck);
                    return tmp;
                }
            }

            if (mbr.entries[i].type == MBR_EXTENDED) {
                /* check the logical partitions */
                tmp = mbr_extended_prtn_intxn(ctx, &prtncount, 
                                  mbr.entries[i].firstLBA, sectorsize);
                if (tmp != CL_CLEAN) {
                    if ((ctx->options & CL_SCAN_ALLMATCHES) && (tmp == CL_VIRUS)) {
                        ret = tmp;
                        tmp = 0;
                    }
                    else if (tmp == CL_VIRUS) {
                        prtn_intxn_list_free(&prtncheck);
                        return CL_VIRUS;
                    }
                    else {
                        prtn_intxn_list_free(&prtncheck);
                        return tmp;
                    }
                }
            }
            else {
                prtncount++;
            }
        }
    }

    prtn_intxn_list_free(&prtncheck);
    return ret;
}
Пример #12
0
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, zip_cb zcb) {
    const uint8_t *lh, *zip;
    char name[256];
    uint32_t csize, usize;

    if(!(lh = fmap_need_off(map, loff, SIZEOF_LH))) {
        cli_dbgmsg("cli_unzip: lh - out of file\n");
        return 0;
    }
    if(LH_magic != 0x04034b50) {
        if (!ch) cli_dbgmsg("cli_unzip: lh - wrkcomplete\n");
        else cli_dbgmsg("cli_unzip: lh - bad magic\n");
        fmap_unneed_off(map, loff, SIZEOF_LH);
        return 0;
    }

    zip = lh + SIZEOF_LH;
    zsize-=SIZEOF_LH;

    if(zsize<=LH_flen) {
        cli_dbgmsg("cli_unzip: lh - fname out of file\n");
        fmap_unneed_off(map, loff, SIZEOF_LH);
        return 0;
    }
    if(ctx->engine->cdb || cli_debug_flag) {
        uint32_t nsize = (LH_flen>=sizeof(name))?sizeof(name)-1:LH_flen;
        const char *src;
        if(nsize && (src = fmap_need_ptr_once(map, zip, nsize))) {
            memcpy(name, zip, nsize);
            name[nsize]='\0';
        } else
            name[0] = '\0';
    }
    zip+=LH_flen;
    zsize-=LH_flen;

    cli_dbgmsg("cli_unzip: lh - ZMDNAME:%d:%s:%u:%u:%x:%u:%u:%u\n", ((LH_flags & F_ENCR)!=0), name, LH_usize, LH_csize, LH_crc32, LH_method, fc, ctx->recursion);
    /* ZMDfmt virname:encrypted(0-1):filename(exact|*):usize(exact|*):csize(exact|*):crc32(exact|*):method(exact|*):fileno(exact|*):maxdepth(exact|*) */

    if(cli_matchmeta(ctx, name, LH_csize, LH_usize, (LH_flags & F_ENCR)!=0, fc, LH_crc32, NULL) == CL_VIRUS) {
        *ret = CL_VIRUS;
        return 0;
    }

    if(LH_flags & F_MSKED) {
        cli_dbgmsg("cli_unzip: lh - header has got unusable masked data\n");
        /* FIXME: need to find/craft a sample */
        fmap_unneed_off(map, loff, SIZEOF_LH);
        return 0;
    }

    if(detect_encrypted && (LH_flags & F_ENCR) && DETECT_ENCRYPTED) {
        cli_dbgmsg("cli_unzip: Encrypted files found in archive.\n");
        cli_append_virus(ctx, "Heuristics.Encrypted.Zip");
        *ret = CL_VIRUS;
        fmap_unneed_off(map, loff, SIZEOF_LH);
        return 0;
    }

    if(LH_flags & F_USEDD) {
        cli_dbgmsg("cli_unzip: lh - has data desc\n");
        if(!ch) {
            fmap_unneed_off(map, loff, SIZEOF_LH);
            return 0;
        }
        else {
            usize = CH_usize;
            csize = CH_csize;
        }
    } else {
        usize = LH_usize;
        csize = LH_csize;
    }

    if(zsize<=LH_elen) {
        cli_dbgmsg("cli_unzip: lh - extra out of file\n");
        fmap_unneed_off(map, loff, SIZEOF_LH);
        return 0;
    }
    zip+=LH_elen;
    zsize-=LH_elen;

    if (!csize) { /* FIXME: what's used for method0 files? csize or usize? Nothing in the specs, needs testing */
        cli_dbgmsg("cli_unzip: lh - skipping empty file\n");
    } else {
        if(zsize<csize) {
            cli_dbgmsg("cli_unzip: lh - stream out of file\n");
            fmap_unneed_off(map, loff, SIZEOF_LH);
            return 0;
        }
        if(LH_flags & F_ENCR) {
            cli_dbgmsg("cli_unzip: lh - skipping encrypted file\n");
        } else {
            if(fmap_need_ptr_once(map, zip, csize))
                *ret = unz(zip, csize, usize, LH_method, LH_flags, fu, ctx, tmpd, zcb);
        }
        zip+=csize;
        zsize-=csize;
    }

    fmap_unneed_off(map, loff, SIZEOF_LH); /* unneed now. block is guaranteed to exists till the next need */
    if(LH_flags & F_USEDD) {
        if(zsize<12) {
            cli_dbgmsg("cli_unzip: lh - data desc out of file\n");
            return 0;
        }
        zsize-=12;
        if(fmap_need_ptr_once(map, zip, 4)) {
            if(cli_readint32(zip)==0x08074b50) {
                if(zsize<4) {
                    cli_dbgmsg("cli_unzip: lh - data desc out of file\n");
                    return 0;
                }
                zip+=4;
            }
        }
        zip+=12;
    }
    return zip-lh;
}
Пример #13
0
int cli_pcre_scanbuf(const unsigned char *buffer, uint32_t length, const char **virname, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, const struct cli_pcre_off *data, cli_ctx *ctx)
{
    struct cli_pcre_meta **metatable = root->pcre_metatable, *pm = NULL;
    struct cli_pcre_data *pd;
    struct cli_ac_result *newres;
    uint32_t adjbuffer, adjshift, adjlength;
    unsigned int i, evalcnt = 0;
    uint64_t maxfilesize, evalids = 0;
    uint32_t global, encompass, rolling;
    int rc, lrc, offset, options=0, ovector[OVECCOUNT];
    uint8_t viruses_found = 0;

    if ((!root->pcre_metatable) || (ctx && ctx->dconf && !(ctx->dconf->pcre & PCRE_CONF_SUPPORT))) {
        return CL_SUCCESS;
    }

    /* NOTE: moved pcre maxfilesize limit check to caller [matcher_run] */

    for (i = 0; i < root->pcre_metas; ++i) {
        pm = root->pcre_metatable[i];
        pd = &(pm->pdata);

        /* skip checking and running disabled pcres */
        if (pm->flags & CLI_PCRE_DISABLED) {
            cli_dbgmsg("cli_pcre_scanbuf: skipping disabled regex /%s/\n", pd->expression);
            continue;
        }

        /* skip checking and running CLI_OFF_NONE pcres */
        if (data && data->offset[i] == CLI_OFF_NONE) {
            pm_dbgmsg("cli_pcre_scanbuf: skipping CLI_OFF_NONE regex /%s/\n", pd->expression);
            continue;
        }

        /* evaluate trigger */
        if (pm->lsigid[0]) {
            cli_dbgmsg("cli_pcre_scanbuf: checking %s; running regex /%s/\n", pm->trigger, pd->expression);
#ifdef PCRE_BYPASS
            if (strcmp(pm->trigger, PCRE_BYPASS))
#endif
                if (cli_ac_chklsig(pm->trigger, pm->trigger + strlen(pm->trigger), mdata->lsigcnt[pm->lsigid[1]], &evalcnt, &evalids, 0) != 1)
                    continue;
        }
        else {
            cli_dbgmsg("cli_pcre_scanbuf: skipping %s check due to unintialized lsigid\n", pm->trigger);
            /* fall-through to unconditional execution - sigtool-only */
        }

        global = (pm->flags & CLI_PCRE_GLOBAL);       /* globally search for all matches (within bounds) */
        encompass = (pm->flags & CLI_PCRE_ENCOMPASS); /* encompass search to offset->offset+maxshift */
        rolling = (pm->flags & CLI_PCRE_ROLLING);     /* rolling search (unanchored) */
        offset = pd->search_offset;                   /* this is usually 0 */

        cli_dbgmsg("cli_pcre_scanbuf: triggered %s; running regex /%s/%s%s\n", pm->trigger, pd->expression, 
                   global ? " (global)":"", rolling ? " (rolling)":"");

        /* adjust the buffer sent to cli_pcre_match for offset and maxshift */
        if (!data) {
            if (cli_pcre_qoff(pm, length, &adjbuffer, &adjshift) != CL_SUCCESS)
                continue;
        }
        else {
            adjbuffer = data->offset[i];
            adjshift = data->shift[i];
        }

        /* check for need to anchoring */
        if (!rolling && !adjshift && (adjbuffer != CLI_OFF_ANY))
            options |= PCRE_ANCHORED;
        else
            options = 0;

        if (adjbuffer == CLI_OFF_ANY)
            adjbuffer = 0;

        /* check the offset bounds */
        if (adjbuffer < length) {
            /* handle encompass flag */
            if (encompass && adjshift != 0 && adjshift != CLI_OFF_NONE) {
                    if (adjbuffer+adjshift > length)
                        adjlength = length - adjbuffer;
                    else
                        adjlength = adjshift;
            }
            else {
                /* NOTE - if using non-encompass method 2, alter shift universally */
                /* TODO - limitations on non-encompassed buffers? */
                adjlength = length - adjbuffer;
            }
        }
        else {
            /* starting offset is outside bounds of file, skip pcre execution silently */
            pm_dbgmsg("cli_pcre_scanbuf: starting offset is outside bounds of file %u >= %u\n", adjbuffer, length);
            continue;
        }

        pm_dbgmsg("cli_pcre_scanbuf: passed buffer adjusted to %u +%u(%u)[%u]%s\n", adjbuffer, adjlength, adjbuffer+adjlength, adjshift, encompass ? " (encompass)":"");

        /* if the global flag is set, loop through the scanning */
        do {
            /* performance metrics */
            cli_event_time_start(p_sigevents, pm->sigtime_id);
            rc = cli_pcre_match(pd, buffer+adjbuffer, adjlength, offset, options, ovector, OVECCOUNT);
            cli_event_time_stop(p_sigevents, pm->sigtime_id);
            /* if debug, generate a match report */
            if (cli_debug_flag)
                cli_pcre_report(pd, buffer+adjbuffer, adjlength, rc, ovector, OVECCOUNT);

            /* matched, rc shouldn't be >0 unless a full match occurs */
            if (rc > 0) {
                cli_dbgmsg("cli_pcre_scanbuf: located regex match @ %d\n", adjbuffer+ovector[0]);

                /* check if we've gone over offset+shift */
                if (!encompass && adjshift) {
                    if (ovector[0] > adjshift) {
                        /* ignore matched offset (outside of maxshift) */
                        cli_dbgmsg("cli_pcre_scanbuf: match found outside of maxshift @%u\n", adjbuffer+ovector[0]);
                        break;
                    }
                }

                /* track the detection count */
                cli_event_count(p_sigevents, pm->sigmatch_id);

                /* for logical signature evaluation */
                if (pm->lsigid[0]) {
                    pm_dbgmsg("cli_pcre_scanbuf: assigning lsigcnt[%d][%d], located @ %d\n",
                              pm->lsigid[1], pm->lsigid[2], adjbuffer+ovector[0]);

                    lrc = lsig_sub_matched(root, mdata, pm->lsigid[1], pm->lsigid[2], adjbuffer+ovector[0], 0);
                    if (lrc != CL_SUCCESS)
                        return lrc;
                } else {
                    /* for raw match data - sigtool only */
                    if(res) {
                        newres = (struct cli_ac_result *)cli_calloc(1, sizeof(struct cli_ac_result));
                        if(!newres) {
                            cli_errmsg("cli_pcre_scanbuff: Can't allocate memory for new result\n");
                            return CL_EMEM;
                        }
                        newres->virname = pm->virname;
                        newres->customdata = NULL; /* get value? */
                        newres->next = *res;
                        newres->offset = adjbuffer+ovector[0];
                        *res = newres;
                    } else {
                        if (ctx && SCAN_ALL) {
                            viruses_found = 1;
                            cli_append_virus(ctx, (const char *)pm->virname);
                        }
                        if (virname)
                            *virname = pm->virname;
                        if (!ctx || !SCAN_ALL)
                            return CL_VIRUS;
                    }
                }
            }

            /* move off to the end of the match for next match; offset is relative to adjbuffer
             * NOTE: misses matches starting within the last match; TODO: start from start of last match? */
            offset = ovector[1];

            /* clear the ovector results (they fall through the pcre_match) */
            memset(ovector, 0, sizeof(ovector));
        } while (global && rc > 0 && offset < adjlength);

        /* handle error codes */
        if (rc < 0 && rc != PCRE_ERROR_NOMATCH) {
            switch (rc) {
            case PCRE_ERROR_CALLOUT:
                break;
            case PCRE_ERROR_NOMEMORY:
                cli_errmsg("cli_pcre_scanbuf: cli_pcre_match: pcre_exec: out of memory\n");
                return CL_EMEM;
            case PCRE_ERROR_MATCHLIMIT:
                cli_dbgmsg("cli_pcre_scanbuf: cli_pcre_match: pcre_exec: match limit exceeded\n");
                break;
            case PCRE_ERROR_RECURSIONLIMIT:
                cli_dbgmsg("cli_pcre_scanbuf: cli_pcre_match: pcre_exec: recursive limit exceeded\n");
                break;
            default:
                cli_errmsg("cli_pcre_scanbuf: cli_pcre_match: pcre_exec: returned error %d\n", rc);
                return CL_BREAK;
            }
        }
    }

    if (viruses_found)
        return CL_VIRUS;
    return CL_SUCCESS;
}
Пример #14
0
static int gpt_prtn_intxn(cli_ctx *ctx, struct gpt_header hdr, size_t sectorsize)
{
    prtn_intxn_list_t prtncheck;
    struct gpt_partition_entry gpe;
    unsigned i, pitxn;
    int ret = CL_CLEAN, tmp = CL_CLEAN;
    off_t pos;
    size_t maplen;
    uint32_t max_prtns = 0;
    int virus_found = 0;

    maplen = (*ctx->fmap)->real_len;

    /* convert endian to host to check partition table */
    hdr.tableStartLBA = le64_to_host(hdr.tableStartLBA);
    hdr.tableNumEntries = le32_to_host(hdr.tableNumEntries);

    prtn_intxn_list_init(&prtncheck);    

    /* check engine maxpartitions limit */
    if (hdr.tableNumEntries < ctx->engine->maxpartitions) {
        max_prtns = hdr.tableNumEntries;
    }
    else {
        max_prtns = ctx->engine->maxpartitions;
    }

    pos = hdr.tableStartLBA * sectorsize;
    for (i = 0; i < max_prtns; ++i) {
        /* read in partition entry */
        if (fmap_readn(*ctx->fmap, &gpe, pos, sizeof(gpe)) != sizeof(gpe)) {
            cli_dbgmsg("cli_scangpt: Invalid GPT partition entry\n");
            prtn_intxn_list_free(&prtncheck);
            return CL_EFORMAT;
        }

        /* convert the endian to host */
        gpe.firstLBA = le64_to_host(gpe.firstLBA);
        gpe.lastLBA = le64_to_host(gpe.lastLBA);

        if (gpe.firstLBA == 0) {
            /* empty partition, invalid */
        }
        else if ((gpe.firstLBA > gpe.lastLBA) ||
                 (gpe.firstLBA < hdr.firstUsableLBA) || (gpe.lastLBA > hdr.lastUsableLBA)) {
            /* partition exists outside bounds specified by header or invalid */
        }
        else if (((gpe.lastLBA+1) * sectorsize) > maplen) {
            /* partition exists outside bounds of the file map */
        }
        else {
            tmp = prtn_intxn_list_check(&prtncheck, &pitxn, gpe.firstLBA, gpe.lastLBA - gpe.firstLBA + 1);
            if (tmp != CL_CLEAN) {
                if (tmp == CL_VIRUS) {
                    cli_dbgmsg("cli_scangpt: detected intersection with partitions "
                               "[%u, %u]\n", pitxn, i);
                    ret = cli_append_virus(ctx, PRTN_INTXN_DETECTION);
                    if (ret == CL_VIRUS)
                        virus_found = 1;
                    if (SCAN_ALLMATCHES || ret == CL_CLEAN)
                        tmp = 0;
                    else
                        goto leave;
                } else {
                    ret = tmp;
                    goto leave;
                }
            }
        }

        /* increment the offsets to next partition entry */
        pos += hdr.tableEntrySize;
    }

 leave:
    prtn_intxn_list_free(&prtncheck);
    if (virus_found)
        return CL_VIRUS;
    return ret;
}
Пример #15
0
/* -------end runtime disable---------*/
int phishingScan(cli_ctx* ctx,tag_arguments_t* hrefs)
{
	/* TODO: get_host and then apply regex, etc. */
	int i;
	struct phishcheck* pchk = (struct phishcheck*) ctx->engine->phishcheck;
	/* check for status of whitelist fatal error, etc. */
	if(!pchk || pchk->is_disabled)
		return CL_CLEAN;

	if(!ctx->found_possibly_unwanted && !SCAN_ALL)
		*ctx->virname=NULL;
#if 0
	FILE *f = fopen("/home/edwin/quarantine/urls","r");
	if(!f)
		abort();
	while(!feof(f)) {
		struct url_check urls;
		char line1[4096];
		char line2[4096];
		char line3[4096];

		fgets(line1, sizeof(line1), f);
		fgets(line2, sizeof(line2), f);
		fgets(line3, sizeof(line3), f);
		if(strcmp(line3, "\n") != 0) {
			strcpy(line1, line2);
			strcpy(line2, line3);
			fgets(line3, sizeof(line3), f);
			while(strcmp(line3, "\n") != 0) {
				fgets(line3, sizeof(line3),f);
			}
		}
		urls.flags = CL_PHISH_ALL_CHECKS;
		urls.link_type = 0;
		string_init_c(&urls.realLink, line1);
		string_init_c(&urls.displayLink, line2);
		string_init_c(&urls.pre_fixup.pre_displayLink, NULL);
		urls.realLink.refcount=-1;
		urls.displayLink.refcount=-1;
		int rc = phishingCheck(ctx->engine, &urls);
	}
	fclose(f);
	return 0;
#endif
	for(i=0;i<hrefs->count;i++) {
			struct url_check urls;
			enum phish_status rc;
			urls.flags	 = strncmp((char*)hrefs->tag[i],href_text,href_text_len)? (CL_PHISH_ALL_CHECKS&~CHECK_SSL): CL_PHISH_ALL_CHECKS;
			urls.link_type   = 0;
			if(!strncmp((char*)hrefs->tag[i],src_text,src_text_len)) {
				if (!(urls.flags&CHECK_IMG_URL))
				continue;
				urls.link_type |= LINKTYPE_IMAGE;
			}
			urls.always_check_flags = 0;
			if (ctx->options & CL_SCAN_PHISHING_BLOCKSSL) {
				urls.always_check_flags |= CHECK_SSL;
			}
			if (ctx->options & CL_SCAN_PHISHING_BLOCKCLOAK) {
				urls.always_check_flags |= CHECK_CLOAKING;
			}
			string_init_c(&urls.realLink,(char*)hrefs->value[i]);
			string_init_c(&urls.displayLink, (char*)hrefs->contents[i]);
			string_init_c(&urls.pre_fixup.pre_displayLink, NULL);

			urls.realLink.refcount=-1;
			urls.displayLink.refcount=-1;/*don't free these, caller will free*/
			if(strcmp((char*)hrefs->tag[i],"href")) {
				char *url;
				url = urls.realLink.data;
				urls.realLink.data = urls.displayLink.data;
				urls.displayLink.data = url;
			}

			rc = phishingCheck(ctx->engine,&urls);
			if(pchk->is_disabled)
				return CL_CLEAN;
			free_if_needed(&urls);
			cli_dbgmsg("Phishcheck: Phishing scan result: %s\n",phishing_ret_toString(rc));
			switch(rc)/*TODO: support flags from ctx->options,*/
			{
				case CL_PHISH_CLEAN:
					continue;
				case CL_PHISH_NUMERIC_IP:
				    cli_append_virus(ctx, "Heuristics.Phishing.Email.Cloaked.NumericIP");
					break;
				case CL_PHISH_CLOAKED_NULL:
				    cli_append_virus(ctx, "Heuristics.Phishing.Email.Cloaked.Null");/*fakesite%01%[email protected]*/
					break;
				case CL_PHISH_SSL_SPOOF:
				    cli_append_virus(ctx, "Heuristics.Phishing.Email.SSL-Spoof");
					break;
				case CL_PHISH_CLOAKED_UIU:
				    cli_append_virus(ctx, "Heuristics.Phishing.Email.Cloaked.Username");/*http://[email protected]*/
					break;
				case CL_PHISH_HASH0:
				    cli_append_virus(ctx, "Heuristics.Safebrowsing.Suspected-malware_safebrowsing.clamav.net");
					break;
				case CL_PHISH_HASH1:
				    cli_append_virus(ctx, "Heuristics.Phishing.URL.Blacklisted");
					break;
				case CL_PHISH_HASH2:
				    cli_append_virus(ctx, "Heuristics.Safebrowsing.Suspected-phishing_safebrowsing.clamav.net");
					break;
				case CL_PHISH_NOMATCH:
				default:
				    cli_append_virus(ctx, "Heuristics.Phishing.Email.SpoofedDomain");
					break;
			}
			return cli_found_possibly_unwanted(ctx);
	}
	return CL_CLEAN;
}