(*) Except for SizeOfImage check which is still to be implemented
git-svn: trunk@2520
... | ... |
@@ -1,3 +1,19 @@ |
1 |
+Sun Nov 26 23:04:20 CET 2006 (acab) |
|
2 |
+----------------------------------- |
|
3 |
+ * libclamav: New PE parsing model |
|
4 |
+ - Accurate virtual and raw size and offset calculations |
|
5 |
+ - Proper parsing of executables with |
|
6 |
+ weird/handcrafted/uncommon headers |
|
7 |
+ - Proper handling (or skipping) of ghost sections at various |
|
8 |
+ places in the code |
|
9 |
+ - Rebuild improvements for various unpackers |
|
10 |
+ - Adjusted alignment on rebuilt executables |
|
11 |
+ - Proper handling of out of sections offsets |
|
12 |
+ - Broken exe detection now mimics the XPSP2 loader (*) |
|
13 |
+ - Lots of misc improvements and fixes |
|
14 |
+ (*) Except for SizeOfImage check which is still to be |
|
15 |
+ implemented |
|
16 |
+ |
|
1 | 17 |
Fri Nov 24 02:01:48 CET 2006 (tk) |
2 | 18 |
--------------------------------- |
3 | 19 |
* libclamav: don't call phishing_init() if not needed (bb#147), |
... | ... |
@@ -47,7 +47,7 @@ |
47 | 47 |
|
48 | 48 |
int unfsg_200(char *source, char *dest, int ssize, int dsize, uint32_t rva, uint32_t base, uint32_t ep, int file) { |
49 | 49 |
char *tsrc; |
50 |
- struct SECTION section; /* Yup, just one ;) */ |
|
50 |
+ struct cli_exe_section section; /* Yup, just one ;) */ |
|
51 | 51 |
|
52 | 52 |
if ( cli_unfsg(source, dest, ssize, dsize, NULL, NULL) ) return -1; |
53 | 53 |
|
... | ... |
@@ -55,13 +55,8 @@ int unfsg_200(char *source, char *dest, int ssize, int dsize, uint32_t rva, uint |
55 | 55 |
section.rsz = dsize; |
56 | 56 |
section.vsz = dsize; |
57 | 57 |
section.rva = rva; |
58 |
- if ( (tsrc = rebuildpe(dest, §ion, 1, base, ep, 0, 0)) ) { |
|
59 |
- if (cli_writen(file, tsrc, 0x148+0x80+0x28+dsize)==-1) { |
|
60 |
- free(tsrc); |
|
61 |
- return 0; |
|
62 |
- } |
|
63 |
- free(tsrc); |
|
64 |
- } else { |
|
58 |
+ |
|
59 |
+ if (!cli_rebuildpe(dest, §ion, 1, base, ep, 0, 0, file)) { |
|
65 | 60 |
cli_dbgmsg("FSG: Rebuilding failed\n"); |
66 | 61 |
return 0; |
67 | 62 |
} |
... | ... |
@@ -69,7 +64,7 @@ int unfsg_200(char *source, char *dest, int ssize, int dsize, uint32_t rva, uint |
69 | 69 |
} |
70 | 70 |
|
71 | 71 |
|
72 |
-int unfsg_133(char *source, char *dest, int ssize, int dsize, struct SECTION *sections, int sectcount, uint32_t base, uint32_t ep, int file) { |
|
72 |
+int unfsg_133(char *source, char *dest, int ssize, int dsize, struct cli_exe_section *sections, int sectcount, uint32_t base, uint32_t ep, int file) { |
|
73 | 73 |
char *tsrc=source, *tdst=dest; |
74 | 74 |
int i, upd=1, offs=0, lastsz=dsize; |
75 | 75 |
|
... | ... |
@@ -118,16 +113,9 @@ int unfsg_133(char *source, char *dest, int ssize, int dsize, struct SECTION *se |
118 | 118 |
cli_dbgmsg("FSG: .SECT%d RVA:%x VSize:%x ROffset: %x, RSize:% x\n", i, sections[i].rva, sections[i].vsz, sections[i].raw, sections[i].rsz); |
119 | 119 |
} |
120 | 120 |
|
121 |
- if ( (tsrc = rebuildpe(dest, sections, sectcount+1, base, ep, 0, 0)) ) { |
|
122 |
- if (cli_writen(file, tsrc, 0x148+0x80+0x28*(sectcount+1)+offs)==-1) { |
|
123 |
- free(tsrc); |
|
124 |
- return 0; |
|
125 |
- } |
|
126 |
- free(tsrc); |
|
127 |
- } else { |
|
121 |
+ if (!cli_rebuildpe(dest, sections, sectcount+1, base, ep, 0, 0, file)) { |
|
128 | 122 |
cli_dbgmsg("FSG: Rebuilding failed\n"); |
129 | 123 |
return 0; |
130 | 124 |
} |
131 |
- |
|
132 | 125 |
return 1; |
133 | 126 |
} |
... | ... |
@@ -21,10 +21,10 @@ |
21 | 21 |
#define __FSG_H |
22 | 22 |
|
23 | 23 |
#include "cltypes.h" |
24 |
-#include "rebuildpe.h" |
|
24 |
+#include "execs.h" |
|
25 | 25 |
|
26 | 26 |
int unfsg_200(char *, char *, int, int, uint32_t, uint32_t, uint32_t, int); |
27 |
-int unfsg_133(char *, char *, int , int, struct SECTION *, int, uint32_t, uint32_t, int); |
|
27 |
+int unfsg_133(char *, char *, int , int, struct cli_exe_section *, int, uint32_t, uint32_t, int); |
|
28 | 28 |
|
29 | 29 |
#endif |
30 | 30 |
|
... | ... |
@@ -301,7 +301,7 @@ static off_t cli_caloff(const char *offstr, struct cli_target_info *info, int fd |
301 | 301 |
|
302 | 302 |
} else if(info->status == 1 && offstr[0] == 'S') { |
303 | 303 |
|
304 |
- if(!strncmp(offstr, "SL", 2)) { |
|
304 |
+ if(!strncmp(offstr, "SL", 2) && info->exeinfo.section[info->exeinfo.nsections - 1].rsz) { |
|
305 | 305 |
|
306 | 306 |
if(sscanf(offstr, "SL+%lu", &offset) != 1) { |
307 | 307 |
*ret = -1; |
... | ... |
@@ -317,7 +317,7 @@ static off_t cli_caloff(const char *offstr, struct cli_target_info *info, int fd |
317 | 317 |
return 0; |
318 | 318 |
} |
319 | 319 |
|
320 |
- if(n >= info->exeinfo.nsections) { |
|
320 |
+ if(n >= info->exeinfo.nsections || !info->exeinfo.section[n].rsz) { |
|
321 | 321 |
*ret = -1; |
322 | 322 |
return 0; |
323 | 323 |
} |
... | ... |
@@ -46,7 +46,6 @@ |
46 | 46 |
#include "suecrypt.h" |
47 | 47 |
#include "unsp.h" |
48 | 48 |
#include "scanners.h" |
49 |
-#include "rebuildpe.h" |
|
50 | 49 |
#include "str.h" |
51 | 50 |
#include "execs.h" |
52 | 51 |
#include "md5.h" |
... | ... |
@@ -78,13 +77,22 @@ struct offset_list { |
78 | 78 |
struct offset_list *next; |
79 | 79 |
}; |
80 | 80 |
|
81 |
-static uint32_t cli_rawaddr(uint32_t rva, struct pe_image_section_hdr *shp, uint16_t nos, unsigned int *err, uint32_t valign, uint32_t falign) |
|
81 |
+static uint32_t cli_rawaddr(uint32_t rva, struct cli_exe_section *shp, uint16_t nos, unsigned int *err, size_t fsize) |
|
82 | 82 |
{ |
83 | 83 |
int i, found = 0; |
84 |
+ uint32_t ret; |
|
84 | 85 |
|
86 |
+ if (rva<0x1000) { /* Out of section EP - mapped to imagebase+rva */ |
|
87 |
+ if (rva >= fsize) { |
|
88 |
+ *err=1; |
|
89 |
+ return 0; |
|
90 |
+ } |
|
91 |
+ *err=0; |
|
92 |
+ return rva; |
|
93 |
+ } |
|
85 | 94 |
|
86 |
- for(i = 0; i < nos; i++) { |
|
87 |
- if(PEALIGN(EC32(shp[i].VirtualAddress), valign) <= rva && PEALIGN(EC32(shp[i].VirtualAddress), valign) + PESALIGN(EC32(shp[i].SizeOfRawData), falign) > rva) { |
|
95 |
+ for(i = nos-1; i >= 0; i--) { |
|
96 |
+ if(shp[i].rsz && shp[i].rva <= rva && shp[i].rsz > rva - shp[i].rva) { |
|
88 | 97 |
found = 1; |
89 | 98 |
break; |
90 | 99 |
} |
... | ... |
@@ -95,31 +103,32 @@ static uint32_t cli_rawaddr(uint32_t rva, struct pe_image_section_hdr *shp, uint |
95 | 95 |
return 0; |
96 | 96 |
} |
97 | 97 |
|
98 |
+ ret = rva - shp[i].rva + shp[i].raw; |
|
98 | 99 |
*err = 0; |
99 |
- return rva - PEALIGN(EC32(shp[i].VirtualAddress), valign) + PEALIGN(EC32(shp[i].PointerToRawData), falign); |
|
100 |
+ return ret; |
|
100 | 101 |
} |
101 | 102 |
|
102 | 103 |
static void xckriz(char **opcode, int *len, int checksize, int reg) { |
103 |
- while(*len>6) { |
|
104 |
- if (**opcode>='\x48' && **opcode<='\x4f' && **opcode!='\x4c') { |
|
105 |
- if ((char)(**opcode-reg)=='\x48') break; |
|
106 |
- (*len)--; |
|
107 |
- (*opcode)++; |
|
108 |
- continue; |
|
109 |
- } |
|
110 |
- if (**opcode>='\xb8' && **opcode<='\xbf' && **opcode!='\xbc') { |
|
111 |
- if (checksize && cli_readint32(*opcode+1)==0x0fd2) break; |
|
112 |
- (*len)-=5; |
|
113 |
- (*opcode)+=5; |
|
114 |
- continue; |
|
115 |
- } |
|
116 |
- if (**opcode=='\x81') { |
|
117 |
- (*len)-=6; |
|
118 |
- (*opcode)+=6; |
|
119 |
- continue; |
|
120 |
- } |
|
121 |
- break; |
|
104 |
+ while(*len>6) { |
|
105 |
+ if (**opcode>='\x48' && **opcode<='\x4f' && **opcode!='\x4c') { |
|
106 |
+ if ((char)(**opcode-reg)=='\x48') break; |
|
107 |
+ (*len)--; |
|
108 |
+ (*opcode)++; |
|
109 |
+ continue; |
|
110 |
+ } |
|
111 |
+ if (**opcode>='\xb8' && **opcode<='\xbf' && **opcode!='\xbc') { |
|
112 |
+ if (checksize && cli_readint32(*opcode+1)==0x0fd2) break; |
|
113 |
+ (*len)-=5; |
|
114 |
+ (*opcode)+=5; |
|
115 |
+ continue; |
|
116 |
+ } |
|
117 |
+ if (**opcode=='\x81') { |
|
118 |
+ (*len)-=6; |
|
119 |
+ (*opcode)+=6; |
|
120 |
+ continue; |
|
122 | 121 |
} |
122 |
+ break; |
|
123 |
+ } |
|
123 | 124 |
} |
124 | 125 |
|
125 | 126 |
|
... | ... |
@@ -177,30 +186,23 @@ static int cli_ddump(int desc, int offset, int size, const char *file) |
177 | 177 |
} |
178 | 178 |
*/ |
179 | 179 |
|
180 |
-static unsigned char *cli_md5sect(int fd, uint32_t offset, uint32_t size) |
|
180 |
+static unsigned int cli_md5sect(int fd, uint32_t offset, uint32_t size, unsigned char *digest) |
|
181 | 181 |
{ |
182 | 182 |
size_t bread, sum = 0; |
183 | 183 |
off_t pos; |
184 | 184 |
char buff[FILEBUFF]; |
185 |
- unsigned char *digest; |
|
186 | 185 |
MD5_CTX md5ctx; |
187 | 186 |
|
188 | 187 |
|
189 | 188 |
if((pos = lseek(fd, 0, SEEK_CUR)) == -1) { |
190 | 189 |
cli_dbgmsg("cli_md5sect: Invalid descriptor %d\n", fd); |
191 |
- return NULL; |
|
190 |
+ return 0; |
|
192 | 191 |
} |
193 | 192 |
|
194 | 193 |
if(lseek(fd, offset, SEEK_SET) == -1) { |
195 | 194 |
cli_dbgmsg("cli_md5sect: lseek() failed\n"); |
196 | 195 |
lseek(fd, pos, SEEK_SET); |
197 |
- return NULL; |
|
198 |
- } |
|
199 |
- |
|
200 |
- digest = cli_calloc(16, sizeof(char)); |
|
201 |
- if(!digest) { |
|
202 |
- cli_errmsg("cli_md5sect: Can't allocate memory for digest\n"); |
|
203 |
- return NULL; |
|
196 |
+ return 0; |
|
204 | 197 |
} |
205 | 198 |
|
206 | 199 |
MD5_Init(&md5ctx); |
... | ... |
@@ -217,7 +219,7 @@ static unsigned char *cli_md5sect(int fd, uint32_t offset, uint32_t size) |
217 | 217 |
|
218 | 218 |
MD5_Final(digest, &md5ctx); |
219 | 219 |
lseek(fd, pos, SEEK_SET); |
220 |
- return digest; |
|
220 |
+ return 1; |
|
221 | 221 |
} |
222 | 222 |
|
223 | 223 |
int cli_scanpe(int desc, cli_ctx *ctx) |
... | ... |
@@ -225,24 +227,30 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
225 | 225 |
uint16_t e_magic; /* DOS signature ("MZ") */ |
226 | 226 |
uint16_t nsections; |
227 | 227 |
uint32_t e_lfanew; /* address of new exe header */ |
228 |
- uint32_t ep; /* entry point (raw) */ |
|
228 |
+ uint32_t ep, vep; /* entry point (raw, virtual) */ |
|
229 | 229 |
uint8_t polipos = 0; |
230 | 230 |
time_t timestamp; |
231 | 231 |
struct pe_image_file_hdr file_hdr; |
232 |
- struct pe_image_optional_hdr32 optional_hdr32; |
|
233 |
- struct pe_image_optional_hdr64 optional_hdr64; |
|
232 |
+ union { |
|
233 |
+ struct pe_image_optional_hdr64 opt64; |
|
234 |
+ struct pe_image_optional_hdr32 opt32; |
|
235 |
+ } pe_opt; |
|
236 |
+ struct pe_image_optional_hdr64 optional_hdr64 = pe_opt.opt64; |
|
237 |
+ struct pe_image_optional_hdr32 optional_hdr32 = pe_opt.opt32; |
|
234 | 238 |
struct pe_image_section_hdr *section_hdr; |
235 | 239 |
struct cli_md5_node *md5_sect; |
236 | 240 |
struct stat sb; |
237 | 241 |
char sname[9], buff[4096], *tempfile; |
238 |
- unsigned char *ubuff, *md5_dig; |
|
242 |
+ unsigned char *ubuff; |
|
239 | 243 |
ssize_t bytes; |
240 |
- unsigned int i, found, upx_success = 0, min = 0, max = 0, err, broken = 0; |
|
244 |
+ unsigned int i, found, upx_success = 0, min = 0, max = 0, err; |
|
241 | 245 |
unsigned int ssize = 0, dsize = 0, dll = 0, pe_plus = 0; |
242 | 246 |
int (*upxfn)(char *, uint32_t, char *, uint32_t *, uint32_t, uint32_t, uint32_t) = NULL; |
243 | 247 |
char *src = NULL, *dest = NULL; |
244 | 248 |
int ndesc, ret = CL_CLEAN; |
245 | 249 |
size_t fsize; |
250 |
+ uint32_t valign, falign; |
|
251 |
+ struct cli_exe_section *exe_sections; |
|
246 | 252 |
|
247 | 253 |
|
248 | 254 |
if(cli_readn(desc, &e_magic, sizeof(e_magic)) != sizeof(e_magic)) { |
... | ... |
@@ -394,7 +402,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
394 | 394 |
} |
395 | 395 |
|
396 | 396 |
nsections = EC16(file_hdr.NumberOfSections); |
397 |
- if(nsections < 1 || nsections > 99) { |
|
397 |
+ if(nsections < 1 || nsections > 96) { |
|
398 | 398 |
if(DETECT_BROKEN) { |
399 | 399 |
if(ctx->virname) |
400 | 400 |
*ctx->virname = "Broken.Executable"; |
... | ... |
@@ -413,111 +421,123 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
413 | 413 |
|
414 | 414 |
cli_dbgmsg("SizeOfOptionalHeader: %x\n", EC16(file_hdr.SizeOfOptionalHeader)); |
415 | 415 |
|
416 |
- if(EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr32) && EC16(file_hdr.SizeOfOptionalHeader)!=0x148) { |
|
417 |
- if(EC16(file_hdr.SizeOfOptionalHeader) == sizeof(struct pe_image_optional_hdr64)) { |
|
418 |
- pe_plus = 1; |
|
419 |
- } else { |
|
420 |
- cli_dbgmsg("Incorrect value of SizeOfOptionalHeader\n"); |
|
421 |
- if(DETECT_BROKEN) { |
|
422 |
- if(ctx->virname) |
|
423 |
- *ctx->virname = "Broken.Executable"; |
|
424 |
- return CL_VIRUS; |
|
425 |
- } |
|
426 |
- return CL_CLEAN; |
|
416 |
+ if (EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) { |
|
417 |
+ cli_dbgmsg("SizeOfOptionalHeader too small\n"); |
|
418 |
+ if(DETECT_BROKEN) { |
|
419 |
+ if(ctx->virname) |
|
420 |
+ *ctx->virname = "Broken.Executable"; |
|
421 |
+ return CL_VIRUS; |
|
427 | 422 |
} |
423 |
+ return CL_CLEAN; |
|
428 | 424 |
} |
429 | 425 |
|
430 |
- if(!pe_plus) { /* PE */ |
|
426 |
+ if(cli_readn(desc, &optional_hdr32, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) { |
|
427 |
+ cli_dbgmsg("Can't read optional file header\n"); |
|
428 |
+ if(DETECT_BROKEN) { |
|
429 |
+ if(ctx->virname) |
|
430 |
+ *ctx->virname = "Broken.Executable"; |
|
431 |
+ return CL_VIRUS; |
|
432 |
+ } |
|
433 |
+ return CL_CLEAN; |
|
434 |
+ } |
|
431 | 435 |
|
432 |
- if(cli_readn(desc, &optional_hdr32, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) { |
|
433 |
- cli_dbgmsg("Can't read optional file header\n"); |
|
436 |
+ /* This will be a chicken and egg problem until we drop 9x */ |
|
437 |
+ if(EC32(optional_hdr64.Magic)==PE32P_SIGNATURE) { |
|
438 |
+ if(EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr64)) { |
|
439 |
+ /* FIXME: need to play around a bit more with xp64 */ |
|
440 |
+ cli_dbgmsg("Incorrect SizeOfOptionalHeader for PE32+\n"); |
|
434 | 441 |
if(DETECT_BROKEN) { |
435 |
- if(ctx->virname) |
|
442 |
+ if(ctx->virname) |
|
436 | 443 |
*ctx->virname = "Broken.Executable"; |
437 | 444 |
return CL_VIRUS; |
438 | 445 |
} |
439 | 446 |
return CL_CLEAN; |
440 | 447 |
} |
441 |
- if (EC16(file_hdr.SizeOfOptionalHeader)==0x148) { |
|
442 |
- cli_dbgmsg("Found long header\n"); |
|
443 |
- lseek(desc, (0x148-0xe0), SEEK_CUR); /* Seek to the end of the long header */ |
|
444 |
- } |
|
445 |
- |
|
446 |
- if(EC16(optional_hdr32.Magic) != PE32_SIGNATURE) { |
|
448 |
+ pe_plus = 1; |
|
449 |
+ } else { |
|
450 |
+ /* |
|
451 |
+ either it's got a PE32_SIGNATURE or |
|
452 |
+ we enable win9x compatibility in that we don't honor magic (see bb#119) |
|
453 |
+ either way it's a 32bit thingy |
|
454 |
+ */ |
|
455 |
+ if(EC16(optional_hdr32.Magic) != PE32_SIGNATURE) { |
|
447 | 456 |
cli_warnmsg("Incorrect magic number in optional header\n"); |
448 | 457 |
if(DETECT_BROKEN) { |
449 |
- if(ctx->virname) |
|
458 |
+ if(ctx->virname) |
|
450 | 459 |
*ctx->virname = "Broken.Executable"; |
451 | 460 |
return CL_VIRUS; |
452 | 461 |
} |
453 | 462 |
} |
463 |
+ cli_dbgmsg("9x compatibility mode\n"); |
|
464 |
+ } |
|
465 |
+ |
|
466 |
+ if(!pe_plus) { /* PE */ |
|
467 |
+ if (EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr32)) { |
|
468 |
+ /* Seek to the end of the long header */ |
|
469 |
+ lseek(desc, (EC16(file_hdr.SizeOfOptionalHeader)-sizeof(struct pe_image_optional_hdr32)), SEEK_CUR); |
|
470 |
+ } |
|
471 |
+ |
|
472 |
+ vep = EC32(optional_hdr32.AddressOfEntryPoint); |
|
454 | 473 |
cli_dbgmsg("File format: PE\n"); |
455 | 474 |
|
456 | 475 |
cli_dbgmsg("MajorLinkerVersion: %d\n", optional_hdr32.MajorLinkerVersion); |
457 | 476 |
cli_dbgmsg("MinorLinkerVersion: %d\n", optional_hdr32.MinorLinkerVersion); |
458 |
- cli_dbgmsg("SizeOfCode: %d\n", EC32(optional_hdr32.SizeOfCode)); |
|
459 |
- cli_dbgmsg("SizeOfInitializedData: %d\n", EC32(optional_hdr32.SizeOfInitializedData)); |
|
460 |
- cli_dbgmsg("SizeOfUninitializedData: %d\n", EC32(optional_hdr32.SizeOfUninitializedData)); |
|
461 |
- cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", EC32(optional_hdr32.AddressOfEntryPoint)); |
|
477 |
+ cli_dbgmsg("SizeOfCode: 0x%x\n", EC32(optional_hdr32.SizeOfCode)); |
|
478 |
+ cli_dbgmsg("SizeOfInitializedData: 0x%x\n", EC32(optional_hdr32.SizeOfInitializedData)); |
|
479 |
+ cli_dbgmsg("SizeOfUninitializedData: 0x%x\n", EC32(optional_hdr32.SizeOfUninitializedData)); |
|
480 |
+ cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", vep); |
|
462 | 481 |
cli_dbgmsg("BaseOfCode: 0x%x\n", EC32(optional_hdr32.BaseOfCode)); |
463 |
- cli_dbgmsg("SectionAlignment: %d\n", EC32(optional_hdr32.SectionAlignment)); |
|
464 |
- cli_dbgmsg("FileAlignment: %d\n", EC32(optional_hdr32.FileAlignment)); |
|
482 |
+ cli_dbgmsg("SectionAlignment: 0x%x\n", EC32(optional_hdr32.SectionAlignment)); |
|
483 |
+ cli_dbgmsg("FileAlignment: 0x%x\n", EC32(optional_hdr32.FileAlignment)); |
|
465 | 484 |
cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(optional_hdr32.MajorSubsystemVersion)); |
466 | 485 |
cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(optional_hdr32.MinorSubsystemVersion)); |
467 |
- cli_dbgmsg("SizeOfImage: %d\n", EC32(optional_hdr32.SizeOfImage)); |
|
468 |
- cli_dbgmsg("SizeOfHeaders: %d\n", EC32(optional_hdr32.SizeOfHeaders)); |
|
486 |
+ cli_dbgmsg("SizeOfImage: 0x%x\n", EC32(optional_hdr32.SizeOfImage)); |
|
487 |
+ cli_dbgmsg("SizeOfHeaders: 0x%x\n", EC32(optional_hdr32.SizeOfHeaders)); |
|
469 | 488 |
cli_dbgmsg("NumberOfRvaAndSizes: %d\n", EC32(optional_hdr32.NumberOfRvaAndSizes)); |
470 | 489 |
|
471 | 490 |
} else { /* PE+ */ |
472 |
- |
|
473 |
- if(cli_readn(desc, &optional_hdr64, sizeof(struct pe_image_optional_hdr64)) != sizeof(struct pe_image_optional_hdr64)) { |
|
474 |
- cli_dbgmsg("Can't optional file header\n"); |
|
491 |
+ /* read the remaining part of the header */ |
|
492 |
+ if(cli_readn(desc, &optional_hdr32 + 1, sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) { |
|
493 |
+ cli_dbgmsg("Can't read optional file header\n"); |
|
475 | 494 |
if(DETECT_BROKEN) { |
476 |
- if(ctx->virname) |
|
495 |
+ if(ctx->virname) |
|
477 | 496 |
*ctx->virname = "Broken.Executable"; |
478 | 497 |
return CL_VIRUS; |
479 | 498 |
} |
480 | 499 |
return CL_CLEAN; |
481 | 500 |
} |
482 | 501 |
|
483 |
- if(EC16(optional_hdr64.Magic) != PE32P_SIGNATURE) { |
|
484 |
- cli_warnmsg("Incorrect magic number in optional header\n"); |
|
485 |
- if(DETECT_BROKEN) { |
|
486 |
- if(ctx->virname) |
|
487 |
- *ctx->virname = "Broken.Executable"; |
|
488 |
- return CL_VIRUS; |
|
489 |
- } |
|
490 |
- } |
|
502 |
+ vep = EC32(optional_hdr64.AddressOfEntryPoint); |
|
491 | 503 |
cli_dbgmsg("File format: PE32+\n"); |
492 | 504 |
|
493 | 505 |
cli_dbgmsg("MajorLinkerVersion: %d\n", optional_hdr64.MajorLinkerVersion); |
494 | 506 |
cli_dbgmsg("MinorLinkerVersion: %d\n", optional_hdr64.MinorLinkerVersion); |
495 |
- cli_dbgmsg("SizeOfCode: %d\n", EC32(optional_hdr64.SizeOfCode)); |
|
496 |
- cli_dbgmsg("SizeOfInitializedData: %d\n", EC32(optional_hdr64.SizeOfInitializedData)); |
|
497 |
- cli_dbgmsg("SizeOfUninitializedData: %d\n", EC32(optional_hdr64.SizeOfUninitializedData)); |
|
498 |
- cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", EC32(optional_hdr64.AddressOfEntryPoint)); |
|
507 |
+ cli_dbgmsg("SizeOfCode: 0x%x\n", EC32(optional_hdr64.SizeOfCode)); |
|
508 |
+ cli_dbgmsg("SizeOfInitializedData: 0x%x\n", EC32(optional_hdr64.SizeOfInitializedData)); |
|
509 |
+ cli_dbgmsg("SizeOfUninitializedData: 0x%x\n", EC32(optional_hdr64.SizeOfUninitializedData)); |
|
510 |
+ cli_dbgmsg("AddressOfEntryPoint: 0x%x\n", vep); |
|
499 | 511 |
cli_dbgmsg("BaseOfCode: 0x%x\n", EC32(optional_hdr64.BaseOfCode)); |
500 |
- cli_dbgmsg("SectionAlignment: %d\n", EC32(optional_hdr64.SectionAlignment)); |
|
501 |
- cli_dbgmsg("FileAlignment: %d\n", EC32(optional_hdr64.FileAlignment)); |
|
512 |
+ cli_dbgmsg("SectionAlignment: 0x%x\n", EC32(optional_hdr64.SectionAlignment)); |
|
513 |
+ cli_dbgmsg("FileAlignment: 0x%x\n", EC32(optional_hdr64.FileAlignment)); |
|
502 | 514 |
cli_dbgmsg("MajorSubsystemVersion: %d\n", EC16(optional_hdr64.MajorSubsystemVersion)); |
503 | 515 |
cli_dbgmsg("MinorSubsystemVersion: %d\n", EC16(optional_hdr64.MinorSubsystemVersion)); |
504 |
- cli_dbgmsg("SizeOfImage: %d\n", EC32(optional_hdr64.SizeOfImage)); |
|
505 |
- cli_dbgmsg("SizeOfHeaders: %d\n", EC32(optional_hdr64.SizeOfHeaders)); |
|
516 |
+ cli_dbgmsg("SizeOfImage: 0x%x\n", EC32(optional_hdr64.SizeOfImage)); |
|
517 |
+ cli_dbgmsg("SizeOfHeaders: 0x%x\n", EC32(optional_hdr64.SizeOfHeaders)); |
|
506 | 518 |
cli_dbgmsg("NumberOfRvaAndSizes: %d\n", EC32(optional_hdr64.NumberOfRvaAndSizes)); |
507 | 519 |
} |
508 | 520 |
|
509 | 521 |
if (DETECT_BROKEN && (!(pe_plus?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment)) || (pe_plus?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment))%0x1000)) { |
510 |
- cli_dbgmsg("Bad virtual alignemnt\n"); |
|
511 |
- if(ctx->virname) |
|
512 |
- *ctx->virname = "Broken.Executable"; |
|
513 |
- return CL_VIRUS; |
|
522 |
+ cli_dbgmsg("Bad virtual alignemnt\n"); |
|
523 |
+ if(ctx->virname) |
|
524 |
+ *ctx->virname = "Broken.Executable"; |
|
525 |
+ return CL_VIRUS; |
|
514 | 526 |
} |
515 | 527 |
|
516 | 528 |
if (DETECT_BROKEN && (!(pe_plus?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment)) || (pe_plus?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment))%0x200)) { |
517 |
- cli_dbgmsg("Bad file alignemnt\n"); |
|
518 |
- if(ctx->virname) |
|
519 |
- *ctx->virname = "Broken.Executable"; |
|
520 |
- return CL_VIRUS; |
|
529 |
+ cli_dbgmsg("Bad file alignemnt\n"); |
|
530 |
+ if(ctx->virname) |
|
531 |
+ *ctx->virname = "Broken.Executable"; |
|
532 |
+ return CL_VIRUS; |
|
521 | 533 |
} |
522 | 534 |
|
523 | 535 |
switch(pe_plus ? EC16(optional_hdr64.Subsystem) : EC16(optional_hdr32.Subsystem)) { |
... | ... |
@@ -574,33 +594,60 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
574 | 574 |
return CL_EMEM; |
575 | 575 |
} |
576 | 576 |
|
577 |
- for(i = 0; i < nsections; i++) { |
|
577 |
+ exe_sections = (struct cli_exe_section *) cli_calloc(nsections, sizeof(struct cli_exe_section)); |
|
578 |
+ |
|
579 |
+ if(!exe_sections) { |
|
580 |
+ cli_dbgmsg("Can't allocate memory for section headers\n"); |
|
581 |
+ free(section_hdr); |
|
582 |
+ return CL_EMEM; |
|
583 |
+ } |
|
578 | 584 |
|
579 |
- if(cli_readn(desc, §ion_hdr[i], sizeof(struct pe_image_section_hdr)) != sizeof(struct pe_image_section_hdr)) { |
|
580 |
- cli_dbgmsg("Can't read section header\n"); |
|
581 |
- cli_dbgmsg("Possibly broken PE file\n"); |
|
582 |
- free(section_hdr); |
|
583 |
- if(DETECT_BROKEN) { |
|
584 |
- if(ctx->virname) |
|
585 |
- *ctx->virname = "Broken.Executable"; |
|
586 |
- return CL_VIRUS; |
|
587 |
- } |
|
588 |
- return CL_CLEAN; |
|
585 |
+ valign = (pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment); |
|
586 |
+ falign = (pe_plus)?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment); |
|
587 |
+ |
|
588 |
+ if(cli_readn(desc, section_hdr, sizeof(struct pe_image_section_hdr)*nsections) != (int)(nsections*sizeof(struct pe_image_section_hdr))) { |
|
589 |
+ cli_dbgmsg("Can't read section header\n"); |
|
590 |
+ cli_dbgmsg("Possibly broken PE file\n"); |
|
591 |
+ free(section_hdr); |
|
592 |
+ free(exe_sections); |
|
593 |
+ if(DETECT_BROKEN) { |
|
594 |
+ if(ctx->virname) |
|
595 |
+ *ctx->virname = "Broken.Executable"; |
|
596 |
+ return CL_VIRUS; |
|
597 |
+ } |
|
598 |
+ return CL_CLEAN; |
|
599 |
+ } |
|
600 |
+ |
|
601 |
+ for(i = 0; falign!=0x200 && i<nsections; i++) { |
|
602 |
+ /* file alignment fallback mode - blah */ |
|
603 |
+ if (section_hdr[i].SizeOfRawData && EC32(section_hdr[i].PointerToRawData)%falign && !(EC32(section_hdr[i].PointerToRawData)%0x200)) { |
|
604 |
+ cli_dbgmsg("Found misaligned section, using 0x200\n"); |
|
605 |
+ falign = 0x200; |
|
589 | 606 |
} |
607 |
+ } |
|
590 | 608 |
|
609 |
+ for(i = 0; i < nsections; i++) { |
|
591 | 610 |
strncpy(sname, (char *) section_hdr[i].Name, 8); |
592 | 611 |
sname[8] = 0; |
612 |
+ exe_sections[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign); |
|
613 |
+ exe_sections[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign); |
|
614 |
+ exe_sections[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign); |
|
615 |
+ exe_sections[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign); |
|
616 |
+ if (exe_sections[i].rsz && fsize>exe_sections[i].raw && !CLI_ISCONTAINED(0, (uint32_t) fsize, exe_sections[i].raw, exe_sections[i].rsz)) |
|
617 |
+ exe_sections[i].rsz = fsize - exe_sections[i].raw; |
|
618 |
+ |
|
593 | 619 |
cli_dbgmsg("Section %d\n", i); |
594 | 620 |
cli_dbgmsg("Section name: %s\n", sname); |
595 |
- cli_dbgmsg("VirtualSize: %d\n", EC32(section_hdr[i].VirtualSize)); |
|
596 |
- cli_dbgmsg("VirtualAddress: 0x%x\n", EC32(section_hdr[i].VirtualAddress)); |
|
597 |
- cli_dbgmsg("SizeOfRawData: %d\n", EC32(section_hdr[i].SizeOfRawData)); |
|
598 |
- cli_dbgmsg("PointerToRawData: 0x%x (%d)\n", EC32(section_hdr[i].PointerToRawData), EC32(section_hdr[i].PointerToRawData)); |
|
621 |
+ cli_dbgmsg("Section data (from headers - in memory)\n"); |
|
622 |
+ cli_dbgmsg("VirtualSize: 0x%x 0x%x\n", EC32(section_hdr[i].VirtualSize), exe_sections[i].vsz); |
|
623 |
+ cli_dbgmsg("VirtualAddress: 0x%x 0x%x\n", EC32(section_hdr[i].VirtualAddress), exe_sections[i].rva); |
|
624 |
+ cli_dbgmsg("SizeOfRawData: 0x%x 0x%x\n", EC32(section_hdr[i].SizeOfRawData), exe_sections[i].rsz); |
|
625 |
+ cli_dbgmsg("PointerToRawData: 0x%x 0x%x\n", EC32(section_hdr[i].PointerToRawData), exe_sections[i].raw); |
|
599 | 626 |
|
600 | 627 |
if(EC32(section_hdr[i].Characteristics) & 0x20) { |
601 | 628 |
cli_dbgmsg("Section contains executable code\n"); |
602 | 629 |
|
603 |
- if(EC32(section_hdr[i].VirtualSize) < EC32(section_hdr[i].SizeOfRawData)) { |
|
630 |
+ if(exe_sections[i].vsz < exe_sections[i].rsz) { |
|
604 | 631 |
cli_dbgmsg("Section contains free space\n"); |
605 | 632 |
/* |
606 | 633 |
cli_dbgmsg("Dumping %d bytes\n", section_hdr.SizeOfRawData - section_hdr.VirtualSize); |
... | ... |
@@ -618,79 +665,81 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
618 | 618 |
|
619 | 619 |
cli_dbgmsg("------------------------------------\n"); |
620 | 620 |
|
621 |
- if (DETECT_BROKEN && EC32(section_hdr[i].VirtualAddress)%((pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment))) { /* Bad virtual alignment */ |
|
621 |
+ if (DETECT_BROKEN && EC32(section_hdr[i].VirtualAddress)%valign) { /* Bad virtual alignment */ |
|
622 | 622 |
cli_dbgmsg("VirtualAddress is misaligned\n"); |
623 | 623 |
if(ctx->virname) |
624 | 624 |
*ctx->virname = "Broken.Executable"; |
625 | 625 |
free(section_hdr); |
626 |
+ free(exe_sections); |
|
626 | 627 |
return CL_VIRUS; |
627 | 628 |
} |
628 | 629 |
|
629 |
- if (EC32(section_hdr[i].SizeOfRawData)) { /* Don't bother with virtual only sections */ |
|
630 |
- if(!CLI_ISCONTAINED2(0, (uint32_t) fsize, EC32(section_hdr[i].PointerToRawData), EC32(section_hdr[i].SizeOfRawData)) || EC32(section_hdr[i].PointerToRawData) > fsize) { |
|
631 |
- cli_dbgmsg("Possibly broken PE file - Section %d out of file (Offset@ %d, Rsize %d, Total filesize %d)\n", i, EC32(section_hdr[i].PointerToRawData), EC32(section_hdr[i].SizeOfRawData), fsize); |
|
632 |
- if(DETECT_BROKEN) { |
|
633 |
- if(ctx->virname) |
|
634 |
- *ctx->virname = "Broken.Executable"; |
|
635 |
- free(section_hdr); |
|
636 |
- return CL_VIRUS; |
|
637 |
- } |
|
638 |
- broken = 1; |
|
639 |
- |
|
640 |
- } else { |
|
641 |
- /* check MD5 section sigs */ |
|
642 |
- md5_sect = ctx->engine->md5_sect; |
|
643 |
- while(md5_sect && md5_sect->size < EC32(section_hdr[i].SizeOfRawData)) |
|
644 |
- md5_sect = md5_sect->next; |
|
645 |
- |
|
646 |
- if(md5_sect && md5_sect->size == EC32(section_hdr[i].SizeOfRawData)) { |
|
647 |
- md5_dig = cli_md5sect(desc, EC32(section_hdr[i].PointerToRawData), EC32(section_hdr[i].SizeOfRawData)); |
|
648 |
- if(!md5_dig) { |
|
649 |
- cli_errmsg("PE: Can't calculate MD5 for section %d\n", i); |
|
650 |
- } else { |
|
651 |
- while(md5_sect && md5_sect->size == EC32(section_hdr[i].SizeOfRawData)) { |
|
652 |
- if(!memcmp(md5_dig, md5_sect->md5, 16)) { |
|
653 |
- if(ctx->virname) |
|
654 |
- *ctx->virname = md5_sect->virname; |
|
655 |
- free(md5_dig); |
|
656 |
- free(section_hdr); |
|
657 |
- return CL_VIRUS; |
|
658 |
- } |
|
659 |
- md5_sect = md5_sect->next; |
|
630 |
+ if (exe_sections[i].rsz) { /* Don't bother with virtual only sections */ |
|
631 |
+ unsigned char md5_dig[16]; |
|
632 |
+ if (exe_sections[i].raw >= fsize) { /* really broken */ |
|
633 |
+ cli_dbgmsg("Broken PE file - Section %d starts beyond the end of file (Offset@ %d, Total filesize %d)\n", i, exe_sections[i].raw, fsize); |
|
634 |
+ free(section_hdr); |
|
635 |
+ free(exe_sections); |
|
636 |
+ if(DETECT_BROKEN) { |
|
637 |
+ if(ctx->virname) |
|
638 |
+ *ctx->virname = "Broken.Executable"; |
|
639 |
+ return CL_VIRUS; |
|
640 |
+ } |
|
641 |
+ return CL_CLEAN; /* no ninjas to see here! move along! */ |
|
642 |
+ } |
|
643 |
+ |
|
644 |
+ /* check MD5 section sigs */ |
|
645 |
+ md5_sect = ctx->engine->md5_sect; |
|
646 |
+ while(md5_sect && md5_sect->size < exe_sections[i].rsz) |
|
647 |
+ md5_sect = md5_sect->next; |
|
648 |
+ |
|
649 |
+ if(md5_sect && md5_sect->size == exe_sections[i].rsz) { |
|
650 |
+ if(!cli_md5sect(desc, exe_sections[i].raw, exe_sections[i].rsz, md5_dig)) { |
|
651 |
+ cli_errmsg("PE: Can't calculate MD5 for section %d\n", i); |
|
652 |
+ } else { |
|
653 |
+ while(md5_sect && md5_sect->size == exe_sections[i].rsz) { |
|
654 |
+ if(!memcmp(md5_dig, md5_sect->md5, 16)) { |
|
655 |
+ if(ctx->virname) |
|
656 |
+ *ctx->virname = md5_sect->virname; |
|
657 |
+ free(section_hdr); |
|
658 |
+ free(exe_sections); |
|
659 |
+ return CL_VIRUS; |
|
660 | 660 |
} |
661 |
- free(md5_dig); |
|
661 |
+ md5_sect = md5_sect->next; |
|
662 | 662 |
} |
663 | 663 |
} |
664 | 664 |
} |
665 | 665 |
} |
666 | 666 |
|
667 | 667 |
if(!i) { |
668 |
- if (DETECT_BROKEN && EC32(section_hdr[i].VirtualAddress)!=((pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment))) { /* Bad first section RVA */ |
|
668 |
+ if (DETECT_BROKEN && EC32(section_hdr[i].VirtualAddress)!=valign) { /* Bad first section RVA */ |
|
669 | 669 |
cli_dbgmsg("First section is in the wrong place\n"); |
670 | 670 |
if(ctx->virname) |
671 | 671 |
*ctx->virname = md5_sect->virname; |
672 | 672 |
free(section_hdr); |
673 |
+ free(exe_sections); |
|
673 | 674 |
return CL_VIRUS; |
674 | 675 |
} |
675 |
- min = EC32(section_hdr[i].VirtualAddress); |
|
676 |
- max = EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData); |
|
676 |
+ min = exe_sections[i].rva; |
|
677 |
+ max = exe_sections[i].rva + exe_sections[i].rsz; |
|
677 | 678 |
} else { |
678 |
- if (DETECT_BROKEN && EC32(section_hdr[i].VirtualAddress)-EC32(section_hdr[i-1].VirtualAddress)!=PESALIGN(EC32(section_hdr[i-1].VirtualSize), ((pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment)))) { /* No holes, no overlapping, no virtual disorder */ |
|
679 |
+ if (DETECT_BROKEN && EC32(section_hdr[i].VirtualAddress)-EC32(section_hdr[i-1].VirtualAddress)!= exe_sections[i-1].vsz) { /* No holes, no overlapping, no virtual disorder */ |
|
679 | 680 |
cli_dbgmsg("Virtually misplaced section (wrong order, overlapping, non contiguous)\n"); |
680 | 681 |
if(ctx->virname) |
681 | 682 |
*ctx->virname = md5_sect->virname; |
682 | 683 |
free(section_hdr); |
684 |
+ free(exe_sections); |
|
683 | 685 |
return CL_VIRUS; |
684 | 686 |
} |
685 |
- if(EC32(section_hdr[i].VirtualAddress) < min) |
|
686 |
- min = EC32(section_hdr[i].VirtualAddress); |
|
687 |
+ if(exe_sections[i].rva < min) |
|
688 |
+ min = exe_sections[i].rva; |
|
687 | 689 |
|
688 |
- if(EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData) > max) |
|
689 |
- max = EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData); |
|
690 |
+ if(exe_sections[i].rva + exe_sections[i].rsz > max) |
|
691 |
+ max = exe_sections[i].rva + exe_sections[i].rsz; |
|
690 | 692 |
} |
691 | 693 |
|
692 | 694 |
if(SCAN_ALGO && !strlen(sname)) { |
693 |
- if(EC32(section_hdr[i].VirtualSize) > 40000 && EC32(section_hdr[i].VirtualSize) < 70000) { |
|
695 |
+ if(exe_sections[i].vsz > 40000 && exe_sections[i].vsz < 70000) { |
|
694 | 696 |
if(EC32(section_hdr[i].Characteristics) == 0xe0000060) { |
695 | 697 |
polipos = i; |
696 | 698 |
} |
... | ... |
@@ -699,16 +748,10 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
699 | 699 |
|
700 | 700 |
} |
701 | 701 |
|
702 |
- |
|
703 |
- |
|
704 |
- if(pe_plus) |
|
705 |
- ep = EC32(optional_hdr64.AddressOfEntryPoint); |
|
706 |
- else |
|
707 |
- ep = EC32(optional_hdr32.AddressOfEntryPoint); |
|
708 |
- |
|
709 |
- if(ep >= min && !(ep = cli_rawaddr(ep, section_hdr, nsections, &err, 0, 0)) && err) { |
|
710 |
- cli_dbgmsg("Possibly broken PE file\n"); |
|
702 |
+ if(!(ep = cli_rawaddr(vep, exe_sections, nsections, &err, fsize)) && err) { |
|
703 |
+ cli_dbgmsg("EntryPoint out of file\n"); |
|
711 | 704 |
free(section_hdr); |
705 |
+ free(exe_sections); |
|
712 | 706 |
if(DETECT_BROKEN) { |
713 | 707 |
if(ctx->virname) |
714 | 708 |
*ctx->virname = "Broken.Executable"; |
... | ... |
@@ -721,13 +764,14 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
721 | 721 |
|
722 | 722 |
if(pe_plus) { /* Do not continue for PE32+ files */ |
723 | 723 |
free(section_hdr); |
724 |
+ free(exe_sections); |
|
724 | 725 |
return CL_CLEAN; |
725 | 726 |
} |
726 | 727 |
|
727 | 728 |
/* Attempt to detect some popular polymorphic viruses */ |
728 | 729 |
|
729 | 730 |
/* W32.Parite.B */ |
730 |
- if(SCAN_ALGO && !dll && ep == EC32(section_hdr[nsections - 1].PointerToRawData)) { |
|
731 |
+ if(SCAN_ALGO && !dll && ep == exe_sections[nsections - 1].raw) { |
|
731 | 732 |
lseek(desc, ep, SEEK_SET); |
732 | 733 |
if(cli_readn(desc, buff, 4096) == 4096) { |
733 | 734 |
const char *pt = cli_memstr(buff, 4040, "\x47\x65\x74\x50\x72\x6f\x63\x41\x64\x64\x72\x65\x73\x73\x00", 15); |
... | ... |
@@ -738,6 +782,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
738 | 738 |
if(((dw1 = cli_readint32(pt)) ^ (dw2 = cli_readint32(pt + 4))) == 0x505a4f && ((dw1 = cli_readint32(pt + 8)) ^ (dw2 = cli_readint32(pt + 12))) == 0xffffb && ((dw1 = cli_readint32(pt + 16)) ^ (dw2 = cli_readint32(pt + 20))) == 0xb8) { |
739 | 739 |
*ctx->virname = "W32.Parite.B"; |
740 | 740 |
free(section_hdr); |
741 |
+ free(exe_sections); |
|
741 | 742 |
return CL_VIRUS; |
742 | 743 |
} |
743 | 744 |
} |
... | ... |
@@ -745,7 +790,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
745 | 745 |
} |
746 | 746 |
|
747 | 747 |
/* Kriz */ |
748 |
- if(SCAN_ALGO && CLI_ISCONTAINED(EC32(section_hdr[nsections - 1].PointerToRawData), EC32(section_hdr[nsections - 1].SizeOfRawData), ep, 0x0fd2)) { |
|
748 |
+ if(SCAN_ALGO && CLI_ISCONTAINED(exe_sections[nsections - 1].raw, exe_sections[nsections - 1].rsz, ep, 0x0fd2)) { |
|
749 | 749 |
cli_dbgmsg("in kriz\n"); |
750 | 750 |
lseek(desc, ep, SEEK_SET); |
751 | 751 |
if(cli_readn(desc, buff, 200) == 200) { |
... | ... |
@@ -800,6 +845,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
800 | 800 |
} |
801 | 801 |
*ctx->virname = "Win32.Kriz"; |
802 | 802 |
free(section_hdr); |
803 |
+ free(exe_sections); |
|
803 | 804 |
return CL_VIRUS; |
804 | 805 |
} |
805 | 806 |
} |
... | ... |
@@ -820,6 +866,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
820 | 820 |
if(cli_memstr(buff, 4091, "\xe8\x2c\x61\x00\x00", 5)) { |
821 | 821 |
*ctx->virname = "W32.Magistr.A"; |
822 | 822 |
free(section_hdr); |
823 |
+ free(exe_sections); |
|
823 | 824 |
return CL_VIRUS; |
824 | 825 |
} |
825 | 826 |
} |
... | ... |
@@ -832,6 +879,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
832 | 832 |
if(cli_memstr(buff, 4091, "\xe8\x04\x72\x00\x00", 5)) { |
833 | 833 |
*ctx->virname = "W32.Magistr.B"; |
834 | 834 |
free(section_hdr); |
835 |
+ free(exe_sections); |
|
835 | 836 |
return CL_VIRUS; |
836 | 837 |
} |
837 | 838 |
} |
... | ... |
@@ -840,7 +888,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
840 | 840 |
|
841 | 841 |
/* W32.Polipos.A */ |
842 | 842 |
if(polipos && !dll && nsections > 2 && nsections < 13 && e_lfanew <= 0x800 && (EC16(optional_hdr32.Subsystem) == 2 || EC16(optional_hdr32.Subsystem) == 3) && EC16(file_hdr.Machine) == 0x14c && optional_hdr32.SizeOfStackReserve >= 0x80000) { |
843 |
- uint32_t remaining = EC32(section_hdr[0].SizeOfRawData); |
|
843 |
+ uint32_t remaining = exe_sections[0].rsz; |
|
844 | 844 |
uint32_t chunk = sizeof(buff); |
845 | 845 |
uint32_t val, shift, raddr, total = 0; |
846 | 846 |
const char *jpt; |
... | ... |
@@ -852,23 +900,24 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
852 | 852 |
if(remaining < chunk) |
853 | 853 |
chunk = remaining; |
854 | 854 |
|
855 |
- lseek(desc, EC32(section_hdr[0].PointerToRawData), SEEK_SET); |
|
855 |
+ lseek(desc, exe_sections[0].raw, SEEK_SET); |
|
856 | 856 |
while((bytes = cli_readn(desc, buff, chunk)) > 0) { |
857 | 857 |
shift = 0; |
858 |
- while(bytes - 5 > shift) { |
|
858 |
+ while((uint32_t)bytes - 5 > shift) { |
|
859 | 859 |
jpt = buff + shift; |
860 | 860 |
if(*jpt!='\xe9' && *jpt!='\xe8') { |
861 | 861 |
shift++; |
862 | 862 |
continue; |
863 | 863 |
} |
864 | 864 |
val = cli_readint32(jpt + 1); |
865 |
- val += 5 + EC32(section_hdr[0].VirtualAddress) + total + shift; |
|
866 |
- raddr = cli_rawaddr(val, section_hdr, nsections, &err, 0, 0); |
|
865 |
+ val += 5 + exe_sections[0].rva + total + shift; |
|
866 |
+ raddr = cli_rawaddr(val, exe_sections, nsections, &err, fsize); |
|
867 | 867 |
|
868 |
- if(!err && (raddr >= EC32(section_hdr[polipos].PointerToRawData) && raddr < EC32(section_hdr[polipos].PointerToRawData) + EC32(section_hdr[polipos].SizeOfRawData)) && (!offlist || (raddr != offlist->offset))) { |
|
868 |
+ if(!err && (raddr >= exe_sections[polipos].raw && raddr < exe_sections[polipos].raw + exe_sections[polipos].rsz) && (!offlist || (raddr != offlist->offset))) { |
|
869 | 869 |
offnode = (struct offset_list *) cli_malloc(sizeof(struct offset_list)); |
870 | 870 |
if(!offnode) { |
871 | 871 |
free(section_hdr); |
872 |
+ free(exe_sections); |
|
872 | 873 |
while(offlist) { |
873 | 874 |
offnode = offlist; |
874 | 875 |
offlist = offlist->next; |
... | ... |
@@ -925,33 +974,30 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
925 | 925 |
|
926 | 926 |
if(ret == CL_VIRUS) { |
927 | 927 |
free(section_hdr); |
928 |
+ free(exe_sections); |
|
928 | 929 |
return CL_VIRUS; |
929 | 930 |
} |
930 | 931 |
} |
931 | 932 |
|
932 | 933 |
|
933 |
- if(broken) { |
|
934 |
- free(section_hdr); |
|
935 |
- return CL_CLEAN; |
|
936 |
- } |
|
937 |
- |
|
938 | 934 |
#ifdef CL_EXPERIMENTAL |
939 | 935 |
/* SUE */ |
940 | 936 |
|
941 |
- if(nsections > 2 && EC32(optional_hdr32.AddressOfEntryPoint) == EC32(section_hdr[nsections - 1].VirtualAddress) && EC32(section_hdr[nsections - 1].SizeOfRawData) > 0x350 && EC32(section_hdr[nsections - 1].SizeOfRawData) < 0x292+0x350+1000) { |
|
937 |
+ if(nsections > 2 && vep == exe_sections[nsections - 1].rva && exe_sections[nsections - 1].rsz > 0x350 && exe_sections[nsections - 1].rsz < 0x292+0x350+1000) { |
|
942 | 938 |
|
943 | 939 |
|
944 | 940 |
char *sue=buff+0x74; |
945 | 941 |
uint32_t key; |
946 | 942 |
|
947 | 943 |
if(lseek(desc, ep-4, SEEK_SET) == -1) { |
948 |
- cli_dbgmsg("SUE: lseek() failed - EP out of file\n"); |
|
944 |
+ cli_dbgmsg("SUE: lseek() failed\n"); |
|
949 | 945 |
free(section_hdr); |
946 |
+ free(exe_sections); |
|
950 | 947 |
return CL_EIO; |
951 | 948 |
} |
952 |
- if((unsigned int) cli_readn(desc, buff, EC32(section_hdr[nsections - 1].SizeOfRawData)+4) == EC32(section_hdr[nsections - 1].SizeOfRawData)+4) { |
|
949 |
+ if((unsigned int) cli_readn(desc, buff, exe_sections[nsections - 1].rsz+4) == exe_sections[nsections - 1].rsz+4) { |
|
953 | 950 |
found=0; |
954 |
- while(CLI_ISCONTAINED(buff+4, EC32(section_hdr[nsections - 1].SizeOfRawData), sue, 4*3)) { |
|
951 |
+ while(CLI_ISCONTAINED(buff+4, exe_sections[nsections - 1].rsz, sue, 4*3)) { |
|
955 | 952 |
if((cli_readint32(sue)^cli_readint32(sue+4))==0x5c41090e && (cli_readint32(sue)^cli_readint32(sue+8))==0x021e0145) { |
956 | 953 |
found=1; |
957 | 954 |
key=(cli_readint32(sue)^0x6e72656b); |
... | ... |
@@ -960,28 +1006,31 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
960 | 960 |
sue++; |
961 | 961 |
} |
962 | 962 |
cli_dbgmsg("SUE: key(%x) found @%x\n", key, sue-buff); |
963 |
- if (found && CLI_ISCONTAINED(buff, EC32(section_hdr[nsections - 1].SizeOfRawData), sue-0x74, 0xbe) && |
|
964 |
- (sue=sudecrypt(desc, fsize, section_hdr, nsections-1, sue, key, cli_readint32(buff), e_lfanew))) { |
|
963 |
+ if (found && CLI_ISCONTAINED(buff, exe_sections[nsections - 1].rsz, sue-0x74, 0xbe) && |
|
964 |
+ (sue=sudecrypt(desc, fsize, exe_sections, nsections-1, sue, key, cli_readint32(buff), e_lfanew))) { |
|
965 | 965 |
if(!(tempfile = cli_gentemp(NULL))) { |
966 | 966 |
free(sue); |
967 | 967 |
free(section_hdr); |
968 |
+ free(exe_sections); |
|
968 | 969 |
return CL_EMEM; |
969 | 970 |
} |
970 |
- |
|
971 |
+ |
|
971 | 972 |
if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) { |
972 | 973 |
cli_dbgmsg("sue: Can't create file %s\n", tempfile); |
973 | 974 |
free(tempfile); |
974 | 975 |
free(sue); |
975 | 976 |
free(section_hdr); |
977 |
+ free(exe_sections); |
|
976 | 978 |
return CL_EIO; |
977 | 979 |
} |
978 | 980 |
|
979 |
- if((unsigned int) write(ndesc, sue, ep) != ep) { |
|
981 |
+ if((unsigned int) cli_writen(ndesc, sue, ep) != ep) { |
|
980 | 982 |
cli_dbgmsg("sue: Can't write %d bytes\n", ep); |
981 | 983 |
close(ndesc); |
982 | 984 |
free(tempfile); |
983 | 985 |
free(sue); |
984 | 986 |
free(section_hdr); |
987 |
+ free(exe_sections); |
|
985 | 988 |
return CL_EIO; |
986 | 989 |
} |
987 | 990 |
|
... | ... |
@@ -995,6 +1044,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
995 | 995 |
|
996 | 996 |
if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) { |
997 | 997 |
free(section_hdr); |
998 |
+ free(exe_sections); |
|
998 | 999 |
close(ndesc); |
999 | 1000 |
if(!cli_leavetemps_flag) |
1000 | 1001 |
unlink(tempfile); |
... | ... |
@@ -1029,6 +1079,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1029 | 1029 |
if(lseek(desc, ep, SEEK_SET) == -1) { |
1030 | 1030 |
cli_dbgmsg("UPX/FSG: lseek() failed\n"); |
1031 | 1031 |
free(section_hdr); |
1032 |
+ free(exe_sections); |
|
1032 | 1033 |
return CL_EIO; |
1033 | 1034 |
} |
1034 | 1035 |
|
... | ... |
@@ -1036,6 +1087,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1036 | 1036 |
cli_dbgmsg("UPX/FSG: Can't read 168 bytes at 0x%x (%d)\n", ep, ep); |
1037 | 1037 |
cli_dbgmsg("UPX/FSG: Broken or not UPX/FSG compressed file\n"); |
1038 | 1038 |
free(section_hdr); |
1039 |
+ free(exe_sections); |
|
1039 | 1040 |
return CL_CLEAN; |
1040 | 1041 |
} |
1041 | 1042 |
|
... | ... |
@@ -1043,8 +1095,8 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1043 | 1043 |
|
1044 | 1044 |
/* FSG v2.0 support - thanks to aCaB ! */ |
1045 | 1045 |
|
1046 |
- ssize = EC32(section_hdr[i + 1].SizeOfRawData); |
|
1047 |
- dsize = EC32(section_hdr[i].VirtualSize); |
|
1046 |
+ ssize = exe_sections[i + 1].rsz; |
|
1047 |
+ dsize = exe_sections[i].vsz; |
|
1048 | 1048 |
|
1049 | 1049 |
while(found) { |
1050 | 1050 |
uint32_t newesi, newedi, newebx, newedx; |
... | ... |
@@ -1052,6 +1104,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1052 | 1052 |
if(ctx->limits && ctx->limits->maxfilesize && (ssize > ctx->limits->maxfilesize || dsize > ctx->limits->maxfilesize)) { |
1053 | 1053 |
cli_dbgmsg("FSG: Sizes exceeded (ssize: %u, dsize: %u, max: %lu)\n", ssize, dsize , ctx->limits->maxfilesize); |
1054 | 1054 |
free(section_hdr); |
1055 |
+ free(exe_sections); |
|
1055 | 1056 |
if(BLOCKMAX) { |
1056 | 1057 |
*ctx->virname = "PE.FSG.ExceededFileSize"; |
1057 | 1058 |
return CL_VIRUS; |
... | ... |
@@ -1063,40 +1116,47 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1063 | 1063 |
if(ssize <= 0x19 || dsize <= ssize) { |
1064 | 1064 |
cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); |
1065 | 1065 |
free(section_hdr); |
1066 |
+ free(exe_sections); |
|
1066 | 1067 |
return CL_CLEAN; |
1067 | 1068 |
} |
1068 | 1069 |
|
1069 |
- if((newedx = cli_readint32(buff + 2) - EC32(optional_hdr32.ImageBase)) < EC32(section_hdr[i + 1].VirtualAddress) || newedx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 4) { |
|
1070 |
+ newedx = cli_readint32(buff + 2) - EC32(optional_hdr32.ImageBase); |
|
1071 |
+ if(!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newedx, 4)) { |
|
1070 | 1072 |
cli_dbgmsg("FSG: xchg out of bounds (%x), giving up\n", newedx); |
1071 | 1073 |
break; |
1072 | 1074 |
} |
1073 | 1075 |
|
1074 | 1076 |
if((src = (char *) cli_malloc(ssize)) == NULL) { |
1075 | 1077 |
free(section_hdr); |
1078 |
+ free(exe_sections); |
|
1076 | 1079 |
return CL_EMEM; |
1077 | 1080 |
} |
1078 | 1081 |
|
1079 |
- lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET); |
|
1082 |
+ lseek(desc, exe_sections[i + 1].raw, SEEK_SET); |
|
1080 | 1083 |
if((unsigned int) cli_readn(desc, src, ssize) != ssize) { |
1081 |
- cli_dbgmsg("Can't read raw data of section %d\n", i); |
|
1084 |
+ cli_dbgmsg("Can't read raw data of section %d\n", i + 1); |
|
1082 | 1085 |
free(section_hdr); |
1086 |
+ free(exe_sections); |
|
1083 | 1087 |
free(src); |
1084 | 1088 |
return CL_EIO; |
1085 | 1089 |
} |
1086 | 1090 |
|
1087 |
- if(newedx < EC32(section_hdr[i + 1].VirtualAddress) || ((dest = src + newedx - EC32(section_hdr[i + 1].VirtualAddress)) < src && dest >= src + EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 4)) { |
|
1091 |
+ dest = src + newedx - exe_sections[i + 1].rva; |
|
1092 |
+ if(newedx < exe_sections[i + 1].rva || !CLI_ISCONTAINED(src, ssize, dest, 4)) { |
|
1088 | 1093 |
cli_dbgmsg("FSG: New ESP out of bounds\n"); |
1089 | 1094 |
free(src); |
1090 | 1095 |
break; |
1091 | 1096 |
} |
1092 | 1097 |
|
1093 |
- if((newedx = cli_readint32(dest) - EC32(optional_hdr32.ImageBase)) <= EC32(section_hdr[i + 1].VirtualAddress) || newedx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 4) { |
|
1098 |
+ newedx = cli_readint32(dest) - EC32(optional_hdr32.ImageBase); |
|
1099 |
+ if(!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newedx, 4)) { |
|
1094 | 1100 |
cli_dbgmsg("FSG: New ESP (%x) is wrong\n", newedx); |
1095 | 1101 |
free(src); |
1096 | 1102 |
break; |
1097 | 1103 |
} |
1098 | 1104 |
|
1099 |
- if((dest = src + newedx - EC32(section_hdr[i + 1].VirtualAddress)) < src || dest >= src + EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 32) { |
|
1105 |
+ dest = src + newedx - exe_sections[i + 1].rva; |
|
1106 |
+ if(!CLI_ISCONTAINED(src, ssize, dest, 32)) { |
|
1100 | 1107 |
cli_dbgmsg("FSG: New stack out of bounds\n"); |
1101 | 1108 |
free(src); |
1102 | 1109 |
break; |
... | ... |
@@ -1107,35 +1167,37 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1107 | 1107 |
newebx = cli_readint32(dest + 16) - EC32(optional_hdr32.ImageBase); |
1108 | 1108 |
newedx = cli_readint32(dest + 20); |
1109 | 1109 |
|
1110 |
- if(newedi != EC32(section_hdr[i].VirtualAddress)) { |
|
1111 |
- cli_dbgmsg("FSG: Bad destination buffer (edi is %x should be %x)\n", newedi, EC32(section_hdr[i].VirtualAddress)); |
|
1110 |
+ if(newedi != exe_sections[i].rva) { |
|
1111 |
+ cli_dbgmsg("FSG: Bad destination buffer (edi is %x should be %x)\n", newedi, exe_sections[i].rva); |
|
1112 | 1112 |
free(src); |
1113 | 1113 |
break; |
1114 | 1114 |
} |
1115 | 1115 |
|
1116 |
- if(newesi < EC32(section_hdr[i + 1].VirtualAddress) || newesi >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData)) { |
|
1116 |
+ if(newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].rsz) { |
|
1117 | 1117 |
cli_dbgmsg("FSG: Source buffer out of section bounds\n"); |
1118 | 1118 |
free(src); |
1119 | 1119 |
break; |
1120 | 1120 |
} |
1121 | 1121 |
|
1122 |
- if(newebx < EC32(section_hdr[i + 1].VirtualAddress) || newebx >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData) - 16) { |
|
1122 |
+ if(!CLI_ISCONTAINED(exe_sections[i + 1].rva, exe_sections[i + 1].rsz, newebx, 16)) { |
|
1123 | 1123 |
cli_dbgmsg("FSG: Array of functions out of bounds\n"); |
1124 | 1124 |
free(src); |
1125 | 1125 |
break; |
1126 | 1126 |
} |
1127 | 1127 |
|
1128 |
- newedx=cli_readint32(newebx + 12 - EC32(section_hdr[i + 1].VirtualAddress) + src) - EC32(optional_hdr32.ImageBase); |
|
1128 |
+ newedx=cli_readint32(newebx + 12 - exe_sections[i + 1].rva + src) - EC32(optional_hdr32.ImageBase); |
|
1129 | 1129 |
cli_dbgmsg("FSG: found old EP @%x\n",newedx); |
1130 | 1130 |
|
1131 | 1131 |
if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { |
1132 | 1132 |
free(section_hdr); |
1133 |
+ free(exe_sections); |
|
1133 | 1134 |
free(src); |
1134 | 1135 |
return CL_EMEM; |
1135 | 1136 |
} |
1136 | 1137 |
|
1137 | 1138 |
if(!(tempfile = cli_gentemp(NULL))) { |
1138 | 1139 |
free(section_hdr); |
1140 |
+ free(exe_sections); |
|
1139 | 1141 |
free(src); |
1140 | 1142 |
return CL_EMEM; |
1141 | 1143 |
} |
... | ... |
@@ -1144,12 +1206,13 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1144 | 1144 |
cli_dbgmsg("FSG: Can't create file %s\n", tempfile); |
1145 | 1145 |
free(tempfile); |
1146 | 1146 |
free(section_hdr); |
1147 |
+ free(exe_sections); |
|
1147 | 1148 |
free(src); |
1148 | 1149 |
free(dest); |
1149 | 1150 |
return CL_EIO; |
1150 | 1151 |
} |
1151 | 1152 |
|
1152 |
- switch (unfsg_200(newesi - EC32(section_hdr[i + 1].VirtualAddress) + src, dest, ssize + EC32(section_hdr[i + 1].VirtualAddress) - newesi, dsize, newedi, EC32(optional_hdr32.ImageBase), newedx, ndesc)) { |
|
1153 |
+ switch (unfsg_200(newesi - exe_sections[i + 1].rva + src, dest, ssize + exe_sections[i + 1].rva - newesi, dsize, newedi, EC32(optional_hdr32.ImageBase), newedx, ndesc)) { |
|
1153 | 1154 |
case 1: /* Everything OK */ |
1154 | 1155 |
cli_dbgmsg("FSG: Unpacked and rebuilt executable saved in %s\n", tempfile); |
1155 | 1156 |
free(src); |
... | ... |
@@ -1160,6 +1223,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1160 | 1160 |
cli_dbgmsg("***** Scanning rebuilt PE file *****\n"); |
1161 | 1161 |
if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) { |
1162 | 1162 |
free(section_hdr); |
1163 |
+ free(exe_sections); |
|
1163 | 1164 |
close(ndesc); |
1164 | 1165 |
if(!cli_leavetemps_flag) |
1165 | 1166 |
unlink(tempfile); |
... | ... |
@@ -1172,10 +1236,11 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1172 | 1172 |
unlink(tempfile); |
1173 | 1173 |
free(tempfile); |
1174 | 1174 |
free(section_hdr); |
1175 |
+ free(exe_sections); |
|
1175 | 1176 |
return CL_CLEAN; |
1176 | 1177 |
|
1177 | 1178 |
case 0: /* We've got an unpacked buffer, no exe though */ |
1178 |
- cli_dbgmsg("FSG: FSG: Successfully decompressed\n"); |
|
1179 |
+ cli_dbgmsg("FSG: Successfully decompressed\n"); |
|
1179 | 1180 |
close(ndesc); |
1180 | 1181 |
unlink(tempfile); |
1181 | 1182 |
free(tempfile); |
... | ... |
@@ -1201,19 +1266,20 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1201 | 1201 |
|
1202 | 1202 |
/* FSG support - v. 1.33 (thx trog for the many samples) */ |
1203 | 1203 |
|
1204 |
- ssize = EC32(section_hdr[i + 1].SizeOfRawData); |
|
1205 |
- dsize = EC32(section_hdr[i].VirtualSize); |
|
1204 |
+ ssize = exe_sections[i + 1].rsz; |
|
1205 |
+ dsize = exe_sections[i].vsz; |
|
1206 | 1206 |
|
1207 | 1207 |
while(found) { |
1208 |
- int gp, t, sectcnt = 0; |
|
1208 |
+ int sectcnt = 0; |
|
1209 | 1209 |
char *support; |
1210 |
- uint32_t newesi, newedi, newebx, oldep; |
|
1211 |
- struct SECTION *sections; |
|
1210 |
+ uint32_t newesi, newedi, newebx, oldep, gp, t; |
|
1211 |
+ struct cli_exe_section *sections; |
|
1212 | 1212 |
|
1213 | 1213 |
|
1214 | 1214 |
if(ctx->limits && ctx->limits->maxfilesize && (ssize > ctx->limits->maxfilesize || dsize > ctx->limits->maxfilesize)) { |
1215 | 1215 |
cli_dbgmsg("FSG: Sizes exceeded (ssize: %u, dsize: %u, max: %lu)\n", ssize, dsize, ctx->limits->maxfilesize); |
1216 | 1216 |
free(section_hdr); |
1217 |
+ free(exe_sections); |
|
1217 | 1218 |
if(BLOCKMAX) { |
1218 | 1219 |
*ctx->virname = "PE.FSG.ExceededFileSize"; |
1219 | 1220 |
return CL_VIRUS; |
... | ... |
@@ -1225,20 +1291,22 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1225 | 1225 |
if(ssize <= 0x19 || dsize <= ssize) { |
1226 | 1226 |
cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); |
1227 | 1227 |
free(section_hdr); |
1228 |
+ free(exe_sections); |
|
1228 | 1229 |
return CL_CLEAN; |
1229 | 1230 |
} |
1230 | 1231 |
|
1231 |
- if((gp = cli_readint32(buff + 1) - EC32(optional_hdr32.ImageBase)) >= (int) EC32(section_hdr[i + 1].PointerToRawData) || gp < 0) { |
|
1232 |
- cli_dbgmsg("FSG: Support data out of padding area (vaddr: %d)\n", EC32(section_hdr[i].VirtualAddress)); |
|
1232 |
+ if(!(gp = cli_rawaddr(cli_readint32(buff + 1) - EC32(optional_hdr32.ImageBase), NULL, 0 , &err, fsize)) && err ) { |
|
1233 |
+ cli_dbgmsg("FSG: Support data out of padding area\n"); |
|
1233 | 1234 |
break; |
1234 | 1235 |
} |
1235 | 1236 |
|
1236 | 1237 |
lseek(desc, gp, SEEK_SET); |
1237 |
- gp = EC32(section_hdr[i + 1].PointerToRawData) - gp; |
|
1238 |
+ gp = exe_sections[i + 1].raw - gp; |
|
1238 | 1239 |
|
1239 | 1240 |
if(ctx->limits && ctx->limits->maxfilesize && (unsigned int) gp > ctx->limits->maxfilesize) { |
1240 | 1241 |
cli_dbgmsg("FSG: Buffer size exceeded (size: %d, max: %lu)\n", gp, ctx->limits->maxfilesize); |
1241 | 1242 |
free(section_hdr); |
1243 |
+ free(exe_sections); |
|
1242 | 1244 |
if(BLOCKMAX) { |
1243 | 1245 |
*ctx->virname = "PE.FSG.ExceededFileSize"; |
1244 | 1246 |
return CL_VIRUS; |
... | ... |
@@ -1249,28 +1317,30 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1249 | 1249 |
|
1250 | 1250 |
if((support = (char *) cli_malloc(gp)) == NULL) { |
1251 | 1251 |
free(section_hdr); |
1252 |
+ free(exe_sections); |
|
1252 | 1253 |
return CL_EMEM; |
1253 | 1254 |
} |
1254 | 1255 |
|
1255 |
- if(cli_readn(desc, support, gp) != gp) { |
|
1256 |
+ if((int)cli_readn(desc, support, gp) != (int)gp) { |
|
1256 | 1257 |
cli_dbgmsg("Can't read %d bytes from padding area\n", gp); |
1257 | 1258 |
free(section_hdr); |
1259 |
+ free(exe_sections); |
|
1258 | 1260 |
free(support); |
1259 | 1261 |
return CL_EIO; |
1260 | 1262 |
} |
1261 | 1263 |
|
1262 |
- newebx = cli_readint32(support) - EC32(optional_hdr32.ImageBase); /* Unused */ |
|
1264 |
+ /* newebx = cli_readint32(support) - EC32(optional_hdr32.ImageBase); Unused */ |
|
1263 | 1265 |
newedi = cli_readint32(support + 4) - EC32(optional_hdr32.ImageBase); /* 1st dest */ |
1264 | 1266 |
newesi = cli_readint32(support + 8) - EC32(optional_hdr32.ImageBase); /* Source */ |
1265 | 1267 |
|
1266 |
- if(newesi < EC32(section_hdr[i + 1].VirtualAddress) || newesi >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData)) { |
|
1268 |
+ if(newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].rsz) { |
|
1267 | 1269 |
cli_dbgmsg("FSG: Source buffer out of section bounds\n"); |
1268 | 1270 |
free(support); |
1269 | 1271 |
break; |
1270 | 1272 |
} |
1271 | 1273 |
|
1272 |
- if(newedi != EC32(section_hdr[i].VirtualAddress)) { |
|
1273 |
- cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, EC32(section_hdr[i].VirtualAddress)); |
|
1274 |
+ if(newedi != exe_sections[i].rva) { |
|
1275 |
+ cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, exe_sections[i].rva); |
|
1274 | 1276 |
free(support); |
1275 | 1277 |
break; |
1276 | 1278 |
} |
... | ... |
@@ -1289,7 +1359,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1289 | 1289 |
/* FIXME: really need to bother? */ |
1290 | 1290 |
cli_dbgmsg("FSG: Original section %d is misaligned\n", sectcnt); |
1291 | 1291 |
|
1292 |
- if(rva < EC32(section_hdr[i].VirtualAddress) || rva >= EC32(section_hdr[i].VirtualAddress)+EC32(section_hdr[i].VirtualSize)) { |
|
1292 |
+ if(rva < exe_sections[i].rva || rva - exe_sections[i].rva >= exe_sections[i].vsz) { |
|
1293 | 1293 |
cli_dbgmsg("FSG: Original section %d is out of bounds\n", sectcnt); |
1294 | 1294 |
break; |
1295 | 1295 |
} |
... | ... |
@@ -1300,28 +1370,31 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1300 | 1300 |
break; |
1301 | 1301 |
} |
1302 | 1302 |
|
1303 |
- if((sections = (struct SECTION *) cli_malloc((sectcnt + 1) * sizeof(struct SECTION))) == NULL) { |
|
1303 |
+ if((sections = (struct cli_exe_section *) cli_malloc((sectcnt + 1) * sizeof(struct cli_exe_section))) == NULL) { |
|
1304 | 1304 |
free(section_hdr); |
1305 |
+ free(exe_sections); |
|
1305 | 1306 |
free(support); |
1306 | 1307 |
return CL_EMEM; |
1307 | 1308 |
} |
1308 | 1309 |
|
1309 | 1310 |
sections[0].rva = newedi; |
1310 |
- for(t = 1; t <= sectcnt; t++) |
|
1311 |
- sections[t].rva = cli_readint32(support + 8 + t * 4) - 1 -EC32(optional_hdr32.ImageBase); |
|
1311 |
+ for(t = 1; t <= (uint32_t)sectcnt; t++) |
|
1312 |
+ sections[t].rva = cli_readint32(support + 8 + t * 4) - 1 - EC32(optional_hdr32.ImageBase); |
|
1312 | 1313 |
|
1313 | 1314 |
free(support); |
1314 | 1315 |
|
1315 | 1316 |
if((src = (char *) cli_malloc(ssize)) == NULL) { |
1316 | 1317 |
free(section_hdr); |
1318 |
+ free(exe_sections); |
|
1317 | 1319 |
free(sections); |
1318 | 1320 |
return CL_EMEM; |
1319 | 1321 |
} |
1320 | 1322 |
|
1321 |
- lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET); |
|
1323 |
+ lseek(desc, exe_sections[i + 1].raw, SEEK_SET); |
|
1322 | 1324 |
if((unsigned int) cli_readn(desc, src, ssize) != ssize) { |
1323 | 1325 |
cli_dbgmsg("Can't read raw data of section %d\n", i); |
1324 | 1326 |
free(section_hdr); |
1327 |
+ free(exe_sections); |
|
1325 | 1328 |
free(sections); |
1326 | 1329 |
free(src); |
1327 | 1330 |
return CL_EIO; |
... | ... |
@@ -1329,16 +1402,18 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1329 | 1329 |
|
1330 | 1330 |
if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { |
1331 | 1331 |
free(section_hdr); |
1332 |
+ free(exe_sections); |
|
1332 | 1333 |
free(src); |
1333 | 1334 |
free(sections); |
1334 | 1335 |
return CL_EMEM; |
1335 | 1336 |
} |
1336 | 1337 |
|
1337 |
- oldep = EC32(optional_hdr32.AddressOfEntryPoint) + 161 + 6 + cli_readint32(buff+163); |
|
1338 |
+ oldep = vep + 161 + 6 + cli_readint32(buff+163); |
|
1338 | 1339 |
cli_dbgmsg("FSG: found old EP @%x\n", oldep); |
1339 | 1340 |
|
1340 | 1341 |
if(!(tempfile = cli_gentemp(NULL))) { |
1341 | 1342 |
free(section_hdr); |
1343 |
+ free(exe_sections); |
|
1342 | 1344 |
free(src); |
1343 | 1345 |
free(dest); |
1344 | 1346 |
free(sections); |
... | ... |
@@ -1349,13 +1424,14 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1349 | 1349 |
cli_dbgmsg("FSG: Can't create file %s\n", tempfile); |
1350 | 1350 |
free(tempfile); |
1351 | 1351 |
free(section_hdr); |
1352 |
+ free(exe_sections); |
|
1352 | 1353 |
free(src); |
1353 | 1354 |
free(dest); |
1354 | 1355 |
free(sections); |
1355 | 1356 |
return CL_EIO; |
1356 | 1357 |
} |
1357 | 1358 |
|
1358 |
- switch(unfsg_133(src + newesi - EC32(section_hdr[i + 1].VirtualAddress), dest, ssize + EC32(section_hdr[i + 1].VirtualAddress) - newesi, dsize, sections, sectcnt, EC32(optional_hdr32.ImageBase), oldep, ndesc)) { |
|
1359 |
+ switch(unfsg_133(src + newesi - exe_sections[i + 1].rva, dest, ssize + exe_sections[i + 1].rva - newesi, dsize, sections, sectcnt, EC32(optional_hdr32.ImageBase), oldep, ndesc)) { |
|
1359 | 1360 |
case 1: /* Everything OK */ |
1360 | 1361 |
cli_dbgmsg("FSG: Unpacked and rebuilt executable saved in %s\n", tempfile); |
1361 | 1362 |
free(src); |
... | ... |
@@ -1367,6 +1443,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1367 | 1367 |
cli_dbgmsg("***** Scanning rebuilt PE file *****\n"); |
1368 | 1368 |
if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) { |
1369 | 1369 |
free(section_hdr); |
1370 |
+ free(exe_sections); |
|
1370 | 1371 |
close(ndesc); |
1371 | 1372 |
if(!cli_leavetemps_flag) |
1372 | 1373 |
unlink(tempfile); |
... | ... |
@@ -1379,10 +1456,11 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1379 | 1379 |
unlink(tempfile); |
1380 | 1380 |
free(tempfile); |
1381 | 1381 |
free(section_hdr); |
1382 |
+ free(exe_sections); |
|
1382 | 1383 |
return CL_CLEAN; |
1383 | 1384 |
|
1384 | 1385 |
case 0: /* We've got an unpacked buffer, no exe though */ |
1385 |
- cli_dbgmsg("FSG: FSG: Successfully decompressed\n"); |
|
1386 |
+ cli_dbgmsg("FSG: Successfully decompressed\n"); |
|
1386 | 1387 |
close(ndesc); |
1387 | 1388 |
unlink(tempfile); |
1388 | 1389 |
free(tempfile); |
... | ... |
@@ -1407,40 +1485,42 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1407 | 1407 |
} |
1408 | 1408 |
|
1409 | 1409 |
/* FIXME: easy 2 hack */ |
1410 |
- if(found && buff[0] == '\xbb' && cli_readint32(buff + 1) - EC32(optional_hdr32.ImageBase) < min && buff[5] == '\xbf' && buff[10] == '\xbe') { |
|
1410 |
+ if(found && buff[0] == '\xbb' && cli_readint32(buff + 1) - EC32(optional_hdr32.ImageBase) < min && buff[5] == '\xbf' && buff[10] == '\xbe' && vep >= exe_sections[i + 1].rva && vep - exe_sections[i + 1].rva > exe_sections[i + 1].rva - 0xe0 ) { |
|
1411 | 1411 |
|
1412 | 1412 |
/* FSG support - v. 1.31 */ |
1413 | 1413 |
|
1414 |
- ssize = EC32(section_hdr[i + 1].SizeOfRawData); |
|
1415 |
- dsize = EC32(section_hdr[i].VirtualSize); |
|
1414 |
+ ssize = exe_sections[i + 1].rsz; |
|
1415 |
+ dsize = exe_sections[i].vsz; |
|
1416 | 1416 |
|
1417 | 1417 |
while(found) { |
1418 |
- int gp = cli_readint32(buff+1) - EC32(optional_hdr32.ImageBase), t, sectcnt = 0; |
|
1418 |
+ int sectcnt = 0; |
|
1419 |
+ uint32_t t; |
|
1420 |
+ uint32_t gp = cli_rawaddr(cli_readint32(buff+1) - EC32(optional_hdr32.ImageBase), NULL, 0 , &err, fsize); |
|
1419 | 1421 |
char *support; |
1420 | 1422 |
uint32_t newesi = cli_readint32(buff+11) - EC32(optional_hdr32.ImageBase); |
1421 | 1423 |
uint32_t newedi = cli_readint32(buff+6) - EC32(optional_hdr32.ImageBase); |
1422 |
- uint32_t oldep = EC32(optional_hdr32.AddressOfEntryPoint); |
|
1423 |
- struct SECTION *sections; |
|
1424 |
+ uint32_t oldep = vep - exe_sections[i + 1].rva; |
|
1425 |
+ struct cli_exe_section *sections; |
|
1424 | 1426 |
|
1425 |
- if (oldep <= EC32(section_hdr[i + 1].VirtualAddress) || oldep > EC32(section_hdr[i + 1].VirtualAddress)+EC32(section_hdr[i + 1].SizeOfRawData) - 0xe0) { |
|
1426 |
- cli_dbgmsg("FSG: EP not in section %d\n", i+1); |
|
1427 |
- break; |
|
1427 |
+ if(err) { |
|
1428 |
+ cli_dbgmsg("FSG: Support data out of padding area\n"); |
|
1429 |
+ break; |
|
1428 | 1430 |
} |
1429 |
- oldep -= EC32(section_hdr[i + 1].VirtualAddress); |
|
1430 | 1431 |
|
1431 |
- if(newesi < EC32(section_hdr[i + 1].VirtualAddress) || newesi >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData)) { |
|
1432 |
+ if(newesi < exe_sections[i + 1].rva || newesi - exe_sections[i + 1].rva >= exe_sections[i + 1].raw) { |
|
1432 | 1433 |
cli_dbgmsg("FSG: Source buffer out of section bounds\n"); |
1433 | 1434 |
break; |
1434 | 1435 |
} |
1435 | 1436 |
|
1436 |
- if(newedi != EC32(section_hdr[i].VirtualAddress)) { |
|
1437 |
- cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, EC32(section_hdr[i].VirtualAddress)); |
|
1437 |
+ if(newedi != exe_sections[i].rva) { |
|
1438 |
+ cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, exe_sections[i].rva); |
|
1438 | 1439 |
break; |
1439 | 1440 |
} |
1440 | 1441 |
|
1441 | 1442 |
if(ctx->limits && ctx->limits->maxfilesize && (ssize > ctx->limits->maxfilesize || dsize > ctx->limits->maxfilesize)) { |
1442 | 1443 |
cli_dbgmsg("FSG: Sizes exceeded (ssize: %u, dsize: %u, max: %lu)\n", ssize, dsize, ctx->limits->maxfilesize); |
1443 | 1444 |
free(section_hdr); |
1445 |
+ free(exe_sections); |
|
1444 | 1446 |
if(BLOCKMAX) { |
1445 | 1447 |
*ctx->virname = "PE.FSG.ExceededFileSize"; |
1446 | 1448 |
return CL_VIRUS; |
... | ... |
@@ -1452,20 +1532,17 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1452 | 1452 |
if(ssize <= 0x19 || dsize <= ssize) { |
1453 | 1453 |
cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); |
1454 | 1454 |
free(section_hdr); |
1455 |
+ free(exe_sections); |
|
1455 | 1456 |
return CL_CLEAN; |
1456 | 1457 |
} |
1457 | 1458 |
|
1458 |
- if(gp >= (int) EC32(section_hdr[i + 1].PointerToRawData) || gp < 0) { |
|
1459 |
- cli_dbgmsg("FSG: Support data out of padding area (newedi: %d, vaddr: %d)\n", newedi, EC32(section_hdr[i].VirtualAddress)); |
|
1460 |
- break; |
|
1461 |
- } |
|
1462 |
- |
|
1463 | 1459 |
lseek(desc, gp, SEEK_SET); |
1464 |
- gp = EC32(section_hdr[i + 1].PointerToRawData) - gp; |
|
1460 |
+ gp = exe_sections[i + 1].raw - gp; |
|
1465 | 1461 |
|
1466 |
- if(ctx->limits && ctx->limits->maxfilesize && (unsigned int) gp > ctx->limits->maxfilesize) { |
|
1462 |
+ if(ctx->limits && ctx->limits->maxfilesize && gp > ctx->limits->maxfilesize) { |
|
1467 | 1463 |
cli_dbgmsg("FSG: Buffer size exceeded (size: %d, max: %lu)\n", gp, ctx->limits->maxfilesize); |
1468 | 1464 |
free(section_hdr); |
1465 |
+ free(exe_sections); |
|
1469 | 1466 |
if(BLOCKMAX) { |
1470 | 1467 |
*ctx->virname = "PE.FSG.ExceededFileSize"; |
1471 | 1468 |
return CL_VIRUS; |
... | ... |
@@ -1476,19 +1553,21 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1476 | 1476 |
|
1477 | 1477 |
if((support = (char *) cli_malloc(gp)) == NULL) { |
1478 | 1478 |
free(section_hdr); |
1479 |
+ free(exe_sections); |
|
1479 | 1480 |
return CL_EMEM; |
1480 | 1481 |
} |
1481 | 1482 |
|
1482 |
- if(cli_readn(desc, support, gp) != gp) { |
|
1483 |
+ if(cli_readn(desc, support, gp) != (int)gp) { |
|
1483 | 1484 |
cli_dbgmsg("Can't read %d bytes from padding area\n", gp); |
1484 | 1485 |
free(section_hdr); |
1486 |
+ free(exe_sections); |
|
1485 | 1487 |
free(support); |
1486 | 1488 |
return CL_EIO; |
1487 | 1489 |
} |
1488 | 1490 |
|
1489 | 1491 |
/* Counting original sections */ |
1490 | 1492 |
for(t = 0; t < gp - 2; t += 2) { |
1491 |
- uint32_t rva = support[t]+256*support[t+1]; |
|
1493 |
+ uint32_t rva = support[t]|(support[t+1]<<8); |
|
1492 | 1494 |
|
1493 | 1495 |
if (rva == 2 || rva == 1) |
1494 | 1496 |
break; |
... | ... |
@@ -1496,7 +1575,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1496 | 1496 |
rva = ((rva-2)<<12) - EC32(optional_hdr32.ImageBase); |
1497 | 1497 |
sectcnt++; |
1498 | 1498 |
|
1499 |
- if(rva < EC32(section_hdr[i].VirtualAddress) || rva >= EC32(section_hdr[i].VirtualAddress)+EC32(section_hdr[i].VirtualSize)) { |
|
1499 |
+ if(rva < exe_sections[i].rva || rva - exe_sections[i].rva >= exe_sections[i].vsz) { |
|
1500 | 1500 |
cli_dbgmsg("FSG: Original section %d is out of bounds\n", sectcnt); |
1501 | 1501 |
break; |
1502 | 1502 |
} |
... | ... |
@@ -1507,29 +1586,32 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1507 | 1507 |
break; |
1508 | 1508 |
} |
1509 | 1509 |
|
1510 |
- if((sections = (struct SECTION *) cli_malloc((sectcnt + 1) * sizeof(struct SECTION))) == NULL) { |
|
1510 |
+ if((sections = (struct cli_exe_section *) cli_malloc((sectcnt + 1) * sizeof(struct cli_exe_section))) == NULL) { |
|
1511 | 1511 |
free(section_hdr); |
1512 |
+ free(exe_sections); |
|
1512 | 1513 |
free(support); |
1513 | 1514 |
return CL_EMEM; |
1514 | 1515 |
} |
1515 | 1516 |
|
1516 | 1517 |
sections[0].rva = newedi; |
1517 |
- for(t = 0; t <= sectcnt - 1; t++) { |
|
1518 |
- sections[t+1].rva = (((support[t*2]+256*support[t*2+1])-2)<<12)-EC32(optional_hdr32.ImageBase); |
|
1518 |
+ for(t = 0; t <= (uint32_t)sectcnt - 1; t++) { |
|
1519 |
+ sections[t+1].rva = (((support[t*2]|(support[t*2+1]<<8))-2)<<12)-EC32(optional_hdr32.ImageBase); |
|
1519 | 1520 |
} |
1520 | 1521 |
|
1521 | 1522 |
free(support); |
1522 | 1523 |
|
1523 | 1524 |
if((src = (char *) cli_malloc(ssize)) == NULL) { |
1524 | 1525 |
free(section_hdr); |
1526 |
+ free(exe_sections); |
|
1525 | 1527 |
free(sections); |
1526 | 1528 |
return CL_EMEM; |
1527 | 1529 |
} |
1528 | 1530 |
|
1529 |
- lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET); |
|
1531 |
+ lseek(desc, exe_sections[i + 1].raw, SEEK_SET); |
|
1530 | 1532 |
if((unsigned int) cli_readn(desc, src, ssize) != ssize) { |
1531 |
- cli_dbgmsg("Can't read raw data of section %d\n", i); |
|
1533 |
+ cli_dbgmsg("FSG: Can't read raw data of section %d\n", i); |
|
1532 | 1534 |
free(section_hdr); |
1535 |
+ free(exe_sections); |
|
1533 | 1536 |
free(sections); |
1534 | 1537 |
free(src); |
1535 | 1538 |
return CL_EIO; |
... | ... |
@@ -1537,6 +1619,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1537 | 1537 |
|
1538 | 1538 |
if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { |
1539 | 1539 |
free(section_hdr); |
1540 |
+ free(exe_sections); |
|
1540 | 1541 |
free(src); |
1541 | 1542 |
free(sections); |
1542 | 1543 |
return CL_EMEM; |
... | ... |
@@ -1544,11 +1627,12 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1544 | 1544 |
|
1545 | 1545 |
/* Better not increasing buff size any further, let's go the hard way */ |
1546 | 1546 |
gp = 0xda + 6*(buff[16]=='\xe8'); |
1547 |
- oldep = EC32(optional_hdr32.AddressOfEntryPoint) + gp + 6 + cli_readint32(src+gp+2+oldep); |
|
1547 |
+ oldep = vep + gp + 6 + cli_readint32(src+gp+2+oldep); |
|
1548 | 1548 |
cli_dbgmsg("FSG: found old EP @%x\n", oldep); |
1549 | 1549 |
|
1550 | 1550 |
if(!(tempfile = cli_gentemp(NULL))) { |
1551 | 1551 |
free(section_hdr); |
1552 |
+ free(exe_sections); |
|
1552 | 1553 |
free(src); |
1553 | 1554 |
free(dest); |
1554 | 1555 |
free(sections); |
... | ... |
@@ -1559,6 +1643,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1559 | 1559 |
cli_dbgmsg("FSG: Can't create file %s\n", tempfile); |
1560 | 1560 |
free(tempfile); |
1561 | 1561 |
free(section_hdr); |
1562 |
+ free(exe_sections); |
|
1562 | 1563 |
free(src); |
1563 | 1564 |
free(dest); |
1564 | 1565 |
free(sections); |
... | ... |
@@ -1577,6 +1662,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1577 | 1577 |
cli_dbgmsg("***** Scanning rebuilt PE file *****\n"); |
1578 | 1578 |
if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) { |
1579 | 1579 |
free(section_hdr); |
1580 |
+ free(exe_sections); |
|
1580 | 1581 |
close(ndesc); |
1581 | 1582 |
if(!cli_leavetemps_flag) |
1582 | 1583 |
unlink(tempfile); |
... | ... |
@@ -1589,6 +1675,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1589 | 1589 |
unlink(tempfile); |
1590 | 1590 |
free(tempfile); |
1591 | 1591 |
free(section_hdr); |
1592 |
+ free(exe_sections); |
|
1592 | 1593 |
return CL_CLEAN; |
1593 | 1594 |
|
1594 | 1595 |
case 0: /* We've got an unpacked buffer, no exe though */ |
... | ... |
@@ -1632,12 +1719,13 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1632 | 1632 |
cli_dbgmsg("UPX: Possibly hacked UPX section headers\n"); |
1633 | 1633 |
|
1634 | 1634 |
/* we assume (i + 1) is UPX1 */ |
1635 |
- ssize = EC32(section_hdr[i + 1].SizeOfRawData); |
|
1636 |
- dsize = EC32(section_hdr[i].VirtualSize) + EC32(section_hdr[i + 1].VirtualSize); |
|
1635 |
+ ssize = exe_sections[i + 1].rsz; |
|
1636 |
+ dsize = exe_sections[i].vsz + exe_sections[i + 1].vsz; |
|
1637 | 1637 |
|
1638 | 1638 |
if(ctx->limits && ctx->limits->maxfilesize && (ssize > ctx->limits->maxfilesize || dsize > ctx->limits->maxfilesize)) { |
1639 | 1639 |
cli_dbgmsg("UPX: Sizes exceeded (ssize: %u, dsize: %u, max: %lu)\n", ssize, dsize , ctx->limits->maxfilesize); |
1640 | 1640 |
free(section_hdr); |
1641 |
+ free(exe_sections); |
|
1641 | 1642 |
if(BLOCKMAX) { |
1642 | 1643 |
*ctx->virname = "PE.UPX.ExceededFileSize"; |
1643 | 1644 |
return CL_VIRUS; |
... | ... |
@@ -1649,32 +1737,37 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1649 | 1649 |
if(ssize <= 0x19 || dsize <= ssize) { /* FIXME: What are reasonable values? */ |
1650 | 1650 |
cli_dbgmsg("UPX: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize); |
1651 | 1651 |
free(section_hdr); |
1652 |
+ free(exe_sections); |
|
1652 | 1653 |
return CL_CLEAN; |
1653 | 1654 |
} |
1654 | 1655 |
|
1655 | 1656 |
/* FIXME: use file operations in case of big files */ |
1656 | 1657 |
if((src = (char *) cli_malloc(ssize)) == NULL) { |
1657 | 1658 |
free(section_hdr); |
1659 |
+ free(exe_sections); |
|
1658 | 1660 |
return CL_EMEM; |
1659 | 1661 |
} |
1660 | 1662 |
|
1661 | 1663 |
if(dsize > CLI_MAX_ALLOCATION) { |
1662 | 1664 |
cli_errmsg("UPX: Too big value of dsize\n"); |
1663 | 1665 |
free(section_hdr); |
1666 |
+ free(exe_sections); |
|
1664 | 1667 |
free(src); |
1665 | 1668 |
return CL_EMEM; |
1666 | 1669 |
} |
1667 | 1670 |
|
1668 |
- if((dest = (char *) cli_calloc(dsize + 1024 + nsections * 40, sizeof(char))) == NULL) { |
|
1671 |
+ if((dest = (char *) cli_calloc(dsize + 8192, sizeof(char))) == NULL) { |
|
1669 | 1672 |
free(section_hdr); |
1673 |
+ free(exe_sections); |
|
1670 | 1674 |
free(src); |
1671 | 1675 |
return CL_EMEM; |
1672 | 1676 |
} |
1673 | 1677 |
|
1674 |
- lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET); |
|
1678 |
+ lseek(desc, exe_sections[i + 1].raw, SEEK_SET); |
|
1675 | 1679 |
if((unsigned int) cli_readn(desc, src, ssize) != ssize) { |
1676 |
- cli_dbgmsg("Can't read raw data of section %d\n", i); |
|
1680 |
+ cli_dbgmsg("UPX: Can't read raw data of section %d\n", i+1); |
|
1677 | 1681 |
free(section_hdr); |
1682 |
+ free(exe_sections); |
|
1678 | 1683 |
free(src); |
1679 | 1684 |
free(dest); |
1680 | 1685 |
return CL_EIO; |
... | ... |
@@ -1683,8 +1776,9 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1683 | 1683 |
/* try to detect UPX code */ |
1684 | 1684 |
|
1685 | 1685 |
if(lseek(desc, ep, SEEK_SET) == -1) { |
1686 |
- cli_dbgmsg("lseek() failed\n"); |
|
1686 |
+ cli_dbgmsg("UPX: lseek() failed\n"); |
|
1687 | 1687 |
free(section_hdr); |
1688 |
+ free(exe_sections); |
|
1688 | 1689 |
free(src); |
1689 | 1690 |
free(dest); |
1690 | 1691 |
return CL_EIO; |
... | ... |
@@ -1692,8 +1786,9 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1692 | 1692 |
|
1693 | 1693 |
if(cli_readn(desc, buff, 126) != 126) { /* i.e. 0x69 + 13 + 8 */ |
1694 | 1694 |
cli_dbgmsg("UPX: Can't read 126 bytes at 0x%x (%d)\n", ep, ep); |
1695 |
- cli_dbgmsg("UPX/FSG: Broken or not UPX/FSG compressed file\n"); |
|
1695 |
+ cli_dbgmsg("UPX: Broken or not UPX compressed file\n"); |
|
1696 | 1696 |
free(section_hdr); |
1697 |
+ free(exe_sections); |
|
1697 | 1698 |
free(src); |
1698 | 1699 |
free(dest); |
1699 | 1700 |
return CL_CLEAN; |
... | ... |
@@ -1711,27 +1806,27 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1711 | 1711 |
} |
1712 | 1712 |
|
1713 | 1713 |
if(upxfn) { |
1714 |
- int skew = cli_readint32(buff + 2) - EC32(optional_hdr32.ImageBase) - EC32(section_hdr[i + 1].VirtualAddress); |
|
1714 |
+ int skew = cli_readint32(buff + 2) - EC32(optional_hdr32.ImageBase) - exe_sections[i + 1].rva; |
|
1715 | 1715 |
|
1716 | 1716 |
if(buff[1] != '\xbe' || skew <= 0 || skew > 0xfff) { /* FIXME: legit skews?? */ |
1717 | 1717 |
skew = 0; |
1718 |
- if(upxfn(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint)) >= 0) |
|
1718 |
+ if(upxfn(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) >= 0) |
|
1719 | 1719 |
upx_success = 1; |
1720 | 1720 |
|
1721 | 1721 |
} else { |
1722 | 1722 |
cli_dbgmsg("UPX: UPX1 seems skewed by %d bytes\n", skew); |
1723 |
- if(upxfn(src + skew, ssize - skew, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint)-skew) >= 0 || upxfn(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint)) >= 0) |
|
1723 |
+ if(upxfn(src + skew, ssize - skew, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep-skew) >= 0 || upxfn(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) >= 0) |
|
1724 | 1724 |
upx_success = 1; |
1725 | 1725 |
} |
1726 | 1726 |
|
1727 | 1727 |
if(upx_success) |
1728 | 1728 |
cli_dbgmsg("UPX: Successfully decompressed\n"); |
1729 | 1729 |
else |
1730 |
- cli_dbgmsg("UPX: Prefered decompressor failed\n"); |
|
1730 |
+ cli_dbgmsg("UPX: Preferred decompressor failed\n"); |
|
1731 | 1731 |
} |
1732 | 1732 |
|
1733 | 1733 |
if(!upx_success && upxfn != upx_inflate2b) { |
1734 |
- if(upx_inflate2b(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint)) == -1 && upx_inflate2b(src + 0x15, ssize - 0x15, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint) - 0x15) == -1) { |
|
1734 |
+ if(upx_inflate2b(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2b(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) { |
|
1735 | 1735 |
|
1736 | 1736 |
cli_dbgmsg("UPX: NRV2B decompressor failed\n"); |
1737 | 1737 |
} else { |
... | ... |
@@ -1741,7 +1836,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1741 | 1741 |
} |
1742 | 1742 |
|
1743 | 1743 |
if(!upx_success && upxfn != upx_inflate2d) { |
1744 |
- if(upx_inflate2d(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint)) == -1 && upx_inflate2d(src + 0x15, ssize - 0x15, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint) - 0x15) == -1) { |
|
1744 |
+ if(upx_inflate2d(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2d(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) { |
|
1745 | 1745 |
|
1746 | 1746 |
cli_dbgmsg("UPX: NRV2D decompressor failed\n"); |
1747 | 1747 |
} else { |
... | ... |
@@ -1751,7 +1846,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1751 | 1751 |
} |
1752 | 1752 |
|
1753 | 1753 |
if(!upx_success && upxfn != upx_inflate2e) { |
1754 |
- if(upx_inflate2e(src, ssize, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint)) == -1 && upx_inflate2e(src + 0x15, ssize - 0x15, dest, &dsize, EC32(section_hdr[i].VirtualAddress), EC32(section_hdr[i + 1].VirtualAddress), EC32(optional_hdr32.AddressOfEntryPoint) - 0x15) == -1) { |
|
1754 |
+ if(upx_inflate2e(src, ssize, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep) == -1 && upx_inflate2e(src + 0x15, ssize - 0x15, dest, &dsize, exe_sections[i].rva, exe_sections[i + 1].rva, vep - 0x15) == -1) { |
|
1755 | 1755 |
cli_dbgmsg("UPX: NRV2E decompressor failed\n"); |
1756 | 1756 |
} else { |
1757 | 1757 |
upx_success = 1; |
... | ... |
@@ -1769,6 +1864,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1769 | 1769 |
if(upx_success) { |
1770 | 1770 |
free(src); |
1771 | 1771 |
free(section_hdr); |
1772 |
+ free(exe_sections); |
|
1772 | 1773 |
|
1773 | 1774 |
if(!(tempfile = cli_gentemp(NULL))) { |
1774 | 1775 |
free(dest); |
... | ... |
@@ -1823,6 +1919,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1823 | 1823 |
if(cli_readn(desc, buff, 200) == -1) { |
1824 | 1824 |
cli_dbgmsg("cli_readn() failed\n"); |
1825 | 1825 |
free(section_hdr); |
1826 |
+ free(exe_sections); |
|
1826 | 1827 |
return CL_EIO; |
1827 | 1828 |
} |
1828 | 1829 |
|
... | ... |
@@ -1844,6 +1941,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1844 | 1844 |
if(ctx->limits && ctx->limits->maxfilesize && dsize > ctx->limits->maxfilesize) { |
1845 | 1845 |
cli_dbgmsg("Petite: Size exceeded (dsize: %u, max: %lu)\n", dsize, ctx->limits->maxfilesize); |
1846 | 1846 |
free(section_hdr); |
1847 |
+ free(exe_sections); |
|
1847 | 1848 |
if(BLOCKMAX) { |
1848 | 1849 |
*ctx->virname = "PE.Petite.ExceededFileSize"; |
1849 | 1850 |
return CL_VIRUS; |
... | ... |
@@ -1855,15 +1953,17 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1855 | 1855 |
if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { |
1856 | 1856 |
cli_dbgmsg("Petite: Can't allocate %d bytes\n", dsize); |
1857 | 1857 |
free(section_hdr); |
1858 |
+ free(exe_sections); |
|
1858 | 1859 |
return CL_EMEM; |
1859 | 1860 |
} |
1860 | 1861 |
|
1861 | 1862 |
for(i = 0 ; i < nsections; i++) { |
1862 | 1863 |
if(section_hdr[i].SizeOfRawData) { |
1863 |
- uint32_t offset = cli_rawaddr(EC32(section_hdr[i].VirtualAddress), section_hdr, nsections, &err, 0, 0); |
|
1864 |
+ uint32_t offset = cli_rawaddr(EC32(section_hdr[i].VirtualAddress), exe_sections, nsections, &err, fsize); |
|
1864 | 1865 |
|
1865 | 1866 |
if(err || lseek(desc, offset, SEEK_SET) == -1 || (unsigned int) cli_readn(desc, dest + EC32(section_hdr[i].VirtualAddress) - min, EC32(section_hdr[i].SizeOfRawData)) != EC32(section_hdr[i].SizeOfRawData)) { |
1866 | 1867 |
free(section_hdr); |
1868 |
+ free(exe_sections); |
|
1867 | 1869 |
free(dest); |
1868 | 1870 |
return CL_EIO; |
1869 | 1871 |
} |
... | ... |
@@ -1873,6 +1973,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1873 | 1873 |
if(!(tempfile = cli_gentemp(NULL))) { |
1874 | 1874 |
free(dest); |
1875 | 1875 |
free(section_hdr); |
1876 |
+ free(exe_sections); |
|
1876 | 1877 |
return CL_EMEM; |
1877 | 1878 |
} |
1878 | 1879 |
|
... | ... |
@@ -1880,61 +1981,49 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1880 | 1880 |
cli_dbgmsg("Petite: Can't create file %s\n", tempfile); |
1881 | 1881 |
free(tempfile); |
1882 | 1882 |
free(section_hdr); |
1883 |
+ free(exe_sections); |
|
1883 | 1884 |
free(dest); |
1884 | 1885 |
return CL_EIO; |
1885 | 1886 |
} |
1886 | 1887 |
|
1887 | 1888 |
/* aCaB: Fixed to allow petite v2.1 unpacking (last section is a ghost) */ |
1888 |
- switch(petite_inflate2x_1to9(dest, min, max - min, section_hdr, |
|
1889 |
+ if (!petite_inflate2x_1to9(dest, min, max - min, section_hdr, |
|
1889 | 1890 |
nsections - (found == 1 ? 1 : 0), EC32(optional_hdr32.ImageBase), |
1890 |
- EC32(optional_hdr32.AddressOfEntryPoint), ndesc, |
|
1891 |
- found, EC32(optional_hdr32.DataDirectory[2].VirtualAddress), |
|
1891 |
+ vep, ndesc, found, EC32(optional_hdr32.DataDirectory[2].VirtualAddress), |
|
1892 | 1892 |
EC32(optional_hdr32.DataDirectory[2].Size))) { |
1893 |
- case 1: |
|
1894 |
- cli_dbgmsg("Petite: Unpacked and rebuilt executable saved in %s\n", tempfile); |
|
1895 |
- cli_dbgmsg("***** Scanning rebuilt PE file *****\n"); |
|
1896 |
- break; |
|
1897 |
- |
|
1898 |
- case 0: |
|
1899 |
- cli_dbgmsg("Petite: Unpacked data saved in %s\n", tempfile); |
|
1900 |
- break; |
|
1901 |
- |
|
1902 |
- default: |
|
1903 |
- cli_dbgmsg("Petite: Unpacking failed\n"); |
|
1904 |
- } |
|
1905 |
- |
|
1906 |
- free(dest); |
|
1907 |
- fsync(ndesc); |
|
1908 |
- lseek(ndesc, 0, SEEK_SET); |
|
1909 |
- |
|
1910 |
- if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) { |
|
1911 |
- free(section_hdr); |
|
1912 |
- close(ndesc); |
|
1913 |
- if(!cli_leavetemps_flag) { |
|
1914 |
- unlink(tempfile); |
|
1915 |
- free(tempfile); |
|
1916 |
- } else { |
|
1893 |
+ cli_dbgmsg("Petite: Unpacked and rebuilt executable saved in %s\n", tempfile); |
|
1894 |
+ cli_dbgmsg("***** Scanning rebuilt PE file *****\n"); |
|
1895 |
+ free(dest); |
|
1896 |
+ fsync(ndesc); |
|
1897 |
+ lseek(ndesc, 0, SEEK_SET); |
|
1898 |
+ if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) { |
|
1899 |
+ free(section_hdr); |
|
1900 |
+ free(exe_sections); |
|
1901 |
+ close(ndesc); |
|
1902 |
+ if(!cli_leavetemps_flag) { |
|
1903 |
+ unlink(tempfile); |
|
1904 |
+ } |
|
1917 | 1905 |
free(tempfile); |
1906 |
+ return CL_VIRUS; |
|
1918 | 1907 |
} |
1919 |
- return CL_VIRUS; |
|
1920 |
- } |
|
1921 | 1908 |
|
1909 |
+ } else { |
|
1910 |
+ cli_dbgmsg("Petite: Unpacking failed\n"); |
|
1911 |
+ free(dest); |
|
1912 |
+ } |
|
1922 | 1913 |
close(ndesc); |
1923 |
- |
|
1924 | 1914 |
if(!cli_leavetemps_flag) { |
1925 |
- unlink(tempfile); |
|
1926 |
- free(tempfile); |
|
1927 |
- } else { |
|
1928 |
- free(tempfile); |
|
1915 |
+ unlink(tempfile); |
|
1929 | 1916 |
} |
1917 |
+ free(tempfile); |
|
1930 | 1918 |
} |
1931 | 1919 |
} |
1932 | 1920 |
|
1933 | 1921 |
/* PESpin 1.1 */ |
1934 | 1922 |
|
1935 | 1923 |
if(nsections > 1 && |
1936 |
- EC32(optional_hdr32.AddressOfEntryPoint) >= EC32(section_hdr[nsections - 1].VirtualAddress) && |
|
1937 |
- EC32(optional_hdr32.AddressOfEntryPoint) < EC32(section_hdr[nsections - 1].VirtualAddress) + EC32(section_hdr[nsections - 1].SizeOfRawData) - 0x3217 - 4 && |
|
1924 |
+ vep >= EC32(section_hdr[nsections - 1].VirtualAddress) && |
|
1925 |
+ vep < EC32(section_hdr[nsections - 1].VirtualAddress) + EC32(section_hdr[nsections - 1].SizeOfRawData) - 0x3217 - 4 && |
|
1938 | 1926 |
memcmp(buff+4, "\xe8\x00\x00\x00\x00\x8b\x1c\x24\x83\xc3", 10) == 0) { |
1939 | 1927 |
|
1940 | 1928 |
char *spinned; |
... | ... |
@@ -1942,6 +2031,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1942 | 1942 |
if(ctx->limits && ctx->limits->maxfilesize && fsize > ctx->limits->maxfilesize) { |
1943 | 1943 |
cli_dbgmsg("PEspin: Size exceeded (fsize: %u, max: %lu)\n", fsize, ctx->limits->maxfilesize); |
1944 | 1944 |
free(section_hdr); |
1945 |
+ free(exe_sections); |
|
1945 | 1946 |
if(BLOCKMAX) { |
1946 | 1947 |
*ctx->virname = "PE.Pespin.ExceededFileSize"; |
1947 | 1948 |
return CL_VIRUS; |
... | ... |
@@ -1952,6 +2042,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1952 | 1952 |
|
1953 | 1953 |
if((spinned = (char *) cli_malloc(fsize)) == NULL) { |
1954 | 1954 |
free(section_hdr); |
1955 |
+ free(exe_sections); |
|
1955 | 1956 |
return CL_EMEM; |
1956 | 1957 |
} |
1957 | 1958 |
|
... | ... |
@@ -1960,12 +2051,14 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1960 | 1960 |
cli_dbgmsg("PESpin: Can't read %d bytes\n", fsize); |
1961 | 1961 |
free(spinned); |
1962 | 1962 |
free(section_hdr); |
1963 |
+ free(exe_sections); |
|
1963 | 1964 |
return CL_EIO; |
1964 | 1965 |
} |
1965 | 1966 |
|
1966 | 1967 |
if(!(tempfile = cli_gentemp(NULL))) { |
1967 | 1968 |
free(spinned); |
1968 | 1969 |
free(section_hdr); |
1970 |
+ free(exe_sections); |
|
1969 | 1971 |
return CL_EMEM; |
1970 | 1972 |
} |
1971 | 1973 |
|
... | ... |
@@ -1974,10 +2067,11 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1974 | 1974 |
free(tempfile); |
1975 | 1975 |
free(spinned); |
1976 | 1976 |
free(section_hdr); |
1977 |
+ free(exe_sections); |
|
1977 | 1978 |
return CL_EIO; |
1978 | 1979 |
} |
1979 | 1980 |
|
1980 |
- switch(unspin(spinned, fsize, section_hdr, nsections - 1, EC32(optional_hdr32.AddressOfEntryPoint), ndesc, ctx)) { |
|
1981 |
+ switch(unspin(spinned, fsize, section_hdr, nsections - 1, vep, ndesc, ctx)) { |
|
1981 | 1982 |
case 0: |
1982 | 1983 |
free(spinned); |
1983 | 1984 |
if(cli_leavetemps_flag) |
... | ... |
@@ -1992,6 +2086,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
1992 | 1992 |
unlink(tempfile); |
1993 | 1993 |
free(tempfile); |
1994 | 1994 |
free(section_hdr); |
1995 |
+ free(exe_sections); |
|
1995 | 1996 |
return CL_VIRUS; |
1996 | 1997 |
} |
1997 | 1998 |
close(ndesc); |
... | ... |
@@ -2012,6 +2107,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2012 | 2012 |
if(BLOCKMAX) { |
2013 | 2013 |
free(tempfile); |
2014 | 2014 |
free(section_hdr); |
2015 |
+ free(exe_sections); |
|
2015 | 2016 |
*ctx->virname = "PE.Pespin.ExceededFileSize"; |
2016 | 2017 |
return CL_VIRUS; |
2017 | 2018 |
} |
... | ... |
@@ -2032,6 +2128,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2032 | 2032 |
if ( fsize >= EC32(section_hdr[nsections - 1].PointerToRawData) + 0xC6 + 0xb97 ) { /* size check on yC sect */ |
2033 | 2033 |
if((spinned = (char *) cli_malloc(fsize)) == NULL) { |
2034 | 2034 |
free(section_hdr); |
2035 |
+ free(exe_sections); |
|
2035 | 2036 |
return CL_EMEM; |
2036 | 2037 |
} |
2037 | 2038 |
|
... | ... |
@@ -2040,12 +2137,14 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2040 | 2040 |
cli_dbgmsg("yC: Can't read %d bytes\n", fsize); |
2041 | 2041 |
free(spinned); |
2042 | 2042 |
free(section_hdr); |
2043 |
+ free(exe_sections); |
|
2043 | 2044 |
return CL_EIO; |
2044 | 2045 |
} |
2045 | 2046 |
|
2046 | 2047 |
if(!(tempfile = cli_gentemp(NULL))) { |
2047 | 2048 |
free(spinned); |
2048 | 2049 |
free(section_hdr); |
2050 |
+ free(exe_sections); |
|
2049 | 2051 |
return CL_EMEM; |
2050 | 2052 |
} |
2051 | 2053 |
|
... | ... |
@@ -2054,6 +2153,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2054 | 2054 |
free(tempfile); |
2055 | 2055 |
free(spinned); |
2056 | 2056 |
free(section_hdr); |
2057 |
+ free(exe_sections); |
|
2057 | 2058 |
return CL_EIO; |
2058 | 2059 |
} |
2059 | 2060 |
|
... | ... |
@@ -2065,6 +2165,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2065 | 2065 |
|
2066 | 2066 |
if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) { |
2067 | 2067 |
free(section_hdr); |
2068 |
+ free(exe_sections); |
|
2068 | 2069 |
close(ndesc); |
2069 | 2070 |
if(!cli_leavetemps_flag) { |
2070 | 2071 |
unlink(tempfile); |
... | ... |
@@ -2095,24 +2196,23 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2095 | 2095 |
/* WWPack */ |
2096 | 2096 |
|
2097 | 2097 |
if(nsections > 1 && |
2098 |
- EC32(section_hdr[nsections-1].SizeOfRawData)>0x2b1 && |
|
2099 |
- EC32(optional_hdr32.AddressOfEntryPoint) == EC32(section_hdr[nsections - 1].VirtualAddress) && |
|
2100 |
- EC32(section_hdr[nsections - 1].VirtualAddress)+EC32(section_hdr[nsections - 1].SizeOfRawData) == max && |
|
2098 |
+ exe_sections[nsections-1].raw>0x2b1 && |
|
2099 |
+ vep == exe_sections[nsections - 1].rva && |
|
2100 |
+ exe_sections[nsections - 1].rva + exe_sections[nsections - 1].rsz == max && |
|
2101 | 2101 |
memcmp(buff, "\x53\x55\x8b\xe8\x33\xdb\xeb", 7) == 0 && |
2102 | 2102 |
memcmp(buff+0x68, "\xe8\x00\x00\x00\x00\x58\x2d\x6d\x00\x00\x00\x50\x60\x33\xc9\x50\x58\x50\x50", 19) == 0) { |
2103 |
- uint32_t headsize=EC32(section_hdr[nsections - 1].PointerToRawData); |
|
2103 |
+ uint32_t headsize=exe_sections[nsections - 1].raw; |
|
2104 | 2104 |
char *dest, *wwp; |
2105 | 2105 |
|
2106 |
- for(i = 0 ; i < (unsigned int)nsections-1; i++) { |
|
2107 |
- uint32_t offset = cli_rawaddr(EC32(section_hdr[i].VirtualAddress), section_hdr, nsections, &err, 0, 0); |
|
2108 |
- if (!err && offset<headsize) headsize=offset; |
|
2109 |
- } |
|
2106 |
+ for(i = 0 ; i < (unsigned int)nsections-1; i++) |
|
2107 |
+ if (!err && exe_sections[i].raw<headsize) headsize=exe_sections[i].raw; |
|
2110 | 2108 |
|
2111 |
- dsize = max-min+headsize-EC32(section_hdr[nsections - 1].SizeOfRawData); |
|
2109 |
+ dsize = max-min+headsize-exe_sections[nsections - 1].rsz; |
|
2112 | 2110 |
|
2113 | 2111 |
if(ctx->limits && ctx->limits->maxfilesize && dsize > ctx->limits->maxfilesize) { |
2114 | 2112 |
cli_dbgmsg("WWPack: Size exceeded (dsize: %u, max: %lu)\n", dsize, ctx->limits->maxfilesize); |
2115 | 2113 |
free(section_hdr); |
2114 |
+ free(exe_sections); |
|
2116 | 2115 |
if(BLOCKMAX) { |
2117 | 2116 |
*ctx->virname = "PE.WWPack.ExceededFileSize"; |
2118 | 2117 |
return CL_VIRUS; |
... | ... |
@@ -2124,6 +2224,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2124 | 2124 |
if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) { |
2125 | 2125 |
cli_dbgmsg("WWPack: Can't allocate %d bytes\n", dsize); |
2126 | 2126 |
free(section_hdr); |
2127 |
+ free(exe_sections); |
|
2127 | 2128 |
return CL_EMEM; |
2128 | 2129 |
} |
2129 | 2130 |
memset(dest, 0, dsize); |
... | ... |
@@ -2133,44 +2234,49 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2133 | 2133 |
cli_dbgmsg("WWPack: Can't read %d bytes from headers\n", headsize); |
2134 | 2134 |
free(dest); |
2135 | 2135 |
free(section_hdr); |
2136 |
+ free(exe_sections); |
|
2136 | 2137 |
return CL_EIO; |
2137 | 2138 |
} |
2138 | 2139 |
|
2139 | 2140 |
for(i = 0 ; i < (unsigned int)nsections-1; i++) { |
2140 |
- if(section_hdr[i].SizeOfRawData) { |
|
2141 |
- uint32_t offset = cli_rawaddr(EC32(section_hdr[i].VirtualAddress), section_hdr, nsections, &err, 0, 0); |
|
2141 |
+ if(exe_sections[i].rsz) { |
|
2142 |
+ uint32_t offset = exe_sections[i].raw; |
|
2142 | 2143 |
|
2143 |
- if(err || lseek(desc, offset, SEEK_SET) == -1 || (unsigned int) cli_readn(desc, dest + headsize + EC32(section_hdr[i].VirtualAddress) - min, EC32(section_hdr[i].SizeOfRawData)) != EC32(section_hdr[i].SizeOfRawData)) { |
|
2144 |
+ if(err || lseek(desc, offset, SEEK_SET) == -1 || (unsigned int) cli_readn(desc, dest + headsize + exe_sections[i].rva - min, exe_sections[i].rsz) != exe_sections[i].rsz) { |
|
2144 | 2145 |
free(dest); |
2145 | 2146 |
free(section_hdr); |
2147 |
+ free(exe_sections); |
|
2146 | 2148 |
return CL_EIO; |
2147 | 2149 |
} |
2148 | 2150 |
} |
2149 | 2151 |
} |
2150 | 2152 |
|
2151 |
- if((wwp = (char *) cli_calloc(EC32(section_hdr[nsections - 1].SizeOfRawData), sizeof(char))) == NULL) { |
|
2152 |
- cli_dbgmsg("WWPack: Can't allocate %d bytes\n", EC32(section_hdr[nsections - 1].SizeOfRawData)); |
|
2153 |
+ if((wwp = (char *) cli_calloc(exe_sections[nsections - 1].rsz, sizeof(char))) == NULL) { |
|
2154 |
+ cli_dbgmsg("WWPack: Can't allocate %d bytes\n", exe_sections[nsections - 1].rsz); |
|
2153 | 2155 |
free(dest); |
2154 | 2156 |
free(section_hdr); |
2157 |
+ free(exe_sections); |
|
2155 | 2158 |
return CL_EMEM; |
2156 | 2159 |
} |
2157 | 2160 |
|
2158 |
- lseek(desc, EC32(section_hdr[nsections - 1].PointerToRawData), SEEK_SET); |
|
2159 |
- if((size_t) cli_readn(desc, wwp, EC32(section_hdr[nsections - 1].SizeOfRawData)) != EC32(section_hdr[nsections - 1].SizeOfRawData)) { |
|
2160 |
- cli_dbgmsg("WWPack: Can't read %d bytes from wwpack sect\n", EC32(section_hdr[nsections - 1].SizeOfRawData)); |
|
2161 |
+ lseek(desc, exe_sections[nsections - 1].raw, SEEK_SET); |
|
2162 |
+ if((size_t) cli_readn(desc, wwp, exe_sections[nsections - 1].rsz) != exe_sections[nsections - 1].rsz) { |
|
2163 |
+ cli_dbgmsg("WWPack: Can't read %d bytes from wwpack sect\n", exe_sections[nsections - 1].rsz); |
|
2161 | 2164 |
free(dest); |
2162 | 2165 |
free(wwp); |
2163 | 2166 |
free(section_hdr); |
2167 |
+ free(exe_sections); |
|
2164 | 2168 |
return CL_EIO; |
2165 | 2169 |
} |
2166 | 2170 |
|
2167 |
- if (!wwunpack(dest, dsize, headsize, min, EC32(section_hdr[nsections-1].VirtualAddress), e_lfanew, wwp, EC32(section_hdr[nsections - 1].SizeOfRawData), nsections-1)) { |
|
2171 |
+ if (!wwunpack(dest, dsize, headsize, min, exe_sections[nsections-1].rva, e_lfanew, wwp, exe_sections[nsections - 1].rsz, nsections-1)) { |
|
2168 | 2172 |
|
2169 | 2173 |
free(wwp); |
2170 | 2174 |
|
2171 | 2175 |
if(!(tempfile = cli_gentemp(NULL))) { |
2172 | 2176 |
free(dest); |
2173 | 2177 |
free(section_hdr); |
2178 |
+ free(exe_sections); |
|
2174 | 2179 |
return CL_EMEM; |
2175 | 2180 |
} |
2176 | 2181 |
|
... | ... |
@@ -2179,6 +2285,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2179 | 2179 |
free(tempfile); |
2180 | 2180 |
free(dest); |
2181 | 2181 |
free(section_hdr); |
2182 |
+ free(exe_sections); |
|
2182 | 2183 |
return CL_EIO; |
2183 | 2184 |
} |
2184 | 2185 |
|
... | ... |
@@ -2188,6 +2295,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2188 | 2188 |
free(tempfile); |
2189 | 2189 |
free(dest); |
2190 | 2190 |
free(section_hdr); |
2191 |
+ free(exe_sections); |
|
2191 | 2192 |
return CL_EIO; |
2192 | 2193 |
} |
2193 | 2194 |
|
... | ... |
@@ -2202,6 +2310,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2202 | 2202 |
|
2203 | 2203 |
if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) { |
2204 | 2204 |
free(section_hdr); |
2205 |
+ free(exe_sections); |
|
2205 | 2206 |
close(ndesc); |
2206 | 2207 |
if(!cli_leavetemps_flag) |
2207 | 2208 |
unlink(tempfile); |
... | ... |
@@ -2223,36 +2332,34 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2223 | 2223 |
#ifdef CL_EXPERIMENTAL |
2224 | 2224 |
/* NsPack */ |
2225 | 2225 |
|
2226 |
- /* WATCH OUT: ep && buff destroyed!!! */ |
|
2227 | 2226 |
while (1) { |
2228 |
- uint32_t eprva = EC32(optional_hdr32.AddressOfEntryPoint); |
|
2229 |
- uint32_t start_of_stuff, ssize, dsize; |
|
2227 |
+ uint32_t eprva = vep; |
|
2228 |
+ uint32_t start_of_stuff, ssize, dsize, rep = ep; |
|
2230 | 2229 |
unsigned int nowinldr; |
2231 |
- char *src, *dest; |
|
2230 |
+ char nbuff[24]; |
|
2231 |
+ char *src=buff, *dest; |
|
2232 | 2232 |
FILE *asd; |
2233 | 2233 |
|
2234 |
- ep = cli_rawaddr(eprva , section_hdr, nsections, &err, EC32(optional_hdr32.SectionAlignment), EC32(optional_hdr32.FileAlignment)); |
|
2235 |
- if (lseek(desc, ep, SEEK_SET)==-1) break; |
|
2236 |
- if (cli_readn(desc, buff, 13)!=13) break; |
|
2237 | 2234 |
if (*buff=='\xe9') { /* bitched headers */ |
2238 |
- eprva = cli_readint32(buff+1)+EC32(optional_hdr32.AddressOfEntryPoint)+5; |
|
2239 |
- ep = cli_rawaddr(eprva, section_hdr, nsections, &err, EC32(optional_hdr32.SectionAlignment), EC32(optional_hdr32.FileAlignment)); |
|
2240 |
- if (lseek(desc, ep, SEEK_SET)==-1) break; |
|
2241 |
- if (cli_readn(desc, buff, 24)!=24) break; |
|
2235 |
+ eprva = cli_readint32(buff+1)+vep+5; |
|
2236 |
+ if (!(rep = cli_rawaddr(eprva, exe_sections, nsections, &err, fsize)) && err) break; |
|
2237 |
+ if (lseek(desc, rep, SEEK_SET)==-1) break; |
|
2238 |
+ if (cli_readn(desc, nbuff, 24)!=24) break; |
|
2239 |
+ src = nbuff; |
|
2242 | 2240 |
} |
2243 | 2241 |
|
2244 |
- if (memcmp(buff, "\x9c\x60\xe8\x00\x00\x00\x00\x5d\xb8\x07\x00\x00\x00", 13)) break; |
|
2242 |
+ if (memcmp(src, "\x9c\x60\xe8\x00\x00\x00\x00\x5d\xb8\x07\x00\x00\x00", 13)) break; |
|
2245 | 2243 |
|
2246 |
- nowinldr = 0x54-cli_readint32(buff+17); |
|
2244 |
+ nowinldr = 0x54-cli_readint32(src+17); |
|
2247 | 2245 |
cli_dbgmsg("NsPack: Found *start_of_stuff @delta-%x\n", nowinldr); |
2248 | 2246 |
|
2249 |
- if (lseek(desc, ep-nowinldr, SEEK_SET)==-1) break; |
|
2250 |
- if (cli_readn(desc, buff, 4)!=4) break; |
|
2251 |
- start_of_stuff=ep+cli_readint32(buff); |
|
2247 |
+ if (lseek(desc, rep-nowinldr, SEEK_SET)==-1) break; |
|
2248 |
+ if (cli_readn(desc, nbuff, 4)!=4) break; |
|
2249 |
+ start_of_stuff=rep+cli_readint32(nbuff); |
|
2252 | 2250 |
if (lseek(desc, start_of_stuff, SEEK_SET)==-1) break; |
2253 |
- if (cli_readn(desc, buff, 20)!=20) break; |
|
2254 |
- src = buff; |
|
2255 |
- if (!cli_readint32(buff)) { |
|
2251 |
+ if (cli_readn(desc, nbuff, 20)!=20) break; |
|
2252 |
+ src = nbuff; |
|
2253 |
+ if (!cli_readint32(nbuff)) { |
|
2256 | 2254 |
start_of_stuff+=4; /* FIXME: more to do */ |
2257 | 2255 |
src+=4; |
2258 | 2256 |
} |
... | ... |
@@ -2263,6 +2370,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2263 | 2263 |
if(ctx->limits && ctx->limits->maxfilesize && (ssize > ctx->limits->maxfilesize || dsize > ctx->limits->maxfilesize)) { |
2264 | 2264 |
cli_dbgmsg("NsPack: Size exceeded\n"); |
2265 | 2265 |
free(section_hdr); |
2266 |
+ free(exe_sections); |
|
2266 | 2267 |
if(BLOCKMAX) { |
2267 | 2268 |
*ctx->virname = "PE.NsPack.ExceededFileSize"; |
2268 | 2269 |
return CL_VIRUS; |
... | ... |
@@ -2271,7 +2379,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2271 | 2271 |
} |
2272 | 2272 |
} |
2273 | 2273 |
|
2274 |
- if ( !ssize || !dsize || dsize != (uint32_t)PESALIGN(EC32(section_hdr[0].VirtualSize), EC32(optional_hdr32.SectionAlignment))) break; |
|
2274 |
+ if ( !ssize || !dsize || dsize != exe_sections[0].vsz) break; |
|
2275 | 2275 |
if (lseek(desc, start_of_stuff, SEEK_SET)==-1) break; |
2276 | 2276 |
if (!(dest=cli_malloc(dsize))) break; |
2277 | 2277 |
/* memset(dest, 0xfc, dsize); */ |
... | ... |
@@ -2284,16 +2392,17 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2284 | 2284 |
cli_readn(desc, src, ssize); |
2285 | 2285 |
|
2286 | 2286 |
eprva+=0x27a; |
2287 |
- ep = cli_rawaddr(eprva, section_hdr, nsections, &err, EC32(optional_hdr32.SectionAlignment), EC32(optional_hdr32.FileAlignment)); |
|
2288 |
- if (lseek(desc, ep, SEEK_SET)==-1) break; |
|
2289 |
- if (cli_readn(desc, buff, 5)!=5) break; |
|
2290 |
- eprva=eprva+5+cli_readint32(buff+1); |
|
2287 |
+ if (!(rep = cli_rawaddr(eprva, exe_sections, nsections, &err, fsize)) && err) break; |
|
2288 |
+ if (lseek(desc, rep, SEEK_SET)==-1) break; |
|
2289 |
+ if (cli_readn(desc, nbuff, 5)!=5) break; |
|
2290 |
+ eprva=eprva+5+cli_readint32(nbuff+1); |
|
2291 | 2291 |
cli_dbgmsg("NsPack: OEP = %08x\n", eprva); |
2292 | 2292 |
|
2293 | 2293 |
if(!(tempfile = cli_gentemp(NULL))) { |
2294 | 2294 |
free(src); |
2295 | 2295 |
free(dest); |
2296 | 2296 |
free(section_hdr); |
2297 |
+ free(exe_sections); |
|
2297 | 2298 |
return CL_EMEM; |
2298 | 2299 |
} |
2299 | 2300 |
|
... | ... |
@@ -2303,10 +2412,11 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2303 | 2303 |
free(src); |
2304 | 2304 |
free(dest); |
2305 | 2305 |
free(section_hdr); |
2306 |
+ free(exe_sections); |
|
2306 | 2307 |
return CL_EIO; |
2307 | 2308 |
} |
2308 | 2309 |
|
2309 |
- if (!unspack(src, dest, ctx, EC32(section_hdr[0].VirtualAddress), EC32(optional_hdr32.ImageBase), eprva, ndesc)) { |
|
2310 |
+ if (!unspack(src, dest, ctx, exe_sections[0].rva, EC32(optional_hdr32.ImageBase), eprva, ndesc)) { |
|
2310 | 2311 |
free(src); |
2311 | 2312 |
free(dest); |
2312 | 2313 |
if (cli_leavetemps_flag) |
... | ... |
@@ -2318,6 +2428,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2318 | 2318 |
|
2319 | 2319 |
if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) { |
2320 | 2320 |
free(section_hdr); |
2321 |
+ free(exe_sections); |
|
2321 | 2322 |
close(ndesc); |
2322 | 2323 |
if(!cli_leavetemps_flag) unlink(tempfile); |
2323 | 2324 |
free(tempfile); |
... | ... |
@@ -2338,6 +2449,7 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
2338 | 2338 |
/* to be continued ... */ |
2339 | 2339 |
|
2340 | 2340 |
free(section_hdr); |
2341 |
+ free(exe_sections); |
|
2341 | 2342 |
return CL_CLEAN; |
2342 | 2343 |
} |
2343 | 2344 |
|
... | ... |
@@ -2345,18 +2457,32 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo) |
2345 | 2345 |
{ |
2346 | 2346 |
uint16_t e_magic; /* DOS signature ("MZ") */ |
2347 | 2347 |
uint32_t e_lfanew; /* address of new exe header */ |
2348 |
- uint32_t min = 0, max = 0; |
|
2348 |
+ /* Obsolete - see below |
|
2349 |
+ uint32_t min = 0, max = 0; |
|
2350 |
+ */ |
|
2349 | 2351 |
struct pe_image_file_hdr file_hdr; |
2350 |
- struct pe_image_optional_hdr32 optional_hdr32; |
|
2351 |
- struct pe_image_optional_hdr64 optional_hdr64; |
|
2352 |
+ union { |
|
2353 |
+ struct pe_image_optional_hdr64 opt64; |
|
2354 |
+ struct pe_image_optional_hdr32 opt32; |
|
2355 |
+ } pe_opt; |
|
2356 |
+ struct pe_image_optional_hdr64 optional_hdr64 = pe_opt.opt64; |
|
2357 |
+ struct pe_image_optional_hdr32 optional_hdr32 = pe_opt.opt32; |
|
2352 | 2358 |
struct pe_image_section_hdr *section_hdr; |
2353 | 2359 |
struct stat sb; |
2354 | 2360 |
int i; |
2355 | 2361 |
unsigned int err, pe_plus = 0; |
2356 |
- |
|
2362 |
+ uint32_t valign, falign; |
|
2363 |
+ size_t fsize; |
|
2357 | 2364 |
|
2358 | 2365 |
cli_dbgmsg("in cli_peheader\n"); |
2359 | 2366 |
|
2367 |
+ if(fstat(desc, &sb) == -1) { |
|
2368 |
+ cli_dbgmsg("fstat failed\n"); |
|
2369 |
+ return -1; |
|
2370 |
+ } |
|
2371 |
+ |
|
2372 |
+ fsize = sb.st_size; |
|
2373 |
+ |
|
2360 | 2374 |
if(cli_readn(desc, &e_magic, sizeof(e_magic)) != sizeof(e_magic)) { |
2361 | 2375 |
cli_dbgmsg("Can't read DOS signature\n"); |
2362 | 2376 |
return -1; |
... | ... |
@@ -2400,32 +2526,49 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo) |
2400 | 2400 |
|
2401 | 2401 |
peinfo->nsections = EC16(file_hdr.NumberOfSections); |
2402 | 2402 |
|
2403 |
- if(EC16(file_hdr.SizeOfOptionalHeader) != sizeof(struct pe_image_optional_hdr32)) { |
|
2404 |
- if(EC16(file_hdr.SizeOfOptionalHeader) == sizeof(struct pe_image_optional_hdr64)) { |
|
2405 |
- pe_plus = 1; |
|
2406 |
- } else { |
|
2407 |
- cli_dbgmsg("Incorrect value of SizeOfOptionalHeader\n"); |
|
2403 |
+ if (EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) { |
|
2404 |
+ cli_dbgmsg("SizeOfOptionalHeader too small\n"); |
|
2405 |
+ return -1; |
|
2406 |
+ } |
|
2407 |
+ |
|
2408 |
+ if(cli_readn(desc, &optional_hdr32, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) { |
|
2409 |
+ cli_dbgmsg("Can't read optional file header\n"); |
|
2410 |
+ return -1; |
|
2411 |
+ } |
|
2412 |
+ |
|
2413 |
+ if(EC32(optional_hdr64.Magic)==PE32P_SIGNATURE) { |
|
2414 |
+ if(EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr64)) { |
|
2415 |
+ cli_dbgmsg("Incorrect SizeOfOptionalHeader for PE32+\n"); |
|
2408 | 2416 |
return -1; |
2409 | 2417 |
} |
2418 |
+ pe_plus = 1; |
|
2410 | 2419 |
} |
2411 | 2420 |
|
2412 | 2421 |
if(!pe_plus) { /* PE */ |
2413 | 2422 |
cli_dbgmsg("File format: PE\n"); |
2414 | 2423 |
|
2415 | 2424 |
if(cli_readn(desc, &optional_hdr32, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) { |
2416 |
- cli_dbgmsg("Can't optional file header\n"); |
|
2425 |
+ cli_dbgmsg("Can't read optional file header\n"); |
|
2417 | 2426 |
return -1; |
2418 | 2427 |
} |
2419 | 2428 |
|
2420 |
- } else { /* PE+ */ |
|
2421 |
- cli_dbgmsg("File format: PE32+\n"); |
|
2429 |
+ if (EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr32)) { |
|
2430 |
+ /* Seek to the end of the long header */ |
|
2431 |
+ lseek(desc, (EC16(file_hdr.SizeOfOptionalHeader)-sizeof(struct pe_image_optional_hdr32)), SEEK_CUR); |
|
2432 |
+ } |
|
2422 | 2433 |
|
2423 |
- if(cli_readn(desc, &optional_hdr64, sizeof(struct pe_image_optional_hdr64)) != sizeof(struct pe_image_optional_hdr64)) { |
|
2424 |
- cli_dbgmsg("Can't optional file header\n"); |
|
2434 |
+ } else { /* PE+ */ |
|
2435 |
+ if(cli_readn(desc, &optional_hdr32 + 1, sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) { |
|
2436 |
+ cli_dbgmsg("Can't read optional file header\n"); |
|
2425 | 2437 |
return -1; |
2426 | 2438 |
} |
2439 |
+ |
|
2440 |
+ cli_dbgmsg("File format: PE32+\n"); |
|
2427 | 2441 |
} |
2428 | 2442 |
|
2443 |
+ valign = (pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment); |
|
2444 |
+ falign = (pe_plus)?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment); |
|
2445 |
+ |
|
2429 | 2446 |
peinfo->section = (struct cli_exe_section *) cli_calloc(peinfo->nsections, sizeof(struct cli_exe_section)); |
2430 | 2447 |
|
2431 | 2448 |
if(!peinfo->section) { |
... | ... |
@@ -2433,13 +2576,6 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo) |
2433 | 2433 |
return -1; |
2434 | 2434 |
} |
2435 | 2435 |
|
2436 |
- if(fstat(desc, &sb) == -1) { |
|
2437 |
- cli_dbgmsg("fstat failed\n"); |
|
2438 |
- free(peinfo->section); |
|
2439 |
- peinfo->section = NULL; |
|
2440 |
- return -1; |
|
2441 |
- } |
|
2442 |
- |
|
2443 | 2436 |
section_hdr = (struct pe_image_section_hdr *) cli_calloc(peinfo->nsections, sizeof(struct pe_image_section_hdr)); |
2444 | 2437 |
|
2445 | 2438 |
if(!section_hdr) { |
... | ... |
@@ -2460,14 +2596,18 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo) |
2460 | 2460 |
return -1; |
2461 | 2461 |
} |
2462 | 2462 |
|
2463 |
- peinfo->section[i].rva = EC32(section_hdr[i].VirtualAddress); |
|
2464 |
- peinfo->section[i].vsz = EC32(section_hdr[i].VirtualSize); |
|
2465 |
- peinfo->section[i].raw = EC32(section_hdr[i].PointerToRawData); |
|
2466 |
- peinfo->section[i].rsz = EC32(section_hdr[i].SizeOfRawData); |
|
2463 |
+ peinfo->section[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign); |
|
2464 |
+ peinfo->section[i].vsz = PESALIGN(EC32(section_hdr[i].VirtualSize), valign); |
|
2465 |
+ peinfo->section[i].raw = PEALIGN(EC32(section_hdr[i].PointerToRawData), falign); |
|
2466 |
+ peinfo->section[i].rsz = PESALIGN(EC32(section_hdr[i].SizeOfRawData), falign); |
|
2467 |
+ if (peinfo->section[i].rsz && !CLI_ISCONTAINED(0, (uint32_t) fsize, peinfo->section[i].raw, peinfo->section[i].rsz)) |
|
2468 |
+ peinfo->section[i].rsz = (fsize - peinfo->section[i].raw)*(fsize>peinfo->section[i].raw); |
|
2467 | 2469 |
|
2470 |
+ /* cli_rawaddr now handles the whole process space |
|
2471 |
+ * TO BE REMOVED |
|
2468 | 2472 |
if(!i) { |
2469 |
- min = EC32(section_hdr[i].VirtualAddress); |
|
2470 |
- max = EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData); |
|
2473 |
+ min = peinfo->section[i].rva; |
|
2474 |
+ max = peinfo->section[i].rva + peinfo->section[i].rsz; |
|
2471 | 2475 |
} else { |
2472 | 2476 |
if(EC32(section_hdr[i].VirtualAddress) < min) |
2473 | 2477 |
min = EC32(section_hdr[i].VirtualAddress); |
... | ... |
@@ -2475,6 +2615,7 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo) |
2475 | 2475 |
if(EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData) > max) |
2476 | 2476 |
max = EC32(section_hdr[i].VirtualAddress) + EC32(section_hdr[i].SizeOfRawData); |
2477 | 2477 |
} |
2478 |
+ */ |
|
2478 | 2479 |
} |
2479 | 2480 |
|
2480 | 2481 |
if(pe_plus) |
... | ... |
@@ -2482,12 +2623,16 @@ int cli_peheader(int desc, struct cli_exe_info *peinfo) |
2482 | 2482 |
else |
2483 | 2483 |
peinfo->ep = EC32(optional_hdr32.AddressOfEntryPoint); |
2484 | 2484 |
|
2485 |
- if(peinfo->ep >= min && !(peinfo->ep = cli_rawaddr(peinfo->ep, section_hdr, peinfo->nsections, &err, 0, 0)) && err) { |
|
2486 |
- cli_dbgmsg("Possibly broken PE file\n"); |
|
2485 |
+ if(!(peinfo->ep = cli_rawaddr(peinfo->ep, peinfo->section, peinfo->nsections, &err, fsize)) && err) { |
|
2486 |
+#ifdef ACAB_REGRESSION |
|
2487 |
+ peinfo->ep = 0x7fffffff; |
|
2488 |
+#else |
|
2489 |
+ cli_dbgmsg("Broken PE file\n"); |
|
2487 | 2490 |
free(section_hdr); |
2488 | 2491 |
free(peinfo->section); |
2489 | 2492 |
peinfo->section = NULL; |
2490 | 2493 |
return -1; |
2494 |
+#endif /* ACAB_REGRESSION */ |
|
2491 | 2495 |
} |
2492 | 2496 |
|
2493 | 2497 |
free(section_hdr); |
... | ... |
@@ -54,6 +54,7 @@ |
54 | 54 |
#include "cltypes.h" |
55 | 55 |
#include "pe.h" |
56 | 56 |
#include "rebuildpe.h" |
57 |
+#include "execs.h" |
|
57 | 58 |
#include "others.h" |
58 | 59 |
|
59 | 60 |
#define EC32(x) le32_to_host(x) /* Convert little endian to host */ |
... | ... |
@@ -81,7 +82,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_ |
81 | 81 |
char *packed = NULL; |
82 | 82 |
uint32_t thisrva=0, bottom = 0, enc_ep=0, irva=0, workdone=0, grown=0x355, skew=0x35; |
83 | 83 |
int j = 0, oob, mangled = 0, check4resources=0; |
84 |
- struct SECTION *usects = NULL; |
|
84 |
+ struct cli_exe_section *usects = NULL; |
|
85 | 85 |
void *tmpsct = NULL; |
86 | 86 |
|
87 | 87 |
/* |
... | ... |
@@ -111,7 +112,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_ |
111 | 111 |
if ( ! CLI_ISCONTAINED(buf, bufsz, packed, 4)) { |
112 | 112 |
if (usects) |
113 | 113 |
free(usects); |
114 |
- return -1; |
|
114 |
+ return 1; |
|
115 | 115 |
} |
116 | 116 |
srva = cli_readint32(packed); |
117 | 117 |
|
... | ... |
@@ -120,7 +121,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_ |
120 | 120 |
int t, upd = 1; |
121 | 121 |
|
122 | 122 |
if ( j <= 0 ) /* Some non petite compressed files will get here */ |
123 |
- return -1; |
|
123 |
+ return 1; |
|
124 | 124 |
|
125 | 125 |
/* Select * from sections order by rva asc; */ |
126 | 126 |
while ( upd ) { |
... | ... |
@@ -202,10 +203,12 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_ |
202 | 202 |
} else |
203 | 203 |
workdone = 1; |
204 | 204 |
enc_ep = pep+5+enc_ep; |
205 |
- if ( workdone == 1 ) |
|
205 |
+ if ( workdone == 1 ) { |
|
206 | 206 |
cli_dbgmsg("Petite: Old EP: %x\n", enc_ep); |
207 |
- else |
|
208 |
- cli_dbgmsg("Petite: In troubles while attempting to decrypt old EP\n"); |
|
207 |
+ } else { |
|
208 |
+ enc_ep = usects[0].rva; |
|
209 |
+ cli_dbgmsg("Petite: In troubles while attempting to decrypt old EP, using bogus %x\n", enc_ep); |
|
210 |
+ } |
|
209 | 211 |
} |
210 | 212 |
|
211 | 213 |
/* Let's compact data */ |
... | ... |
@@ -219,18 +222,13 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_ |
219 | 219 |
cli_dbgmsg("Petite: Sections dump:\n"); |
220 | 220 |
for (t = 0; t < j ; t++) |
221 | 221 |
cli_dbgmsg("Petite: .SECT%d RVA:%x VSize:%x ROffset: %x, RSize:% x\n", t, usects[t].rva, usects[t].vsz, usects[t].raw, usects[t].rsz); |
222 |
- if ( (ssrc = rebuildpe(buf, usects, j, Imagebase, enc_ep, ResRva, ResSize)) ) { |
|
223 |
- if (cli_writen(desc, ssrc, 0x148+0x80+0x28*j+usects[j-1].raw+usects[j-1].rsz)==-1) { |
|
224 |
- free(ssrc); |
|
225 |
- free(usects); |
|
226 |
- return -1; |
|
227 |
- } |
|
228 |
- free(ssrc); |
|
229 |
- } else |
|
222 |
+ if (! cli_rebuildpe(buf, usects, j, Imagebase, enc_ep, ResRva, ResSize, desc)) { |
|
230 | 223 |
cli_dbgmsg("Petite: Rebuilding failed\n"); |
231 |
- |
|
224 |
+ free(usects); |
|
225 |
+ return 1; |
|
226 |
+ } |
|
232 | 227 |
free(usects); |
233 |
- return workdone; |
|
228 |
+ return 0; |
|
234 | 229 |
} |
235 | 230 |
|
236 | 231 |
|
... | ... |
@@ -247,7 +245,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_ |
247 | 247 |
if ( ! CLI_ISCONTAINED(buf, bufsz, packed+4, 8) ) { |
248 | 248 |
if (usects) |
249 | 249 |
free(usects); |
250 |
- return -1; |
|
250 |
+ return 1; |
|
251 | 251 |
} |
252 | 252 |
/* Save the end of current packed section for later use */ |
253 | 253 |
bottom = cli_readint32(packed+8) + 4; |
... | ... |
@@ -257,7 +255,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_ |
257 | 257 |
if ( !CLI_ISCONTAINED(buf, bufsz, ssrc, size*4) || !CLI_ISCONTAINED(buf, bufsz, ddst, size*4) ) { |
258 | 258 |
if (usects) |
259 | 259 |
free(usects); |
260 |
- return -1; |
|
260 |
+ return 1; |
|
261 | 261 |
} |
262 | 262 |
|
263 | 263 |
/* Copy packed data to the end of the current packed section */ |
... | ... |
@@ -273,26 +271,26 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_ |
273 | 273 |
if ( ! CLI_ISCONTAINED(buf, bufsz, packed+4, 8)) { |
274 | 274 |
if (usects) |
275 | 275 |
free(usects); |
276 |
- return -1; |
|
276 |
+ return 1; |
|
277 | 277 |
} |
278 | 278 |
|
279 | 279 |
size = cli_readint32(packed+4); /* How many bytes to unpack */ |
280 | 280 |
thisrva=cli_readint32(packed+8); /* RVA of the original section */ |
281 | 281 |
packed += 0x10; |
282 | 282 |
|
283 |
- if ( j >= 99 ) { |
|
283 |
+ if ( j >= 96 ) { |
|
284 | 284 |
cli_dbgmsg("Petite: maximum number of sections exceeded, giving up.\n"); |
285 | 285 |
free(usects); |
286 |
- return -1; |
|
286 |
+ return 1; |
|
287 | 287 |
} |
288 | 288 |
/* Alloc 1 more struct */ |
289 |
- if ( ! (tmpsct = cli_realloc(usects, sizeof(struct SECTION) * (j+1))) ) { |
|
289 |
+ if ( ! (tmpsct = cli_realloc(usects, sizeof(struct cli_exe_section) * (j+1))) ) { |
|
290 | 290 |
if (usects) |
291 | 291 |
free(usects); |
292 |
- return -1; |
|
292 |
+ return 1; |
|
293 | 293 |
} |
294 | 294 |
|
295 |
- usects = (struct SECTION *) tmpsct; |
|
295 |
+ usects = (struct cli_exe_section *) tmpsct; |
|
296 | 296 |
/* Save section spex for later rebuilding */ |
297 | 297 |
usects[j].rva = thisrva; |
298 | 298 |
usects[j].rsz = size; |
... | ... |
@@ -352,7 +350,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_ |
352 | 352 |
|
353 | 353 |
if ( !CLI_ISCONTAINED(buf, bufsz, ssrc, 1) || !CLI_ISCONTAINED(buf, bufsz, ddst, 1)) { |
354 | 354 |
free(usects); |
355 |
- return -1; |
|
355 |
+ return 1; |
|
356 | 356 |
} |
357 | 357 |
|
358 | 358 |
size--; |
... | ... |
@@ -365,12 +363,12 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_ |
365 | 365 |
oob = doubledl(&ssrc, &mydl, buf, bufsz); |
366 | 366 |
if ( oob == -1 ) { |
367 | 367 |
free(usects); |
368 |
- return -1; |
|
368 |
+ return 1; |
|
369 | 369 |
} |
370 | 370 |
if (!oob) { |
371 | 371 |
if ( !CLI_ISCONTAINED(buf, bufsz, ssrc, 1) || !CLI_ISCONTAINED(buf, bufsz, ddst, 1) ) { |
372 | 372 |
free(usects); |
373 |
- return -1; |
|
373 |
+ return 1; |
|
374 | 374 |
} |
375 | 375 |
*ddst++ = (char)((*ssrc++)^(size & 0xff)); |
376 | 376 |
size--; |
... | ... |
@@ -380,12 +378,12 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_ |
380 | 380 |
while (1) { |
381 | 381 |
if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) { |
382 | 382 |
free(usects); |
383 |
- return -1; |
|
383 |
+ return 1; |
|
384 | 384 |
} |
385 | 385 |
backbytes = backbytes*2 + oob; |
386 | 386 |
if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) { |
387 | 387 |
free(usects); |
388 |
- return -1; |
|
388 |
+ return 1; |
|
389 | 389 |
} |
390 | 390 |
if (!oob) |
391 | 391 |
break; |
... | ... |
@@ -396,7 +394,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_ |
396 | 396 |
do { |
397 | 397 |
if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) { |
398 | 398 |
free(usects); |
399 |
- return -1; |
|
399 |
+ return 1; |
|
400 | 400 |
} |
401 | 401 |
backbytes = backbytes*2 + oob; |
402 | 402 |
backsize--; |
... | ... |
@@ -411,12 +409,12 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_ |
411 | 411 |
|
412 | 412 |
if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) { |
413 | 413 |
free(usects); |
414 |
- return -1; |
|
414 |
+ return 1; |
|
415 | 415 |
} |
416 | 416 |
backsize = backsize*2 + oob; |
417 | 417 |
if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) { |
418 | 418 |
free(usects); |
419 |
- return -1; |
|
419 |
+ return 1; |
|
420 | 420 |
} |
421 | 421 |
backsize = backsize*2 + oob; |
422 | 422 |
if (!backsize) { |
... | ... |
@@ -424,12 +422,12 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_ |
424 | 424 |
while (1) { |
425 | 425 |
if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) { |
426 | 426 |
free(usects); |
427 |
- return -1; |
|
427 |
+ return 1; |
|
428 | 428 |
} |
429 | 429 |
backsize = backsize*2 + oob; |
430 | 430 |
if ( (oob = doubledl(&ssrc, &mydl, buf, bufsz)) == -1 ) { |
431 | 431 |
free(usects); |
432 |
- return -1; |
|
432 |
+ return 1; |
|
433 | 433 |
} |
434 | 434 |
if (!oob) |
435 | 435 |
break; |
... | ... |
@@ -440,7 +438,7 @@ int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct pe_ |
440 | 440 |
size-=backsize; |
441 | 441 |
if(!CLI_ISCONTAINED(buf, bufsz, ddst, backsize) || !CLI_ISCONTAINED(buf, bufsz, ddst+backbytes, backsize)) { |
442 | 442 |
free(usects); |
443 |
- return -1; |
|
443 |
+ return 1; |
|
444 | 444 |
} |
445 | 445 |
while(backsize--) { |
446 | 446 |
*ddst=*(ddst+backbytes); |
... | ... |
@@ -31,7 +31,6 @@ |
31 | 31 |
** lookalike PE & Optional headers, an array of structures and |
32 | 32 |
** of course the real content. |
33 | 33 |
** Sections characteristics will have all the bits set. |
34 |
-** Raw alignment is a waste and therefore is not performed. |
|
35 | 34 |
*/ |
36 | 35 |
|
37 | 36 |
#if HAVE_CONFIG_H |
... | ... |
@@ -45,6 +44,9 @@ |
45 | 45 |
|
46 | 46 |
#define EC32(x) le32_to_host(x) /* Convert little endian to host */ |
47 | 47 |
#define EC16(x) le16_to_host(x) /* Convert little endian to host */ |
48 |
+#define PEALIGN(o,a) (((a))?(((o)/(a))*(a)):(o)) |
|
49 |
+#define PESALIGN(o,a) (((a))?(((o)/(a)+((o)%(a)!=0))*(a)):(o)) |
|
50 |
+ |
|
48 | 51 |
|
49 | 52 |
struct IMAGE_PE_HEADER { |
50 | 53 |
uint32_t Signature; |
... | ... |
@@ -115,27 +117,29 @@ struct IMAGE_PE_HEADER { |
115 | 115 |
\x00\x00\x00\x00\x10\x00\x00\x00\ |
116 | 116 |
" |
117 | 117 |
|
118 |
-char *rebuildpe(char *buffer, struct SECTION *sections, int sects, uint32_t base, uint32_t ep, uint32_t ResRva, uint32_t ResSize) |
|
118 |
+int cli_rebuildpe(char *buffer, struct cli_exe_section *sections, int sects, uint32_t base, uint32_t ep, uint32_t ResRva, uint32_t ResSize, int file) |
|
119 | 119 |
{ |
120 | 120 |
int i; |
121 | 121 |
uint32_t datasize=0, rawbase; |
122 | 122 |
char *pefile=NULL, *curpe; |
123 | 123 |
struct IMAGE_PE_HEADER *fakepe; |
124 | 124 |
|
125 |
- |
|
126 |
- if(sects > 90) |
|
127 |
- return NULL; |
|
125 |
+ if(sects > 96) |
|
126 |
+ return 0; |
|
128 | 127 |
|
129 | 128 |
for (i=0; i < sects; i++) |
130 |
- datasize+=sections[i].rsz; |
|
129 |
+ datasize+=PESALIGN(sections[i].rsz, 0x200); |
|
130 |
+ |
|
131 |
+ rawbase = PESALIGN(0x148+0x80+0x28*sects, 0x200); |
|
131 | 132 |
|
132 | 133 |
if(datasize > CLI_MAX_ALLOCATION) |
133 |
- return NULL; |
|
134 |
+ return 0; |
|
134 | 135 |
|
135 |
- rawbase = 0x148+0x80+0x28*sects; |
|
136 |
- if((pefile = (char *) cli_malloc(rawbase+datasize))) { |
|
136 |
+ if((pefile = (char *) cli_calloc(rawbase+datasize, 1))) { |
|
137 | 137 |
memcpy(pefile, HEADERS, 0x148); |
138 | 138 |
|
139 |
+ datasize = 0x1000; |
|
140 |
+ |
|
139 | 141 |
fakepe = (struct IMAGE_PE_HEADER *)(pefile+0xd0); |
140 | 142 |
fakepe->NumberOfSections = EC16(sects); |
141 | 143 |
fakepe->AddressOfEntryPoint = EC32(ep); |
... | ... |
@@ -150,17 +154,22 @@ char *rebuildpe(char *buffer, struct SECTION *sections, int sects, uint32_t base |
150 | 150 |
cli_writeint32(curpe+8, sections[i].vsz); |
151 | 151 |
cli_writeint32(curpe+12, sections[i].rva); |
152 | 152 |
cli_writeint32(curpe+16, sections[i].rsz); |
153 |
- cli_writeint32(curpe+20, sections[i].raw + rawbase); |
|
153 |
+ cli_writeint32(curpe+20, rawbase); |
|
154 | 154 |
cli_writeint32(curpe+24, 0); |
155 | 155 |
cli_writeint32(curpe+28, 0); |
156 | 156 |
cli_writeint32(curpe+32, 0); |
157 | 157 |
cli_writeint32(curpe+0x24, 0xffffffff); |
158 |
+ memcpy(pefile+rawbase, buffer+sections[i].raw, sections[i].rsz); |
|
159 |
+ rawbase+=PESALIGN(sections[i].rsz, 0x200); |
|
158 | 160 |
curpe+=40; |
161 |
+ datasize+=PESALIGN(sections[i].vsz, 0x1000); |
|
159 | 162 |
} |
160 |
- memcpy(curpe, buffer, datasize); |
|
163 |
+ fakepe->SizeOfImage = EC32(datasize); |
|
164 |
+ } else { |
|
165 |
+ return 0; |
|
161 | 166 |
} |
162 | 167 |
|
163 |
- return pefile; |
|
168 |
+ i = (cli_writen(file, pefile, rawbase)!=-1); |
|
169 |
+ free(pefile); |
|
170 |
+ return i; |
|
164 | 171 |
} |
165 |
- |
|
166 |
- |
... | ... |
@@ -21,14 +21,8 @@ |
21 | 21 |
#define __REBUILDPE_H |
22 | 22 |
|
23 | 23 |
#include "cltypes.h" |
24 |
+#include "execs.h" |
|
24 | 25 |
|
25 |
-struct SECTION { |
|
26 |
- uint32_t rva; |
|
27 |
- uint32_t vsz; |
|
28 |
- uint32_t raw; |
|
29 |
- uint32_t rsz; |
|
30 |
-}; |
|
31 |
- |
|
32 |
-char *rebuildpe(char *buffer, struct SECTION *sections, int sects, uint32_t base, uint32_t ep, uint32_t ResRva, uint32_t ResSize); |
|
26 |
+int cli_rebuildpe(char *, struct cli_exe_section *, int, uint32_t, uint32_t, uint32_t, uint32_t, int); |
|
33 | 27 |
|
34 | 28 |
#endif |
... | ... |
@@ -57,6 +57,7 @@ |
57 | 57 |
#include "cltypes.h" |
58 | 58 |
#include "pe.h" |
59 | 59 |
#include "rebuildpe.h" |
60 |
+#include "execs.h" |
|
60 | 61 |
#include "others.h" |
61 | 62 |
#include "packlibs.h" |
62 | 63 |
|
... | ... |
@@ -466,8 +467,8 @@ int unspin(char *src, int ssize, struct pe_image_section_hdr *sections, int sect |
466 | 466 |
bitmap=bitman; /* save as a free() bitmap */ |
467 | 467 |
|
468 | 468 |
if ( (ep = (char *) cli_malloc(blobsz)) != NULL ) { |
469 |
- struct SECTION *rebhlp; |
|
470 |
- if ( (rebhlp = (struct SECTION *) cli_malloc(sizeof(struct SECTION)*(sectcnt))) != NULL ) { |
|
469 |
+ struct cli_exe_section *rebhlp; |
|
470 |
+ if ( (rebhlp = (struct cli_exe_section *) cli_malloc(sizeof(struct cli_exe_section)*(sectcnt))) != NULL ) { |
|
471 | 471 |
char *to = ep; |
472 | 472 |
int retval = 0; |
473 | 473 |
|
... | ... |
@@ -483,13 +484,7 @@ int unspin(char *src, int ssize, struct pe_image_section_hdr *sections, int sect |
483 | 483 |
bitmap = bitmap >>1; |
484 | 484 |
} |
485 | 485 |
|
486 |
- if ( (to = rebuildpe(ep, rebhlp, sectcnt, 0x400000, 0x1000, 0, 0))) { /* can't be bothered fixing those values: the rebuilt exe is completely broken anyway. */ |
|
487 |
- if (cli_writen(desc, to, 0x148+0x80+0x28*j+rebhlp[j-1].raw+rebhlp[j-1].rsz)==-1) { |
|
488 |
- cli_dbgmsg("spin: Cannot write unpacked file\n"); |
|
489 |
- retval = 1; |
|
490 |
- } |
|
491 |
- free(to); |
|
492 |
- } else { |
|
486 |
+ 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. */ |
|
493 | 487 |
cli_dbgmsg("spin: Cannot write unpacked file\n"); |
494 | 488 |
retval = 1; |
495 | 489 |
} |
... | ... |
@@ -37,14 +37,6 @@ |
37 | 37 |
** (*) some versions or maybe only some samples |
38 | 38 |
*/ |
39 | 39 |
|
40 |
- |
|
41 |
-/* |
|
42 |
-** TODO: |
|
43 |
-** |
|
44 |
-** needs performance tests |
|
45 |
-** |
|
46 |
-*/ |
|
47 |
- |
|
48 | 40 |
#if HAVE_CONFIG_H |
49 | 41 |
#include "clamav-config.h" |
50 | 42 |
#endif |
... | ... |
@@ -64,9 +56,8 @@ |
64 | 64 |
|
65 | 65 |
#define EC32(x) le32_to_host(x) /* Convert little endian to host */ |
66 | 66 |
#define EC16(x) le16_to_host(x) |
67 |
-#define VAALIGN(s) (((s)/0x1000+((s)%0x1000!=0))*0x1000) |
|
68 | 67 |
|
69 |
-char *sudecrypt(int desc, size_t fsize, struct pe_image_section_hdr *section_hdr, uint16_t sects, char *buff, uint32_t bkey, uint32_t pkey, uint32_t e_lfanew) { |
|
68 |
+char *sudecrypt(int desc, size_t fsize, struct cli_exe_section *sections, uint16_t sects, char *buff, uint32_t bkey, uint32_t pkey, uint32_t e_lfanew) { |
|
70 | 69 |
char *file, *hunk; |
71 | 70 |
uint32_t va,sz,key; |
72 | 71 |
int i, j; |
... | ... |
@@ -110,8 +101,8 @@ char *sudecrypt(int desc, size_t fsize, struct pe_image_section_hdr *section_hdr |
110 | 110 |
if (!va) break; |
111 | 111 |
cli_dbgmsg("SUE: Hunk #%d RVA:%x size:%d\n", i, va, sz); |
112 | 112 |
for (j=0; j<sects; j++) { |
113 |
- if(!CLI_ISCONTAINED(EC32(section_hdr[j].VirtualAddress), EC32(section_hdr[j].SizeOfRawData), va, sz)) continue; |
|
114 |
- hunk=file+EC32(section_hdr[j].VirtualAddress)-va+EC32(section_hdr[j].PointerToRawData); |
|
113 |
+ if(!CLI_ISCONTAINED(sections[j].rva, sections[j].rsz, va, sz)) continue; |
|
114 |
+ hunk=file+sections[j].rva-va+sections[j].raw; |
|
115 | 115 |
while(sz>=4) { |
116 | 116 |
cli_writeint32(hunk, cli_readint32(hunk)^key); |
117 | 117 |
hunk+=4; |
... | ... |
@@ -24,7 +24,7 @@ |
24 | 24 |
#include "cltypes.h" |
25 | 25 |
#include "rebuildpe.h" |
26 | 26 |
|
27 |
-char *sudecrypt(int, size_t, struct pe_image_section_hdr *, uint16_t, char *, uint32_t, uint32_t, uint32_t); |
|
27 |
+char *sudecrypt(int, size_t, struct cli_exe_section *, uint16_t, char *, uint32_t, uint32_t, uint32_t); |
|
28 | 28 |
|
29 | 29 |
#endif |
30 | 30 |
#endif |
... | ... |
@@ -116,6 +116,7 @@ nsp1:00435A5A push 8000h |
116 | 116 |
#include "clamav.h" |
117 | 117 |
#include "others.h" |
118 | 118 |
#include "rebuildpe.h" |
119 |
+#include "execs.h" |
|
119 | 120 |
#include "unsp.h" |
120 | 121 |
|
121 | 122 |
|
... | ... |
@@ -126,7 +127,7 @@ uint32_t unspack(char *start_of_stuff, char *dest, cli_ctx *ctx, uint32_t rva, u |
126 | 126 |
uint16_t *table; |
127 | 127 |
char *dst = dest; |
128 | 128 |
char *src = start_of_stuff+0xd; |
129 |
- struct SECTION section; |
|
129 |
+ struct cli_exe_section section; |
|
130 | 130 |
|
131 | 131 |
if (c>=0xe1) return 1; |
132 | 132 |
|
... | ... |
@@ -162,14 +163,7 @@ uint32_t unspack(char *start_of_stuff, char *dest, cli_ctx *ctx, uint32_t rva, u |
162 | 162 |
section.rsz = dsize; |
163 | 163 |
section.vsz = dsize; |
164 | 164 |
section.rva = rva; |
165 |
- if ( (src = rebuildpe(dest, §ion, 1, base, ep, 0, 0)) ) { |
|
166 |
- if (cli_writen(file, src, 0x148+0x80+0x28+dsize)!=-1) { |
|
167 |
- free(src); |
|
168 |
- return 0; |
|
169 |
- } |
|
170 |
- free(src); |
|
171 |
- } |
|
172 |
- return 1; |
|
165 |
+ return !cli_rebuildpe(dest, §ion, 1, base, ep, 0, 0, file); |
|
173 | 166 |
} |
174 | 167 |
|
175 | 168 |
|
... | ... |
@@ -49,6 +49,9 @@ |
49 | 49 |
#include "cltypes.h" |
50 | 50 |
#include "others.h" |
51 | 51 |
|
52 |
+#define PEALIGN(o,a) (((a))?(((o)/(a))*(a)):(o)) |
|
53 |
+#define PESALIGN(o,a) (((a))?(((o)/(a)+((o)%(a)!=0))*(a)):(o)) |
|
54 |
+ |
|
52 | 55 |
#define HEADERS "\ |
53 | 56 |
\x4D\x5A\x90\x00\x02\x00\x00\x00\x04\x00\x0F\x00\xFF\xFF\x00\x00\ |
54 | 57 |
\xB0\x00\x00\x00\x00\x00\x00\x00\x40\x00\x1A\x00\x00\x00\x00\x00\ |
... | ... |
@@ -71,7 +74,7 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0 |
71 | 71 |
{ |
72 | 72 |
char *imports, *sections, *pehdr, *newbuf; |
73 | 73 |
int sectcnt, upd=1; |
74 |
- uint32_t realstuffsz; |
|
74 |
+ uint32_t realstuffsz, valign; |
|
75 | 75 |
uint32_t foffset=0xd0+0xf8; |
76 | 76 |
|
77 | 77 |
if((dst == NULL) || (src == NULL)) |
... | ... |
@@ -109,7 +112,7 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0 |
109 | 109 |
return 0; |
110 | 110 |
} |
111 | 111 |
|
112 |
- if (! cli_readint32(pehdr+0x38)) { |
|
112 |
+ if (!(valign=cli_readint32(pehdr+0x38))) { |
|
113 | 113 |
cli_dbgmsg("UPX: Cant align to a NULL bound - giving up rebuild\n"); |
114 | 114 |
return 0; |
115 | 115 |
} |
... | ... |
@@ -120,7 +123,7 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0 |
120 | 120 |
return 0; |
121 | 121 |
} |
122 | 122 |
|
123 |
- foffset+=0x28*sectcnt; |
|
123 |
+ foffset = PESALIGN(foffset+0x28*sectcnt, valign); |
|
124 | 124 |
|
125 | 125 |
if (!CLI_ISCONTAINED(dst, *dsize, sections, 0x28*sectcnt)) { |
126 | 126 |
cli_dbgmsg("UPX: Not enough space for all sects - giving up rebuild\n"); |
... | ... |
@@ -128,11 +131,8 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0 |
128 | 128 |
} |
129 | 129 |
|
130 | 130 |
for (upd = 0; upd <sectcnt ; upd++) { |
131 |
- uint32_t vsize=cli_readint32(sections+8)-1; |
|
132 |
- uint32_t rsize=cli_readint32(sections+16); |
|
133 |
- uint32_t urva=cli_readint32(sections+12); |
|
134 |
- |
|
135 |
- vsize=(((vsize/0x1000)+1)*0x1000); /* FIXME: get bounds from header */ |
|
131 |
+ uint32_t vsize=PESALIGN(cli_readint32(sections+8), valign); |
|
132 |
+ uint32_t urva=PEALIGN(cli_readint32(sections+12), valign); |
|
136 | 133 |
|
137 | 134 |
/* Within bounds ? */ |
138 | 135 |
if (!CLI_ISCONTAINED(upx0, realstuffsz, urva, vsize)) { |
... | ... |
@@ -140,28 +140,19 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0 |
140 | 140 |
return 0; |
141 | 141 |
} |
142 | 142 |
|
143 |
- /* Rsize -gt Vsize ? */ |
|
144 |
- if ( rsize > vsize ) { |
|
145 |
- cli_dbgmsg("UPX: Raw size for sect %d is greater than virtual (%x / %x) - giving up rebuild\n", upd, rsize, vsize); |
|
146 |
- return 0; |
|
147 |
- } |
|
148 |
- |
|
149 |
- /* Am i been fooled? There are better ways ;) */ |
|
150 |
- if ( rsize+4 < vsize && cli_readint32(dst+urva-upx0+rsize) ) { |
|
151 |
- cli_dbgmsg("UPX: Am i been fooled? - giving up rebuild\n", upd); |
|
152 |
- return 0; |
|
153 |
- } |
|
154 |
- |
|
155 | 143 |
cli_writeint32(sections+8, vsize); |
144 |
+ cli_writeint32(sections+12, urva); |
|
145 |
+ cli_writeint32(sections+16, vsize); |
|
156 | 146 |
cli_writeint32(sections+20, foffset); |
157 |
- foffset+=rsize; |
|
147 |
+ foffset+=vsize; |
|
158 | 148 |
|
159 | 149 |
sections+=0x28; |
160 | 150 |
} |
161 | 151 |
|
162 | 152 |
cli_writeint32(pehdr+8, 0x4d414c43); |
153 |
+ cli_writeint32(pehdr+0x3c, valign); |
|
163 | 154 |
|
164 |
- if (!(newbuf = (char *) cli_malloc(foffset))) { |
|
155 |
+ if (!(newbuf = (char *) cli_calloc(foffset, sizeof(char)))) { |
|
165 | 156 |
cli_dbgmsg("UPX: malloc failed - giving up rebuild\n", upd); |
166 | 157 |
return 0; |
167 | 158 |
} |
... | ... |
@@ -177,7 +168,7 @@ int pefromupx (char *src, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0 |
177 | 177 |
/* CBA restoring the imports they'll look different from the originals anyway... */ |
178 | 178 |
/* ...and yeap i miss the icon too :P */ |
179 | 179 |
|
180 |
- if (foffset > *dsize) { |
|
180 |
+ if (foffset > *dsize + 8192) { |
|
181 | 181 |
cli_dbgmsg("UPX: wrong raw size - giving up rebuild\n"); |
182 | 182 |
return 0; |
183 | 183 |
} |