mirror of
https://github.com/Cisco-Talos/clamav.git
synced 2025-10-19 10:23:17 +00:00
add support for FSG 1.33
git-svn: trunk@750
This commit is contained in:
parent
7d2998bfcb
commit
5eb34facd5
5 changed files with 298 additions and 8 deletions
|
@ -1,3 +1,7 @@
|
||||||
|
Sat Aug 14 12:50:07 CEST 2004 (tk)
|
||||||
|
----------------------------------
|
||||||
|
* libclamav: add support for FSG 1.33 (aCaB)
|
||||||
|
|
||||||
Fri Aug 13 11:22:02 BST 2004 (njh)
|
Fri Aug 13 11:22:02 BST 2004 (njh)
|
||||||
----------------------------------
|
----------------------------------
|
||||||
* clamav-milter: Single thread through the tcpwrappers code, thanks to
|
* clamav-milter: Single thread through the tcpwrappers code, thanks to
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
** 02/08/2k4 - Done coding
|
** 02/08/2k4 - Done coding
|
||||||
** 03/08/2k4 - Cleaning and securing
|
** 03/08/2k4 - Cleaning and securing
|
||||||
** 04/08/2k4 - Done porting
|
** 04/08/2k4 - Done porting
|
||||||
|
** 07/08/2k4 - Started adding support for 1.33
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -47,6 +48,20 @@
|
||||||
#include "rebuildpe.h"
|
#include "rebuildpe.h"
|
||||||
#include "others.h"
|
#include "others.h"
|
||||||
|
|
||||||
|
#if WORDS_BIGENDIAN == 0
|
||||||
|
#define EC16(v) (v)
|
||||||
|
#define EC32(v) (v)
|
||||||
|
#else
|
||||||
|
static inline uint16_t EC16(uint16_t v)
|
||||||
|
{
|
||||||
|
return ((v >> 8) + (v << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t EC32(uint32_t v)
|
||||||
|
{
|
||||||
|
return ((v >> 24) | ((v & 0x00FF0000) >> 8) | ((v & 0x0000FF00) << 8) | (v << 24));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int doubledl(char **scur, uint8_t *mydlptr, char *buffer, int buffersize)
|
static int doubledl(char **scur, uint8_t *mydlptr, char *buffer, int buffersize)
|
||||||
{
|
{
|
||||||
|
@ -65,7 +80,7 @@ static int doubledl(char **scur, uint8_t *mydlptr, char *buffer, int buffersize)
|
||||||
return (olddl>>7)&1;
|
return (olddl>>7)&1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int unfsg(char *source, char *dest, int ssize, int dsize) {
|
static int unfsg(char *source, char *dest, int ssize, int dsize, char **endsrc, char **enddst) {
|
||||||
uint8_t mydl=0x80;
|
uint8_t mydl=0x80;
|
||||||
uint32_t backbytes, backsize, oldback;
|
uint32_t backbytes, backsize, oldback;
|
||||||
char *csrc = source, *cdst = dest;
|
char *csrc = source, *cdst = dest;
|
||||||
|
@ -186,5 +201,75 @@ int unfsg(char *source, char *dest, int ssize, int dsize) {
|
||||||
lostbit=1;
|
lostbit=1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*endsrc = csrc;
|
||||||
|
*enddst = cdst;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int unfsg_200(char *source, char *dest, int ssize, int dsize) {
|
||||||
|
char *fake;
|
||||||
|
|
||||||
|
return unfsg(source, dest, ssize, dsize, &fake, &fake);
|
||||||
|
}
|
||||||
|
|
||||||
|
int unfsg_133(char *source, char *dest, int ssize, int dsize, struct SECTION *sections, int sectcount, uint32_t base, uint32_t ep, int file) {
|
||||||
|
char *tsrc=source, *tdst=dest;
|
||||||
|
int i, upd=1, offs=0, lastsz=dsize;
|
||||||
|
|
||||||
|
for (i = 0 ; i <= sectcount ; i++) {
|
||||||
|
char *startd=tdst;
|
||||||
|
if ( unfsg(tsrc, tdst, tsrc - source + ssize, tdst - dest + dsize, &tsrc, &tdst) == -1 )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* RVA has been filled already in pe.c */
|
||||||
|
sections[i].raw=offs;
|
||||||
|
sections[i].rsz=tdst-startd;
|
||||||
|
/* cli_dbgmsg("Unpacked section %d @%x size %x Vsize =%x \n", i, offs, tdst-startd, dsize - (startd - dest)); */
|
||||||
|
offs+=tdst-startd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sort out the sections */
|
||||||
|
while ( upd ) {
|
||||||
|
upd = 0;
|
||||||
|
for (i = 0; i < sectcount ; i++) {
|
||||||
|
uint32_t trva,trsz,traw;
|
||||||
|
|
||||||
|
if ( sections[i].rva < sections[i+1].rva )
|
||||||
|
continue;
|
||||||
|
trva = sections[i].rva;
|
||||||
|
traw = sections[i].raw;
|
||||||
|
trsz = sections[i].rsz;
|
||||||
|
sections[i].rva = sections[i+1].rva;
|
||||||
|
sections[i].rsz = sections[i+1].rsz;
|
||||||
|
sections[i].raw = sections[i+1].raw;
|
||||||
|
sections[i+1].rva = trva;
|
||||||
|
sections[i+1].raw = traw;
|
||||||
|
sections[i+1].rsz = trsz;
|
||||||
|
upd = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cure Vsizes and debugspam */
|
||||||
|
for (i = 0; i <= sectcount ; i++) {
|
||||||
|
if ( i != sectcount ) {
|
||||||
|
sections[i].vsz = sections[i+1].rva - sections[i].rva;
|
||||||
|
lastsz-= sections[i+1].rva - sections[i].rva;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sections[i].vsz = lastsz;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (tsrc = rebuildpe(dest, sections, sectcount+1, base, ep, 0, 0)) ) {
|
||||||
|
write(file, tsrc, 0x148+0x80+0x28*(sectcount+1)+offs);
|
||||||
|
free(tsrc);
|
||||||
|
} else {
|
||||||
|
free(tsrc);
|
||||||
|
cli_dbgmsg("FSG: Rebuilding failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
|
@ -20,9 +20,12 @@
|
||||||
#define __FSG_H
|
#define __FSG_H
|
||||||
|
|
||||||
#include "cltypes.h"
|
#include "cltypes.h"
|
||||||
#include "pe.h"
|
#include "rebuildpe.h"
|
||||||
|
|
||||||
int unfsg(char *, char *, int, int);
|
int unfsg_200(char *, char *, int, int);
|
||||||
|
int unfsg_133(char *, char *, int , int, struct SECTION *, int, uint32_t, uint32_t, int);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2004 Tomasz Kojm <tkojm@clamav.net>
|
* Copyright (C) 2004 Tomasz Kojm <tkojm@clamav.net>
|
||||||
*
|
*
|
||||||
|
* With additions from aCaB <acab@clamav.net>
|
||||||
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
@ -37,6 +39,7 @@
|
||||||
#include "petite.h"
|
#include "petite.h"
|
||||||
#include "fsg.h"
|
#include "fsg.h"
|
||||||
#include "scanners.h"
|
#include "scanners.h"
|
||||||
|
#include "rebuildpe.h"
|
||||||
|
|
||||||
#define IMAGE_DOS_SIGNATURE 0x5a4d /* MZ */
|
#define IMAGE_DOS_SIGNATURE 0x5a4d /* MZ */
|
||||||
#define IMAGE_DOS_SIGNATURE_OLD 0x4d5a /* ZM */
|
#define IMAGE_DOS_SIGNATURE_OLD 0x4d5a /* ZM */
|
||||||
|
@ -420,15 +423,15 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
|
||||||
return CL_EIO;
|
return CL_EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(read(desc, buff, 126) != 126) { /* i.e. 0x69 + 13 + 8 */
|
if(read(desc, buff, 168) != 168) {
|
||||||
cli_dbgmsg("UPX/FSG: Can't read 126 bytes at 0x%x (%d)\n", ep, ep);
|
cli_dbgmsg("UPX/FSG: Can't read 126 bytes at 0x%x (%d)\n", ep, ep);
|
||||||
free(section_hdr);
|
free(section_hdr);
|
||||||
return CL_EIO;
|
return CL_EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(buff[0]=='\x87' && buff [1]=='\x25') {
|
if(buff[0] == '\x87' && buff[1] == '\x25') {
|
||||||
|
|
||||||
/* FSG support - thanks to aCaB ! */
|
/* FSG v2.0 support - thanks to aCaB ! */
|
||||||
|
|
||||||
ssize = EC32(section_hdr[i + 1].SizeOfRawData);
|
ssize = EC32(section_hdr[i + 1].SizeOfRawData);
|
||||||
dsize = EC32(section_hdr[i].VirtualSize);
|
dsize = EC32(section_hdr[i].VirtualSize);
|
||||||
|
@ -516,7 +519,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
|
||||||
return CL_EMEM;
|
return CL_EMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(unfsg(newesi - EC32(section_hdr[i + 1].VirtualAddress) + src, dest, ssize, dsize) == -1) {
|
if(unfsg_200(newesi - EC32(section_hdr[i + 1].VirtualAddress) + src, dest, ssize + EC32(section_hdr[i + 1].VirtualAddress) - newesi, dsize) == -1) {
|
||||||
cli_dbgmsg("FSG: Unpacking failed\n");
|
cli_dbgmsg("FSG: Unpacking failed\n");
|
||||||
free(src);
|
free(src);
|
||||||
free(dest);
|
free(dest);
|
||||||
|
@ -529,6 +532,197 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(found && buff[0] == '\xbe' && cli_readint32(buff + 1) - EC32(optional_hdr.ImageBase) < min) {
|
||||||
|
|
||||||
|
/* FSG support - v. 1.33 (thx trog for the many samples) */
|
||||||
|
|
||||||
|
ssize = EC32(section_hdr[i + 1].SizeOfRawData);
|
||||||
|
dsize = EC32(section_hdr[i].VirtualSize);
|
||||||
|
|
||||||
|
while(found) {
|
||||||
|
int gp, t, sectcnt = 0;
|
||||||
|
char *support;
|
||||||
|
uint32_t newesi, newedi, newebx, oldep;
|
||||||
|
struct SECTION *sections;
|
||||||
|
|
||||||
|
|
||||||
|
if(limits && limits->maxfilesize && (ssize > limits->maxfilesize || dsize > limits->maxfilesize)) {
|
||||||
|
cli_dbgmsg("FSG: Sizes exceeded (ssize: %d, dsize: %d, max: %lu)\n", ssize, dsize, limits->maxfilesize);
|
||||||
|
free(section_hdr);
|
||||||
|
return CL_CLEAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ssize <= 0x19 || dsize <= ssize) {
|
||||||
|
cli_dbgmsg("FSG: Size mismatch (ssize: %d, dsize: %d)\n", ssize, dsize);
|
||||||
|
free(section_hdr);
|
||||||
|
return CL_CLEAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((gp = cli_readint32(buff + 1) - EC32(optional_hdr.ImageBase)) >= EC32(section_hdr[i + 1].PointerToRawData) || gp < 0) {
|
||||||
|
cli_dbgmsg("FSG: Support data out of padding area (newedi: %d, vaddr: %d)\n", newedi, EC32(section_hdr[i].VirtualAddress));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(limits && limits->maxfilesize && gp > limits->maxfilesize) {
|
||||||
|
cli_dbgmsg("FSG: Buffer size exceeded (size: %d, max: %lu)\n", gp, limits->maxfilesize);
|
||||||
|
free(section_hdr);
|
||||||
|
return CL_CLEAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((support = (char *) cli_malloc(gp)) == NULL) {
|
||||||
|
free(section_hdr);
|
||||||
|
return CL_EMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
lseek(desc, gp, SEEK_SET);
|
||||||
|
gp = EC32(section_hdr[i + 1].PointerToRawData) - gp;
|
||||||
|
|
||||||
|
if(read(desc, support, gp) != gp) {
|
||||||
|
cli_dbgmsg("Can't read %d bytes from padding area\n", gp);
|
||||||
|
free(section_hdr);
|
||||||
|
free(support);
|
||||||
|
return CL_EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
newebx = cli_readint32(support) - EC32(optional_hdr.ImageBase); /* Unused */
|
||||||
|
newedi = cli_readint32(support + 4) - EC32(optional_hdr.ImageBase); /* 1st dest */
|
||||||
|
newesi = cli_readint32(support + 8) - EC32(optional_hdr.ImageBase); /* Source */
|
||||||
|
|
||||||
|
if(newesi < EC32(section_hdr[i + 1].VirtualAddress || newesi >= EC32(section_hdr[i + 1].VirtualAddress) + EC32(section_hdr[i + 1].SizeOfRawData))) {
|
||||||
|
cli_dbgmsg("FSG: Source buffer out of section bounds\n");
|
||||||
|
free(support);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(newedi != EC32(section_hdr[i].VirtualAddress)) {
|
||||||
|
cli_dbgmsg("FSG: Bad destination (is %x should be %x)\n", newedi, EC32(section_hdr[i].VirtualAddress));
|
||||||
|
free(support);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Counting original sections */
|
||||||
|
for(t = 12; t < gp - 4; t += 4) {
|
||||||
|
uint32_t rva = cli_readint32(support+t);
|
||||||
|
|
||||||
|
if(!rva)
|
||||||
|
break;
|
||||||
|
|
||||||
|
rva -= EC32(optional_hdr.ImageBase)+1;
|
||||||
|
sectcnt++;
|
||||||
|
|
||||||
|
if(rva % 0x1000)
|
||||||
|
/* FIXME: really need to bother? */
|
||||||
|
cli_dbgmsg("FSG: Original section %d is misaligned\n", sectcnt);
|
||||||
|
|
||||||
|
if(rva < EC32(section_hdr[i].VirtualAddress) || rva >= EC32(section_hdr[i].VirtualAddress)+EC32(section_hdr[i].VirtualSize)) {
|
||||||
|
cli_dbgmsg("FSG: Original section %d is out of bounds\n", sectcnt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!sectcnt || t >= gp - 4 || cli_readint32(support + t)) {
|
||||||
|
free(support);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((sections = (struct SECTION *) cli_malloc((sectcnt + 1) * sizeof(struct SECTION))) == NULL) {
|
||||||
|
free(section_hdr);
|
||||||
|
free(support);
|
||||||
|
return CL_EMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
sections[0].rva = newedi;
|
||||||
|
for(t = 1; t <= sectcnt; t++)
|
||||||
|
sections[t].rva = cli_readint32(support + 8 + t * 4) - 1 -EC32(optional_hdr.ImageBase);
|
||||||
|
|
||||||
|
free(support);
|
||||||
|
|
||||||
|
if((src = (char *) cli_malloc(ssize)) == NULL) {
|
||||||
|
free(section_hdr);
|
||||||
|
free(sections);
|
||||||
|
return CL_EMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
lseek(desc, EC32(section_hdr[i + 1].PointerToRawData), SEEK_SET);
|
||||||
|
if(read(desc, src, ssize) != ssize) {
|
||||||
|
cli_dbgmsg("Can't read raw data of section %d\n", i);
|
||||||
|
free(section_hdr);
|
||||||
|
free(sections);
|
||||||
|
free(src);
|
||||||
|
return CL_EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((dest = (char *) cli_calloc(dsize, sizeof(char))) == NULL) {
|
||||||
|
free(section_hdr);
|
||||||
|
free(src);
|
||||||
|
free(sections);
|
||||||
|
return CL_EMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
oldep = EC32(optional_hdr.AddressOfEntryPoint) + 161 + 6 + cli_readint32(buff+163);
|
||||||
|
cli_dbgmsg("FSG: found old EP @%x\n", oldep);
|
||||||
|
|
||||||
|
tempfile = cli_gentemp(NULL);
|
||||||
|
if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC, S_IRWXU)) < 0) {
|
||||||
|
cli_dbgmsg("FSG: Can't create file %s\n", tempfile);
|
||||||
|
free(tempfile);
|
||||||
|
free(section_hdr);
|
||||||
|
free(src);
|
||||||
|
free(dest);
|
||||||
|
free(sections);
|
||||||
|
return CL_EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_hdr.ImageBase), oldep, ndesc)) {
|
||||||
|
case 1: /* Everything OK */
|
||||||
|
cli_dbgmsg("FSG: Unpacked and rebuilt executable saved in %s\n", tempfile);
|
||||||
|
free(src);
|
||||||
|
free(dest);
|
||||||
|
free(sections);
|
||||||
|
fsync(ndesc);
|
||||||
|
lseek(ndesc, 0, SEEK_SET);
|
||||||
|
|
||||||
|
if(cli_magic_scandesc(ndesc, virname, scanned, root, limits, options, arec, mrec) == CL_VIRUS) {
|
||||||
|
free(section_hdr);
|
||||||
|
close(ndesc);
|
||||||
|
if(!cli_leavetemps_flag)
|
||||||
|
unlink(tempfile);
|
||||||
|
free(tempfile);
|
||||||
|
return CL_VIRUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(ndesc);
|
||||||
|
if(!cli_leavetemps_flag)
|
||||||
|
unlink(tempfile);
|
||||||
|
free(tempfile);
|
||||||
|
free(section_hdr);
|
||||||
|
return CL_CLEAN;
|
||||||
|
|
||||||
|
case 0: /* We've got an unpacked buffer, no exe though */
|
||||||
|
cli_dbgmsg("FSG: FSG: Successfully decompressed\n");
|
||||||
|
close(ndesc);
|
||||||
|
unlink(tempfile);
|
||||||
|
free(tempfile);
|
||||||
|
free(sections);
|
||||||
|
found = 0;
|
||||||
|
upx_success = 1;
|
||||||
|
break; /* Go and scan the buffer! */
|
||||||
|
|
||||||
|
default: /* Everything gone wrong */
|
||||||
|
cli_dbgmsg("FSG: Unpacking failed\n");
|
||||||
|
close(ndesc);
|
||||||
|
unlink(tempfile); // It's empty anyway
|
||||||
|
free(tempfile);
|
||||||
|
free(src);
|
||||||
|
free(dest);
|
||||||
|
free(sections);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break; /* were done with 1.33 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(found) {
|
if(found) {
|
||||||
|
|
||||||
/* UPX support */
|
/* UPX support */
|
||||||
|
@ -709,6 +903,7 @@ int cli_scanpe(int desc, const char **virname, long int *scanned, const struct c
|
||||||
|
|
||||||
lseek(desc, ep, SEEK_SET);
|
lseek(desc, ep, SEEK_SET);
|
||||||
if(read(desc, buff, 200) != 200) {
|
if(read(desc, buff, 200) != 200) {
|
||||||
|
cli_dbgmsg("Can't read 200 bytes\n");
|
||||||
free(section_hdr);
|
free(section_hdr);
|
||||||
return CL_EIO;
|
return CL_EIO;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
** rebuildpe.c
|
** rebuildpe.c
|
||||||
**
|
**
|
||||||
** 28/07/2k4 - Moved out of petitep.c
|
** 28/07/2k4 - Moved out of petitep.c
|
||||||
|
** 08/08/2k4 - Fixed typo for sects characteristics
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -161,7 +162,7 @@ char *rebuildpe(char *buffer, struct SECTION *sections, int sects, uint32_t base
|
||||||
cli_writeint32(curpe+24, 0);
|
cli_writeint32(curpe+24, 0);
|
||||||
cli_writeint32(curpe+28, 0);
|
cli_writeint32(curpe+28, 0);
|
||||||
cli_writeint32(curpe+32, 0);
|
cli_writeint32(curpe+32, 0);
|
||||||
cli_writeint32(curpe+24, 0xffffffff);
|
cli_writeint32(curpe+0x24, 0xffffffff);
|
||||||
curpe+=40;
|
curpe+=40;
|
||||||
}
|
}
|
||||||
memcpy(curpe, buffer, datasize);
|
memcpy(curpe, buffer, datasize);
|
||||||
|
@ -169,3 +170,5 @@ char *rebuildpe(char *buffer, struct SECTION *sections, int sects, uint32_t base
|
||||||
|
|
||||||
return pefile;
|
return pefile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue