mirror of https://github.com/Cisco-Talos/clamav
parent
bc978636ac
commit
f8be651b43
@ -0,0 +1,315 @@ |
||||
/*
|
||||
* Copyright (C) 2007 Sourcefire Inc. |
||||
* Author: aCaB <acab@clamav.net> |
||||
* |
||||
* 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. |
||||
*/ |
||||
|
||||
/*
|
||||
* Written from scratch based on specs from PKWARE: |
||||
* see www.pkware.com/documents/casestudies/APPNOTE.TXT |
||||
* |
||||
* To the best of my knowledge, it's patent free: |
||||
* http://www.unisys.com/about__unisys/lzw
|
||||
*/ |
||||
|
||||
|
||||
/* To Cami and Dario, the only laywers I can stand */ |
||||
|
||||
|
||||
#if HAVE_CONFIG_H |
||||
#include "clamav-config.h" |
||||
#endif |
||||
|
||||
#if HAVE_STRING_H |
||||
#include <string.h> |
||||
#endif |
||||
|
||||
#include "explode.h" |
||||
|
||||
/* NOTE: sorting algo must be stable! */ |
||||
static void bs(uint8_t *k, uint8_t *v, unsigned int elements) { |
||||
uint8_t tmp; |
||||
unsigned int i=0, l=0, stop=0, r=elements; |
||||
|
||||
while(!stop) { |
||||
stop=1; |
||||
for(; i<r; i++) { |
||||
if(v[k[i]]>v[k[i+1]]) { |
||||
tmp=k[i]; |
||||
k[i]=k[i+1]; |
||||
k[i+1]=tmp; |
||||
stop=0; |
||||
} |
||||
} |
||||
if(stop) break; |
||||
r--; |
||||
i--; |
||||
for(; i>l; i--) { |
||||
if(v[k[i]]<v[k[i-1]]) { |
||||
tmp=k[i]; |
||||
k[i]=k[i-1]; |
||||
k[i-1]=tmp; |
||||
stop=0; |
||||
} |
||||
} |
||||
l++; |
||||
i++; |
||||
} |
||||
} |
||||
|
||||
|
||||
static int unpack_tree(struct xplstate *X, uint32_t *tree, unsigned int expected) { |
||||
uint8_t temptree[256], order[256], *ttree=temptree; |
||||
uint8_t *cur=X->window; |
||||
uint8_t packsz; |
||||
unsigned int i; |
||||
uint16_t code=0, codeinc=0, lastlen=0; |
||||
|
||||
packsz=*cur++; |
||||
|
||||
for(i=0; i<expected; i++) order[i]=i; |
||||
|
||||
i=expected; |
||||
|
||||
do { |
||||
uint8_t values, len; |
||||
values = *cur++; |
||||
len = (values&15) + 1; |
||||
values = (values>>4) + 1; |
||||
if(values>i) return 1; |
||||
i-=values; |
||||
while(values--) |
||||
*ttree++ = len; |
||||
} while(packsz--); |
||||
|
||||
if(i) return 1; |
||||
|
||||
bs(order, temptree, expected-1); |
||||
|
||||
i=expected-1; |
||||
do { |
||||
code=code+codeinc; |
||||
if(temptree[order[i]]!=lastlen) { |
||||
lastlen=temptree[order[i]]; |
||||
codeinc=1<<(16-lastlen); |
||||
} |
||||
tree[order[i]]=code | ((uint32_t)lastlen<<16); |
||||
} while(i--); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/* bit lame of a lookup, but prolly not worth optimizing */ |
||||
static int lookup_tree(uint32_t *tree, unsigned int size, uint16_t code, uint8_t len) { |
||||
uint32_t lookup=((uint32_t)(len+1))<<16 | code; |
||||
unsigned int i; |
||||
for(i=0; i<size; i++) |
||||
if(tree[i]==lookup) return i; |
||||
return -1; |
||||
} |
||||
|
||||
int explode_init(struct xplstate *X, uint8_t flags) { |
||||
X->bits = X->cur = 0; |
||||
if(flags&2) { |
||||
X->largewin = 1; |
||||
X->mask = 0x1fff; |
||||
} else { |
||||
X->largewin = 0; |
||||
X->mask = 0xfff; |
||||
} |
||||
if(flags&4) { |
||||
X->state = GRABLITS; |
||||
X->litcodes = 1; |
||||
X->minlen=3; |
||||
} else { |
||||
X->state = GRABLENS; |
||||
X->litcodes = 0; |
||||
X->minlen=2; |
||||
} |
||||
X->got=0; |
||||
return EXPLODE_OK; |
||||
} |
||||
|
||||
#define GETBIT \ |
||||
if(X->bits) { \
|
||||
X->bits--; \
|
||||
val=X->bitmap&1; \
|
||||
X->bitmap>>=1; \
|
||||
} else { \
|
||||
if(!X->avail_in) return EXPLODE_EBUFF; \
|
||||
if(X->avail_in>=4) { \
|
||||
X->bitmap=*(uint32_t *)X->next_in; \
|
||||
X->bits=31; \
|
||||
X->next_in+=4; \
|
||||
X->avail_in-=4; \
|
||||
} else { \
|
||||
X->bitmap=*X->next_in; \
|
||||
X->bits=7; \
|
||||
X->next_in++; \
|
||||
X->avail_in--; \
|
||||
} \
|
||||
val=X->bitmap&1; \
|
||||
X->bitmap>>=1; \
|
||||
} |
||||
|
||||
|
||||
#define GETBITS(NUM) \ |
||||
if(X->bits>=(NUM)) { \
|
||||
val=X->bitmap&((1<<(NUM))-1); \
|
||||
X->bitmap>>=(NUM); \
|
||||
X->bits-=(NUM); \
|
||||
} else { \
|
||||
if(X->avail_in*8+X->bits<(NUM)) return EXPLODE_EBUFF; \
|
||||
val=X->bitmap; \
|
||||
if(X->avail_in>=4) { \
|
||||
X->bitmap=*(uint32_t *)X->next_in; \
|
||||
X->next_in+=4; \
|
||||
X->avail_in-=4; \
|
||||
val|=(X->bitmap&((1<<((NUM)-X->bits))-1))<<X->bits; \
|
||||
X->bitmap>>=(NUM)-X->bits; \
|
||||
X->bits=32-((NUM)-X->bits); \
|
||||
} else { \
|
||||
X->bitmap=*X->next_in; \
|
||||
X->next_in++; \
|
||||
X->avail_in--; \
|
||||
val|=(X->bitmap&((1<<((NUM)-X->bits))-1))<<X->bits; \
|
||||
X->bitmap>>=(NUM)-X->bits; \
|
||||
X->bits=8-((NUM)-X->bits); \
|
||||
} \
|
||||
} |
||||
|
||||
|
||||
#define GETCODES(CASE, WHICH, HOWMANY) \ |
||||
case CASE: { \
|
||||
if(!X->avail_in) return EXPLODE_EBUFF; \
|
||||
if(!X->got) need = *X->next_in; \
|
||||
else need = X->window[0]; \
|
||||
if(need > HOWMANY - 1) return EXPLODE_ESTREAM; /* too many codes */ \
|
||||
need = need + 2 - X->got; /* bytes remaining */ \
|
||||
if(need>X->avail_in) { /* if not enuff */ \
|
||||
/* just copy what's avail... */ \
|
||||
memcpy(&X->window[X->got], X->next_in, X->avail_in); \
|
||||
X->got += X->avail_in; \
|
||||
X->next_in += X->avail_in; \
|
||||
X->avail_in = 0; \
|
||||
return EXPLODE_EBUFF; /* ...and beg for more */ \
|
||||
} \
|
||||
/* else fetch what's needed */ \
|
||||
memcpy(&X->window[X->got], X->next_in, need); \
|
||||
X->avail_in -= need; \
|
||||
X->next_in += need; \
|
||||
if(unpack_tree(X, X->WHICH, HOWMANY )) return EXPLODE_ESTREAM; \
|
||||
/* and move on */ \
|
||||
X->got=0; \
|
||||
X->state++; \
|
||||
} |
||||
|
||||
#define SETCASE(CASE) \ |
||||
X->state = (CASE); \
|
||||
case(CASE): \
|
||||
{/* FAKE */} |
||||
|
||||
int explode(struct xplstate *X) { |
||||
unsigned int val, need; |
||||
int temp; |
||||
|
||||
switch(X->state) { |
||||
/* grab compressed coded literals, if present */ |
||||
GETCODES(GRABLITS, lit_tree, 256); |
||||
/* grab compressed coded lens */ |
||||
GETCODES(GRABLENS, len_tree, 64); |
||||
/* grab compressed coded dists */ |
||||
GETCODES(GRABDISTS, dist_tree, 64); |
||||
|
||||
case EXPLODE: |
||||
while(X->avail_in || X->bits) { |
||||
GETBIT; /* can't fail */ |
||||
if(val) { |
||||
if(X->litcodes) { |
||||
X->backsize=0; |
||||
X->state=EXPLODE_LITCODES; |
||||
for(X->got=0; X->got<=15; X->got++) { |
||||
case EXPLODE_LITCODES: |
||||
GETBIT; |
||||
X->backsize|=val<<(15-X->got); |
||||
if((temp=lookup_tree(X->lit_tree, 256, X->backsize, X->got))!=-1) break; |
||||
} |
||||
if(temp==-1) return EXPLODE_ESTREAM; |
||||
X->got=temp; |
||||
} else { |
||||
SETCASE(EXPLODE_LITS); |
||||
GETBITS(8); |
||||
X->got=val; |
||||
} |
||||
SETCASE(EXPLODE_WBYTE); |
||||
if(!X->avail_out) return EXPLODE_EBUFF; |
||||
X->avail_out--; |
||||
*X->next_out = X->window[X->cur & X->mask] = X->got; |
||||
X->cur++; |
||||
X->next_out++; |
||||
} else { |
||||
SETCASE(EXPLODE_BASEDIST); |
||||
GETBITS(6+X->largewin); |
||||
X->backbytes=val; |
||||
X->backsize=0; |
||||
X->state=EXPLODE_DECODEDISTS; |
||||
for(X->got=0; X->got<=15; X->got++) { |
||||
case EXPLODE_DECODEDISTS: |
||||
GETBIT; |
||||
X->backsize|=val<<(15-X->got); |
||||
if((temp=lookup_tree(X->dist_tree, 64, X->backsize, X->got))!=-1) break; |
||||
} |
||||
if(temp==-1) return EXPLODE_ESTREAM; |
||||
X->backbytes|=temp<<(6+X->largewin); |
||||
X->backbytes++; |
||||
X->backsize=0; |
||||
X->state=EXPLODE_DECODELENS; |
||||
for(X->got=0; X->got<=15; X->got++) { |
||||
case EXPLODE_DECODELENS: |
||||
GETBIT; |
||||
X->backsize|=val<<(15-X->got); |
||||
if((temp=lookup_tree(X->len_tree, 64, X->backsize, X->got))!=-1) break; |
||||
} |
||||
if(temp==-1) { |
||||
cli_dbgmsg("HERE3\n"); |
||||
return EXPLODE_ESTREAM; |
||||
} |
||||
if(temp==63) { |
||||
SETCASE(EXPLODE_DECODEEXTRA); |
||||
GETBITS(8); |
||||
temp=63+val; |
||||
} |
||||
X->backsize=temp+X->minlen; |
||||
X->state=EXPLODE_BACKCOPY; |
||||
while(X->backsize--) { |
||||
case EXPLODE_BACKCOPY: |
||||
if(!X->avail_out) return EXPLODE_EBUFF; |
||||
X->avail_out--; |
||||
if (X->cur>=X->backbytes) |
||||
*X->next_out = X->window[X->cur & X->mask] = X->window[(X->cur-X->backbytes) & X->mask]; |
||||
else |
||||
*X->next_out = X->window[X->cur & X->mask] = 0; |
||||
X->cur++; |
||||
X->next_out++; |
||||
} |
||||
} |
||||
X->state=EXPLODE; |
||||
} |
||||
} |
||||
return EXPLODE_EBUFF; |
||||
} |
||||
|
||||
void explode_shutdown() {}; |
@ -0,0 +1,73 @@ |
||||
/*
|
||||
* Copyright (C) 2007 Sourcefire Inc. |
||||
* Author: aCaB <acab@clamav.net> |
||||
* |
||||
* 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. |
||||
*/ |
||||
|
||||
#ifndef __EXPLODE_H |
||||
#define __EXPLODE_H |
||||
|
||||
#include "cltypes.h" |
||||
|
||||
enum { |
||||
EXPLODE_EBUFF, |
||||
EXPLODE_ESTREAM |
||||
}; |
||||
|
||||
#define EXPLODE_OK EXPLODE_EBUFF |
||||
|
||||
enum XPL_STATE { |
||||
GRABLITS, |
||||
GRABLENS, |
||||
GRABDISTS, |
||||
EXPLODE, |
||||
EXPLODE_LITCODES, |
||||
EXPLODE_LITS, |
||||
EXPLODE_BASEDIST, |
||||
EXPLODE_DECODEDISTS, |
||||
EXPLODE_DECODELENS, |
||||
EXPLODE_DECODEEXTRA, |
||||
EXPLODE_WBYTE, |
||||
EXPLODE_BACKCOPY |
||||
}; |
||||
|
||||
struct xplstate { |
||||
uint8_t *next_in; |
||||
uint8_t *next_out; |
||||
unsigned int got; |
||||
unsigned int minlen; |
||||
unsigned int mask; |
||||
unsigned int cur; |
||||
uint32_t lit_tree[256]; |
||||
uint32_t len_tree[64]; |
||||
uint32_t dist_tree[64]; |
||||
uint32_t bitmap; |
||||
uint32_t avail_in; |
||||
uint32_t avail_out; |
||||
uint16_t backbytes; |
||||
uint16_t backsize; |
||||
uint8_t window[8192]; |
||||
uint8_t bits; |
||||
uint8_t largewin; |
||||
uint8_t litcodes; |
||||
enum XPL_STATE state; |
||||
}; |
||||
|
||||
int explode_init(struct xplstate *, uint8_t); |
||||
int explode(struct xplstate *); |
||||
void explode_shutdown(); |
||||
|
||||
#endif /* __EXPLODE_H */ |
Loading…
Reference in new issue