/src/clamav/libclamav/mew.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2013-2023 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
3 | | * Copyright (C) 2007-2013 Sourcefire, Inc. |
4 | | * |
5 | | * Authors: Michal 'GiM' Spadlinski |
6 | | * |
7 | | * This program is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU General Public License version 2 as |
9 | | * published by the Free Software Foundation. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
19 | | * MA 02110-1301, USA. |
20 | | */ |
21 | | |
22 | | /* |
23 | | * lzma.c |
24 | | * |
25 | | * o2:28:18 CEST 2oo6-25-o6 - initial 0xA4/0x536 |
26 | | * oo:29:4o CEST 2oo6-26-o6 - 0x1cd/0x536 [+0x129] |
27 | | * o2:13:19 CEST 2oo6-o1-o7, 2oo6-3o-o6 - 0x536/0x536 |
28 | | * |
29 | | */ |
30 | | |
31 | | #if HAVE_CONFIG_H |
32 | | #include "clamav-config.h" |
33 | | #endif |
34 | | |
35 | | #include <stdio.h> |
36 | | #ifdef HAVE_STDLIB_H |
37 | | #include <stdlib.h> |
38 | | #endif |
39 | | #ifdef HAVE_SYS_TYPES_H |
40 | | #include <sys/types.h> |
41 | | #endif |
42 | | #ifdef HAVE_SYS_STAT_H |
43 | | #include <sys/stat.h> |
44 | | #endif |
45 | | #ifdef HAVE_UNISTD_H |
46 | | #include <unistd.h> |
47 | | #endif |
48 | | #ifdef HAVE_STRING_H |
49 | | #include <string.h> |
50 | | #endif |
51 | | |
52 | | #include "clamav.h" |
53 | | #include "pe.h" |
54 | | #include "others.h" |
55 | | #include "mew.h" |
56 | | #include "packlibs.h" |
57 | | #include "rebuildpe.h" |
58 | | |
59 | 373 | #define EC32(x) le32_to_host(x) /* Convert little endian to host */ |
60 | | #define CE32(x) be32_to_host(x) /* Convert big endian to host */ |
61 | | #define PEALIGN(o, a) (((a)) ? (((o) / (a)) * (a)) : (o)) |
62 | 133 | #define PESALIGN(o, a) (((a)) ? (((o) / (a) + ((o) % (a) != 0)) * (a)) : (o)) |
63 | | |
64 | | /* modifies all parameters */ |
65 | | /* northfox does this shitty way, |
66 | | * this should be done with just a bswap |
67 | | */ |
68 | | static const char *lzma_bswap_4861dc(struct lzmastate *p, const char *old_edx) |
69 | 373 | { |
70 | | /* dumb_dump_start |
71 | | * |
72 | | |
73 | | old_edx was 'uint32_t *' before and in mew_lzma there was |
74 | | &new_edx where new_edx = var1C |
75 | | |
76 | | uint32_t loc_esi, loc_edi; |
77 | | uint8_t *loc_eax; |
78 | | |
79 | | p->p2 = loc_esi = 0; |
80 | | p->p0 = loc_eax = (uint8_t *)*old_edx; |
81 | | *old_edx = 5; |
82 | | do { |
83 | | loc_esi = p->p2 << 8; |
84 | | loc_edi = *(uint8_t *)((loc_eax)++); |
85 | | loc_esi |= loc_edi; |
86 | | (*old_edx)--; |
87 | | p->p2 = loc_esi; |
88 | | } while (*old_edx); |
89 | | p->p0 = loc_eax; |
90 | | p->p1 = 0xffffffff; |
91 | | |
92 | | * dumb_dump_end |
93 | | */ |
94 | | |
95 | | /* XXX, mine replacement */ |
96 | 373 | p->p2 = EC32(CE32(((uint32_t)cli_readint32(old_edx + 1)))); |
97 | 373 | p->p1 = 0xffffffff; |
98 | 373 | p->p0 = old_edx + 5; |
99 | | |
100 | 373 | return p->p0; |
101 | 373 | } |
102 | | |
103 | | static uint32_t lzma_486248(struct lzmastate *p, const char **old_ecx, char *src, uint32_t size) |
104 | 1.07M | { |
105 | 1.07M | uint32_t loc_esi, loc_edi, loc_eax, loc_ecx, ret; |
106 | 1.07M | if (!CLI_ISCONTAINED(src, size, *old_ecx, 4) || !CLI_ISCONTAINED(src, size, p->p0, 1)) |
107 | 12 | return 0xffffffff; |
108 | 1.07M | loc_esi = p->p1; |
109 | 1.07M | loc_eax = loc_esi >> 0xb; |
110 | 1.07M | loc_ecx = cli_readint32(*old_ecx); |
111 | 1.07M | ret = loc_ecx & 0xffff; |
112 | 1.07M | (loc_eax) *= ret; |
113 | 1.07M | loc_edi = p->p2; |
114 | 1.07M | if (loc_edi < loc_eax) { |
115 | | /* 48625f */ |
116 | 693k | p->p1 = loc_eax; |
117 | 693k | loc_esi = ret; |
118 | 693k | loc_edi = ((int32_t)(0x800 - ret) >> 5) + ((loc_eax & 0xffff0000) | ret); |
119 | | /* signed<-sar, &|<-mov ax, [ecx] */ |
120 | 693k | loc_ecx = (loc_ecx & 0xffff0000) | (loc_edi & 0xffff); |
121 | 693k | cli_writeint32(*old_ecx, loc_ecx); |
122 | | |
123 | 693k | ret = 0; |
124 | 693k | } else { |
125 | | /* 48629e */ |
126 | 379k | loc_esi -= loc_eax; |
127 | 379k | loc_edi -= loc_eax; |
128 | 379k | p->p1 = loc_esi; |
129 | 379k | p->p2 = loc_edi; |
130 | 379k | loc_eax = (loc_eax & 0xffff0000) | ret; |
131 | 379k | loc_esi = (loc_esi & 0xffff0000) | (ret >> 5); |
132 | 379k | loc_eax -= loc_esi; |
133 | | |
134 | 379k | loc_ecx = (loc_ecx & 0xffff0000) | (loc_eax & 0xffff); |
135 | 379k | cli_writeint32(*old_ecx, loc_ecx); |
136 | | |
137 | 379k | ret = 1; |
138 | 379k | } |
139 | 1.07M | loc_eax = p->p1; |
140 | 1.07M | if (loc_eax < 0x1000000) { |
141 | 20.3k | *old_ecx = p->p0; |
142 | 20.3k | loc_edi = (*(uint8_t *)(p->p0)); |
143 | 20.3k | loc_esi = ((p->p2) << 8) | loc_edi; |
144 | 20.3k | (*old_ecx)++; |
145 | 20.3k | loc_eax <<= 8; |
146 | 20.3k | p->p2 = loc_esi; |
147 | 20.3k | p->p1 = loc_eax; |
148 | 20.3k | p->p0 = *old_ecx; |
149 | 20.3k | } |
150 | 1.07M | return ret; |
151 | 1.07M | } |
152 | | |
153 | | static uint32_t lzma_48635C(uint8_t znaczek, const char **old_ecx, struct lzmastate *p, uint32_t *retval, char *src, uint32_t size) |
154 | 3.02k | { |
155 | 3.02k | uint32_t loc_esi = (znaczek & 0xff) >> 7, /* msb */ |
156 | 3.02k | loc_ebx, ret; |
157 | 3.02k | const char *loc_edi; |
158 | 3.02k | znaczek <<= 1; |
159 | 3.02k | ret = loc_esi << 9; |
160 | 3.02k | loc_edi = *old_ecx; |
161 | 3.02k | *old_ecx = loc_edi + ret + 0x202; |
162 | 3.02k | if ((ret = lzma_486248(p, old_ecx, src, size)) == 0xffffffff) |
163 | 0 | return 0xffffffff; |
164 | 3.02k | loc_ebx = ret | 2; |
165 | | |
166 | 12.1k | while (loc_esi == ret) { |
167 | 9.67k | if (loc_ebx >= 0x100) { |
168 | 554 | ret = (ret & 0xffffff00) | (loc_ebx & 0xff); |
169 | 554 | *retval = ret; |
170 | 554 | return 0; |
171 | 554 | } |
172 | 9.11k | loc_esi = (znaczek & 0xff) >> 7; |
173 | 9.11k | znaczek <<= 1; |
174 | 9.11k | ret = ((loc_esi + 1) << 8) + loc_ebx; |
175 | 9.11k | *old_ecx = loc_edi + ret * 2; |
176 | 9.11k | if ((ret = lzma_486248(p, old_ecx, src, size)) == 0xffffffff) |
177 | 0 | return 0xffffffff; |
178 | 9.11k | loc_ebx += loc_ebx; |
179 | 9.11k | loc_ebx |= ret; |
180 | 9.11k | } |
181 | 2.46k | loc_esi = 0x100; |
182 | 14.5k | while (loc_ebx < loc_esi) { |
183 | 12.0k | loc_ebx += loc_ebx; |
184 | 12.0k | *old_ecx = loc_edi + loc_ebx; |
185 | 12.0k | if ((ret = lzma_486248(p, old_ecx, src, size)) == 0xffffffff) |
186 | 0 | return 0xffffffff; |
187 | 12.0k | loc_ebx |= ret; |
188 | 12.0k | } |
189 | 2.46k | ret = (ret & 0xffffff00) | (loc_ebx & 0xff); |
190 | 2.46k | *retval = ret; |
191 | 2.46k | return 0; |
192 | 2.46k | } |
193 | | |
194 | | static uint32_t lzma_4862e0(struct lzmastate *p, const char **old_ecx, uint32_t *old_edx, uint32_t *retval, char *src, uint32_t size) |
195 | 106k | { |
196 | 106k | uint32_t loc_ebx, loc_esi, stack_ecx, ret; |
197 | 106k | const char *loc_edi; |
198 | | |
199 | 106k | loc_ebx = *old_edx; |
200 | 106k | ret = 1; |
201 | 106k | loc_edi = *old_ecx; |
202 | 106k | if (loc_ebx && !(loc_ebx & 0x80000000)) { |
203 | | /* loc_4862f1 */ |
204 | 106k | stack_ecx = loc_ebx; |
205 | 328k | do { |
206 | 328k | loc_esi = ret + ret; |
207 | 328k | *old_ecx = loc_edi + loc_esi; |
208 | 328k | if ((ret = lzma_486248(p, old_ecx, src, size)) == 0xffffffff) |
209 | 0 | return 0xffffffff; |
210 | 328k | ret += loc_esi; |
211 | 328k | stack_ecx--; |
212 | 328k | } while (stack_ecx); |
213 | 106k | } |
214 | | /* loc_48630b */ |
215 | | /* unneeded |
216 | | *old_ecx = (uint8_t *)loc_ebx; |
217 | | */ |
218 | | |
219 | 106k | *old_edx = 1 << (loc_ebx & 0xff); |
220 | 106k | ret -= *old_edx; |
221 | 106k | *retval = ret; |
222 | 106k | return 0; |
223 | 106k | } |
224 | | |
225 | | /* old_edx - write only */ |
226 | | static uint32_t lzma_4863da(uint32_t var0, struct lzmastate *p, const char **old_ecx, uint32_t *old_edx, uint32_t *retval, char *src, uint32_t size) |
227 | 104k | { |
228 | 104k | uint32_t ret; |
229 | 104k | const char *loc_esi = *old_ecx; |
230 | | |
231 | 104k | if ((ret = lzma_486248(p, old_ecx, src, size)) == 0xffffffff) |
232 | 3 | return -1; |
233 | 104k | if (ret) { |
234 | | /* loc_4863ff */ |
235 | 1.84k | *old_ecx = loc_esi + 2; |
236 | 1.84k | if ((ret = lzma_486248(p, old_ecx, src, size)) == 0xffffffff) |
237 | 0 | return -1; |
238 | 1.84k | if (ret) { |
239 | | /* loc_486429 */ |
240 | 1.02k | *old_edx = 8; |
241 | 1.02k | *old_ecx = loc_esi + 0x204; |
242 | 1.02k | if (lzma_4862e0(p, old_ecx, old_edx, &ret, src, size) == 0xffffffff) |
243 | 0 | return -1; |
244 | 1.02k | ret += 0x10; |
245 | 1.02k | } else { |
246 | | /* loc_48640e */ |
247 | 823 | ret = var0 << 4; |
248 | 823 | *old_edx = 3; |
249 | 823 | *old_ecx = loc_esi + 0x104 + ret; |
250 | 823 | if (lzma_4862e0(p, old_ecx, old_edx, &ret, src, size) == 0xffffffff) |
251 | 0 | return -1; |
252 | 823 | ret += 0x8; |
253 | 823 | } |
254 | 102k | } else { |
255 | | /* loc_4863e9 */ |
256 | 102k | ret = var0 << 4; |
257 | 102k | *old_edx = 3; |
258 | 102k | *old_ecx = loc_esi + 0x4 + ret; |
259 | 102k | if (lzma_4862e0(p, old_ecx, old_edx, &ret, src, size) == 0xffffffff) |
260 | 0 | return -1; |
261 | 102k | } |
262 | 104k | *retval = ret; |
263 | 104k | return 0; |
264 | 104k | } |
265 | | |
266 | | static uint32_t lzma_486204(struct lzmastate *p, uint32_t old_edx, uint32_t *retval, char *src, uint32_t size) |
267 | 350 | { |
268 | 350 | uint32_t loc_esi, loc_edi, loc_ebx, loc_eax; |
269 | 350 | const char *loc_edx; |
270 | 350 | loc_esi = p->p1; |
271 | 350 | loc_edi = p->p2; |
272 | 350 | loc_eax = 0; |
273 | 350 | if (old_edx && !(old_edx & 0x80000000)) { |
274 | | /* loc_4866212 */ |
275 | 350 | loc_ebx = old_edx; |
276 | 4.00k | do { |
277 | 4.00k | loc_esi >>= 1; |
278 | 4.00k | loc_eax <<= 1; |
279 | 4.00k | if (loc_edi >= loc_esi) { |
280 | 1.89k | loc_edi -= loc_esi; |
281 | 1.89k | loc_eax |= 1; |
282 | 1.89k | } |
283 | | /* loc_486222 */ |
284 | 4.00k | if (loc_esi < 0x1000000) { |
285 | 474 | if (!CLI_ISCONTAINED(src, size, p->p0, 1)) |
286 | 0 | return 0xffffffff; |
287 | 474 | loc_edx = p->p0; |
288 | 474 | loc_edi <<= 8; |
289 | 474 | loc_esi <<= 8; |
290 | 474 | loc_edi |= (*loc_edx) & 0xff; /* movzx ebp, byte ptr [edx] */ |
291 | 474 | p->p0 = ++loc_edx; |
292 | 474 | } |
293 | 4.00k | loc_ebx--; |
294 | 4.00k | } while (loc_ebx); |
295 | 350 | } |
296 | 350 | p->p2 = loc_edi; |
297 | 350 | p->p1 = loc_esi; |
298 | 350 | *retval = loc_eax; |
299 | 350 | return 0; |
300 | 350 | } |
301 | | |
302 | | static uint32_t lzma_48631a(struct lzmastate *p, const char **old_ecx, uint32_t *old_edx, uint32_t *retval, char *src, uint32_t size) |
303 | 415 | { |
304 | 415 | uint32_t copy1, copy2; |
305 | 415 | uint32_t loc_esi, loc_edi, ret; |
306 | 415 | const char *loc_ebx; |
307 | | |
308 | 415 | copy1 = *old_edx; |
309 | 415 | loc_edi = 0; |
310 | 415 | loc_ebx = *old_ecx; |
311 | 415 | *old_edx = 1; |
312 | 415 | copy2 = (uint32_t)loc_edi; |
313 | | |
314 | 415 | if (copy1 <= (uint32_t)loc_edi) { |
315 | 0 | *retval = copy2; |
316 | 0 | return 0; |
317 | 0 | } |
318 | | |
319 | 1.54k | do { |
320 | 1.54k | loc_esi = *old_edx + *old_edx; |
321 | 1.54k | *old_ecx = loc_esi + loc_ebx; |
322 | 1.54k | if ((ret = lzma_486248(p, old_ecx, src, size)) == 0xffffffff) |
323 | 0 | return 0xffffffff; |
324 | | /* unneeded *old_ecx = loc_edi; */ |
325 | 1.54k | *old_edx = loc_esi + ret; |
326 | | /* ret <<= (uint32_t)(*old_ecx)&0xff; */ |
327 | 1.54k | ret <<= (loc_edi & 0xff); |
328 | 1.54k | copy2 |= ret; |
329 | 1.54k | loc_edi++; |
330 | 1.54k | } while (loc_edi < copy1); |
331 | | |
332 | 415 | *retval = copy2; |
333 | 415 | return 0; |
334 | 415 | } |
335 | | |
336 | | int mew_lzma(char *orgsource, const char *buf, uint32_t size_sum, uint32_t vma, uint32_t special) |
337 | 396 | { |
338 | 396 | uint32_t var08, var0C, var10, var14, var20, var24, var28, var34; |
339 | 396 | struct lzmastate var40; |
340 | 396 | uint32_t new_eax, new_edx, temp; |
341 | 396 | int i, mainloop; |
342 | | |
343 | 396 | char var1; |
344 | 396 | const char *source = buf; |
345 | 396 | char *dest, *new_ebx; |
346 | 396 | const char *new_ecx, *var0C_ecxcopy; |
347 | 396 | const char *var2C; |
348 | 396 | char *pushed_esi = NULL; |
349 | 396 | const char *pushed_ebx = NULL; |
350 | 396 | uint32_t pushed_edx = 0; |
351 | | |
352 | 396 | uint32_t loc_esi, loc_edi; |
353 | 396 | uint8_t *var18; |
354 | | |
355 | 396 | if (special) { |
356 | 0 | pushed_edx = cli_readint32(source); |
357 | 0 | source += 4; |
358 | 0 | } |
359 | 396 | temp = cli_readint32(source) - vma; |
360 | 396 | source += 4; |
361 | 396 | if (!special) pushed_ebx = source; |
362 | 396 | new_ebx = orgsource + temp; |
363 | | |
364 | 408 | do { |
365 | 408 | mainloop = 1; |
366 | 408 | do { |
367 | | /* loc_486450 */ |
368 | 408 | if (!special) { |
369 | 408 | source = pushed_ebx; |
370 | 408 | if (!CLI_ISCONTAINED(orgsource, size_sum, source, 16)) |
371 | 6 | return -1; |
372 | | |
373 | 402 | if (cli_readint32(source) == 0) { |
374 | 19 | return 0; |
375 | 19 | } |
376 | 402 | } else { |
377 | 0 | if (!CLI_ISCONTAINED(orgsource, size_sum, source, 12)) |
378 | 0 | return -1; |
379 | 0 | } |
380 | | |
381 | 383 | var28 = cli_readint32(source); |
382 | 383 | source += 4; |
383 | 383 | temp = cli_readint32(source) - vma; |
384 | 383 | var18 = (uint8_t *)(orgsource + temp); |
385 | 383 | if (special) pushed_esi = orgsource + temp; |
386 | 383 | source += 4; |
387 | 383 | temp = cli_readint32(source); |
388 | 383 | source += 5; /* yes, five */ |
389 | 383 | var2C = source; |
390 | 383 | source += temp; |
391 | 383 | if (special) |
392 | 0 | pushed_ebx = source; |
393 | 383 | else |
394 | 383 | pushed_ebx = source; |
395 | 383 | var1 = 0; |
396 | 383 | dest = new_ebx; |
397 | | |
398 | 383 | if (!CLI_ISCONTAINED(orgsource, size_sum, dest, 0x6E6C)) |
399 | 10 | return -1; |
400 | 2.63M | for (i = 0; i < 0x1b9b; i++) { |
401 | 2.63M | cli_writeint32(dest, 0x4000400); |
402 | 2.63M | dest += 4; |
403 | 2.63M | } |
404 | 373 | loc_esi = 0; |
405 | 373 | var08 = var20 = 0; |
406 | 373 | loc_edi = 1; |
407 | 373 | var14 = var10 = var24 = 1; |
408 | | |
409 | 373 | if (!CLI_ISCONTAINED(orgsource, size_sum, var2C, 5)) |
410 | 0 | return -1; |
411 | 373 | lzma_bswap_4861dc(&var40, var2C); |
412 | 373 | new_edx = 0; |
413 | 373 | } while (var28 <= loc_esi); /* source = 0 */ |
414 | | |
415 | 373 | cli_dbgmsg("MEWlzma: entering do while loop\n"); |
416 | 127k | do { |
417 | | /* loc_4864a5 */ |
418 | 127k | new_eax = var08 & 3; |
419 | 127k | new_ecx = (((loc_esi << 4) + new_eax) * 2) + new_ebx; |
420 | 127k | var0C = new_eax; |
421 | 127k | if ((new_eax = lzma_486248(&var40, &new_ecx, orgsource, size_sum)) == 0xffffffff) |
422 | 1 | return -1; |
423 | 127k | if (new_eax) { |
424 | | /* loc_486549 */ |
425 | 105k | new_ecx = new_ebx + loc_esi * 2 + 0x180; |
426 | 105k | var20 = 1; |
427 | | /* eax=1 */ |
428 | 105k | if ((new_eax = lzma_486248(&var40, &new_ecx, orgsource, size_sum)) == 0xffffffff) |
429 | 0 | return -1; |
430 | 105k | if (new_eax != 1) { |
431 | | /* loc_486627 */ |
432 | 1.61k | var24 = var10; |
433 | 1.61k | var10 = var14; |
434 | | /* xor eax,eax; cmp esi, 7; setnl al; dec eax; add eax, 0Ah */ |
435 | | /* new_eax = (((loc_esi >= 7)-1)&0xFFFFFFFD) + 0xA; */ |
436 | 1.61k | new_eax = loc_esi >= 7 ? 10 : 7; |
437 | 1.61k | new_ecx = new_ebx + 0x664; |
438 | 1.61k | var14 = loc_edi; |
439 | 1.61k | loc_esi = new_eax; |
440 | 1.61k | if (lzma_4863da(var0C, &var40, &new_ecx, &new_edx, &new_eax, orgsource, size_sum) == 0xffffffff) |
441 | 1 | return -1; |
442 | 1.60k | var0C = new_eax; |
443 | 1.60k | if (var0C >= 4) |
444 | 580 | new_eax = 3; |
445 | | |
446 | | /* loc_486662 */ |
447 | 1.60k | new_edx = 6; |
448 | 1.60k | new_eax <<= 7; |
449 | 1.60k | new_ecx = new_eax + new_ebx + 0x360; |
450 | 1.60k | if (lzma_4862e0(&var40, &new_ecx, &new_edx, &new_eax, orgsource, size_sum) == 0xffffffff) |
451 | 0 | return -1; |
452 | 1.60k | if (new_eax < 4) { |
453 | | /* loc_4866ca */ |
454 | 1.19k | loc_edi = new_eax; |
455 | 1.19k | } else { |
456 | | /* loc_48667d */ |
457 | 415 | uint32_t loc_ecx; |
458 | 415 | loc_ecx = ((int32_t)new_eax >> 1) - 1; /* sar */ |
459 | 415 | loc_edi = ((new_eax & 1) | 2) << (loc_ecx & 0xff); |
460 | 415 | if (new_eax >= 0xe) { |
461 | | /* loc_4866ab */ |
462 | 350 | new_edx = loc_ecx - 4; |
463 | 350 | if (lzma_486204(&var40, new_edx, &new_eax, orgsource, size_sum) == 0xffffffff) |
464 | 0 | return -1; |
465 | 350 | loc_edi += new_eax << 4; |
466 | | |
467 | 350 | new_edx = 4; |
468 | 350 | new_ecx = new_ebx + 0x644; |
469 | 350 | } else { |
470 | | /* loc_486691 */ |
471 | 65 | new_edx = loc_ecx; |
472 | 65 | loc_ecx = loc_edi - new_eax; |
473 | 65 | new_ecx = new_ebx + loc_ecx * 2 + 0x55e; |
474 | 65 | } |
475 | | /* loc_4866a2 */ |
476 | 415 | if (lzma_48631a(&var40, &new_ecx, &new_edx, &new_eax, orgsource, size_sum) == 0xffffffff) |
477 | 0 | return -1; |
478 | 415 | loc_edi += new_eax; |
479 | 415 | } |
480 | 1.60k | loc_edi++; |
481 | 103k | } else { |
482 | | /* loc_486568 */ |
483 | 103k | new_ecx = new_ebx + loc_esi * 2 + 0x198; |
484 | 103k | if ((new_eax = lzma_486248(&var40, &new_ecx, orgsource, size_sum)) == 0xffffffff) |
485 | 0 | return -1; |
486 | 103k | if (new_eax) { |
487 | | /* loc_4865bd */ |
488 | 102k | new_ecx = new_ebx + loc_esi * 2 + 0x1B0; |
489 | 102k | if ((new_eax = lzma_486248(&var40, &new_ecx, orgsource, size_sum)) == 0xffffffff) |
490 | 1 | return -1; |
491 | 102k | if (new_eax) { |
492 | | /* loc_4865d2 */ |
493 | 14.3k | new_ecx = new_ebx + loc_esi * 2 + 0x1C8; |
494 | 14.3k | if ((new_eax = lzma_486248(&var40, &new_ecx, orgsource, size_sum)) == 0xffffffff) |
495 | 1 | return -1; |
496 | 14.3k | if (new_eax) { |
497 | | /* loc_4865ea */ |
498 | 3.80k | new_eax = var24; |
499 | 3.80k | var24 = var10; |
500 | 10.5k | } else { |
501 | | /* loc_4865e5 */ |
502 | 10.5k | new_eax = var10; |
503 | 10.5k | } |
504 | | /* loc_4865f3 */ |
505 | 14.3k | var10 = var14; |
506 | 88.2k | } else { |
507 | | /* loc_4865cd */ |
508 | 88.2k | new_eax = var14; |
509 | 88.2k | } |
510 | | /* loc_4865f9 */ |
511 | 102k | var14 = loc_edi; |
512 | 102k | loc_edi = new_eax; |
513 | 102k | } else { |
514 | | /* loc_48657e */ |
515 | 925 | new_eax = ((loc_esi + 0xf) << 4) + var0C; |
516 | 925 | new_ecx = new_ebx + new_eax * 2; |
517 | 925 | if ((new_eax = lzma_486248(&var40, &new_ecx, orgsource, size_sum)) == 0xffffffff) |
518 | 1 | return -1; |
519 | 924 | if (!new_eax) { |
520 | 510 | uint32_t loc_ecx; |
521 | | /* loc_486593 */ |
522 | 510 | loc_ecx = var08; |
523 | 510 | loc_ecx -= loc_edi; |
524 | | /* loc_esi = ((((loc_esi >= 7)-1)&0xFFFFFFFE) + 0xB); */ |
525 | 510 | loc_esi = loc_esi >= 7 ? 11 : 9; |
526 | 510 | if (!CLI_ISCONTAINED((uint8_t *)orgsource, size_sum, var18 + loc_ecx, 1)) |
527 | 0 | return -1; |
528 | 510 | var1 = *(var18 + loc_ecx); |
529 | 510 | loc_ecx = (loc_ecx & 0xffffff00) | var1; |
530 | | /* loc_4865af */ |
531 | 510 | new_edx = var08++; |
532 | 510 | if (!CLI_ISCONTAINED((uint8_t *)orgsource, size_sum, var18 + new_edx, 1)) |
533 | 0 | return -1; |
534 | 510 | *(var18 + new_edx) = loc_ecx & 0xff; |
535 | | |
536 | | /* loc_4866fe */ |
537 | 510 | new_eax = var08; |
538 | 510 | continue; /* !!! */ |
539 | 510 | } |
540 | 924 | } |
541 | | /* loc_4865fe */ |
542 | 102k | new_ecx = new_ebx + 0xa68; |
543 | 102k | if (lzma_4863da(var0C, &var40, &new_ecx, &new_edx, &new_eax, orgsource, size_sum) == 0xffffffff) |
544 | 2 | return -1; |
545 | 102k | var0C = new_eax; |
546 | | /* new_eax = (((loc_esi >= 7)-1)&0xFFFFFFFD) + 0xB; */ |
547 | 102k | new_eax = loc_esi >= 7 ? 11 : 8; |
548 | 102k | loc_esi = new_eax; |
549 | 102k | } |
550 | | /* loc_4866cd */ |
551 | 104k | if (!loc_edi) { |
552 | 0 | break; |
553 | 104k | } else { |
554 | 104k | var0C += 2; |
555 | 104k | new_ecx = (char *)var18; |
556 | 104k | new_edx = new_eax = var08; |
557 | 104k | new_eax -= loc_edi; |
558 | 104k | if (((var0C < var28 - new_edx) && |
559 | 104k | (!CLI_ISCONTAINED(orgsource, size_sum, (char *)(new_ecx + new_eax), var0C) || |
560 | 104k | !CLI_ISCONTAINED(orgsource, size_sum, (char *)(new_ecx + new_edx), var0C))) || |
561 | 104k | (!CLI_ISCONTAINED(orgsource, size_sum, (char *)(new_ecx + new_eax), var28 - new_edx) || |
562 | 104k | !CLI_ISCONTAINED(orgsource, size_sum, (char *)(new_ecx + new_edx), var28 - new_edx))) |
563 | 344 | return -1; |
564 | 323k | do { |
565 | 323k | var1 = *(uint8_t *)(new_ecx + new_eax); |
566 | 323k | *(uint8_t *)(new_ecx + new_edx) = var1; |
567 | | |
568 | 323k | new_edx++; |
569 | 323k | new_eax++; |
570 | 323k | var0C--; |
571 | 323k | if (var0C <= 0) |
572 | 104k | break; |
573 | 323k | } while (new_edx < var28); |
574 | 0 | var08 = new_edx; |
575 | 104k | } |
576 | 104k | } else { |
577 | | /* loc_4864C8 */ |
578 | 22.7k | new_eax = (((var1 & 0xff) >> 4) * 3) << 9; |
579 | 22.7k | new_ecx = new_eax + new_ebx + 0xe6c; |
580 | 22.7k | var0C_ecxcopy = new_ecx; |
581 | 22.7k | if (loc_esi >= 4) { |
582 | | /* loc_4864e8 */ |
583 | 5.22k | if (loc_esi >= 10) |
584 | 587 | loc_esi -= 6; |
585 | 4.63k | else |
586 | 4.63k | loc_esi -= 3; |
587 | | |
588 | 17.5k | } else { |
589 | | /* loc_4864e4 */ |
590 | 17.5k | loc_esi = 0; |
591 | 17.5k | } |
592 | | |
593 | 22.7k | if (var20 == 0) { |
594 | | /* loc_48651D */ |
595 | 19.7k | new_eax = 1; |
596 | 158k | do { |
597 | | /* loc_486525 */ |
598 | | /*new_ecx = var0C_ecxcopy;*/ |
599 | 158k | new_eax += new_eax; |
600 | 158k | new_ecx += new_eax; |
601 | 158k | var34 = new_eax; |
602 | 158k | if ((new_eax = lzma_486248(&var40, &new_ecx, orgsource, size_sum)) == 0xffffffff) |
603 | 5 | return -1; |
604 | 158k | new_eax |= var34; |
605 | | /* loc_486522 */ |
606 | | /* keeping it here instead of at the top |
607 | | * seems to work faster |
608 | | */ |
609 | 158k | if (new_eax < 0x100) { |
610 | 138k | new_ecx = var0C_ecxcopy; |
611 | 138k | } |
612 | 158k | } while (new_eax < 0x100); |
613 | | /* loc_48653e */ |
614 | 19.7k | var1 = (uint8_t)(new_eax & 0xff); |
615 | 19.7k | } else { |
616 | 3.02k | int t; |
617 | | /* loc_4864FB */ |
618 | 3.02k | new_eax = var08 - loc_edi; |
619 | 3.02k | if (!CLI_ISCONTAINED((uint8_t *)orgsource, size_sum, var18 + new_eax, 1)) |
620 | 0 | return -1; |
621 | 3.02k | t = *(var18 + new_eax); |
622 | 3.02k | new_eax = (new_eax & 0xffffff00) | t; |
623 | | |
624 | 3.02k | if (lzma_48635C(t, &new_ecx, &var40, &new_eax, orgsource, size_sum) == 0xffffffff) |
625 | 0 | return -1; |
626 | 3.02k | var20 = 0; |
627 | 3.02k | var1 = new_eax & 0xff; |
628 | 3.02k | } |
629 | | |
630 | | /* loc_486541 */ |
631 | | |
632 | | /* unneeded: new_ecx = (new_ecx&0xffffff00) | var1; */ |
633 | | |
634 | | /* loc_4865af */ |
635 | 22.7k | new_edx = var08++; |
636 | | |
637 | 22.7k | if (!CLI_ISCONTAINED((uint8_t *)orgsource, size_sum, var18 + new_edx, 1)) |
638 | 5 | return -1; |
639 | 22.7k | *(var18 + new_edx) = var1; |
640 | 22.7k | } |
641 | | /* loc_4866fe */ |
642 | 127k | new_eax = var08; |
643 | 127k | } while (new_eax < var28); |
644 | | |
645 | 12 | while (special) { |
646 | 0 | uint32_t loc_ecx; |
647 | | /* let's fix calls */ |
648 | 0 | cli_dbgmsg("MEWlen: %08x ? %08x\n", new_edx, pushed_edx); |
649 | |
|
650 | 0 | if (pushed_edx < 5 || !CLI_ISCONTAINED(orgsource, size_sum, pushed_esi, pushed_edx)) |
651 | 0 | return 0; /* No point in full failing just because we can't fixxup the calls */ |
652 | | |
653 | 0 | for (loc_ecx = 0; loc_ecx < pushed_edx - 5; loc_ecx++) { |
654 | | /* 0xe8, 0xe9 call opcodes */ |
655 | 0 | if (pushed_esi[loc_ecx] == '\xe8' || pushed_esi[loc_ecx] == '\xe9') { |
656 | 0 | char *adr = (char *)(pushed_esi + loc_ecx + 1); |
657 | |
|
658 | 0 | cli_writeint32(adr, EC32(CE32((uint32_t)cli_readint32(adr))) - loc_ecx - 1); |
659 | 0 | loc_ecx += 4; |
660 | 0 | } |
661 | 0 | } |
662 | 0 | return 0; /*pushed_edx;*/ |
663 | 0 | } |
664 | 12 | } while (mainloop); |
665 | | |
666 | 0 | return 0xbadc0de; |
667 | 396 | } |
668 | | |
669 | | /* UPack lzma */ |
670 | | |
671 | | /* compare with 486248 */ |
672 | | uint32_t lzma_upack_esi_00(struct lzmastate *p, char *old_ecx, char *bb, uint32_t bl) |
673 | 0 | { |
674 | 0 | uint32_t loc_eax, ret, loc_edi; |
675 | 0 | loc_eax = p->p1 >> 0xb; |
676 | 0 | if (!CLI_ISCONTAINED(bb, bl, old_ecx, 4) || !CLI_ISCONTAINED(bb, bl, p->p0, 4)) { |
677 | 0 | if (!CLI_ISCONTAINED(bb, bl, old_ecx, 4)) |
678 | 0 | cli_dbgmsg("contain error! %p %08x ecx: %p [%p]\n", bb, bl, old_ecx, bb + bl); |
679 | 0 | else |
680 | 0 | cli_dbgmsg("contain error! %p %08x p0: %p [%p]\n", bb, bl, p->p0, bb + bl); |
681 | 0 | return 0xffffffff; |
682 | 0 | } |
683 | 0 | ret = cli_readint32(old_ecx); |
684 | 0 | loc_eax *= ret; |
685 | 0 | loc_edi = cli_readint32((char *)p->p0); |
686 | 0 | loc_edi = EC32(CE32(loc_edi)); /* bswap */ |
687 | 0 | loc_edi -= p->p2; |
688 | 0 | if (loc_edi < loc_eax) { |
689 | 0 | p->p1 = loc_eax; |
690 | 0 | loc_eax = (0x800 - ret) >> 5; |
691 | 0 | cli_writeint32(old_ecx, cli_readint32(old_ecx) + loc_eax); |
692 | 0 | ret = 0; |
693 | 0 | } else { |
694 | 0 | p->p2 += loc_eax; |
695 | 0 | p->p1 -= loc_eax; |
696 | 0 | loc_eax = ret >> 5; |
697 | 0 | cli_writeint32(old_ecx, cli_readint32(old_ecx) - loc_eax); |
698 | 0 | ret = 1; |
699 | 0 | } |
700 | 0 | if (((p->p1) & 0xff000000) == 0) { |
701 | 0 | p->p2 <<= 8; |
702 | 0 | p->p1 <<= 8; |
703 | 0 | p->p0++; |
704 | 0 | } |
705 | 0 | return ret; |
706 | 0 | } |
707 | | |
708 | | /* compare with lzma_4862e0 */ |
709 | | /* lzma_upack_esi_4c 0x1 as eax! |
710 | | */ |
711 | | uint32_t lzma_upack_esi_50(struct lzmastate *p, uint32_t old_eax, uint32_t old_ecx, char **old_edx, char *old_ebp, uint32_t *retval, char *bs, uint32_t bl) |
712 | 0 | { |
713 | 0 | uint32_t loc_eax = old_eax, ret; |
714 | |
|
715 | 0 | do { |
716 | 0 | *old_edx = old_ebp + (loc_eax << 2); |
717 | 0 | if ((ret = lzma_upack_esi_00(p, *old_edx, bs, bl)) == 0xffffffff) |
718 | 0 | return 0xffffffff; |
719 | 0 | loc_eax += loc_eax; |
720 | 0 | loc_eax += ret; |
721 | 0 | } while (loc_eax < old_ecx); |
722 | | |
723 | 0 | *retval = loc_eax - old_ecx; |
724 | 0 | return 0; |
725 | 0 | } |
726 | | |
727 | | uint32_t lzma_upack_esi_54(struct lzmastate *p, uint32_t old_eax, uint32_t *old_ecx, char **old_edx, uint32_t *retval, char *bs, uint32_t bl) |
728 | 0 | { |
729 | 0 | uint32_t ret, loc_eax = old_eax; |
730 | |
|
731 | 0 | *old_ecx = ((*old_ecx) & 0xffffff00) | 8; |
732 | 0 | ret = lzma_upack_esi_00(p, *old_edx, bs, bl); |
733 | 0 | *old_edx = ((*old_edx) + 4); |
734 | 0 | loc_eax = (loc_eax & 0xffffff00) | 1; |
735 | 0 | if (ret) { |
736 | 0 | ret = lzma_upack_esi_00(p, *old_edx, bs, bl); |
737 | 0 | loc_eax |= 8; /* mov al, 9 */ |
738 | 0 | if (ret) { |
739 | 0 | *old_ecx <<= 5; |
740 | 0 | loc_eax = 0x11; /* mov al, 11 */ |
741 | 0 | } |
742 | 0 | } |
743 | 0 | ret = loc_eax; |
744 | 0 | if (lzma_upack_esi_50(p, 1, *old_ecx, old_edx, *old_edx + (loc_eax << 2), &loc_eax, bs, bl) == 0xffffffff) |
745 | 0 | return 0xffffffff; |
746 | | |
747 | 0 | *retval = ret + loc_eax; |
748 | 0 | return 0; |
749 | 0 | } |
750 | | |
751 | | /** |
752 | | * @brief Unpack MEW 11 packed PE file |
753 | | * |
754 | | * @param src buffer to unpack |
755 | | * @param off offset of diff |
756 | | * @param ssize pe section size |
757 | | * @param dsize diff size |
758 | | * @param base OPTIONAL_HEADER32.ImageBase |
759 | | * @param vadd RVA of pe section |
760 | | * @param uselzma Bool - use LZMA |
761 | | * @param filedesc File descriptor |
762 | | * @return int Returns -1 on failure, 1 on success. |
763 | | */ |
764 | | int unmew11(char *src, uint32_t off, uint32_t ssize, uint32_t dsize, uint32_t base, uint32_t vadd, int uselzma, int filedesc) |
765 | 1.04k | { |
766 | 1.04k | uint32_t entry_point, newedi, loc_ds = dsize, loc_ss = ssize; |
767 | 1.04k | char *source = NULL; |
768 | 1.04k | const char *lesi = NULL; |
769 | 1.04k | char *ledi; |
770 | 1.04k | const char *f1; |
771 | 1.04k | char *f2; |
772 | 1.04k | int i; |
773 | 1.04k | struct cli_exe_section *section = NULL; |
774 | 1.04k | uint32_t vma = base + vadd; |
775 | 1.04k | uint32_t size_sum = ssize + dsize; |
776 | | |
777 | | /* Guard against integer overflows */ |
778 | 1.04k | if (base + vadd < base) { |
779 | 1 | cli_dbgmsg("MEW: base (%08x) + PE section RVA (%08x) exceeds max size of unsigned int (%08x)\n", |
780 | 1 | base, vadd, UINT32_MAX); |
781 | 1 | return -1; |
782 | 1 | } |
783 | 1.04k | if (ssize + dsize < ssize) { |
784 | 0 | cli_dbgmsg("MEW: section size (%08x) + diff size (%08x) exceeds max size of unsigned int (%08x)\n", |
785 | 0 | ssize, dsize, UINT32_MAX); |
786 | 0 | return -1; |
787 | 0 | } |
788 | 1.04k | if (((size_t)(src + off) < (size_t)(src)) || |
789 | 1.04k | ((size_t)(src + off) < (size_t)(off))) { |
790 | 0 | cli_dbgmsg("MEW: Buffer pointer (%08zx) + offset (%08zx) exceeds max size of pointer (%08lx)\n", |
791 | 0 | (size_t)src, (size_t)off, SIZE_MAX); |
792 | 0 | return -1; |
793 | 0 | } |
794 | | |
795 | | /* Ensure that off + required data exists within buffer */ |
796 | 1.04k | if (!CLI_ISCONTAINED(src, size_sum, src + off, 12)) { |
797 | 0 | cli_dbgmsg("MEW: Data reference exceeds size of provided buffer.\n"); |
798 | 0 | return -1; |
799 | 0 | } |
800 | | |
801 | 1.04k | source = src + dsize + off; |
802 | 1.04k | lesi = source + 12; |
803 | | |
804 | 1.04k | entry_point = cli_readint32(source + 4); |
805 | 1.04k | newedi = cli_readint32(source + 8); |
806 | 1.04k | ledi = src + (newedi - vma); |
807 | 1.04k | loc_ds = size_sum - (newedi - vma); |
808 | | |
809 | 1.04k | i = 0; |
810 | 1.04k | loc_ss -= 12; |
811 | 1.04k | loc_ss -= off; |
812 | 1.15k | while (1) { |
813 | 1.15k | cli_dbgmsg("MEW unpacking section %d (%p->%p)\n", i, lesi, ledi); |
814 | 1.15k | if (!CLI_ISCONTAINED(src, size_sum, lesi, loc_ss) || !CLI_ISCONTAINED(src, size_sum, ledi, loc_ds)) { |
815 | 262 | cli_dbgmsg("Possibly programmer error or hand-crafted PE file, report to clamav team\n"); |
816 | 262 | if (section != NULL) |
817 | 26 | free(section); |
818 | 262 | return -1; |
819 | 262 | } |
820 | 892 | if (unmew(lesi, ledi, loc_ss, loc_ds, &f1, &f2)) { |
821 | 335 | free(section); |
822 | 335 | return -1; |
823 | 335 | } |
824 | | |
825 | | /* we don't need last section in sections since this is information for fixing imptbl */ |
826 | 557 | if (!CLI_ISCONTAINED(src, size_sum, f1, 4)) { |
827 | 0 | free(section); |
828 | 0 | return -1; |
829 | 0 | } |
830 | | |
831 | | /* XXX */ |
832 | 557 | loc_ss -= (f1 + 4 - lesi); |
833 | 557 | lesi = f1 + 4; |
834 | | |
835 | 557 | ledi = src + (cli_readint32(f1) - vma); |
836 | 557 | loc_ds = size_sum - (cli_readint32(f1) - vma); |
837 | | |
838 | 557 | if (!uselzma) { |
839 | 114 | uint32_t val = PESALIGN(f2 - src, 0x1000); |
840 | 114 | void *newsect; |
841 | | |
842 | 114 | if (i && val < section[i].raw) { |
843 | 8 | cli_dbgmsg("MEW: WTF - please report\n"); |
844 | 8 | free(section); |
845 | 8 | return -1; |
846 | 8 | } |
847 | | |
848 | 106 | if (!(newsect = cli_realloc(section, (i + 2) * sizeof(struct cli_exe_section)))) { |
849 | 0 | cli_dbgmsg("MEW: Out of memory\n"); |
850 | 0 | free(section); |
851 | 0 | return -1; |
852 | 0 | } |
853 | | |
854 | 106 | section = (struct cli_exe_section *)newsect; |
855 | 106 | section[0].raw = 0; |
856 | 106 | section[0].rva = vadd; |
857 | 106 | section[i + 1].raw = val; |
858 | 106 | section[i + 1].rva = val + vadd; |
859 | 106 | section[i].rsz = section[i].vsz = ((i) ? (val - section[i].raw) : val); |
860 | | |
861 | | /* |
862 | | * bb#11212 - alternate fix, buffer is aligned |
863 | | * must validate that sections do not intersect with source |
864 | | * or, in other words, exceed the specified size of destination |
865 | | */ |
866 | 106 | if (section[i].raw + section[i].rsz > dsize) { |
867 | 20 | cli_dbgmsg("MEW: Section %i [%d, %d] exceeds destination size %u\n", |
868 | 20 | i, section[i].raw, section[i].raw + section[i].rsz, dsize); |
869 | 20 | free(section); |
870 | 20 | return -1; |
871 | 20 | } |
872 | 106 | } |
873 | 529 | i++; |
874 | | |
875 | 529 | if (!cli_readint32(f1)) |
876 | 420 | break; |
877 | 529 | } |
878 | | |
879 | | /* LZMA stuff */ |
880 | 420 | if (uselzma) { |
881 | 396 | free(section); |
882 | | |
883 | | /* put everything in one section */ |
884 | 396 | i = 1; |
885 | 396 | if (!CLI_ISCONTAINED(src, size_sum, src + uselzma + 8, 1)) { |
886 | 0 | cli_dbgmsg("MEW: couldn't access lzma 'special' tag\n"); |
887 | 0 | return -1; |
888 | 0 | } |
889 | | /* 0x50 -> push eax */ |
890 | 396 | cli_dbgmsg("MEW: lzma %swas used, unpacking\n", (*(src + uselzma + 8) == '\x50') ? "special " : ""); |
891 | 396 | if (!CLI_ISCONTAINED(src, size_sum, f1 + 4, 20 + 4 + 5)) { |
892 | 0 | cli_dbgmsg("MEW: lzma initialization data not available!\n"); |
893 | 0 | return -1; |
894 | 0 | } |
895 | | |
896 | 396 | if (mew_lzma(src, f1 + 4, size_sum, vma, *(src + uselzma + 8) == '\x50')) { |
897 | 377 | return -1; |
898 | 377 | } |
899 | 19 | loc_ds = PESALIGN(loc_ds, 0x1000); |
900 | | |
901 | 19 | section = cli_calloc(1, sizeof(struct cli_exe_section)); |
902 | 19 | if (!section) { |
903 | 0 | cli_dbgmsg("MEW: Out of memory\n"); |
904 | 0 | return -1; |
905 | 0 | } |
906 | | |
907 | 19 | section[0].raw = 0; |
908 | 19 | section[0].rva = vadd; |
909 | 19 | section[0].rsz = section[0].vsz = dsize; |
910 | 19 | } |
911 | 43 | if (!cli_rebuildpe_align(src, section, i, base, entry_point - base, 0, 0, filedesc, 0x1000)) { |
912 | 0 | cli_dbgmsg("MEW: Rebuilding failed\n"); |
913 | 0 | free(section); |
914 | 0 | return -1; |
915 | 0 | } |
916 | 43 | free(section); |
917 | 43 | return 1; |
918 | 43 | } |