File: | libclamav/aspack.c |
Location: | line 149, column 3 |
Description: | Value stored to 'i' is never read |
1 | /* |
2 | * Copyright (C) 2007-2008 Sourcefire, Inc. |
3 | * |
4 | * Authors: Luciano Giuseppe 'Pnluck', Alberto Wu |
5 | * |
6 | * 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. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
18 | * MA 02110-1301, USA. |
19 | */ |
20 | |
21 | #include <string.h> |
22 | |
23 | #include "clamav.h" |
24 | #include "cltypes.h" |
25 | #include "execs.h" |
26 | #include "others.h" |
27 | #include "rebuildpe.h" |
28 | #include "aspack.h" |
29 | |
30 | |
31 | struct DICT_HELPER { |
32 | uint32_t *starts; |
33 | uint8_t *ends; |
34 | uint32_t size; |
35 | }; |
36 | |
37 | struct ASPK { |
38 | uint32_t bitpos; |
39 | uint32_t hash; |
40 | uint32_t init_array[58]; |
41 | struct DICT_HELPER dict_helper[4]; |
42 | uint8_t *input; |
43 | uint8_t *iend; |
44 | uint8_t *decrypt_dict; |
45 | uint32_t decarray3[4][24]; |
46 | uint32_t decarray4[4][24]; |
47 | int dict_ok; |
48 | uint8_t array2[758]; |
49 | uint8_t array1[19]; |
50 | }; |
51 | |
52 | |
53 | static inline int readstream(struct ASPK *stream) { |
54 | while (stream->bitpos >= 8) { |
55 | if (stream->input>=stream->iend) return 0; |
56 | stream->hash = (stream->hash << 8) | *stream->input; |
57 | stream->input++; |
58 | stream->bitpos -= 8; |
59 | } |
60 | return 1; |
61 | } |
62 | |
63 | static uint32_t getdec(struct ASPK *stream, uint8_t which, int *err) { |
64 | uint32_t ret; |
65 | uint8_t pos; |
66 | uint32_t *d3 = stream->decarray3[which]; |
67 | uint32_t *d4 = stream->decarray4[which]; |
68 | |
69 | *err=1; |
70 | |
71 | if (!readstream(stream)) return 0; |
72 | |
73 | ret = (stream->hash >> (8 - stream->bitpos)) & 0xfffe00; |
74 | |
75 | if (ret < d3[8]) { |
76 | if ((ret>>16) >= 0x100) return 0; |
77 | if (!(pos=stream->dict_helper[which].ends[ret>>16]) || pos>= 24) return 0; /* 0<pos<24 */ |
78 | } else { |
79 | if (ret < d3[10]) { |
80 | if (ret < d3[9]) pos = 9; |
81 | else pos = 10; |
82 | } else { |
83 | if (ret < d3[11] ) pos = 11; |
84 | else { |
85 | if (ret < d3[12]) pos = 12; |
86 | else { |
87 | if (ret < d3[13]) pos = 13; |
88 | else { |
89 | if (ret < d3[14]) pos = 14; |
90 | else pos = 15; |
91 | } |
92 | } |
93 | } |
94 | } |
95 | } |
96 | |
97 | stream->bitpos += pos; |
98 | ret = ((ret - d3[pos-1]) >> (24 - pos)) + d4[pos]; |
99 | |
100 | if (ret >= stream->dict_helper[which].size) return 0; |
101 | ret = stream->dict_helper[which].starts[ret]; |
102 | |
103 | *err=0; |
104 | return ret; |
105 | } |
106 | |
107 | |
108 | static uint8_t build_decrypt_array(struct ASPK *stream, uint8_t* array, uint8_t which) { |
109 | uint32_t sum = 0, counter = 23, i, endoff = 0, bus[18], dict[18]; |
110 | |
111 | uint32_t *d3 = stream->decarray3[which]; |
112 | uint32_t *d4 = stream->decarray4[which]; |
113 | |
114 | memset(bus,0,sizeof(bus)); |
115 | memset(dict,0,sizeof(dict)); |
116 | |
117 | for (i = 0; i < stream->dict_helper[which].size; i++) { |
118 | /* within bounds - see comments in build_decrypt_dictionaries */ |
119 | if (array[i] > 17) return 0; |
120 | bus[array[i]]++; |
121 | } |
122 | |
123 | d3[0] = 0; |
124 | d4[0] = 0; |
125 | |
126 | i = 0; |
127 | while (counter >= 9) { /* 0<=i<=14 */ |
128 | sum += (bus[i+1] << counter); |
129 | if (sum > 0x1000000) return 0; |
130 | |
131 | d3[i+1] = sum; |
132 | d4[i+1] = dict[i+1] = bus[i] + d4[i]; |
133 | |
134 | if (counter >= 0x10) { |
135 | uint32_t old = endoff; |
136 | endoff = d3[i+1] >> 0x10; |
137 | if (endoff-old) { |
138 | if (!CLI_ISCONTAINED(stream->dict_helper[which].ends, 0x100, stream->dict_helper[which].ends+old, endoff-old)((0x100) > 0 && (endoff-old) > 0 && (size_t )(endoff-old) <= (size_t)(0x100) && (stream->dict_helper [which].ends+old) >= (stream->dict_helper[which].ends) && ((stream->dict_helper[which].ends+old) + (endoff-old)) <= ((stream->dict_helper[which].ends) + (0x100)) && ( (stream->dict_helper[which].ends+old) + (endoff-old)) > (stream->dict_helper[which].ends) && (stream-> dict_helper[which].ends+old) < ((stream->dict_helper[which ].ends) + (0x100)))) return 0; |
139 | memset((stream->dict_helper[which].ends + old), i+1, endoff-old); |
140 | } |
141 | } |
142 | |
143 | i++; |
144 | counter--; |
145 | } |
146 | |
147 | if (sum != 0x1000000) return 0; |
148 | |
149 | i = 0; |
Value stored to 'i' is never read | |
150 | for (i=0; i < stream->dict_helper[which].size; i++) { |
151 | if (array[i]) { /* within bounds - see above */ |
152 | if (array[i] > 17) return 0; |
153 | if (dict[array[i]]>=stream->dict_helper[which].size) return 0; |
154 | stream->dict_helper[which].starts[dict[array[i]]] = i; |
155 | dict[array[i]]++; |
156 | } |
157 | } |
158 | |
159 | return 1; |
160 | } |
161 | |
162 | |
163 | static uint8_t getbits(struct ASPK *stream, uint32_t num, int *err) { |
164 | uint8_t retvalue; |
165 | |
166 | if (!readstream(stream)) { |
167 | *err=1; |
168 | return 0; |
169 | } |
170 | |
171 | *err = 0; |
172 | retvalue = ((stream->hash >> (8 - stream->bitpos))&0xffffff) >> (24 - num); |
173 | stream->bitpos += num; |
174 | |
175 | return retvalue; |
176 | } |
177 | |
178 | |
179 | static int build_decrypt_dictionaries(struct ASPK *stream) { |
180 | unsigned int counter; |
181 | uint32_t ret; |
182 | int oob; |
183 | |
184 | if (!getbits(stream, 1, &oob)) memset(stream->decrypt_dict, 0, 0x2f5); |
185 | if (oob) return 0; |
186 | |
187 | for (counter = 0; counter < 19; counter++) { |
188 | stream->array1[counter]=getbits(stream, 4, &oob); |
189 | if (oob) return 0; |
190 | } |
191 | |
192 | if (!build_decrypt_array(stream, stream->array1, 3)) return 0; /* array1[19] - [3].size=19 */ |
193 | |
194 | counter = 0; |
195 | while (counter < 757) { |
196 | ret = getdec(stream, 3, &oob); |
197 | if (oob) return 0; |
198 | if (ret >= 16) { |
199 | if (ret != 16) { |
200 | if (ret == 17) ret = 3 + getbits(stream, 3, &oob); |
201 | else ret = 11 + getbits(stream, 7, &oob); |
202 | if (oob) return 0; |
203 | while (ret) { |
204 | if (counter >= 757) break; |
205 | stream->array2[1+counter] = 0; |
206 | counter++; |
207 | ret--; |
208 | } |
209 | } else { |
210 | ret = 3 + getbits(stream, 2, &oob); |
211 | if (oob) return 0; |
212 | while (ret) { |
213 | if (counter >= 757) break; |
214 | stream->array2[1+counter] = stream->array2[counter]; |
215 | counter++; |
216 | ret--; |
217 | } |
218 | } |
219 | } else { |
220 | stream->array2[1+counter] = (stream->decrypt_dict[counter] + ret) & 0xF; |
221 | counter++; |
222 | } |
223 | } |
224 | |
225 | if (!build_decrypt_array(stream, &stream->array2[1], 0) /* array2[758-1=757] - [0].size=721 */ || !build_decrypt_array(stream, &stream->array2[722], 1) /* array2[758-722=36] - [1].size=28 */ || !build_decrypt_array(stream, &stream->array2[750], 2) /* array2[758-750=8] - [2].size=8 */ ) return 0; |
226 | |
227 | stream->dict_ok = 0; |
228 | for (counter = 0; counter < 8; counter++) { |
229 | if (stream->array2[750+counter] != 3) { |
230 | stream->dict_ok = 1; |
231 | break; |
232 | } |
233 | } |
234 | |
235 | memcpy(stream->decrypt_dict,&stream->array2[1],757); |
236 | |
237 | return 1; |
238 | } |
239 | |
240 | |
241 | static int decrypt(struct ASPK *stream, uint8_t *stuff, uint32_t size, uint8_t *output) { |
242 | /* ep+6d6 -> ep+748 = 0x72*/ |
243 | uint32_t gen, backsize, backbytes, useold, counter = 0; |
244 | uint32_t hist[4]={0,0,0,0}; |
245 | int oob; |
246 | |
247 | while (counter < size) { |
248 | gen = getdec(stream, 0, &oob); |
249 | if (oob) return 0; |
250 | if (gen < 256) { /* implied within bounds */ |
251 | output[counter] = (uint8_t)gen; |
252 | counter++; |
253 | continue; |
254 | } |
255 | if (gen >= 720) { |
256 | if (!build_decrypt_dictionaries(stream)) return 0; |
257 | continue; |
258 | } |
259 | if ((backbytes = (gen - 256) >> 3)>=58) return 0; /* checks init_array + stuff */ |
260 | backsize = ((gen - 256) & 7) + 2; |
261 | if ((backsize-2)==7) { |
262 | uint8_t hlp; |
263 | gen = getdec(stream, 1, &oob); |
264 | if (oob || gen>=0x56) return 0; |
265 | hlp = stuff[gen + 0x1c]; |
266 | if (!readstream(stream)) return 0; |
267 | backsize += stuff[gen] + (( (stream->hash >> (8 - stream->bitpos)) & 0xffffff ) >> (0x18 - hlp)); |
268 | stream->bitpos += hlp; |
269 | } |
270 | |
271 | useold = stream->init_array[backbytes]; |
272 | gen = stuff[backbytes + 0x38]; |
273 | |
274 | if (!stream->dict_ok || gen < 3) { |
275 | if (!readstream(stream)) return 0; |
276 | useold += ((stream->hash >> ( 8 - stream->bitpos) ) & 0xffffff) >> (24 - gen); |
277 | stream->bitpos += gen; |
278 | } else { |
279 | gen -= 3; |
280 | if (!readstream(stream)) return 0; |
281 | useold += ((((stream->hash >> ( 8 - stream->bitpos)) & 0xffffff) >> (24 - gen)) * 8); |
282 | stream->bitpos += gen; |
283 | useold += getdec(stream, 2, &oob); |
284 | if (oob) return 0; |
285 | } |
286 | |
287 | if (useold < 3) { |
288 | backbytes = hist[useold]; |
289 | if (useold != 0) { |
290 | hist[useold] = hist[0]; |
291 | hist[0] = backbytes; |
292 | } |
293 | } else { |
294 | hist[2] = hist[1]; |
295 | hist[1] = hist[0]; |
296 | hist[0] = backbytes = useold-3; |
297 | } |
298 | |
299 | backbytes++; |
300 | |
301 | if (!backbytes || backbytes>counter || backsize>size-counter) return 0; |
302 | while (backsize--) { |
303 | output[counter] = output[counter-backbytes]; |
304 | counter++; |
305 | } |
306 | } |
307 | |
308 | return 1; |
309 | } |
310 | |
311 | |
312 | static int decomp_block(struct ASPK *stream, uint32_t size, uint8_t *stuff, uint8_t *output) { |
313 | memset(stream->decarray3,0,sizeof(stream->decarray3)); |
314 | memset(stream->decarray4,0,sizeof(stream->decarray4)); |
315 | memset(stream->decrypt_dict, 0, 757); |
316 | stream->bitpos = 0x20; |
317 | if (!build_decrypt_dictionaries(stream)) return 0; |
318 | return decrypt(stream, stuff, size, output); |
319 | } |
320 | |
321 | #define INIT_DICT_HELPER(n,sz)stream.dict_helper[n].starts = (uint32_t *)wrkbuf; stream.dict_helper [n].ends = &wrkbuf[sz * sizeof(uint32_t)]; stream.dict_helper [n].size = sz; wrkbuf = &wrkbuf[sz * sizeof(uint32_t) + 0x100 ]; \ |
322 | stream.dict_helper[n].starts = (uint32_t *)wrkbuf; \ |
323 | stream.dict_helper[n].ends = &wrkbuf[sz * sizeof(uint32_t)]; \ |
324 | stream.dict_helper[n].size = sz; \ |
325 | wrkbuf = &wrkbuf[sz * sizeof(uint32_t) + 0x100]; |
326 | |
327 | int unaspack212(uint8_t *image, unsigned int size, struct cli_exe_section *sections, uint16_t sectcount, uint32_t ep, uint32_t base, int f) { |
328 | struct ASPK stream; |
329 | uint32_t i=0, j=0; |
330 | uint8_t *blocks = image+ep+0x57c, *wrkbuf; |
331 | uint32_t block_rva = 1, block_size; |
332 | struct cli_exe_section *outsects; |
333 | |
334 | if (!(wrkbuf = cli_calloc(0x1800, sizeof(uint8_t)))) { |
335 | cli_dbgmsg(!__builtin_expect(!!(cli_debug_flag), 0)) ? (void)0 : cli_dbgmsg_internal("Aspack: Unable to allocate dictionary\n"); |
336 | return 0; |
337 | } |
338 | |
339 | INIT_DICT_HELPER(0, 721)stream.dict_helper[0].starts = (uint32_t *)wrkbuf; stream.dict_helper [0].ends = &wrkbuf[721 * sizeof(uint32_t)]; stream.dict_helper [0].size = 721; wrkbuf = &wrkbuf[721 * sizeof(uint32_t) + 0x100];; /* dictionary -> dictionary + b44 */ |
340 | INIT_DICT_HELPER(1, 28)stream.dict_helper[1].starts = (uint32_t *)wrkbuf; stream.dict_helper [1].ends = &wrkbuf[28 * sizeof(uint32_t)]; stream.dict_helper [1].size = 28; wrkbuf = &wrkbuf[28 * sizeof(uint32_t) + 0x100 ];; /* dictionary + c44 -> dictionary + cb4 */ |
341 | INIT_DICT_HELPER(2, 8)stream.dict_helper[2].starts = (uint32_t *)wrkbuf; stream.dict_helper [2].ends = &wrkbuf[8 * sizeof(uint32_t)]; stream.dict_helper [2].size = 8; wrkbuf = &wrkbuf[8 * sizeof(uint32_t) + 0x100 ];; /* dictionary + db4 -> dictionary + dd4 */ |
342 | INIT_DICT_HELPER(3, 19)stream.dict_helper[3].starts = (uint32_t *)wrkbuf; stream.dict_helper [3].ends = &wrkbuf[19 * sizeof(uint32_t)]; stream.dict_helper [3].size = 19; wrkbuf = &wrkbuf[19 * sizeof(uint32_t) + 0x100 ];; /* dictionary + ed4 -> dictionary + f20 */ |
343 | stream.decrypt_dict = wrkbuf; |
344 | |
345 | stream.hash = 0x10000; |
346 | |
347 | for (i = 0; i < 58; i++) { |
348 | stream.init_array[i] = j; |
349 | j += ( 1 << image[ep+i+0x70e]); /* boundchecked in pe.c */ |
350 | } |
351 | |
352 | memset(stream.array1,0,sizeof(stream.array1)); |
353 | memset(stream.array2,0,sizeof(stream.array2)); |
354 | |
355 | i=0; |
356 | while (CLI_ISCONTAINED(image, size, blocks, 8)((size) > 0 && (8) > 0 && (size_t)(8) <= (size_t)(size) && (blocks) >= (image) && ( (blocks) + (8)) <= ((image) + (size)) && ((blocks) + (8)) > (image) && (blocks) < ((image) + (size ))) && (block_rva = cli_readint32(blocks)(((const union unaligned_32 *)(blocks))->una_s32)) && (block_size = cli_readint32(blocks+4)(((const union unaligned_32 *)(blocks+4))->una_s32)) && CLI_ISCONTAINED(image, size, image+block_rva, block_size)((size) > 0 && (block_size) > 0 && (size_t )(block_size) <= (size_t)(size) && (image+block_rva ) >= (image) && ((image+block_rva) + (block_size)) <= ((image) + (size)) && ((image+block_rva) + (block_size )) > (image) && (image+block_rva) < ((image) + ( size)))) { |
357 | wrkbuf = (uint8_t *)cli_calloc(block_size+0x10e, sizeof(uint8_t)); |
358 | if (!wrkbuf) break; |
359 | |
360 | stream.input = wrkbuf; |
361 | stream.iend = &wrkbuf[block_size+0x10e]; |
362 | |
363 | memcpy(wrkbuf, image + block_rva, block_size); |
364 | |
365 | cli_dbgmsg(!__builtin_expect(!!(cli_debug_flag), 0)) ? (void)0 : cli_dbgmsg_internal("Aspack: unpacking block rva:%x - sz:%x\n", block_rva, block_size); |
366 | if (!decomp_block(&stream, block_size, &image[ep+0x6d6], image + block_rva)) { |
367 | free(wrkbuf); |
368 | break; |
369 | } |
370 | |
371 | free(wrkbuf); |
372 | |
373 | if (i==0 && block_size>7) { /* first sect j/c unrolling */ |
374 | while (i < block_size - 6) { |
375 | uint8_t curbyte = image[block_rva+i]; |
376 | if (curbyte == 0xe8 || curbyte == 0xe9) { |
377 | wrkbuf = &image[block_rva+i+1]; |
378 | if (*wrkbuf == image[ep+0x148]) { |
379 | uint32_t target = cli_readint32(wrkbuf)(((const union unaligned_32 *)(wrkbuf))->una_s32) & 0xffffff00; |
380 | CLI_ROL(target, 0x18)target = ( target << ((0x18) & ((sizeof(target)<< 3)-1)) ) | ( target >> (((sizeof(target)<<3) - (0x18 )) & ((sizeof(target)<<3)-1)) ); |
381 | cli_writeint32(wrkbuf, target - i)(((union unaligned_32 *)(wrkbuf))->una_u32=(uint32_t)(target - i)); |
382 | i+=4; |
383 | } |
384 | } |
385 | i++; |
386 | } |
387 | } |
388 | blocks+=8; |
389 | } |
390 | |
391 | free(stream.dict_helper[0].starts); |
392 | if (block_rva) { |
393 | cli_dbgmsg(!__builtin_expect(!!(cli_debug_flag), 0)) ? (void)0 : cli_dbgmsg_internal("Aspack: unpacking failure\n"); |
394 | return 0; |
395 | } |
396 | |
397 | if(sectcount>2 && ep == sections[sectcount-2].rva && !sections[sectcount-1].rsz) { |
398 | sectcount-=2; |
399 | } |
400 | if(!(outsects=cli_malloc(sizeof(struct cli_exe_section)*sectcount))) { |
401 | cli_dbgmsg(!__builtin_expect(!!(cli_debug_flag), 0)) ? (void)0 : cli_dbgmsg_internal("Aspack: OOM - rebuild failed\n"); |
402 | cli_writen(f, image, size); |
403 | return 1; /* No whatsoheader - won't infloop in pe.c */ |
404 | } |
405 | memcpy(outsects, sections, sizeof(struct cli_exe_section)*sectcount); |
406 | for(i=0; i<sectcount; i++) { |
407 | outsects[i].raw=outsects[i].rva; |
408 | outsects[i].rsz=outsects[i].vsz; |
409 | } |
410 | if (!cli_rebuildpe((char *)image, outsects, sectcount, base, cli_readint32(image + ep + 0x39b)(((const union unaligned_32 *)(image + ep + 0x39b))->una_s32 ), 0, 0, f)) { |
411 | cli_dbgmsg(!__builtin_expect(!!(cli_debug_flag), 0)) ? (void)0 : cli_dbgmsg_internal("Aspack: rebuild failed\n"); |
412 | cli_writen(f, image, size); |
413 | } else { |
414 | cli_dbgmsg(!__builtin_expect(!!(cli_debug_flag), 0)) ? (void)0 : cli_dbgmsg_internal("Aspack: successfully rebuilt\n"); |
415 | } |
416 | free(outsects); |
417 | return 1; |
418 | } |
419 |