git-svn: trunk@1989
aCaB authored on 2006/05/24 04:54:17... | ... |
@@ -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 |
} |