223 lines
7.2 KiB
C
223 lines
7.2 KiB
C
/*
|
|
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
|
* Copyright (C) 2011-2013 Sourcefire, Inc.
|
|
*
|
|
* Authors: aCaB
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
* MA 02110-1301, USA.
|
|
*/
|
|
|
|
#if defined(_WIN32)
|
|
#include <WinSock2.h>
|
|
#include <Windows.h>
|
|
#endif
|
|
|
|
#include "clamav.h"
|
|
#include "7z_iface.h"
|
|
#include "lzma_iface.h"
|
|
#include "scanners.h"
|
|
#include "others.h"
|
|
#include "fmap.h"
|
|
|
|
#include "7z/7z.h"
|
|
#include "7z/7zAlloc.h"
|
|
#include "7z/7zFile.h"
|
|
|
|
static ISzAlloc allocImp = {__lzma_wrap_alloc, __lzma_wrap_free}, allocTempImp = {__lzma_wrap_alloc, __lzma_wrap_free};
|
|
|
|
static SRes FileInStream_fmap_Read(void *pp, void *buf, size_t *size)
|
|
{
|
|
CFileInStream *p = (CFileInStream *)pp;
|
|
size_t read_sz;
|
|
|
|
if (*size == 0)
|
|
return 0;
|
|
|
|
read_sz = fmap_readn(p->file.fmap, buf, p->s.curpos, *size);
|
|
if (read_sz == (size_t)-1) {
|
|
*size = 0;
|
|
return SZ_ERROR_READ;
|
|
}
|
|
|
|
p->s.curpos += read_sz;
|
|
|
|
*size = read_sz;
|
|
return SZ_OK;
|
|
}
|
|
|
|
static SRes FileInStream_fmap_Seek(void *pp, Int64 *pos, ESzSeek origin)
|
|
{
|
|
CFileInStream *p = (CFileInStream *)pp;
|
|
|
|
switch (origin) {
|
|
case SZ_SEEK_SET:
|
|
p->s.curpos = *pos;
|
|
break;
|
|
case SZ_SEEK_CUR:
|
|
p->s.curpos += *pos;
|
|
*pos = p->s.curpos;
|
|
break;
|
|
case SZ_SEEK_END:
|
|
p->s.curpos = p->file.fmap->len + *pos;
|
|
*pos = p->s.curpos;
|
|
break;
|
|
default:
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#define UTFBUFSZ 256
|
|
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;
|
|
cl_error_t found = CL_CLEAN;
|
|
Int64 begin_of_archive = offset;
|
|
|
|
/* 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_ERROR_ENCRYPTED && SCAN_HEURISTIC_ENCRYPTED_ARCHIVE) {
|
|
cli_dbgmsg("cli_7unz: Encrypted header found in archive.\n");
|
|
found = cli_append_potentially_unwanted(ctx, "Heuristics.Encrypted.7Zip");
|
|
} else 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;
|
|
char *tmp_name;
|
|
size_t j;
|
|
int newnamelen, fd;
|
|
|
|
// abort if we would exceed max files or max scan time.
|
|
if ((found = cli_checklimits("7unz", ctx, 0, 0, 0)))
|
|
break;
|
|
|
|
if (f->IsDir)
|
|
continue;
|
|
|
|
// skip this file if we would exceed max file size or max scan size. (we already checked for the max files and max scan time)
|
|
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 (SCAN_HEURISTIC_ENCRYPTED_ARCHIVE) {
|
|
cli_dbgmsg("cli_7unz: Encrypted files found in archive.\n");
|
|
found = cli_append_potentially_unwanted(ctx, "Heuristics.Encrypted.7Zip");
|
|
if (found != CL_SUCCESS) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (CL_VIRUS == cli_matchmeta(ctx, name, 0, f->Size, encrypted, i, f->CrcDefined ? f->Crc : 0, NULL)) {
|
|
found = CL_VIRUS;
|
|
break;
|
|
}
|
|
if (res != SZ_OK)
|
|
cli_dbgmsg("cli_unz: extraction failed with %d\n", res);
|
|
else if ((outBuffer == NULL) || (outSizeProcessed == 0)) {
|
|
cli_dbgmsg("cli_unz: extracted empty file\n");
|
|
} else {
|
|
if ((found = cli_gentempfd(ctx->sub_tmpdir, &tmp_name, &fd)))
|
|
break;
|
|
|
|
cli_dbgmsg("cli_7unz: Saving to %s\n", tmp_name);
|
|
if (cli_writen(fd, outBuffer + offset, outSizeProcessed) != outSizeProcessed) {
|
|
found = CL_EWRITE;
|
|
}
|
|
|
|
found = cli_magic_scan_desc(fd, tmp_name, ctx, name, LAYER_ATTRIBUTES_NONE);
|
|
|
|
close(fd);
|
|
if (!ctx->engine->keeptmp && cli_unlink(tmp_name))
|
|
found = CL_EUNLINK;
|
|
|
|
free(tmp_name);
|
|
if (found != CL_SUCCESS)
|
|
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 if (res == SZ_ERROR_ENCRYPTED)
|
|
cli_dbgmsg("cli_7unz: encrypted\n");
|
|
else
|
|
cli_dbgmsg("cli_7unz: error %d\n", res);
|
|
|
|
return found;
|
|
}
|