Browse code

Improved UPX rebuild capabilities

git-svn: trunk@1989

aCaB authored on 2006/05/24 04:54:17
Showing 2 changed files
... ...
@@ -1,3 +1,8 @@
1
+Tue May 23 21:51:37 CEST 2006 (acab)
2
+------------------------------------
3
+  * libclamav/upx.c: Improved UPX unpacking capabilities and geneal cleanup
4
+                     Patch by Andrey J. Melnikoff
5
+
1 6
 Mon May 22 18:27:09 CEST 2006 (tk)
2 7
 ----------------------------------
3 8
   * libclamav/unzip.[ch]: new files
... ...
@@ -69,9 +69,16 @@
69 69
 \x63\x6C\x61\x6D\x61\x76\x2E\x6E\x65\x74\x0D\x0A\x24\x00\x00\x00\
70 70
 "
71 71
 
72
+#if WORDS_BIGENDIAN == 0
73
+#define CLI_READLE32(x) *(int32_t *)(x)
74
+#else
75
+#define CLI_READLE32(x) ((*x) >> 24) | ((*(x+1) & 0x00FF0000) >> 8) | \
76
+			    ((*(x+2) & 0x0000FF00) << 8) | (*(x) << 24))
77
+#endif
78
+
72 79
 /* PE from UPX */
73 80
 
74
-int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0, uint32_t upx1, uint32_t magic)
81
+static int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0, uint32_t upx1, uint32_t magic)
75 82
 {
76 83
   char *imports, *sections, *pehdr, *newbuf;
77 84
   int sectcnt, upd=1;
... ...
@@ -81,7 +88,7 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0
81 81
   if((dst == NULL) || (src == NULL))
82 82
     return 0;
83 83
 
84
-  imports = dst + cli_readint32(src + ep - upx1 + magic);
84
+  imports = dst + CLI_READLE32(src + ep - upx1 + magic);
85 85
 
86 86
   realstuffsz = imports-dst;
87 87
   
... ...
@@ -91,7 +98,7 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0
91 91
   }
92 92
   
93 93
   pehdr = imports;
94
-  while (CLI_ISCONTAINED(dst, *dsize,  pehdr, 8) && cli_readint32(pehdr)) {
94
+  while (CLI_ISCONTAINED(dst, *dsize,  pehdr, 8) && CLI_READLE32(pehdr)) {
95 95
     pehdr+=8;
96 96
     while(CLI_ISCONTAINED(dst, *dsize,  pehdr, 2) && *pehdr) {
97 97
       pehdr++;
... ...
@@ -107,13 +114,24 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0
107 107
     cli_dbgmsg("UPX: sections out of bounds - giving up rebuild\n");
108 108
     return 0;
109 109
   }
110
+
111
+  if ( CLI_READLE32(pehdr) != 0x4550 ) {
112
+    cli_dbgmsg("UPX: OOPS: no magic for PE - scanning\n");
113
+    while (CLI_ISCONTAINED(dst, *dsize,  pehdr, 2) && 
114
+	    CLI_READLE32(pehdr) != 0x4550) {
115
+	pehdr+=2;
116
+	while (CLI_ISCONTAINED(dst, *dsize,  pehdr, 2) && *pehdr)
117
+	    pehdr++;
118
+	pehdr++;
119
+    }
120
+  }
110 121
   
111
-  if ( cli_readint32(pehdr) != 0x4550 ) {
112
-    cli_dbgmsg("UPX: No magic for PE - giving up rebuild\n");
122
+  if (!CLI_ISCONTAINED(dst, *dsize,  pehdr, 0xf8)){
123
+    cli_dbgmsg("UPX: Magic for PE - not found, aborting!\n");
113 124
     return 0;
114 125
   }
115 126
   
116
-  if (! cli_readint32(pehdr+0x38)) {
127
+  if (! CLI_READLE32(pehdr+0x38)) {
117 128
     cli_dbgmsg("UPX: Cant align to a NULL bound - giving up rebuild\n");
118 129
     return 0;
119 130
   }
... ...
@@ -132,9 +150,9 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0
132 132
   }
133 133
   
134 134
   for (upd = 0; upd <sectcnt ; upd++) {
135
-    uint32_t vsize=cli_readint32(sections+8)-1;
136
-    uint32_t rsize=cli_readint32(sections+16);
137
-    uint32_t urva=cli_readint32(sections+12);
135
+    uint32_t vsize=CLI_READLE32(sections+8)-1;
136
+    uint32_t rsize=CLI_READLE32(sections+16);
137
+    uint32_t urva=CLI_READLE32(sections+12);
138 138
     
139 139
     vsize=(((vsize/0x1000)+1)*0x1000); /* FIXME: get bounds from header */
140 140
     
... ...
@@ -151,7 +169,7 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0
151 151
     }
152 152
     
153 153
     /* Am i been fooled? There are better ways ;) */
154
-    if ( rsize+4 < vsize && cli_readint32(dst+urva-upx0+rsize) ) {
154
+    if ( rsize+4 < vsize && CLI_READLE32(dst+urva-upx0+rsize) ) {
155 155
       cli_dbgmsg("UPX: Am i been fooled? - giving up rebuild\n", upd);
156 156
       return 0;
157 157
     }
... ...
@@ -174,7 +192,7 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0
174 174
   memcpy(newbuf+0xd0, pehdr,0xf8+0x28*sectcnt);
175 175
   sections = pehdr+0xf8;
176 176
   for (upd = 0; upd <sectcnt ; upd++) {
177
-    memcpy(newbuf+cli_readint32(sections+20), dst+cli_readint32(sections+12)-upx0, cli_readint32(sections+16));
177
+    memcpy(newbuf+CLI_READLE32(sections+20), dst+CLI_READLE32(sections+12)-upx0, CLI_READLE32(sections+16));
178 178
     sections+=0x28;
179 179
   }
180 180
 
... ...
@@ -189,6 +207,32 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0
189 189
   return 1;
190 190
 }
191 191
 
192
+static int upx_find_ep(char *src, uint32_t ssize, uint32_t upx1, uint32_t ep)
193
+{
194
+    int32_t len;
195
+    int i;
196
+
197
+    len = ssize - (ep - upx1);
198
+
199
+    /* Verify decompressor length. Avoid crashing on multiple 
200
+     * compressed files. exe packed by UPX and PEC. */
201
+    if (!CLI_ISCONTAINED(src, ssize, src + ep - upx1, len))
202
+	return -1;
203
+
204
+    /* Shift to decompressor start */
205
+    src += (ep - upx1);
206
+        
207
+    for (i = 0xC0; i != len - 6; i++){
208
+	if ((CLI_READLE32(src+i) & 0x0000FFFF) == 0x0000BE8D){
209
+	    cli_dbgmsg("UPX: found at %p, off: %x val: %08x\n", src+i+6, i+6, CLI_READLE32(src+i+6));
210
+	    if (CLI_READLE32(src+i+6) == 0xC009078B){
211
+		return i+2;
212
+	    }
213
+	}
214
+    }
215
+    cli_dbgmsg("UPX: upx_find_ep %p, %d - FAILED!\n", src, len);
216
+    return -1;
217
+}
192 218
 
193 219
 /* [doubleebx] */
194 220
 
... ...
@@ -200,7 +244,7 @@ static int doubleebx(char *src, int32_t *myebx, int *scur, int ssize)
200 200
   if ( !(oldebx & 0x7fffffff)) {
201 201
     if (! CLI_ISCONTAINED(src, ssize, src+*scur, 4))
202 202
       return -1;
203
-    oldebx = cli_readint32(src+*scur);
203
+    oldebx = CLI_READLE32(src+*scur);
204 204
     *myebx = oldebx*2+1;
205 205
     *scur+=4;
206 206
   }
... ...
@@ -283,11 +327,9 @@ int upx_inflate2b(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_
283 283
     dcur+=backsize;
284 284
   }
285 285
 
286
-
287
-  if ( ep - upx1 + 0x108 <= ssize-5  &&    /* Wondering how we got so far?! */
288
-       src[ep - upx1 + 0x106] == '\x8d' && /* lea edi, ...                  */
289
-       src[ep - upx1 + 0x107] == '\xbe' )  /* ... [esi + offset]          */
290
-    return pefromupx (src, dst, dsize, ep, upx0, upx1, 0x108);
286
+  scur = upx_find_ep(src, ssize, upx1, ep);
287
+  if (scur != -1)
288
+    return pefromupx (src, dst, dsize, ep, upx0, upx1, scur);
291 289
 
292 290
   cli_dbgmsg("UPX: bad magic for 2b\n");
293 291
   return 0;
... ...
@@ -373,12 +415,10 @@ int upx_inflate2d(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_
373 373
     dcur+=backsize;
374 374
   }
375 375
 
376
-  if ( ep - upx1 + 0x124 <= ssize-5 ) {   /* Wondering how we got so far?! */
377
-    if ( src[ep - upx1 + 0x11a] == '\x8d' && src[ep - upx1 + 0x11b] == '\xbe' )
378
-      return pefromupx (src, dst, dsize, ep, upx0, upx1, 0x11c);
379
-    if ( src[ep - upx1 + 0x122] == '\x8d' && src[ep - upx1 + 0x123] == '\xbe' )
380
-      return pefromupx (src, dst, dsize, ep, upx0, upx1, 0x124);
381
-  }
376
+  scur = upx_find_ep(src, ssize, upx1, ep);
377
+  if (scur != -1)
378
+    return pefromupx (src, dst, dsize, ep, upx0, upx1, scur);
379
+
382 380
   cli_dbgmsg("UPX: bad magic for 2d\n");
383 381
   return 0;
384 382
 }
... ...
@@ -472,12 +512,10 @@ int upx_inflate2e(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_
472 472
     dcur+=backsize;
473 473
   }
474 474
 
475
-  if ( ep - upx1 + 0x130 <= ssize-5 ) {   /* Wondering how we got so far?! */
476
-    if ( src[ep - upx1 + 0x126] == '\x8d' && src[ep - upx1 + 0x127] == '\xbe' )
477
-      return pefromupx (src, dst, dsize, ep, upx0, upx1, 0x128);
478
-    if ( src[ep - upx1 + 0x12e] == '\x8d' && src[ep - upx1 + 0x12f] == '\xbe' )
479
-      return pefromupx (src, dst, dsize, ep, upx0, upx1, 0x130);
480
-  }
475
+  scur = upx_find_ep(src, ssize, upx1, ep);
476
+  if (scur != -1)
477
+    return pefromupx (src, dst, dsize, ep, upx0, upx1, scur);
478
+
481 479
   cli_dbgmsg("UPX: bad magic for 2e\n");
482 480
   return 0;
483 481
 }