Browse code

upx: scan for pe if lea fails

git-svn: trunk@2969

aCaB authored on 2007/03/25 00:54:09
Showing 2 changed files
... ...
@@ -1,3 +1,7 @@
1
+Sat Mar 24 15:01:50 CET 2007 (acab)
2
+-----------------------------------
3
+  * libclamav/upx.c: improve upx rebuilder - more to come
4
+
1 5
 Sat Mar 24 13:49:59 CET 2007 (acab)
2 6
 -----------------------------------
3 7
   * libclamav/upx.c: improve upx rebuilder - more to come
... ...
@@ -26,7 +26,7 @@
26 26
 ** 04/06/2k4 - Now we handle 2B, 2D and 2E :D
27 27
 ** 28/08/2k4 - PE rebuild for nested packers
28 28
 ** 12/12/2k4 - Improved PE rebuild code and added some debug info on failure
29
-** 23/03/2k4 - New approach for rebuilding:
29
+** 23/03/2k7 - New approach for rebuilding:
30 30
                o Get imports via magic
31 31
                o Get imports via leascan
32 32
                o if (!pe) pe=scan4pe();
... ...
@@ -35,7 +35,6 @@
35 35
 
36 36
 /*
37 37
   TODO:
38
-  - scan4pe()
39 38
   - forgepe()
40 39
   - pass dll flag from pe.c
41 40
   - grab statistical magic data from teh zoo
... ...
@@ -83,11 +82,41 @@
83 83
 \x63\x6C\x61\x6D\x61\x76\x2E\x6E\x65\x74\x0D\x0A\x24\x00\x00\x00\
84 84
 "
85 85
 
86
+static char *checkpe(char *dst, uint32_t dsize, char *pehdr, uint32_t *valign, unsigned int *sectcnt) {
87
+  char *sections;
88
+  if (!CLI_ISCONTAINED(dst, dsize,  pehdr, 0xf8)) {
89
+    cli_dbgmsg("UPX: sections out of bounds\n");
90
+    return NULL;
91
+  } 
92
+
93
+  if (cli_readint32(pehdr) != 0x4550 ) {
94
+    cli_dbgmsg("UPX: No magic for PE\n");
95
+    return NULL;
96
+  }
97
+  
98
+  if (!(*valign=cli_readint32(pehdr+0x38))) {
99
+    cli_dbgmsg("UPX: Cant align to a NULL bound\n");
100
+    return NULL;
101
+  }
102
+  
103
+  sections = pehdr+0xf8;
104
+  if (!(*sectcnt = (unsigned char)pehdr[6] + (unsigned char)pehdr[7]*256)) {
105
+    cli_dbgmsg("UPX: No sections?\n");
106
+    return NULL;
107
+  }
108
+  
109
+  if (!CLI_ISCONTAINED(dst, dsize, sections, *sectcnt*0x28)) {
110
+    cli_dbgmsg("UPX: Not enough space for all sects\n");
111
+    return NULL;
112
+  }
113
+  return sections;
114
+}
115
+
86 116
 /* PE from UPX */
87 117
 
88
-static int pefromupx (char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0, uint32_t upx1, uint32_t *magic)
118
+static int pefromupx (char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0, uint32_t upx1, uint32_t *magic, uint32_t dend)
89 119
 {
90
-  char *imports, *sections, *pehdr, *newbuf;
120
+  char *imports, *sections, *pehdr=NULL, *newbuf;
91 121
   unsigned int sectcnt=0, upd=1;
92 122
   uint32_t realstuffsz, valign=0;
93 123
   uint32_t foffset=0xd0+0xf8;
... ...
@@ -121,60 +150,45 @@ static int pefromupx (char *src, uint32_t ssize, char *dst, uint32_t *dsize, uin
121 121
     realstuffsz = imports-dst;
122 122
     
123 123
     if (realstuffsz >= *dsize ) {
124
-      cli_dbgmsg("UPX: wrong realstuff size - giving up rebuild\n");
125
-      return 0;
126
-    }
127
-    
128
-    pehdr = imports;
129
-    while (CLI_ISCONTAINED(dst, *dsize,  pehdr, 8) && cli_readint32(pehdr)) {
130
-      pehdr+=8;
131
-      while(CLI_ISCONTAINED(dst, *dsize,  pehdr, 2) && *pehdr) {
132
-	pehdr++;
133
-	while (CLI_ISCONTAINED(dst, *dsize,  pehdr, 2) && *pehdr)
124
+      cli_dbgmsg("UPX: wrong realstuff size\n");
125
+      /* fallback and eventually craft */
126
+    } else {
127
+      pehdr = imports;
128
+      while (CLI_ISCONTAINED(dst, *dsize,  pehdr, 8) && cli_readint32(pehdr)) {
129
+	pehdr+=8;
130
+	while(CLI_ISCONTAINED(dst, *dsize,  pehdr, 2) && *pehdr) {
134 131
 	  pehdr++;
132
+	  while (CLI_ISCONTAINED(dst, *dsize,  pehdr, 2) && *pehdr)
133
+	    pehdr++;
134
+	  pehdr++;
135
+	}
135 136
 	pehdr++;
136 137
       }
137
-      pehdr++;
138
+      
139
+      pehdr+=4;
140
+      if (!(sections=checkpe(dst, *dsize, pehdr, &valign, &sectcnt))) pehdr=NULL;
138 141
     }
139
-
140
-    pehdr+=4;
141
-  } else { /* TODO: this one should be a separate if (!pe) */
142
-    cli_dbgmsg("UPX: no luck - brutally scanning for PE (TODO)\n");
143
-    /* TODO */
144
-    return 0;
145 142
   }
146 143
 
147
-  /* TODO: forgepe() */
148
-
149
-  /* TODO: Kick the checks outta here and write a checkpe() */
150
-  if (!CLI_ISCONTAINED(dst, *dsize,  pehdr, 0xf8)) {
151
-    cli_dbgmsg("UPX: sections out of bounds - giving up rebuild\n");
152
-    return 0;
153
-  } 
154
-
155
-  if (cli_readint32(pehdr) != 0x4550 ) {
156
-    cli_dbgmsg("UPX: No magic for PE - giving up rebuild\n");
157
-    return 0;
158
-  }
159
-  
160
-  if (!(valign=cli_readint32(pehdr+0x38))) {
161
-    cli_dbgmsg("UPX: Cant align to a NULL bound - giving up rebuild\n");
162
-    return 0;
144
+  if (!pehdr && dend>0xf8+0x28) {
145
+    cli_dbgmsg("UPX: no luck - scanning for PE\n");
146
+    pehdr = &dst[dend-0xf8-0x28];
147
+    while (pehdr>=dst) {
148
+      if ((sections=checkpe(dst, *dsize, pehdr, &valign, &sectcnt)))
149
+	break;
150
+      pehdr--;
151
+    }
152
+    if (pehdr==dst) pehdr=NULL;
163 153
   }
164
-  
165
-  sections = pehdr+0xf8;
166
-  if ( ! (sectcnt = (unsigned char)pehdr[6]+256*(unsigned char)pehdr[7])) {
167
-    cli_dbgmsg("UPX: No sections? - giving up rebuild\n");
154
+
155
+  if (!pehdr) {
156
+    cli_dbgmsg("UPX: no luck - brutally crafing a reasonable PE (TODO)\n");
157
+    /*TODO: forgepe() or escape via cli_rebuildpe() ?*/
168 158
     return 0;
169 159
   }
170 160
   
171 161
   foffset = PESALIGN(foffset+0x28*sectcnt, valign);
172 162
   
173
-  if (!CLI_ISCONTAINED(dst, *dsize, sections, 0x28*sectcnt)) {
174
-    cli_dbgmsg("UPX: Not enough space for all sects - giving up rebuild\n");
175
-    return 0;
176
-  }
177
-  
178 163
   for (upd = 0; upd <sectcnt ; upd++) {
179 164
     uint32_t vsize=PESALIGN((uint32_t)cli_readint32(sections+8), valign);
180 165
     uint32_t urva=PEALIGN((uint32_t)cli_readint32(sections+12), valign);
... ...
@@ -249,7 +263,7 @@ static int doubleebx(char *src, uint32_t *myebx, uint32_t *scur, uint32_t ssize)
249 249
 int upx_inflate2b(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
250 250
 {
251 251
   int32_t backbytes, unp_offset = -1;
252
-  uint32_t backsize, myebx = 0, scur=0, dcur=0, i, magic[]={0x108,0x110,0};
252
+  uint32_t backsize, myebx = 0, scur=0, dcur=0, i, magic[]={/*0, TODO: removeme */0x108,0x110,0};
253 253
   int oob;
254 254
   
255 255
   while (1) {
... ...
@@ -318,7 +332,7 @@ int upx_inflate2b(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_
318 318
     dcur+=backsize;
319 319
   }
320 320
 
321
-  return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic);
321
+  return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur);
322 322
 }
323 323
 
324 324
 int upx_inflate2d(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
... ...
@@ -400,7 +414,7 @@ int upx_inflate2d(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_
400 400
     dcur+=backsize;
401 401
   }
402 402
 
403
-  return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic);
403
+  return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur);
404 404
 }
405 405
 
406 406
 int upx_inflate2e(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep)
... ...
@@ -489,5 +503,5 @@ int upx_inflate2e(char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_
489 489
     dcur+=backsize;
490 490
   }
491 491
 
492
-  return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic);
492
+  return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur);
493 493
 }