Browse code

upx revert + kriz detection

git-svn: trunk@2054

aCaB authored on 2006/06/30 03:43:35
Showing 3 changed files
... ...
@@ -1,3 +1,7 @@
1
+Thu Jun 29 19:42:01 CEST 2006 (acab)
2
+  * libclamav: Revert old UPX code due to bugs
3
+               Add algorithmic detection of Win32.Kriz
4
+
1 5
 Wed Jun 28 17:16:06 BST 2006 (njh)
2 6
 ----------------------------------
3 7
   * libclamav/mbox.c:	Code tidy
... ...
@@ -87,6 +87,30 @@ static uint32_t cli_rawaddr(uint32_t rva, struct pe_image_section_hdr *shp, uint
87 87
     return rva - EC32(shp[i].VirtualAddress) + EC32(shp[i].PointerToRawData);
88 88
 }
89 89
 
90
+static void xckriz(char **opcode, int *len, int checksize, int reg) {
91
+	while(*len>6) {
92
+		if (**opcode>='\x48' && **opcode<='\x4f' && **opcode!='\x4c') {
93
+			if ((char)(**opcode-reg)=='\x48') break;
94
+			(*len)--;
95
+			(*opcode)++;
96
+			continue;
97
+		}
98
+		if (**opcode>='\xb8' && **opcode<='\xbf' && **opcode!='\xbc') {
99
+			if (checksize && cli_readint32(*opcode+1)==0x0fd2) break;
100
+			(*len)-=5;
101
+			(*opcode)+=5;
102
+			continue;
103
+		}
104
+		if (**opcode=='\x81') {
105
+			(*len)-=6;
106
+			(*opcode)+=6;
107
+			continue;
108
+		}
109
+		break;
110
+	}
111
+}
112
+
113
+
90 114
 /*
91 115
 static int cli_ddump(int desc, int offset, int size, const char *file)
92 116
 {
... ...
@@ -590,6 +614,67 @@ int cli_scanpe(int desc, cli_ctx *ctx)
590 590
 	}
591 591
     }
592 592
 
593
+    /* Kriz */
594
+    if(SCAN_ALGO && CLI_ISCONTAINED(EC32(section_hdr[nsections - 1].PointerToRawData), EC32(section_hdr[nsections - 1].SizeOfRawData), ep, 0x0fd2)) {
595
+	cli_dbgmsg("in kriz\n");
596
+	lseek(desc, ep, SEEK_SET);
597
+	if(read(desc, buff, 200) == 200) {
598
+		while (1) {
599
+			char *krizpos=buff+3;
600
+			char *krizmov, *krizxor;
601
+			int krizleft = 200-3;
602
+			int krizrega,krizregb;
603
+
604
+			if (buff[1]!='\x9c' || buff[2]!='\x60') break; /* EP+1 */
605
+			xckriz(&krizpos, &krizleft, 0, 8);
606
+			if (krizleft < 6 || *krizpos!='\xe8' || krizpos[2] || krizpos[3] || krizpos[4]) break; /* call DELTA */
607
+			krizleft-=5+(unsigned char)krizpos[1];
608
+			if (krizleft < 2) break;
609
+			krizpos+=5+(unsigned char)krizpos[1];
610
+			if (*krizpos<'\x58' || *krizpos>'\x5f' || *krizpos=='\x5c') break; /* pop DELTA */
611
+			krizrega=*krizpos-'\x58';
612
+			cli_dbgmsg("kriz: pop delta using %d\n", krizrega);
613
+			krizpos+=1;
614
+			krizleft-=1;
615
+			xckriz(&krizpos, &krizleft, 1, 8);
616
+			if (krizleft <6 || *krizpos<'\xb8' || *krizpos>'\xbf' || *krizpos=='\xbc' || cli_readint32(krizpos+1)!=0x0fd2) break;
617
+			krizregb=*krizpos-'\xb8';
618
+			if (krizrega==krizregb) break;
619
+			cli_dbgmsg("kriz: using %d for size\n", krizregb);
620
+			krizpos+=5;
621
+			krizleft-=5;
622
+			krizmov = krizpos;
623
+			xckriz(&krizpos, &krizleft, 0, 8);
624
+			krizxor=krizpos;
625
+			if (krizleft && *krizpos=='\x3e') {
626
+				/* strip ds: */
627
+				krizpos++;
628
+				krizleft--;
629
+			}
630
+			if (krizleft<8 || *krizpos!='\x80' || (char)(krizpos[1]-krizrega)!='\xb0') {
631
+				cli_dbgmsg("kriz: bogus opcode or register\n");
632
+				break;
633
+			}
634
+			krizpos+=7;
635
+			krizleft-=7;
636
+			xckriz(&krizpos, &krizleft, 0, krizrega);
637
+			if (! krizleft || (char)(*krizpos-krizrega)!='\x48') break; /* dec delta */
638
+			krizpos++;
639
+			krizleft--;
640
+			cli_dbgmsg("kriz: dec delta found\n");
641
+			xckriz(&krizpos, &krizleft, 0, krizregb);
642
+                        if (krizleft <4 || (char)(*krizpos-krizregb)!='\x48' || krizpos[1]!='\x75') break; /* dec size + jne loop */
643
+			if (krizpos+3+(int)krizpos[2]<krizmov || krizpos+3+(int)krizpos[2]>krizxor) {
644
+				cli_dbgmsg("kriz: jmp back out of range (%d>%d>%d)\n", krizmov-(krizpos+3), (int)krizpos[2], krizxor-(krizpos+3));
645
+				break;
646
+			}
647
+			*ctx->virname = "Win32.Kriz";
648
+			free(section_hdr);
649
+			return CL_VIRUS;
650
+		}
651
+	}
652
+    }
653
+
593 654
     /* W32.Magistr.A/B */
594 655
     if(SCAN_ALGO && !dll && (EC32(section_hdr[nsections - 1].Characteristics) & 0x80000000)) {
595 656
 	    uint32_t rsize, vsize;
... ...
@@ -69,16 +69,9 @@
69 69
 \x63\x6C\x61\x6D\x61\x76\x2E\x6E\x65\x74\x0D\x0A\x24\x00\x00\x00\
70 70
 "
71 71
 
72
-#if WORDS_BIGENDIAN == 0
73
-#define CLI_READLE32(x) (*(int32_t *)(x))
74
-#else
75
-#define CLI_READLE32(x) (((*x) >> 24) | ((*(x+1) & 0x00FF0000) >> 8) | \
76
-			    ((*(x+2) & 0x0000FF00) << 8) | (*(x) << 24))
77
-#endif
78
-
79 72
 /* PE from UPX */
80 73
 
81
-static int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0, uint32_t upx1, uint32_t magic)
74
+int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0, uint32_t upx1, uint32_t magic)
82 75
 {
83 76
   char *imports, *sections, *pehdr, *newbuf;
84 77
   int sectcnt, upd=1;
... ...
@@ -88,7 +81,7 @@ static int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32
88 88
   if((dst == NULL) || (src == NULL))
89 89
     return 0;
90 90
 
91
-  imports = dst + CLI_READLE32(src + ep - upx1 + magic);
91
+  imports = dst + cli_readint32(src + ep - upx1 + magic);
92 92
 
93 93
   realstuffsz = imports-dst;
94 94
   
... ...
@@ -98,7 +91,7 @@ static int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32
98 98
   }
99 99
   
100 100
   pehdr = imports;
101
-  while (CLI_ISCONTAINED(dst, *dsize,  pehdr, 8) && CLI_READLE32(pehdr)) {
101
+  while (CLI_ISCONTAINED(dst, *dsize,  pehdr, 8) && cli_readint32(pehdr)) {
102 102
     pehdr+=8;
103 103
     while(CLI_ISCONTAINED(dst, *dsize,  pehdr, 2) && *pehdr) {
104 104
       pehdr++;
... ...
@@ -114,24 +107,13 @@ static int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32
114 114
     cli_dbgmsg("UPX: sections out of bounds - giving up rebuild\n");
115 115
     return 0;
116 116
   }
117
-
118
-  if ( CLI_READLE32(pehdr) != 0x4550 ) {
119
-    cli_dbgmsg("UPX: OOPS: no magic for PE - scanning\n");
120
-    while (CLI_ISCONTAINED(dst, *dsize,  pehdr, 2) && 
121
-	    CLI_READLE32(pehdr) != 0x4550) {
122
-	pehdr+=2;
123
-	while (CLI_ISCONTAINED(dst, *dsize,  pehdr, 2) && *pehdr)
124
-	    pehdr++;
125
-	pehdr++;
126
-    }
127
-  }
128 117
   
129
-  if (!CLI_ISCONTAINED(dst, *dsize,  pehdr, 0xf8)){
130
-    cli_dbgmsg("UPX: Magic for PE - not found, aborting!\n");
118
+  if ( cli_readint32(pehdr) != 0x4550 ) {
119
+    cli_dbgmsg("UPX: No magic for PE - giving up rebuild\n");
131 120
     return 0;
132 121
   }
133 122
   
134
-  if (! CLI_READLE32(pehdr+0x38)) {
123
+  if (! cli_readint32(pehdr+0x38)) {
135 124
     cli_dbgmsg("UPX: Cant align to a NULL bound - giving up rebuild\n");
136 125
     return 0;
137 126
   }
... ...
@@ -150,9 +132,9 @@ static int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32
150 150
   }
151 151
   
152 152
   for (upd = 0; upd <sectcnt ; upd++) {
153
-    uint32_t vsize=CLI_READLE32(sections+8)-1;
154
-    uint32_t rsize=CLI_READLE32(sections+16);
155
-    uint32_t urva=CLI_READLE32(sections+12);
153
+    uint32_t vsize=cli_readint32(sections+8)-1;
154
+    uint32_t rsize=cli_readint32(sections+16);
155
+    uint32_t urva=cli_readint32(sections+12);
156 156
     
157 157
     vsize=(((vsize/0x1000)+1)*0x1000); /* FIXME: get bounds from header */
158 158
     
... ...
@@ -169,7 +151,7 @@ static int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32
169 169
     }
170 170
     
171 171
     /* Am i been fooled? There are better ways ;) */
172
-    if ( rsize+4 < vsize && CLI_READLE32(dst+urva-upx0+rsize) ) {
172
+    if ( rsize+4 < vsize && cli_readint32(dst+urva-upx0+rsize) ) {
173 173
       cli_dbgmsg("UPX: Am i been fooled? - giving up rebuild\n", upd);
174 174
       return 0;
175 175
     }
... ...
@@ -192,7 +174,7 @@ static int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32
192 192
   memcpy(newbuf+0xd0, pehdr,0xf8+0x28*sectcnt);
193 193
   sections = pehdr+0xf8;
194 194
   for (upd = 0; upd <sectcnt ; upd++) {
195
-    memcpy(newbuf+CLI_READLE32(sections+20), dst+CLI_READLE32(sections+12)-upx0, CLI_READLE32(sections+16));
195
+    memcpy(newbuf+cli_readint32(sections+20), dst+cli_readint32(sections+12)-upx0, cli_readint32(sections+16));
196 196
     sections+=0x28;
197 197
   }
198 198
 
... ...
@@ -207,32 +189,6 @@ static int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32
207 207
   return 1;
208 208
 }
209 209
 
210
-static int upx_find_ep(char *src, uint32_t ssize, uint32_t upx1, uint32_t ep)
211
-{
212
-    int32_t len;
213
-    int i;
214
-
215
-    len = ssize - (ep - upx1);
216
-
217
-    /* Verify decompressor length. Avoid crashing on multiple 
218
-     * compressed files. exe packed by UPX and PEC. */
219
-    if (!CLI_ISCONTAINED(src, ssize, src + ep - upx1 + 0xc0, len))
220
-	return -1;
221
-
222
-    /* Shift to decompressor start */
223
-    src += (ep - upx1);
224
-        
225
-    for (i = 0xC0; i != len - 10; i++){
226
-	if ((CLI_READLE32(src+i) & 0x0000FFFF) == 0x0000BE8D){
227
-	    cli_dbgmsg("UPX: found at %p, off: %x val: %08x\n", src+i+6, i+6, CLI_READLE32(src+i+6));
228
-	    if (CLI_READLE32(src+i+6) == 0xC009078B){
229
-		return i+2;
230
-	    }
231
-	}
232
-    }
233
-    cli_dbgmsg("UPX: upx_find_ep %p, %d - FAILED!\n", src, len);
234
-    return -1;
235
-}
236 210
 
237 211
 /* [doubleebx] */
238 212
 
... ...
@@ -244,7 +200,7 @@ static int doubleebx(char *src, int32_t *myebx, int *scur, int ssize)
244 244
   if ( !(oldebx & 0x7fffffff)) {
245 245
     if (! CLI_ISCONTAINED(src, ssize, src+*scur, 4))
246 246
       return -1;
247
-    oldebx = CLI_READLE32(src+*scur);
247
+    oldebx = cli_readint32(src+*scur);
248 248
     *myebx = oldebx*2+1;
249 249
     *scur+=4;
250 250
   }
... ...
@@ -327,9 +283,11 @@ int upx_inflate2b(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_
327 327
     dcur+=backsize;
328 328
   }
329 329
 
330
-  scur = upx_find_ep(src, ssize, upx1, ep);
331
-  if (scur != -1)
332
-    return pefromupx (src, dst, dsize, ep, upx0, upx1, scur);
330
+
331
+  if ( ep - upx1 + 0x108 <= ssize-5  &&    /* Wondering how we got so far?! */
332
+       src[ep - upx1 + 0x106] == '\x8d' && /* lea edi, ...                  */
333
+       src[ep - upx1 + 0x107] == '\xbe' )  /* ... [esi + offset]          */
334
+    return pefromupx (src, dst, dsize, ep, upx0, upx1, 0x108);
333 335
 
334 336
   cli_dbgmsg("UPX: bad magic for 2b\n");
335 337
   return 0;
... ...
@@ -415,10 +373,12 @@ int upx_inflate2d(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_
415 415
     dcur+=backsize;
416 416
   }
417 417
 
418
-  scur = upx_find_ep(src, ssize, upx1, ep);
419
-  if (scur != -1)
420
-    return pefromupx (src, dst, dsize, ep, upx0, upx1, scur);
421
-
418
+  if ( ep - upx1 + 0x124 <= ssize-5 ) {   /* Wondering how we got so far?! */
419
+    if ( src[ep - upx1 + 0x11a] == '\x8d' && src[ep - upx1 + 0x11b] == '\xbe' )
420
+      return pefromupx (src, dst, dsize, ep, upx0, upx1, 0x11c);
421
+    if ( src[ep - upx1 + 0x122] == '\x8d' && src[ep - upx1 + 0x123] == '\xbe' )
422
+      return pefromupx (src, dst, dsize, ep, upx0, upx1, 0x124);
423
+  }
422 424
   cli_dbgmsg("UPX: bad magic for 2d\n");
423 425
   return 0;
424 426
 }
... ...
@@ -512,10 +472,12 @@ int upx_inflate2e(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_
512 512
     dcur+=backsize;
513 513
   }
514 514
 
515
-  scur = upx_find_ep(src, ssize, upx1, ep);
516
-  if (scur != -1)
517
-    return pefromupx (src, dst, dsize, ep, upx0, upx1, scur);
518
-
515
+  if ( ep - upx1 + 0x130 <= ssize-5 ) {   /* Wondering how we got so far?! */
516
+    if ( src[ep - upx1 + 0x126] == '\x8d' && src[ep - upx1 + 0x127] == '\xbe' )
517
+      return pefromupx (src, dst, dsize, ep, upx0, upx1, 0x128);
518
+    if ( src[ep - upx1 + 0x12e] == '\x8d' && src[ep - upx1 + 0x12f] == '\xbe' )
519
+      return pefromupx (src, dst, dsize, ep, upx0, upx1, 0x130);
520
+  }
519 521
   cli_dbgmsg("UPX: bad magic for 2e\n");
520 522
   return 0;
521 523
 }