denyhosts/clamav/libclamav/wwunpack.c

269 lines
9.2 KiB
C

/*
* Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2007-2013 Sourcefire, Inc.
*
* Authors: Alberto Wu
*
* 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 HAVE_CONFIG_H
#include "clamav-config.h"
#endif
#include "clamav.h"
#include "others.h"
#include "execs.h"
#include "wwunpack.h"
#if HAVE_STRING_H
#include <string.h>
#endif
#define RESEED \
if (CLI_ISCONTAINED(compd, szd, ccur, 4)) { \
bt = cli_readint32(ccur); \
ccur += 4; \
} else { \
cli_dbgmsg("WWPack: Out of bits\n"); \
error = 1; \
} \
bc = 32;
#define BIT \
bits = bt >> 31; \
bt <<= 1; \
if (!--bc) { \
RESEED; \
}
#define BITS(N) \
bits = bt >> (32 - (N)); \
if (bc >= (N)) { \
bc -= (N); \
bt <<= (N); \
if (!bc) { \
RESEED; \
} \
} else { \
if (CLI_ISCONTAINED(compd, szd, ccur, 4)) { \
bt = cli_readint32(ccur); \
ccur += 4; \
bc += 32 - (N); \
bits |= bt >> (bc); \
bt <<= (32 - bc); \
} else { \
cli_dbgmsg("WWPack: Out of bits\n"); \
error = 1; \
} \
}
cl_error_t 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;
cl_error_t error = 0;
uint16_t 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 (CL_SUCCESS == 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 (CL_SUCCESS == error) {
if (pe + 6 > exesz || pe + 7 > exesz || pe + 0x28 > exesz ||
pe + 0x50 > exesz || pe + 0x14 > exesz)
return CL_EFORMAT;
exe[pe + 6] = (uint8_t)scount;
exe[pe + 7] = (uint8_t)(scount >> 8);
if (!CLI_ISCONTAINED(wwsect, sects[scount].rsz, wwsect + 0x295, 4))
cli_dbgmsg("WWPack: unpack memory address out of bounds.\n");
else
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);
if (cli_writen(desc, exe, exesz) != (size_t)exesz) {
error = CL_EWRITE;
}
}
return error;
}