... | ... |
@@ -1,5 +1,5 @@ |
1 | 1 |
/* |
2 |
- * Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
2 |
+ * Copyright (C) 2015, 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
3 | 3 |
* Copyright (C) 2007-2008 Sourcefire, Inc. |
4 | 4 |
* |
5 | 5 |
* Authors: Alberto Wu |
... | ... |
@@ -35,7 +35,6 @@ |
35 | 35 |
** [ A big fat thank to christoph for not letting me give up ] |
36 | 36 |
*/ |
37 | 37 |
|
38 |
- |
|
39 | 38 |
/* |
40 | 39 |
** TODO ( a fat one ): |
41 | 40 |
** |
... | ... |
@@ -48,7 +47,6 @@ |
48 | 48 |
** |
49 | 49 |
*/ |
50 | 50 |
|
51 |
- |
|
52 | 51 |
#if HAVE_CONFIG_H |
53 | 52 |
#include "clamav-config.h" |
54 | 53 |
#endif |
... | ... |
@@ -65,451 +63,521 @@ |
65 | 65 |
#include "packlibs.h" |
66 | 66 |
#include "spin.h" |
67 | 67 |
|
68 |
- |
|
69 |
-static char exec86(uint8_t aelle, uint8_t cielle, char *curremu, int *retval) { |
|
70 |
- int len = 0; |
|
71 |
- *retval=0; |
|
72 |
- while (len <0x24) { |
|
73 |
- uint8_t opcode = curremu[len], support; |
|
74 |
- len++; |
|
75 |
- switch (opcode) { |
|
76 |
- case 0xeb: |
|
77 |
- len++; |
|
78 |
- case 0x0a: |
|
79 |
- len++; |
|
80 |
- case 0x90: |
|
81 |
- case 0xf8: |
|
82 |
- case 0xf9: |
|
83 |
- break; |
|
84 |
- |
|
85 |
- case 0x02: /* add al, cl */ |
|
86 |
- aelle+=cielle; |
|
87 |
- len++; |
|
88 |
- break; |
|
89 |
- case 0x2a: /* sub al, cl */ |
|
90 |
- aelle-=cielle; |
|
91 |
- len++; |
|
92 |
- break; |
|
93 |
- case 0x04: /* add al, ?? */ |
|
94 |
- aelle+=curremu[len]; |
|
95 |
- len++; |
|
96 |
- break; |
|
97 |
- case 0x2c: /* sub al, ?? */ |
|
98 |
- aelle-=curremu[len]; |
|
99 |
- len++; |
|
100 |
- break; |
|
101 |
- case 0x32: /* xor al, cl */ |
|
102 |
- aelle^=cielle; |
|
103 |
- len++; |
|
104 |
- break; |
|
105 |
- case 0x34: /* xor al, ?? */ |
|
106 |
- aelle^=curremu[len]; |
|
107 |
- len++; |
|
108 |
- break; |
|
109 |
- |
|
110 |
- case 0xfe: /* inc/dec al */ |
|
111 |
- if ( curremu[len] == '\xc0' ) aelle++; |
|
112 |
- else aelle--; |
|
113 |
- len++; |
|
114 |
- break; |
|
115 |
- |
|
116 |
- case 0xc0: /* ror/rol al, ?? */ |
|
117 |
- support = curremu[len]; |
|
118 |
- len++; |
|
119 |
- if ( support == 0xc0 ) CLI_ROL(aelle, curremu[len]); |
|
120 |
- else CLI_ROR(aelle, curremu[len]); |
|
68 |
+static char exec86(uint8_t aelle, uint8_t cielle, char *curremu, int *retval) |
|
69 |
+{ |
|
70 |
+ int len = 0; |
|
71 |
+ *retval = 0; |
|
72 |
+ while (len < 0x24) |
|
73 |
+ { |
|
74 |
+ uint8_t opcode = curremu[len], support; |
|
121 | 75 |
len++; |
122 |
- break; |
|
123 |
- |
|
124 |
- default: |
|
125 |
- cli_dbgmsg("spin: bogus opcode %x\n", opcode); |
|
126 |
- *retval=1; |
|
127 |
- return aelle; |
|
76 |
+ switch (opcode) |
|
77 |
+ { |
|
78 |
+ case 0xeb: |
|
79 |
+ len++; |
|
80 |
+ case 0x0a: |
|
81 |
+ len++; |
|
82 |
+ case 0x90: |
|
83 |
+ case 0xf8: |
|
84 |
+ case 0xf9: |
|
85 |
+ break; |
|
86 |
+ |
|
87 |
+ case 0x02: /* add al, cl */ |
|
88 |
+ aelle += cielle; |
|
89 |
+ len++; |
|
90 |
+ break; |
|
91 |
+ case 0x2a: /* sub al, cl */ |
|
92 |
+ aelle -= cielle; |
|
93 |
+ len++; |
|
94 |
+ break; |
|
95 |
+ case 0x04: /* add al, ?? */ |
|
96 |
+ aelle += curremu[len]; |
|
97 |
+ len++; |
|
98 |
+ break; |
|
99 |
+ case 0x2c: /* sub al, ?? */ |
|
100 |
+ aelle -= curremu[len]; |
|
101 |
+ len++; |
|
102 |
+ break; |
|
103 |
+ case 0x32: /* xor al, cl */ |
|
104 |
+ aelle ^= cielle; |
|
105 |
+ len++; |
|
106 |
+ break; |
|
107 |
+ case 0x34: /* xor al, ?? */ |
|
108 |
+ aelle ^= curremu[len]; |
|
109 |
+ len++; |
|
110 |
+ break; |
|
111 |
+ |
|
112 |
+ case 0xfe: /* inc/dec al */ |
|
113 |
+ if (curremu[len] == '\xc0') |
|
114 |
+ aelle++; |
|
115 |
+ else |
|
116 |
+ aelle--; |
|
117 |
+ len++; |
|
118 |
+ break; |
|
119 |
+ |
|
120 |
+ case 0xc0: /* ror/rol al, ?? */ |
|
121 |
+ support = curremu[len]; |
|
122 |
+ len++; |
|
123 |
+ if (support == 0xc0) |
|
124 |
+ CLI_ROL(aelle, curremu[len]); |
|
125 |
+ else |
|
126 |
+ CLI_ROR(aelle, curremu[len]); |
|
127 |
+ len++; |
|
128 |
+ break; |
|
129 |
+ |
|
130 |
+ default: |
|
131 |
+ cli_dbgmsg("spin: bogus opcode %x\n", opcode); |
|
132 |
+ *retval = 1; |
|
133 |
+ return aelle; |
|
134 |
+ } |
|
135 |
+ } |
|
136 |
+ if (len != 0x24 || curremu[len] != '\xaa') |
|
137 |
+ { |
|
138 |
+ cli_dbgmsg("spin: bad emucode\n"); |
|
139 |
+ *retval = 1; |
|
128 | 140 |
} |
129 |
- } |
|
130 |
- if ( len!=0x24 || curremu[len]!='\xaa' ) { |
|
131 |
- cli_dbgmsg("spin: bad emucode\n"); |
|
132 |
- *retval=1; |
|
133 |
- } |
|
134 |
- return aelle; |
|
141 |
+ return aelle; |
|
135 | 142 |
} |
136 | 143 |
|
137 |
- |
|
138 |
-static uint32_t summit (char *src, int size) |
|
144 |
+static uint32_t summit(char *src, int size) |
|
139 | 145 |
{ |
140 |
- uint32_t eax=0xffffffff, ebx=0xffffffff; |
|
141 |
- int i; |
|
142 |
- |
|
143 |
- while(size) { |
|
144 |
- eax ^= *src++<<8 & 0xff00; |
|
145 |
- eax = eax>>3 & 0x1fffffff; |
|
146 |
- for (i=0; i<4; i++) { |
|
147 |
- uint32_t swap; |
|
148 |
- eax ^= ebx>>8 & 0xff; |
|
149 |
- eax += 0x7801a108; |
|
150 |
- eax ^= ebx; |
|
151 |
- CLI_ROR(eax, ebx&0xff); |
|
152 |
- swap = eax; |
|
153 |
- eax = ebx; |
|
154 |
- ebx = swap; |
|
146 |
+ uint32_t eax = 0xffffffff, ebx = 0xffffffff; |
|
147 |
+ int i; |
|
148 |
+ |
|
149 |
+ while (size) |
|
150 |
+ { |
|
151 |
+ eax ^= *src++ << 8 & 0xff00; |
|
152 |
+ eax = eax >> 3 & 0x1fffffff; |
|
153 |
+ for (i = 0; i < 4; i++) |
|
154 |
+ { |
|
155 |
+ uint32_t swap; |
|
156 |
+ eax ^= ebx >> 8 & 0xff; |
|
157 |
+ eax += 0x7801a108; |
|
158 |
+ eax ^= ebx; |
|
159 |
+ CLI_ROR(eax, ebx & 0xff); |
|
160 |
+ swap = eax; |
|
161 |
+ eax = ebx; |
|
162 |
+ ebx = swap; |
|
163 |
+ } |
|
164 |
+ size--; |
|
155 | 165 |
} |
156 |
- size--; |
|
157 |
- } |
|
158 |
- return ebx; |
|
166 |
+ return ebx; |
|
159 | 167 |
} |
160 | 168 |
|
169 |
+int unspin(char *src, int ssize, struct cli_exe_section *sections, int sectcnt, uint32_t nep, int desc, cli_ctx *ctx) |
|
170 |
+{ |
|
171 |
+ char *curr, *emu, *ep, *spinned; |
|
172 |
+ char **sects; |
|
173 |
+ int blobsz = 0, j; |
|
174 |
+ uint32_t key32, bitmap, bitman; |
|
175 |
+ uint32_t len; |
|
176 |
+ uint8_t key8; |
|
177 |
+ |
|
178 |
+ cli_dbgmsg("in unspin\n"); |
|
179 |
+ |
|
180 |
+ if ((spinned = (char *)cli_malloc(sections[sectcnt].rsz)) == NULL) |
|
181 |
+ { |
|
182 |
+ cli_dbgmsg("spin: Unable to allocate memory for spinned\n"); |
|
183 |
+ return 1; |
|
184 |
+ } |
|
161 | 185 |
|
162 |
-int unspin(char *src, int ssize, struct cli_exe_section *sections, int sectcnt, uint32_t nep, int desc, cli_ctx *ctx) { |
|
163 |
- char *curr, *emu, *ep, *spinned; |
|
164 |
- char **sects; |
|
165 |
- int blobsz=0, j; |
|
166 |
- uint32_t key32, bitmap, bitman; |
|
167 |
- uint32_t len; |
|
168 |
- uint8_t key8; |
|
169 |
- |
|
170 |
- cli_dbgmsg("in unspin\n"); |
|
171 |
- |
|
172 |
- if ((spinned = (char *) cli_malloc(sections[sectcnt].rsz)) == NULL ) { |
|
173 |
- cli_dbgmsg("spin: Unable to allocate memory for spinned\n"); |
|
174 |
- return 1; |
|
175 |
- } |
|
176 |
- |
|
177 |
- memcpy(spinned, src + sections[sectcnt].raw, sections[sectcnt].rsz); |
|
178 |
- ep = spinned + nep - sections[sectcnt].rva; |
|
179 |
- |
|
180 |
- curr = ep+0xdb; |
|
181 |
- if ( *curr != '\xbb' ) { |
|
182 |
- free(spinned); |
|
183 |
- cli_dbgmsg("spin: Not spinned or bad version\n"); |
|
184 |
- return 1; |
|
185 |
- } |
|
186 |
- |
|
187 |
- key8 = (uint8_t)*++curr; |
|
188 |
- curr+=4; |
|
189 |
- if ( *curr != '\xb9' ) { |
|
190 |
- free(spinned); |
|
191 |
- cli_dbgmsg("spin: Not spinned or bad version\n"); |
|
192 |
- return 1; |
|
193 |
- } |
|
194 |
- |
|
195 |
- if ( (len = cli_readint32(curr+1)) != 0x11fe ) { |
|
196 |
- free(spinned); |
|
197 |
- cli_dbgmsg("spin: Not spinned or bad version\n"); |
|
198 |
- return 1; |
|
199 |
- } |
|
200 |
- |
|
201 |
- cli_dbgmsg("spin: Key8 is %x, Len is %x\n", key8, len); |
|
202 |
- |
|
203 |
- if (!CLI_ISCONTAINED(spinned, sections[sectcnt].rsz, ep, len+0x1fe5-1)) { |
|
204 |
- free(spinned); |
|
205 |
- cli_dbgmsg("spin: len out of bounds, giving up\n"); |
|
206 |
- return 1; |
|
207 |
- } |
|
208 |
- |
|
209 |
- if ( ep[0x1e0]!='\xb8' ) |
|
210 |
- cli_dbgmsg("spin: prolly not spinned, expect failure\n"); |
|
211 |
- |
|
212 |
- if ( (cli_readint32(ep+0x1e1) & 0x00200000) ) |
|
213 |
- cli_dbgmsg("spin: password protected, expect failure\n"); |
|
214 |
- |
|
215 |
- curr = ep+0x1fe5+len-1; |
|
216 |
- while ( len-- ) { |
|
217 |
- *curr=(*curr)^(key8--); |
|
218 |
- curr--; |
|
219 |
- } |
|
220 |
- |
|
221 |
- if (!CLI_ISCONTAINED(spinned, sections[sectcnt].rsz, ep+0x3217, 4)) { |
|
222 |
- free(spinned); |
|
223 |
- cli_dbgmsg("spin: key out of bounds, giving up\n"); |
|
224 |
- return 1; |
|
225 |
- } |
|
226 |
- |
|
227 |
- curr = ep+0x26eb; |
|
228 |
- key32 = cli_readint32(curr); |
|
229 |
- if ( (len = cli_readint32(curr+5)) != 0x5a0) { |
|
230 |
- free(spinned); |
|
231 |
- cli_dbgmsg("spin: Not spinned or bad version\n"); |
|
232 |
- return 1; |
|
233 |
- } |
|
234 |
- |
|
235 |
- curr = ep+0x2d5; |
|
236 |
- cli_dbgmsg("spin: Key is %x, Len is %x\n", key32, len); |
|
237 |
- |
|
238 |
- while ( len-- ) { |
|
239 |
- if ( key32 & 1 ) { |
|
240 |
- key32 = key32>>1; |
|
241 |
- key32 ^= 0x8c328834; |
|
242 |
- } else { |
|
243 |
- key32 = key32>>1; |
|
186 |
+ memcpy(spinned, src + sections[sectcnt].raw, sections[sectcnt].rsz); |
|
187 |
+ ep = spinned + nep - sections[sectcnt].rva; |
|
188 |
+ |
|
189 |
+ curr = ep + 0xdb; |
|
190 |
+ if (*curr != '\xbb') |
|
191 |
+ { |
|
192 |
+ free(spinned); |
|
193 |
+ cli_dbgmsg("spin: Not spinned or bad version\n"); |
|
194 |
+ return 1; |
|
244 | 195 |
} |
245 |
- *curr = *curr ^ (key32 & 0xff); |
|
246 |
- curr++; |
|
247 |
- } |
|
248 |
- |
|
249 |
- len = ssize - cli_readint32(ep+0x429); /* sub size, value */ |
|
250 |
- if ( len >= (uint32_t)ssize ) { |
|
251 |
- free(spinned); |
|
252 |
- cli_dbgmsg("spin: crc out of bounds, giving up\n"); |
|
253 |
- return 1; |
|
254 |
- } |
|
255 |
- key32 = cli_readint32(ep+0x3217) - summit(src,len); |
|
256 |
- |
|
257 |
- memcpy(src + sections[sectcnt].raw, spinned, sections[sectcnt].rsz); |
|
258 |
- free(spinned); /* done CRC'ing - can have a dirty buffer now */ |
|
259 |
- ep = src + nep + sections[sectcnt].raw - sections[sectcnt].rva; /* Fix the helper */ |
|
260 |
- |
|
261 |
- if (!CLI_ISCONTAINED(src, ssize, ep+0x3207, 4)) { /* this one holds all ep based checks */ |
|
262 |
- cli_dbgmsg("spin: key out of bounds, giving up\n"); |
|
263 |
- return 1; |
|
264 |
- } |
|
265 |
- bitmap = cli_readint32(ep+0x3207); |
|
266 |
- cli_dbgmsg("spin: Key32 is %x - XORbitmap is %x\n", key32, bitmap); |
|
267 |
- |
|
268 |
- cli_dbgmsg("spin: Decrypting sects (xor)\n"); |
|
269 |
- for (j=0; j<sectcnt; j++) { |
|
270 |
- |
|
271 |
- if (bitmap&1) { |
|
272 |
- uint32_t size = sections[j].rsz; |
|
273 |
- char *ptr = src + sections[j].raw; |
|
274 |
- uint32_t keydup = key32; |
|
275 |
- |
|
276 |
- if (!CLI_ISCONTAINED(src, ssize, ptr, size)) { |
|
277 |
- cli_dbgmsg("spin: sect %d out of file, giving up\n", j); |
|
278 |
- return 1; /* FIXME: Already checked in pe.c? */ |
|
279 |
- } |
|
280 |
- |
|
281 |
- while (size--) { |
|
282 |
- if (! (keydup & 1)) { |
|
283 |
- keydup = keydup>>1; |
|
284 |
- keydup ^= 0xed43af31; |
|
285 |
- } else { |
|
286 |
- keydup = keydup>>1; |
|
287 |
- } |
|
288 |
- *ptr = *ptr ^ (keydup & 0xff); |
|
289 |
- ptr++; |
|
290 |
- } |
|
291 |
- } |
|
292 |
- bitmap = bitmap >>1; |
|
293 |
- } |
|
294 |
- |
|
295 |
- cli_dbgmsg("spin: done\n"); |
|
296 |
- |
|
297 |
- |
|
298 |
- curr = ep+0x644; |
|
299 |
- if ( (len = cli_readint32(curr)) != 0x180) { |
|
300 |
- cli_dbgmsg("spin: Not spinned or bad version\n"); |
|
301 |
- return 1; |
|
302 |
- } |
|
303 |
- |
|
304 |
- key32 = cli_readint32(curr+0x0c); |
|
305 |
- cli_dbgmsg("spin: Key is %x, Len is %x\n", key32, len); |
|
306 |
- curr = ep+0x28d3; |
|
307 |
- |
|
308 |
- if (!CLI_ISCONTAINED(src, ssize, curr, len)) { /* always true but i may decide to remove the previous check */ |
|
309 |
- cli_dbgmsg("spin: key out of bounds, giving up\n"); |
|
310 |
- return 1; |
|
311 |
- } |
|
312 |
- while ( len-- ) { |
|
313 |
- if ( key32 & 1 ) { |
|
314 |
- key32 = key32>>1; |
|
315 |
- key32 ^= 0xed43af32; |
|
316 |
- } else { |
|
317 |
- key32 = key32>>1; |
|
196 |
+ |
|
197 |
+ key8 = (uint8_t) * ++curr; |
|
198 |
+ curr += 4; |
|
199 |
+ if (*curr != '\xb9') |
|
200 |
+ { |
|
201 |
+ free(spinned); |
|
202 |
+ cli_dbgmsg("spin: Not spinned or bad version\n"); |
|
203 |
+ return 1; |
|
318 | 204 |
} |
319 |
- *curr = *curr ^ (key32 & 0xff); |
|
320 |
- curr++; |
|
321 |
- } |
|
322 |
- |
|
323 |
- |
|
324 |
- curr = ep+0x28dd; |
|
325 |
- if ( (len = cli_readint32(curr)) != 0x1a1 ) { |
|
326 |
- cli_dbgmsg("spin: Not spinned or bad version\n"); |
|
327 |
- return 1; |
|
328 |
- } |
|
329 |
- |
|
330 |
- cli_dbgmsg("spin: POLY1 len is %x\n", len); |
|
331 |
- curr+=0xf; /* POLY1 */ |
|
332 |
- emu = ep+0x6d4; |
|
333 |
- if (!CLI_ISCONTAINED(src, ssize, emu, len)) { |
|
334 |
- cli_dbgmsg("spin: poly1 out of bounds\n"); |
|
335 |
- return 1; |
|
336 |
- } |
|
337 |
- while (len) { |
|
338 |
- int xcfailure=0; |
|
339 |
- *emu=exec86(*emu, len-- & 0xff, curr, &xcfailure); /* unlame POLY1 */ |
|
340 |
- if (xcfailure) { |
|
341 |
- cli_dbgmsg("spin: cannot exec poly1\n"); |
|
342 |
- return 1; |
|
205 |
+ |
|
206 |
+ if ((len = cli_readint32(curr + 1)) != 0x11fe) |
|
207 |
+ { |
|
208 |
+ free(spinned); |
|
209 |
+ cli_dbgmsg("spin: Not spinned or bad version\n"); |
|
210 |
+ return 1; |
|
343 | 211 |
} |
344 |
- emu++; |
|
345 |
- } |
|
346 | 212 |
|
213 |
+ cli_dbgmsg("spin: Key8 is %x, Len is %x\n", key8, len); |
|
347 | 214 |
|
348 |
- bitmap = cli_readint32(ep+0x6f1); |
|
349 |
- cli_dbgmsg("spin: POLYbitmap is %x - decrypting sects (poly)\n", bitmap); |
|
350 |
- curr = ep+0x755; |
|
215 |
+ if (!CLI_ISCONTAINED(spinned, sections[sectcnt].rsz, ep, len + 0x1fe5 - 1)) |
|
216 |
+ { |
|
217 |
+ free(spinned); |
|
218 |
+ cli_dbgmsg("spin: len out of bounds, giving up\n"); |
|
219 |
+ return 1; |
|
220 |
+ } |
|
351 | 221 |
|
352 |
- for (j=0; j<sectcnt; j++) { |
|
353 |
- if (bitmap&1) { |
|
354 |
- uint32_t notthesamelen = sections[j].rsz; |
|
222 |
+ if (ep[0x1e0] != '\xb8') |
|
223 |
+ cli_dbgmsg("spin: prolly not spinned, expect failure\n"); |
|
355 | 224 |
|
356 |
- emu = src + sections[j].raw; |
|
225 |
+ if ((cli_readint32(ep + 0x1e1) & 0x00200000)) |
|
226 |
+ cli_dbgmsg("spin: password protected, expect failure\n"); |
|
357 | 227 |
|
358 |
- if (!CLI_ISCONTAINED(src,ssize,curr,0x24)) { /* section bounds already checked twice now */ |
|
359 |
- cli_dbgmsg("spin: poly1 emucode is out of file?\n"); |
|
360 |
- return 1; |
|
361 |
- } |
|
228 |
+ curr = ep + 0x1fe5 + len - 1; |
|
229 |
+ while (len--) |
|
230 |
+ { |
|
231 |
+ *curr = (*curr) ^ (key8--); |
|
232 |
+ curr--; |
|
233 |
+ } |
|
234 |
+ |
|
235 |
+ if (!CLI_ISCONTAINED(spinned, sections[sectcnt].rsz, ep + 0x3217, 4)) |
|
236 |
+ { |
|
237 |
+ free(spinned); |
|
238 |
+ cli_dbgmsg("spin: key out of bounds, giving up\n"); |
|
239 |
+ return 1; |
|
240 |
+ } |
|
241 |
+ |
|
242 |
+ curr = ep + 0x26eb; |
|
243 |
+ key32 = cli_readint32(curr); |
|
244 |
+ if ((len = cli_readint32(curr + 5)) != 0x5a0) |
|
245 |
+ { |
|
246 |
+ free(spinned); |
|
247 |
+ cli_dbgmsg("spin: Not spinned or bad version\n"); |
|
248 |
+ return 1; |
|
249 |
+ } |
|
250 |
+ |
|
251 |
+ curr = ep + 0x2d5; |
|
252 |
+ cli_dbgmsg("spin: Key is %x, Len is %x\n", key32, len); |
|
253 |
+ |
|
254 |
+ while (len--) |
|
255 |
+ { |
|
256 |
+ if (key32 & 1) |
|
257 |
+ { |
|
258 |
+ key32 = key32 >> 1; |
|
259 |
+ key32 ^= 0x8c328834; |
|
260 |
+ } |
|
261 |
+ else |
|
262 |
+ { |
|
263 |
+ key32 = key32 >> 1; |
|
264 |
+ } |
|
265 |
+ *curr = *curr ^ (key32 & 0xff); |
|
266 |
+ curr++; |
|
267 |
+ } |
|
268 |
+ |
|
269 |
+ len = ssize - cli_readint32(ep + 0x429); /* sub size, value */ |
|
270 |
+ if (len >= (uint32_t)ssize) |
|
271 |
+ { |
|
272 |
+ free(spinned); |
|
273 |
+ cli_dbgmsg("spin: crc out of bounds, giving up\n"); |
|
274 |
+ return 1; |
|
275 |
+ } |
|
276 |
+ key32 = cli_readint32(ep + 0x3217) - summit(src, len); |
|
362 | 277 |
|
363 |
- while (notthesamelen) { |
|
364 |
- int xcfailure=0; |
|
365 |
- *emu=exec86(*emu, notthesamelen-- & 0xff, curr, &xcfailure); |
|
366 |
- if (xcfailure) { |
|
367 |
- cli_dbgmsg("spin: cannot exec section\n"); |
|
368 |
- return 1; |
|
369 |
- } |
|
278 |
+ memcpy(src + sections[sectcnt].raw, spinned, sections[sectcnt].rsz); |
|
279 |
+ free(spinned); /* done CRC'ing - can have a dirty buffer now */ |
|
280 |
+ ep = src + nep + sections[sectcnt].raw - sections[sectcnt].rva; /* Fix the helper */ |
|
281 |
+ |
|
282 |
+ if (!CLI_ISCONTAINED(src, ssize, ep + 0x3207, 4)) |
|
283 |
+ { /* this one holds all ep based checks */ |
|
284 |
+ cli_dbgmsg("spin: key out of bounds, giving up\n"); |
|
285 |
+ return 1; |
|
286 |
+ } |
|
287 |
+ bitmap = cli_readint32(ep + 0x3207); |
|
288 |
+ cli_dbgmsg("spin: Key32 is %x - XORbitmap is %x\n", key32, bitmap); |
|
289 |
+ |
|
290 |
+ cli_dbgmsg("spin: Decrypting sects (xor)\n"); |
|
291 |
+ for (j = 0; j < sectcnt; j++) |
|
292 |
+ { |
|
293 |
+ |
|
294 |
+ if (bitmap & 1) |
|
295 |
+ { |
|
296 |
+ uint32_t size = sections[j].rsz; |
|
297 |
+ char *ptr = src + sections[j].raw; |
|
298 |
+ uint32_t keydup = key32; |
|
299 |
+ |
|
300 |
+ if (!CLI_ISCONTAINED(src, ssize, ptr, size)) |
|
301 |
+ { |
|
302 |
+ cli_dbgmsg("spin: sect %d out of file, giving up\n", j); |
|
303 |
+ return 1; /* FIXME: Already checked in pe.c? */ |
|
304 |
+ } |
|
305 |
+ |
|
306 |
+ while (size--) |
|
307 |
+ { |
|
308 |
+ if (!(keydup & 1)) |
|
309 |
+ { |
|
310 |
+ keydup = keydup >> 1; |
|
311 |
+ keydup ^= 0xed43af31; |
|
312 |
+ } |
|
313 |
+ else |
|
314 |
+ { |
|
315 |
+ keydup = keydup >> 1; |
|
316 |
+ } |
|
317 |
+ *ptr = *ptr ^ (keydup & 0xff); |
|
318 |
+ ptr++; |
|
319 |
+ } |
|
320 |
+ } |
|
321 |
+ bitmap = bitmap >> 1; |
|
322 |
+ } |
|
323 |
+ |
|
324 |
+ cli_dbgmsg("spin: done\n"); |
|
325 |
+ |
|
326 |
+ curr = ep + 0x644; |
|
327 |
+ if ((len = cli_readint32(curr)) != 0x180) |
|
328 |
+ { |
|
329 |
+ cli_dbgmsg("spin: Not spinned or bad version\n"); |
|
330 |
+ return 1; |
|
331 |
+ } |
|
332 |
+ |
|
333 |
+ key32 = cli_readint32(curr + 0x0c); |
|
334 |
+ cli_dbgmsg("spin: Key is %x, Len is %x\n", key32, len); |
|
335 |
+ curr = ep + 0x28d3; |
|
336 |
+ |
|
337 |
+ if (!CLI_ISCONTAINED(src, ssize, curr, len)) |
|
338 |
+ { /* always true but i may decide to remove the previous check */ |
|
339 |
+ cli_dbgmsg("spin: key out of bounds, giving up\n"); |
|
340 |
+ return 1; |
|
341 |
+ } |
|
342 |
+ while (len--) |
|
343 |
+ { |
|
344 |
+ if (key32 & 1) |
|
345 |
+ { |
|
346 |
+ key32 = key32 >> 1; |
|
347 |
+ key32 ^= 0xed43af32; |
|
348 |
+ } |
|
349 |
+ else |
|
350 |
+ { |
|
351 |
+ key32 = key32 >> 1; |
|
352 |
+ } |
|
353 |
+ *curr = *curr ^ (key32 & 0xff); |
|
354 |
+ curr++; |
|
355 |
+ } |
|
356 |
+ |
|
357 |
+ curr = ep + 0x28dd; |
|
358 |
+ if ((len = cli_readint32(curr)) != 0x1a1) |
|
359 |
+ { |
|
360 |
+ cli_dbgmsg("spin: Not spinned or bad version\n"); |
|
361 |
+ return 1; |
|
362 |
+ } |
|
363 |
+ |
|
364 |
+ cli_dbgmsg("spin: POLY1 len is %x\n", len); |
|
365 |
+ curr += 0xf; /* POLY1 */ |
|
366 |
+ emu = ep + 0x6d4; |
|
367 |
+ if (!CLI_ISCONTAINED(src, ssize, emu, len)) |
|
368 |
+ { |
|
369 |
+ cli_dbgmsg("spin: poly1 out of bounds\n"); |
|
370 |
+ return 1; |
|
371 |
+ } |
|
372 |
+ while (len) |
|
373 |
+ { |
|
374 |
+ int xcfailure = 0; |
|
375 |
+ *emu = exec86(*emu, len-- & 0xff, curr, &xcfailure); /* unlame POLY1 */ |
|
376 |
+ if (xcfailure) |
|
377 |
+ { |
|
378 |
+ cli_dbgmsg("spin: cannot exec poly1\n"); |
|
379 |
+ return 1; |
|
380 |
+ } |
|
370 | 381 |
emu++; |
371 |
- } |
|
372 | 382 |
} |
373 |
- bitmap = bitmap >>1; |
|
374 |
- } |
|
375 |
- |
|
376 |
- cli_dbgmsg("spin: done\n"); |
|
377 |
- |
|
378 |
- bitmap = cli_readint32(ep+0x3061); |
|
379 |
- bitman = bitmap; |
|
380 |
- |
|
381 |
- /* FIXMELIMITS: possibly rewrite to use the limits api */ |
|
382 |
- if(ctx->engine->maxfilesize) { |
|
383 |
- unsigned long int filesize = 0; |
|
384 |
- |
|
385 |
- for (j=0; j<sectcnt; j++) { |
|
386 |
- if (bitmap&1) { |
|
387 |
- if ( filesize > ctx->engine->maxfilesize || sections[j].vsz > ctx->engine->maxfilesize - filesize ) return 2; |
|
388 |
- filesize += sections[j].vsz; |
|
389 |
- } |
|
390 |
- bitmap>>=1; |
|
383 |
+ |
|
384 |
+ bitmap = cli_readint32(ep + 0x6f1); |
|
385 |
+ cli_dbgmsg("spin: POLYbitmap is %x - decrypting sects (poly)\n", bitmap); |
|
386 |
+ curr = ep + 0x755; |
|
387 |
+ |
|
388 |
+ for (j = 0; j < sectcnt; j++) |
|
389 |
+ { |
|
390 |
+ if (bitmap & 1) |
|
391 |
+ { |
|
392 |
+ uint32_t notthesamelen = sections[j].rsz; |
|
393 |
+ |
|
394 |
+ emu = src + sections[j].raw; |
|
395 |
+ |
|
396 |
+ if (!CLI_ISCONTAINED(src, ssize, curr, 0x24)) |
|
397 |
+ { /* section bounds already checked twice now */ |
|
398 |
+ cli_dbgmsg("spin: poly1 emucode is out of file?\n"); |
|
399 |
+ return 1; |
|
400 |
+ } |
|
401 |
+ |
|
402 |
+ while (notthesamelen) |
|
403 |
+ { |
|
404 |
+ int xcfailure = 0; |
|
405 |
+ *emu = exec86(*emu, notthesamelen-- & 0xff, curr, &xcfailure); |
|
406 |
+ if (xcfailure) |
|
407 |
+ { |
|
408 |
+ cli_dbgmsg("spin: cannot exec section\n"); |
|
409 |
+ return 1; |
|
410 |
+ } |
|
411 |
+ emu++; |
|
412 |
+ } |
|
413 |
+ } |
|
414 |
+ bitmap = bitmap >> 1; |
|
391 | 415 |
} |
392 |
- |
|
393 |
- bitmap = bitman; |
|
394 |
- } |
|
395 |
- |
|
396 |
- cli_dbgmsg("spin: Compression bitmap is %x\n", bitmap); |
|
397 |
- if ( (sects= (char **) cli_malloc(sectcnt*sizeof(char *))) == NULL ) { |
|
398 |
- cli_dbgmsg("spin: malloc(%lu) failed\n", sectcnt*sizeof(char *)); |
|
399 |
- return 1; |
|
400 |
- } |
|
401 |
- |
|
402 |
- len = 0; |
|
403 |
- for (j=0; j<sectcnt; j++) { |
|
404 |
- if (bitmap&1) { |
|
405 |
- if ( (sects[j] = (char *) cli_malloc(sections[j].vsz) ) == NULL ) { |
|
406 |
- cli_dbgmsg("spin: malloc(%d) failed\n", sections[j].vsz); |
|
407 |
- len = 1; |
|
408 |
- break; |
|
409 |
- } |
|
410 |
- blobsz+=sections[j].vsz; |
|
411 |
- memset(sects[j], 0, sections[j].vsz); |
|
412 |
- cli_dbgmsg("spin: Growing sect%d: was %x will be %x\n", j, sections[j].rsz, sections[j].vsz); |
|
413 |
- if ( cli_unfsg(src + sections[j].raw, sects[j], sections[j].rsz, sections[j].vsz, NULL, NULL) == -1 ) { |
|
414 |
- len++; |
|
415 |
- cli_dbgmsg("spin: Unpack failure\n"); |
|
416 |
- } |
|
417 |
- } else { |
|
418 |
- blobsz+=sections[j].rsz; |
|
419 |
- sects[j] = src + sections[j].raw; |
|
420 |
- cli_dbgmsg("spin: Not growing sect%d\n", j); |
|
416 |
+ |
|
417 |
+ cli_dbgmsg("spin: done\n"); |
|
418 |
+ |
|
419 |
+ bitmap = cli_readint32(ep + 0x3061); |
|
420 |
+ bitman = bitmap; |
|
421 |
+ |
|
422 |
+ /* FIXMELIMITS: possibly rewrite to use the limits api */ |
|
423 |
+ if (ctx->engine->maxfilesize) |
|
424 |
+ { |
|
425 |
+ unsigned long int filesize = 0; |
|
426 |
+ |
|
427 |
+ for (j = 0; j < sectcnt; j++) |
|
428 |
+ { |
|
429 |
+ if (bitmap & 1) |
|
430 |
+ { |
|
431 |
+ if (filesize > ctx->engine->maxfilesize || sections[j].vsz > ctx->engine->maxfilesize - filesize) |
|
432 |
+ return 2; |
|
433 |
+ filesize += sections[j].vsz; |
|
434 |
+ } |
|
435 |
+ bitmap >>= 1; |
|
436 |
+ } |
|
437 |
+ |
|
438 |
+ bitmap = bitman; |
|
421 | 439 |
} |
422 |
- bitmap>>=1; |
|
423 |
- } |
|
424 |
- |
|
425 |
- cli_dbgmsg("spin: decompression complete\n"); |
|
426 |
- |
|
427 |
- if ( len ) { |
|
428 |
- int t; |
|
429 |
- for (t=0 ; t<j ; t++) { |
|
430 |
- if (bitman&1) |
|
431 |
- free(sects[t]); |
|
432 |
- bitman = bitman >>1 & 0x7fffffff; |
|
440 |
+ |
|
441 |
+ cli_dbgmsg("spin: Compression bitmap is %x\n", bitmap); |
|
442 |
+ if ((sects = (char **)cli_malloc(sectcnt * sizeof(char *))) == NULL) |
|
443 |
+ { |
|
444 |
+ cli_dbgmsg("spin: malloc(%lu) failed\n", sectcnt * sizeof(char *)); |
|
445 |
+ return 1; |
|
433 | 446 |
} |
434 |
- free(sects); |
|
435 |
- return 1; |
|
436 |
- } |
|
437 | 447 |
|
448 |
+ len = 0; |
|
449 |
+ for (j = 0; j < sectcnt; j++) |
|
450 |
+ { |
|
451 |
+ if (bitmap & 1) |
|
452 |
+ { |
|
453 |
+ if ((sects[j] = (char *)cli_malloc(sections[j].vsz)) == NULL) |
|
454 |
+ { |
|
455 |
+ cli_dbgmsg("spin: malloc(%d) failed\n", sections[j].vsz); |
|
456 |
+ len = 1; |
|
457 |
+ break; |
|
458 |
+ } |
|
459 |
+ blobsz += sections[j].vsz; |
|
460 |
+ memset(sects[j], 0, sections[j].vsz); |
|
461 |
+ cli_dbgmsg("spin: Growing sect%d: was %x will be %x\n", j, sections[j].rsz, sections[j].vsz); |
|
462 |
+ if (cli_unfsg(src + sections[j].raw, sects[j], sections[j].rsz, sections[j].vsz, NULL, NULL) == -1) |
|
463 |
+ { |
|
464 |
+ len++; |
|
465 |
+ cli_dbgmsg("spin: Unpack failure\n"); |
|
466 |
+ } |
|
467 |
+ } |
|
468 |
+ else |
|
469 |
+ { |
|
470 |
+ blobsz += sections[j].rsz; |
|
471 |
+ sects[j] = src + sections[j].raw; |
|
472 |
+ cli_dbgmsg("spin: Not growing sect%d\n", j); |
|
473 |
+ } |
|
474 |
+ bitmap >>= 1; |
|
475 |
+ } |
|
438 | 476 |
|
439 |
- key32 = cli_readint32(ep+0x2fee); |
|
440 |
- if (key32) { |
|
441 |
- /* len = cli_readint32(ep+0x2fc8); -- Using vsizes instead */ |
|
477 |
+ cli_dbgmsg("spin: decompression complete\n"); |
|
478 |
+ |
|
479 |
+ if (len) |
|
480 |
+ { |
|
481 |
+ int t; |
|
482 |
+ for (t = 0; t < j; t++) |
|
483 |
+ { |
|
484 |
+ if (bitman & 1) |
|
485 |
+ free(sects[t]); |
|
486 |
+ bitman = bitman >> 1 & 0x7fffffff; |
|
487 |
+ } |
|
488 |
+ free(sects); |
|
489 |
+ return 1; |
|
490 |
+ } |
|
442 | 491 |
|
443 |
- for (j=0; j<sectcnt; j++) { |
|
444 |
- if (sections[j].rva <= key32 && key32-sections[j].rva < sections[j].vsz && CLI_ISCONTAINED(src + sections[j].raw, sections[j].rsz, src + sections[j].raw, key32 - sections[j].rva)) |
|
445 |
- break; |
|
492 |
+ key32 = cli_readint32(ep + 0x2fee); |
|
493 |
+ if (key32) |
|
494 |
+ { |
|
495 |
+ /* len = cli_readint32(ep+0x2fc8); -- Using vsizes instead */ |
|
496 |
+ |
|
497 |
+ for (j = 0; j < sectcnt; j++) |
|
498 |
+ { |
|
499 |
+ if (sections[j].rva <= key32 && key32 - sections[j].rva < sections[j].vsz && CLI_ISCONTAINED(src + sections[j].raw, sections[j].rsz, src + sections[j].raw, key32 - sections[j].rva)) |
|
500 |
+ break; |
|
501 |
+ } |
|
502 |
+ |
|
503 |
+ if (j != sectcnt && ((bitman & (1 << j)) == 0)) |
|
504 |
+ { /* FIXME: not really sure either the res sect is lamed or just compressed, but this'll save some major headakes */ |
|
505 |
+ cli_dbgmsg("spin: Resources (sect%d) appear to be compressed\n\tuncompressed offset %x, len %x\n\tcompressed offset %x, len %x\n", j, sections[j].rva, key32 - sections[j].rva, key32, sections[j].vsz - (key32 - sections[j].rva)); |
|
506 |
+ |
|
507 |
+ if ((curr = (char *)cli_malloc(sections[j].vsz)) != NULL) |
|
508 |
+ { |
|
509 |
+ memcpy(curr, src + sections[j].raw, key32 - sections[j].rva); /* Uncompressed part */ |
|
510 |
+ memset(curr + key32 - sections[j].rva, 0, sections[j].vsz - (key32 - sections[j].rva)); /* bzero */ |
|
511 |
+ if (cli_unfsg(src + sections[j].raw + key32 - sections[j].rva, curr + key32 - sections[j].rva, sections[j].rsz - (key32 - sections[j].rva), sections[j].vsz - (key32 - sections[j].rva), NULL, NULL)) |
|
512 |
+ { |
|
513 |
+ |
|
514 |
+ free(curr); |
|
515 |
+ cli_dbgmsg("spin: Failed to grow resources, continuing anyway\n"); |
|
516 |
+ blobsz += sections[j].rsz; |
|
517 |
+ } |
|
518 |
+ else |
|
519 |
+ { |
|
520 |
+ sects[j] = curr; |
|
521 |
+ bitman |= 1 << j; |
|
522 |
+ cli_dbgmsg("spin: Resources grown\n"); |
|
523 |
+ blobsz += sections[j].vsz; |
|
524 |
+ } |
|
525 |
+ } |
|
526 |
+ else |
|
527 |
+ { |
|
528 |
+ /* malloc failed but i'm too deep into this crap to quit without leaking more :( */ |
|
529 |
+ cli_dbgmsg("spin: memory allocation failed, continuing anyway\n"); |
|
530 |
+ blobsz += sections[j].rsz; |
|
531 |
+ } |
|
532 |
+ } |
|
533 |
+ else |
|
534 |
+ { |
|
535 |
+ cli_dbgmsg("spin: No res?!\n"); |
|
536 |
+ } |
|
446 | 537 |
} |
447 | 538 |
|
448 |
- if (j!=sectcnt && ((bitman & (1<<j)) == 0)) { /* FIXME: not really sure either the res sect is lamed or just compressed, but this'll save some major headakes */ |
|
449 |
- cli_dbgmsg("spin: Resources (sect%d) appear to be compressed\n\tuncompressed offset %x, len %x\n\tcompressed offset %x, len %x\n", j, sections[j].rva, key32 - sections[j].rva, key32, sections[j].vsz - (key32 - sections[j].rva)); |
|
450 |
- |
|
451 |
- if ( (curr=(char *)cli_malloc(sections[j].vsz)) != NULL ) { |
|
452 |
- memcpy(curr, src + sections[j].raw, key32 - sections[j].rva); /* Uncompressed part */ |
|
453 |
- memset(curr + key32 - sections[j].rva, 0, sections[j].vsz - (key32 - sections[j].rva)); /* bzero */ |
|
454 |
- if ( cli_unfsg(src + sections[j].raw + key32 - sections[j].rva, curr + key32 - sections[j].rva, sections[j].rsz - (key32 - sections[j].rva), sections[j].vsz - (key32 - sections[j].rva), NULL, NULL) ) { |
|
455 |
- |
|
456 |
- free(curr); |
|
457 |
- cli_dbgmsg("spin: Failed to grow resources, continuing anyway\n"); |
|
458 |
- blobsz+=sections[j].rsz; |
|
459 |
- } else { |
|
460 |
- sects[j]=curr; |
|
461 |
- bitman|=1<<j; |
|
462 |
- cli_dbgmsg("spin: Resources grown\n"); |
|
463 |
- blobsz+=sections[j].vsz; |
|
464 |
- } |
|
465 |
- } else { |
|
466 |
- /* malloc failed but i'm too deep into this crap to quit without leaking more :( */ |
|
467 |
- cli_dbgmsg("spin: memory allocation failed, continuing anyway\n"); |
|
468 |
- blobsz+=sections[j].rsz; |
|
469 |
- } |
|
470 |
- } else { |
|
471 |
- cli_dbgmsg("spin: No res?!\n"); |
|
539 |
+ bitmap = bitman; /* save as a free() bitmap */ |
|
540 |
+ |
|
541 |
+ if ((ep = (char *)cli_malloc(blobsz)) != NULL) |
|
542 |
+ { |
|
543 |
+ struct cli_exe_section *rebhlp; |
|
544 |
+ if ((rebhlp = (struct cli_exe_section *)cli_malloc(sizeof(struct cli_exe_section) * (sectcnt))) != NULL) |
|
545 |
+ { |
|
546 |
+ char *to = ep; |
|
547 |
+ int retval = 0; |
|
548 |
+ |
|
549 |
+ for (j = 0; j < sectcnt; j++) |
|
550 |
+ { |
|
551 |
+ rebhlp[j].raw = (j > 0) ? (rebhlp[j - 1].raw + rebhlp[j - 1].rsz) : 0; |
|
552 |
+ rebhlp[j].rsz = (bitmap & 1) ? sections[j].vsz : sections[j].rsz; |
|
553 |
+ rebhlp[j].rva = sections[j].rva; |
|
554 |
+ rebhlp[j].vsz = sections[j].vsz; |
|
555 |
+ |
|
556 |
+ memcpy(to, sects[j], rebhlp[j].rsz); |
|
557 |
+ to += rebhlp[j].rsz; |
|
558 |
+ if (bitmap & 1) |
|
559 |
+ free(sects[j]); |
|
560 |
+ bitmap = bitmap >> 1; |
|
561 |
+ } |
|
562 |
+ |
|
563 |
+ if (!cli_rebuildpe(ep, rebhlp, sectcnt, 0x400000, 0x1000, 0, 0, desc)) |
|
564 |
+ { /* can't be bothered fixing those values: the rebuilt exe is completely broken anyway. */ |
|
565 |
+ cli_dbgmsg("spin: Cannot write unpacked file\n"); |
|
566 |
+ retval = 1; |
|
567 |
+ } |
|
568 |
+ free(rebhlp); |
|
569 |
+ free(ep); |
|
570 |
+ free(sects); |
|
571 |
+ return retval; |
|
572 |
+ } |
|
573 |
+ free(ep); |
|
472 | 574 |
} |
473 |
- } |
|
474 |
- |
|
475 |
- |
|
476 |
- bitmap=bitman; /* save as a free() bitmap */ |
|
477 |
- |
|
478 |
- if ( (ep = (char *) cli_malloc(blobsz)) != NULL ) { |
|
479 |
- struct cli_exe_section *rebhlp; |
|
480 |
- if ( (rebhlp = (struct cli_exe_section *) cli_malloc(sizeof(struct cli_exe_section)*(sectcnt))) != NULL ) { |
|
481 |
- char *to = ep; |
|
482 |
- int retval = 0; |
|
483 |
- |
|
484 |
- for (j = 0; j < sectcnt; j++) { |
|
485 |
- rebhlp[j].raw = (j>0)?(rebhlp[j-1].raw + rebhlp[j-1].rsz):0; |
|
486 |
- rebhlp[j].rsz = (bitmap &1) ? sections[j].vsz : sections[j].rsz; |
|
487 |
- rebhlp[j].rva = sections[j].rva; |
|
488 |
- rebhlp[j].vsz = sections[j].vsz; |
|
489 |
- |
|
490 |
- memcpy(to, sects[j], rebhlp[j].rsz); |
|
491 |
- to+=rebhlp[j].rsz; |
|
492 |
- if ( bitmap & 1 ) free(sects[j]); |
|
493 |
- bitmap = bitmap >>1; |
|
494 |
- } |
|
495 |
- |
|
496 |
- if (! cli_rebuildpe(ep, rebhlp, sectcnt, 0x400000, 0x1000, 0, 0, desc)) { /* can't be bothered fixing those values: the rebuilt exe is completely broken anyway. */ |
|
497 |
- cli_dbgmsg("spin: Cannot write unpacked file\n"); |
|
498 |
- retval = 1; |
|
499 |
- } |
|
500 |
- free(rebhlp); |
|
501 |
- free(ep); |
|
502 |
- free(sects); |
|
503 |
- return retval; |
|
575 |
+ |
|
576 |
+ cli_dbgmsg("spin: free bitmap is %x\n", bitman); |
|
577 |
+ for (j = 0; j < sectcnt; j++) |
|
578 |
+ { |
|
579 |
+ if (bitmap & 1) |
|
580 |
+ free(sects[j]); |
|
581 |
+ bitman = bitman >> 1 & 0x7fffffff; |
|
504 | 582 |
} |
505 |
- free(ep); |
|
506 |
- } |
|
507 |
- |
|
508 |
- cli_dbgmsg ("spin: free bitmap is %x\n", bitman); |
|
509 |
- for (j=0; j<sectcnt; j++) { |
|
510 |
- if (bitmap&1) free(sects[j]); |
|
511 |
- bitman = bitman >>1 & 0x7fffffff; |
|
512 |
- } |
|
513 |
- free(sects); |
|
514 |
- return 1; /* :( */ |
|
583 |
+ free(sects); |
|
584 |
+ return 1; /* :( */ |
|
515 | 585 |
} |