Пример #1
0
int cli_scanmacho_unibin(cli_ctx *ctx)
{
	struct macho_fat_header fat_header;
	struct macho_fat_arch fat_arch;
	unsigned int conv, i, matcher = 0;
	int ret = CL_CLEAN;
	fmap_t *map = *ctx->fmap;
	ssize_t at;

    if(fmap_readn(map, &fat_header, 0, sizeof(fat_header)) != sizeof(fat_header)) {
	cli_dbgmsg("cli_scanmacho_unibin: Can't read fat_header\n");
	return CL_EFORMAT;
    }
    at = sizeof(fat_header);

    if(fat_header.magic == 0xcafebabe) {
	conv = 0;
    } else if(fat_header.magic == 0xbebafeca) {
	conv = 1;
    } else {
	cli_dbgmsg("cli_scanmacho_unibin: Incorrect magic\n");
	return CL_EFORMAT;
    }

    fat_header.nfats = EC32(fat_header.nfats, conv);
    if((fat_header.nfats & 0xffff) >= 39) /* Java Bytecode */
	return CL_CLEAN;

    if(fat_header.nfats > 32) {
	cli_dbgmsg("cli_scanmacho_unibin: Invalid number of architectures\n");
	return CL_EFORMAT;
    }
    cli_dbgmsg("UNIBIN: Number of architectures: %u\n", (unsigned int) fat_header.nfats);
    for(i = 0; i < fat_header.nfats; i++) {
	if(fmap_readn(map, &fat_arch, at, sizeof(fat_arch)) != sizeof(fat_arch)) {
	    cli_dbgmsg("cli_scanmacho_unibin: Can't read fat_arch\n");
	    RETURN_BROKEN;
	}
	at += sizeof(fat_arch);
	fat_arch.offset = EC32(fat_arch.offset, conv);
	fat_arch.size = EC32(fat_arch.size, conv);
	cli_dbgmsg("UNIBIN: Binary %u of %u\n", i + 1, fat_header.nfats);
	cli_dbgmsg("UNIBIN: File offset: %u\n", fat_arch.offset);
	cli_dbgmsg("UNIBIN: File size: %u\n", fat_arch.size);
	ret = cli_map_scan(map, fat_arch.offset, fat_arch.size, ctx);
	if(ret == CL_VIRUS)
	    break;
    }

    return ret; /* result from the last binary */
}
Пример #2
0
int32_t cli_bcapi_file_find_limit(struct cli_bc_ctx *ctx , const uint8_t* data, uint32_t len, int32_t limit)
{
    char buf[4096];
    fmap_t *map = ctx->fmap;
    uint32_t off = ctx->off;
    int n;

    if (!map || len > sizeof(buf)/4 || len <= 0 || limit <= 0) {
	cli_dbgmsg("bcapi_file_find_limit preconditions not met\n");
	API_MISUSE();
	return -1;
    }

    cli_event_int(EV, BCEV_OFFSET, off);
    cli_event_fastdata(EV, BCEV_FIND, data, len);
    for (;;) {
	const char *p;
	int32_t readlen = sizeof(buf);
	if (off + readlen > limit) {
	    readlen = limit - off;
	    if (readlen < 0)
		return -1;
	}
	n = fmap_readn(map, buf, off, readlen);
	if ((unsigned)n < len || n < 0)
	    return -1;
	p = cli_memmem(buf, n, data, len);
	if (p)
	    return off + p - buf;
	off += n;
    }
    return -1;
}
Пример #3
0
static int jpeg_check_photoshop_8bim(cli_ctx *ctx, off_t *off)
{
	const unsigned char *buf;
	uint16_t ntmp;
	uint8_t nlength, id[2];
	uint32_t size;
	off_t offset = *off;
	int retval;
	fmap_t *map = *ctx->fmap;

	if(!(buf = fmap_need_off_once(map, offset, 4 + 2 + 1))) {
		cli_dbgmsg("read bim failed\n");
		return -1;
	}
	if (memcmp(buf, "8BIM", 4) != 0) {
		cli_dbgmsg("missed 8bim\n");
		return -1;
	}

	id[0] = (uint8_t)buf[4];
        id[1] = (uint8_t)buf[5];
	cli_dbgmsg("ID: 0x%.2x%.2x\n", id[0], id[1]);
	nlength = buf[6];
	ntmp = nlength + ((((uint16_t)nlength)+1) & 0x01);
	offset += 4 + 2 + 1 + ntmp;

	if (fmap_readn(map, &size, offset, 4) != 4) {
		return -1;
	}
	size = special_endian_convert_32(size);
	if (size == 0) {
		return -1;
	}
	if ((size & 0x01) == 1) {
		size++;
	}

	*off = offset + 4 + size;
	/* Is it a thumbnail image: 0x0409 or 0x040c */
	if ((id[0] == 0x04) && ((id[1] == 0x09) || (id[1] == 0x0c))) {
		/* Yes */
		cli_dbgmsg("found thumbnail\n");
	}
	else {
		/* No - Seek past record */
		return 0;
	}

	/* Jump past header */
	offset += 4 + 28;

	retval = cli_check_jpeg_exploit(ctx, offset);
	if (retval == 1) {
		cli_dbgmsg("Exploit found in thumbnail\n");
	}
	return retval;
}
Пример #4
0
static void gpt_printSectors(cli_ctx *ctx, size_t sectorsize)
{
#ifdef DEBUG_GPT_PARSE
    struct gpt_header phdr, shdr;
    off_t ppos = 0, spos = 0;
    size_t pptable_len, sptable_len, maplen;
    uint64_t ptableLastLBA, stableLastLBA;

    /* sector size calculation */
    sectorsize = GPT_DEFAULT_SECTOR_SIZE;

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

    ppos = 1 * sectorsize; /* sector 1 (second sector) is the primary gpt header */
    spos = maplen - sectorsize; /* last sector is the secondary gpt header */

    /* read in the primary and secondary gpt headers */
    if (fmap_readn(*ctx->fmap, &phdr, ppos, sizeof(phdr)) != sizeof(phdr)) {
        cli_dbgmsg("cli_scangpt: Invalid primary GPT header\n");
        return;
    }
    if (fmap_readn(*ctx->fmap, &shdr, spos, sizeof(shdr)) != sizeof(shdr)) {
        cli_dbgmsg("cli_scangpt: Invalid secondary GPT header\n");
        return;
    }

    pptable_len = phdr.tableNumEntries * phdr.tableEntrySize;
    sptable_len = shdr.tableNumEntries * shdr.tableEntrySize;
    ptableLastLBA = (phdr.tableStartLBA + (pptable_len / sectorsize)) - 1;
    stableLastLBA = (shdr.tableStartLBA + (sptable_len / sectorsize)) - 1;

    gpt_parsemsg("0: MBR\n");
    gpt_parsemsg("%llu: Primary GPT Header\n", phdr.currentLBA);
    gpt_parsemsg("%llu-%llu: Primary GPT Partition Table\n", phdr.tableStartLBA, ptableLastLBA);
    gpt_parsemsg("%llu-%llu: Usable LBAs\n", phdr.firstUsableLBA, phdr.lastUsableLBA);
    gpt_parsemsg("%llu-%llu: Secondary GPT Partition Table\n", shdr.tableStartLBA, stableLastLBA);
    gpt_parsemsg("%llu: Secondary GPT Header\n", phdr.backupLBA);
#else
    UNUSEDPARAM(ctx);
    UNUSEDPARAM(sectorsize);
    return;
#endif
}
Пример #5
0
static int
tnef_header(fmap_t *map, off_t *pos, uint8_t *part, uint16_t *type, uint16_t *tag, int32_t *length)
{
	uint32_t i32;
	int rc;

	if (fmap_readn(map, part, *pos, 1) != 1)
		return 0;
	(*pos)++;

	if(*part == (uint8_t)0)
		return 0;

	rc = fmap_readn(map, &i32, *pos, sizeof(uint32_t));
	if (rc != sizeof(uint32_t)) {
		if(((*part == '\n') || (*part == '\r')) && (rc == 0)) {
			/*
			 * trailing newline in the file, could be caused by
			 * broken quoted-printable encoding in the source
			 * message missing a final '='
			 */
			cli_dbgmsg("tnef_header: ignoring trailing newline\n");
			return 0;
		}
		return -1;
	}
	(*pos) += sizeof(uint32_t);

	i32 = host32(i32);
	*tag = (uint16_t)(i32 & 0xFFFF);
	*type = (uint16_t)((i32 & 0xFFFF0000) >> 16);

	if(fmap_readn(map, &i32, *pos, sizeof(uint32_t)) != sizeof(uint32_t))
		return -1;
	(*pos) += sizeof(uint32_t);
	*length = (int32_t)host32(i32);

	cli_dbgmsg("message tag 0x%x, type 0x%x, length %d\n",
		*tag, *type, (int)*length);

	return 1;
}
Пример #6
0
static int gpt_check_mbr(cli_ctx *ctx, size_t sectorsize)
{
    struct mbr_boot_record pmbr;
    off_t pos = 0, mbr_base = 0;
    int ret = CL_CLEAN;
    unsigned i = 0;

    /* read the mbr */
    mbr_base = sectorsize - sizeof(struct mbr_boot_record);
    pos = (MBR_SECTOR * sectorsize) + mbr_base;

    if (fmap_readn(*ctx->fmap, &pmbr, pos, sizeof(pmbr)) != sizeof(pmbr)) {
        cli_dbgmsg("cli_scangpt: Invalid primary MBR header\n");
        return CL_EFORMAT;
    }

    /* convert mbr */
    mbr_convert_to_host(&pmbr);

    /* check the protective mbr - warning */
    if (pmbr.entries[0].type == MBR_PROTECTIVE) {
        /* check the efi partition matches the gpt spec */
        if (pmbr.entries[0].firstLBA != GPT_PRIMARY_HDR_LBA) {
            cli_warnmsg("cli_scangpt: protective MBR first LBA is incorrect %u\n",
                        pmbr.entries[0].firstLBA);
        }

        /* other entries are empty */
        for (i = 1; i < MBR_MAX_PARTITION_ENTRIES; ++i) {
            if (pmbr.entries[i].type != MBR_EMPTY) {
                cli_warnmsg("cli_scangpt: protective MBR has non-empty partition\n");
                break;
            }
        }
    }
    else if (pmbr.entries[0].type == MBR_HYBRID) {
        /* hybrid mbr detected */
        cli_warnmsg("cli_scangpt: detected a hybrid MBR\n");
    }
    else {
        /* non-protective mbr detected */
        cli_warnmsg("cli_scangpt: detected a non-protective MBR\n");
    }

    /* scan the bootloader segment - pushed to scanning mbr */
    /* check if MBR size matches GPT size */
    /* check if the MBR and GPT partitions align - heuristic */
    /* scan the MBR partitions - additional scans */

    return ret;
}
Пример #7
0
int32_t cli_bcapi_file_byteat(struct cli_bc_ctx *ctx, uint32_t off)
{
    unsigned char c;
    if (!ctx->fmap) {
	cli_dbgmsg("bcapi_file_byteat: no fmap\n");
	return -1;
    }
    cli_event_int(EV, BCEV_OFFSET, off);
    if (fmap_readn(ctx->fmap, &c, off, 1) != 1) {
	cli_dbgmsg("bcapi_file_byteat: fmap_readn failed at %u\n", off);
	return -1;
    }
    return c;
}
Пример #8
0
static SRes FileInStream_fmap_Read(void *pp, void *buf, size_t *size) {
    CFileInStream *p = (CFileInStream *)pp;
    int read_sz;

    if (*size == 0)
	return 0;

    read_sz = fmap_readn(p->file.fmap, buf, p->s.curpos, *size);
    if(read_sz < 0) {
	*size = 0;
	return SZ_ERROR_READ;
    }

    p->s.curpos += read_sz;

    *size = read_sz;
    return SZ_OK;
}
Пример #9
0
int cli_mbr_check2(cli_ctx *ctx, size_t sectorsize) {
    struct mbr_boot_record mbr;
    off_t pos = 0, mbr_base = 0;
    size_t maplen;

    if (!ctx || !ctx->fmap) {
        cli_errmsg("cli_scanmbr: Invalid context\n");
        return CL_ENULLARG;
    }

    /* sector size calculation, actual value is OS dependent */
    if (sectorsize == 0)
        sectorsize = MBR_SECTOR_SIZE;

    mbr_base = sectorsize - sizeof(struct mbr_boot_record);

    /* size of total file must be a multiple of the sector size */
    maplen = (*ctx->fmap)->real_len;
    if ((maplen % sectorsize) != 0) {
        cli_dbgmsg("cli_scanmbr: File sized %lu is not a multiple of sector size %lu\n",
                   (unsigned long)maplen, (unsigned long)sectorsize);
        return CL_EFORMAT;
    }

    /* sector 0 (first sector) is the master boot record */
    pos = (MBR_SECTOR * sectorsize) + mbr_base;

    /* read the master boot record */
    if (fmap_readn(*ctx->fmap, &mbr, pos, sizeof(mbr)) != sizeof(mbr)) {
        cli_dbgmsg("cli_scanmbr: Invalid master boot record\n");
        return CL_EFORMAT;
    }

    /* convert the little endian to host, include the internal  */
    mbr_convert_to_host(&mbr);

    if ((mbr.entries[0].type == MBR_PROTECTIVE) || (mbr.entries[0].type == MBR_HYBRID))
        return CL_TYPE_GPT;

    return mbr_check_mbr(&mbr, maplen, sectorsize);
}
Пример #10
0
int32_t cli_bcapi_read(struct cli_bc_ctx* ctx, uint8_t *data, int32_t size)
{
    int n;
    if (!ctx->fmap) {
	API_MISUSE();
	return -1;
    }
    if (size < 0 || size > CLI_MAX_ALLOCATION) {
	cli_warnmsg("bytecode: negative read size: %d\n", size);
	API_MISUSE();
	return -1;
    }
    n = fmap_readn(ctx->fmap, data, ctx->off, size);
    if (n <= 0) {
	cli_dbgmsg("bcapi_read: fmap_readn failed (requested %d)\n", size);
	cli_event_count(EV, BCEV_READ_ERR);
	return n;
    }
    cli_event_int(EV, BCEV_OFFSET, ctx->off);
    cli_event_fastdata(EV, BCEV_READ, data, size);
    //cli_event_data(EV, BCEV_READ, data, n);
    ctx->off += n;
    return n;
}
Пример #11
0
/* Fetch a node's contents into the buffer */
static int hfsplus_fetch_node (cli_ctx *ctx, hfsPlusVolumeHeader *volHeader, hfsHeaderRecord *catHeader,
    hfsHeaderRecord *extHeader, uint32_t node, uint8_t *buff)
{
    int foundBlock = 0;
    uint64_t catalogOffset;
    uint32_t fetchBlock, fetchStart;
    uint32_t extentNum = 0, realFileBlock;
    size_t fileOffset = 0;
    hfsPlusForkData *catFork;

    UNUSEDPARAM(extHeader);

    /* Make sure node is in range */
    if (node >= catHeader->totalNodes) {
        cli_dbgmsg("hfsplus_fetch_node: invalid node number " STDu32 "\n", node);
        return CL_EFORMAT;
    }

    catFork = &(volHeader->catalogFile);
    /* Do we need one block or more? */
    if (catHeader->nodeSize <= volHeader->blockSize) {
        /* Need one block */
        /* First, calculate the node's offset within the catalog */
        catalogOffset = (uint64_t)node * catHeader->nodeSize;
        /* Determine which block of the catalog we need */
        fetchBlock = (uint32_t) (catalogOffset / volHeader->blockSize);
        fetchStart = (uint32_t) (catalogOffset % volHeader->blockSize);
        cli_dbgmsg("hfsplus_fetch_node: need catalog block " STDu32 "\n", fetchBlock);
        if (fetchBlock >= catFork->totalBlocks) {
            cli_dbgmsg("hfsplus_fetch_node: block number invalid!\n");
            return CL_EFORMAT;
        }

        /* Find which extent has that block */
        for (extentNum = 0; extentNum < 8; extentNum++) {
            hfsPlusExtentDescriptor *currExt = &(catFork->extents[extentNum]);

            /* Beware empty extent */
            if ((currExt->startBlock == 0) || (currExt->blockCount == 0)) {
                cli_dbgmsg("hfsplus_fetch_node: extent " STDu32 " empty!\n", extentNum);
                return CL_EFORMAT;
            }
            /* Beware too long extent */
            if ((currExt->startBlock & 0x10000000) && (currExt->blockCount & 0x10000000)) {
                cli_dbgmsg("hfsplus_fetch_node: extent " STDu32 " illegal!\n", extentNum);
                return CL_EFORMAT;
            }
            /* Check if block found in current extent */
            if (fetchBlock < currExt->blockCount) {
                cli_dbgmsg("hfsplus_fetch_node: found block in extent " STDu32 "\n", extentNum);
                realFileBlock = currExt->startBlock + fetchBlock;
                foundBlock = 1;
                break;
            }
            else {
                cli_dbgmsg("hfsplus_fetch_node: not in extent " STDu32 "\n", extentNum);
                fetchBlock -= currExt->blockCount;
            }
        }

        if (foundBlock == 0) {
            cli_dbgmsg("hfsplus_fetch_node: not in first 8 extents\n");
            cli_dbgmsg("hfsplus_fetch_node: finding this node requires extent overflow support\n");
            return CL_EFORMAT;
        }

        /* Block found */
        if (realFileBlock >= volHeader->totalBlocks) {
            cli_dbgmsg("hfsplus_fetch_node: block past end of volume\n");
            return CL_EFORMAT;
        }
        fileOffset = realFileBlock * volHeader->blockSize;
    }
    else {
        /* Need more than one block for this node */
        cli_dbgmsg("hfsplus_fetch_node: nodesize bigger than blocksize, is this allowed?\n");
        return CL_EFORMAT;
    }

    if (fileOffset) {
        if (fmap_readn(*ctx->fmap, buff, fileOffset, catHeader->nodeSize) != catHeader->nodeSize) {
            cli_dbgmsg("hfsplus_fetch_node: not all bytes read\n");
            return CL_EFORMAT;
        }
    }
    else {
        cli_dbgmsg("hfsplus_fetch_node: nodesize bigger than blocksize, is this allowed?\n");
        return CL_EFORMAT;
    }

    return CL_CLEAN;
}
Пример #12
0
int cli_scanapm(cli_ctx *ctx)
{
    struct apm_driver_desc_map ddm;
    struct apm_partition_info aptable, apentry;
    int ret = CL_CLEAN, detection = CL_CLEAN, old_school = 0;
    size_t sectorsize, maplen, partsize, sectorcheck;
    off_t pos = 0, partoff = 0;
    unsigned i;
    uint32_t max_prtns = 0;

    if (!ctx || !ctx->fmap) {
        cli_errmsg("cli_scanapm: Invalid context\n");
        return CL_ENULLARG;
    }

    /* read driver description map at sector 0  */
    if (fmap_readn(*ctx->fmap, &ddm, pos, sizeof(ddm)) != sizeof(ddm)) {
        cli_dbgmsg("cli_scanapm: Invalid Apple driver description map\n");
        return CL_EFORMAT;
    }

    /* convert driver description map big-endian to host */
    ddm.signature = be16_to_host(ddm.signature);
    ddm.blockSize = be16_to_host(ddm.blockSize);
    ddm.blockCount = be32_to_host(ddm.blockCount);

    /* check DDM signature */
    if (ddm.signature != DDM_SIGNATURE) {
        cli_dbgmsg("cli_scanapm: Apple driver description map signature mismatch\n");
        return CL_EFORMAT;
    }

    /* sector size is determined by the ddm */
    sectorsize = ddm.blockSize;

    /* size of total file must be described by the ddm */
    maplen = (*ctx->fmap)->real_len;
    if ((ddm.blockSize * ddm.blockCount) != maplen) {
        cli_dbgmsg("cli_scanapm: File described %u size does not match %lu actual size\n",
                   (ddm.blockSize * ddm.blockCount), (unsigned long)maplen);
        return CL_EFORMAT;
    }

    /* check for old-school partition map */
    if (sectorsize == 2048) {
        if (fmap_readn(*ctx->fmap, &aptable, APM_FALLBACK_SECTOR_SIZE, sizeof(aptable)) != sizeof(aptable)) {
            cli_dbgmsg("cli_scanapm: Invalid Apple partition entry\n");
            return CL_EFORMAT;
        }

        aptable.signature = be16_to_host(aptable.signature);
        if (aptable.signature == APM_SIGNATURE) {
            sectorsize = APM_FALLBACK_SECTOR_SIZE;
            old_school = 1;
        }
    }

    /* read partition table at sector 1 (or after the ddm if old-school) */
    pos = APM_PTABLE_BLOCK * sectorsize;

    if (fmap_readn(*ctx->fmap, &aptable, pos, sizeof(aptable)) != sizeof(aptable)) {
        cli_dbgmsg("cli_scanapm: Invalid Apple partition table\n");
        return CL_EFORMAT;
    }

    /* convert partition table big endian to host */
    aptable.signature = be16_to_host(aptable.signature);
    aptable.numPartitions = be32_to_host(aptable.numPartitions);
    aptable.pBlockStart = be32_to_host(aptable.pBlockStart);
    aptable.pBlockCount = be32_to_host(aptable.pBlockCount);

    /* check the partition entry signature */
    if (aptable.signature != APM_SIGNATURE) {
        cli_dbgmsg("cli_scanapm: Apple partition table signature mismatch\n");
        return CL_EFORMAT;
    }

    /* check if partition table partition */
    if (strncmp((char*)aptable.type, "Apple_Partition_Map", 32) &&
            strncmp((char*)aptable.type, "Apple_partition_map", 32) &&
            strncmp((char*)aptable.type, "Apple_patition_map", 32)) {
        cli_dbgmsg("cli_scanapm: Initial Apple Partition Map partition is not detected\n");
        return CL_EFORMAT;
    }

    /* check that the partition table fits in the space specified - HEURISTICS */
    if ((ctx->options & CL_SCAN_PARTITION_INTXN) && (ctx->dconf->other & OTHER_CONF_PRTNINTXN)) {
        ret = apm_prtn_intxn(ctx, &aptable, sectorsize, old_school);
        if (ret != CL_CLEAN) {
            if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
                detection = CL_VIRUS;
            else
                return ret;
        }
    }

    /* print debugging info on partition tables */
    cli_dbgmsg("APM Partition Table:\n");
    cli_dbgmsg("Name: %s\n", (char*)aptable.name);
    cli_dbgmsg("Type: %s\n", (char*)aptable.type);
    cli_dbgmsg("Signature: %x\n", aptable.signature);
    cli_dbgmsg("Partition Count: %u\n", aptable.numPartitions);
    cli_dbgmsg("Blocks: [%u, +%u), ([%lu, +%lu))\n",
               aptable.pBlockStart, aptable.pBlockCount,
               (unsigned long)(aptable.pBlockStart * sectorsize),
               (unsigned long)(aptable.pBlockCount * sectorsize));

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

    /* partition table is a partition [at index 1], so skip it */
    for (i = 2; 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");
            return CL_EFORMAT;
        }

        /* convert partition entry big endian to host */
        apentry.signature = be16_to_host(apentry.signature);
        apentry.reserved = be16_to_host(apentry.reserved);
        apentry.numPartitions = be32_to_host(apentry.numPartitions);
        apentry.pBlockStart = be32_to_host(apentry.pBlockStart);
        apentry.pBlockCount = be32_to_host(apentry.pBlockCount);

        /* check the partition entry signature */
        if (aptable.signature != APM_SIGNATURE) {
            cli_dbgmsg("cli_scanapm: Apple partition entry signature mismatch\n");
            return CL_EFORMAT;
        }

        /* check if a out-of-order partition map */
        if (!strncmp((char*)apentry.type, "Apple_Partition_Map", 32) ||
                !strncmp((char*)apentry.type, "Apple_partition_map", 32) ||
                !strncmp((char*)apentry.type, "Apple_patition_map", 32)) {

            cli_dbgmsg("cli_scanapm: Out of order Apple Partition Map partition\n");
            continue;
        }

        partoff = apentry.pBlockStart * sectorsize;
        partsize = apentry.pBlockCount * sectorsize;
        /* 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)) {

                partsize = apentry.pBlockCount * 2048;;
            }
        }

        /* check if invalid partition */
        if ((partoff == 0) || (partoff+partsize > maplen)) {
            cli_dbgmsg("cli_scanapm: Detected invalid Apple partition entry\n");
            continue;
        }

        /* print debugging info on partition */
        cli_dbgmsg("APM Partition Entry %u:\n", i);
        cli_dbgmsg("Name: %s\n", (char*)apentry.name);
        cli_dbgmsg("Type: %s\n", (char*)apentry.type);
        cli_dbgmsg("Signature: %x\n", apentry.signature);
        cli_dbgmsg("Partition Count: %u\n", apentry.numPartitions);
        cli_dbgmsg("Blocks: [%u, +%u), ([%lu, +%lu))\n",
                   apentry.pBlockStart, apentry.pBlockCount, (long unsigned)partoff, (long unsigned)partsize);

        /* send the partition to cli_map_scan */
        ret = cli_map_scan(*ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY);
        if (ret != CL_CLEAN) {
            if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
                detection = CL_VIRUS;
            else
                return ret;
        }
    }

    if (i >= ctx->engine->maxpartitions) {
        cli_dbgmsg("cli_scanapm: max partitions reached\n");
    }

    return detection;
}
Пример #13
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;
}
Пример #14
0
int
cli_tnef(const char *dir, cli_ctx *ctx)
{
	uint32_t i32;
	uint16_t i16;
	fileblob *fb;
	int ret, alldone;
	off_t fsize, pos = 0;
	STATBUF statb;


	fsize = ctx->fmap[0]->len;

	if(fsize < (off_t) MIN_SIZE) {
		cli_dbgmsg("cli_tngs: file too small, ignoring\n");
		return CL_CLEAN;
	}

	if (fmap_readn(*ctx->fmap, &i32, pos, sizeof(uint32_t)) != sizeof(uint32_t)) {
		/* The file is at least MIN_SIZE bytes, so it "can't" fail */
		return CL_EREAD;
	}
	pos += sizeof(uint32_t);

	if(host32(i32) != TNEF_SIGNATURE) {
		return CL_EFORMAT;
	}

	if(fmap_readn(*ctx->fmap, &i16, pos, sizeof(uint16_t)) != sizeof(uint16_t)) {
		/* The file is at least MIN_SIZE bytes, so it "can't" fail */
		return CL_EREAD;
	}
	pos += sizeof(uint16_t);

	fb = NULL;
	ret = CL_CLEAN;	/* we don't know if it's clean or not :-) */
	alldone = 0;

	do {
		uint8_t part = 0;
		uint16_t type = 0, tag = 0;
		int32_t length = 0;

		switch(tnef_header(*ctx->fmap, &pos, &part, &type, &tag, &length)) {
			case 0:
				alldone = 1;
				break;
			case 1:
				break;
			default:
				/*
				 * Assume truncation, not file I/O error
				 */
				cli_warnmsg("cli_tnef: file truncated, returning CLEAN\n");
				ret = CL_CLEAN;
				alldone = 1;
				break;
		}
		if(length == 0)
			continue;
		if(length < 0) {
			cli_warnmsg("Corrupt TNEF header detected - length %d\n",
				(int)length);
			ret = CL_EFORMAT;
			break;
		}
		if(alldone)
			break;
		switch(part) {
			case LVL_MESSAGE:
				cli_dbgmsg("TNEF - found message\n");
				if(fb != NULL) {
					fileblobDestroy(fb);
					fb = NULL;
				}
				fb = fileblobCreate();
				if(tnef_message(*ctx->fmap, &pos, type, tag, length, fsize) != 0) {
					cli_dbgmsg("TNEF: Error reading TNEF message\n");
					ret = CL_EFORMAT;
					alldone = 1;
				}
				break;
			case LVL_ATTACHMENT:
				cli_dbgmsg("TNEF - found attachment\n");
				if(tnef_attachment(*ctx->fmap, &pos, type, tag, length, dir, &fb, fsize) != 0) {
					cli_dbgmsg("TNEF: Error reading TNEF attachment\n");
					ret = CL_EFORMAT;
					alldone = 1;
				}
				break;
			case 0:
				break;
			default:
				cli_warnmsg("TNEF - unknown level %d tag 0x%x\n", (int)part, (int)tag);

				/*
				 * Dump the file incase it was part of an
				 * email that's about to be deleted
				 */
				if(cli_debug_flag) {
					int fout = -1;
					char *filename = cli_gentemp(ctx->engine->tmpdir);
					char buffer[BUFSIZ];

					if(filename)
						fout = open(filename, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC|O_BINARY, 0600);

					if(fout >= 0) {
						int count;

						cli_warnmsg("Saving dump to %s:  refer to http://www.clamav.net/bugs\n", filename);

						pos = 0;
						while ((count = fmap_readn(*ctx->fmap, buffer, pos, sizeof(buffer))) > 0) {
						        pos += count;
							cli_writen(fout, buffer, count);
						}
						close(fout);
					}
					free(filename);
				}
				ret = CL_EFORMAT;
				alldone = 1;
				break;
		}
	} while(!alldone);

	if(fb) {
		cli_dbgmsg("cli_tnef: flushing final data\n");
		if(fileblobGetFilename(fb) == NULL) {
			cli_dbgmsg("Saving TNEF portion with an unknown name\n");
			fileblobSetFilename(fb, dir, "tnef");
		}
		fileblobDestroy(fb);
		fb = NULL;
	}

	cli_dbgmsg("cli_tnef: returning %d\n", ret);
	return ret;
}
Пример #15
0
int cli_scancpio_old(cli_ctx *ctx)
{
	struct cpio_hdr_old hdr_old;
	char name[513];
	unsigned int file = 0, trailer = 0;
	uint32_t filesize, namesize, hdr_namesize;
	int ret, conv;
	off_t pos = 0;


    while(fmap_readn(*ctx->fmap, &hdr_old, pos, sizeof(hdr_old)) == sizeof(hdr_old)) {
	pos += sizeof(hdr_old);
	if(!hdr_old.magic && trailer)
	    return CL_SUCCESS;

	if(hdr_old.magic == 070707) {
	    conv = 0;
	} else if(hdr_old.magic == 0143561) {
	    conv = 1;
	} else {
	    cli_dbgmsg("cli_scancpio_old: Invalid magic number\n");
	    return CL_EFORMAT;
	}

	cli_dbgmsg("CPIO: -- File %u --\n", ++file);

	if(hdr_old.namesize) {
	    hdr_namesize = EC16(hdr_old.namesize, conv);
	    namesize = MIN(sizeof(name), hdr_namesize);
	    if ((uint32_t)fmap_readn(*ctx->fmap, &name, pos, namesize) != namesize) {
		cli_dbgmsg("cli_scancpio_old: Can't read file name\n");
		return CL_EFORMAT;
	    }
	    pos += namesize;
	    name[namesize - 1] = 0;
	    sanitname(name);
	    cli_dbgmsg("CPIO: Name: %s\n", name);
	    if(!strcmp(name, "TRAILER!!!"))
		trailer = 1;

	    if(namesize < hdr_namesize) {
		if(hdr_namesize % 2)
		    hdr_namesize++;
		pos += hdr_namesize - namesize;
	    } else if(hdr_namesize % 2)
		pos++;
	}
	filesize = (uint32_t) (EC16(hdr_old.filesize[0], conv) << 16 | EC16(hdr_old.filesize[1], conv));
	cli_dbgmsg("CPIO: Filesize: %u\n", filesize);
	if(!filesize)
	    continue;

	if(cli_matchmeta(ctx, name, filesize, filesize, 0, file, 0, NULL) == CL_VIRUS)
	    return CL_VIRUS;


	if((EC16(hdr_old.mode, conv) & 0170000) != 0100000) {
	    cli_dbgmsg("CPIO: Not a regular file, skipping\n");
	} else {
	    ret = cli_checklimits("cli_scancpio_old", ctx, filesize, 0, 0);
	    if(ret == CL_EMAXFILES) {
		return ret;
	    } else if(ret == CL_SUCCESS) {
		ret = cli_map_scan(*ctx->fmap, pos, filesize, ctx, CL_TYPE_ANY);
		if(ret == CL_VIRUS)
		    return ret;
	    }
	}
	if(filesize % 2)
	    filesize++;

	pos += filesize;
    }

    return CL_CLEAN;
}
Пример #16
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;
}
Пример #17
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 && DETECT_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 && DETECT_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 %u\n", i);
	    cli_dbgmsg("ELF: Section offset: " STDu64 "\n", EC64(section_hdr[i].sh_offset, conv));
	    cli_dbgmsg("ELF: Section size: " STDu64 "\n", 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;
}
Пример #18
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;
}
Пример #19
0
static int mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, off_t extlba, size_t extlbasize, size_t sectorsize)
{
    struct mbr_boot_record ebr;
    enum MBR_STATE state = SEEN_NOTHING;
    int ret = CL_CLEAN, detection = CL_CLEAN;
    off_t pos = 0, mbr_base = 0, logiclba = 0, extoff = 0, partoff = 0;
    size_t partsize, extsize;
    unsigned i = 0, j = 0;

    ebr_parsemsg("The start of something exhausting: EBR parsing\n");

    mbr_base = sectorsize - sizeof(struct mbr_boot_record);

    logiclba = 0;
    extoff = extlba * sectorsize;
    extsize = extlbasize * sectorsize;
    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");
            return CL_EFORMAT;
        }

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

        /* EBR checks */
        ret = mbr_check_ebr(&ebr);
        if (ret != CL_CLEAN) {
            return ret;
        }

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

        /* EBR is valid, examine partitions */
        cli_dbgmsg("EBR Partition Entry %u:\n", i++);
        cli_dbgmsg("EBR Signature: %x\n", ebr.signature);
        for (j = 0; j < MBR_MAX_PARTITION_ENTRIES; ++j) {
            if (j < 2) {
                cli_dbgmsg("Logical Partition Entry %u:\n", j);
                cli_dbgmsg("Status: %u\n", ebr.entries[j].status);
                cli_dbgmsg("Type: %x\n", ebr.entries[j].type);
                cli_dbgmsg("Blocks: [%u, +%u), ([%lu, +%lu))\n",
                           ebr.entries[j].firstLBA, ebr.entries[j].numLBA,
                           (unsigned long)(ebr.entries[j].firstLBA * sectorsize),
                           (unsigned long)(ebr.entries[j].numLBA * sectorsize));

                if (ebr.entries[j].type == MBR_EMPTY) {
                    /* empty partiton entry */
                    switch(state) {
                    case SEEN_NOTHING:
                        state = SEEN_EMPTY;
                        break;
                    case SEEN_PARTITION:
                        logiclba = 0;
                        break;
                    case SEEN_EMPTY:
                        logiclba = 0;
                        /* fall-through */
                    case SEEN_EXTENDED:
                        cli_warnmsg("cli_scanebr: detected a logical boot record "
                                    "without a partition record\n");
                        break;
                    default:
                        cli_warnmsg("cli_scanebr: undefined state for EBR parsing\n");
                        return CL_EPARSE;
                    }
                }
                else if (ebr.entries[j].type == MBR_EXTENDED) {
                    switch(state) {
                    case SEEN_NOTHING:
                        state = SEEN_EXTENDED;
                        break;
                    case SEEN_PARTITION:
                        break;
                    case SEEN_EMPTY:
                        cli_warnmsg("cli_scanebr: detected a logical boot record "
                                    "without a partition record\n");
                        break;
                    case SEEN_EXTENDED:
                        cli_warnmsg("cli_scanebr: detected a logical boot record "
                                    "with multiple extended partition records\n");
                        return CL_EFORMAT;
                    default:
                        cli_dbgmsg("cli_scanebr: undefined state for EBR parsing\n");
                        return CL_EPARSE;
                    }

                    logiclba = ebr.entries[j].firstLBA;
                }
                else {
                    switch(state) {
                    case SEEN_NOTHING:
                        state = SEEN_PARTITION;
                        break;
                    case SEEN_PARTITION:
                        cli_warnmsg("cli_scanebr: detected a logical boot record "
                                    "with multiple partition records\n");
                        logiclba = 0; /* no extended partitions are possible */
                        break;
                    case SEEN_EXTENDED:
                        cli_warnmsg("cli_scanebr: detected a logical boot record "
                                    "with extended partition record first\n");
                        break;
                    case SEEN_EMPTY:
                        cli_warnmsg("cli_scanebr: detected a logical boot record "
                                    "with empty partition record first\n");
                        logiclba = 0; /* no extended partitions are possible */
                        break;
                    default:
                        cli_dbgmsg("cli_scanebr: undefined state for EBR parsing\n");
                        return CL_EPARSE;
                    }

                    partoff = (extlba + logiclba + ebr.entries[j].firstLBA) * sectorsize;
                    partsize = ebr.entries[j].numLBA * sectorsize;
                    if (partoff + partsize > extoff + extsize) {
                        cli_dbgmsg("cli_scanebr: Invalid extended partition entry\n");
                        return CL_EFORMAT;
                    }

                    ret = cli_map_scan(*ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY);
                    if (ret != CL_CLEAN) {
                        if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
                            detection = CL_VIRUS;
                        else
                            return ret;
                    }
                }
            }
            else {
                /* check the last two entries to be empty */
                if (ebr.entries[j].type != MBR_EMPTY) {
                    cli_dbgmsg("cli_scanebr: detected a non-empty partition "
                               "entry at index %u\n", j);
                    /* should we attempt to use these entries? */
                    return CL_EFORMAT;
                }
            }
        }
    } while (logiclba != 0 && (*prtncount) < ctx->engine->maxpartitions);

    cli_dbgmsg("cli_scanmbr: examined %u logical partitions\n", i);

    return detection;
}
Пример #20
0
/* sets sectorsize to default value if specified to be 0 */
int cli_scanmbr(cli_ctx *ctx, size_t sectorsize)
{
    struct mbr_boot_record mbr;
    enum MBR_STATE state = SEEN_NOTHING;
    int ret = CL_CLEAN, detection = CL_CLEAN;
    off_t pos = 0, mbr_base = 0, partoff = 0;
    unsigned i = 0, prtncount = 0;
    size_t maplen, partsize;

    mbr_parsemsg("The start of something magnificant: MBR parsing\n");

    if (!ctx || !ctx->fmap) {
        cli_errmsg("cli_scanmbr: Invalid context\n");
        return CL_ENULLARG;
    }

    /* sector size calculation, actual value is OS dependent */
    if (sectorsize == 0)
        sectorsize = MBR_SECTOR_SIZE;

    mbr_base = sectorsize - sizeof(struct mbr_boot_record);

    /* size of total file must be a multiple of the sector size */
    maplen = (*ctx->fmap)->real_len;
    if ((maplen % sectorsize) != 0) {
        cli_dbgmsg("cli_scanmbr: File sized %lu is not a multiple of sector size %lu\n",
                   (unsigned long)maplen, (unsigned long)sectorsize);
        return CL_EFORMAT;
    }

    /* sector 0 (first sector) is the master boot record */
    pos = (MBR_SECTOR * sectorsize) + mbr_base;

    /* read the master boot record */
    if (fmap_readn(*ctx->fmap, &mbr, pos, sizeof(mbr)) != sizeof(mbr)) {
        cli_dbgmsg("cli_scanmbr: Invalid master boot record\n");
        return CL_EFORMAT;
    }

    /* convert the little endian to host, include the internal  */
    mbr_convert_to_host(&mbr);

    /* MBR checks */
    ret = mbr_check_mbr(&mbr, maplen, sectorsize);
    if (ret != CL_CLEAN) {
        return ret;
    }

    /* MBR is valid, examine bootstrap code */
    ret = cli_map_scan(*ctx->fmap, 0, sectorsize, ctx, CL_TYPE_ANY);
    if (ret != CL_CLEAN) {
        if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
            detection = CL_VIRUS;
        else
            return ret;
    }

    /* check that the partition table has no intersections - HEURISTICS */
    if ((ctx->options & CL_SCAN_PARTITION_INTXN) && (ctx->dconf->other & OTHER_CONF_PRTNINTXN)) {
        ret = mbr_primary_prtn_intxn(ctx, mbr, sectorsize);
        if (ret != CL_CLEAN) {
            if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
                detection = CL_VIRUS;
            else
                return ret;
        }
    }

    /* MBR is valid, examine partitions */
    prtncount = 0;
    cli_dbgmsg("MBR Signature: %x\n", mbr.signature);
    for (i = 0; i < MBR_MAX_PARTITION_ENTRIES && prtncount < ctx->engine->maxpartitions; ++i) {
        cli_dbgmsg("MBR Partition Entry %u:\n", i);
        cli_dbgmsg("Status: %u\n", mbr.entries[i].status);
        cli_dbgmsg("Type: %x\n", mbr.entries[i].type);
        cli_dbgmsg("Blocks: [%u, +%u), ([%lu, +%lu))\n",
                   mbr.entries[i].firstLBA, mbr.entries[i].numLBA,
                   (unsigned long)(mbr.entries[i].firstLBA * sectorsize),
                   (unsigned long)(mbr.entries[i].numLBA * sectorsize));

        /* Handle MBR entry based on type */
        if (mbr.entries[i].type == MBR_EMPTY) {
            /* empty partiton entry */
            prtncount++;
        }
        else if (mbr.entries[i].type == MBR_EXTENDED) {
            if (state == SEEN_EXTENDED) {
                cli_dbgmsg("cli_scanmbr: detected a master boot record "
                           "with multiple extended partitions\n");
            }
            state = SEEN_EXTENDED; /* used only to detect multiple extended partitions */

            ret = mbr_scanextprtn(ctx, &prtncount, mbr.entries[i].firstLBA, 
                                  mbr.entries[i].numLBA, sectorsize);
            if (ret != CL_CLEAN) {
                if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
                    detection = CL_VIRUS;
                else
                    return ret;
            }
        }
        else {
            prtncount++;

            partoff = mbr.entries[i].firstLBA * sectorsize;
            partsize = mbr.entries[i].numLBA * sectorsize;
            mbr_parsemsg("cli_map_scan: [%u, +%u)\n", partoff, partsize);
            ret = cli_map_scan(*ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY);
            if (ret != CL_CLEAN) {
                if ((ctx->options & CL_SCAN_ALLMATCHES) && (ret == CL_VIRUS))
                    detection = CL_VIRUS;
                else
                    return ret;
            }
        }
    }

    if (prtncount >= ctx->engine->maxpartitions) {
        cli_dbgmsg("cli_scanmbr: maximum partitions reached\n");
    }

    return detection;
}
Пример #21
0
int cli_scanxar(cli_ctx *ctx)
{
    int rc = CL_SUCCESS;
    unsigned int cksum_fails = 0;
    unsigned int extract_errors = 0;
#if HAVE_LIBXML2
    int fd = -1;
    struct xar_header hdr;
    fmap_t *map = *ctx->fmap;
    long length, offset, size, at;
    int encoding;
    z_stream strm;
    char *toc, *tmpname;
    xmlTextReaderPtr reader = NULL;
    int a_hash, e_hash;
    unsigned char *a_cksum = NULL, *e_cksum = NULL;

    memset(&strm, 0x00, sizeof(z_stream));

    /* retrieve xar header */
    if (fmap_readn(*ctx->fmap, &hdr, 0, sizeof(hdr)) != sizeof(hdr)) {
        cli_dbgmsg("cli_scanxar: Invalid header, too short.\n");
        return CL_EFORMAT;
    }
    hdr.magic = be32_to_host(hdr.magic);

    if (hdr.magic == XAR_HEADER_MAGIC) {
        cli_dbgmsg("cli_scanxar: Matched magic\n");
    }
    else {
        cli_dbgmsg("cli_scanxar: Invalid magic\n");
        return CL_EFORMAT;
    }
    hdr.size = be16_to_host(hdr.size);
    hdr.version = be16_to_host(hdr.version);
    hdr.toc_length_compressed = be64_to_host(hdr.toc_length_compressed);
    hdr.toc_length_decompressed = be64_to_host(hdr.toc_length_decompressed);
    hdr.chksum_alg = be32_to_host(hdr.chksum_alg);

    /* cli_dbgmsg("hdr.magic %x\n", hdr.magic); */
    /* cli_dbgmsg("hdr.size %i\n", hdr.size); */
    /* cli_dbgmsg("hdr.version %i\n", hdr.version); */
    /* cli_dbgmsg("hdr.toc_length_compressed %lu\n", hdr.toc_length_compressed); */
    /* cli_dbgmsg("hdr.toc_length_decompressed %lu\n", hdr.toc_length_decompressed); */
    /* cli_dbgmsg("hdr.chksum_alg %i\n", hdr.chksum_alg); */

    /* Uncompress TOC */
    strm.next_in = (unsigned char *)fmap_need_off_once(*ctx->fmap, hdr.size, hdr.toc_length_compressed);
    if (strm.next_in == NULL) {
        cli_dbgmsg("cli_scanxar: fmap_need_off_once fails on TOC.\n");
        return CL_EREAD;
    }
    strm.avail_in = hdr.toc_length_compressed;
    toc = cli_malloc(hdr.toc_length_decompressed+1);
    if (toc == NULL) {
        cli_dbgmsg("cli_scanxar: cli_malloc fails on TOC decompress buffer.\n");
        return CL_EMEM;
    }
    toc[hdr.toc_length_decompressed] = '\0';
    strm.avail_out = hdr.toc_length_decompressed;
    strm.next_out = (unsigned char *)toc;
    rc = inflateInit(&strm);
    if (rc != Z_OK) {
        cli_dbgmsg("cli_scanxar:inflateInit error %i \n", rc);
        rc = CL_EFORMAT;
        goto exit_toc;
    }
    rc = inflate(&strm, Z_SYNC_FLUSH);
    if (rc != Z_OK && rc != Z_STREAM_END) {
        cli_dbgmsg("cli_scanxar:inflate error %i \n", rc);
        rc = CL_EFORMAT;
        goto exit_toc;
    }
    rc = inflateEnd(&strm);
    if (rc != Z_OK) {
        cli_dbgmsg("cli_scanxar:inflateEnd error %i \n", rc);
        rc = CL_EFORMAT;
        goto exit_toc;
    }

    /* cli_dbgmsg("cli_scanxar: TOC xml:\n%s\n", toc); */
    /* printf("cli_scanxar: TOC xml:\n%s\n", toc); */
    /* cli_dbgmsg("cli_scanxar: TOC end:\n"); */
    /* printf("cli_scanxar: TOC end:\n"); */

    /* scan the xml */
    cli_dbgmsg("cli_scanxar: scanning xar TOC xml in memory.\n");
    rc = cli_mem_scandesc(toc, hdr.toc_length_decompressed, ctx);
    if (rc != CL_SUCCESS) {
        if (rc != CL_VIRUS || !SCAN_ALL)
            goto exit_toc;
    }

    /* make a file to leave if --leave-temps in effect */
    if(ctx->engine->keeptmp) {
        if ((rc = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
            cli_dbgmsg("cli_scanxar: Can't create temporary file for TOC.\n");
            goto exit_toc;
        }
        if (cli_writen(fd, toc, hdr.toc_length_decompressed) < 0) {
            cli_dbgmsg("cli_scanxar: cli_writen error writing TOC.\n");
            rc = CL_EWRITE;
            xar_cleanup_temp_file(ctx, fd, tmpname);
            goto exit_toc;
        }
        rc = xar_cleanup_temp_file(ctx, fd, tmpname);
        if (rc != CL_SUCCESS)
            goto exit_toc;
    }

    reader = xmlReaderForMemory(toc, hdr.toc_length_decompressed, "noname.xml", NULL, 0);
    if (reader == NULL) {
        cli_dbgmsg("cli_scanxar: xmlReaderForMemory error for TOC\n");
        goto exit_toc;
    }

    rc = xar_scan_subdocuments(reader, ctx);
    if (rc != CL_SUCCESS) {
        cli_dbgmsg("xar_scan_subdocuments returns %i.\n", rc);
        goto exit_reader;
    }

    /* Walk the TOC XML and extract files */
    fd = -1;
    tmpname = NULL;
    while (CL_SUCCESS == (rc = xar_get_toc_data_values(reader, &length, &offset, &size, &encoding,
                               &a_cksum, &a_hash, &e_cksum, &e_hash))) {
        int do_extract_cksum = 1;
        unsigned char * blockp;
        void *a_sc, *e_sc;
        void *a_mc, *e_mc;
        void *a_hash_ctx, *e_hash_ctx;
        char result[SHA1_HASH_SIZE];
        char * expected;

        /* clean up temp file from previous loop iteration */
        if (fd > -1 && tmpname) {
            rc = xar_cleanup_temp_file(ctx, fd, tmpname);
            if (rc != CL_SUCCESS)
                goto exit_reader;
        }

        at = offset + hdr.toc_length_compressed + hdr.size;

        if ((rc = cli_gentempfd(ctx->engine->tmpdir, &tmpname, &fd)) != CL_SUCCESS) {
            cli_dbgmsg("cli_scanxar: Can't generate temporary file.\n");
            goto exit_reader;
        }

        cli_dbgmsg("cli_scanxar: decompress into temp file:\n%s, size %li,\n"
                   "from xar heap offset %li length %li\n",
                   tmpname, size, offset, length);


        a_hash_ctx = xar_hash_init(a_hash, &a_sc, &a_mc);
        e_hash_ctx = xar_hash_init(e_hash, &e_sc, &e_mc);

        switch (encoding) {
        case CL_TYPE_GZ:
            /* inflate gzip directly because file segments do not contain magic */
            memset(&strm, 0, sizeof(strm));
            if ((rc = inflateInit(&strm)) != Z_OK) {
                cli_dbgmsg("cli_scanxar: InflateInit failed: %d\n", rc);
                rc = CL_EFORMAT;
                extract_errors++;
                break;
            }

            while ((size_t)at < map->len && (unsigned long)at < offset+hdr.toc_length_compressed+hdr.size+length) {
                unsigned long avail_in;
                void * next_in;
                unsigned int bytes = MIN(map->len - at, map->pgsz);
                bytes = MIN(length, bytes);
                if(!(strm.next_in = next_in = (void*)fmap_need_off_once(map, at, bytes))) {
                    cli_dbgmsg("cli_scanxar: Can't read %u bytes @ %lu.\n", bytes, (long unsigned)at);
                    inflateEnd(&strm);
                    rc = CL_EREAD;
                    goto exit_tmpfile;
                }
                at += bytes;
                strm.avail_in = avail_in = bytes;
                do {
                    int inf, outsize = 0;
                    unsigned char buff[FILEBUFF];
                    strm.avail_out = sizeof(buff);
                    strm.next_out = buff;
                    inf = inflate(&strm, Z_SYNC_FLUSH);
                    if (inf != Z_OK && inf != Z_STREAM_END && inf != Z_BUF_ERROR) {
                        cli_dbgmsg("cli_scanxar: inflate error %i %s.\n", inf, strm.msg?strm.msg:"");
                        rc = CL_EFORMAT;
                        extract_errors++;
                        break;
                    }

                    bytes = sizeof(buff) - strm.avail_out;

                    xar_hash_update(e_hash_ctx, buff, bytes, e_hash);

                    if (cli_writen(fd, buff, bytes) < 0) {
                        cli_dbgmsg("cli_scanxar: cli_writen error file %s.\n", tmpname);
                        inflateEnd(&strm);
                        rc = CL_EWRITE;
                        goto exit_tmpfile;
                    }
                    outsize += sizeof(buff) - strm.avail_out;
                    if (cli_checklimits("cli_scanxar", ctx, outsize, 0, 0) != CL_CLEAN) {
                        break;
                    }
                    if (inf == Z_STREAM_END) {
                        break;
                    }
                } while (strm.avail_out == 0);

                if (rc != CL_SUCCESS)
                    break;

                avail_in -= strm.avail_in;
                xar_hash_update(a_hash_ctx, next_in, avail_in, a_hash);
            }

            inflateEnd(&strm);
            break;
        case CL_TYPE_7Z:
#define CLI_LZMA_OBUF_SIZE 1024*1024
#define CLI_LZMA_HDR_SIZE LZMA_PROPS_SIZE+8
#define CLI_LZMA_IBUF_SIZE CLI_LZMA_OBUF_SIZE>>2 /* estimated compression ratio 25% */
        {
            struct CLI_LZMA lz;
            unsigned long in_remaining = length;
            unsigned long out_size = 0;
            unsigned char * buff = __lzma_wrap_alloc(NULL, CLI_LZMA_OBUF_SIZE);
            int lret;

            memset(&lz, 0, sizeof(lz));
            if (buff == NULL) {
                cli_dbgmsg("cli_scanxar: memory request for lzma decompression buffer fails.\n");
                rc = CL_EMEM;
                goto exit_tmpfile;

            }

            blockp = (void*)fmap_need_off_once(map, at, CLI_LZMA_HDR_SIZE);
            if (blockp == NULL) {
                char errbuff[128];
                cli_strerror(errno, errbuff, sizeof(errbuff));
                cli_dbgmsg("cli_scanxar: Can't read %li bytes @ %li, errno:%s.\n",
                           length, at, errbuff);
                rc = CL_EREAD;
                __lzma_wrap_free(NULL, buff);
                goto exit_tmpfile;
            }

            lz.next_in = blockp;
            lz.avail_in = CLI_LZMA_HDR_SIZE;

            xar_hash_update(a_hash_ctx, blockp, CLI_LZMA_HDR_SIZE, a_hash);

            lret = cli_LzmaInit(&lz, 0);
            if (lret != LZMA_RESULT_OK) {
                cli_dbgmsg("cli_scanxar: cli_LzmaInit() fails: %i.\n", lret);
                rc = CL_EFORMAT;
                __lzma_wrap_free(NULL, buff);
                extract_errors++;
                break;
            }

            at += CLI_LZMA_HDR_SIZE;
            in_remaining -= CLI_LZMA_HDR_SIZE;
            while ((size_t)at < map->len && (unsigned long)at < offset+hdr.toc_length_compressed+hdr.size+length) {
                SizeT avail_in;
                SizeT avail_out;
                void * next_in;
                unsigned long in_consumed;

                lz.next_out = buff;
                lz.avail_out = CLI_LZMA_OBUF_SIZE;
                lz.avail_in = avail_in = MIN(CLI_LZMA_IBUF_SIZE, in_remaining);
                lz.next_in = next_in = (void*)fmap_need_off_once(map, at, lz.avail_in);
                if (lz.next_in == NULL) {
                    char errbuff[128];
                    cli_strerror(errno, errbuff, sizeof(errbuff));
                    cli_dbgmsg("cli_scanxar: Can't read %li bytes @ %li, errno: %s.\n",
                               length, at, errbuff);
                    rc = CL_EREAD;
                    __lzma_wrap_free(NULL, buff);
                    cli_LzmaShutdown(&lz);
                    goto exit_tmpfile;
                }

                lret = cli_LzmaDecode(&lz);
                if (lret != LZMA_RESULT_OK && lret != LZMA_STREAM_END) {
                    cli_dbgmsg("cli_scanxar: cli_LzmaDecode() fails: %i.\n", lret);
                    rc = CL_EFORMAT;
                    extract_errors++;
                    break;
                }

                in_consumed = avail_in - lz.avail_in;
                in_remaining -= in_consumed;
                at += in_consumed;
                avail_out = CLI_LZMA_OBUF_SIZE - lz.avail_out;

                if (avail_out == 0)
                    cli_dbgmsg("cli_scanxar: cli_LzmaDecode() produces no output for "
                               "avail_in %lu, avail_out %lu.\n", avail_in, avail_out);

                xar_hash_update(a_hash_ctx, next_in, in_consumed, a_hash);
                xar_hash_update(e_hash_ctx, buff, avail_out, e_hash);

                /* Write a decompressed block. */
                /* cli_dbgmsg("Writing %li bytes to LZMA decompress temp file, " */
                /*            "consumed %li of %li available compressed bytes.\n", */
                /*            avail_out, in_consumed, avail_in); */

                if (cli_writen(fd, buff, avail_out) < 0) {
                    cli_dbgmsg("cli_scanxar: cli_writen error writing lzma temp file for %li bytes.\n",
                               avail_out);
                    __lzma_wrap_free(NULL, buff);
                    cli_LzmaShutdown(&lz);
                    rc = CL_EWRITE;
                    goto exit_tmpfile;
                }

                /* Check file size limitation. */
                out_size += avail_out;
                if (cli_checklimits("cli_scanxar", ctx, out_size, 0, 0) != CL_CLEAN) {
                    break;
                }

                if (lret == LZMA_STREAM_END)
                    break;
            }

            cli_LzmaShutdown(&lz);
            __lzma_wrap_free(NULL, buff);
        }
        break;
        case CL_TYPE_ANY:
        default:
        case CL_TYPE_BZ:
        case CL_TYPE_XZ:
            /* for uncompressed, bzip2, xz, and unknown, just pull the file, cli_magic_scandesc does the rest */
            do_extract_cksum = 0;
            {
                unsigned long write_len;

                if (ctx->engine->maxfilesize)
                    write_len = MIN((size_t)(ctx->engine->maxfilesize), (size_t)length);
                else
                    write_len = length;

                if (!(blockp = (void*)fmap_need_off_once(map, at, length))) {
                    char errbuff[128];
                    cli_strerror(errno, errbuff, sizeof(errbuff));
                    cli_dbgmsg("cli_scanxar: Can't read %li bytes @ %li, errno:%s.\n",
                               length, at, errbuff);
                    rc = CL_EREAD;
                    goto exit_tmpfile;
                }

                xar_hash_update(a_hash_ctx, blockp, length, a_hash);

                if (cli_writen(fd, blockp, write_len) < 0) {
                    cli_dbgmsg("cli_scanxar: cli_writen error %li bytes @ %li.\n", length, at);
                    rc = CL_EWRITE;
                    goto exit_tmpfile;
                }
                /*break;*/
            }
        }

        if (rc == CL_SUCCESS) {
            xar_hash_final(a_hash_ctx, result, a_hash);
            if (a_cksum != NULL) {
                expected = cli_hex2str((char *)a_cksum);
                if (xar_hash_check(a_hash, result, expected) != 0) {
                    cli_dbgmsg("cli_scanxar: archived-checksum missing or mismatch.\n");
                    cksum_fails++;
                } else {
                    cli_dbgmsg("cli_scanxar: archived-checksum matched.\n");
                }
                free(expected);
            }
            if (e_cksum != NULL) {
                if (do_extract_cksum) {
                    xar_hash_final(e_hash_ctx, result, e_hash);
                    expected = cli_hex2str((char *)e_cksum);
                    if (xar_hash_check(e_hash, result, expected) != 0) {
                        cli_dbgmsg("cli_scanxar: extracted-checksum missing or mismatch.\n");
                        cksum_fails++;
                    } else {
                        cli_dbgmsg("cli_scanxar: extracted-checksum matched.\n");
                    }
                    free(expected);
                }
            }

            rc = cli_magic_scandesc(fd, ctx);
            if (rc != CL_SUCCESS) {
                if (rc == CL_VIRUS) {
                    cli_dbgmsg("cli_scanxar: Infected with %s\n", cli_get_last_virus(ctx));
                    if (!SCAN_ALL)
                        goto exit_tmpfile;
                } else if (rc != CL_BREAK) {
                    cli_dbgmsg("cli_scanxar: cli_magic_scandesc error %i\n", rc);
                    goto exit_tmpfile;
                }
            }
        }

        if (a_cksum != NULL) {
            xmlFree(a_cksum);
            a_cksum = NULL;
        }
        if (e_cksum != NULL) {
            xmlFree(e_cksum);
            e_cksum = NULL;
        }
    }

exit_tmpfile:
    xar_cleanup_temp_file(ctx, fd, tmpname);

exit_reader:
    if (a_cksum != NULL)
        xmlFree(a_cksum);
    if (e_cksum != NULL)
        xmlFree(e_cksum);
    xmlTextReaderClose(reader);
    xmlFreeTextReader(reader);

exit_toc:
    free(toc);
    if (rc == CL_BREAK)
        rc = CL_SUCCESS;
#else
    cli_dbgmsg("cli_scanxar: can't scan xar files, need libxml2.\n");
#endif
    if (cksum_fails + extract_errors != 0) {
        cli_warnmsg("cli_scanxar: %u checksum errors and %u extraction errors, use --debug for more info.\n",
                    cksum_fails, extract_errors);
    }

    return rc;
}
Пример #22
0
/* Read callback for lzx compressed data */
static int chm_readn(struct cab_file *file, unsigned char *buffer, int bytes) {
    int ret = fmap_readn(file->cab->map, buffer, file->cab->cur_offset, bytes);
    if(ret > 0)
	file->cab->cur_offset += ret;
    return ret;
}
Пример #23
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;
}
Пример #24
0
int cli_scancpio_odc(cli_ctx *ctx)
{
	struct cpio_hdr_odc hdr_odc;
	char name[513], buff[12];
	unsigned int file = 0, trailer = 0;
	uint32_t filesize, namesize, hdr_namesize;
	int ret = CL_CLEAN;
	off_t pos = 0;
        int virus_found = 0;


    while(fmap_readn(*ctx->fmap, &hdr_odc, pos, sizeof(hdr_odc)) == sizeof(hdr_odc)) {
	pos += sizeof(hdr_odc);
	if(!hdr_odc.magic[0] && trailer)
	    goto leave;

	if(strncmp(hdr_odc.magic, "070707", 6)) {
	    cli_dbgmsg("cli_scancpio_odc: Invalid magic string\n");
	    ret = CL_EFORMAT;
            goto leave;
	}

	cli_dbgmsg("CPIO: -- File %u --\n", ++file);

	strncpy(buff, hdr_odc.namesize, 6);
	buff[6] = 0;
	if(sscanf(buff, "%o", &hdr_namesize) != 1) {
	    cli_dbgmsg("cli_scancpio_odc: Can't convert name size\n");
	    ret = CL_EFORMAT;
            goto leave;
	}
	if(hdr_namesize) {
	    namesize = MIN(sizeof(name), hdr_namesize);
	    if ((uint32_t)fmap_readn(*ctx->fmap, &name, pos, namesize) != namesize) {
		cli_dbgmsg("cli_scancpio_odc: Can't read file name\n");
		ret = CL_EFORMAT;
                goto leave;
	    }
	    pos += namesize;
	    name[namesize - 1] = 0;
	    sanitname(name);
	    cli_dbgmsg("CPIO: Name: %s\n", name);
	    if(!strcmp(name, "TRAILER!!!"))
		trailer = 1;

	    if(namesize < hdr_namesize)
		pos += hdr_namesize - namesize;
	}

	strncpy(buff, hdr_odc.filesize, 11);
	buff[11] = 0;
	if(sscanf(buff, "%o", &filesize) != 1) {
	    cli_dbgmsg("cli_scancpio_odc: Can't convert file size\n");
	    ret = CL_EFORMAT;
            goto leave;
	}
	cli_dbgmsg("CPIO: Filesize: %u\n", filesize);
	if(!filesize)
	    continue;

	if(cli_matchmeta(ctx, name, filesize, filesize, 0, file, 0, NULL) == CL_VIRUS) {
            if (!SCAN_ALL)
                return CL_VIRUS;
            virus_found = 1;
        }


	ret = cli_checklimits("cli_scancpio_odc", ctx, filesize, 0, 0);
	if(ret == CL_EMAXFILES) {
	    goto leave;
	} else if(ret == CL_SUCCESS) {
	    ret = cli_map_scan(*ctx->fmap, pos, filesize, ctx, CL_TYPE_ANY);
	    if(ret == CL_VIRUS) {
                if (!SCAN_ALL)
                    return ret;
                virus_found = 1;
            }
	}

	pos += filesize;
    }

 leave:
    if (virus_found != 0)
        return CL_VIRUS;
    return ret;
}
Пример #25
0
int cli_scanswf(cli_ctx *ctx)
{
    struct swf_file_hdr file_hdr;
    fmap_t *map = *ctx->fmap;
    unsigned int bitpos, bitbuf, getbits_n, nbits, getword_1, getword_2, getdword_1, getdword_2;
    const char *pt;
    unsigned char get_c;
    size_t offset = 0;
    unsigned int val, foo, tag_hdr, tag_type, tag_len;
    unsigned long int bits;

    cli_dbgmsg("in cli_scanswf()\n");

    if(fmap_readn(map, &file_hdr, offset, sizeof(file_hdr)) != sizeof(file_hdr)) {
        cli_dbgmsg("SWF: Can't read file header\n");
        return CL_CLEAN;
    }
    offset += sizeof(file_hdr);

    if(!strncmp(file_hdr.signature, "CWS", 3)) {
        cli_dbgmsg("SWF: zlib compressed file\n");
        return scancws(ctx, &file_hdr);
    } else if(!strncmp(file_hdr.signature, "ZWS", 3)) {
        cli_dbgmsg("SWF: LZMA compressed file\n");
        return scanzws(ctx, &file_hdr);
    } else if(!strncmp(file_hdr.signature, "FWS", 3)) {
        cli_dbgmsg("SWF: Uncompressed file\n");
    } else {
        cli_dbgmsg("SWF: Not a SWF file\n");
        return CL_CLEAN;
    }

    cli_dbgmsg("SWF: Version: %u\n", file_hdr.version);
    cli_dbgmsg("SWF: File size: %u\n", EC32(file_hdr.filesize));

    INITBITS;

    GETBITS(nbits, 5);
    cli_dbgmsg("SWF: FrameSize RECT size bits: %u\n", nbits);
    {
        uint32_t xMin = 0, xMax = 0, yMin = 0, yMax = 0;
        GETBITS(xMin, nbits); /* Should be zero */
        GETBITS(xMax, nbits);
        GETBITS(yMin, nbits); /* Should be zero */
        GETBITS(yMax, nbits);
        cli_dbgmsg("SWF: FrameSize xMin %u xMax %u yMin %u yMax %u\n", xMin, xMax, yMin, yMax);
    }

    GETWORD(foo);
    GETWORD(val);
    cli_dbgmsg("SWF: Frames total: %d\n", val);

    /* Skip Flash tag walk unless debug mode */
    if(!cli_debug_flag) {
        return CL_CLEAN;
    }

    while(offset < map->len) {
        GETWORD(tag_hdr);
        tag_type = tag_hdr >> 6;
        if(tag_type == 0)
            break;
        tag_len = tag_hdr & 0x3f;
        if(tag_len == 0x3f)
            GETDWORD(tag_len);

        pt = tagname(tag_type);
        cli_dbgmsg("SWF: %s\n", pt ? pt : "UNKNOWN TAG");
        cli_dbgmsg("SWF: Tag length: %u\n", tag_len);
        if (tag_len > map->len) {
            cli_dbgmsg("SWF: Invalid tag length.\n");
            return CL_EFORMAT;
        }
        if ((offset + tag_len) < offset) {
            cli_warnmsg("SWF: Tag length too large.\n");
            break;
        }
        if(!pt) {
            offset += tag_len;
            continue;
        }

        switch(tag_type) {
            case TAG_SCRIPTLIMITS: {
                unsigned int recursion, timeout;
                GETWORD(recursion);
                GETWORD(timeout);
                cli_dbgmsg("SWF: scriptLimits recursion %u timeout %u\n", recursion, timeout);
                break;
            }

            case TAG_FILEATTRIBUTES:
                GETDWORD(val);
                cli_dbgmsg("SWF: File attributes:\n");
                if(val & SWF_ATTR_USENETWORK)
                    cli_dbgmsg("    * Use network\n");
                if(val & SWF_ATTR_RELATIVEURLS)
                    cli_dbgmsg("    * Relative URLs\n");
                if(val & SWF_ATTR_SUPPRESSCROSSDOMAINCACHE)
                    cli_dbgmsg("    * Suppress cross domain cache\n");
                if(val & SWF_ATTR_ACTIONSCRIPT3)
                    cli_dbgmsg("    * ActionScript 3.0\n");
                if(val & SWF_ATTR_HASMETADATA)
                    cli_dbgmsg("    * Has metadata\n");
                if(val & SWF_ATTR_USEDIRECTBLIT)
                    cli_dbgmsg("    * Use hardware acceleration\n");
                if(val & SWF_ATTR_USEGPU)
                    cli_dbgmsg("    * Use GPU\n");
                break;

            default:
                offset += tag_len;
                continue;
        }
    }

    return CL_CLEAN;
}
Пример #26
0
int cli_scancpio_newc(cli_ctx *ctx, int crc)
{
	struct cpio_hdr_newc hdr_newc;
	char name[513], buff[9];
	unsigned int file = 0, trailer = 0;
	uint32_t filesize, namesize, hdr_namesize, pad;
	int ret;
	off_t pos = 0;


    while(fmap_readn(*ctx->fmap, &hdr_newc, pos, sizeof(hdr_newc)) == sizeof(hdr_newc)) {
	pos += sizeof(hdr_newc);
	if(!hdr_newc.magic[0] && trailer)
	    return CL_SUCCESS;

	if((!crc && strncmp(hdr_newc.magic, "070701", 6)) || (crc && strncmp(hdr_newc.magic, "070702", 6))) {
	    cli_dbgmsg("cli_scancpio_newc: Invalid magic string\n");
	    return CL_EFORMAT;
	}

	cli_dbgmsg("CPIO: -- File %u --\n", ++file);

	strncpy(buff, hdr_newc.namesize, 8);
	buff[8] = 0;
	if(sscanf(buff, "%x", &hdr_namesize) != 1) {
	    cli_dbgmsg("cli_scancpio_newc: Can't convert name size\n");
	    return CL_EFORMAT;
	}
	if(hdr_namesize) {
	    namesize = MIN(sizeof(name), hdr_namesize);
	    if ((uint32_t)fmap_readn(*ctx->fmap, &name, pos, namesize) != namesize) {
		cli_dbgmsg("cli_scancpio_newc: Can't read file name\n");
		return CL_EFORMAT;
	    }
	    pos += namesize;
	    name[namesize - 1] = 0;
	    sanitname(name);
	    cli_dbgmsg("CPIO: Name: %s\n", name);
	    if(!strcmp(name, "TRAILER!!!"))
		trailer = 1;

	    pad = (4 - (sizeof(hdr_newc) + hdr_namesize) % 4) % 4;
	    if(namesize < hdr_namesize) {
		if(pad)
		    hdr_namesize += pad;
		pos += hdr_namesize - namesize;
	    } else if(pad)
		pos += pad;
	}

	strncpy(buff, hdr_newc.filesize, 8);
	buff[8] = 0;
	if(sscanf(buff, "%x", &filesize) != 1) {
	    cli_dbgmsg("cli_scancpio_newc: Can't convert file size\n");
	    return CL_EFORMAT;
	}
	cli_dbgmsg("CPIO: Filesize: %u\n", filesize);
	if(!filesize)
	    continue;

	if(cli_matchmeta(ctx, name, filesize, filesize, 0, file, 0, NULL) == CL_VIRUS)
	    return CL_VIRUS;


	ret = cli_checklimits("cli_scancpio_newc", ctx, filesize, 0, 0);
	if(ret == CL_EMAXFILES) {
	    return ret;
	} else if(ret == CL_SUCCESS) {
	    ret = cli_map_scan(*ctx->fmap, pos, filesize, ctx, CL_TYPE_ANY);
	    if(ret == CL_VIRUS)
		return ret;
	}

	if((pad = filesize % 4))
	    filesize += (4 - pad);

	pos += filesize;
    }

    return CL_CLEAN;
}
Пример #27
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 && DETECT_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 && DETECT_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 && DETECT_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%x\n", EC32(program_hdr[i].p_type, conv));
                cli_dbgmsg("ELF: Segment offset: 0x" STDx64 "\n", EC64(program_hdr[i].p_offset, conv));
                cli_dbgmsg("ELF: Segment virtual address: 0x" STDx64 "\n", EC64(program_hdr[i].p_vaddr, conv));
                cli_dbgmsg("ELF: Segment real size: 0x" STDx64 "\n", EC64(program_hdr[i].p_filesz, conv));
                cli_dbgmsg("ELF: Segment virtual size: 0x" STDx64 "\n", 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 && DETECT_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;
}
Пример #28
0
static int
tnef_message(fmap_t *map, off_t *pos, uint16_t type, uint16_t tag, int32_t length, off_t fsize)
{
	uint16_t i16;
	off_t offset;
#ifdef	CL_DEBUG
	uint32_t i32;
	char *string;
#endif

	cli_dbgmsg("message tag 0x%x, type 0x%x, length %d\n", tag, type,
		(int)length);

	offset = *pos;

	/*
	 * a lot of this stuff should be only discovered in debug mode...
	 */
	switch(tag) {
		case attBODY:
			cli_warnmsg("TNEF body not being scanned - if you believe this file contains a virus, submit it to www.clamav.net\n");
			break;
#ifdef	CL_DEBUG
		case attTNEFVERSION:
			/*assert(length == sizeof(uint32_t))*/
			if(fmap_readn(map, &i32, *pos, sizeof(uint32_t)) != sizeof(uint32_t))
				return -1;
			(*pos) += sizeof(uint32_t);
			i32 = host32(i32);
			cli_dbgmsg("TNEF version %d\n", i32);
			break;
		case attOEMCODEPAGE:
			/* 8 bytes, but just print the first 4 */
			/*assert(length == sizeof(uint32_t))*/
			if(fmap_readn(map, &i32, *pos, sizeof(uint32_t)) != sizeof(uint32_t))
				return -1;
			(*pos) += sizeof(uint32_t);
			i32 = host32(i32);
			cli_dbgmsg("TNEF codepage %d\n", i32);
			break;
		case attDATEMODIFIED:
			/* 14 bytes, long */
			break;
		case attMSGCLASS:
			if(length <= 0)
				return -1;
			string = cli_malloc(length + 1);
			if(string == NULL) {
                cli_errmsg("tnef_message: Unable to allocate memory for string\n");
				return -1;
            }
			if(fmap_readn(map, string, *pos, (uint32_t)length) != (uint32_t)length) {
				free(string);
				return -1;
			}
			(*pos) += (uint32_t)length;
			string[length] = '\0';
			cli_dbgmsg("TNEF class %s\n", string);
			free(string);
			break;
		default:
			cli_dbgmsg("TNEF - unsupported message tag 0x%x type 0x%d length %d\n", tag, type, length);
			break;
#endif
	}

	/*cli_dbgmsg("%lu %lu\n", (long)(offset + length), ftell(fp));*/

	if(!CLI_ISCONTAINED2(0, fsize, (off_t)offset, (off_t)length)) {
		cli_dbgmsg("TNEF: Incorrect length field in tnef_message\n");
		return -1;
	}
	(*pos) = offset + length;

	/* Checksum - TODO, verify */
	(*pos) += 2;

	return 0;
}
Пример #29
0
/* Return converted endian-fixed header, or error code */
static int cli_elf_fileheader(cli_ctx *ctx, fmap_t *map, union elf_file_hdr *file_hdr,
    uint8_t *do_convert, uint8_t *is64)
{
	uint8_t format64, conv;

    /* Load enough for smaller header first */
    if(fmap_readn(map, file_hdr, 0, sizeof(struct elf_file_hdr32)) != sizeof(struct elf_file_hdr32)) {
	/* Not an ELF file? */
	cli_dbgmsg("ELF: Can't read file header\n");
	return CL_BREAK;
    }

    if(memcmp(file_hdr->hdr64.e_ident, "\x7f\x45\x4c\x46", 4)) {
	cli_dbgmsg("ELF: Not an ELF file\n");
	return CL_BREAK;
    }

    switch(file_hdr->hdr64.e_ident[4]) {
	case 1:
	    cli_dbgmsg("ELF: ELF class 1 (32-bit)\n");
	    format64 = 0;
	    break;
        case 2:
	    cli_dbgmsg("ELF: ELF class 2 (64-bit)\n");
	    format64 = 1;
	    break;
        default:
	    cli_dbgmsg("ELF: Unknown ELF class (%u)\n", file_hdr->hdr64.e_ident[4]);
	    return CL_EFORMAT;
    }

    /* Need to know to endian convert */
    if(file_hdr->hdr64.e_ident[5] == 1) {
#if WORDS_BIGENDIAN == 0
	if(ctx)
            cli_dbgmsg("ELF: File is little-endian - conversion not required\n");
	conv = 0;
#else
	if(ctx)
            cli_dbgmsg("ELF: File is little-endian - data conversion enabled\n");
	conv = 1;
#endif
    } else {
#if WORDS_BIGENDIAN == 0
	if(ctx)
            cli_dbgmsg("ELF: File is big-endian - data conversion enabled\n");
	conv = 1;
#else
	if(ctx)
            cli_dbgmsg("ELF: File is big-endian - conversion not required\n");
	conv = 0;
#endif
    }

    *do_convert = conv;
    *is64 = format64;

    /* Solve bit-size and conversion pronto */
    file_hdr->hdr64.e_type = EC16(file_hdr->hdr64.e_type, conv);
    file_hdr->hdr64.e_machine = EC16(file_hdr->hdr64.e_machine, conv);
    file_hdr->hdr64.e_version = EC32(file_hdr->hdr64.e_version, conv);

    if(format64) {
	/* Read rest of 64-bit header */
	if(fmap_readn(map, file_hdr->hdr32.pad, sizeof(struct elf_file_hdr32), ELF_HDR_SIZEDIFF)
                != ELF_HDR_SIZEDIFF) {
	    /* Not an ELF file? */
	    cli_dbgmsg("ELF: Can't read file header\n");
	    return CL_BREAK;
	}
	/* Now endian convert, if needed */
	if(conv) {
	    file_hdr->hdr64.e_entry = EC64(file_hdr->hdr64.e_entry, conv);
            file_hdr->hdr64.e_phoff = EC64(file_hdr->hdr64.e_phoff, conv);
            file_hdr->hdr64.e_shoff = EC64(file_hdr->hdr64.e_shoff, conv);
	    file_hdr->hdr64.e_flags = EC32(file_hdr->hdr64.e_flags, conv);
	    file_hdr->hdr64.e_ehsize = EC16(file_hdr->hdr64.e_ehsize, conv);
	    file_hdr->hdr64.e_phentsize = EC16(file_hdr->hdr64.e_phentsize, conv);
	    file_hdr->hdr64.e_phnum = EC16(file_hdr->hdr64.e_phnum, conv);
	    file_hdr->hdr64.e_shentsize = EC16(file_hdr->hdr64.e_shentsize, conv);
	    file_hdr->hdr64.e_shnum = EC16(file_hdr->hdr64.e_shnum, conv);
	    file_hdr->hdr64.e_shstrndx = EC16(file_hdr->hdr64.e_shstrndx, conv);
	}
    }
    else {
	/* Convert 32-bit structure, if needed */
	if(conv) {
	    file_hdr->hdr32.hdr.e_entry = EC32(file_hdr->hdr32.hdr.e_entry, conv);
            file_hdr->hdr32.hdr.e_phoff = EC32(file_hdr->hdr32.hdr.e_phoff, conv);
            file_hdr->hdr32.hdr.e_shoff = EC32(file_hdr->hdr32.hdr.e_shoff, conv);
	    file_hdr->hdr32.hdr.e_flags = EC32(file_hdr->hdr32.hdr.e_flags, conv);
	    file_hdr->hdr32.hdr.e_ehsize = EC16(file_hdr->hdr32.hdr.e_ehsize, conv);
	    file_hdr->hdr32.hdr.e_phentsize = EC16(file_hdr->hdr32.hdr.e_phentsize, conv);
	    file_hdr->hdr32.hdr.e_phnum = EC16(file_hdr->hdr32.hdr.e_phnum, conv);
	    file_hdr->hdr32.hdr.e_shentsize = EC16(file_hdr->hdr32.hdr.e_shentsize, conv);
	    file_hdr->hdr32.hdr.e_shnum = EC16(file_hdr->hdr32.hdr.e_shnum, conv);
	    file_hdr->hdr32.hdr.e_shstrndx = EC16(file_hdr->hdr32.hdr.e_shstrndx, conv);
        }
        /* Wipe pad for safety */
        memset(file_hdr->hdr32.pad, 0, ELF_HDR_SIZEDIFF);
    }

    return CL_CLEAN;
}
Пример #30
0
static int
tnef_attachment(fmap_t *map, off_t *pos, uint16_t type, uint16_t tag, int32_t length, const char *dir, fileblob **fbref, off_t fsize)
{
	uint32_t todo;
	uint16_t i16;
	off_t offset;
	char *string;

	cli_dbgmsg("attachment tag 0x%x, type 0x%x, length %d\n", tag, type,
		(int)length);

	offset = *pos;

	switch(tag) {
		case attATTACHTITLE:
			if(length <= 0)
				return -1;
			string = cli_malloc(length + 1);
			if(string == NULL) {
                cli_errmsg("tnef_attachment: Unable to allocate memory for string\n");
				return -1;
            }
			if(fmap_readn(map, string, *pos, (uint32_t)length) != (uint32_t)length) {
				free(string);
				return -1;
			}
			(*pos) += (uint32_t)length;
			string[length] = '\0';
			cli_dbgmsg("TNEF filename %s\n", string);
			if(*fbref == NULL) {
				*fbref = fileblobCreate();
				if(*fbref == NULL) {
					free(string);
					return -1;
				}
			}
			fileblobSetFilename(*fbref, dir, string);
			free(string);
			break;
		case attATTACHDATA:
			if(*fbref == NULL) {
				*fbref = fileblobCreate();
				if(*fbref == NULL)
					return -1;
			}
			todo = length;
			while(todo) {
			    unsigned char buf[BUFSIZ];
			    int32_t got = fmap_readn(map, buf, *pos, MIN(sizeof(buf), todo));
			    if (got <= 0)
				break;
			    (*pos) += got;

			    fileblobAddData(*fbref, buf, got);
			    todo -= got;
			}
			break;
		default:
			cli_dbgmsg("TNEF - unsupported attachment tag 0x%x type 0x%d length %d\n",
				tag, type, (int)length);
			break;
	}

	/*cli_dbgmsg("%lu %lu\n", (long)(offset + length), ftell(fp));*/

	if(!CLI_ISCONTAINED2(0, fsize, (off_t)offset, (off_t)length)) {
		cli_dbgmsg("TNEF: Incorrect length field in tnef_attachment\n");
		return -1;
	}
	(*pos) = (long)(offset + length);	/* shouldn't be needed */

	(*pos) += 2;

	return 0;
}