Browse code

Improvements and fixups for pespin unpacker

git-svn: trunk@1692

aCaB authored on 2005/08/14 02:17:14
Showing 2 changed files
... ...
@@ -1,3 +1,7 @@
1
+Sat Aug 13 19:08:55 CEST 2005 (acab)
2
+-----------------------------------
3
+  * libclamav/spin.c: improvements and fixups
4
+
1 5
 Fri Aug 12 18:17:59 CEST 2005 (tk)
2 6
 ----------------------------------
3 7
   * libclamav/filetypes.c: update zip-sfx type signature (Sven Strickroth)
... ...
@@ -75,16 +75,16 @@ static inline uint32_t EC32(uint32_t v)
75 75
 #define ROR(a,b) a = ( a >> (b % (sizeof(a)<<3) ))  |  (a << (  (sizeof(a)<<3)  -  (b % (sizeof(a)<<3 )) ) )
76 76
 
77 77
 
78
-/* FIXME: poly block is fixed size */
79
-static char exec86(uint8_t aelle, uint8_t cielle, char *curremu) {  
80
-  while (*curremu!='\xaa') {
81
-    uint8_t opcode = *curremu, support;
82
-    curremu++;
78
+static char exec86(uint8_t aelle, uint8_t cielle, char *curremu) {
79
+  int len = 0;
80
+  while (len <0x24) {
81
+    uint8_t opcode = curremu[len], support;
82
+    len++;
83 83
     switch (opcode) {
84 84
       case 0xeb:
85
-        curremu++;
85
+        len++;
86 86
       case 0x0a:
87
-        curremu++;
87
+        len++;
88 88
       case 0x90:
89 89
       case 0xf8:
90 90
       case 0xf9:
... ...
@@ -92,47 +92,49 @@ static char exec86(uint8_t aelle, uint8_t cielle, char *curremu) {
92 92
 
93 93
       case 0x02: /* add al, cl */
94 94
         aelle+=cielle;
95
-	curremu++;
95
+	len++;
96 96
         break;
97 97
       case 0x2a: /* sub al, cl */
98 98
         aelle-=cielle;
99
-	curremu++;
99
+	len++;
100 100
         break;
101 101
       case 0x04: /* add al, ?? */
102
-        aelle+=*curremu;
103
-	curremu++;
102
+        aelle+=curremu[len];
103
+	len++;
104 104
         break;
105 105
       case 0x2c: /* sub al, ?? */
106
-        aelle-=*curremu;
107
-	curremu++;
106
+        aelle-=curremu[len];
107
+	len++;
108 108
         break;
109 109
       case 0x32: /* xor al, cl */
110 110
         aelle^=cielle;
111
-	curremu++;
111
+	len++;
112 112
         break;
113 113
       case 0x34: /* xor al, ?? */
114
-        aelle^=*curremu;
115
-	curremu++;
114
+        aelle^=curremu[len];
115
+	len++;
116 116
         break;
117 117
 
118 118
       case 0xfe: /* inc/dec al */
119
-        if ( *curremu == '\xc0' ) aelle++;
119
+        if ( curremu[len] == '\xc0' ) aelle++;
120 120
 	else aelle--;
121
-        curremu++;
121
+        len++;
122 122
         break;
123 123
 
124 124
       case 0xc0: /* ror/rol al, ?? */
125
-	support = *curremu;
126
-        curremu++;
127
-        if ( support == 0xc0 ) ROL(aelle, *curremu);
128
-        else ROR(aelle, *curremu);
129
-        curremu++;
125
+	support = curremu[len];
126
+        len++;
127
+        if ( support == 0xc0 ) ROL(aelle, curremu[len]);
128
+        else ROR(aelle, curremu[len]);
129
+        len++;
130 130
         break;
131 131
 
132 132
       default:
133 133
         cli_dbgmsg("Bogus opcode %x\n", opcode);
134 134
     }
135 135
   }
136
+  if ( len!=0x24 || curremu[len]!='\xaa' )
137
+    cli_dbgmsg("spin: bad emucode\n"); // FIXME: I should really give up here
136 138
   return aelle;
137 139
 }
138 140
 
... ...
@@ -261,7 +263,7 @@ static int unfsg(char *source, char *dest, int ssize, int dsize) {
261 261
 	}
262 262
 	lostbit = 0;
263 263
       }
264
-      if ((backsize >= dest + dsize - cdst) || (backbytes > cdst - dest))
264
+      if ((backsize > dest + dsize - cdst) || (backbytes > cdst - dest))
265 265
 	return -1;
266 266
       while(backsize--) {
267 267
 	*cdst=*(cdst-backbytes);
... ...
@@ -346,12 +348,20 @@ int unspin(char *src, int ssize, struct pe_image_section_hdr *sections, int sect
346 346
 
347 347
   cli_dbgmsg("spin: Key8 is %x, Len is %x\n", key8, len);
348 348
 
349
-  if (  ep - spinned >= EC32(sections[sectcnt].SizeOfRawData) - len - 0x1fe5 ) {
349
+  if ( ep - spinned >= EC32(sections[sectcnt].SizeOfRawData) - len - 0x1fe5 ) {
350 350
     free(spinned);
351 351
     cli_dbgmsg("spin: len out of bounds, giving up\n");
352 352
     return 1; // Outta bounds - HELP: i suppose i should check for wraps.. not sure though
353 353
   }
354 354
 
355
+
356
+  if ( ep[0x1e0]!='\xb8' )
357
+    cli_dbgmsg("spin: prolly not spinned, expect failure\n");
358
+  
359
+  if ( (cli_readint32(ep+0x1e1) & 0x00200000) )
360
+    cli_dbgmsg("spin: password protected, expect failure\n");
361
+
362
+
355 363
   curr = ep+0x1fe5+len-1;
356 364
   while ( len-- ) {
357 365
     *curr=(*curr)^(key8--);
... ...
@@ -363,7 +373,7 @@ int unspin(char *src, int ssize, struct pe_image_section_hdr *sections, int sect
363 363
   if ( (len = cli_readint32(curr+5)) != 0x5a0) {
364 364
     free(spinned);
365 365
     cli_dbgmsg("spin: Not spinned or bad version\n");
366
-    return 1; // FIXME: apparently static
366
+    return 1;
367 367
   }
368 368
 
369 369
   curr = ep+0x2d5; // 0x2d5+5a0 < 0x3217 - still within bounds (checked by caller)
... ...
@@ -380,8 +390,6 @@ int unspin(char *src, int ssize, struct pe_image_section_hdr *sections, int sect
380 380
     curr++;
381 381
   }
382 382
 
383
-
384
-  cli_dbgmsg("spin: here\n");
385 383
   len = ssize - cli_readint32(ep+0x429); // sub size, value
386 384
   if ( len >= ssize ) {
387 385
     free(spinned);
... ...
@@ -394,11 +402,10 @@ int unspin(char *src, int ssize, struct pe_image_section_hdr *sections, int sect
394 394
   free(spinned); // done CRC'ing - can have a dirty buffer now
395 395
   ep = src + nep + sections[sectcnt].PointerToRawData - sections[sectcnt].VirtualAddress; // Fix the helper
396 396
 
397
-  cli_dbgmsg("spin: Key32 is %x\n", key32);
398
-
399 397
   bitmap = cli_readint32(ep+0x3207);
400
-  cli_dbgmsg("spin: XORbitmap is %x\n", bitmap);
401
-
398
+  cli_dbgmsg("spin: Key32 is %x - XORbitmap is %x\n", key32, bitmap);
399
+  
400
+  cli_dbgmsg("spin: Decrypting sects (xor)\n");
402 401
   for (j=0; j<sectcnt; j++) {
403 402
     if (bitmap&1) {
404 403
       uint32_t size = EC32(sections[j].SizeOfRawData);
... ...
@@ -424,9 +431,10 @@ int unspin(char *src, int ssize, struct pe_image_section_hdr *sections, int sect
424 424
       bitmap = bitmap >>1 & 0x7fffffff; /* HELP: clear sign bit for unsigned values too? */
425 425
     }
426 426
   }
427
+  
427 428
   cli_dbgmsg("spin: done\n");
428 429
 
429
-
430
+  
430 431
   curr = ep+0x644; // 0x28d3+0x180 < 0x3217 - still within bounds (checked by caller)
431 432
   if ( (len = cli_readint32(curr)) != 0x180) {
432 433
     cli_dbgmsg("spin: Not spinned or bad version\n");
... ...
@@ -465,8 +473,9 @@ int unspin(char *src, int ssize, struct pe_image_section_hdr *sections, int sect
465 465
     emu++;
466 466
   }
467 467
 
468
+
468 469
   bitmap = cli_readint32(ep+0x6f1);
469
-  cli_dbgmsg("spin: POLYbitmap is %x\n", bitmap);
470
+  cli_dbgmsg("spin: POLYbitmap is %x - decrypting sects (poly)\n", bitmap);
470 471
   curr = ep+0x755;
471 472
 
472 473
   for (j=0; j<sectcnt; j++) {
... ...
@@ -489,6 +498,8 @@ int unspin(char *src, int ssize, struct pe_image_section_hdr *sections, int sect
489 489
 
490 490
     }
491 491
   }
492
+  
493
+  cli_dbgmsg("spin: done\n");
492 494
 
493 495
   bitmap = cli_readint32(ep+0x3061);
494 496
   bitman = bitmap;
... ...
@@ -500,13 +511,17 @@ int unspin(char *src, int ssize, struct pe_image_section_hdr *sections, int sect
500 500
   for (j=0; j<sectcnt; j++) {
501 501
     if (bitmap&1) {
502 502
        if ( (sects[j] = (char *) cli_malloc(EC32(sections[j].VirtualSize)) ) == NULL ) { // FIXME: use "static" maxmalloc @4380b6 instead???
503
+	 cli_dbgmsg("spin: malloc(%d) failed\n", EC32(sections[j].VirtualSize));
503 504
 	 len = 1;
504 505
 	 break;
505 506
        }
506 507
        blobsz+=EC32(sections[j].VirtualSize);
507 508
        memset(sects[j], 0, EC32(sections[j].VirtualSize));
508 509
        cli_dbgmsg("spin: Growing sect%d: was %x will be %x\n", j, EC32(sections[j].SizeOfRawData), EC32(sections[j].VirtualSize));
509
-       len = unfsg(src + EC32(sections[j].PointerToRawData), sects[j], EC32(sections[j].SizeOfRawData), EC32(sections[j].VirtualSize)); // FIXME: checr retval
510
+       if ( unfsg(src + EC32(sections[j].PointerToRawData), sects[j], EC32(sections[j].SizeOfRawData), EC32(sections[j].VirtualSize)) == -1 ) {
511
+	 len++;
512
+         cli_dbgmsg("spin: Unpack failure\n");
513
+       }
510 514
        // sections[j].rsz = sections[j].vsz; FIXME: can't hack the caller, gotta find a better way!
511 515
     } else {
512 516
       blobsz+=EC32(sections[j].SizeOfRawData);
... ...
@@ -515,12 +530,16 @@ int unspin(char *src, int ssize, struct pe_image_section_hdr *sections, int sect
515 515
     }
516 516
     bitmap = bitmap >>1 & 0x7fffffff;
517 517
   }
518
-
518
+  
519
+  cli_dbgmsg("spin: decompression complete\n");
520
+ 
519 521
   if ( len ) {
520 522
     int t;
521
-    for (t=0 ; t<j ; t++)
523
+    for (t=0 ; t<j ; t++) {
522 524
       if (bitman&1)
523 525
 	free(sects[t]);
526
+      bitman = bitman >>1 & 0x7fffffff;
527
+    }
524 528
     free(sects);
525 529
     return 1;
526 530
   }
... ...
@@ -535,10 +554,10 @@ int unspin(char *src, int ssize, struct pe_image_section_hdr *sections, int sect
535 535
 	break;
536 536
     }
537 537
 
538
-      cli_dbgmsg("spin: --- %x < %x < %x  %d / %d\n", EC32(sections[j].VirtualAddress), key32, EC32(sections[j].VirtualAddress)+EC32(sections[j].SizeOfRawData), j, sectcnt);
538
+//      cli_dbgmsg("spin: --- %x < %x < %x  %d / %d\n", EC32(sections[j].VirtualAddress), key32, EC32(sections[j].VirtualAddress)+EC32(sections[j].SizeOfRawData), j, sectcnt);
539 539
 
540 540
     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
541
-      cli_dbgmsg("spin: Resources (sect%d) appear to be compressed\n  uncompressed offset %x, len %x\n  compressed offset %x, len %x\n", j, EC32(sections[j].VirtualAddress), key32 - EC32(sections[j].VirtualAddress), key32, EC32(sections[j].VirtualSize) - (key32 - EC32(sections[j].VirtualAddress)));
541
+      cli_dbgmsg("spin: Resources (sect%d) appear to be compressed\n\tuncompressed offset %x, len %x\n\tcompressed offset %x, len %x\n", j, EC32(sections[j].VirtualAddress), key32 - EC32(sections[j].VirtualAddress), key32, EC32(sections[j].VirtualSize) - (key32 - EC32(sections[j].VirtualAddress)));
542 542
 
543 543
       if ( (curr=(char *)cli_malloc(EC32(sections[j].VirtualSize))) != NULL ) {
544 544
 	memcpy(curr, src + EC32(sections[j].PointerToRawData), key32 - EC32(sections[j].VirtualAddress)); // Uncompressed part