Browse code

add support for NsPack

git-svn: trunk@2428

aCaB authored on 2006/10/25 11:35:25
Showing 6 changed files
... ...
@@ -1,3 +1,7 @@
1
+Wed Oct 25 04:30:36 CEST 2006 (acab)
2
+------------------------------------
3
+  * libclamav: add support for NsPack (--enable-experimental)
4
+  
1 5
 Mon Oct 23 17:48:39 CEST 2006 (tk)
2 6
 ----------------------------------
3 7
   * libclamav: improve support for NodalCore SDK 3.3
... ...
@@ -96,6 +96,8 @@ libclamav_la_SOURCES = \
96 96
 	wwunpack.h \
97 97
 	suecrypt.c \
98 98
 	suecrypt.h \
99
+	unsp.c \
100
+	unsp.h \
99 101
 	packlibs.c \
100 102
 	packlibs.h \
101 103
 	fsg.c \
... ...
@@ -83,12 +83,12 @@ am_libclamav_la_OBJECTS = matcher-ac.lo matcher-bm.lo matcher.lo \
83 83
 	text.lo ole2_extract.lo vba_extract.lo msexpand.lo pe.lo \
84 84
 	cabd.lo lzxd.lo mszipd.lo qtmd.lo system.lo upx.lo htmlnorm.lo \
85 85
 	chmunpack.lo rebuildpe.lo petite.lo wwunpack.lo suecrypt.lo \
86
-	packlibs.lo fsg.lo line.lo untar.lo unzip.lo special.lo \
87
-	binhex.lo is_tar.lo tnef.lo unrar15.lo unrarvm.lo unrar.lo \
88
-	unrarfilter.lo unrarppm.lo unrar20.lo unrarcmd.lo pdf.lo \
89
-	spin.lo yc.lo elf.lo sis.lo uuencode.lo pst.lo phishcheck.lo \
90
-	phish_domaincheck_db.lo phish_whitelist.lo regex_list.lo \
91
-	sha256.lo
86
+	unsp.lo packlibs.lo fsg.lo line.lo untar.lo unzip.lo \
87
+	special.lo binhex.lo is_tar.lo tnef.lo unrar15.lo unrarvm.lo \
88
+	unrar.lo unrarfilter.lo unrarppm.lo unrar20.lo unrarcmd.lo \
89
+	pdf.lo spin.lo yc.lo elf.lo sis.lo uuencode.lo pst.lo \
90
+	phishcheck.lo phish_domaincheck_db.lo phish_whitelist.lo \
91
+	regex_list.lo sha256.lo
92 92
 libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS)
93 93
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
94 94
 depcomp = $(SHELL) $(top_srcdir)/depcomp
... ...
@@ -297,6 +297,8 @@ libclamav_la_SOURCES = \
297 297
 	wwunpack.h \
298 298
 	suecrypt.c \
299 299
 	suecrypt.h \
300
+	unsp.c \
301
+	unsp.h \
300 302
 	packlibs.c \
301 303
 	packlibs.h \
302 304
 	fsg.c \
... ...
@@ -480,6 +482,7 @@ distclean-compile:
480 480
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unrarfilter.Plo@am__quote@
481 481
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unrarppm.Plo@am__quote@
482 482
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unrarvm.Plo@am__quote@
483
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unsp.Plo@am__quote@
483 484
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/untar.Plo@am__quote@
484 485
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unzip.Plo@am__quote@
485 486
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upx.Plo@am__quote@
... ...
@@ -45,6 +45,7 @@
45 45
 #include "yc.h"
46 46
 #include "wwunpack.h"
47 47
 #include "suecrypt.h"
48
+#include "unsp.h"
48 49
 #include "scanners.h"
49 50
 #include "rebuildpe.h"
50 51
 #include "str.h"
... ...
@@ -67,6 +68,9 @@
67 67
 
68 68
 #define EC32(x) le32_to_host(x) /* Convert little endian to host */
69 69
 #define EC16(x) le16_to_host(x)
70
+/* lower and upper bondary alignment (size vs offset) */
71
+#define PEALIGN(o,a) (((a))?(((o)/(a))*(a)):(o))
72
+#define PESALIGN(o,a) (((a))?(((o)/(a)+((o)%(a)!=0))*(a)):(o))
70 73
 
71 74
 extern short cli_leavetemps_flag;
72 75
 
... ...
@@ -75,13 +79,13 @@ struct offset_list {
75 75
     struct offset_list *next;
76 76
 };
77 77
 
78
-static uint32_t cli_rawaddr(uint32_t rva, struct pe_image_section_hdr *shp, uint16_t nos, unsigned int *err)
78
+static uint32_t cli_rawaddr(uint32_t rva, struct pe_image_section_hdr *shp, uint16_t nos, unsigned int *err, uint32_t valign, uint32_t falign)
79 79
 {
80 80
 	int i, found = 0;
81 81
 
82 82
 
83 83
     for(i = 0; i < nos; i++) {
84
-	if(EC32(shp[i].VirtualAddress) <= rva && EC32(shp[i].VirtualAddress) + EC32(shp[i].SizeOfRawData) > rva) {
84
+      if(PEALIGN(EC32(shp[i].VirtualAddress), valign) <= rva && PEALIGN(EC32(shp[i].VirtualAddress), valign) + PESALIGN(EC32(shp[i].SizeOfRawData), falign) > rva) {
85 85
 	    found = 1;
86 86
 	    break;
87 87
 	}
... ...
@@ -93,7 +97,7 @@ static uint32_t cli_rawaddr(uint32_t rva, struct pe_image_section_hdr *shp, uint
93 93
     }
94 94
 
95 95
     *err = 0;
96
-    return rva - EC32(shp[i].VirtualAddress) + EC32(shp[i].PointerToRawData);
96
+    return rva - PEALIGN(EC32(shp[i].VirtualAddress), valign) + PEALIGN(EC32(shp[i].PointerToRawData), falign);
97 97
 }
98 98
 
99 99
 static void xckriz(char **opcode, int *len, int checksize, int reg) {
... ...
@@ -661,7 +665,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
661 661
     else
662 662
 	ep = EC32(optional_hdr32.AddressOfEntryPoint);
663 663
 
664
-    if(ep >= min && !(ep = cli_rawaddr(ep, section_hdr, nsections, &err)) && err) {
664
+    if(ep >= min && !(ep = cli_rawaddr(ep, section_hdr, nsections, &err, 0, 0)) && err) {
665 665
 	cli_dbgmsg("Possibly broken PE file\n");
666 666
 	free(section_hdr);
667 667
 	if(DETECT_BROKEN) {
... ...
@@ -813,7 +817,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
813 813
 		}
814 814
 		val = cli_readint32(jpt + 1);
815 815
 		val += 5 + EC32(section_hdr[0].VirtualAddress) + total + shift;
816
-		raddr = cli_rawaddr(val, section_hdr, nsections, &err);
816
+		raddr = cli_rawaddr(val, section_hdr, nsections, &err, 0, 0);
817 817
 
818 818
 		if(!err && (raddr >= EC32(section_hdr[polipos].PointerToRawData) && raddr < EC32(section_hdr[polipos].PointerToRawData) + EC32(section_hdr[polipos].SizeOfRawData)) && (!offlist || (raddr != offlist->offset))) {
819 819
 		    offnode = (struct offset_list *) cli_malloc(sizeof(struct offset_list));
... ...
@@ -1815,7 +1819,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1815 1815
 
1816 1816
 	    for(i = 0 ; i < nsections; i++) {
1817 1817
 		if(section_hdr[i].SizeOfRawData) {
1818
-			uint32_t offset = cli_rawaddr(EC32(section_hdr[i].VirtualAddress), section_hdr, nsections, &err);
1818
+		  uint32_t offset = cli_rawaddr(EC32(section_hdr[i].VirtualAddress), section_hdr, nsections, &err, 0, 0);
1819 1819
 
1820 1820
 		    if(err || lseek(desc, offset, SEEK_SET) == -1 || (unsigned int) cli_readn(desc, dest + EC32(section_hdr[i].VirtualAddress) - min, EC32(section_hdr[i].SizeOfRawData)) != EC32(section_hdr[i].SizeOfRawData)) {
1821 1821
 			free(section_hdr);
... ...
@@ -1892,8 +1896,8 @@ int cli_scanpe(int desc, cli_ctx *ctx)
1892 1892
        EC32(optional_hdr32.AddressOfEntryPoint) < EC32(section_hdr[nsections - 1].VirtualAddress) + EC32(section_hdr[nsections - 1].SizeOfRawData) - 0x3217 - 4 &&
1893 1893
        memcmp(buff+4, "\xe8\x00\x00\x00\x00\x8b\x1c\x24\x83\xc3", 10) == 0)  {
1894 1894
 
1895
-	char *spinned;
1896
-	    
1895
+	    char *spinned;
1896
+
1897 1897
 	if(ctx->limits && ctx->limits->maxfilesize && fsize > ctx->limits->maxfilesize) {
1898 1898
 	    cli_dbgmsg("PEspin: Size exceeded (fsize: %u, max: %lu)\n", fsize, ctx->limits->maxfilesize);
1899 1899
             free(section_hdr);
... ...
@@ -2059,7 +2063,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2059 2059
       char *dest, *wwp;
2060 2060
 
2061 2061
       for(i = 0 ; i < (unsigned int)nsections-1; i++) {
2062
-	uint32_t offset = cli_rawaddr(EC32(section_hdr[i].VirtualAddress), section_hdr, nsections, &err);
2062
+	uint32_t offset = cli_rawaddr(EC32(section_hdr[i].VirtualAddress), section_hdr, nsections, &err, 0, 0);
2063 2063
 	if (!err && offset<headsize) headsize=offset;
2064 2064
       }
2065 2065
       
... ...
@@ -2093,7 +2097,7 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2093 2093
 
2094 2094
       for(i = 0 ; i < (unsigned int)nsections-1; i++) {
2095 2095
 	if(section_hdr[i].SizeOfRawData) {
2096
-	  uint32_t offset = cli_rawaddr(EC32(section_hdr[i].VirtualAddress), section_hdr, nsections, &err);
2096
+	  uint32_t offset = cli_rawaddr(EC32(section_hdr[i].VirtualAddress), section_hdr, nsections, &err, 0, 0);
2097 2097
 	  
2098 2098
 	  if(err || lseek(desc, offset, SEEK_SET) == -1 || (unsigned int) cli_readn(desc, dest + headsize + EC32(section_hdr[i].VirtualAddress) - min, EC32(section_hdr[i].SizeOfRawData)) != EC32(section_hdr[i].SizeOfRawData)) {
2099 2099
 	    free(dest);
... ...
@@ -2175,6 +2179,120 @@ int cli_scanpe(int desc, cli_ctx *ctx)
2175 2175
       }
2176 2176
     }
2177 2177
 
2178
+#ifdef CL_EXPERIMENTAL
2179
+    /* NsPack */
2180
+
2181
+    /* WATCH OUT: ep && buff destroyed!!! */
2182
+    while (1) {
2183
+      uint32_t eprva = EC32(optional_hdr32.AddressOfEntryPoint);
2184
+      uint32_t start_of_stuff, ssize, dsize;
2185
+      unsigned int nowinldr;
2186
+      char *src, *dest;
2187
+      FILE *asd;
2188
+
2189
+      ep = cli_rawaddr(eprva , section_hdr, nsections, &err, EC32(optional_hdr32.SectionAlignment), EC32(optional_hdr32.FileAlignment));
2190
+      if (lseek(desc, ep, SEEK_SET)==-1) break;
2191
+      if (cli_readn(desc, buff, 13)!=13) break;
2192
+      if (*buff=='\xe9') { /* bitched headers */
2193
+	eprva = cli_readint32(buff+1)+EC32(optional_hdr32.AddressOfEntryPoint)+5;
2194
+	ep = cli_rawaddr(eprva, section_hdr, nsections, &err, EC32(optional_hdr32.SectionAlignment), EC32(optional_hdr32.FileAlignment));
2195
+	if (lseek(desc, ep, SEEK_SET)==-1) break;
2196
+	if (cli_readn(desc, buff, 24)!=24) break;
2197
+      }
2198
+
2199
+      if (memcmp(buff, "\x9c\x60\xe8\x00\x00\x00\x00\x5d\xb8\x07\x00\x00\x00", 13)) break;
2200
+
2201
+      nowinldr = 0x54-cli_readint32(buff+17);
2202
+      cli_dbgmsg("NsPack: Found *start_of_stuff @delta-%x\n", nowinldr);
2203
+
2204
+      if (lseek(desc, ep-nowinldr, SEEK_SET)==-1) break;
2205
+      if (cli_readn(desc, buff, 4)!=4) break;
2206
+      start_of_stuff=ep+cli_readint32(buff);
2207
+      if (lseek(desc, start_of_stuff, SEEK_SET)==-1) break;
2208
+      if (cli_readn(desc, buff, 20)!=20) break;
2209
+      src = buff;
2210
+      if (!cli_readint32(buff)) {
2211
+	start_of_stuff+=4; /* FIXME: more to do */
2212
+	src+=4;
2213
+      }
2214
+
2215
+      ssize = cli_readint32(src+5)|0xff;
2216
+      dsize = cli_readint32(src+9);
2217
+
2218
+      if(ctx->limits && ctx->limits->maxfilesize && (ssize > ctx->limits->maxfilesize || dsize > ctx->limits->maxfilesize)) {
2219
+	cli_dbgmsg("NsPack: Size exceeded\n");
2220
+	free(section_hdr);
2221
+	if(BLOCKMAX) {
2222
+	  *ctx->virname = "PE.NsPack.ExceededFileSize";
2223
+	  return CL_VIRUS;
2224
+	} else {
2225
+	  return CL_CLEAN;
2226
+	}
2227
+      }
2228
+
2229
+      if ( !ssize || !dsize || dsize != (uint32_t)PESALIGN(EC32(section_hdr[0].VirtualSize), EC32(optional_hdr32.SectionAlignment))) break;
2230
+      if (lseek(desc, start_of_stuff, SEEK_SET)==-1) break;
2231
+      if (!(dest=cli_malloc(dsize))) break;
2232
+      /* memset(dest, 0xfc, dsize); */
2233
+
2234
+      if (!(src=cli_malloc(ssize))) {
2235
+	free(dest);
2236
+	break;
2237
+      }
2238
+      /* memset(src, 0x00, ssize); */
2239
+      cli_readn(desc, src, ssize);
2240
+
2241
+      eprva+=0x27a;
2242
+      ep = cli_rawaddr(eprva, section_hdr, nsections, &err, EC32(optional_hdr32.SectionAlignment), EC32(optional_hdr32.FileAlignment));
2243
+      if (lseek(desc, ep, SEEK_SET)==-1) break;
2244
+      if (cli_readn(desc, buff, 5)!=5) break;
2245
+      eprva=eprva+5+cli_readint32(buff+1);
2246
+      cli_dbgmsg("NsPack: OEP = %08x\n", eprva);
2247
+
2248
+      if(!(tempfile = cli_gentemp(NULL))) {
2249
+	free(src);
2250
+	free(dest);
2251
+	free(section_hdr);
2252
+	return CL_EMEM;
2253
+      }
2254
+
2255
+      if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
2256
+	cli_dbgmsg("NsPack: Can't create file %s\n", tempfile);
2257
+	free(tempfile);
2258
+	free(src);
2259
+	free(dest);
2260
+	free(section_hdr);
2261
+	return CL_EIO;
2262
+      }
2263
+
2264
+      if (!unspack(src, dest, ctx, EC32(section_hdr[0].VirtualAddress), EC32(optional_hdr32.ImageBase), eprva, ndesc)) {
2265
+	free(src);
2266
+	free(dest);
2267
+	if (cli_leavetemps_flag)
2268
+	  cli_dbgmsg("NsPack: Unpacked and rebuilt executable saved in %s\n", tempfile);
2269
+	else
2270
+	  cli_dbgmsg("NsPack: Unpacked and rebuilt executable\n");
2271
+	fsync(ndesc);
2272
+	lseek(ndesc, 0, SEEK_SET);
2273
+
2274
+	if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) {
2275
+	  free(section_hdr);
2276
+	  close(ndesc);
2277
+	  if(!cli_leavetemps_flag) unlink(tempfile);
2278
+	  free(tempfile);
2279
+	  return CL_VIRUS;
2280
+	}
2281
+      } else {
2282
+	free(src);
2283
+	free(dest);
2284
+	cli_dbgmsg("NsPack: Unpacking failed\n");
2285
+      }
2286
+      close(ndesc);
2287
+      if(!cli_leavetemps_flag) unlink(tempfile);
2288
+      free(tempfile);
2289
+      break;
2290
+    }
2291
+#endif /* CL_EXPERIMENTAL - NsPack */
2178 2292
 
2179 2293
     /* to be continued ... */
2180 2294
 
... ...
@@ -2320,7 +2438,7 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo)
2320 2320
     else
2321 2321
 	peinfo->ep = EC32(optional_hdr32.AddressOfEntryPoint);
2322 2322
 
2323
-    if(peinfo->ep >= min && !(peinfo->ep = cli_rawaddr(peinfo->ep, section_hdr, peinfo->nsections, &err)) && err) {
2323
+	if(peinfo->ep >= min && !(peinfo->ep = cli_rawaddr(peinfo->ep, section_hdr, peinfo->nsections, &err, 0, 0)) && err) {
2324 2324
 	cli_dbgmsg("Possibly broken PE file\n");
2325 2325
 	free(section_hdr);
2326 2326
 	free(peinfo->section);
2327 2327
new file mode 100644
... ...
@@ -0,0 +1,530 @@
0
+/*
1
+ *  Copyright (C) 2006 aCaB <acab@clamav.net>
2
+ *
3
+ *  This program is free software; you can redistribute it and/or modify
4
+ *  it under the terms of the GNU General Public License as published by
5
+ *  the Free Software Foundation; either version 2 of the License, or
6
+ *  (at your option) any later version.
7
+ *
8
+ *  This program is distributed in the hope that it will be useful,
9
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
+ *  GNU General Public License for more details.
12
+ *
13
+ *  You should have received a copy of the GNU General Public License
14
+ *  along with this program; if not, write to the Free Software
15
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16
+ *  MA 02110-1301, USA.
17
+ */
18
+
19
+/*
20
+** unsp.c
21
+**
22
+** 11/10/2k6 - Merge started.
23
+**
24
+*/
25
+
26
+/*
27
+** Plays around with NsPack compressed executables
28
+**
29
+** This piece of code is dedicated to Damian Put
30
+** who I made a successful and wealthy man.
31
+**
32
+** Damian, you owe me a pint!
33
+*/
34
+
35
+/*
36
+** TODO:
37
+**
38
+** - Investigate the "unused" code in NsPack
39
+** - Fetch all the nspacked samples from the zoo and run extensive testing
40
+** - Add bound checks
41
+** - Test against the zoo again
42
+** - Perform regression testing against the full zoo 
43
+** - check nested
44
+** - look at the 64bit version (one of these days)
45
+**
46
+*/
47
+
48
+/* 
49
+
50
+   FIXME: clean this rubbish
51
+
52
+
53
+init_and_check_dll_loadflags();
54
+
55
+nsp1:004359FE                 add     edi, [ebp-28Dh]
56
+nsp1:00435A04                 mov     ebx, edi
57
+nsp1:00435A06                 cmp     dword ptr [edi], 0
58
+nsp1:00435A09                 jnz     short loc_435A15
59
+nsp1:00435A0B                 add     edi, 4
60
+nsp1:00435A0E                 mov     ecx, 0
61
+nsp1:00435A13                 jmp     short loc_435A2B
62
+nsp1:00435A15 ; ---------------------------------------------------------------------------
63
+nsp1:00435A15
64
+nsp1:00435A15 loc_435A15:                             ; CODE XREF: start+349EEj
65
+nsp1:00435A15                 mov     ecx, 1
66
+nsp1:00435A1A                 add     edi, [ebx]
67
+nsp1:00435A1C                 add     ebx, 4
68
+nsp1:00435A1F
69
+nsp1:00435A1F loc_435A1F:                             ; CODE XREF: start+34A3Dj
70
+nsp1:00435A1F                 cmp     dword ptr [ebx], 0
71
+nsp1:00435A22                 jz      short loc_435A5A
72
+nsp1:00435A24                 add     [ebx], edx
73
+nsp1:00435A26                 mov     esi, [ebx]
74
+nsp1:00435A28                 add     edi, [ebx+4]
75
+nsp1:00435A2B
76
+nsp1:00435A2B loc_435A2B:                             ; CODE XREF: start+349F8j
77
+nsp1:00435A2B                 push    edi
78
+nsp1:00435A2C                 push    ecx
79
+nsp1:00435A2D                 push    edx
80
+nsp1:00435A2E                 push    ebx
81
+nsp1:00435A2F                 push    dword ptr [ebp-1D1h] ; VirtualFree
82
+nsp1:00435A35                 push    dword ptr [ebp-1D5h] ; alloc
83
+nsp1:00435A3B                 mov     edx, esi
84
+nsp1:00435A3D                 mov     ecx, edi
85
+nsp1:00435A3F                 mov     eax, offset get_byte
86
+nsp1:00435A44                 int     3               ; Trap to Debugger
87
+nsp1:00435A45                 add     eax, 5A9h
88
+nsp1:00435A4A                 call    eax ; real_unpack ; edx=401000
89
+nsp1:00435A4A                                         ; ecx=436282
90
+nsp1:00435A4C                 pop     ebx
91
+nsp1:00435A4D                 pop     edx
92
+nsp1:00435A4E                 pop     ecx
93
+nsp1:00435A4F                 pop     edi
94
+nsp1:00435A50                 cmp     ecx, 0
95
+nsp1:00435A53                 jz      short loc_435A5A
96
+nsp1:00435A55                 add     ebx, 8
97
+nsp1:00435A58                 jmp     short loc_435A1F
98
+nsp1:00435A5A ; ---------------------------------------------------------------------------
99
+nsp1:00435A5A
100
+nsp1:00435A5A loc_435A5A:                             ; CODE XREF: start+34A07j
101
+nsp1:00435A5A                                         ; start+34A38j
102
+nsp1:00435A5A                 push    8000h
103
+
104
+*/
105
+
106
+#if HAVE_CONFIG_H
107
+#include "clamav-config.h"
108
+#endif
109
+
110
+#ifdef CL_EXPERIMENTAL
111
+
112
+#include <stdlib.h>
113
+
114
+#include "cltypes.h"
115
+#include "clamav.h"
116
+#include "others.h"
117
+#include "rebuildpe.h"
118
+#include "unsp.h"
119
+
120
+
121
+/* real_unpack(start_of_stuff, dest, malloc, free); */
122
+uint32_t unspack(char *start_of_stuff, char *dest, cli_ctx *ctx, uint32_t rva, uint32_t base, uint32_t ep, int file) {
123
+  uint8_t c = *start_of_stuff;
124
+  uint32_t i,firstbyte,tre,allocsz,tablesz,dsize,ssize;
125
+  uint16_t *table;
126
+  char *dst = dest;
127
+  char *src = start_of_stuff+0xd;
128
+  struct SECTION section;
129
+  
130
+  if (c>=0xe1) return 1;
131
+
132
+  if (c>=0x2d) {
133
+    firstbyte = i = c/0x2d;
134
+    do {c+=0xd3;} while (--i);
135
+  } else firstbyte = 0;
136
+
137
+  if (c>=9) {
138
+    allocsz = i = c/9;
139
+    do {c+=0xf7;} while (--i);
140
+  } else allocsz = 0;
141
+  
142
+  tre = c;
143
+  i = allocsz;
144
+  c = (tre+i)&0xff;
145
+  tablesz = ((0x300<<c)+0x736)*sizeof(uint16_t);
146
+  if(ctx->limits && ctx->limits->maxfilesize && tablesz > ctx->limits->maxfilesize) {
147
+    return 1; /* Should be ~15KB, if it's so big it's prolly just not nspacked */
148
+  }
149
+    
150
+  cli_dbgmsg("unsp: table size = %d\n", tablesz);
151
+  if (!(table = cli_malloc(tablesz))) return 1;
152
+  
153
+  dsize = cli_readint32(start_of_stuff+9);
154
+  ssize = cli_readint32(start_of_stuff+5);
155
+  
156
+  tre = very_real_unpack(table,tablesz,tre,allocsz,firstbyte,src,ssize,dst,dsize);
157
+  free(table);
158
+  if (tre) return 1;
159
+
160
+  section.raw=0;
161
+  section.rsz = dsize;
162
+  section.vsz = dsize;
163
+  section.rva = rva;
164
+  if ( (src = rebuildpe(dest, &section, 1, base, ep, 0, 0)) ) {
165
+    if (cli_writen(file, src, 0x148+0x80+0x28+dsize)!=-1) {
166
+      free(src);
167
+      return 0;
168
+    }
169
+    free(src);
170
+  }
171
+  return 1;
172
+}
173
+
174
+
175
+uint32_t very_real_unpack(uint16_t *table, uint32_t tablesz, uint32_t tre, uint32_t allocsz, uint32_t firstbyte, char *src, uint32_t ssize, char *dst, uint32_t dsize) {
176
+  struct UNSP read_struct;
177
+  uint32_t i = (0x300<<((allocsz+tre)&0xff)) + 0x736;
178
+
179
+  uint32_t previous_bit = 0;
180
+  uint32_t unpacked_so_far = 0;
181
+  uint32_t backbytes = 1;
182
+  uint32_t oldbackbytes = 1;
183
+  uint32_t old_oldbackbytes = 1;
184
+  uint32_t old_old_oldbackbytes = 1;
185
+
186
+  uint32_t damian = 0;
187
+  uint32_t put = (1<<(allocsz&0xff))-1;
188
+
189
+  uint32_t bielle = 0;
190
+
191
+  firstbyte = (1<<(firstbyte&0xff))-1;
192
+
193
+  if (tablesz < i*sizeof(uint16_t)) return 2;
194
+
195
+  /* init table */
196
+  while (i) table[--i]=0x400;
197
+
198
+  /* table noinit */
199
+
200
+  /* get_five - inlined */
201
+  read_struct.error = 0;
202
+  read_struct.oldval = 0;
203
+  read_struct.src_curr = src;
204
+  read_struct.bitmap = 0xffffffff;
205
+  read_struct.src_end = src + ssize;
206
+  read_struct.table = (char *)table;
207
+  read_struct.tablesz = tablesz;
208
+
209
+  for ( i = 0; i<5 ; i++) read_struct.oldval = (read_struct.oldval<<8) | get_byte(&read_struct);
210
+  if (read_struct.error) return 1;
211
+  /* if (!dsize) return 0; - checked in pe.c */
212
+
213
+
214
+  /* very_unpacking_loop */
215
+
216
+  while (1) {
217
+    uint32_t backsize = firstbyte&unpacked_so_far;
218
+    uint32_t tpos;
219
+    uint32_t temp = damian;
220
+
221
+    if (read_struct.error) return 1; /* checked once per mainloop, keeps the code readable and it's still safe */
222
+    
223
+    if (!getbit_from_table(&table[(damian<<4) + backsize], &read_struct)) { /* no_mainbit */
224
+
225
+      uint32_t shft = 8 - (tre&0xff);
226
+      shft &= 0xff;
227
+      tpos = (bielle>>shft) + ((put&unpacked_so_far)<<(tre&0xff));
228
+      tpos *=3;
229
+      tpos<<=8;
230
+
231
+      if ((int32_t)damian>=4) { /* signed */
232
+	if ((int32_t)damian>=0xa) { /* signed */
233
+	  damian -= 6;
234
+	} else {
235
+	  damian -= 3;
236
+	}
237
+      } else {
238
+	damian=0;
239
+      }
240
+
241
+      /* 44847E */
242
+      if (previous_bit) {
243
+	if (!CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far - backbytes], 1)) return 1;
244
+	ssize = (ssize&0xffffff00) | (uint8_t)dst[unpacked_so_far - backbytes]; /* FIXME! ssize is not static */
245
+	bielle = get_100_bits_from_tablesize(&table[tpos+0x736], &read_struct, ssize);
246
+	previous_bit=0;
247
+      } else {
248
+	bielle = get_100_bits_from_table(&table[tpos+0x736], &read_struct);
249
+      }
250
+
251
+      /* unpack_one_byte - duplicated */
252
+      if (!CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far], 1)) return 1;
253
+      dst[unpacked_so_far] = bielle;
254
+      unpacked_so_far++;
255
+      if (unpacked_so_far>=dsize) return 0;
256
+      continue;
257
+
258
+    } else { /* got_mainbit */
259
+
260
+      bielle = previous_bit = 1;
261
+
262
+      if (getbit_from_table(&table[damian+0xc0], &read_struct)) {
263
+	if (!getbit_from_table(&table[damian+0xcc], &read_struct)) {
264
+	  tpos = damian+0xf;
265
+	  tpos <<=4;
266
+	  tpos += backsize;
267
+	  if (!getbit_from_table(&table[tpos], &read_struct)) {
268
+	    if (!unpacked_so_far) return bielle; /* FIXME: WTF?! */
269
+	    
270
+	    damian = 2*((int32_t)damian>=7)+9; /* signed */
271
+	    if (!CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far - backbytes], 1)) return 1;
272
+	    bielle = (uint8_t)dst[unpacked_so_far - backbytes];
273
+	    /* unpack_one_byte - real */
274
+	    dst[unpacked_so_far] = bielle;
275
+	    unpacked_so_far++;
276
+	    if (unpacked_so_far>=dsize) return 0;
277
+	    continue;
278
+	    
279
+	  } else { /* gotbit_tre */
280
+	    backsize = get_n_bits_from_tablesize(&table[0x534], &read_struct, backsize);
281
+	    damian = ((int32_t)damian>=7); /* signed */
282
+	    damian = ((damian-1) & 0xfffffffd)+0xb;
283
+	    /* jmp checkloop_and_backcopy (uses edx) */
284
+	  } /* gotbit_uno ends */
285
+	} else { /* gotbit_due */
286
+	  if (!getbit_from_table(&table[damian+0xd8], &read_struct)) {
287
+	    tpos = oldbackbytes;
288
+	  } else {
289
+	    if (!getbit_from_table(&table[damian+0xe4], &read_struct)) {
290
+	      tpos = old_oldbackbytes;
291
+	    } else {
292
+	      /* set_old_old_oldback */
293
+	      tpos = old_old_oldbackbytes;
294
+	      old_old_oldbackbytes = old_oldbackbytes;
295
+	    }
296
+	    /* set_old_oldback */
297
+	    old_oldbackbytes = oldbackbytes;
298
+	  }
299
+	  /* set_oldback */
300
+	  oldbackbytes = backbytes;
301
+	  backbytes = tpos;
302
+	  
303
+	  backsize = get_n_bits_from_tablesize(&table[0x534], &read_struct, backsize);
304
+	  damian = ((int32_t)damian>=7); /* signed */
305
+	  damian = ((damian-1) & 0xfffffffd)+0xb;
306
+	  /* jmp checkloop_and_backcopy (uses edx) */
307
+	} /* gotbit_due ends */
308
+      } else { /* gotbit_uno */
309
+	
310
+	old_old_oldbackbytes = old_oldbackbytes;
311
+	old_oldbackbytes = oldbackbytes;
312
+	oldbackbytes = backbytes;
313
+	
314
+	damian = ((int32_t)damian>=7); /* signed */
315
+	damian = ((damian-1) & 0xfffffffd)+0xa;
316
+
317
+	backsize = get_n_bits_from_tablesize(&table[0x332], &read_struct, backsize);
318
+
319
+	tpos = ((int32_t)backsize>=4)?3:backsize; /* signed */
320
+	tpos<<=6;
321
+	tpos = get_n_bits_from_table(&table[0x1b0+tpos], 6, &read_struct);
322
+
323
+	if (tpos>=4) { /* signed */
324
+
325
+	  uint32_t s = tpos;
326
+	  s>>=1;
327
+	  s--;
328
+
329
+	  temp = (tpos & bielle) | 2;
330
+	  temp<<=(s&0xff);
331
+
332
+
333
+	  if ((int32_t)tpos<0xe) {
334
+	    temp += get_bb(&table[(temp-tpos)+0x2af], s, &read_struct);
335
+	  } else {
336
+	    s += 0xfffffffc;
337
+	    tpos = get_bitmap(&read_struct, s);
338
+	    tpos <<=4;
339
+	    temp += tpos;
340
+	    temp += get_bb(&table[0x322], 4, &read_struct);
341
+	  }
342
+	} else {
343
+	  /* gotbit_uno_out1 */
344
+	  backbytes = temp = tpos;
345
+	}
346
+	/* gotbit_uno_out2 */
347
+	backbytes = temp+1;
348
+	/* jmp checkloop_and_backcopy (uses edx) */
349
+      } /* gotbit_uno ends */
350
+
351
+      /* checkloop_and_backcopy */
352
+      if (!backbytes) return 0; /* very_real_unpack_end */
353
+      if (backbytes > unpacked_so_far) return bielle; /* FIXME: WTF?! */
354
+
355
+      backsize +=2;
356
+
357
+      if (!CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far], backsize) ||
358
+	  !CLI_ISCONTAINED(dst, dsize, &dst[unpacked_so_far - backbytes], backsize)
359
+	  ) {
360
+	cli_dbgmsg("%x %x %x %x\n", dst, dsize, &dst[unpacked_so_far], backsize);
361
+	return 1;
362
+      }
363
+      
364
+      do {
365
+	dst[unpacked_so_far] = dst[unpacked_so_far - backbytes];
366
+	unpacked_so_far++;
367
+      } while (--backsize && unpacked_so_far<dsize);
368
+      bielle = (uint8_t)dst[unpacked_so_far - 1];
369
+
370
+      if (unpacked_so_far>=dsize) return 0;
371
+
372
+    } /* got_mainbit ends */
373
+
374
+  } /* while true ends */
375
+}
376
+
377
+
378
+
379
+uint32_t get_byte(struct UNSP *read_struct) {
380
+
381
+  uint32_t ret;
382
+
383
+  if (read_struct->src_curr >= read_struct->src_end) {
384
+    read_struct->error = 1;
385
+    return 0xff;
386
+  }
387
+  ret = *(read_struct->src_curr);
388
+  read_struct->src_curr++;
389
+  return ret&0xff;
390
+}
391
+
392
+
393
+int getbit_from_table(uint16_t *intable, struct UNSP *read_struct) {
394
+  
395
+  uint32_t nval;
396
+  if (!CLI_ISCONTAINED((char *)read_struct->table, read_struct->tablesz, (char *)intable, sizeof(uint16_t))) {
397
+    read_struct->error = 1;
398
+    return 0xff;
399
+  }
400
+  nval = *intable * (read_struct->bitmap>>0xb);
401
+
402
+  if (read_struct->oldval<nval) { /* unsigned */
403
+    uint32_t sval;
404
+    read_struct->bitmap = nval;
405
+    nval = *intable;
406
+    sval = 0x800 - nval;
407
+    sval = ((int32_t)sval)>>5; /* signed */
408
+    sval += nval;
409
+    *intable=sval;
410
+    if (read_struct->bitmap<0x1000000) { /* unsigned */
411
+      read_struct->oldval = (read_struct->oldval<<8) | get_byte(read_struct);
412
+      read_struct->bitmap<<=8;
413
+    }
414
+    return 0;
415
+  }
416
+
417
+  read_struct->bitmap -= nval;
418
+  read_struct->oldval -= nval;
419
+
420
+  nval = *intable;
421
+  nval -= (nval>>5); /* word, unsigned */
422
+  *intable=nval;
423
+
424
+  if (read_struct->bitmap<0x1000000) { /* unsigned */
425
+    read_struct->oldval = (read_struct->oldval<<8) | get_byte(read_struct);
426
+    read_struct->bitmap<<=8;
427
+  }
428
+
429
+  return 1;
430
+}
431
+
432
+
433
+uint32_t get_100_bits_from_tablesize(uint16_t *intable, struct UNSP *read_struct, uint32_t ssize) {
434
+  
435
+  uint32_t count = 1;
436
+  
437
+  while (count<0x100) {
438
+    uint32_t lpos, tpos;
439
+    lpos = ssize&0xff;
440
+    ssize=(ssize&0xffffff00)|((lpos<<1)&0xff);
441
+    lpos>>=7;
442
+    tpos = lpos+1;
443
+    tpos<<=8;
444
+    tpos+=count;
445
+    tpos = getbit_from_table(&intable[tpos], read_struct);
446
+    count=(count*2)|tpos;
447
+    if (lpos!=tpos) {
448
+      /* second loop */
449
+      while (count<0x100)
450
+	count = (count*2)|getbit_from_table(&intable[count], read_struct);
451
+    }
452
+  } 
453
+  return count&0xff;
454
+}
455
+
456
+
457
+uint32_t get_100_bits_from_table(uint16_t *intable, struct UNSP *read_struct) {
458
+  uint32_t count = 1;
459
+  
460
+  while (count<0x100)
461
+    count = (count*2)|getbit_from_table(&intable[count], read_struct);
462
+  return count&0xff;
463
+}
464
+
465
+
466
+uint32_t get_n_bits_from_table(uint16_t *intable, uint32_t bits, struct UNSP *read_struct) {
467
+  uint32_t count = 1;
468
+  uint32_t bitcounter;
469
+
470
+  /*  if (bits) { always set! */
471
+  bitcounter = bits;
472
+  while (bitcounter--)
473
+    count = count*2 + getbit_from_table(&intable[count], read_struct);
474
+  /*  } */
475
+  
476
+  return count-(1<<(bits&0xff));
477
+}
478
+
479
+
480
+uint32_t get_n_bits_from_tablesize(uint16_t *intable, struct UNSP *read_struct, uint32_t backsize) {
481
+  
482
+  if (!getbit_from_table(intable, read_struct))
483
+    return get_n_bits_from_table(&intable[(backsize<<3)+2], 3, read_struct);
484
+  
485
+  if (!getbit_from_table(&intable[1], read_struct))
486
+    return 8+get_n_bits_from_table(&intable[(backsize<<3)+0x82], 3, read_struct);
487
+
488
+  return 0x10+get_n_bits_from_table(&intable[0x102], 8, read_struct);
489
+}
490
+
491
+
492
+uint32_t get_bb(uint16_t *intable, uint32_t back, struct UNSP *read_struct) {
493
+  uint32_t pos = 1;
494
+  uint32_t bb = 0;
495
+  uint32_t i;
496
+
497
+  if ((int32_t)back<=0) /* signed */
498
+    return 0;
499
+  
500
+  for (i=0;i<back;i++) {
501
+    uint32_t bit = getbit_from_table(&intable[pos], read_struct);
502
+    pos=(pos*2) + bit;
503
+    bb|=(bit<<i);
504
+  }
505
+  return bb;
506
+}
507
+
508
+
509
+uint32_t get_bitmap(struct UNSP *read_struct, uint32_t bits) {
510
+  uint32_t retv = 0;
511
+
512
+  if ((int32_t)bits<=0) return 0; /* signed */
513
+
514
+  while (bits--) {
515
+    read_struct->bitmap>>=1; /* unsigned */
516
+    retv<<=1;
517
+    if (read_struct->oldval>=read_struct->bitmap) { /* unsigned */
518
+      read_struct->oldval-=read_struct->bitmap;
519
+      retv|=1;
520
+    }
521
+    if (read_struct->bitmap<0x1000000) {
522
+      read_struct->bitmap<<=8;
523
+      read_struct->oldval = (read_struct->oldval<<8) | get_byte(read_struct);
524
+    }
525
+  }
526
+  return retv;
527
+}
528
+
529
+#endif
0 530
new file mode 100644
... ...
@@ -0,0 +1,50 @@
0
+/*
1
+ *  Copyright (C) 2006 aCaB <acab@clamav.net>
2
+ *
3
+ *  This program is free software; you can redistribute it and/or modify
4
+ *  it under the terms of the GNU General Public License as published by
5
+ *  the Free Software Foundation; either version 2 of the License, or
6
+ *  (at your option) any later version.
7
+ *
8
+ *  This program is distributed in the hope that it will be useful,
9
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
+ *  GNU General Public License for more details.
12
+ *
13
+ *  You should have received a copy of the GNU General Public License
14
+ *  along with this program; if not, write to the Free Software
15
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16
+ *  MA 02110-1301, USA.
17
+ */
18
+
19
+#ifdef CL_EXPERIMENTAL
20
+#ifndef __UNSP_H
21
+#define __UNSP_H
22
+
23
+#include "cltypes.h"
24
+#include "others.h"
25
+
26
+struct UNSP {
27
+  char *src_curr;
28
+  char *src_end;
29
+  uint32_t bitmap;
30
+  uint32_t oldval;
31
+  int error;
32
+  /* the following are not in the original structure */
33
+  char *table;
34
+  uint32_t tablesz;
35
+};
36
+
37
+uint32_t unspack(char *, char *, cli_ctx *, uint32_t, uint32_t, uint32_t, int);
38
+uint32_t very_real_unpack(uint16_t *, uint32_t, uint32_t, uint32_t, uint32_t, char *, uint32_t, char *, uint32_t);
39
+uint32_t get_byte(struct UNSP *);
40
+int getbit_from_table(uint16_t *, struct UNSP *);
41
+uint32_t get_100_bits_from_tablesize(uint16_t *, struct UNSP *, uint32_t);
42
+uint32_t get_100_bits_from_table(uint16_t *, struct UNSP *);
43
+uint32_t get_n_bits_from_table(uint16_t *, uint32_t, struct UNSP *);
44
+uint32_t get_n_bits_from_tablesize(uint16_t *, struct UNSP *, uint32_t);
45
+uint32_t get_bb(uint16_t *, uint32_t, struct UNSP *);
46
+uint32_t get_bitmap(struct UNSP *, uint32_t);
47
+
48
+#endif
49
+#endif