0e605501 |
/* |
c442ca9c |
* Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2011-2013 Sourcefire, Inc. |
0e605501 |
*
* 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.
*/
|
c7ad4bea |
#if defined(_WIN32)
#include <WinSock2.h>
#include <Windows.h>
#endif |
0e605501 |
|
60d8d2c3 |
#include "clamav.h" |
0e605501 |
#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;
int read_sz;
if (*size == 0)
return 0;
read_sz = fmap_readn(p->file.fmap, buf, p->s.curpos, *size); |
afa9976c |
if(read_sz < 0) {
*size = 0; |
0e605501 |
return SZ_ERROR_READ; |
afa9976c |
} |
0e605501 |
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 |
9a47aa20 |
int cli_7unz (cli_ctx *ctx, size_t offset) { |
0e605501 |
CFileInStream archiveStream;
CLookToRead lookStream;
CSzArEx db;
SRes res;
UInt16 utf16buf[UTFBUFSZ], *utf16name = utf16buf;
int namelen = UTFBUFSZ, found = CL_CLEAN; |
9a47aa20 |
Int64 begin_of_archive = offset; |
6ad45a29 |
UInt32 viruses_found = 0; |
0e605501 |
/* 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);
|
9a47aa20 |
if(archiveStream.s.Seek(&archiveStream.s, &begin_of_archive, SZ_SEEK_SET) != 0)
return CL_CLEAN;
|
0e605501 |
lookStream.realStream = &archiveStream.s;
LookToRead_Init(&lookStream);
SzArEx_Init(&db);
res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp); |
f61e92da |
if(res == SZ_ERROR_ENCRYPTED && SCAN_HEURISTIC_ENCRYPTED_ARCHIVE) { |
03526dcc |
cli_dbgmsg("cli_7unz: Encrypted header found in archive.\n"); |
cbf5017a |
found = cli_append_virus(ctx, "Heuristics.Encrypted.7Zip"); |
03526dcc |
} else if(res == SZ_OK) { |
0e605501 |
UInt32 i, blockIndex = 0xFFFFFFFF;
Byte *outBuffer = 0;
size_t outBufferSize = 0; |
61fafd18 |
unsigned int encrypted = 0; |
0e605501 |
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;
|
afa9976c |
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; |
0e605501 |
} |
afa9976c |
SzArEx_GetFileNameUtf16(&db, i, utf16name); |
0e605501 |
} |
afa9976c |
|
0e605501 |
name = (char *)utf16name; |
cd94be7a |
for(j=0; j<(size_t)newnamelen; j++) /* FIXME */ |
0e605501 |
name[j] = utf16name[j]; |
afa9976c |
name[j] = 0; |
0e605501 |
cli_dbgmsg("cli_7unz: extracting %s\n", name); |
61fafd18 |
res = SzArEx_Extract(&db, &lookStream.s, i, &blockIndex, &outBuffer, &outBufferSize, &offset, &outSizeProcessed, &allocImp, &allocTempImp);
if(res == SZ_ERROR_ENCRYPTED) {
encrypted = 1; |
f61e92da |
if(SCAN_HEURISTIC_ENCRYPTED_ARCHIVE) { |
61fafd18 |
cli_dbgmsg("cli_7unz: Encrypted files found in archive.\n"); |
cbf5017a |
found = cli_append_virus(ctx, "Heuristics.Encrypted.7Zip");
if (found != CL_CLEAN) {
if (found == CL_VIRUS) { |
d7979d4f |
if (SCAN_ALLMATCHES) |
cbf5017a |
viruses_found++;
} else
break; |
6ad45a29 |
} |
61fafd18 |
}
}
if(cli_matchmeta(ctx, name, 0, f->Size, encrypted, i, f->CrcDefined ? f->Crc : 0, NULL)) { |
0e605501 |
found = CL_VIRUS; |
6ad45a29 |
viruses_found++; |
d7979d4f |
if (!SCAN_ALLMATCHES) |
6ad45a29 |
break; |
0e605501 |
}
if (res != SZ_OK) |
61fafd18 |
cli_dbgmsg("cli_unz: extraction failed with %d\n", res); |
0e605501 |
else { |
054ae9a1 |
if((found = cli_gentempfd(ctx->engine->tmpdir, &name, &fd))) |
0e605501 |
break;
cli_dbgmsg("cli_7unz: Saving to %s\n", name); |
cd94be7a |
if((size_t)cli_writen(fd, outBuffer + offset, outSizeProcessed) != outSizeProcessed) |
0e605501 |
found = CL_EWRITE;
else |
d39cb658 |
if ((found = cli_magic_scandesc(fd, name, ctx)) == CL_VIRUS) |
6ad45a29 |
viruses_found++; |
0e605501 |
close(fd);
if(!ctx->engine->keeptmp && cli_unlink(name))
found = CL_EUNLINK;
free(name);
if(found != CL_CLEAN) |
d7979d4f |
if (!(SCAN_ALLMATCHES && found == CL_VIRUS)) |
6ad45a29 |
break; |
0e605501 |
}
}
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"); |
03526dcc |
else if (res == SZ_ERROR_ENCRYPTED)
cli_dbgmsg("cli_7unz: encrypted\n"); |
0e605501 |
else
cli_dbgmsg("cli_7unz: error %d\n", res);
|
d7979d4f |
if (SCAN_ALLMATCHES && viruses_found) |
6ad45a29 |
return CL_VIRUS; |
0e605501 |
return found;
} |