~ubuntu-branches/ubuntu/feisty/clamav/feisty

« back to all changes in this revision

Viewing changes to libclamav/wwunpack.c

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2007-02-20 10:33:44 UTC
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: james.westby@ubuntu.com-20070220103344-zgcu2psnx9d98fpa
Tags: upstream-0.90
ImportĀ upstreamĀ versionĀ 0.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 *  Copyright (C) 2007-2008 Sourcefire, Inc.
3
 
 *
4
 
 *  Authors: Alberto Wu
 
2
 *  Copyright (C) 2006 aCaB <acab@clamav.net>
5
3
 *
6
4
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License version 2 as
8
 
 *  published by the Free Software Foundation.
 
5
 *  it under the terms of the GNU General Public License as published by
 
6
 *  the Free Software Foundation; either version 2 of the License, or
 
7
 *  (at your option) any later version.
9
8
 *
10
9
 *  This program is distributed in the hope that it will be useful,
11
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18
17
 *  MA 02110-1301, USA.
19
18
 */
20
19
 
 
20
/*
 
21
** wwunpack.c
 
22
**
 
23
** 09/07/2k6 - Campioni del mondo!!!
 
24
** 14/07/2k6 - RCE'ed + standalone sect unpacker
 
25
** 15/07/2k6 - Merge started
 
26
** 17/07/2k6 - Rebuild
 
27
** 18/07/2k6 - Secured (well, hopefully...)
 
28
**
 
29
*/
 
30
 
 
31
/*
 
32
** Unpacks+rebuilds WWPack32 1.20
 
33
**
 
34
** Just boooooring stuff, blah.
 
35
**
 
36
*/
 
37
 
 
38
 
 
39
/*
 
40
** TODO:
 
41
**
 
42
** review
 
43
** check eax vs al
 
44
** (check for dll's)
 
45
** (have a look at older versions)
 
46
**
 
47
*/
 
48
 
 
49
 
21
50
#if HAVE_CONFIG_H
22
51
#include "clamav-config.h"
23
52
#endif
24
53
 
 
54
#include <stdlib.h>
 
55
#include <string.h>
 
56
 
25
57
#include "cltypes.h"
26
58
#include "others.h"
27
 
#include "execs.h"
28
59
#include "wwunpack.h"
29
60
 
30
 
#if HAVE_STRING_H
31
 
#include <string.h>
32
 
#endif
33
 
 
34
 
#define RESEED \
35
 
if (CLI_ISCONTAINED(compd, szd, ccur, 4)) { \
36
 
  bt = cli_readint32(ccur); \
37
 
  ccur+=4; \
38
 
} else { \
39
 
  cli_dbgmsg("WWPack: Out of bits\n"); \
40
 
  error=1; \
41
 
} \
42
 
bc = 32;
43
 
 
44
 
 
45
 
#define BIT \
46
 
bits = bt>>31; \
47
 
bt<<=1; \
48
 
if(!--bc) { \
49
 
  RESEED; \
50
 
}
51
 
 
52
 
#define BITS(N) \
53
 
bits = bt>>(32-(N)); \
54
 
if (bc>=(N)) { \
55
 
  bc -= (N); \
56
 
  bt<<=(N); \
57
 
  if (!bc) { \
58
 
    RESEED; \
59
 
  } \
60
 
} else { \
61
 
  if (CLI_ISCONTAINED(compd, szd, ccur, 4)) { \
62
 
    bt = cli_readint32(ccur); \
63
 
    ccur+=4; \
64
 
    bc += 32 - (N); \
65
 
    bits |= bt>>(bc); \
66
 
    bt <<= (32-bc); \
67
 
  } else { \
68
 
    cli_dbgmsg("WWPack: Out of bits\n"); \
69
 
    error=1; \
70
 
  } \
71
 
}
72
 
 
73
 
int wwunpack(uint8_t *exe, uint32_t exesz, uint8_t *wwsect, struct cli_exe_section *sects, uint16_t scount, uint32_t pe, int desc) {
74
 
  uint8_t *structs = wwsect + 0x2a1, *compd, *ccur, *unpd, *ucur, bc;
75
 
  uint32_t src, srcend, szd, bt, bits;
76
 
  int error=0, i;
77
 
 
78
 
  cli_dbgmsg("in wwunpack\n");
 
61
#define VAALIGN(s) (((s)/0x1000+((s)%0x1000!=0))*0x1000)
 
62
#define FIXVS(v, r) (VAALIGN((r>v)?r:v))
 
63
 
 
64
 
 
65
static int getbitmap(uint32_t *bitmap, char **src, uint8_t *bits, char *buf, unsigned int size) {
 
66
  if (! CLI_ISCONTAINED(buf, size, *src, 4)) return 1;
 
67
  *bitmap=cli_readint32(*src);
 
68
  *src+=4;
 
69
  *bits=32;
 
70
  return 0;
 
71
}
 
72
 
 
73
static int getbits(uint8_t X, uint32_t *eax, uint32_t *bitmap, uint8_t *bits, char **src, char *buf, unsigned int size) {
 
74
  *eax=*bitmap>>(32-X);
 
75
  if (*bits>X) {
 
76
    *bitmap<<=X;
 
77
    *bits-=X;
 
78
  } else if (*bits<X) {
 
79
    X-=*bits;
 
80
    *eax>>=X;
 
81
    if (getbitmap(bitmap, src, bits, buf, size)) return 1;
 
82
    *eax<<=X;
 
83
    *eax|=*bitmap>>(32-X);
 
84
    *bitmap<<=X;
 
85
    *bits-=X;
 
86
  } else {
 
87
    if (getbitmap(bitmap, src, bits, buf, size)) return 1;
 
88
  }
 
89
  return 0;
 
90
}
 
91
 
 
92
static int wunpsect(char *packed, char *unpacked, unsigned int psize, unsigned int usize) {
 
93
  char *src=packed, *dst=unpacked;
 
94
  uint32_t bitmap, eax;
 
95
  uint8_t bits;
 
96
  unsigned int lostbit, getmorestuff;
 
97
  uint16_t backbytes;
 
98
  uint16_t backsize;
 
99
  uint8_t oal;
 
100
 
 
101
  if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
 
102
  eax=bitmap;
 
103
 
79
104
  while (1) {
80
 
    if (!CLI_ISCONTAINED(wwsect, sects[scount].rsz, structs, 17)) {
81
 
      cli_dbgmsg("WWPack: Array of structs out of section\n");
82
 
      break;
83
 
    }
84
 
    src = sects[scount].rva - cli_readint32(structs); /* src delta / dst delta - not used / dwords / end of src */
85
 
    structs+=8;
86
 
    szd = cli_readint32(structs) * 4;
87
 
    structs+=4;
88
 
    srcend = cli_readint32(structs);
89
 
    structs+=4;
90
 
 
91
 
    unpd = ucur = exe+src+srcend+4-szd;
92
 
    if (!szd || !CLI_ISCONTAINED(exe, exesz, unpd, szd)) {
93
 
      cli_dbgmsg("WWPack: Compressed data out of file\n");
94
 
      break;
95
 
    }
96
 
    cli_dbgmsg("WWP: src: %x, szd: %x, srcend: %x - %x\n", src, szd, srcend, srcend+4-szd);
97
 
    if (!(compd = cli_malloc(szd))) break;
98
 
    memcpy(compd, unpd, szd);
99
 
    memset(unpd, -1, szd); /*FIXME*/
100
 
    ccur=compd;
101
 
    
102
 
    RESEED;
103
 
    while(!error) {
104
 
      uint32_t backbytes, backsize;
105
 
      uint8_t saved;
106
 
 
107
 
      BIT;
108
 
      if (!bits) { /* BYTE copy */
109
 
        if(ccur-compd>=szd || !CLI_ISCONTAINED(exe, exesz, ucur, 1))
110
 
          error=1;
111
 
        else
112
 
          *ucur++=*ccur++;
113
 
        continue;
114
 
      }
115
 
 
116
 
      BITS(2);
117
 
      if(bits==3) { /* WORD backcopy */
118
 
        uint8_t shifted, subbed = 31;
119
 
        BITS(2);
120
 
        shifted = bits + 5;
121
 
        if(bits>=2) {
122
 
          shifted++;
123
 
          subbed += 0x80;
124
 
        }
125
 
        backbytes = (1<<shifted)-subbed; /* 1h, 21h, 61h, 161h */
126
 
        BITS(shifted); /* 5, 6, 8, 9 */
127
 
        if(error || bits == 0x1ff) break;
128
 
        backbytes+=bits;
129
 
        if(!CLI_ISCONTAINED(exe, exesz, ucur, 2) || !CLI_ISCONTAINED(exe, exesz, ucur-backbytes, 2)) {
130
 
          error=1;
131
 
        } else {
132
 
          ucur[0]=*(ucur-backbytes);
133
 
          ucur[1]=*(ucur-backbytes+1);
134
 
          ucur+=2;
135
 
        }
136
 
        continue;
137
 
      }
138
 
 
139
 
      /* BLOCK backcopy */
140
 
      saved = bits; /* cmp al, 1 / pushf */
141
 
 
142
 
      BITS(3);
143
 
      if (bits<6) {
144
 
        backbytes = bits;
145
 
        switch(bits) {
146
 
        case 4: /* 10,11 */
147
 
          backbytes++;
148
 
        case 3: /* 8,9 */
149
 
          BIT;
150
 
          backbytes+=bits;
151
 
        case 0: case 1: case 2: /* 5,6,7 */
152
 
          backbytes+=5;
153
 
          break;
154
 
        case 5: /* 12 */
155
 
          backbytes=12;
156
 
          break;
157
 
        }
158
 
        BITS(backbytes);
159
 
        bits+=(1<<backbytes)-31;
160
 
      } else if(bits==6) {
161
 
        BITS(0x0e);
162
 
        bits+=0x1fe1;
 
105
    lostbit=bitmap>>31;
 
106
    bitmap<<=1;
 
107
    bits--;
 
108
    if (!lostbit && bits) {
 
109
      if (!(CLI_ISCONTAINED(packed, psize, src, 1) && CLI_ISCONTAINED(unpacked, usize, dst, 1))) return 1;
 
110
      *dst++=*src++;
 
111
      continue;
 
112
    }
 
113
    
 
114
    if (!bits) {
 
115
      if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;
 
116
      eax=bitmap;
 
117
      if (!lostbit) {
 
118
        if (!(CLI_ISCONTAINED(packed, psize, src, 1) && CLI_ISCONTAINED(unpacked, usize, dst, 1))) return 1;
 
119
        *dst++=*src++;
 
120
        continue;
 
121
      }
 
122
    }
 
123
    
 
124
    if (getbits(2, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
 
125
    
 
126
    if ((eax&0xff)>=3) {
 
127
      /* 50ff - two_bytes */
 
128
      uint8_t fetchbits;
 
129
      
 
130
      if (getbits(2, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
 
131
      fetchbits=(eax&0xff)+5;
 
132
      eax--;
 
133
      if ((int16_t)(eax&0xffff)<=0) {
 
134
        /* 5113 */
 
135
        backbytes=1<<fetchbits;
 
136
        backbytes=(backbytes&0xff00)|((backbytes-31)&0xff);
163
137
      } else {
164
 
        BITS(0x0f);
165
 
        bits+=0x5fe1;
166
 
      }
167
 
 
168
 
      backbytes = bits;
169
 
 
170
 
      /* popf / jb */
171
 
      if (!saved) {
172
 
        BIT;
173
 
        if(!bits) {
174
 
          BIT;
175
 
          bits+=5;
176
 
        } else {
177
 
          BITS(3);
178
 
          if(bits) {
179
 
            bits+=6;
 
138
        /* 511b */
 
139
        fetchbits++;
 
140
        backbytes=1<<fetchbits;
 
141
        backbytes-=0x9f;
 
142
      }
 
143
      /* 5125 */
 
144
      if (getbits(fetchbits, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
 
145
      if ((eax&0xffff)==0x1ff) break;
 
146
      eax&=0xffff;
 
147
      backbytes+=eax;
 
148
      if (!(CLI_ISCONTAINED(unpacked, usize, dst-backbytes, 2) && CLI_ISCONTAINED(unpacked, usize, dst, 2))) return 1;
 
149
      *dst=*(dst-backbytes);
 
150
      dst++;
 
151
      *dst=*(dst-backbytes);
 
152
      dst++;
 
153
      continue;
 
154
    }
 
155
 
 
156
    /* 5143 - more_backbytes */      
 
157
    oal=eax&0xff;
 
158
    getmorestuff=1;
 
159
 
 
160
    
 
161
    if (getbits(3, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
 
162
    if ((eax&0xff)<=3) {
 
163
      lostbit=0;
 
164
      if ((eax&0xff)==3) {
 
165
        /* next_bit_or_reseed */
 
166
        lostbit=bitmap>>31;
 
167
        bitmap<<=1;
 
168
        bits--;
 
169
        if (!bits) {
 
170
          if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1; 
 
171
        }
 
172
      }
 
173
      eax=eax+lostbit+5;
 
174
      /* jmp more_bb_commondock */
 
175
    } else { /* >3 */
 
176
      /* 5160 - more_bb_morethan3 */
 
177
      if ((eax&0xff)==4) {
 
178
        /* next_bit_or_reseed */
 
179
        lostbit=bitmap>>31;
 
180
        bitmap<<=1;
 
181
        bits--;
 
182
        if (!bits) {
 
183
          if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;  
 
184
        }
 
185
        eax=eax+lostbit+6;
 
186
        /* jmp more_bb_commondock */
 
187
      } else { /* !=4 */
 
188
        eax+=7;
 
189
        if ((eax&0xff)>=0x0d) {
 
190
          getmorestuff=0; /* jmp more_bb_PASTcommondock */
 
191
          if ((eax&0xff)==0x0d) {
 
192
            /* 5179  */
 
193
            if (getbits(0x0e, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
 
194
            eax+=0x1fe1;
180
195
          } else {
181
 
            BITS(4);
182
 
            if(bits) {
183
 
              bits+=13;
184
 
            } else {
185
 
              uint8_t cnt = 4;
186
 
              uint16_t shifted = 0x0d;
187
 
              
188
 
              do {
189
 
                if(cnt==7) { cnt = 0x0e; shifted = 0; break; }
190
 
                shifted=((shifted+2)<<1)-1;
191
 
                BIT;
192
 
                cnt++;
193
 
              } while(!bits);
194
 
              BITS(cnt);
195
 
              bits+=shifted;
196
 
            }
 
196
            /* 516c */
 
197
            if (getbits(0x0f, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
 
198
            eax+=0x5fe1;
197
199
          }
 
200
          /* jmp more_bb_PASTcommondock */
 
201
        } /* al >= 0d */
 
202
      } /* al != 4 */
 
203
    } /* >3 */
 
204
    
 
205
    if (getmorestuff) {
 
206
      /* 5192 - more_bb_commondock */
 
207
      uint16_t bk=(1<<(eax&0xff))-0x1f;
 
208
      if (getbits((eax&0xff), &eax, &bitmap, &bits, &src, packed, psize)) return 1;
 
209
      eax+=bk;
 
210
    }
 
211
    
 
212
    /* 51a7 - more_bb_pastcommondock */
 
213
    eax&=0xffff;
 
214
    backbytes=eax;
 
215
    backsize=3+(oal!=1);
 
216
    
 
217
    if (oal<1) { /* overrides backsize */
 
218
      /* 51bb - more_bb_again */
 
219
      
 
220
      /* next_bit_or_reseed */
 
221
      lostbit=bitmap>>31;
 
222
      bitmap<<=1;
 
223
      bits--;
 
224
      if (!bits) {
 
225
        if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;  
 
226
      }
 
227
      if (!lostbit) {
 
228
        /* 51c2 */
 
229
        /* next_bit_or_reseed */
 
230
        lostbit=bitmap>>31;
 
231
        bitmap<<=1;
 
232
        bits--;
 
233
        if (!bits) {
 
234
          if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;   
198
235
        }
199
 
        backsize = bits;
 
236
        eax=5+lostbit;
 
237
        /* jmp setsize_and_backcopy */
200
238
      } else {
201
 
        backsize = saved+2;
202
 
      }
203
 
 
204
 
      if(!CLI_ISCONTAINED(exe, exesz, ucur, backsize) || !CLI_ISCONTAINED(exe, exesz, ucur-backbytes, backsize)) error=1;
205
 
      else while(backsize--) {
206
 
        *ucur=*(ucur-backbytes);
207
 
        ucur++;
208
 
      }
209
 
    }
210
 
    free(compd);
211
 
    if(error) {
212
 
      cli_dbgmsg("WWPack: decompression error\n");
213
 
      break;
214
 
    }
215
 
    if (error || !*structs++) break;
216
 
  }
217
 
 
218
 
  if(!error) {
219
 
    exe[pe+6]=(uint8_t)scount;
220
 
    exe[pe+7]=(uint8_t)(scount>>8);
221
 
    cli_writeint32(&exe[pe+0x28], cli_readint32(wwsect+0x295)+sects[scount].rva+0x299);
222
 
    cli_writeint32(&exe[pe+0x50], cli_readint32(&exe[pe+0x50])-sects[scount].vsz);
223
 
 
224
 
    structs = &exe[(0xffff&cli_readint32(&exe[pe+0x14]))+pe+0x18];
225
 
    for(i=0 ; i<scount ; i++) {
226
 
      cli_writeint32(structs+8, sects[i].vsz);
227
 
      cli_writeint32(structs+12, sects[i].rva);
228
 
      cli_writeint32(structs+16, sects[i].vsz);
229
 
      cli_writeint32(structs+20, sects[i].rva);
230
 
      structs+=0x28;
231
 
    }
232
 
    memset(structs, 0, 0x28);
233
 
    error = cli_writen(desc, exe, exesz)!=exesz;
234
 
  }
235
 
  return error;
 
239
        /* 51ce - more_bb_again_and_again */
 
240
        if (getbits(3, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
 
241
        if (eax&0xff) {
 
242
          /* 51e6 */
 
243
          eax+=6;
 
244
          /* jmp setsize_and_backcopy */
 
245
        } else {
 
246
          if (getbits(4, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
 
247
          if (eax&0xff) {
 
248
            /* 51e4 */
 
249
            eax+=7+6;
 
250
            /* jmp setsize_and_backcopy */
 
251
          } else {
 
252
            /* 51ea - OMGWTF */
 
253
            uint8_t c=4;
 
254
            uint16_t d=0x0d;
 
255
            
 
256
            while ( 1 ) {
 
257
              if (c!=7){
 
258
                d+=2;
 
259
                d<<=1;
 
260
                d--;
 
261
                
 
262
                /* next_bit_or_reseed */
 
263
                lostbit=bitmap>>31;
 
264
                bitmap<<=1;
 
265
                bits--;
 
266
                if (!bits) {
 
267
                  if (getbitmap(&bitmap, &src, &bits, packed, psize)) return 1;    
 
268
                }
 
269
                c++;
 
270
                if (!lostbit) continue;
 
271
                if (getbits(c, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
 
272
                d+=eax&0xff;
 
273
                eax&=0xffffff00;
 
274
                eax|=d&0xff;
 
275
              } else {
 
276
                if (getbits(14, &eax, &bitmap, &bits, &src, packed, psize)) return 1;
 
277
              }
 
278
              break;
 
279
            } /* while */
 
280
          } /* OMGWTF */
 
281
        } /* eax&0xff */
 
282
      } /* lostbit */
 
283
        /* 521b - setsize_and_backcopy */
 
284
      backsize=eax&0xffff;
 
285
    }
 
286
 
 
287
    /* 521e - backcopy */
 
288
    if (!(CLI_ISCONTAINED(unpacked, usize, dst-backbytes, backsize) && CLI_ISCONTAINED(unpacked, usize, dst, backsize))) return 1;
 
289
    while(backsize--){
 
290
      *dst=*(dst-backbytes);
 
291
      dst++;
 
292
    }
 
293
 
 
294
  } /* while true */
 
295
 
 
296
  return 0;
 
297
}
 
298
 
 
299
int wwunpack(char *exe, uint32_t exesz, uint32_t headsize, uint32_t min, uint32_t wwprva, uint32_t e_lfanew, char *wwp, uint32_t wwpsz, uint16_t sects) {
 
300
  char *stuff=wwp+0x2a1, *packed, *unpacked;
 
301
  uint32_t rva, csize;
 
302
 
 
303
  cli_dbgmsg("in wwunpack\n");
 
304
 
 
305
 
 
306
  while(1) {
 
307
    if (!CLI_ISCONTAINED(wwp, wwpsz, stuff, 17)) {
 
308
      cli_dbgmsg("WWPack: next chunk out ouf file, giving up.\n");
 
309
      return 1;
 
310
    }
 
311
    if ((csize=cli_readint32(stuff+8)*4)!=(uint32_t)cli_readint32(stuff+12)+4) {
 
312
      cli_dbgmsg("WWPack: inconsistent/hacked data, go figure!\n");
 
313
      return 1;
 
314
    }
 
315
    rva = wwprva-cli_readint32(stuff);
 
316
    if((packed = (char *) cli_calloc(csize, sizeof(char))) == NULL) {
 
317
      cli_dbgmsg("WWPack: Can't allocate %d bytes\n", csize);
 
318
      return 1;
 
319
    }
 
320
    unpacked=exe+headsize+rva-min;
 
321
    if (!CLI_ISCONTAINED(exe, exesz, unpacked, csize)) {
 
322
      free(packed);
 
323
      cli_dbgmsg("WWPack: packed data out of bounds, giving up.\n");
 
324
      return 1;
 
325
    }
 
326
    memcpy(packed, unpacked, csize);
 
327
    if (wunpsect(packed, unpacked, csize, exesz-(unpacked-exe))) {
 
328
      free(packed);
 
329
      cli_dbgmsg("WWPack: unpacking failed.\n");
 
330
      return 1;
 
331
    }
 
332
    free(packed);
 
333
    if (!stuff[16]) break;
 
334
    stuff+=17;
 
335
  }
 
336
 
 
337
  stuff=exe+e_lfanew;
 
338
  stuff[6]=sects&0xff;
 
339
  stuff[7]=sects>>8;
 
340
 
 
341
  csize=cli_readint32(wwp+0x295)+wwprva+0x299;
 
342
  cli_dbgmsg("WWPack: found OEP @%x\n", csize);
 
343
  cli_writeint32(stuff+0x28, csize);
 
344
 
 
345
  csize=cli_readint32(stuff+0x50)-VAALIGN(wwpsz);
 
346
  cli_writeint32(stuff+0x50, csize);
 
347
 
 
348
 
 
349
  stuff+=0x18+(cli_readint32(stuff+0x14)&0xffff);
 
350
  while (sects--) {
 
351
    uint32_t v=cli_readint32(stuff+8);
 
352
    uint32_t r=cli_readint32(stuff+16);
 
353
    csize=FIXVS(v, r);
 
354
    cli_writeint32(stuff+8, csize);
 
355
    cli_writeint32(stuff+16, csize);
 
356
    cli_writeint32(stuff+20, cli_readint32(stuff+12)-min+headsize);
 
357
    stuff+=0x28;
 
358
  }
 
359
  memset(stuff, 0, 0x28);
 
360
 
 
361
  return 0;
236
362
}