Пример #1
0
/* Stripe handling: zero block (type 0x0 or 0x2) */
static int dmg_stripe_zeroes(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mish_with_stripes *mish_set)
{
    int ret = CL_CLEAN;
    size_t len = mish_set->stripes[index].sectorCount * DMG_SECTOR_SIZE;
    ssize_t written;
    uint8_t obuf[BUFSIZ];

    cli_dbgmsg("dmg_stripe_zeroes: stripe " STDu32 "\n", index);
    if (len == 0)
        return CL_CLEAN;

    memset(obuf, 0, sizeof(obuf));
    while (len > sizeof(obuf)) {
        written = cli_writen(fd, obuf, sizeof(obuf));
        if (written != sizeof(obuf)) {
            ret = CL_EWRITE;
            break;
        }
        len -= sizeof(obuf);
    }

    if ((ret == CL_CLEAN) && (len > 0)) {
        written = cli_writen(fd, obuf, len);
        if (written != len) {
            ret = CL_EWRITE;
        }
    }

    if (ret != CL_CLEAN) {
        cli_errmsg("dmg_stripe_zeroes: error writing bytes to file (out of disk space?)\n");
        return CL_EWRITE;
    }
    return CL_CLEAN;
}
Пример #2
0
/* Stripe handling: stored block (type 0x1) */
static int dmg_stripe_store(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mish_with_stripes *mish_set)
{
    const void *obuf;
    int ret;
    size_t off = mish_set->stripes[index].dataOffset;
    size_t len = mish_set->stripes[index].dataLength;
    ssize_t written;

    cli_dbgmsg("dmg_stripe_store: stripe " STDu32 "\n", index);
    if (len == 0)
        return CL_CLEAN;

    obuf = (void *)fmap_need_off_once(*ctx->fmap, off, len);
    if (!obuf) {
        cli_warnmsg("dmg_stripe_store: fmap need failed on stripe " STDu32 "\n", index);
        return CL_EMAP;
    }
    written = cli_writen(fd, obuf, len);
    if (written < 0) {
        cli_errmsg("dmg_stripe_store: error writing bytes to file (out of disk space?)\n");
        return CL_EWRITE;
    }
    else if (written != len) {
        cli_errmsg("dmg_stripe_store: error writing bytes to file (out of disk space?)\n");
        return CL_EWRITE;
    }
    return CL_CLEAN;
}
Пример #3
0
/*
  xar_process_subdocument - check TOC for xml subdocument. If found, extract and
                            scan in memory.
  Parameters:
     reader - xmlTextReaderPtr
     ctx - pointer to cli_ctx
  Returns:
     CL_SUCCESS - subdoc found and clean scan (or virus found and SCAN_ALL), or no subdocument
     other - error return code from cli_mem_scandesc()
*/
static int xar_scan_subdocuments(xmlTextReaderPtr reader, cli_ctx *ctx)
{
    int rc = CL_SUCCESS, subdoc_len, fd;
    xmlChar * subdoc;
    const xmlChar *name;
    char * tmpname;

    while (xmlTextReaderRead(reader) == 1) {
        name = xmlTextReaderConstLocalName(reader);
        if (name == NULL) {
            cli_dbgmsg("cli_scanxar: xmlTextReaderConstLocalName() no name.\n");
            rc = CL_EFORMAT;
            break;
        }
        if (xmlStrEqual(name, (const xmlChar *)"toc") &&
                xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
            return CL_SUCCESS;
        if (xmlStrEqual(name, (const xmlChar *)"subdoc") &&
                xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) {
            subdoc = xmlTextReaderReadInnerXml(reader);
            if (subdoc == NULL) {
                cli_dbgmsg("cli_scanxar: no content in subdoc element.\n");
                xmlTextReaderNext(reader);
                continue;
            }
            subdoc_len = xmlStrlen(subdoc);
            cli_dbgmsg("cli_scanxar: in-memory scan of xml subdocument, len %i.\n", subdoc_len);
            rc = cli_mem_scandesc(subdoc, subdoc_len, ctx);
            if (rc == CL_VIRUS && SCAN_ALL)
                rc = CL_SUCCESS;

            /* 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 subdocument.\n");
                } else {
                    cli_dbgmsg("cli_scanxar: Writing subdoc to temp file %s.\n", tmpname);
                    if (cli_writen(fd, subdoc, subdoc_len) < 0) {
                        cli_dbgmsg("cli_scanxar: cli_writen error writing subdoc temporary file.\n");
                        rc = CL_EWRITE;
                    }
                    rc = xar_cleanup_temp_file(ctx, fd, tmpname);
                }
            }

            xmlFree(subdoc);
            if (rc != CL_SUCCESS)
                return rc;
            xmlTextReaderNext(reader);
        }
    }
    return rc;
}
Пример #4
0
static int dmg_extract_xml(cli_ctx *ctx, char *dir, struct dmg_koly_block *hdr)
{
    char * xmlfile;
    const char *outdata;
    size_t namelen, nread;
    int ofd;

    /* Prep TOC XML for output */
    outdata = fmap_need_off_once_len(*ctx->fmap, hdr->xmlOffset, hdr->xmlLength, &nread);
    if (!outdata || (nread != hdr->xmlLength)) {
        cli_errmsg("cli_scandmg: Failed getting XML from map, len " STDu64 "\n", hdr->xmlLength);
        return CL_EMAP;
    }

    namelen = strlen(dir) + 1 + 7 + 1;
    if (!(xmlfile = cli_malloc(namelen))) {
        return CL_EMEM;
    }
    snprintf(xmlfile, namelen, "%s"PATHSEP"toc.xml", dir);
    cli_dbgmsg("cli_scandmg: Extracting XML as %s\n", xmlfile);

    /* Write out TOC XML */
    if ((ofd = open(xmlfile, O_CREAT|O_RDWR|O_EXCL|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
        char err[128];
        cli_errmsg("cli_scandmg: Can't create temporary file %s: %s\n",
                   xmlfile, cli_strerror(errno, err, sizeof(err)));
        free(xmlfile);
        return CL_ETMPFILE;
    }

    if (cli_writen(ofd, outdata, hdr->xmlLength) != hdr->xmlLength) {
        cli_errmsg("cli_scandmg: Not all bytes written!\n");
        close(ofd);
        free(xmlfile);
        return CL_EWRITE;
    }

    close(ofd);
    free(xmlfile);
    return CL_SUCCESS;
}
Пример #5
0
static uint64_t chm_copy_file_data(int ifd, int ofd, uint64_t len)
{
	unsigned char data[8192];
	uint64_t count, rem;
	unsigned int todo;
	
	rem = len;

	while (rem > 0) {
		todo = MIN(8192, rem);
		count = cli_readn(ifd, data, todo);
		if (count != todo) {
			return len-rem;
		}
		if (cli_writen(ofd, data, count) != (int64_t)count) {
			return len-rem-count;
		}
		rem -= count;
	}
	return len;
}
Пример #6
0
/* TODO: field in ctx, id of last bytecode that called magicscandesc, reset
 * after hooks/other bytecodes are run. TODO: need a more generic solution
 * to avoid uselessly recursing on bytecode-unpacked files, but also a way to
 * override the limit if we need it in a special situation */
int32_t cli_bcapi_write(struct cli_bc_ctx *ctx, uint8_t*data, int32_t len)
{
    char err[128];
    int32_t res;

    cli_ctx *cctx = (cli_ctx*)ctx->ctx;
    if (len < 0) {
	cli_warnmsg("Bytecode API: called with negative length!\n");
	API_MISUSE();
	return -1;
    }
    if (!ctx->outfd) {
	ctx->tempfile = cli_gentemp(cctx ? cctx->engine->tmpdir : NULL);
	if (!ctx->tempfile) {
	    cli_dbgmsg("Bytecode API: Unable to allocate memory for tempfile\n");
	    cli_event_error_oom(EV, 0);
	    return -1;
	}
	ctx->outfd = open(ctx->tempfile, O_RDWR|O_CREAT|O_EXCL|O_TRUNC|O_BINARY, 0600);
	if (ctx->outfd == -1) {
	    ctx->outfd = 0;
	    cli_warnmsg("Bytecode API: Can't create file %s: %s\n", ctx->tempfile, cli_strerror(errno, err, sizeof(err)));
	    cli_event_error_str(EV, "cli_bcapi_write: Can't create temporary file");
	    free(ctx->tempfile);
	    return -1;
	}
	cli_dbgmsg("bytecode opened new tempfile: %s\n", ctx->tempfile);
    }

    cli_event_fastdata(ctx->bc_events, BCEV_WRITE, data, len);
    if (cli_checklimits("bytecode api", cctx, ctx->written + len, 0, 0))
	return -1;
    res = cli_writen(ctx->outfd, data, len);
    if (res > 0) ctx->written += res;
    if (res == -1) {
	cli_warnmsg("Bytecode API: write failed: %s\n", cli_strerror(errno, err, sizeof(err)));
	cli_event_error_str(EV, "cli_bcapi_write: write failed");
    }
    return res;
}
Пример #7
0
int fmap_dump_to_file(fmap_t *map, const char *tmpdir, char **outname, int *outfd)
{
    char *tmpname;
    int tmpfd, ret;
    size_t pos = 0, len;

    cli_dbgmsg("fmap_dump_to_file: dumping fmap not backed by file...\n");
    ret = cli_gentempfd(tmpdir, &tmpname, &tmpfd);
    if(ret != CL_SUCCESS) {
        cli_dbgmsg("fmap_dump_to_file: failed to generate temporary file.\n");
        return ret;
    }

    do {
        const char *b;
        len = 0;
        b = fmap_need_off_once_len(map, pos, BUFSIZ, &len);
        pos += len;
        if(b && (len > 0)) {
            if ((size_t)cli_writen(tmpfd, b, len) != len) {
                cli_warnmsg("fmap_dump_to_file: write failed to %s!\n", tmpname);
                close(tmpfd);
                unlink(tmpname);
                free(tmpname);
                return CL_EWRITE;
            }
        }
    } while (len > 0);

    if(lseek(tmpfd, 0, SEEK_SET) == -1) {
        cli_dbgmsg("fmap_dump_to_file: lseek failed\n");
    }

    *outname = tmpname;
    *outfd = tmpfd;
    return CL_SUCCESS;
}
Пример #8
0
Файл: cab.c Проект: OPSF/uClinux
static int cab_unstore(struct cab_file *file, int bytes)
{
	int todo, bread;
	unsigned char buff[4096];


    if(bytes < 0) {
	cli_warnmsg("cab_unstore: bytes < 0\n");
	return CL_EFORMAT;
    }

    todo = MIN((unsigned int) bytes, file->max_size);

    while(1) {

	if((unsigned int) todo <= sizeof(buff))
	    bread = todo;
	else
	    bread = sizeof(buff);

	if((bread = cab_read(file, buff, bread)) == -1) {
	    cli_dbgmsg("cab_unstore: cab_read failed for descriptor %d\n", file->fd);
	    return file->error;
	} else if(cli_writen(file->ofd, buff, bread) != bread) {
	    cli_warnmsg("cab_unstore: Can't write %d bytes to descriptor %d\n", bread, file->ofd);
	    return CL_EWRITE;
	}

	todo -= bread;

	if(!bread || todo <= 0)
	    break;
    }

    return CL_SUCCESS;
}
Пример #9
0
/* Read and dump a file for scanning */
static int hfsplus_scanfile(cli_ctx *ctx, hfsPlusVolumeHeader *volHeader, hfsHeaderRecord *extHeader,
    hfsPlusForkData *fork, const char *dirname)
{
    hfsPlusExtentDescriptor *currExt;
    const uint8_t *mPtr = NULL;
    char *tmpname = NULL;
    int ofd, ret = CL_CLEAN;
    uint64_t targetSize;
    uint32_t outputBlocks = 0;
    uint8_t ext;

    UNUSEDPARAM(extHeader);

    /* bad record checks */
    if (!fork || (fork->logicalSize == 0) || (fork->totalBlocks == 0)) {
        cli_dbgmsg("hfsplus_dumpfile: Empty file.\n");
        return CL_CLEAN;
    }

    /* check limits */
    targetSize = fork->logicalSize;
#if SIZEOF_LONG < 8
    if (targetSize > ULONG_MAX) {
        cli_dbgmsg("hfsplus_dumpfile: File too large for limit check.\n");
        return CL_EFORMAT;
    }
#endif
    ret = cli_checklimits("hfsplus_scanfile", ctx, (unsigned long)targetSize, 0, 0);
    if (ret != CL_CLEAN) {
        return ret;
    }

    /* open file */
    ret = cli_gentempfd(dirname, &tmpname, &ofd);
    if (ret != CL_CLEAN) {
        cli_dbgmsg("hfsplus_dumpfile: Cannot generate temporary file.\n");
        return ret;
    }
    cli_dbgmsg("hfsplus_dumpfile: Extracting to %s\n", tmpname);

    ext = 0;
    /* Dump file, extent by extent */
    do {
        uint32_t currBlock, endBlock, outputSize = 0;
        if (targetSize == 0) {
            cli_dbgmsg("hfsplus_dumpfile: output complete\n");
            break;
        }
        if (outputBlocks >= fork->totalBlocks) {
            cli_dbgmsg("hfsplus_dumpfile: output all blocks, remaining size " STDu64 "\n", targetSize);
            break;
        }
        /* Prepare extent */
        if (ext < 8) {
            currExt = &(fork->extents[ext]);
            cli_dbgmsg("hfsplus_dumpfile: extent %u\n", ext);
        }
        else {
            cli_dbgmsg("hfsplus_dumpfile: need next extent from ExtentOverflow\n");
            /* Not implemented yet */
            ret = CL_EFORMAT;
            break;
        }
        /* have extent, so validate and get block range */
        if ((currExt->startBlock == 0) || (currExt->blockCount == 0)) {
            cli_dbgmsg("hfsplus_dumpfile: next extent empty, done\n");
            break;
        }
        if ((currExt->startBlock & 0x10000000) && (currExt->blockCount & 0x10000000)) {
            cli_dbgmsg("hfsplus_dumpfile: next extent illegal!\n");
            ret = CL_EFORMAT;
            break;
        }
        currBlock = currExt->startBlock;
        endBlock = currExt->startBlock + currExt->blockCount - 1;
        if ((currBlock > volHeader->totalBlocks) || (endBlock > volHeader->totalBlocks)
                || (currExt->blockCount > volHeader->totalBlocks)) {
            cli_dbgmsg("hfsplus_dumpfile: bad extent!\n");
            ret = CL_EFORMAT;
            break;
        }
        /* Write the blocks, walking the map */
        while (currBlock <= endBlock) {
            size_t to_write = MIN(targetSize, volHeader->blockSize);
            ssize_t written;
            off_t offset = currBlock * volHeader->blockSize;
            /* move map to next block */
            mPtr = fmap_need_off_once(*ctx->fmap, offset, volHeader->blockSize);
            if (!mPtr) {
                cli_errmsg("hfsplus_dumpfile: map error\n");
                ret = CL_EMAP;
                break;
            }
            written = cli_writen(ofd, mPtr, to_write);
            if ((size_t)written != to_write) {
                cli_errmsg("hfsplus_dumpfile: write error\n");
                ret = CL_EWRITE;
                break;
            }
            targetSize -= to_write;
            outputSize += to_write;
            currBlock++;
            if (targetSize == 0) {
                cli_dbgmsg("hfsplus_dumpfile: all data written\n");
                break;
            }
            if (outputBlocks >= fork->totalBlocks) {
                cli_dbgmsg("hfsplus_dumpfile: output all blocks, remaining size " STDu64 "\n", targetSize);
                break;
            }
        }
        /* Finished the extent, move to next */
        ext++;
    } while (ret == CL_CLEAN);

    /* if successful so far, scan the output */
    if (ret == CL_CLEAN) {
        ret = cli_magic_scandesc(ofd, tmpname, ctx);
    }

    if (ofd >= 0) {
        close(ofd);
    }
    if (!ctx->engine->keeptmp) {
        if (cli_unlink(tmpname)) {
            ret = CL_EUNLINK;
        }
    }
    free(tmpname);

    return ret;
}
Пример #10
0
/* static const unsigned char* parse_dispatch_cmd(client_conn_t *conn, struct fd_buf *buf, size_t *ppos, int *error, const struct optstruct *opts, int readtimeout) */
static int handle_stream(client_conn_t *conn, struct fd_buf *buf, const struct optstruct *opts, int *error, size_t *ppos, int readtimeout)
{
    int rc;
    size_t pos = *ppos;
    size_t cmdlen;
    
    logg("$mode == MODE_STREAM\n");
    /* we received some data, set readtimeout */
    time(&buf->timeout_at);
    buf->timeout_at += readtimeout;
    while (pos <= buf->off) {
	if (!buf->chunksize) {
	    /* read chunksize */
	    if (buf->off-pos >= 4) {
		uint32_t cs;
		memmove(&cs, buf->buffer + pos, 4);
		pos += 4;
		buf->chunksize = ntohl(cs);
		logg("$Got chunksize: %u\n", buf->chunksize);
		if (!buf->chunksize) {
		    /* chunksize 0 marks end of stream */
		    conn->scanfd = buf->dumpfd;
		    conn->term = buf->term;
		    buf->dumpfd = -1;
		    buf->mode = buf->group ? MODE_COMMAND : MODE_WAITREPLY;
		    if (buf->mode == MODE_WAITREPLY)
			buf->fd = -1;
		    logg("$Chunks complete\n");
		    buf->dumpname = NULL;
		    if ((rc = execute_or_dispatch_command(conn, COMMAND_INSTREAMSCAN, NULL)) < 0) {
			logg("!Command dispatch failed\n");
			if(rc == -1 && optget(opts, "ExitOnOOM")->enabled) {
			    pthread_mutex_lock(&exit_mutex);
			    progexit = 1;
			    pthread_mutex_unlock(&exit_mutex);
			}
			*error = 1;
		    } else {
			memmove (buf->buffer, &buf->buffer[pos], buf->off - pos);
			buf->off -= pos;
			*ppos = 0;
			buf->id++;
			return 0;
                    }
		}
		if (buf->chunksize > buf->quota) {
		    logg("^INSTREAM: Size limit reached, (requested: %lu, max: %lu)\n",
			 (unsigned long)buf->chunksize, (unsigned long)buf->quota);
		    conn_reply_error(conn, "INSTREAM size limit exceeded.");
                    *error = 1;
		    *ppos = pos;
		    return -1;
                } else {
		    buf->quota -= buf->chunksize;
                }
		logg("$Quota Remaining: %lu\n", buf->quota);
	    } else {
		/* need more data, so return and wait for some */
		memmove (buf->buffer, &buf->buffer[pos], buf->off - pos);
		buf->off -= pos;
		*ppos = 0;
                return -1;
            }
	}
	if (pos + buf->chunksize < buf->off)
	    cmdlen = buf->chunksize;
	else
	    cmdlen = buf->off - pos;
	buf->chunksize -= cmdlen;
	if (cli_writen(buf->dumpfd, buf->buffer + pos, cmdlen) < 0) {
	    conn_reply_error(conn, "Error writing to temporary file");
	    logg("!INSTREAM: Can't write to temporary file.\n");
	    *error = 1;
	}
	logg("$Processed %lu bytes of chunkdata, pos %lu\n", cmdlen, pos);
	pos += cmdlen;
	if (pos == buf->off) {
	    buf->off = 0;
	    pos = 0;
	    /* need more data, so return and wait for some */
	    *ppos = pos;
            return -1;
	}
    }
    *ppos = pos;
    return 0;
}
Пример #11
0
cl_error_t fmap_dump_to_file(fmap_t* map, const char* filepath, const char* tmpdir, char** outname, int* outfd, size_t start_offset, size_t end_offset)
{
    cl_error_t ret = CL_EARG;

    char* filebase = NULL;
    char* prefix = NULL;

    char* tmpname = NULL;
    int tmpfd = -1;

    size_t pos = 0, len = 0, bytes_remaining = 0, write_size = 0;

    if ((start_offset > map->real_len) || (end_offset < start_offset)) {
        cli_dbgmsg("fmap_dump_to_file: Invalid offset arguments: start %zu, end %zu\n", start_offset, end_offset);
        return ret;
    }

    pos = start_offset;
    end_offset = MIN(end_offset, map->real_len);
    bytes_remaining = end_offset - start_offset;

    /* Create a filename prefix that includes the original filename, if available */
    if (filepath != NULL) {
        if (CL_SUCCESS != cli_basename(filepath, strlen(filepath), &filebase)) {
            cli_dbgmsg("fmap_dump_to_file: Unable to determine basename from filepath.\n");
        } else if ((start_offset != 0) && (end_offset != map->real_len)) {
            /* If we're only dumping a portion of the file, inlcude the offsets in the prefix,...
			 * e.g. tmp filename will become something like:  filebase.500-1200.<randhex> */
            uint32_t prefix_len = strlen(filebase) + 1 + SIZE_T_CHARLEN + 1 + SIZE_T_CHARLEN + 1;
            prefix = malloc(prefix_len);
            if (NULL == prefix) {
                cli_errmsg("fmap_dump_to_file: Failed to allocate memory for tempfile prefix.\n");
                if (NULL != filebase)
                    free(filebase);
                return CL_EMEM;
            }
            snprintf(prefix, prefix_len, "%s.%zu-%zu", filebase, start_offset, end_offset);

            free(filebase);
            filebase = NULL;
        } else {
            /* Else if we're dumping the whole thing, use the filebase as the prefix */
            prefix = filebase;
            filebase = NULL;
        }
    }

    cli_dbgmsg("fmap_dump_to_file: dumping fmap not backed by file...\n");
    ret = cli_gentempfd_with_prefix(tmpdir, prefix, &tmpname, &tmpfd);
    if (ret != CL_SUCCESS) {
        cli_dbgmsg("fmap_dump_to_file: failed to generate temporary file.\n");
        if (NULL != prefix) {
            free(prefix);
            prefix = NULL;
        }
        return ret;
    }

    if (NULL != prefix) {
        free(prefix);
        prefix = NULL;
    }

    do {
        const char* b;
        len = 0;
        write_size = MIN(BUFSIZ, bytes_remaining);

        b = fmap_need_off_once_len(map, pos, write_size, &len);
        pos += len;
        if (b && (len > 0)) {
            if ((size_t)cli_writen(tmpfd, b, len) != len) {
                cli_warnmsg("fmap_dump_to_file: write failed to %s!\n", tmpname);
                close(tmpfd);
                unlink(tmpname);
                free(tmpname);
                return CL_EWRITE;
            }
        }
        if (len <= bytes_remaining) {
            bytes_remaining -= len;
        } else {
            bytes_remaining = 0;
        }
    } while ((len > 0) && (bytes_remaining > 0));

    if (lseek(tmpfd, 0, SEEK_SET) == -1) {
        cli_dbgmsg("fmap_dump_to_file: lseek failed\n");
    }

    *outname = tmpname;
    *outfd = tmpfd;
    return CL_SUCCESS;
}
Пример #12
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;
}
Пример #13
0
int yc_decrypt(cli_ctx *ctx, char *fbuf, unsigned int filesize, struct cli_exe_section *sections, unsigned int sectcount, uint32_t peoffset, int desc, uint32_t ecx,int16_t offset) {
  uint32_t ycsect = sections[sectcount].raw+offset;
  unsigned int i;
  struct pe_image_file_hdr *pe = (struct pe_image_file_hdr*) (fbuf + peoffset);
  char *sname = (char *)pe + EC16(pe->SizeOfOptionalHeader) + 0x18;
  uint32_t max_emu;
  unsigned int ofilesize = filesize;
  /* 

  First layer (decryptor of the section decryptor) in last section 

  Start offset for analyze: Start of yC Section + 0x93
  End offset for analyze: Start of yC Section + 0xC3
  Length to decrypt - ECX = 0xB97

  */
  cli_dbgmsg("yC: offset: %x, length: %x\n", offset, ecx);
  cli_dbgmsg("yC: decrypting decryptor on sect %d\n", sectcount);
  switch (yc_poly_emulator(ctx, fbuf, filesize, fbuf + ycsect + 0x93, fbuf + ycsect + 0xc6, ecx, ecx)) {
  case 2:
      return CL_VIRUS;
  case 1:
      return CL_EUNPACK;
  }
  filesize-=sections[sectcount].ursz;

  /* 

  Second layer (decryptor of the sections) in last section 

  Start offset for analyze: Start of yC Section + 0x457
  End offset for analyze: Start of yC Section + 0x487
  Length to decrypt - ECX = Raw Size of Section

  */


  /* Loop through all sections and decrypt them... */
  for(i=0;i<sectcount;i++) {
    uint32_t name = (uint32_t) cli_readint32(sname+i*0x28);
    if (!sections[i].raw ||
	!sections[i].rsz ||
	name == 0x63727372 || /* rsrc */
	name == 0x7273722E || /* .rsr */
	name == 0x6F6C6572 || /* relo */
	name == 0x6C65722E || /* .rel */
	name == 0x6164652E || /* .eda */
	name == 0x6164722E || /* .rda */
	name == 0x6164692E || /* .ida */
	name == 0x736C742E || /* .tls */
	(name&0xffff) == 0x4379  /* yC */
	) continue;
    cli_dbgmsg("yC: decrypting sect%d\n",i);
    max_emu = filesize - sections[i].raw;
    if (max_emu > filesize) {
      cli_dbgmsg("yC: bad emulation length limit %u\n", max_emu);
      return 1;
    }
    switch (yc_poly_emulator(ctx, fbuf, ofilesize, fbuf + ycsect + (offset == -0x18 ? 0x3ea : 0x457), 
			 fbuf + sections[i].raw, 
			 sections[i].ursz, 
			 max_emu)) {
    case 2:
        return CL_VIRUS;
    case 1:
        return CL_EUNPACK;
    }
  }

  /* Remove yC section */
  pe->NumberOfSections=EC16(sectcount);

  /* Remove IMPORT_DIRECTORY information */
  memset((char *)pe + sizeof(struct pe_image_file_hdr) + 0x68, 0, 8);

  /* OEP resolving */
  /* OEP = DWORD PTR [ Start of yC section+ A0F] */
  cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 16, cli_readint32(fbuf + ycsect + 0xa0f));

  /* Fix SizeOfImage */
  cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38, cli_readint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38) - sections[sectcount].vsz);

  if (cli_writen(desc, fbuf, filesize)==-1) {
    cli_dbgmsg("yC: Cannot write unpacked file\n");
    return CL_EUNPACK;
  }
  return CL_SUCCESS;
}
Пример #14
0
static int nsis_unpack_next(struct nsis_st *n, cli_ctx *ctx) {
  const unsigned char *ibuf;
  uint32_t size, loops;
  int ret, gotsome=0, opened=0;
  unsigned char obuf[BUFSIZ];

  if (n->eof) {
    cli_dbgmsg("NSIS: extraction complete\n");
    return CL_BREAK;
  }
  
  if ((ret=cli_checklimits("NSIS", ctx, 0, 0, 0))!=CL_CLEAN)
    return ret;

  if (n->fno)
    snprintf(n->ofn, 1023, "%s"PATHSEP"content.%.3u", n->dir, n->fno);
  else
    snprintf(n->ofn, 1023, "%s"PATHSEP"headers", n->dir);

  n->fno++;
  n->opened = 0;

  if (!n->solid) {
    if (fmap_readn(n->map, &size, n->curpos, 4)!=4) {
      cli_dbgmsg("NSIS: reached EOF - extraction complete\n");
      return CL_BREAK;
    }
    n->curpos += 4;
    if (n->asz==4) {
      cli_dbgmsg("NSIS: reached CRC - extraction complete\n");
      return CL_BREAK;
    }
    loops = EC32(size);
    if (!(size = (loops&~0x80000000))) {
      cli_dbgmsg("NSIS: empty file found\n");
      return CL_SUCCESS;
    }
    if (n->asz <4 || size > n->asz-4) {
      cli_dbgmsg("NSIS: next file is outside the archive\n");
      return CL_BREAK;
    }

    n->asz -= size+4;

    if ((ret=cli_checklimits("NSIS", ctx, size, 0, 0))!=CL_CLEAN) {
      n->curpos += size;
      return ret;
    }
    if (!(ibuf = fmap_need_off_once(n->map, n->curpos, size))) {
      cli_dbgmsg("NSIS: cannot read %u bytes"__AT__"\n", size);
      return CL_EREAD;
    }
  if ((n->ofd=open(n->ofn, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600))==-1) {
    cli_errmsg("NSIS: unable to create output file %s - aborting.", n->ofn);
    return CL_ECREAT;
  }
  n->opened = 1;
    n->curpos += size;
    if (loops==size) {

      if (cli_writen(n->ofd, ibuf, size) != (ssize_t) size) {
	cli_dbgmsg("NSIS: cannot write output file"__AT__"\n");
	close(n->ofd);
	return CL_EWRITE;
      }
    } else {
      if ((ret=nsis_init(n))!=CL_SUCCESS) {
	cli_dbgmsg("NSIS: decompressor init failed"__AT__"\n");
	close(n->ofd);
	return ret;
      }
      
      n->nsis.avail_in = size;
      n->nsis.next_in = (void*)ibuf;
      n->nsis.next_out = obuf;
      n->nsis.avail_out = BUFSIZ;
      loops=0;

      while ((ret=nsis_decomp(n))==CL_SUCCESS) {
	if ((size = n->nsis.next_out - obuf)) {
	  gotsome=1;
	  if (cli_writen(n->ofd, obuf, size) != (ssize_t) size) {
	    cli_dbgmsg("NSIS: cannot write output file"__AT__"\n");
	    close(n->ofd);
	    nsis_shutdown(n);
	    return CL_EWRITE;
	  }
	  n->nsis.next_out = obuf;
	  n->nsis.avail_out = BUFSIZ;
	  loops=0;
	  if ((ret=cli_checklimits("NSIS", ctx, size, 0, 0))!=CL_CLEAN) {
	    close(n->ofd);
	    nsis_shutdown(n);
	    return ret;
	  }
	} else if (++loops > 20) {
	  cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n");
	  ret = CL_EFORMAT;
	  break;
	}
      }

      nsis_shutdown(n);

      if (n->nsis.next_out - obuf) {
	gotsome=1;
	if (cli_writen(n->ofd, obuf, n->nsis.next_out - obuf) != n->nsis.next_out - obuf) {
	  cli_dbgmsg("NSIS: cannot write output file"__AT__"\n");
	  close(n->ofd);
	  return CL_EWRITE;
	}
      }

      if (ret != CL_SUCCESS && ret != CL_BREAK) {
	cli_dbgmsg("NSIS: bad stream"__AT__"\n");
	if (gotsome) {
	  ret = CL_SUCCESS;
	} else {
	  ret = CL_EMAXSIZE;
	  close(n->ofd);
	}
	return ret;
      }

    }

    return CL_SUCCESS;

  } else {
    if (!n->freeme) {
      if ((ret=nsis_init(n))!=CL_SUCCESS) {
	cli_dbgmsg("NSIS: decompressor init failed\n");
	return ret;
      }
      if(!(n->freeme = fmap_need_off_once(n->map, n->curpos, n->asz))) {
	cli_dbgmsg("NSIS: cannot read %u bytes"__AT__"\n", n->asz);
	return CL_EREAD;
      }
      n->nsis.next_in = (void*)n->freeme;
      n->nsis.avail_in = n->asz;
    }

    if (n->nsis.avail_in<=4) {
      cli_dbgmsg("NSIS: extraction complete\n");
      return CL_BREAK;
    }
    n->nsis.next_out = obuf;
    n->nsis.avail_out = 4;
    loops = 0;

    while ((ret=nsis_decomp(n))==CL_SUCCESS) {
      if (n->nsis.next_out - obuf == 4) break;
      if (++loops > 20) {
	cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n");
	ret = CL_BREAK;
	break;
      }
    }

    if (ret != CL_SUCCESS) {
      cli_dbgmsg("NSIS: bad stream"__AT__"\n");
      return CL_EFORMAT;
    }

    size=cli_readint32(obuf);
    if ((ret=cli_checklimits("NSIS", ctx, size, 0, 0))!=CL_CLEAN) {
      return ret;
    }

    if (size == 0) {
        cli_dbgmsg("NSIS: Empty file found.\n");
        return CL_SUCCESS;
    }

    n->nsis.next_out = obuf;
    n->nsis.avail_out = MIN(BUFSIZ,size);
    loops = 0;

      if ((n->ofd=open(n->ofn, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600))==-1) {
        cli_errmsg("NSIS: unable to create output file %s - aborting.", n->ofn);
        return CL_ECREAT;
      }
      n->opened = 1;

    while (size && (ret=nsis_decomp(n))==CL_SUCCESS) {
      unsigned int wsz;
      if ((wsz = n->nsis.next_out - obuf)) {
	gotsome=1;
	if (cli_writen(n->ofd, obuf, wsz) != (ssize_t) wsz) {
	  cli_dbgmsg("NSIS: cannot write output file"__AT__"\n");
	  close(n->ofd);
	  return CL_EWRITE;
	}
	size-=wsz;
	loops=0;
	n->nsis.next_out = obuf;
	n->nsis.avail_out = MIN(size,BUFSIZ);
      } else if ( ++loops > 20 ) {
	cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n");
	ret = CL_EFORMAT;
	break;
      }
    }

    if (n->nsis.next_out - obuf) {
      gotsome=1;
      if (cli_writen(n->ofd, obuf, n->nsis.next_out - obuf) != n->nsis.next_out - obuf) {
	cli_dbgmsg("NSIS: cannot write output file"__AT__"\n");
	close(n->ofd);
	return CL_EWRITE;
      }
    }

    if (ret == CL_EFORMAT) {
      cli_dbgmsg("NSIS: bad stream"__AT__"\n");
      if (!gotsome) {
	close(n->ofd);
	return CL_EMAXSIZE;
      } 
    }

    if (ret == CL_EFORMAT || ret == CL_BREAK) {
      n->eof=1;
    } else if (ret != CL_SUCCESS) {
      cli_dbgmsg("NSIS: bad stream"__AT__"\n");
      close(n->ofd);
      return CL_EFORMAT;
    }
    return CL_SUCCESS;
  }

}
Пример #15
0
/* Stripe handling: deflate block (type 0x80000005) */
static int dmg_stripe_inflate(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mish_with_stripes *mish_set)
{
    int ret = CL_CLEAN, zstat;
    z_stream strm;
    size_t off = mish_set->stripes[index].dataOffset;
    size_t len = mish_set->stripes[index].dataLength;
    uint64_t size_so_far = 0;
    uint64_t expected_len = mish_set->stripes[index].sectorCount * DMG_SECTOR_SIZE;
    uint8_t obuf[BUFSIZ];

    cli_dbgmsg("dmg_stripe_inflate: stripe " STDu32 "\n", index);
    if (len == 0)
        return CL_CLEAN;

    memset(&strm, 0, sizeof(strm));
    strm.next_in = (void*)fmap_need_off_once(*ctx->fmap, off, len);
    if (!strm.next_in) {
        cli_warnmsg("dmg_stripe_inflate: fmap need failed on stripe " STDu32 "\n", index);
        return CL_EMAP;
    }
    strm.avail_in = len;
    strm.next_out = obuf;
    strm.avail_out = sizeof(obuf);

    zstat = inflateInit(&strm);
    if(zstat != Z_OK) {
        cli_warnmsg("dmg_stripe_inflate: inflateInit failed\n");
        return CL_EMEM;
    }

    while(strm.avail_in) {
        int written;
        if (size_so_far > expected_len) {
            cli_warnmsg("dmg_stripe_inflate: expected size exceeded!\n");
            inflateEnd(&strm);
            return CL_EFORMAT;
        }
        zstat = inflate(&strm, Z_NO_FLUSH);   /* zlib */
        switch(zstat) {
        case Z_OK:
            if(strm.avail_out == 0) {
                if ((written=cli_writen(fd, obuf, sizeof(obuf)))!=sizeof(obuf)) {
                    cli_errmsg("dmg_stripe_inflate: failed write to output file\n");
                    inflateEnd(&strm);
                    return CL_EWRITE;
                }
                size_so_far += written;
                strm.next_out = (Bytef *)obuf;
                strm.avail_out = sizeof(obuf);
            }
            continue;
        case Z_STREAM_END:
        default:
            written = sizeof(obuf) - strm.avail_out;
            if (written) {
                if ((cli_writen(fd, obuf, written))!=written) {
                    cli_errmsg("dmg_stripe_inflate: failed write to output file\n");
                    inflateEnd(&strm);
                    return CL_EWRITE;
                }
                size_so_far += written;
                strm.next_out = (Bytef *)obuf;
                strm.avail_out = sizeof(obuf);
                if (zstat == Z_STREAM_END)
                    break;
            }
            if(strm.msg)
                cli_dbgmsg("dmg_stripe_inflate: after writing " STDu64 " bytes, "
                           "got error \"%s\" inflating stripe " STDu32 "\n",
                           size_so_far, strm.msg, index);
            else
                cli_dbgmsg("dmg_stripe_inflate: after writing " STDu64 " bytes, "
                           "got error %d inflating stripe " STDu32 "\n",
                           size_so_far, zstat, index);
            inflateEnd(&strm);
            return CL_EFORMAT;
        }
        break;
    }

    if(strm.avail_out != sizeof(obuf)) {
        if(cli_writen(fd, obuf, sizeof(obuf) - strm.avail_out) < 0) {
            cli_errmsg("dmg_stripe_inflate: failed write to output file\n");
            inflateEnd(&strm);
            return CL_EWRITE;
        }
    }

    inflateEnd(&strm);
    return CL_CLEAN;
}
Пример #16
0
/* Stripe handling: bzip block (type 0x80000006) */
static int dmg_stripe_bzip(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mish_with_stripes *mish_set)
{
    int ret = CL_CLEAN;
    size_t off = mish_set->stripes[index].dataOffset;
    size_t len = mish_set->stripes[index].dataLength;
    uint64_t size_so_far = 0;
    uint64_t expected_len = mish_set->stripes[index].sectorCount * DMG_SECTOR_SIZE;
#if HAVE_BZLIB_H
    int rc;
    bz_stream strm;
    uint8_t obuf[BUFSIZ];
#endif

    cli_dbgmsg("dmg_stripe_bzip: stripe " STDu32 " initial len " STDu64 " expected len " STDu64 "\n",
               index, len, expected_len);

#if HAVE_BZLIB_H
    memset(&strm, 0, sizeof(strm));
    strm.next_out = obuf;
    strm.avail_out = sizeof(obuf);
    if (BZ2_bzDecompressInit(&strm, 0, 0) != BZ_OK) {
        cli_dbgmsg("dmg_stripe_bzip: bzDecompressInit failed\n");
        return CL_EOPEN;
    }

    do {
        if (size_so_far > expected_len) {
            cli_warnmsg("dmg_stripe_bzip: expected size exceeded!\n");
            ret = CL_EFORMAT;
            break;
        }
        if (strm.avail_in == 0) {
            size_t next_len = (len > sizeof(obuf)) ? sizeof(obuf) : len;
            dmg_bzipmsg("dmg_stripe_bzip: off %lu len %lu next_len %lu\n", off, len, next_len);
            strm.next_in = (void*)fmap_need_off_once(*ctx->fmap, off, next_len);
            if (strm.next_in == NULL) {
                cli_dbgmsg("dmg_stripe_bzip: expected more stream\n");
                ret = CL_EMAP;
                break;
            }
            strm.avail_in = next_len;
            len -= next_len;
            off += next_len;
        }

        dmg_bzipmsg("dmg_stripe_bzip: before = strm.avail_in %lu strm.avail_out: %lu\n", strm.avail_in, strm.avail_out);
        rc = BZ2_bzDecompress(&strm);
        if ((rc != BZ_OK) && (rc != BZ_STREAM_END)) {
            cli_dbgmsg("dmg_stripe_bzip: decompress error: %d\n", rc);
            ret = CL_EFORMAT;
            break;
        }

        dmg_bzipmsg("dmg_stripe_bzip: after = strm.avail_in %lu strm.avail_out: %lu rc: %d %d\n",
                    strm.avail_in, strm.avail_out, rc, BZ_STREAM_END);
        /* Drain output buffer */
        if (!strm.avail_out) {
            size_t next_write = sizeof(obuf);
            do {
                size_so_far += next_write;
                dmg_bzipmsg("dmg_stripe_bzip: size_so_far: " STDu64 " next_write: %lu\n", size_so_far, next_write);
                if (size_so_far > expected_len) {
                    cli_warnmsg("dmg_stripe_bzip: expected size exceeded!\n");
                    ret = CL_EFORMAT;
                    rc = BZ_DATA_ERROR; /* prevent stream end block */
                    break;
                }

                ret = cli_checklimits("dmg_stripe_bzip", ctx, (unsigned long)(size_so_far + sizeof(obuf)), 0, 0);
                if (ret != CL_CLEAN) {
                    break;
                }

                if (cli_writen(fd, obuf, next_write) != next_write) {
                    cli_dbgmsg("dmg_stripe_bzip: error writing to tmpfile\n");
                    ret = CL_EWRITE;
                    break;
                }

                strm.next_out = obuf;
                strm.avail_out = sizeof(obuf);

                if (rc == BZ_OK)
                    rc = BZ2_bzDecompress(&strm);
                if ((rc != BZ_OK) && (rc != BZ_STREAM_END)) {
                    cli_dbgmsg("dmg_stripe_bzip: decompress error: %d\n", rc);
                    ret = CL_EFORMAT;
                    break;
                }
            } while (!strm.avail_out);
        }
        /* Stream end, so write data if any remains in buffer */
        if (rc == BZ_STREAM_END) {
            size_t next_write = sizeof(obuf) - strm.avail_out;
            size_so_far += next_write;
            dmg_bzipmsg("dmg_stripe_bzip: size_so_far: " STDu64 " next_write: %lu\n", size_so_far, next_write);

            ret = cli_checklimits("dmg_stripe_bzip", ctx, (unsigned long)(size_so_far + sizeof(obuf)), 0, 0);
            if (ret != CL_CLEAN) {
                break;
            }

            if (cli_writen(fd, obuf, next_write) != next_write) {
                cli_dbgmsg("dmg_stripe_bzip: error writing to tmpfile\n");
                ret = CL_EWRITE;
                break;
            }

            strm.next_out = obuf;
            strm.avail_out = sizeof(obuf);
        }
    } while ((rc == BZ_OK) && (len > 0));

    BZ2_bzDecompressEnd(&strm);
#endif

    if (ret == CL_CLEAN) {
        if (size_so_far != expected_len) {
            cli_dbgmsg("dmg_stripe_bzip: output does not match expected size!\n");
        }
    }
    return ret;
}
Пример #17
0
int cli_rebuildpe(char *buffer, struct cli_exe_section *sections, int sects, uint32_t base, uint32_t ep, uint32_t ResRva, uint32_t ResSize, int file)
{
  uint32_t datasize=0, rawbase=PESALIGN(0x148+0x80+0x28*sects, 0x200);
  char *pefile=NULL, *curpe;
  struct IMAGE_PE_HEADER *fakepe;
  int i, gotghost=(sections[0].rva > PESALIGN(rawbase, 0x1000));

  if (gotghost) rawbase=PESALIGN(0x148+0x80+0x28*(sects+1), 0x200);

  if(sects+gotghost > 96)
    return 0;

  for (i=0; i < sects; i++)
    datasize+=PESALIGN(sections[i].rsz, 0x200);

  if(datasize > CLI_MAX_ALLOCATION)
    return 0;

  if((pefile = (char *) cli_calloc(rawbase+datasize, 1))) {
    memcpy(pefile, HEADERS, 0x148);

    datasize = PESALIGN(rawbase, 0x1000);

    fakepe = (struct IMAGE_PE_HEADER *)(pefile+0xd0);
    fakepe->NumberOfSections = EC16(sects+gotghost);
    fakepe->AddressOfEntryPoint = EC32(ep);
    fakepe->ImageBase = EC32(base);
    fakepe->SizeOfHeaders = EC32(rawbase);
    memset(pefile+0x148, 0, 0x80);
    cli_writeint32(pefile+0x148+0x10, ResRva);
    cli_writeint32(pefile+0x148+0x14, ResSize);
    curpe = pefile+0x148+0x80;

    if (gotghost) {
      snprintf(curpe, 8, "empty");
      cli_writeint32(curpe+8, sections[0].rva-datasize); /* vsize */
      cli_writeint32(curpe+12, datasize); /* rva */
      cli_writeint32(curpe+0x24, 0xffffffff);
      curpe+=40;
      datasize+=PESALIGN(sections[0].rva-datasize, 0x1000);
    }

    for (i=0; i < sects; i++) {
      snprintf(curpe, 8, ".clam%.2d", i+1);
      cli_writeint32(curpe+8, sections[i].vsz);
      cli_writeint32(curpe+12, sections[i].rva);
      cli_writeint32(curpe+16, sections[i].rsz);
      cli_writeint32(curpe+20, rawbase);
      /* already zeroed
      cli_writeint32(curpe+24, 0);
      cli_writeint32(curpe+28, 0);
      cli_writeint32(curpe+32, 0);
      */
      cli_writeint32(curpe+0x24, 0xffffffff);
      memcpy(pefile+rawbase, buffer+sections[i].raw, sections[i].rsz);
      rawbase+=PESALIGN(sections[i].rsz, 0x200);
      curpe+=40;
      datasize+=PESALIGN(sections[i].vsz, 0x1000);
    }
    fakepe->SizeOfImage = EC32(datasize);
  } else {
    return 0;
  }

  i = (cli_writen(file, pefile, rawbase)!=-1);
  free(pefile);
  return i;
}
Пример #18
0
static int unz(const uint8_t *src, uint32_t csize, uint32_t usize, uint16_t method, uint16_t flags, unsigned int *fu, cli_ctx *ctx, char *tmpd, zip_cb zcb) {
    char name[1024], obuf[BUFSIZ];
    char *tempfile = name;
    int of, ret=CL_CLEAN;
    unsigned int res=1, written=0;

    if(tmpd) {
        snprintf(name, sizeof(name), "%s"PATHSEP"zip.%03u", tmpd, *fu);
        name[sizeof(name)-1]='\0';
    } else {
        if(!(tempfile = cli_gentemp(ctx->engine->tmpdir))) return CL_EMEM;
    }
    if((of = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRUSR|S_IWUSR))==-1) {
        cli_warnmsg("cli_unzip: failed to create temporary file %s\n", tempfile);
        if(!tmpd) free(tempfile);
        return CL_ECREAT;
    }
    switch (method) {
    case ALG_STORED:
        if(csize<usize) {
            unsigned int fake = *fu + 1;
            cli_dbgmsg("cli_unzip: attempting to inflate stored file with inconsistent size\n");
            if ((ret=unz(src, csize, usize, ALG_DEFLATE, 0, &fake, ctx, tmpd, zcb))==CL_CLEAN) {
                (*fu)++;
                res=fake-(*fu);
            }
            else break;
        }
        if(res==1) {
            if(ctx->engine->maxfilesize && csize > ctx->engine->maxfilesize) {
                cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", (long unsigned int) ctx->engine->maxfilesize);
                csize = ctx->engine->maxfilesize;
            }
            if(cli_writen(of, src, csize)!=(int)csize) ret = CL_EWRITE;
            else res=0;
        }
        break;

    case ALG_DEFLATE:
    case ALG_DEFLATE64: {
        union {
            z_stream64 strm64;
            z_stream strm;
        } strm;
        typedef int (*unz_init_) (void *, int);
        typedef int (*unz_unz_) (void *, int);
        typedef int (*unz_end_) (void *);
        unz_init_ unz_init;
        unz_unz_ unz_unz;
        unz_end_ unz_end;
        int wbits;
        void **next_in;
        void **next_out;
        unsigned int *avail_in;
        unsigned int *avail_out;

        if(method == ALG_DEFLATE64) {
            unz_init = (unz_init_)inflate64Init2;
            unz_unz = (unz_unz_)inflate64;
            unz_end = (unz_end_)inflate64End;
            next_in = (void *)&strm.strm64.next_in;
            next_out = (void *)&strm.strm64.next_out;
            avail_in = &strm.strm64.avail_in;
            avail_out = &strm.strm64.avail_out;
            wbits=MAX_WBITS64;
        } else {
            unz_init = (unz_init_)wrap_inflateinit2;
            unz_unz = (unz_unz_)inflate;
            unz_end = (unz_end_)inflateEnd;
            next_in = (void *)&strm.strm.next_in;
            next_out = (void *)&strm.strm.next_out;
            avail_in = &strm.strm.avail_in;
            avail_out = &strm.strm.avail_out;
            wbits=MAX_WBITS;
        }

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

        *next_in = (void*) src;
        *next_out = obuf;
        *avail_in = csize;
        *avail_out = sizeof(obuf);
        if (unz_init(&strm, -wbits)!=Z_OK) {
            cli_dbgmsg("cli_unzip: zinit failed\n");
            break;
        }
        while(1) {
            while((res = unz_unz(&strm, Z_NO_FLUSH))==Z_OK) {};
            if(*avail_out!=sizeof(obuf)) {
                written+=sizeof(obuf)-(*avail_out);
                if(ctx->engine->maxfilesize && written > ctx->engine->maxfilesize) {
                    cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", (long unsigned int) ctx->engine->maxfilesize);
                    res = Z_STREAM_END;
                    break;
                }
                if(cli_writen(of, obuf, sizeof(obuf)-(*avail_out)) != (int)(sizeof(obuf)-(*avail_out))) {
                    cli_warnmsg("cli_unzip: falied to write %lu inflated bytes\n", (unsigned long int)sizeof(obuf)-(*avail_out));
                    ret = CL_EWRITE;
                    res = 100;
                    break;
                }
                *next_out = obuf;
                *avail_out = sizeof(obuf);
                continue;
            }
            break;
        }
        unz_end(&strm);
        if (res == Z_STREAM_END) res=0;
        break;
    }


#if HAVE_BZLIB_H
#ifdef NOBZ2PREFIX
#define BZ2_bzDecompress bzDecompress
#define BZ2_bzDecompressEnd bzDecompressEnd
#define BZ2_bzDecompressInit bzDecompressInit
#endif

    case ALG_BZIP2: {
        bz_stream strm;
        memset(&strm, 0, sizeof(strm));
        strm.next_in = (char *)src;
        strm.next_out = obuf;
        strm.avail_in = csize;
        strm.avail_out = sizeof(obuf);
        if (BZ2_bzDecompressInit(&strm, 0, 0)!=BZ_OK) {
            cli_dbgmsg("cli_unzip: bzinit failed\n");
            break;
        }
        while((res = BZ2_bzDecompress(&strm))==BZ_OK || res==BZ_STREAM_END) {
            if(strm.avail_out!=sizeof(obuf)) {
                written+=sizeof(obuf)-strm.avail_out;
                if(ctx->engine->maxfilesize && written > ctx->engine->maxfilesize) {
                    cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", (unsigned long int) ctx->engine->maxfilesize);
                    res = BZ_STREAM_END;
                    break;
                }
                if(cli_writen(of, obuf, sizeof(obuf)-strm.avail_out) != (int)(sizeof(obuf)-strm.avail_out)) {
                    cli_warnmsg("cli_unzip: falied to write %lu bunzipped bytes\n", (long unsigned int)sizeof(obuf)-strm.avail_out);
                    ret = CL_EWRITE;
                    res = 100;
                    break;
                }
                strm.next_out = obuf;
                strm.avail_out = sizeof(obuf);
                if (res == BZ_OK) continue; /* after returning BZ_STREAM_END once, decompress returns an error */
            }
            break;
        }
        BZ2_bzDecompressEnd(&strm);
        if (res == BZ_STREAM_END) res=0;
        break;
    }
#endif /* HAVE_BZLIB_H */


    case ALG_IMPLODE: {
        struct xplstate strm;
        strm.next_in = (void*)src;
        strm.next_out = (uint8_t *)obuf;
        strm.avail_in = csize;
        strm.avail_out = sizeof(obuf);
        if (explode_init(&strm, flags)!=EXPLODE_OK) {
            cli_dbgmsg("cli_unzip: explode_init() failed\n");
            break;
        }
        while((res = explode(&strm))==EXPLODE_OK) {
            if(strm.avail_out!=sizeof(obuf)) {
                written+=sizeof(obuf)-strm.avail_out;
                if(ctx->engine->maxfilesize && written > ctx->engine->maxfilesize) {
                    cli_dbgmsg("cli_unzip: trimming output size to maxfilesize (%lu)\n", (unsigned long int) ctx->engine->maxfilesize);
                    res = 0;
                    break;
                }
                if(cli_writen(of, obuf, sizeof(obuf)-strm.avail_out) != (int)(sizeof(obuf)-strm.avail_out)) {
                    cli_warnmsg("cli_unzip: falied to write %lu exploded bytes\n", (unsigned long int) sizeof(obuf)-strm.avail_out);
                    ret = CL_EWRITE;
                    res = 100;
                    break;
                }
                strm.next_out = (uint8_t *)obuf;
                strm.avail_out = sizeof(obuf);
                continue;
            }
            break;
        }
        break;
    }


    case ALG_LZMA:
        /* easy but there's not a single sample in the zoo */

#if !HAVE_BZLIB_H
    case ALG_BZIP2:
#endif
    case ALG_SHRUNK:
    case ALG_REDUCE1:
    case ALG_REDUCE2:
    case ALG_REDUCE3:
    case ALG_REDUCE4:
    case ALG_TOKENZD:
    case ALG_OLDTERSE:
    case ALG_RSVD1:
    case ALG_RSVD2:
    case ALG_RSVD3:
    case ALG_RSVD4:
    case ALG_RSVD5:
    case ALG_NEWTERSE:
    case ALG_LZ77:
    case ALG_WAVPACK:
    case ALG_PPMD:
        cli_dbgmsg("cli_unzip: unsupported method (%d)\n", method);
        break;
    default:
        cli_dbgmsg("cli_unzip: unknown method (%d)\n", method);
        break;
    }

    if(!res) {
        (*fu)++;
        cli_dbgmsg("cli_unzip: extracted to %s\n", tempfile);
        if (lseek(of, 0, SEEK_SET) == -1) {
            cli_dbgmsg("cli_unzip: call to lseek() failed\n");
            if (!(tmpd))
                free(tempfile);
            close(of);
            return CL_ESEEK;
        }
        ret = zcb(of, ctx);
        close(of);
        if(!ctx->engine->keeptmp)
            if(cli_unlink(tempfile)) ret = CL_EUNLINK;
        if(!tmpd) free(tempfile);
        return ret;
    }

    close(of);
    if(!ctx->engine->keeptmp)
        if(cli_unlink(tempfile)) ret = CL_EUNLINK;
    if(!tmpd) free(tempfile);
    cli_dbgmsg("cli_unzip: extraction failed\n");
    return ret;
}
Пример #19
0
int
cli_untar(const char *dir, unsigned int posix, cli_ctx *ctx)
{
	int size = 0, ret, fout=-1;
	int in_block = 0;
	int last_header_bad = 0;
	int limitnear = 0;
	unsigned int files = 0;
	char fullname[NAME_MAX + 1];
	size_t pos = 0;
	size_t currsize = 0;
        char zero[BLOCKSIZE];
	unsigned int num_viruses = 0; 

	cli_dbgmsg("In untar(%s)\n", dir);
        memset(zero, 0, sizeof(zero));

	for(;;) {
	        const char *block;
		size_t nread;

		block = fmap_need_off_once_len(*ctx->fmap, pos, BLOCKSIZE, &nread); 
		cli_dbgmsg("cli_untar: pos = %lu\n", (unsigned long)pos);

		if(!in_block && !nread)
			break;

                if (!nread)
                    block = zero;

		if(!block) {
			if(fout>=0)
				close(fout);
			cli_errmsg("cli_untar: block read error\n");
			return CL_EREAD;
		}
		pos += nread;

		if(!in_block) {
			char type;
			int directory, skipEntry = 0;
			int checksum = -1;
			char magic[7], name[101], osize[TARSIZELEN + 1];
			currsize = 0;

			if(fout>=0) {
				lseek(fout, 0, SEEK_SET);
				ret = cli_magic_scandesc(fout, ctx);
				close(fout);
				if (!ctx->engine->keeptmp)
					if (cli_unlink(fullname)) return CL_EUNLINK;
				if (ret==CL_VIRUS) {
				    if (!SCAN_ALL)
					return CL_VIRUS;
				    else
					num_viruses++;
				}
				fout = -1;
			}

			if(block[0] == '\0')	/* We're done */
				break;
			if((ret=cli_checklimits("cli_untar", ctx, 0, 0, 0))!=CL_CLEAN)
				return ret;

			checksum = getchecksum(block);
			cli_dbgmsg("cli_untar: Candidate checksum = %d, [%o in octal]\n", checksum, checksum);
			if(testchecksum(block, checksum) != 0) {
				// If checksum is bad, dump and look for next header block
				cli_dbgmsg("cli_untar: Invalid checksum in tar header. Skip to next...\n");
				if (last_header_bad == 0) {
					last_header_bad++;
					cli_dbgmsg("cli_untar: Invalid checksum found inside archive!\n");
				}
				continue;
			} else {
				last_header_bad = 0;
				cli_dbgmsg("cli_untar: Checksum %d is valid.\n", checksum);
			}

			/* Notice assumption that BLOCKSIZE > 262 */
			if(posix) {
				strncpy(magic, block+257, 5);
				magic[5] = '\0';
				if(strcmp(magic, "ustar") != 0) {
					cli_dbgmsg("cli_untar: Incorrect magic string '%s' in tar header\n", magic);
					return CL_EFORMAT;
				}
			}

			type = block[TARFILETYPEOFFSET];

			switch(type) {
				default:
					cli_dbgmsg("cli_untar: unknown type flag %c\n", type);
				case '0':	/* plain file */
				case '\0':	/* plain file */
				case '7':	/* contiguous file */
				case 'M':	/* continuation of a file from another volume; might as well scan it. */
					files++;
					directory = 0;
					break;
				case '1':	/* Link to already archived file */
				case '5':	/* directory */
				case '2':	/* sym link */
				case '3':	/* char device */
				case '4':	/* block device */
				case '6':	/* fifo special */
				case 'V':	/* Volume header */
					directory = 1;
					break;
				case 'K':
				case 'L':
					/* GNU extension - ././@LongLink
					 * Discard the blocks with the extended filename,
					 * the last header will contain parts of it anyway
					 */
				case 'N': 	/* Old GNU format way of storing long filenames. */
				case 'A':	/* Solaris ACL */
				case 'E':	/* Solaris Extended attribute s*/
				case 'I':	/* Inode only */
				case 'g':	/* Global extended header */
				case 'x': 	/* Extended attributes */
				case 'X':	/* Extended attributes (POSIX) */
					directory = 0;
					skipEntry = 1;
					break;
			}

			if(directory) {
				in_block = 0;
				continue;
			}

			strncpy(osize, block+TARSIZEOFFSET, TARSIZELEN);
			osize[TARSIZELEN] = '\0';
			size = octal(osize);
			if(size < 0) {
				cli_dbgmsg("cli_untar: Invalid size in tar header\n");
				skipEntry++;
			} else {
				cli_dbgmsg("cli_untar: size = %d\n", size);
				ret = cli_checklimits("cli_untar", ctx, size, 0, 0);
				switch(ret) {
					case CL_EMAXFILES: // Scan no more files 
						skipEntry++;
						limitnear = 0;
						break;
					case CL_EMAXSIZE: // Either single file limit or total byte limit would be exceeded
						cli_dbgmsg("cli_untar: would exceed limit, will try up to max");
						limitnear = 1;
						break;
					default: // Ok based on reported content size
						limitnear = 0;
						break;
				}
			}

			if(skipEntry) {
				const int nskip = (size % BLOCKSIZE || !size) ? size + BLOCKSIZE - (size % BLOCKSIZE) : size;

				if(nskip < 0) {
					cli_dbgmsg("cli_untar: got negative skip size, giving up\n");
					return CL_CLEAN;
				}
				cli_dbgmsg("cli_untar: skipping entry\n");
				pos += nskip;
				continue;
			}

			strncpy(name, block, 100);
			name[100] = '\0';
			if(cli_matchmeta(ctx, name, size, size, 0, files, 0, NULL) == CL_VIRUS) {
			    if (!SCAN_ALL)
				return CL_VIRUS;
			    else
				num_viruses++;
			}

			snprintf(fullname, sizeof(fullname)-1, "%s"PATHSEP"tar%02u", dir, files);
			fullname[sizeof(fullname)-1] = '\0';
			fout = open(fullname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC|O_BINARY, 0600);

			if(fout < 0) {
				char err[128];
				cli_errmsg("cli_untar: Can't create temporary file %s: %s\n", fullname, cli_strerror(errno, err, sizeof(err)));
				return CL_ETMPFILE;
			}

			cli_dbgmsg("cli_untar: extracting to %s\n", fullname);

			in_block = 1;
		} else { /* write or continue writing file contents */
                        int nbytes, nwritten;
                        int skipwrite = 0;
                        char err[128];

			nbytes = size>512? 512:size;
                        if (nread && nread < (size_t)nbytes)
                            nbytes = nread;

			if (limitnear > 0) {
				currsize += nbytes;
				cli_dbgmsg("cli_untar: Approaching limit...\n");
				if (cli_checklimits("cli_untar", ctx, (unsigned long)currsize, 0, 0) != CL_SUCCESS) {
					// Limit would be exceeded by this file, suppress writing beyond limit
					// Need to keep reading to get to end of file chunk
					skipwrite++;
				}
			}

			if (skipwrite == 0) {
				nwritten = (int)cli_writen(fout, block, (size_t)nbytes);

				if(nwritten != nbytes) {
					cli_errmsg("cli_untar: only wrote %d bytes to file %s (out of disc space?): %s\n",
						nwritten, fullname, cli_strerror(errno, err, sizeof(err)));
					close(fout);
					return CL_EWRITE;
				}
			}
			size -= nbytes;
			if ((size != 0) && (nread == 0)) {
				// Truncated tar file, so end file content like tar behavior
				cli_dbgmsg("cli_untar: No bytes read! Forcing end of file content.\n");
				size = 0;
			}
		}
		if (size == 0)
			in_block = 0;
        }
	if(fout>=0) {
		lseek(fout, 0, SEEK_SET);
		ret = cli_magic_scandesc(fout, ctx);
		close(fout);
		if (!ctx->engine->keeptmp)
			if (cli_unlink(fullname)) return CL_EUNLINK;
		if (ret==CL_VIRUS)
			return CL_VIRUS;
	}
	if (num_viruses)
	    return CL_VIRUS;
	return CL_CLEAN;
}
Пример #20
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;
}
Пример #21
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;
}
Пример #22
0
int cli_7unz (cli_ctx *ctx, size_t offset) {
    CFileInStream archiveStream;
    CLookToRead lookStream;
    CSzArEx db;
    SRes res;
    UInt16 utf16buf[UTFBUFSZ], *utf16name = utf16buf;
    int namelen = UTFBUFSZ, found = CL_CLEAN;
    Int64 begin_of_archive = offset;
    UInt32 viruses_found = 0;

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

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

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

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

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

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

	    if (f->IsDir)
		continue;

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

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

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

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

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

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

    if (SCAN_ALL && viruses_found)
	return CL_VIRUS;
    return found;
}
Пример #23
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;
}
Пример #24
0
static int nsis_unpack_next(struct nsis_st *n, cli_ctx *ctx) {
  unsigned char *ibuf;
  uint32_t size, loops;
  int ret;
  unsigned char obuf[BUFSIZ];

  if (n->eof) {
    cli_dbgmsg("NSIS: extraction complete\n");
    return CL_BREAK;
  }
  if (ctx->limits && ctx->limits->maxfiles && n->fno >= ctx->limits->maxfiles) {
    cli_dbgmsg("NSIS: Files limit reached (max: %u)\n", ctx->limits->maxfiles);
    return CL_EMAXFILES;
  }

  if (n->fno)
    snprintf(n->ofn, 1023, "%s/content.%.3u", n->dir, n->fno);
  else
    snprintf(n->ofn, 1023, "%s/headers", n->dir);

  n->fno++;

  if ((n->ofd=open(n->ofn, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600))==-1) {
    cli_errmsg("NSIS: unable to create output file %s - aborting.", n->ofn);
    return CL_EIO;
  }

  if (!n->solid) {
    if (cli_readn(n->ifd, &size, 4)!=4) {
      cli_dbgmsg("NSIS: reached EOF - extraction complete\n");
      close(n->ofd);
      return CL_BREAK;
    }
    if (n->asz==4) {
      cli_dbgmsg("NSIS: reached CRC - extraction complete\n");
      close(n->ofd);
      return CL_BREAK;
    }
    loops = EC32(size);
    if (!(size = (loops&~0x80000000))) {
      cli_dbgmsg("NSIS: empty file found\n");
      return CL_SUCCESS;
    }
    if (n->asz <4 || size > n->asz-4) {
      cli_dbgmsg("NSIS: next file is outside the archive\n");
      close(n->ofd);
      return CL_BREAK;
    }

    n->asz -= size+4;

    if (ctx->limits && ctx->limits->maxfilesize && size > ctx->limits->maxfilesize) {
      cli_dbgmsg("NSIS: Skipping file due to size limit (%u, max: %lu)\n", size, ctx->limits->maxfilesize);
      close(n->ofd);
      if (lseek(n->ifd, size, SEEK_CUR)==-1) return CL_EIO;
      return CL_EMAXSIZE;
    }
    if (!(ibuf= (unsigned char *) cli_malloc(size))) {
      	cli_dbgmsg("NSIS: out of memory"__AT__"\n");
      close(n->ofd);
      return CL_EMEM;
    }
    if (cli_readn(n->ifd, ibuf, size) != (ssize_t) size) {
      cli_dbgmsg("NSIS: cannot read %u bytes"__AT__"\n", size);
      free(ibuf);
      close(n->ofd);
      return CL_EIO;
    }
    if (loops==size) {
      if (cli_writen(n->ofd, ibuf, size) != (ssize_t) size) {
	cli_dbgmsg("NSIS: cannot write output file"__AT__"\n");
	free(ibuf);
	close(n->ofd);
	return CL_EIO;
      }
    } else {
      if ((ret=nsis_init(n))!=CL_SUCCESS) {
	cli_dbgmsg("NSIS: decompressor init failed"__AT__"\n");
	free(ibuf);
	close(n->ofd);
	return ret;
      }
      
      n->nsis.avail_in = size;
      n->nsis.next_in = ibuf;
      n->nsis.next_out = obuf;
      n->nsis.avail_out = BUFSIZ;
      loops=0;

      while ((ret=nsis_decomp(n))==CL_SUCCESS) {
	if ((size = n->nsis.next_out - obuf)) {
	  if (cli_writen(n->ofd, obuf, size) != (ssize_t) size) {
	    cli_dbgmsg("NSIS: cannot write output file"__AT__"\n");
	    free(ibuf);
	    close(n->ofd);
	    return CL_EIO;
	  }
	  n->nsis.next_out = obuf;
	  n->nsis.avail_out = BUFSIZ;
	  loops=0;
	  if (ctx->limits && ctx->limits->maxfilesize && size > ctx->limits->maxfilesize) {
	    cli_dbgmsg("NSIS: Skipping file due to size limit (%u, max: %lu)\n", size, ctx->limits->maxfilesize);
	    free(ibuf);
	    close(n->ofd);
	    nsis_shutdown(n);
	    return CL_EMAXSIZE;
	  }
	} else if (++loops > 10) {
	  cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n");
	  ret = CL_BREAK;
	  break;
	}
      }

      if (ret != CL_BREAK) {
	cli_dbgmsg("NSIS: bad stream"__AT__"\n");
	free(ibuf);
	close(n->ofd);
	return CL_EFORMAT;
      }

      if (cli_writen(n->ofd, obuf, n->nsis.next_out - obuf) != n->nsis.next_out - obuf) {
	cli_dbgmsg("NSIS: cannot write output file"__AT__"\n");
	free(ibuf);
	close(n->ofd);
	return CL_EIO;
      }
      nsis_shutdown(n);
    }

    free(ibuf);
    return CL_SUCCESS;

  } else {
    if (!n->freeme) {
      if ((ret=nsis_init(n))!=CL_SUCCESS) {
	cli_dbgmsg("NSIS: decompressor init failed\n");
	close(n->ofd);
	return ret;
      }
      if (!(n->freeme= (unsigned char *) cli_malloc(n->asz))) {
	cli_dbgmsg("NSIS: out of memory\n");
	close(n->ofd);
	return CL_EMEM;
      }
      if (cli_readn(n->ifd, n->freeme, n->asz) != (ssize_t) n->asz) {
	cli_dbgmsg("NSIS: cannot read %u bytes"__AT__"\n", n->asz);
	close(n->ofd);
	return CL_EIO;
      }
      n->nsis.next_in = n->freeme;
      n->nsis.avail_in = n->asz;
    }

    if (n->nsis.avail_in<=4) {
      cli_dbgmsg("NSIS: extraction complete\n");
      close(n->ofd);
      return CL_BREAK;
    }
    n->nsis.next_out = obuf;
    n->nsis.avail_out = 4;
    loops = 0;

    while ((ret=nsis_decomp(n))==CL_SUCCESS) {
      if (n->nsis.next_out - obuf == 4) break;
      if (++loops > 20) {
	cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n");
	ret = CL_BREAK;
	break;
      }
    }

    if (ret != CL_SUCCESS) {
      cli_dbgmsg("NSIS: bad stream"__AT__"\n");
      close(n->ofd);
      return CL_EFORMAT;
    }

    size=cli_readint32(obuf);
    if (ctx->limits && ctx->limits->maxfilesize && size > ctx->limits->maxfilesize) {
      cli_dbgmsg("NSIS: Breaking out due to filesize limit (%u, max: %lu) in solid archive\n", size, ctx->limits->maxfilesize);
      close(n->ofd);
      return CL_EFORMAT;
    }

    n->nsis.next_out = obuf;
    n->nsis.avail_out = MIN(BUFSIZ,size);
    loops = 0;

    while (size && (ret=nsis_decomp(n))==CL_SUCCESS) {
      unsigned int wsz;
      if ((wsz = n->nsis.next_out - obuf)) {
	if (cli_writen(n->ofd, obuf, wsz) != (ssize_t) wsz) {
	  close(n->ofd);
	  return CL_EIO;
	}
	size-=wsz;
	n->nsis.next_out = obuf;
	n->nsis.avail_out = MIN(size,BUFSIZ);
      } else if ( ++loops > 20 ) {
	cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n");
	ret = CL_BREAK;
	break;
      }
    }

    if (ret == CL_BREAK) {
      if (cli_writen(n->ofd, obuf, n->nsis.next_out - obuf) != n->nsis.next_out - obuf) {
	close(n->ofd);
	return CL_EIO;
      }
      n->eof=1;
    } else if (ret != CL_SUCCESS) {
      cli_dbgmsg("NSIS: bad stream"__AT__"\n");
      close(n->ofd);
      return CL_EFORMAT;
    }
    
    return CL_SUCCESS;
  }

}
Пример #25
0
static int rtf_object_process(struct rtf_state* state, const unsigned char* input,const size_t len)
{
	struct rtf_object_data* data = state->cb_data;
	unsigned char outdata[BUFF_SIZE];
	const unsigned char* out_data;
	size_t out_cnt = 0;
	size_t i;
	int ret;

	if(!data || !len)
		return 0;

	if(data->has_partial) {
		for(i=0;i<len && !isxdigit(input[i]);i++)
			;
		if(i<len) {
			outdata[out_cnt++] = data->partial | hextable[input[i++]];
			data->has_partial = 0;
		}
		else
			return 0;
	}
	else
		i = 0;

	for(;i<len;i++) {
		if(isxdigit(input[i])) {
				const unsigned char byte = hextable[ input[i++] ] << 4;
				while(i<len && !isxdigit(input[i]))
					i++;
				if(i == len) {
					data->partial = byte;
					data->has_partial = 1;
					break;
				}
				outdata[out_cnt++] = byte | hextable[ input[i] ];
		}
	}

	out_data = outdata;
	while(out_data && out_cnt) {
		switch(data->internal_state) {
			case WAIT_MAGIC: {
						 cli_dbgmsg("RTF: waiting for magic\n");
						 for(i=0; i<out_cnt && data->bread < rtf_data_magic_len; i++, data->bread++)
							 if(rtf_data_magic[data->bread] != out_data[i]) {
								 cli_dbgmsg("Warning: rtf objdata magic number not matched, expected:%d, got: %d, at pos:%lu\n",rtf_data_magic[i],out_data[i], (unsigned long int) data->bread);
							 }
						 out_cnt  -= i;
						 if(data->bread == rtf_data_magic_len) {
							 out_data += i;
							 data->bread = 0;
							 data->internal_state = WAIT_DESC_LEN;						 
						 }
						 break;
					 }
			case WAIT_DESC_LEN: {
						    if(data->bread == 0)
							    data->desc_len = 0;
						    for(i=0; i<out_cnt && data->bread < 4; i++,data->bread++)
							    data->desc_len  |=  ((size_t)out_data[i]) << (data->bread*8);
						    out_cnt  -= i;
						    if(data->bread == 4) {
							    out_data += i;
							    data->bread=0;
							    if(data->desc_len > 64) {
								    cli_dbgmsg("Description length too big (%lu), showing only 64 bytes of it\n", (unsigned long int) data->desc_len);
								    data->desc_name = cli_malloc(65);
							    }
							    else
								    data->desc_name = cli_malloc(data->desc_len+1);
							    if(!data->desc_name) {
                                    cli_errmsg("rtf_object_process: Unable to allocate memory for data->desc_name\n");
								    return CL_EMEM;
							    }
							    data->internal_state = WAIT_DESC;
							    cli_dbgmsg("RTF: description length:%lu\n", (unsigned long int) data->desc_len);
						    }
						    break;
					    }
			case WAIT_DESC:{
					       cli_dbgmsg("RTF: in WAIT_DESC\n");
					       for(i=0;i<out_cnt && data->bread < data->desc_len && data->bread < 64;i++, data->bread++)
						       data->desc_name[data->bread] = out_data[i];
					       out_cnt -= i;
					       out_data += i;
					       if(data->bread < data->desc_len && data->bread < 64) {
						       cli_dbgmsg("RTF: waiting for more data(1)\n");
						       return 0;/* wait for more data */
					       }
						       data->desc_name[data->bread] = '\0';
					       if(data->desc_len - data->bread > out_cnt) {
						       data->desc_len -= out_cnt;
						       cli_dbgmsg("RTF: waiting for more data(2)\n");
						       return 0;/* wait for more data */
					       }
					       out_cnt  -= data->desc_len - data->bread;
					       if(data->bread >= data->desc_len) {
						       out_data += data->desc_len - data->bread;
						       data->bread = 0;
						       cli_dbgmsg("Preparing to dump rtf embedded object, description:%s\n",data->desc_name);
						       free(data->desc_name);
						       data->desc_name = NULL;
						       data->internal_state = WAIT_ZERO;
					       }
					       break;
				       }
			case WAIT_ZERO:{
					       if(out_cnt < 8-data->bread) {
						       out_cnt = 0;
						       data->bread += out_cnt;
					       }
					       else {
						       out_cnt  -= 8-data->bread;
						       data->bread = 8;
					       }
					       if(data->bread == 8) {
						       out_data += 8;
						       data->bread = 0;
						       cli_dbgmsg("RTF: next state: wait_data_size\n");
						       data->internal_state = WAIT_DATA_SIZE;
					       }
					       break;
				       }

			case WAIT_DATA_SIZE: {
						     cli_dbgmsg("RTF: in WAIT_DATA_SIZE\n");
						    if(data->bread == 0)
							    data->desc_len = 0;
						    for(i=0; i<out_cnt && data->bread < 4; i++,data->bread++)
							    data->desc_len  |= ((size_t)out_data[i]) << (8*data->bread);
						    out_cnt  -= i;
						    if(data->bread == 4) {
							    out_data += i;
							    data->bread=0;
							    cli_dbgmsg("Dumping rtf embedded object of size:%lu\n", (unsigned long int) data->desc_len);
							    if((ret = cli_gentempfd(data->tmpdir, &data->name, &data->fd)))
								    return ret;
							    data->internal_state = DUMP_DATA;
	    						    cli_dbgmsg("RTF: next state: DUMP_DATA\n");
						    }
						    break;
					     }
			case DUMP_DATA: {
						ssize_t out_want = out_cnt < data->desc_len ? out_cnt : data->desc_len;
						if(!data->bread) {
							if(out_data[0] != 0xd0 || out_data[1]!=0xcf) {
								/* this is not an ole2 doc, but some ole (stream?) to be
								 * decoded by cli_decode_ole_object*/
							    char out[4];
							    data->bread = 1;/* flag to indicate this needs to be scanned with cli_decode_ole_object*/
							    cli_writeint32(out,data->desc_len);
							    if(cli_writen(data->fd,out,4)!=4)
								    return CL_EWRITE; 
							}
							else
								data->bread = 2;
						}

						data->desc_len -= out_want;
						if(cli_writen(data->fd,out_data,out_want) != out_want) {
							return CL_EWRITE;
						}
						out_data += out_want;
						out_cnt  -= out_want;
						if(!data->desc_len) { 
							int rc;
							if(( rc = decode_and_scan(data, data->ctx) ))
								return rc;
							data->bread=0;
							data->internal_state = WAIT_MAGIC;
						}
						break;					
					}				    
			case DUMP_DISCARD:
			default:
					out_cnt = 0;
					;
		}
	}
	return 0;
}
Пример #26
0
int wwunpack(uint8_t *exe, uint32_t exesz, uint8_t *wwsect, struct cli_exe_section *sects, uint16_t scount, uint32_t pe, int desc) {
  uint8_t *structs = wwsect + 0x2a1, *compd, *ccur, *unpd, *ucur, bc;
  uint32_t src, srcend, szd, bt, bits;
  int error=0, i;

  cli_dbgmsg("in wwunpack\n");
  while (1) {
    if (!CLI_ISCONTAINED(wwsect, sects[scount].rsz, structs, 17)) {
      cli_dbgmsg("WWPack: Array of structs out of section\n");
      break;
    }
    src = sects[scount].rva - cli_readint32(structs); /* src delta / dst delta - not used / dwords / end of src */
    structs+=8;
    szd = cli_readint32(structs) * 4;
    structs+=4;
    srcend = cli_readint32(structs);
    structs+=4;

    unpd = ucur = exe+src+srcend+4-szd;
    if (!szd || !CLI_ISCONTAINED(exe, exesz, unpd, szd)) {
      cli_dbgmsg("WWPack: Compressed data out of file\n");
      break;
    }
    cli_dbgmsg("WWP: src: %x, szd: %x, srcend: %x - %x\n", src, szd, srcend, srcend+4-szd);
    if (!(compd = cli_malloc(szd))) {
        cli_dbgmsg("WWPack: Unable to allocate memory for compd\n");
        break;
    }
    memcpy(compd, unpd, szd);
    memset(unpd, -1, szd); /*FIXME*/
    ccur=compd;
    
    RESEED;
    while(!error) {
      uint32_t backbytes, backsize;
      uint8_t saved;

      BIT;
      if (!bits) { /* BYTE copy */
	if(ccur-compd>=szd || !CLI_ISCONTAINED(exe, exesz, ucur, 1))
	  error=1;
	else
	  *ucur++=*ccur++;
	continue;
      }

      BITS(2);
      if(bits==3) { /* WORD backcopy */
	uint8_t shifted, subbed = 31;
	BITS(2);
	shifted = bits + 5;
	if(bits>=2) {
	  shifted++;
	  subbed += 0x80;
	}
	backbytes = (1<<shifted)-subbed; /* 1h, 21h, 61h, 161h */
	BITS(shifted); /* 5, 6, 8, 9 */
	if(error || bits == 0x1ff) break;
	backbytes+=bits;
	if(!CLI_ISCONTAINED(exe, exesz, ucur, 2) || !CLI_ISCONTAINED(exe, exesz, ucur-backbytes, 2)) {
	  error=1;
	} else {
	  ucur[0]=*(ucur-backbytes);
	  ucur[1]=*(ucur-backbytes+1);
	  ucur+=2;
	}
	continue;
      }

      /* BLOCK backcopy */
      saved = bits; /* cmp al, 1 / pushf */

      BITS(3);
      if (bits<6) {
	backbytes = bits;
	switch(bits) {
	case 4: /* 10,11 */
	  backbytes++;
	case 3: /* 8,9 */
	  BIT;
	  backbytes+=bits;
	case 0:	case 1:	case 2: /* 5,6,7 */
	  backbytes+=5;
	  break;
	case 5: /* 12 */
	  backbytes=12;
	  break;
	}
	BITS(backbytes);
	bits+=(1<<backbytes)-31;
      } else if(bits==6) {
	BITS(0x0e);
	bits+=0x1fe1;
      } else {
	BITS(0x0f);
	bits+=0x5fe1;
      }

      backbytes = bits;

      /* popf / jb */
      if (!saved) {
	BIT;
	if(!bits) {
	  BIT;
	  bits+=5;
	} else {
	  BITS(3);
	  if(bits) {
	    bits+=6;
	  } else {
	    BITS(4);
	    if(bits) {
	      bits+=13;
	    } else {
	      uint8_t cnt = 4;
	      uint16_t shifted = 0x0d;
	      
	      do {
		if(cnt==7) { cnt = 0x0e; shifted = 0; break; }
		shifted=((shifted+2)<<1)-1;
		BIT;
		cnt++;
	      } while(!bits);
	      BITS(cnt);
	      bits+=shifted;
	    }
	  }
	}
	backsize = bits;
      } else {
	backsize = saved+2;
      }

      if(!CLI_ISCONTAINED(exe, exesz, ucur, backsize) || !CLI_ISCONTAINED(exe, exesz, ucur-backbytes, backsize)) error=1;
      else while(backsize--) {
	*ucur=*(ucur-backbytes);
	ucur++;
      }
    }
    free(compd);
    if(error) {
      cli_dbgmsg("WWPack: decompression error\n");
      break;
    }
    if (error || !*structs++) break;
  }

  if(!error) {
    exe[pe+6]=(uint8_t)scount;
    exe[pe+7]=(uint8_t)(scount>>8);
    cli_writeint32(&exe[pe+0x28], cli_readint32(wwsect+0x295)+sects[scount].rva+0x299);
    cli_writeint32(&exe[pe+0x50], cli_readint32(&exe[pe+0x50])-sects[scount].vsz);

    structs = &exe[(0xffff&cli_readint32(&exe[pe+0x14]))+pe+0x18];
    for(i=0 ; i<scount ; i++) {
	  if (!CLI_ISCONTAINED(exe, exesz, structs, 0x28)) {
	    cli_dbgmsg("WWPack: structs pointer out of bounds\n");
	    return CL_EFORMAT;
	  }

      cli_writeint32(structs+8, sects[i].vsz);
      cli_writeint32(structs+12, sects[i].rva);
      cli_writeint32(structs+16, sects[i].vsz);
      cli_writeint32(structs+20, sects[i].rva);
      structs+=0x28;
    }
	if (!CLI_ISCONTAINED(exe, exesz, structs, 0x28)) {
	  cli_dbgmsg("WWPack: structs pointer out of bounds\n");
	  return CL_EFORMAT;
	}

    memset(structs, 0, 0x28);
    error = (uint32_t)cli_writen(desc, exe, exesz)!=exesz;
  }
Пример #27
0
Файл: yc.c Проект: OPSF/uClinux
int yc_decrypt(char *fbuf, unsigned int filesize, struct cli_exe_section *sections, unsigned int sectcount, uint32_t peoffset, int desc)
{
  uint32_t ycsect = sections[sectcount].raw;
  unsigned int i;
  struct pe_image_file_hdr *pe = (struct pe_image_file_hdr*) (fbuf + peoffset);
  char *sname = (char *)pe + EC16(pe->SizeOfOptionalHeader) + 0x18;

  /* 

  First layer (decryptor of the section decryptor) in last section 

  Start offset for analyze: Start of yC Section + 0x93
  End offset for analyze: Start of yC Section + 0xC3
  Lenght to decrypt - ECX = 0xB97

  */
  cli_dbgmsg("yC: decrypting decryptor on sect %d\n", sectcount); 
  if (yc_poly_emulator(fbuf + ycsect + 0x93, fbuf + ycsect + 0xc6 ,0xB97))
    return 1;
  filesize-=sections[sectcount].ursz;

  /* 

  Second layer (decryptor of the sections) in last section 

  Start offset for analyze: Start of yC Section + 0x457
  End offset for analyze: Start of yC Section + 0x487
  Lenght to decrypt - ECX = Raw Size of Section

  */


  /* Loop through all sections and decrypt them... */
  for(i=0;i<sectcount;i++)
    {
      uint32_t name = (uint32_t) cli_readint32(sname+i*0x28);
      if ( !sections[i].raw ||
	   !sections[i].rsz ||
	   name == 0x63727372 || /* rsrc */
	   name == 0x7273722E || /* .rsr */
	   name == 0x6F6C6572 || /* relo */
	   name == 0x6C65722E || /* .rel */
	   name == 0x6164652E || /* .eda */
	   name == 0x6164722E || /* .rda */
	   name == 0x6164692E || /* .ida */
	   name == 0x736C742E || /* .tls */
	   (name&0xffff) == 0x4379  /* yC */
	) continue;
      cli_dbgmsg("yC: decrypting sect%d\n",i); 
      if (yc_poly_emulator(fbuf + ycsect + 0x457, fbuf + sections[i].raw, sections[i].ursz))
	return 1;
    }

  /* Remove yC section */
  pe->NumberOfSections=EC16(sectcount);

  /* Remove IMPORT_DIRECTORY information */
  memset((char *)pe + sizeof(struct pe_image_file_hdr) + 0x68, 0, 8);

  /* OEP resolving */
  /* OEP = DWORD PTR [ Start of yC section+ A0F] */
  cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 16, cli_readint32(fbuf + ycsect + 0xa0f));

  /* Fix SizeOfImage */
  cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38, cli_readint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38) - sections[sectcount].vsz);

  if (cli_writen(desc, fbuf, filesize)==-1) {
    cli_dbgmsg("yC: Cannot write unpacked file\n");
    return 1;
  }
  return 0;
}
Пример #28
0
/* Stripe handling: ADC block (type 0x80000004) */
static int dmg_stripe_adc(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mish_with_stripes *mish_set)
{
    int ret = CL_CLEAN, adcret;
    adc_stream strm;
    size_t off = mish_set->stripes[index].dataOffset;
    size_t len = mish_set->stripes[index].dataLength;
    uint64_t size_so_far = 0;
    uint64_t expected_len = mish_set->stripes[index].sectorCount * DMG_SECTOR_SIZE;
    uint8_t obuf[BUFSIZ];

    cli_dbgmsg("dmg_stripe_adc: stripe " STDu32 " initial len " STDu64 " expected len " STDu64 "\n",
            index, (uint64_t)len, (uint64_t)expected_len);
    if (len == 0)
        return CL_CLEAN;

    memset(&strm, 0, sizeof(strm));
    strm.next_in = (uint8_t *)fmap_need_off_once(*ctx->fmap, off, len);
    if (!strm.next_in) {
        cli_warnmsg("dmg_stripe_adc: fmap need failed on stripe " STDu32 "\n", index);
        return CL_EMAP;
    }
    strm.avail_in = len;
    strm.next_out = obuf;
    strm.avail_out = sizeof(obuf);

    adcret = adc_decompressInit(&strm);
    if(adcret != ADC_OK) {
        cli_warnmsg("dmg_stripe_adc: adc_decompressInit failed\n");
        return CL_EMEM;
    }

    while(adcret == ADC_OK) {
        int written;
        if (size_so_far > expected_len) {
            cli_warnmsg("dmg_stripe_adc: expected size exceeded!\n");
            adc_decompressEnd(&strm);
            return CL_EFORMAT;
        }
        adcret = adc_decompress(&strm);
        switch(adcret) {
            case ADC_OK:
                if(strm.avail_out == 0) {
                    if ((written=cli_writen(fd, obuf, sizeof(obuf)))!=sizeof(obuf)) {
                        cli_errmsg("dmg_stripe_adc: failed write to output file\n");
                        adc_decompressEnd(&strm);
                        return CL_EWRITE;
                    }
                    size_so_far += written;
                    strm.next_out = obuf;
                    strm.avail_out = sizeof(obuf);
                }
                continue;
            case ADC_STREAM_END:
            default:
                written = sizeof(obuf) - strm.avail_out;
                if (written) {
                    if ((cli_writen(fd, obuf, written))!=written) {
                        cli_errmsg("dmg_stripe_adc: failed write to output file\n");
                        adc_decompressEnd(&strm);
                        return CL_EWRITE;
                    }
                    size_so_far += written;
                    strm.next_out = obuf;
                    strm.avail_out = sizeof(obuf);
                }
                if (adcret == ADC_STREAM_END)
                    break;
                cli_dbgmsg("dmg_stripe_adc: after writing " STDu64 " bytes, "
                           "got error %d decompressing stripe " STDu32 "\n",
                           size_so_far, adcret, index);
                adc_decompressEnd(&strm);
                return CL_EFORMAT;
        }
        break;
    }

    adc_decompressEnd(&strm);
    cli_dbgmsg("dmg_stripe_adc: stripe " STDu32 " actual len " STDu64 " expected len " STDu64 "\n",
            index, size_so_far, expected_len);
    return CL_CLEAN;
}