2004-05-11 23:30:57 +00:00
/*
2008-04-02 15:24:51 +00:00
* Copyright ( C ) 2007 - 2008 Sourcefire , Inc .
*
* Authors : Alberto Wu , Tomasz Kojm
2004-08-14 10:56:23 +00:00
*
2004-05-11 23:30:57 +00:00
* This program is free software ; you can redistribute it and / or modify
2008-04-02 15:24:51 +00:00
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
2004-05-11 23:30:57 +00:00
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
2006-04-09 19:59:28 +00:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston ,
* MA 02110 - 1301 , USA .
2004-05-11 23:30:57 +00:00
*/
# if HAVE_CONFIG_H
# include "clamav-config.h"
# endif
2008-12-02 19:55:57 +00:00
# define _XOPEN_SOURCE 500
2004-05-11 23:30:57 +00:00
# include <stdio.h>
2007-12-13 19:45:38 +00:00
# if HAVE_STRING_H
2004-05-11 23:30:57 +00:00
# include <string.h>
2007-12-13 19:45:38 +00:00
# endif
2004-05-11 23:30:57 +00:00
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
2006-08-11 18:30:35 +00:00
# ifdef HAVE_UNISTD_H
2004-05-11 23:30:57 +00:00
# include <unistd.h>
2006-08-11 18:30:35 +00:00
# endif
2004-05-11 23:30:57 +00:00
# include <time.h>
2007-09-04 00:38:30 +00:00
# include <stdarg.h>
2004-05-11 23:30:57 +00:00
# include "cltypes.h"
# include "clamav.h"
# include "others.h"
2004-08-02 17:09:06 +00:00
# include "pe.h"
# include "petite.h"
2004-08-05 01:15:59 +00:00
# include "fsg.h"
2005-08-05 00:59:37 +00:00
# include "spin.h"
2006-01-14 13:58:35 +00:00
# include "upx.h"
# include "yc.h"
2007-06-17 20:55:02 +00:00
# include "aspack.h"
2006-07-16 19:49:42 +00:00
# include "wwunpack.h"
2006-10-25 02:35:25 +00:00
# include "unsp.h"
2004-08-02 17:09:06 +00:00
# include "scanners.h"
2005-01-16 05:38:06 +00:00
# include "str.h"
2005-09-18 23:19:28 +00:00
# include "execs.h"
2006-09-27 00:36:11 +00:00
# include "md5.h"
2007-01-12 17:53:44 +00:00
# include "mew.h"
2007-01-13 14:40:59 +00:00
# include "upack.h"
2007-04-30 14:12:38 +00:00
# include "matcher.h"
# include "matcher-bm.h"
2008-07-28 13:23:12 +00:00
# include "disasm.h"
2008-12-02 19:55:57 +00:00
# include "special.h"
2009-07-14 09:36:36 +02:00
# include "ishield.h"
2009-11-11 03:58:22 +01:00
# include "pe_icons.h"
2004-05-11 23:30:57 +00:00
2007-01-09 20:06:51 +00:00
# define DCONF ctx->dconf->pe
2009-10-31 19:12:50 +01:00
# define PE_IMAGE_DOS_SIGNATURE 0x5a4d /* MZ */
# define PE_IMAGE_DOS_SIGNATURE_OLD 0x4d5a /* ZM */
# define PE_IMAGE_NT_SIGNATURE 0x00004550
2005-11-26 22:39:01 +00:00
# define PE32_SIGNATURE 0x010b
# define PE32P_SIGNATURE 0x020b
2004-05-11 23:30:57 +00:00
2006-12-04 18:05:16 +00:00
# define optional_hdr64 pe_opt.opt64
# define optional_hdr32 pe_opt.opt32
2004-07-07 00:21:04 +00:00
# define UPX_NRV2B "\x11\xdb\x11\xc9\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9\x11\xc9\x75\x20\x41\x01\xdb"
# define UPX_NRV2D "\x83\xf0\xff\x74\x78\xd1\xf8\x89\xc5\xeb\x0b\x01\xdb\x75\x07\x8b\x1e\x83\xee\xfc\x11\xdb\x11\xc9"
# define UPX_NRV2E "\xeb\x52\x31\xc9\x83\xe8\x03\x72\x11\xc1\xe0\x08\x8a\x06\x46\x83\xf0\xff\x74\x75\xd1\xf8\x89\xc5"
2008-07-31 02:17:25 +00:00
# define UPX_LZMA1 "\x56\x83\xc3\x04\x53\x50\xc7\x03\x03\x00\x02\x00\x90\x90\x90\x55\x57\x56\x53\x83"
# define UPX_LZMA2 "\x56\x83\xc3\x04\x53\x50\xc7\x03\x03\x00\x02\x00\x90\x90\x90\x90\x90\x55\x57\x56"
2004-06-12 00:16:01 +00:00
2006-04-07 23:31:41 +00:00
# define EC32(x) le32_to_host(x) /* Convert little endian to host */
# define EC16(x) le16_to_host(x)
2006-10-25 02:35:25 +00:00
/* lower and upper bondary alignment (size vs offset) */
# define PEALIGN(o,a) (((a))?(((o) / (a))*(a)):(o))
# define PESALIGN(o,a) (((a))?(((o) / (a)+((o)%(a)!=0))*(a)):(o))
2004-07-05 23:50:55 +00:00
2007-09-04 00:38:30 +00:00
# define CLI_UNPSIZELIMITS(NAME,CHK) \
2008-02-08 01:57:50 +00:00
if ( cli_checklimits ( NAME , ctx , ( CHK ) , 0 , 0 ) ! = CL_CLEAN ) { \
free ( exe_sections ) ; \
return CL_CLEAN ; \
2007-09-04 00:38:30 +00:00
}
2007-09-20 23:21:01 +00:00
# define CLI_UNPTEMP(NAME,FREEME) \
2008-11-14 22:23:39 +00:00
if ( ! ( tempfile = cli_gentemp ( ctx - > engine - > tmpdir ) ) ) { \
2007-09-20 23:21:01 +00:00
cli_multifree FREEME ; \
2007-09-04 00:38:30 +00:00
return CL_EMEM ; \
} \
if ( ( ndesc = open ( tempfile , O_RDWR | O_CREAT | O_TRUNC | O_BINARY , S_IRWXU ) ) < 0 ) { \
cli_dbgmsg ( NAME " : Can't create file %s \n " , tempfile ) ; \
2007-09-20 23:21:01 +00:00
free ( tempfile ) ; \
cli_multifree FREEME ; \
2009-02-12 13:53:23 +00:00
return CL_ECREAT ; \
2007-09-04 00:38:30 +00:00
}
2008-11-14 22:23:39 +00:00
# define CLI_TMPUNLK() if(!ctx->engine->keeptmp) { \
2008-04-08 17:45:05 +00:00
if ( cli_unlink ( tempfile ) ) { \
free ( tempfile ) ; \
2009-02-12 13:53:23 +00:00
return CL_EUNLINK ; \
2008-04-08 17:45:05 +00:00
} \
}
2007-09-04 00:38:30 +00:00
# define FSGCASE(NAME,FREESEC) \
case 0 : /* Unpacked and NOT rebuilt */ \
cli_dbgmsg ( NAME " : Successfully decompressed \n " ) ; \
close ( ndesc ) ; \
2008-04-08 17:45:05 +00:00
if ( cli_unlink ( tempfile ) ) { \
free ( exe_sections ) ; \
free ( tempfile ) ; \
FREESEC ; \
2009-02-12 13:53:23 +00:00
return CL_EUNLINK ; \
2008-04-08 17:45:05 +00:00
} \
2007-09-04 00:38:30 +00:00
free ( tempfile ) ; \
FREESEC ; \
found = 0 ; \
upx_success = 1 ; \
break ; /* FSG ONLY! - scan raw data after upx block */
# define SPINCASE() \
case 2 : \
free ( spinned ) ; \
close ( ndesc ) ; \
2008-04-08 17:45:05 +00:00
if ( cli_unlink ( tempfile ) ) { \
free ( exe_sections ) ; \
free ( tempfile ) ; \
2009-02-12 13:53:23 +00:00
return CL_EUNLINK ; \
2008-04-08 17:45:05 +00:00
} \
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " PESpin: Size exceeded \n " ) ; \
free ( tempfile ) ; \
break ; \
2007-09-20 23:21:01 +00:00
# define CLI_UNPRESULTS_(NAME,FSGSTUFF,EXPR,GOOD,FREEME) \
2007-09-04 00:38:30 +00:00
switch ( EXPR ) { \
case GOOD : /* Unpacked and rebuilt */ \
2008-11-14 22:23:39 +00:00
if ( ctx - > engine - > keeptmp ) \
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( NAME " : Unpacked and rebuilt executable saved in %s \n " , tempfile ) ; \
else \
cli_dbgmsg ( NAME " : Unpacked and rebuilt executable \n " ) ; \
2007-09-20 23:21:01 +00:00
cli_multifree FREEME ; \
free ( exe_sections ) ; \
2007-09-04 00:38:30 +00:00
lseek ( ndesc , 0 , SEEK_SET ) ; \
cli_dbgmsg ( " ***** Scanning rebuilt PE file ***** \n " ) ; \
if ( cli_magic_scandesc ( ndesc , ctx ) = = CL_VIRUS ) { \
close ( ndesc ) ; \
CLI_TMPUNLK ( ) ; \
free ( tempfile ) ; \
return CL_VIRUS ; \
} \
close ( ndesc ) ; \
CLI_TMPUNLK ( ) ; \
free ( tempfile ) ; \
return CL_CLEAN ; \
\
2007-09-20 23:21:01 +00:00
FSGSTUFF ; \
2007-09-04 00:38:30 +00:00
\
default : \
cli_dbgmsg ( NAME " : Unpacking failed \n " ) ; \
close ( ndesc ) ; \
2008-04-08 17:45:05 +00:00
if ( cli_unlink ( tempfile ) ) { \
free ( exe_sections ) ; \
free ( tempfile ) ; \
cli_multifree FREEME ; \
2009-02-12 13:53:23 +00:00
return CL_EUNLINK ; \
2008-04-08 17:45:05 +00:00
} \
2007-09-20 23:21:01 +00:00
cli_multifree FREEME ; \
free ( tempfile ) ; \
2007-09-04 00:38:30 +00:00
}
2008-11-06 22:49:53 +00:00
# define CLI_UNPRESULTS(NAME,EXPR,GOOD,FREEME) CLI_UNPRESULTS_(NAME,(void)0,EXPR,GOOD,FREEME)
2007-09-20 23:21:01 +00:00
# define CLI_UNPRESULTSFSG1(NAME,EXPR,GOOD,FREEME) CLI_UNPRESULTS_(NAME,FSGCASE(NAME,free(sections)),EXPR,GOOD,FREEME)
2008-11-06 22:49:53 +00:00
# define CLI_UNPRESULTSFSG2(NAME,EXPR,GOOD,FREEME) CLI_UNPRESULTS_(NAME,FSGCASE(NAME,(void)0),EXPR,GOOD,FREEME)
2004-07-05 23:50:55 +00:00
2006-05-01 18:32:13 +00:00
struct offset_list {
uint32_t offset ;
struct offset_list * next ;
} ;
2007-09-04 00:38:30 +00:00
static void cli_multifree ( void * f , . . . ) {
void * ff ;
va_list ap ;
free ( f ) ;
va_start ( ap , f ) ;
while ( ( ff = va_arg ( ap , void * ) ) ) free ( ff ) ;
va_end ( ap ) ;
}
2010-01-05 01:01:48 +01:00
struct vinfo_list {
uint32_t rvas [ 16 ] ;
unsigned int count ;
} ;
int versioninfo_cb ( void * opaque , uint32_t type , uint32_t name , uint32_t lang , uint32_t rva ) {
struct vinfo_list * vlist = ( struct vinfo_list * ) opaque ;
2010-01-05 02:04:14 +01:00
cli_dbgmsg ( " versioninfo_cb: type: %x, name: %x, lang: %x, rva: %x \n " , type , name , lang , rva ) ;
2010-01-05 01:01:48 +01:00
vlist - > rvas [ vlist - > count ] = rva ;
if ( + + vlist - > count = = sizeof ( vlist - > rvas ) / sizeof ( vlist - > rvas [ 0 ] ) )
return 1 ;
2009-12-22 04:16:30 +01:00
return 0 ;
}
2009-11-11 03:58:22 +01:00
uint32_t cli_rawaddr ( uint32_t rva , struct cli_exe_section * shp , uint16_t nos , unsigned int * err , size_t fsize , uint32_t hdr_size )
2004-06-11 20:17:18 +00:00
{
2007-09-04 00:38:30 +00:00
int i , found = 0 ;
uint32_t ret ;
2004-06-11 20:17:18 +00:00
2007-03-14 22:26:54 +00:00
if ( rva < hdr_size ) { /* Out of section EP - mapped to imagebase+rva */
2007-09-04 00:38:30 +00:00
if ( rva > = fsize ) {
2006-11-26 22:23:11 +00:00
* err = 1 ;
return 0 ;
}
* err = 0 ;
return rva ;
}
2004-06-11 20:17:18 +00:00
2006-11-26 22:23:11 +00:00
for ( i = nos - 1 ; i > = 0 ; i - - ) {
if ( shp [ i ] . rsz & & shp [ i ] . rva < = rva & & shp [ i ] . rsz > rva - shp [ i ] . rva ) {
2004-06-11 20:17:18 +00:00
found = 1 ;
break ;
}
}
if ( ! found ) {
2005-03-18 21:06:25 +00:00
* err = 1 ;
return 0 ;
2004-06-11 20:17:18 +00:00
}
2006-11-26 22:23:11 +00:00
ret = rva - shp [ i ] . rva + shp [ i ] . raw ;
2005-03-18 21:06:25 +00:00
* err = 0 ;
2006-11-26 22:23:11 +00:00
return ret ;
2004-06-11 20:17:18 +00:00
}
2006-06-29 18:43:35 +00:00
2005-03-18 21:06:25 +00:00
/*
2007-09-04 00:38:30 +00:00
static int cli_ddump ( int desc , int offset , int size , const char * file ) {
2004-05-27 20:15:37 +00:00
int pos , ndesc , bread , sum = 0 ;
char buff [ FILEBUFF ] ;
cli_dbgmsg ( " in ddump() \n " ) ;
if ( ( pos = lseek ( desc , 0 , SEEK_CUR ) ) = = - 1 ) {
cli_dbgmsg ( " Invalid descriptor \n " ) ;
2004-07-05 23:50:55 +00:00
return - 1 ;
2004-05-27 20:15:37 +00:00
}
if ( lseek ( desc , offset , SEEK_SET ) = = - 1 ) {
cli_dbgmsg ( " lseek() failed \n " ) ;
lseek ( desc , pos , SEEK_SET ) ;
2004-07-05 23:50:55 +00:00
return - 1 ;
2004-05-27 20:15:37 +00:00
}
2006-08-31 13:50:25 +00:00
if ( ( ndesc = open ( file , O_WRONLY | O_CREAT | O_TRUNC | O_BINARY , S_IRWXU ) ) < 0 ) {
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Can't create file %s \n " , file ) ;
lseek ( desc , pos , SEEK_SET ) ;
2004-07-05 23:50:55 +00:00
return - 1 ;
2004-05-27 20:15:37 +00:00
}
2006-07-31 11:03:20 +00:00
while ( ( bread = cli_readn ( desc , buff , FILEBUFF ) ) > 0 ) {
2004-05-27 20:15:37 +00:00
if ( sum + bread > = size ) {
if ( write ( ndesc , buff , size - sum ) = = - 1 ) {
cli_dbgmsg ( " Can't write to file \n " ) ;
lseek ( desc , pos , SEEK_SET ) ;
close ( ndesc ) ;
2008-04-02 11:13:16 +00:00
cli_unlink ( file ) ;
2004-07-05 23:50:55 +00:00
return - 1 ;
2004-05-27 20:15:37 +00:00
}
break ;
} else {
if ( write ( ndesc , buff , bread ) = = - 1 ) {
cli_dbgmsg ( " Can't write to file \n " ) ;
lseek ( desc , pos , SEEK_SET ) ;
close ( ndesc ) ;
2008-04-02 11:13:16 +00:00
cli_unlink ( file ) ;
2004-07-05 23:50:55 +00:00
return - 1 ;
2004-05-27 20:15:37 +00:00
}
}
sum + = bread ;
}
close ( ndesc ) ;
lseek ( desc , pos , SEEK_SET ) ;
return 0 ;
}
2005-03-18 21:06:25 +00:00
*/
2004-05-27 20:15:37 +00:00
2009-11-11 03:58:22 +01:00
/*
void findres ( uint32_t by_type , uint32_t by_name , uint32_t res_rva , cli_ctx * ctx , struct cli_exe_section * exe_sections , uint16_t nsections , uint32_t hdr_size , int ( * cb ) ( void * , uint32_t , uint32_t , uint32_t , uint32_t ) , void * opaque )
callback based res lookup
by_type : lookup type
by_name : lookup name or ( unsigned ) - 1 to look for any name
res_rva : base resource rva ( i . e . dirs [ 2 ] . VirtualAddress )
ctx , exe_sections , nsections , hdr_size : same as in scanpe
cb : the callback function executed on each successful match
opaque : an opaque pointer passed to the callback
the callback proto is
int pe_res_cballback ( void * opaque , uint32_t type , uint32_t name , uint32_t lang , uint32_t rva ) ;
the callback shall return 0 to continue the lookup or 1 to abort
*/
2010-01-04 14:56:04 +01:00
void findres ( uint32_t by_type , uint32_t by_name , uint32_t res_rva , fmap_t * map , struct cli_exe_section * exe_sections , uint16_t nsections , uint32_t hdr_size , int ( * cb ) ( void * , uint32_t , uint32_t , uint32_t , uint32_t ) , void * opaque ) {
2009-11-11 03:58:22 +01:00
unsigned int err = 0 ;
uint32_t type , type_offs , name , name_offs , lang , lang_offs ;
uint8_t * resdir , * type_entry , * name_entry , * lang_entry ;
uint16_t type_cnt , name_cnt , lang_cnt ;
if ( ! ( resdir = fmap_need_off_once ( map , cli_rawaddr ( res_rva , exe_sections , nsections , & err , map - > len , hdr_size ) , 16 ) ) | | err )
return ;
type_cnt = ( uint16_t ) cli_readint16 ( resdir + 12 ) ;
type_entry = resdir + 16 ;
if ( ! ( by_type > > 31 ) ) {
type_entry + = type_cnt * 8 ;
type_cnt = ( uint16_t ) cli_readint16 ( resdir + 14 ) ;
}
while ( type_cnt - - ) {
if ( ! fmap_need_ptr_once ( map , type_entry , 8 ) )
return ;
type = cli_readint32 ( type_entry ) ;
type_offs = cli_readint32 ( type_entry + 4 ) ;
if ( type = = by_type & & ( type_offs > > 31 ) ) {
type_offs & = 0x7fffffff ;
if ( ! ( resdir = fmap_need_off_once ( map , cli_rawaddr ( res_rva + type_offs , exe_sections , nsections , & err , map - > len , hdr_size ) , 16 ) ) | | err )
return ;
name_cnt = ( uint16_t ) cli_readint16 ( resdir + 12 ) ;
name_entry = resdir + 16 ;
if ( by_name = = 0xffffffff )
name_cnt + = ( uint16_t ) cli_readint16 ( resdir + 14 ) ;
else if ( ! ( by_name > > 31 ) ) {
name_entry + = name_cnt * 8 ;
name_cnt = ( uint16_t ) cli_readint16 ( resdir + 14 ) ;
}
while ( name_cnt - - ) {
if ( ! fmap_need_ptr_once ( map , name_entry , 8 ) )
return ;
name = cli_readint32 ( name_entry ) ;
name_offs = cli_readint32 ( name_entry + 4 ) ;
if ( ( by_name = = 0xffffffff | | name = = by_name ) & & ( name_offs > > 31 ) ) {
name_offs & = 0x7fffffff ;
if ( ! ( resdir = fmap_need_off_once ( map , cli_rawaddr ( res_rva + name_offs , exe_sections , nsections , & err , map - > len , hdr_size ) , 16 ) ) | | err )
return ;
lang_cnt = ( uint16_t ) cli_readint16 ( resdir + 12 ) + ( uint16_t ) cli_readint16 ( resdir + 14 ) ;
lang_entry = resdir + 16 ;
while ( lang_cnt - - ) {
if ( ! fmap_need_ptr_once ( map , lang_entry , 8 ) )
return ;
lang = cli_readint32 ( lang_entry ) ;
lang_offs = cli_readint32 ( lang_entry + 4 ) ;
if ( ! ( lang_offs > > 31 ) ) {
if ( cb ( opaque , type , name , lang , res_rva + lang_offs ) )
return ;
}
lang_entry + = 8 ;
}
}
name_entry + = 8 ;
}
return ; /* FIXME: unless we want to find ALL types */
}
type_entry + = 8 ;
}
}
2009-10-02 18:09:31 +02:00
static unsigned int cli_md5sect ( fmap_t * map , struct cli_exe_section * s , unsigned char * digest ) {
2007-09-04 00:38:30 +00:00
void * hashme ;
cli_md5_ctx md5 ;
2006-09-27 00:36:11 +00:00
2007-09-04 00:38:30 +00:00
if ( s - > rsz > CLI_MAX_ALLOCATION ) {
cli_dbgmsg ( " cli_md5sect: skipping md5 calculation for too big section \n " ) ;
2006-11-26 22:23:11 +00:00
return 0 ;
2006-09-27 00:36:11 +00:00
}
2009-08-31 17:26:22 +02:00
if ( ! s - > rsz ) return 0 ;
if ( ! ( hashme = fmap_need_off_once ( map , s - > raw , s - > rsz ) ) ) {
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " cli_md5sect: unable to read section data \n " ) ;
return 0 ;
2006-09-27 00:36:11 +00:00
}
2007-09-04 00:38:30 +00:00
cli_md5_init ( & md5 ) ;
cli_md5_update ( & md5 , hashme , s - > rsz ) ;
cli_md5_final ( digest , & md5 ) ;
2006-11-26 22:23:11 +00:00
return 1 ;
2006-09-27 00:36:11 +00:00
}
2009-10-02 18:09:31 +02:00
static void cli_parseres_special ( uint32_t base , uint32_t rva , fmap_t * map , struct cli_exe_section * exe_sections , uint16_t nsections , size_t fsize , uint32_t hdr_size , unsigned int level , uint32_t type , unsigned int * maxres , struct swizz_stats * stats ) {
2008-12-02 19:55:57 +00:00
unsigned int err = 0 , i ;
2009-08-31 17:26:22 +02:00
uint8_t * resdir ;
2008-12-02 19:55:57 +00:00
uint8_t * entry , * oentry ;
uint16_t named , unnamed ;
uint32_t rawaddr = cli_rawaddr ( rva , exe_sections , nsections , & err , fsize , hdr_size ) ;
uint32_t entries ;
if ( level > 2 | | ! * maxres ) return ;
* maxres - = 1 ;
2009-08-31 17:26:22 +02:00
if ( err | | ! ( resdir = fmap_need_off_once ( map , rawaddr , 16 ) ) )
2008-12-02 19:55:57 +00:00
return ;
named = ( uint16_t ) cli_readint16 ( resdir + 12 ) ;
unnamed = ( uint16_t ) cli_readint16 ( resdir + 14 ) ;
entries = /*named+*/ unnamed ;
if ( ! entries )
return ;
rawaddr + = named * 8 ; /* skip named */
/* this is just used in a heuristic detection, so don't give error on failure */
2009-08-31 17:26:22 +02:00
if ( ! ( entry = fmap_need_off ( map , rawaddr + 16 , entries * 8 ) ) ) {
2008-12-02 19:55:57 +00:00
cli_dbgmsg ( " cli_parseres_special: failed to read resource directory at:%lu \n " , ( unsigned long ) rawaddr + 16 ) ;
return ;
}
2009-08-31 17:26:22 +02:00
oentry = entry ;
2008-12-02 19:55:57 +00:00
/*for (i=0; i<named; i++) {
uint32_t id , offs ;
id = cli_readint32 ( entry ) ;
offs = cli_readint32 ( entry + 4 ) ;
if ( offs > > 31 )
cli_parseres ( base , base + ( offs & 0x7fffffff ) , srcfd , exe_sections , nsections , fsize , hdr_size , level + 1 , type , maxres , stats ) ;
entry + = 8 ;
} */
2008-12-23 10:53:20 +00:00
for ( i = 0 ; i < unnamed ; i + + , entry + = 8 ) {
2008-12-02 19:55:57 +00:00
uint32_t id , offs ;
2009-04-10 13:23:13 +00:00
if ( stats - > errors > = SWIZZ_MAXERRORS ) {
cli_dbgmsg ( " cli_parseres_special: resources broken, ignoring \n " ) ;
return ;
}
2008-12-02 19:55:57 +00:00
id = cli_readint32 ( entry ) & 0x7fffffff ;
if ( level = = 0 ) {
2008-12-23 10:53:20 +00:00
type = 0 ;
2008-12-02 19:55:57 +00:00
switch ( id ) {
case 4 : /* menu */
case 5 : /* dialog */
case 6 : /* string */
case 11 : /* msgtable */
type = id ;
break ;
case 16 :
2008-12-23 10:53:20 +00:00
type = id ;
2008-12-02 19:55:57 +00:00
/* 14: version */
stats - > has_version = 1 ;
break ;
case 24 : /* manifest */
stats - > has_manifest = 1 ;
break ;
/* otherwise keep it 0, we don't want it */
}
2008-12-23 10:53:20 +00:00
}
if ( ! type ) {
2008-12-02 19:55:57 +00:00
/* if we are not interested in this type, skip */
continue ;
}
offs = cli_readint32 ( entry + 4 ) ;
if ( offs > > 31 )
2009-08-31 17:26:22 +02:00
cli_parseres_special ( base , base + ( offs & 0x7fffffff ) , map , exe_sections , nsections , fsize , hdr_size , level + 1 , type , maxres , stats ) ;
2008-12-02 19:55:57 +00:00
else {
offs = cli_readint32 ( entry + 4 ) ;
rawaddr = cli_rawaddr ( base + offs , exe_sections , nsections , & err , fsize , hdr_size ) ;
2009-08-31 17:26:22 +02:00
if ( ! err & & ( resdir = fmap_need_off_once ( map , rawaddr , 16 ) ) ) {
2008-12-02 19:55:57 +00:00
uint32_t isz = cli_readint32 ( resdir + 4 ) ;
2009-08-31 17:26:22 +02:00
uint8_t * str ;
2008-12-02 19:55:57 +00:00
rawaddr = cli_rawaddr ( cli_readint32 ( resdir ) , exe_sections , nsections , & err , fsize , hdr_size ) ;
2009-04-01 16:39:55 +00:00
if ( err | | ! isz | | isz > = fsize | | rawaddr + isz > = fsize ) {
2008-12-02 19:55:57 +00:00
cli_dbgmsg ( " cli_parseres_special: invalid resource table entry: %lu + %lu \n " ,
( unsigned long ) rawaddr ,
( unsigned long ) isz ) ;
2009-04-10 13:23:13 +00:00
stats - > errors + + ;
2008-12-02 19:55:57 +00:00
continue ;
}
2009-08-31 17:26:22 +02:00
if ( ( str = fmap_need_off_once ( map , rawaddr , isz ) ) )
2008-12-02 19:55:57 +00:00
cli_detect_swizz_str ( str , isz , stats , type ) ;
}
}
}
2009-08-31 17:26:22 +02:00
fmap_unneed_ptr ( map , oentry , entries * 8 ) ;
2008-12-02 19:55:57 +00:00
}
2009-12-11 23:04:18 +01:00
int cli_scanpe ( cli_ctx * ctx , icon_groupset * iconset )
2004-05-11 23:30:57 +00:00
{
uint16_t e_magic ; /* DOS signature ("MZ") */
2004-07-05 23:50:55 +00:00
uint16_t nsections ;
2004-05-11 23:30:57 +00:00
uint32_t e_lfanew ; /* address of new exe header */
2006-11-26 22:23:11 +00:00
uint32_t ep , vep ; /* entry point (raw, virtual) */
2007-03-14 02:53:08 +00:00
uint8_t polipos = 0 ;
2004-07-19 17:54:40 +00:00
time_t timestamp ;
2004-05-11 23:30:57 +00:00
struct pe_image_file_hdr file_hdr ;
2006-11-26 22:23:11 +00:00
union {
struct pe_image_optional_hdr64 opt64 ;
struct pe_image_optional_hdr32 opt32 ;
} pe_opt ;
2004-06-11 20:17:18 +00:00
struct pe_image_section_hdr * section_hdr ;
2009-08-31 17:26:22 +02:00
char sname [ 9 ] , epbuff [ 4096 ] , * tempfile ;
2007-09-04 00:38:30 +00:00
uint32_t epsize ;
2009-08-31 17:26:22 +02:00
ssize_t bytes , at ;
2009-07-14 09:36:36 +02:00
unsigned int i , found , upx_success = 0 , min = 0 , max = 0 , err , overlays = 0 ;
2005-11-26 22:39:01 +00:00
unsigned int ssize = 0 , dsize = 0 , dll = 0 , pe_plus = 0 ;
2006-01-10 00:46:40 +00:00
int ( * upxfn ) ( char * , uint32_t , char * , uint32_t * , uint32_t , uint32_t , uint32_t ) = NULL ;
2004-09-05 16:18:45 +00:00
char * src = NULL , * dest = NULL ;
2007-03-14 22:26:54 +00:00
int ndesc , ret = CL_CLEAN , upack = 0 , native = 0 ;
2006-01-14 18:21:36 +00:00
size_t fsize ;
2009-10-02 17:33:11 +03:00
uint32_t valign , falign , hdr_size , j , offset ;
2006-11-26 22:23:11 +00:00
struct cli_exe_section * exe_sections ;
2007-04-30 14:12:38 +00:00
struct cli_matcher * md5_sect ;
2008-02-08 17:50:44 +00:00
char timestr [ 32 ] ;
2008-12-02 19:55:57 +00:00
struct pe_image_data_dir * dirs ;
2009-10-02 17:33:11 +03:00
struct cli_bc_ctx * bc_ctx ;
2009-10-02 18:09:31 +02:00
fmap_t * map ;
2009-10-02 17:33:11 +03:00
struct cli_pe_hook_data pedata ;
2004-05-11 23:30:57 +00:00
2007-10-05 21:48:57 +00:00
if ( ! ctx ) {
cli_errmsg ( " cli_scanpe: ctx == NULL \n " ) ;
return CL_ENULLARG ;
}
2009-08-31 17:26:22 +02:00
map = * ctx - > fmap ;
if ( fmap_readn ( map , & e_magic , 0 , sizeof ( e_magic ) ) ! = sizeof ( e_magic ) ) {
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Can't read DOS signature \n " ) ;
2004-08-26 00:22:11 +00:00
return CL_CLEAN ;
2004-05-11 23:30:57 +00:00
}
2009-10-31 19:12:50 +01:00
if ( EC16 ( e_magic ) ! = PE_IMAGE_DOS_SIGNATURE & & EC16 ( e_magic ) ! = PE_IMAGE_DOS_SIGNATURE_OLD ) {
2004-05-11 23:30:57 +00:00
cli_dbgmsg ( " Invalid DOS signature \n " ) ;
2004-07-05 23:50:55 +00:00
return CL_CLEAN ;
2004-05-11 23:30:57 +00:00
}
2009-08-31 17:26:22 +02:00
if ( fmap_readn ( map , & e_lfanew , 58 + sizeof ( e_magic ) , sizeof ( e_lfanew ) ) ! = sizeof ( e_lfanew ) ) {
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Can't read new header address \n " ) ;
2004-08-26 00:22:11 +00:00
/* truncated header? */
if ( DETECT_BROKEN ) {
2006-02-15 00:41:40 +00:00
if ( ctx - > virname )
* ctx - > virname = " Broken.Executable " ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2004-08-26 00:22:11 +00:00
}
return CL_CLEAN ;
2004-05-11 23:30:57 +00:00
}
2004-07-05 23:50:55 +00:00
e_lfanew = EC32 ( e_lfanew ) ;
2004-05-11 23:30:57 +00:00
cli_dbgmsg ( " e_lfanew == %d \n " , e_lfanew ) ;
if ( ! e_lfanew ) {
cli_dbgmsg ( " Not a PE file \n " ) ;
2004-07-05 23:50:55 +00:00
return CL_CLEAN ;
2004-05-11 23:30:57 +00:00
}
2004-07-15 22:46:11 +00:00
2009-08-31 17:26:22 +02:00
if ( fmap_readn ( map , & file_hdr , e_lfanew , sizeof ( struct pe_image_file_hdr ) ) ! = sizeof ( struct pe_image_file_hdr ) ) {
2004-07-15 22:46:11 +00:00
/* bad information in e_lfanew - probably not a PE file */
2004-05-11 23:30:57 +00:00
cli_dbgmsg ( " Can't read file header \n " ) ;
2004-07-15 22:46:11 +00:00
return CL_CLEAN ;
2004-05-11 23:30:57 +00:00
}
2009-10-31 19:17:22 +01:00
if ( EC32 ( file_hdr . Magic ) ! = PE_IMAGE_NT_SIGNATURE ) {
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Invalid PE signature (probably NE file) \n " ) ;
2004-07-05 23:50:55 +00:00
return CL_CLEAN ;
2004-05-11 23:30:57 +00:00
}
2005-03-21 00:17:24 +00:00
if ( EC16 ( file_hdr . Characteristics ) & 0x2000 ) {
cli_dbgmsg ( " File type: DLL \n " ) ;
dll = 1 ;
} else if ( EC16 ( file_hdr . Characteristics ) & 0x01 ) {
cli_dbgmsg ( " File type: Executable \n " ) ;
}
2004-07-05 23:50:55 +00:00
switch ( EC16 ( file_hdr . Machine ) ) {
2005-04-19 23:52:13 +00:00
case 0x0 :
cli_dbgmsg ( " Machine type: Unknown \n " ) ;
2007-09-04 00:38:30 +00:00
break ;
2004-05-11 23:30:57 +00:00
case 0x14c :
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Machine type: 80386 \n " ) ;
2004-05-11 23:30:57 +00:00
break ;
2005-04-19 23:52:13 +00:00
case 0x14d :
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Machine type: 80486 \n " ) ;
2004-05-11 23:30:57 +00:00
break ;
2005-04-19 23:52:13 +00:00
case 0x14e :
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Machine type: 80586 \n " ) ;
2004-05-11 23:30:57 +00:00
break ;
2005-04-19 23:52:13 +00:00
case 0x160 :
cli_dbgmsg ( " Machine type: R30000 (big-endian) \n " ) ;
break ;
2004-05-11 23:30:57 +00:00
case 0x162 :
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Machine type: R3000 \n " ) ;
2004-05-11 23:30:57 +00:00
break ;
case 0x166 :
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Machine type: R4000 \n " ) ;
2004-05-11 23:30:57 +00:00
break ;
case 0x168 :
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Machine type: R10000 \n " ) ;
2004-05-11 23:30:57 +00:00
break ;
case 0x184 :
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Machine type: DEC Alpha AXP \n " ) ;
2004-05-11 23:30:57 +00:00
break ;
2004-11-17 23:08:16 +00:00
case 0x284 :
cli_dbgmsg ( " Machine type: DEC Alpha AXP 64bit \n " ) ;
break ;
2004-05-11 23:30:57 +00:00
case 0x1f0 :
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Machine type: PowerPC \n " ) ;
2004-05-11 23:30:57 +00:00
break ;
2004-11-17 23:08:16 +00:00
case 0x200 :
cli_dbgmsg ( " Machine type: IA64 \n " ) ;
break ;
case 0x268 :
cli_dbgmsg ( " Machine type: M68k \n " ) ;
break ;
case 0x266 :
cli_dbgmsg ( " Machine type: MIPS16 \n " ) ;
break ;
case 0x366 :
cli_dbgmsg ( " Machine type: MIPS+FPU \n " ) ;
break ;
case 0x466 :
cli_dbgmsg ( " Machine type: MIPS16+FPU \n " ) ;
break ;
case 0x1a2 :
cli_dbgmsg ( " Machine type: Hitachi SH3 \n " ) ;
break ;
2005-04-19 23:52:13 +00:00
case 0x1a3 :
cli_dbgmsg ( " Machine type: Hitachi SH3-DSP \n " ) ;
break ;
case 0x1a4 :
cli_dbgmsg ( " Machine type: Hitachi SH3-E \n " ) ;
break ;
2004-11-17 23:08:16 +00:00
case 0x1a6 :
cli_dbgmsg ( " Machine type: Hitachi SH4 \n " ) ;
break ;
2005-04-19 23:52:13 +00:00
case 0x1a8 :
cli_dbgmsg ( " Machine type: Hitachi SH5 \n " ) ;
break ;
2004-11-17 23:08:16 +00:00
case 0x1c0 :
cli_dbgmsg ( " Machine type: ARM \n " ) ;
break ;
case 0x1c2 :
cli_dbgmsg ( " Machine type: THUMB \n " ) ;
break ;
2005-04-19 23:52:13 +00:00
case 0x1d3 :
cli_dbgmsg ( " Machine type: AM33 \n " ) ;
break ;
case 0x520 :
cli_dbgmsg ( " Machine type: Infineon TriCore \n " ) ;
break ;
case 0xcef :
cli_dbgmsg ( " Machine type: CEF \n " ) ;
break ;
case 0xebc :
cli_dbgmsg ( " Machine type: EFI Byte Code \n " ) ;
break ;
case 0x9041 :
cli_dbgmsg ( " Machine type: M32R \n " ) ;
break ;
case 0xc0ee :
cli_dbgmsg ( " Machine type: CEE \n " ) ;
break ;
case 0x8664 :
cli_dbgmsg ( " Machine type: AMD64 \n " ) ;
break ;
2004-05-11 23:30:57 +00:00
default :
2008-09-25 20:45:33 +00:00
cli_dbgmsg ( " Machine type: ** UNKNOWN ** (0x%x) \n " , EC16 ( file_hdr . Machine ) ) ;
2004-05-11 23:30:57 +00:00
}
2004-07-05 23:50:55 +00:00
nsections = EC16 ( file_hdr . NumberOfSections ) ;
2006-11-26 22:23:11 +00:00
if ( nsections < 1 | | nsections > 96 ) {
2005-03-15 16:42:07 +00:00
if ( DETECT_BROKEN ) {
2006-02-15 00:41:40 +00:00
if ( ctx - > virname )
* ctx - > virname = " Broken.Executable " ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2005-03-15 16:42:07 +00:00
}
2006-04-04 22:55:54 +00:00
if ( nsections )
cli_warnmsg ( " PE file contains %d sections \n " , nsections ) ;
else
cli_warnmsg ( " PE file contains no sections \n " ) ;
2005-03-15 16:42:07 +00:00
return CL_CLEAN ;
}
2004-07-05 23:50:55 +00:00
cli_dbgmsg ( " NumberOfSections: %d \n " , nsections ) ;
2004-07-19 17:54:40 +00:00
timestamp = ( time_t ) EC32 ( file_hdr . TimeDateStamp ) ;
2008-10-07 13:57:21 +00:00
cli_dbgmsg ( " TimeDateStamp: %s " , cli_ctime ( & timestamp , timestr , sizeof ( timestr ) ) ) ;
2004-05-11 23:30:57 +00:00
2006-11-04 23:01:17 +00:00
cli_dbgmsg ( " SizeOfOptionalHeader: %x \n " , EC16 ( file_hdr . SizeOfOptionalHeader ) ) ;
2004-05-11 23:30:57 +00:00
2006-11-26 22:23:11 +00:00
if ( EC16 ( file_hdr . SizeOfOptionalHeader ) < sizeof ( struct pe_image_optional_hdr32 ) ) {
cli_dbgmsg ( " SizeOfOptionalHeader too small \n " ) ;
if ( DETECT_BROKEN ) {
if ( ctx - > virname )
* ctx - > virname = " Broken.Executable " ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2004-08-04 20:11:18 +00:00
}
2006-11-26 22:23:11 +00:00
return CL_CLEAN ;
2004-05-11 23:30:57 +00:00
}
2009-08-31 17:26:22 +02:00
at = e_lfanew + sizeof ( struct pe_image_file_hdr ) ;
if ( fmap_readn ( map , & optional_hdr32 , at , sizeof ( struct pe_image_optional_hdr32 ) ) ! = sizeof ( struct pe_image_optional_hdr32 ) ) {
2006-11-26 22:23:11 +00:00
cli_dbgmsg ( " Can't read optional file header \n " ) ;
if ( DETECT_BROKEN ) {
if ( ctx - > virname )
* ctx - > virname = " Broken.Executable " ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2006-11-26 22:23:11 +00:00
}
return CL_CLEAN ;
}
2009-08-31 17:26:22 +02:00
at + = sizeof ( struct pe_image_optional_hdr32 ) ;
2005-11-26 22:39:01 +00:00
2006-11-26 22:23:11 +00:00
/* This will be a chicken and egg problem until we drop 9x */
2009-07-31 12:52:41 +02:00
if ( EC16 ( optional_hdr64 . Magic ) = = PE32P_SIGNATURE ) {
2006-11-26 22:23:11 +00:00
if ( EC16 ( file_hdr . SizeOfOptionalHeader ) ! = sizeof ( struct pe_image_optional_hdr64 ) ) {
/* FIXME: need to play around a bit more with xp64 */
cli_dbgmsg ( " Incorrect SizeOfOptionalHeader for PE32+ \n " ) ;
2005-11-26 22:39:01 +00:00
if ( DETECT_BROKEN ) {
2006-11-26 22:23:11 +00:00
if ( ctx - > virname )
2006-02-15 00:41:40 +00:00
* ctx - > virname = " Broken.Executable " ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2005-11-26 22:39:01 +00:00
}
return CL_CLEAN ;
2004-08-04 20:11:18 +00:00
}
2006-11-26 22:23:11 +00:00
pe_plus = 1 ;
} else {
/*
either it ' s got a PE32_SIGNATURE or
we enable win9x compatibility in that we don ' t honor magic ( see bb # 119 )
either way it ' s a 32 bit thingy
*/
if ( EC16 ( optional_hdr32 . Magic ) ! = PE32_SIGNATURE ) {
2005-11-26 22:39:01 +00:00
cli_warnmsg ( " Incorrect magic number in optional header \n " ) ;
if ( DETECT_BROKEN ) {
2006-11-26 22:23:11 +00:00
if ( ctx - > virname )
2006-02-15 00:41:40 +00:00
* ctx - > virname = " Broken.Executable " ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2005-11-26 22:39:01 +00:00
}
2007-01-27 12:59:30 +00:00
cli_dbgmsg ( " 9x compatibility mode \n " ) ;
2005-11-26 22:39:01 +00:00
}
2006-11-26 22:23:11 +00:00
}
if ( ! pe_plus ) { /* PE */
if ( EC16 ( file_hdr . SizeOfOptionalHeader ) ! = sizeof ( struct pe_image_optional_hdr32 ) ) {
/* Seek to the end of the long header */
2009-08-31 17:26:22 +02:00
at + = EC16 ( file_hdr . SizeOfOptionalHeader ) - sizeof ( struct pe_image_optional_hdr32 ) ;
2006-11-26 22:23:11 +00:00
}
2007-01-30 19:18:36 +00:00
if ( DCONF & PE_CONF_UPACK )
upack = ( EC16 ( file_hdr . SizeOfOptionalHeader ) = = 0x148 ) ;
2006-11-26 22:23:11 +00:00
vep = EC32 ( optional_hdr32 . AddressOfEntryPoint ) ;
2007-03-27 03:34:18 +00:00
hdr_size = EC32 ( optional_hdr32 . SizeOfHeaders ) ;
2005-11-26 22:39:01 +00:00
cli_dbgmsg ( " File format: PE \n " ) ;
cli_dbgmsg ( " MajorLinkerVersion: %d \n " , optional_hdr32 . MajorLinkerVersion ) ;
cli_dbgmsg ( " MinorLinkerVersion: %d \n " , optional_hdr32 . MinorLinkerVersion ) ;
2006-11-26 22:23:11 +00:00
cli_dbgmsg ( " SizeOfCode: 0x%x \n " , EC32 ( optional_hdr32 . SizeOfCode ) ) ;
cli_dbgmsg ( " SizeOfInitializedData: 0x%x \n " , EC32 ( optional_hdr32 . SizeOfInitializedData ) ) ;
cli_dbgmsg ( " SizeOfUninitializedData: 0x%x \n " , EC32 ( optional_hdr32 . SizeOfUninitializedData ) ) ;
cli_dbgmsg ( " AddressOfEntryPoint: 0x%x \n " , vep ) ;
2005-11-26 22:39:01 +00:00
cli_dbgmsg ( " BaseOfCode: 0x%x \n " , EC32 ( optional_hdr32 . BaseOfCode ) ) ;
2006-11-26 22:23:11 +00:00
cli_dbgmsg ( " SectionAlignment: 0x%x \n " , EC32 ( optional_hdr32 . SectionAlignment ) ) ;
cli_dbgmsg ( " FileAlignment: 0x%x \n " , EC32 ( optional_hdr32 . FileAlignment ) ) ;
2005-11-26 22:39:01 +00:00
cli_dbgmsg ( " MajorSubsystemVersion: %d \n " , EC16 ( optional_hdr32 . MajorSubsystemVersion ) ) ;
cli_dbgmsg ( " MinorSubsystemVersion: %d \n " , EC16 ( optional_hdr32 . MinorSubsystemVersion ) ) ;
2006-11-26 22:23:11 +00:00
cli_dbgmsg ( " SizeOfImage: 0x%x \n " , EC32 ( optional_hdr32 . SizeOfImage ) ) ;
2007-03-27 03:34:18 +00:00
cli_dbgmsg ( " SizeOfHeaders: 0x%x \n " , hdr_size ) ;
2005-11-26 22:39:01 +00:00
cli_dbgmsg ( " NumberOfRvaAndSizes: %d \n " , EC32 ( optional_hdr32 . NumberOfRvaAndSizes ) ) ;
2008-12-02 19:55:57 +00:00
dirs = optional_hdr32 . DataDirectory ;
2005-11-26 22:39:01 +00:00
} else { /* PE+ */
2006-11-26 22:23:11 +00:00
/* read the remaining part of the header */
2009-08-31 17:26:22 +02:00
if ( fmap_readn ( map , & optional_hdr32 + 1 , at , sizeof ( struct pe_image_optional_hdr64 ) - sizeof ( struct pe_image_optional_hdr32 ) ) ! = sizeof ( struct pe_image_optional_hdr64 ) - sizeof ( struct pe_image_optional_hdr32 ) ) {
2006-11-26 22:23:11 +00:00
cli_dbgmsg ( " Can't read optional file header \n " ) ;
2005-11-26 22:39:01 +00:00
if ( DETECT_BROKEN ) {
2006-11-26 22:23:11 +00:00
if ( ctx - > virname )
2006-02-15 00:41:40 +00:00
* ctx - > virname = " Broken.Executable " ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2005-11-26 22:39:01 +00:00
}
return CL_CLEAN ;
}
2009-08-31 17:26:22 +02:00
at + = sizeof ( struct pe_image_optional_hdr64 ) - sizeof ( struct pe_image_optional_hdr32 ) ;
2006-11-26 22:23:11 +00:00
vep = EC32 ( optional_hdr64 . AddressOfEntryPoint ) ;
2007-03-27 03:41:15 +00:00
hdr_size = EC32 ( optional_hdr64 . SizeOfHeaders ) ;
2005-11-26 22:39:01 +00:00
cli_dbgmsg ( " File format: PE32+ \n " ) ;
cli_dbgmsg ( " MajorLinkerVersion: %d \n " , optional_hdr64 . MajorLinkerVersion ) ;
cli_dbgmsg ( " MinorLinkerVersion: %d \n " , optional_hdr64 . MinorLinkerVersion ) ;
2006-11-26 22:23:11 +00:00
cli_dbgmsg ( " SizeOfCode: 0x%x \n " , EC32 ( optional_hdr64 . SizeOfCode ) ) ;
cli_dbgmsg ( " SizeOfInitializedData: 0x%x \n " , EC32 ( optional_hdr64 . SizeOfInitializedData ) ) ;
cli_dbgmsg ( " SizeOfUninitializedData: 0x%x \n " , EC32 ( optional_hdr64 . SizeOfUninitializedData ) ) ;
cli_dbgmsg ( " AddressOfEntryPoint: 0x%x \n " , vep ) ;
2005-11-26 22:39:01 +00:00
cli_dbgmsg ( " BaseOfCode: 0x%x \n " , EC32 ( optional_hdr64 . BaseOfCode ) ) ;
2006-11-26 22:23:11 +00:00
cli_dbgmsg ( " SectionAlignment: 0x%x \n " , EC32 ( optional_hdr64 . SectionAlignment ) ) ;
cli_dbgmsg ( " FileAlignment: 0x%x \n " , EC32 ( optional_hdr64 . FileAlignment ) ) ;
2005-11-26 22:39:01 +00:00
cli_dbgmsg ( " MajorSubsystemVersion: %d \n " , EC16 ( optional_hdr64 . MajorSubsystemVersion ) ) ;
cli_dbgmsg ( " MinorSubsystemVersion: %d \n " , EC16 ( optional_hdr64 . MinorSubsystemVersion ) ) ;
2006-11-26 22:23:11 +00:00
cli_dbgmsg ( " SizeOfImage: 0x%x \n " , EC32 ( optional_hdr64 . SizeOfImage ) ) ;
2007-03-27 03:34:18 +00:00
cli_dbgmsg ( " SizeOfHeaders: 0x%x \n " , hdr_size ) ;
2005-11-26 22:39:01 +00:00
cli_dbgmsg ( " NumberOfRvaAndSizes: %d \n " , EC32 ( optional_hdr64 . NumberOfRvaAndSizes ) ) ;
2008-12-02 19:55:57 +00:00
dirs = optional_hdr64 . DataDirectory ;
2004-05-11 23:30:57 +00:00
}
2006-11-04 23:48:32 +00:00
2005-11-26 22:39:01 +00:00
switch ( pe_plus ? EC16 ( optional_hdr64 . Subsystem ) : EC16 ( optional_hdr32 . Subsystem ) ) {
2004-11-26 20:11:03 +00:00
case 0 :
cli_dbgmsg ( " Subsystem: Unknown \n " ) ;
break ;
2004-05-11 23:30:57 +00:00
case 1 :
2007-02-18 22:24:21 +00:00
cli_dbgmsg ( " Subsystem: Native (svc) \n " ) ;
2007-03-14 22:26:54 +00:00
native = 1 ;
2004-05-11 23:30:57 +00:00
break ;
case 2 :
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Subsystem: Win32 GUI \n " ) ;
2004-05-11 23:30:57 +00:00
break ;
case 3 :
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Subsystem: Win32 console \n " ) ;
2004-05-11 23:30:57 +00:00
break ;
case 5 :
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Subsystem: OS/2 console \n " ) ;
2004-05-11 23:30:57 +00:00
break ;
case 7 :
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Subsystem: POSIX console \n " ) ;
2004-05-11 23:30:57 +00:00
break ;
2004-11-17 23:08:16 +00:00
case 8 :
cli_dbgmsg ( " Subsystem: Native Win9x driver \n " ) ;
break ;
case 9 :
cli_dbgmsg ( " Subsystem: WinCE GUI \n " ) ;
break ;
case 10 :
cli_dbgmsg ( " Subsystem: EFI application \n " ) ;
break ;
case 11 :
cli_dbgmsg ( " Subsystem: EFI driver \n " ) ;
break ;
case 12 :
cli_dbgmsg ( " Subsystem: EFI runtime driver \n " ) ;
break ;
2008-09-25 20:45:33 +00:00
case 13 :
cli_dbgmsg ( " Subsystem: EFI ROM image \n " ) ;
break ;
case 14 :
cli_dbgmsg ( " Subsystem: Xbox \n " ) ;
break ;
case 16 :
cli_dbgmsg ( " Subsystem: Boot application \n " ) ;
break ;
2004-05-11 23:30:57 +00:00
default :
2008-09-25 20:45:33 +00:00
cli_dbgmsg ( " Subsystem: ** UNKNOWN ** (0x%x) \n " , pe_plus ? EC16 ( optional_hdr64 . Subsystem ) : EC16 ( optional_hdr32 . Subsystem ) ) ;
2004-05-11 23:30:57 +00:00
}
2004-08-02 17:09:06 +00:00
cli_dbgmsg ( " ------------------------------------ \n " ) ;
2004-05-11 23:30:57 +00:00
2007-03-14 22:26:54 +00:00
if ( DETECT_BROKEN & & ! native & & ( ! ( pe_plus ? EC32 ( optional_hdr64 . SectionAlignment ) : EC32 ( optional_hdr32 . SectionAlignment ) ) | | ( pe_plus ? EC32 ( optional_hdr64 . SectionAlignment ) : EC32 ( optional_hdr32 . SectionAlignment ) ) % 0x1000 ) ) {
cli_dbgmsg ( " Bad virtual alignemnt \n " ) ;
if ( ctx - > virname )
* ctx - > virname = " Broken.Executable " ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2007-03-14 22:26:54 +00:00
}
if ( DETECT_BROKEN & & ! native & & ( ! ( pe_plus ? EC32 ( optional_hdr64 . FileAlignment ) : EC32 ( optional_hdr32 . FileAlignment ) ) | | ( pe_plus ? EC32 ( optional_hdr64 . FileAlignment ) : EC32 ( optional_hdr32 . FileAlignment ) ) % 0x200 ) ) {
cli_dbgmsg ( " Bad file alignemnt \n " ) ;
if ( ctx - > virname )
* ctx - > virname = " Broken.Executable " ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2007-03-14 22:26:54 +00:00
}
2009-08-31 17:26:22 +02:00
fsize = map - > len ;
2006-01-14 18:21:36 +00:00
2004-07-05 23:50:55 +00:00
section_hdr = ( struct pe_image_section_hdr * ) cli_calloc ( nsections , sizeof ( struct pe_image_section_hdr ) ) ;
2004-06-11 20:17:18 +00:00
if ( ! section_hdr ) {
cli_dbgmsg ( " Can't allocate memory for section headers \n " ) ;
return CL_EMEM ;
}
2006-11-26 22:23:11 +00:00
exe_sections = ( struct cli_exe_section * ) cli_calloc ( nsections , sizeof ( struct cli_exe_section ) ) ;
if ( ! exe_sections ) {
cli_dbgmsg ( " Can't allocate memory for section headers \n " ) ;
free ( section_hdr ) ;
return CL_EMEM ;
}
2004-05-11 23:30:57 +00:00
2006-11-26 22:23:11 +00:00
valign = ( pe_plus ) ? EC32 ( optional_hdr64 . SectionAlignment ) : EC32 ( optional_hdr32 . SectionAlignment ) ;
falign = ( pe_plus ) ? EC32 ( optional_hdr64 . FileAlignment ) : EC32 ( optional_hdr32 . FileAlignment ) ;
2009-08-31 17:26:22 +02:00
if ( fmap_readn ( map , section_hdr , at , sizeof ( struct pe_image_section_hdr ) * nsections ) ! = ( int ) ( nsections * sizeof ( struct pe_image_section_hdr ) ) ) {
2006-11-26 22:23:11 +00:00
cli_dbgmsg ( " Can't read section header \n " ) ;
cli_dbgmsg ( " Possibly broken PE file \n " ) ;
free ( section_hdr ) ;
free ( exe_sections ) ;
if ( DETECT_BROKEN ) {
if ( ctx - > virname )
* ctx - > virname = " Broken.Executable " ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2006-11-26 22:23:11 +00:00
}
return CL_CLEAN ;
}
2009-08-31 17:26:22 +02:00
at + = sizeof ( struct pe_image_section_hdr ) * nsections ;
2006-11-26 22:23:11 +00:00
for ( i = 0 ; falign ! = 0x200 & & i < nsections ; i + + ) {
/* file alignment fallback mode - blah */
2007-01-27 12:59:30 +00:00
if ( falign & & section_hdr [ i ] . SizeOfRawData & & EC32 ( section_hdr [ i ] . PointerToRawData ) % falign & & ! ( EC32 ( section_hdr [ i ] . PointerToRawData ) % 0x200 ) ) {
2006-11-26 22:23:11 +00:00
cli_dbgmsg ( " Found misaligned section, using 0x200 \n " ) ;
falign = 0x200 ;
2004-05-11 23:30:57 +00:00
}
2006-11-26 22:23:11 +00:00
}
2004-05-11 23:30:57 +00:00
2007-03-19 20:00:13 +00:00
hdr_size = PESALIGN ( hdr_size , valign ) ; /* Aligned headers virtual size */
2007-03-14 22:26:54 +00:00
2006-11-26 22:23:11 +00:00
for ( i = 0 ; i < nsections ; i + + ) {
2006-05-18 11:29:24 +00:00
strncpy ( sname , ( char * ) section_hdr [ i ] . Name , 8 ) ;
2004-05-11 23:30:57 +00:00
sname [ 8 ] = 0 ;
2006-11-26 22:23:11 +00:00
exe_sections [ i ] . rva = PEALIGN ( EC32 ( section_hdr [ i ] . VirtualAddress ) , valign ) ;
exe_sections [ i ] . vsz = PESALIGN ( EC32 ( section_hdr [ i ] . VirtualSize ) , valign ) ;
exe_sections [ i ] . raw = PEALIGN ( EC32 ( section_hdr [ i ] . PointerToRawData ) , falign ) ;
exe_sections [ i ] . rsz = PESALIGN ( EC32 ( section_hdr [ i ] . SizeOfRawData ) , falign ) ;
2007-03-14 02:53:08 +00:00
exe_sections [ i ] . chr = EC32 ( section_hdr [ i ] . Characteristics ) ;
exe_sections [ i ] . urva = EC32 ( section_hdr [ i ] . VirtualAddress ) ; /* Just in case */
exe_sections [ i ] . uvsz = EC32 ( section_hdr [ i ] . VirtualSize ) ;
exe_sections [ i ] . uraw = EC32 ( section_hdr [ i ] . PointerToRawData ) ;
2006-11-28 00:49:50 +00:00
exe_sections [ i ] . ursz = EC32 ( section_hdr [ i ] . SizeOfRawData ) ;
2007-02-18 22:24:21 +00:00
if ( ! exe_sections [ i ] . vsz & & exe_sections [ i ] . rsz )
2007-03-14 02:53:08 +00:00
exe_sections [ i ] . vsz = PESALIGN ( exe_sections [ i ] . ursz , valign ) ;
2007-02-18 22:24:21 +00:00
2006-11-26 22:23:11 +00:00
if ( exe_sections [ i ] . rsz & & fsize > exe_sections [ i ] . raw & & ! CLI_ISCONTAINED ( 0 , ( uint32_t ) fsize , exe_sections [ i ] . raw , exe_sections [ i ] . rsz ) )
exe_sections [ i ] . rsz = fsize - exe_sections [ i ] . raw ;
2004-07-13 16:42:33 +00:00
cli_dbgmsg ( " Section %d \n " , i ) ;
2004-05-11 23:30:57 +00:00
cli_dbgmsg ( " Section name: %s \n " , sname ) ;
2006-11-26 22:23:11 +00:00
cli_dbgmsg ( " Section data (from headers - in memory) \n " ) ;
2007-03-14 02:53:08 +00:00
cli_dbgmsg ( " VirtualSize: 0x%x 0x%x \n " , exe_sections [ i ] . uvsz , exe_sections [ i ] . vsz ) ;
cli_dbgmsg ( " VirtualAddress: 0x%x 0x%x \n " , exe_sections [ i ] . urva , exe_sections [ i ] . rva ) ;
cli_dbgmsg ( " SizeOfRawData: 0x%x 0x%x \n " , exe_sections [ i ] . ursz , exe_sections [ i ] . rsz ) ;
cli_dbgmsg ( " PointerToRawData: 0x%x 0x%x \n " , exe_sections [ i ] . uraw , exe_sections [ i ] . raw ) ;
2004-05-11 23:30:57 +00:00
2007-03-14 02:53:08 +00:00
if ( exe_sections [ i ] . chr & 0x20 ) {
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Section contains executable code \n " ) ;
2006-11-26 22:23:11 +00:00
if ( exe_sections [ i ] . vsz < exe_sections [ i ] . rsz ) {
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Section contains free space \n " ) ;
/*
cli_dbgmsg ( " Dumping %d bytes \n " , section_hdr . SizeOfRawData - section_hdr . VirtualSize ) ;
2004-07-19 17:54:40 +00:00
ddump ( desc , section_hdr . PointerToRawData + section_hdr . VirtualSize , section_hdr . SizeOfRawData - section_hdr . VirtualSize , cli_gentemp ( NULL ) ) ;
2004-05-27 20:15:37 +00:00
*/
}
}
2004-05-11 23:30:57 +00:00
2007-03-14 02:53:08 +00:00
if ( exe_sections [ i ] . chr & 0x20000000 )
2004-05-27 20:15:37 +00:00
cli_dbgmsg ( " Section's memory is executable \n " ) ;
2005-03-21 00:17:24 +00:00
2007-03-14 02:53:08 +00:00
if ( exe_sections [ i ] . chr & 0x80000000 )
2005-03-21 00:17:24 +00:00
cli_dbgmsg ( " Section's memory is writeable \n " ) ;
2004-08-02 17:09:06 +00:00
cli_dbgmsg ( " ------------------------------------ \n " ) ;
2004-05-27 20:15:37 +00:00
2009-03-23 14:15:43 +00:00
if ( DETECT_BROKEN & & ( ! valign | | ( exe_sections [ i ] . urva % valign ) ) ) { /* Bad virtual alignment */
2006-11-05 01:35:40 +00:00
cli_dbgmsg ( " VirtualAddress is misaligned \n " ) ;
if ( ctx - > virname )
* ctx - > virname = " Broken.Executable " ;
free ( section_hdr ) ;
2006-11-26 22:23:11 +00:00
free ( exe_sections ) ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2006-11-05 01:35:40 +00:00
}
2006-09-27 00:36:11 +00:00
2006-11-26 22:23:11 +00:00
if ( exe_sections [ i ] . rsz ) { /* Don't bother with virtual only sections */
if ( exe_sections [ i ] . raw > = fsize ) { /* really broken */
2008-01-05 02:43:07 +00:00
cli_dbgmsg ( " Broken PE file - Section %d starts beyond the end of file (Offset@ %lu, Total filesize %lu) \n " , i , ( unsigned long ) exe_sections [ i ] . raw , ( unsigned long ) fsize ) ;
2006-11-26 22:23:11 +00:00
free ( section_hdr ) ;
free ( exe_sections ) ;
if ( DETECT_BROKEN ) {
if ( ctx - > virname )
* ctx - > virname = " Broken.Executable " ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2006-11-26 22:23:11 +00:00
}
return CL_CLEAN ; /* no ninjas to see here! move along! */
}
2007-04-30 14:12:38 +00:00
2007-09-04 00:38:30 +00:00
if ( SCAN_ALGO & & ( DCONF & PE_CONF_POLIPOS ) & & ! * sname & & exe_sections [ i ] . vsz > 40000 & & exe_sections [ i ] . vsz < 70000 & & exe_sections [ i ] . chr = = 0xe0000060 ) polipos = i ;
2006-11-26 22:23:11 +00:00
/* check MD5 section sigs */
2007-12-15 20:34:31 +00:00
md5_sect = ctx - > engine - > md5_mdb ;
2007-04-30 14:12:38 +00:00
if ( ( DCONF & PE_CONF_MD5SECT ) & & md5_sect ) {
found = 0 ;
for ( j = 0 ; j < md5_sect - > soff_len & & md5_sect - > soff [ j ] < = exe_sections [ i ] . rsz ; j + + ) {
if ( md5_sect - > soff [ j ] = = exe_sections [ i ] . rsz ) {
2007-09-04 00:38:30 +00:00
unsigned char md5_dig [ 16 ] ;
2009-10-02 21:03:26 +02:00
const struct cli_bm_patt * patt ;
2009-10-09 22:07:33 +02:00
if ( cli_md5sect ( map , & exe_sections [ i ] , md5_dig ) & & cli_bm_scanbuff ( md5_dig , 16 , ctx - > virname , & patt , ctx - > engine - > md5_mdb , 0 , NULL , NULL ) = = CL_VIRUS & & patt - > filesize = = exe_sections [ i ] . rsz ) {
if ( cli_bm_scanbuff ( md5_dig , 16 , NULL , & patt , ctx - > engine - > md5_fp , 0 , NULL , NULL ) ! = CL_VIRUS | | patt - > filesize ! = fsize ) {
2007-09-04 00:38:30 +00:00
free ( section_hdr ) ;
free ( exe_sections ) ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2007-12-16 18:49:51 +00:00
}
2006-09-27 00:36:11 +00:00
}
2007-09-04 00:38:30 +00:00
break ;
2006-09-27 00:36:11 +00:00
}
}
}
2004-08-04 20:11:18 +00:00
}
2008-02-13 10:34:58 +00:00
if ( exe_sections [ i ] . urva > > 31 | | exe_sections [ i ] . uvsz > > 31 | | ( exe_sections [ i ] . rsz & & exe_sections [ i ] . uraw > > 31 ) | | exe_sections [ i ] . ursz > > 31 ) {
cli_dbgmsg ( " Found PE values with sign bit set \n " ) ;
free ( section_hdr ) ;
free ( exe_sections ) ;
if ( DETECT_BROKEN ) {
if ( ctx - > virname )
* ctx - > virname = " Broken.Executable " ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2008-02-13 10:34:58 +00:00
}
return CL_CLEAN ;
}
2004-08-02 17:09:06 +00:00
if ( ! i ) {
2007-03-14 22:26:54 +00:00
if ( DETECT_BROKEN & & exe_sections [ i ] . urva ! = hdr_size ) { /* Bad first section RVA */
2006-11-05 01:35:40 +00:00
cli_dbgmsg ( " First section is in the wrong place \n " ) ;
if ( ctx - > virname )
2006-12-04 18:05:16 +00:00
* ctx - > virname = " Broken.Executable " ;
2006-11-05 01:35:40 +00:00
free ( section_hdr ) ;
2006-11-26 22:23:11 +00:00
free ( exe_sections ) ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2006-11-05 01:35:40 +00:00
}
2006-11-26 22:23:11 +00:00
min = exe_sections [ i ] . rva ;
max = exe_sections [ i ] . rva + exe_sections [ i ] . rsz ;
2004-08-02 17:09:06 +00:00
} else {
2007-03-14 02:53:08 +00:00
if ( DETECT_BROKEN & & exe_sections [ i ] . urva - exe_sections [ i - 1 ] . urva ! = exe_sections [ i - 1 ] . vsz ) { /* No holes, no overlapping, no virtual disorder */
2006-11-05 01:35:40 +00:00
cli_dbgmsg ( " Virtually misplaced section (wrong order, overlapping, non contiguous) \n " ) ;
if ( ctx - > virname )
2006-12-04 18:05:16 +00:00
* ctx - > virname = " Broken.Executable " ;
2006-11-05 01:35:40 +00:00
free ( section_hdr ) ;
2006-11-26 22:23:11 +00:00
free ( exe_sections ) ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2006-11-05 01:35:40 +00:00
}
2006-11-26 22:23:11 +00:00
if ( exe_sections [ i ] . rva < min )
min = exe_sections [ i ] . rva ;
2004-05-27 20:15:37 +00:00
2009-07-14 09:36:36 +02:00
if ( exe_sections [ i ] . rva + exe_sections [ i ] . rsz > max ) {
2006-11-26 22:23:11 +00:00
max = exe_sections [ i ] . rva + exe_sections [ i ] . rsz ;
2009-07-14 09:36:36 +02:00
overlays = exe_sections [ i ] . raw + exe_sections [ i ] . rsz ;
}
2004-05-27 20:15:37 +00:00
}
2004-05-11 23:30:57 +00:00
}
2007-03-14 02:53:08 +00:00
free ( section_hdr ) ;
2007-03-14 22:26:54 +00:00
if ( ! ( ep = cli_rawaddr ( vep , exe_sections , nsections , & err , fsize , hdr_size ) ) & & err ) {
2006-11-26 22:23:11 +00:00
cli_dbgmsg ( " EntryPoint out of file \n " ) ;
free ( exe_sections ) ;
2004-08-04 20:11:18 +00:00
if ( DETECT_BROKEN ) {
2006-02-15 00:41:40 +00:00
if ( ctx - > virname )
* ctx - > virname = " Broken.Executable " ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2004-08-04 20:11:18 +00:00
}
2004-06-12 00:16:01 +00:00
return CL_CLEAN ;
2004-05-11 23:30:57 +00:00
}
2004-06-12 00:16:01 +00:00
cli_dbgmsg ( " EntryPoint offset: 0x%x (%d) \n " , ep , ep ) ;
2009-12-11 23:04:18 +01:00
if ( iconset ) {
if ( ! dll & & dirs [ 2 ] . Size & & cli_scanicon ( iconset , EC32 ( dirs [ 2 ] . VirtualAddress ) , ctx , exe_sections , nsections , hdr_size ) = = CL_VIRUS ) {
2009-12-11 00:52:16 +01:00
free ( exe_sections ) ;
return CL_VIRUS ;
}
free ( exe_sections ) ;
return CL_CLEAN ;
2009-11-11 03:58:22 +01:00
}
2006-11-04 17:54:53 +00:00
if ( pe_plus ) { /* Do not continue for PE32+ files */
2006-11-26 22:23:11 +00:00
free ( exe_sections ) ;
2006-11-04 17:54:53 +00:00
return CL_CLEAN ;
}
2009-08-31 17:26:22 +02:00
epsize = fmap_readn ( map , epbuff , ep , 4096 ) ;
2007-03-13 22:50:40 +00:00
2008-07-27 16:27:29 +00:00
CLI_UNPTEMP ( " DISASM " , ( exe_sections , 0 ) ) ;
2009-10-01 14:25:41 +02:00
if ( disasmbuf ( ( unsigned char * ) epbuff , epsize , ndesc ) )
ret = cli_scandesc ( ndesc , ctx , CL_TYPE_PE_DISASM , 1 , NULL , AC_SCAN_VIR ) ;
2008-07-28 13:23:12 +00:00
close ( ndesc ) ;
2008-07-27 16:27:29 +00:00
CLI_TMPUNLK ( ) ;
2008-07-30 11:37:15 +00:00
free ( tempfile ) ;
2008-07-31 22:22:57 +00:00
if ( ret = = CL_VIRUS ) {
free ( exe_sections ) ;
return ret ;
}
2008-07-27 16:27:29 +00:00
2009-07-14 09:36:36 +02:00
if ( overlays ) {
int overlays_sz = fsize - overlays ;
2009-07-19 16:22:05 +02:00
if ( overlays_sz > 0 ) {
2009-09-05 20:16:10 +02:00
ret = cli_scanishield ( ctx , overlays , overlays_sz ) ;
2009-07-19 16:22:05 +02:00
if ( ret ! = CL_CLEAN ) {
free ( exe_sections ) ;
return ret ;
}
}
2009-07-14 09:36:36 +02:00
}
2005-01-16 05:38:06 +00:00
/* Attempt to detect some popular polymorphic viruses */
/* W32.Parite.B */
2007-09-04 00:38:30 +00:00
if ( SCAN_ALGO & & ( DCONF & PE_CONF_PARITE ) & & ! dll & & epsize = = 4096 & & ep = = exe_sections [ nsections - 1 ] . raw ) {
const char * pt = cli_memstr ( epbuff , 4040 , " \x47 \x65 \x74 \x50 \x72 \x6f \x63 \x41 \x64 \x64 \x72 \x65 \x73 \x73 \x00 " , 15 ) ;
if ( pt ) {
pt + = 15 ;
2007-09-08 12:59:57 +00:00
if ( ( ( ( uint32_t ) cli_readint32 ( pt ) ^ ( uint32_t ) cli_readint32 ( pt + 4 ) ) = = 0x505a4f ) & & ( ( ( uint32_t ) cli_readint32 ( pt + 8 ) ^ ( uint32_t ) cli_readint32 ( pt + 12 ) ) = = 0xffffb ) & & ( ( ( uint32_t ) cli_readint32 ( pt + 16 ) ^ ( uint32_t ) cli_readint32 ( pt + 20 ) ) = = 0xb8 ) ) {
2007-09-04 00:38:30 +00:00
* ctx - > virname = " W32.Parite.B " ;
free ( exe_sections ) ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2005-01-16 05:38:06 +00:00
}
}
}
2006-06-29 18:43:35 +00:00
/* Kriz */
2007-09-13 11:26:26 +00:00
if ( SCAN_ALGO & & ( DCONF & PE_CONF_KRIZ ) & & epsize > = 200 & & CLI_ISCONTAINED ( exe_sections [ nsections - 1 ] . raw , exe_sections [ nsections - 1 ] . rsz , ep , 0x0fd2 ) & & epbuff [ 1 ] = = ' \x9c ' & & epbuff [ 2 ] = = ' \x60 ' ) {
2007-09-04 00:38:30 +00:00
enum { KZSTRASH , KZSCDELTA , KZSPDELTA , KZSGETSIZE , KZSXORPRFX , KZSXOR , KZSDDELTA , KZSLOOP , KZSTOP } ;
uint8_t kzs [ ] = { KZSTRASH , KZSCDELTA , KZSPDELTA , KZSGETSIZE , KZSTRASH , KZSXORPRFX , KZSXOR , KZSTRASH , KZSDDELTA , KZSTRASH , KZSLOOP , KZSTOP } ;
uint8_t * kzstate = kzs ;
2007-09-13 11:26:26 +00:00
uint8_t * kzcode = ( uint8_t * ) epbuff + 3 ;
2007-09-04 00:38:30 +00:00
uint8_t kzdptr = 0xff , kzdsize = 0xff ;
int kzlen = 197 , kzinitlen = 0xffff , kzxorlen = - 1 ;
2006-06-29 18:43:35 +00:00
cli_dbgmsg ( " in kriz \n " ) ;
2007-09-04 00:38:30 +00:00
while ( * kzstate ! = KZSTOP ) {
uint8_t op ;
if ( kzlen < = 6 ) break ;
op = * kzcode + + ;
kzlen - - ;
switch ( * kzstate ) {
case KZSTRASH : case KZSGETSIZE : {
int opsz = 0 ;
switch ( op ) {
case 0x81 :
kzcode + = 5 ;
kzlen - = 5 ;
2006-11-26 22:31:16 +00:00
break ;
2007-09-04 00:38:30 +00:00
case 0xb8 : case 0xb9 : case 0xba : case 0xbb : case 0xbd : case 0xbe : case 0xbf :
if ( * kzstate = = KZSGETSIZE & & cli_readint32 ( kzcode ) = = 0x0fd2 ) {
kzinitlen = kzlen - 5 ;
kzdsize = op - 0xb8 ;
kzstate + + ;
op = 4 ; /* fake the register to avoid breaking out */
cli_dbgmsg ( " kriz: using #%d as size counter \n " , kzdsize ) ;
}
opsz = 4 ;
case 0x48 : case 0x49 : case 0x4a : case 0x4b : case 0x4d : case 0x4e : case 0x4f :
op & = 7 ;
if ( op ! = kzdptr & & op ! = kzdsize ) {
kzcode + = opsz ;
kzlen - = opsz ;
break ;
}
default :
kzcode - - ;
kzlen + + ;
kzstate + + ;
2006-11-26 22:31:16 +00:00
}
2007-09-04 00:38:30 +00:00
break ;
}
case KZSCDELTA :
if ( op = = 0xe8 & & ( uint32_t ) cli_readint32 ( kzcode ) < 0xff ) {
kzlen - = * kzcode + 4 ;
kzcode + = * kzcode + 4 ;
kzstate + + ;
} else * kzstate = KZSTOP ;
break ;
case KZSPDELTA :
if ( ( op & 0xf8 ) = = 0x58 & & ( kzdptr = op - 0x58 ) ! = 4 ) {
kzstate + + ;
cli_dbgmsg ( " kriz: using #%d as pointer \n " , kzdptr ) ;
} else * kzstate = KZSTOP ;
break ;
case KZSXORPRFX :
kzstate + + ;
if ( op = = 0x3e ) break ;
case KZSXOR :
if ( op = = 0x80 & & * kzcode = = kzdptr + 0xb0 ) {
kzxorlen = kzlen ;
kzcode + = + 6 ;
kzlen - = + 6 ;
kzstate + + ;
} else * kzstate = KZSTOP ;
break ;
case KZSDDELTA :
if ( op = = kzdptr + 0x48 ) kzstate + + ;
else * kzstate = KZSTOP ;
break ;
case KZSLOOP :
if ( op = = kzdsize + 0x48 & & * kzcode = = 0x75 & & kzlen - ( int8_t ) kzcode [ 1 ] - 3 < = kzinitlen & & kzlen - ( int8_t ) kzcode [ 1 ] > = kzxorlen ) {
* ctx - > virname = " W32.Kriz " ;
free ( exe_sections ) ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2006-06-29 18:43:35 +00:00
}
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " kriz: loop out of bounds, corrupted sample? \n " ) ;
kzstate + + ;
2006-11-26 22:31:16 +00:00
}
2006-06-29 18:43:35 +00:00
}
}
2005-03-21 00:17:24 +00:00
/* W32.Magistr.A/B */
2007-03-14 02:53:08 +00:00
if ( SCAN_ALGO & & ( DCONF & PE_CONF_MAGISTR ) & & ! dll & & ( nsections > 1 ) & & ( exe_sections [ nsections - 1 ] . chr & 0x80000000 ) ) {
2007-09-04 00:38:30 +00:00
uint32_t rsize , vsize , dam = 0 ;
2005-03-21 00:17:24 +00:00
2006-11-27 10:38:52 +00:00
vsize = exe_sections [ nsections - 1 ] . uvsz ;
2006-11-28 00:49:50 +00:00
rsize = exe_sections [ nsections - 1 ] . rsz ;
if ( rsize < exe_sections [ nsections - 1 ] . ursz ) {
rsize = exe_sections [ nsections - 1 ] . ursz ;
dam = 1 ;
}
2005-03-21 00:17:24 +00:00
2006-11-28 00:49:50 +00:00
if ( vsize > = 0x612c & & rsize > = 0x612c & & ( ( vsize & 0xff ) = = 0xec ) ) {
2005-03-21 00:17:24 +00:00
int bw = rsize < 0x7000 ? rsize : 0x7000 ;
2009-08-31 17:26:22 +02:00
char * tbuff ;
2005-03-21 00:17:24 +00:00
2009-08-31 17:26:22 +02:00
if ( ( tbuff = fmap_need_off_once ( map , exe_sections [ nsections - 1 ] . raw + rsize - bw , 4096 ) ) ) {
if ( cli_memstr ( tbuff , 4091 , " \xe8 \x2c \x61 \x00 \x00 " , 5 ) ) {
2006-11-28 00:49:50 +00:00
* ctx - > virname = dam ? " W32.Magistr.A.dam " : " W32.Magistr.A " ;
2006-11-26 22:23:11 +00:00
free ( exe_sections ) ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2005-03-21 00:17:24 +00:00
}
}
} else if ( rsize > = 0x7000 & & vsize > = 0x7000 & & ( ( vsize & 0xff ) = = 0xed ) ) {
int bw = rsize < 0x8000 ? rsize : 0x8000 ;
2009-08-31 17:26:22 +02:00
char * tbuff ;
2005-03-21 00:17:24 +00:00
2009-08-31 17:26:22 +02:00
if ( ( tbuff = fmap_need_off_once ( map , exe_sections [ nsections - 1 ] . raw + rsize - bw , 4096 ) ) ) {
if ( cli_memstr ( tbuff , 4091 , " \xe8 \x04 \x72 \x00 \x00 " , 5 ) ) {
2006-11-28 00:49:50 +00:00
* ctx - > virname = dam ? " W32.Magistr.B.dam " : " W32.Magistr.B " ;
2006-11-26 22:23:11 +00:00
free ( exe_sections ) ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2005-03-21 00:17:24 +00:00
}
}
}
}
2006-05-01 18:32:13 +00:00
/* W32.Polipos.A */
2007-09-04 00:38:30 +00:00
while ( 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 ) {
uint32_t jump , jold , * jumps = NULL ;
uint8_t * code ;
unsigned int xsjs = 0 ;
if ( exe_sections [ 0 ] . rsz > CLI_MAX_ALLOCATION ) break ;
2009-08-31 17:26:22 +02:00
if ( ! exe_sections [ 0 ] . rsz ) break ;
if ( ! ( code = fmap_need_off_once ( map , exe_sections [ 0 ] . raw , exe_sections [ 0 ] . rsz ) ) ) break ;
2007-09-04 00:38:30 +00:00
for ( i = 0 ; i < exe_sections [ 0 ] . rsz - 5 ; i + + ) {
if ( ( uint8_t ) ( code [ i ] - 0xe8 ) > 1 ) continue ;
jump = cli_rawaddr ( exe_sections [ 0 ] . rva + i + 5 + cli_readint32 ( & code [ i + 1 ] ) , exe_sections , nsections , & err , fsize , hdr_size ) ;
if ( err | | ! CLI_ISCONTAINED ( exe_sections [ polipos ] . raw , exe_sections [ polipos ] . rsz , jump , 9 ) ) continue ;
if ( xsjs % 128 = = 0 ) {
if ( xsjs = = 1280 ) break ;
if ( ! ( jumps = ( uint32_t * ) cli_realloc2 ( jumps , ( xsjs + 128 ) * sizeof ( uint32_t ) ) ) ) {
free ( exe_sections ) ;
return CL_EMEM ;
2006-05-01 18:32:13 +00:00
}
}
2007-09-04 00:38:30 +00:00
j = 0 ;
for ( ; j < xsjs ; j + + ) {
if ( jumps [ j ] < jump ) continue ;
if ( jumps [ j ] = = jump ) {
xsjs - - ;
2006-05-01 18:32:13 +00:00
break ;
}
2007-09-04 00:38:30 +00:00
jold = jumps [ j ] ;
jumps [ j ] = jump ;
jump = jold ;
}
jumps [ j ] = jump ;
xsjs + + ;
}
if ( ! xsjs ) break ;
cli_dbgmsg ( " Polipos: Checking %d xsect jump(s) \n " , xsjs ) ;
for ( i = 0 ; i < xsjs ; i + + ) {
2009-08-31 17:26:22 +02:00
if ( ! ( code = fmap_need_off_once ( map , jumps [ i ] , 9 ) ) ) continue ;
2009-10-08 20:48:21 +02:00
if ( ( jump = cli_readint32 ( code ) ) = = 0x60ec8b55 | | ( code [ 4 ] = = 0x0ec & & ( ( jump = = 0x83ec8b55 & & code [ 6 ] = = 0x60 ) | | ( jump = = 0x81ec8b55 & & ! code [ 7 ] & & ! code [ 8 ] ) ) ) ) {
2007-09-04 00:38:30 +00:00
* ctx - > virname = " W32.Polipos.A " ;
free ( jumps ) ;
free ( exe_sections ) ;
2009-10-02 14:36:27 +02:00
return CL_VIRUS ;
2006-05-01 18:32:13 +00:00
}
}
2007-09-04 00:38:30 +00:00
free ( jumps ) ;
break ;
2006-05-01 18:32:13 +00:00
}
2008-12-02 19:55:57 +00:00
/* Trojan.Swizzor.Gen */
if ( SCAN_ALGO & & ( DCONF & PE_CONF_SWIZZOR ) & & nsections > 1 & & fsize > 64 * 1024 & & fsize < 4 * 1024 * 1024 ) {
if ( dirs [ 2 ] . Size ) {
2008-12-06 14:49:00 +00:00
struct swizz_stats * stats = cli_calloc ( 1 , sizeof ( * stats ) ) ;
unsigned int m = 1000 ;
int ret = CL_CLEAN ;
if ( ! stats )
ret = CL_EMEM ;
else {
2009-08-31 17:26:22 +02:00
cli_parseres_special ( EC32 ( dirs [ 2 ] . VirtualAddress ) , EC32 ( dirs [ 2 ] . VirtualAddress ) , map , exe_sections , nsections , fsize , hdr_size , 0 , 0 , & m , stats ) ;
2008-12-06 14:49:00 +00:00
if ( ( ret = cli_detect_swizz ( stats ) ) = = CL_VIRUS ) {
* ctx - > virname = " Trojan.Swizzor.Gen " ;
}
free ( stats ) ;
}
if ( ret ! = CL_CLEAN ) {
2008-12-02 19:55:57 +00:00
free ( exe_sections ) ;
return ret ;
}
}
}
2006-08-11 18:30:35 +00:00
2007-01-12 17:53:44 +00:00
/* UPX, FSG, MEW support */
2004-07-05 23:50:55 +00:00
/* try to find the first section with physical size == 0 */
found = 0 ;
2007-01-30 19:18:36 +00:00
if ( DCONF & ( PE_CONF_UPX | PE_CONF_FSG | PE_CONF_MEW ) ) {
2007-01-09 20:06:51 +00:00
for ( i = 0 ; i < ( unsigned int ) nsections - 1 ; i + + ) {
2007-03-13 22:50:40 +00:00
if ( ! exe_sections [ i ] . rsz & & exe_sections [ i ] . vsz & & exe_sections [ i + 1 ] . rsz & & exe_sections [ i + 1 ] . vsz ) {
2007-01-09 20:06:51 +00:00
found = 1 ;
2007-01-12 17:53:44 +00:00
cli_dbgmsg ( " UPX/FSG/MEW: empty section found - assuming compression \n " ) ;
2007-01-09 20:06:51 +00:00
break ;
}
2004-07-05 23:50:55 +00:00
}
}
2007-01-12 17:53:44 +00:00
/* MEW support */
2007-09-04 00:38:30 +00:00
if ( found & & ( DCONF & PE_CONF_MEW ) & & epsize > = 16 & & epbuff [ 0 ] = = ' \xe9 ' ) {
2007-01-12 17:53:44 +00:00
uint32_t fileoffset ;
2009-08-31 17:26:22 +02:00
char * tbuff ;
2007-01-12 17:53:44 +00:00
2007-09-04 00:38:30 +00:00
fileoffset = ( vep + cli_readint32 ( epbuff + 1 ) + 5 ) ;
while ( fileoffset = = 0x154 | | fileoffset = = 0x158 ) {
uint32_t offdiff , uselzma ;
2007-01-12 17:53:44 +00:00
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " MEW: found MEW characteristics %08X + %08X + 5 = %08X \n " ,
cli_readint32 ( epbuff + 1 ) , vep , cli_readint32 ( epbuff + 1 ) + vep + 5 ) ;
2007-01-12 17:53:44 +00:00
2009-08-31 17:26:22 +02:00
if ( ! ( tbuff = fmap_need_off_once ( map , fileoffset , 0xb0 ) ) )
2007-09-04 00:38:30 +00:00
break ;
if ( fileoffset = = 0x154 ) cli_dbgmsg ( " MEW: Win9x compatibility was set! \n " ) ;
else cli_dbgmsg ( " MEW: Win9x compatibility was NOT set! \n " ) ;
2007-01-12 17:53:44 +00:00
2009-08-31 17:26:22 +02:00
if ( ( offdiff = cli_readint32 ( tbuff + 1 ) - EC32 ( optional_hdr32 . ImageBase ) ) < = exe_sections [ i + 1 ] . rva | | offdiff > = exe_sections [ i + 1 ] . rva + exe_sections [ i + 1 ] . raw - 4 ) {
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " MEW: ESI is not in proper section \n " ) ;
break ;
}
offdiff - = exe_sections [ i + 1 ] . rva ;
2007-01-12 17:53:44 +00:00
2009-08-31 17:26:22 +02:00
if ( ! exe_sections [ i + 1 ] . rsz ) {
cli_dbgmsg ( " MEW: mew section is empty \n " ) ;
break ;
2007-09-04 00:38:30 +00:00
}
ssize = exe_sections [ i + 1 ] . vsz ;
dsize = exe_sections [ i ] . vsz ;
2007-01-12 17:53:44 +00:00
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " MEW: ssize %08x dsize %08x offdiff: %08x \n " , ssize , dsize , offdiff ) ;
2007-01-12 17:53:44 +00:00
2007-12-06 15:08:05 +00:00
CLI_UNPSIZELIMITS ( " MEW " , MAX ( ssize , dsize ) ) ;
2007-09-04 00:38:30 +00:00
CLI_UNPSIZELIMITS ( " MEW " , MAX ( ssize + dsize , exe_sections [ i + 1 ] . rsz ) ) ;
2007-01-12 17:53:44 +00:00
2009-08-31 17:26:22 +02:00
if ( exe_sections [ i + 1 ] . rsz < offdiff + 12 | | exe_sections [ i + 1 ] . rsz > ssize ) {
cli_dbgmsg ( " MEW: Size mismatch: %08x \n " , exe_sections [ i + 1 ] . rsz ) ;
break ;
}
2007-09-04 00:38:30 +00:00
/* allocate needed buffer */
if ( ! ( src = cli_calloc ( ssize + dsize , sizeof ( char ) ) ) ) {
free ( exe_sections ) ;
return CL_EMEM ;
}
2007-01-12 17:53:44 +00:00
2009-08-31 17:26:22 +02:00
if ( ( bytes = fmap_readn ( map , src + dsize , exe_sections [ i + 1 ] . raw , exe_sections [ i + 1 ] . rsz ) ) ! = exe_sections [ i + 1 ] . rsz ) {
cli_dbgmsg ( " MEW: Can't read %d bytes [read: %lu] \n " , exe_sections [ i + 1 ] . rsz , ( unsigned long ) bytes ) ;
2007-09-04 00:38:30 +00:00
free ( exe_sections ) ;
free ( src ) ;
2009-02-12 13:53:23 +00:00
return CL_EREAD ;
2007-09-04 00:38:30 +00:00
}
2008-01-05 02:43:07 +00:00
cli_dbgmsg ( " MEW: %u (%08x) bytes read \n " , ( unsigned int ) bytes , ( unsigned int ) bytes ) ;
2007-01-12 17:53:44 +00:00
2007-09-04 00:38:30 +00:00
/* count offset to lzma proc, if lzma used, 0xe8 -> call */
2009-08-31 17:26:22 +02:00
if ( tbuff [ 0x7b ] = = ' \xe8 ' ) {
if ( ! CLI_ISCONTAINED ( exe_sections [ 1 ] . rva , exe_sections [ 1 ] . vsz , cli_readint32 ( tbuff + 0x7c ) + fileoffset + 0x80 , 4 ) ) {
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " MEW: lzma proc out of bounds! \n " ) ;
2007-01-12 17:53:44 +00:00
free ( src ) ;
2007-09-04 00:38:30 +00:00
break ; /* to next unpacker in chain */
2007-01-12 17:53:44 +00:00
}
2009-08-31 17:26:22 +02:00
uselzma = cli_readint32 ( tbuff + 0x7c ) - ( exe_sections [ 0 ] . rva - fileoffset - 0x80 ) ;
2007-09-04 00:38:30 +00:00
} else {
uselzma = 0 ;
2007-01-12 17:53:44 +00:00
}
2007-03-14 02:53:08 +00:00
2007-09-20 23:21:01 +00:00
CLI_UNPTEMP ( " MEW " , ( src , exe_sections , 0 ) ) ;
2008-01-05 02:43:07 +00:00
CLI_UNPRESULTS ( " MEW " , ( unmew11 ( src , offdiff , ssize , dsize , EC32 ( optional_hdr32 . ImageBase ) , exe_sections [ 0 ] . rva , uselzma , ndesc ) ) , 1 , ( src , 0 ) ) ;
2007-09-04 00:38:30 +00:00
break ;
2004-07-06 02:27:22 +00:00
}
2007-09-04 00:38:30 +00:00
}
2004-07-06 02:27:22 +00:00
2007-09-04 00:38:30 +00:00
if ( epsize < 168 ) {
free ( exe_sections ) ;
return CL_CLEAN ;
}
if ( found | | upack ) {
/* Check EP for UPX vs. FSG vs. Upack */
2004-07-09 02:23:11 +00:00
2007-01-13 14:40:59 +00:00
/* Upack 0.39 produces 2 types of executables
* 3 sections : | 2 sections ( one empty , I don ' t chech found if ! upack , since it ' s in OR above ) :
* mov esi , value | pusha
* lodsd | call $ + 0x9
* push eax |
*
* Upack 1.1 / 1.2 Beta produces [ based on 2 samples ( sUx ) provided by aCaB ] :
* 2 sections
* mov esi , value
* loads
* mov edi , eax
*
* Upack unknown [ sample 02 97729 ]
* 3 sections
* mov esi , value
* push [ esi ]
* jmp
*
*/
/* upack 0.39-3s + sample 0151477*/
2007-09-04 00:38:30 +00:00
while ( ( ( upack & & nsections = = 3 ) & & /* 3 sections */
2007-09-13 12:49:46 +00:00
( (
2007-09-04 00:38:30 +00:00
epbuff [ 0 ] = = ' \xbe ' & & cli_readint32 ( epbuff + 1 ) - EC32 ( optional_hdr32 . ImageBase ) > min & & /* mov esi */
epbuff [ 5 ] = = ' \xad ' & & epbuff [ 6 ] = = ' \x50 ' /* lodsd; push eax */
2007-03-13 22:50:40 +00:00
)
| |
/* based on 0297729 sample from aCaB */
2007-09-04 00:38:30 +00:00
( epbuff [ 0 ] = = ' \xbe ' & & cli_readint32 ( epbuff + 1 ) - EC32 ( optional_hdr32 . ImageBase ) > min & & /* mov esi */
epbuff [ 5 ] = = ' \xff ' & & epbuff [ 6 ] = = ' \x36 ' /* push [esi] */
2007-03-13 22:50:40 +00:00
)
2007-09-13 12:49:46 +00:00
) )
2007-03-13 22:50:40 +00:00
| |
( ( ! upack & & nsections = = 2 ) & & /* 2 sections */
2007-09-13 12:49:46 +00:00
( ( /* upack 0.39-2s */
2007-09-04 00:38:30 +00:00
epbuff [ 0 ] = = ' \x60 ' & & epbuff [ 1 ] = = ' \xe8 ' & & cli_readint32 ( epbuff + 2 ) = = 0x9 /* pusha; call+9 */
2007-03-13 22:50:40 +00:00
)
| |
( /* upack 1.1/1.2, based on 2 samples */
2007-09-04 00:38:30 +00:00
epbuff [ 0 ] = = ' \xbe ' & & cli_readint32 ( epbuff + 1 ) - EC32 ( optional_hdr32 . ImageBase ) < min & & /* mov esi */
cli_readint32 ( epbuff + 1 ) - EC32 ( optional_hdr32 . ImageBase ) > 0 & &
epbuff [ 5 ] = = ' \xad ' & & epbuff [ 6 ] = = ' \x8b ' & & epbuff [ 7 ] = = ' \xf8 ' /* loads; mov edi, eax */
2007-03-13 22:50:40 +00:00
)
2007-09-13 12:49:46 +00:00
) )
2007-09-04 00:38:30 +00:00
) {
uint32_t vma , off ;
int a , b , c ;
cli_dbgmsg ( " Upack characteristics found. \n " ) ;
a = exe_sections [ 0 ] . vsz ;
b = exe_sections [ 1 ] . vsz ;
if ( upack ) {
cli_dbgmsg ( " Upack: var set \n " ) ;
c = exe_sections [ 2 ] . vsz ;
ssize = exe_sections [ 0 ] . ursz + exe_sections [ 0 ] . uraw ;
off = exe_sections [ 0 ] . rva ;
vma = EC32 ( optional_hdr32 . ImageBase ) + exe_sections [ 0 ] . rva ;
} else {
cli_dbgmsg ( " Upack: var NOT set \n " ) ;
c = exe_sections [ 1 ] . rva ;
ssize = exe_sections [ 1 ] . uraw ;
off = 0 ;
vma = exe_sections [ 1 ] . rva - exe_sections [ 1 ] . uraw ;
}
2007-01-13 14:40:59 +00:00
2007-09-04 00:38:30 +00:00
dsize = a + b + c ;
2007-01-13 14:40:59 +00:00
2007-09-04 00:38:30 +00:00
CLI_UNPSIZELIMITS ( " Upack " , MAX ( MAX ( dsize , ssize ) , exe_sections [ 1 ] . ursz ) ) ;
2007-01-13 14:40:59 +00:00
2008-04-14 20:13:05 +00:00
if ( ! CLI_ISCONTAINED ( 0 , dsize , exe_sections [ 1 ] . rva - off , exe_sections [ 1 ] . ursz ) | | ( upack & & ! CLI_ISCONTAINED ( 0 , dsize , exe_sections [ 2 ] . rva - exe_sections [ 0 ] . rva , ssize ) ) | | ssize > dsize ) {
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " Upack: probably malformed pe-header, skipping to next unpacker \n " ) ;
break ;
}
if ( ( dest = ( char * ) cli_calloc ( dsize , sizeof ( char ) ) ) = = NULL ) {
free ( exe_sections ) ;
return CL_EMEM ;
}
2007-01-13 14:40:59 +00:00
2009-08-31 17:26:22 +02:00
if ( fmap_readn ( map , dest , 0 , ssize ) ! = ssize ) {
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " Upack: Can't read raw data of section 0 \n " ) ;
free ( dest ) ;
2008-04-06 11:03:36 +00:00
break ;
2007-09-04 00:38:30 +00:00
}
2007-01-13 14:40:59 +00:00
2007-09-04 00:38:30 +00:00
if ( upack ) memmove ( dest + exe_sections [ 2 ] . rva - exe_sections [ 0 ] . rva , dest , ssize ) ;
2007-03-14 14:50:05 +00:00
2009-08-31 17:26:22 +02:00
if ( fmap_readn ( map , dest + exe_sections [ 1 ] . rva - off , exe_sections [ 1 ] . uraw , exe_sections [ 1 ] . ursz ) ! = exe_sections [ 1 ] . ursz ) {
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " Upack: Can't read raw data of section 1 \n " ) ;
free ( dest ) ;
2008-04-06 11:03:36 +00:00
break ;
2007-09-04 00:38:30 +00:00
}
2004-06-12 00:16:01 +00:00
2007-09-20 23:21:01 +00:00
CLI_UNPTEMP ( " Upack " , ( dest , exe_sections , 0 ) ) ;
CLI_UNPRESULTS ( " Upack " , ( unupack ( upack , dest , dsize , epbuff , vma , ep , EC32 ( optional_hdr32 . ImageBase ) , exe_sections [ 0 ] . rva , ndesc ) ) , 1 , ( dest , 0 ) ) ;
2007-09-04 00:38:30 +00:00
break ;
}
}
2004-06-12 00:16:01 +00:00
2007-09-04 00:38:30 +00:00
while ( found & & ( DCONF & PE_CONF_FSG ) & & epbuff [ 0 ] = = ' \x87 ' & & epbuff [ 1 ] = = ' \x25 ' ) {
2004-07-06 02:27:22 +00:00
2007-09-04 00:38:30 +00:00
/* FSG v2.0 support - thanks to aCaB ! */
2004-07-06 02:27:22 +00:00
2007-09-04 00:38:30 +00:00
uint32_t newesi , newedi , newebx , newedx ;
ssize = exe_sections [ i + 1 ] . rsz ;
dsize = exe_sections [ i ] . vsz ;
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
CLI_UNPSIZELIMITS ( " FSG " , MAX ( dsize , ssize ) ) ;
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
if ( ssize < = 0x19 | | dsize < = ssize ) {
cli_dbgmsg ( " FSG: Size mismatch (ssize: %d, dsize: %d) \n " , ssize , dsize ) ;
free ( exe_sections ) ;
return CL_CLEAN ;
}
newedx = cli_readint32 ( epbuff + 2 ) - EC32 ( optional_hdr32 . ImageBase ) ;
if ( ! CLI_ISCONTAINED ( exe_sections [ i + 1 ] . rva , exe_sections [ i + 1 ] . rsz , newedx , 4 ) ) {
cli_dbgmsg ( " FSG: xchg out of bounds (%x), giving up \n " , newedx ) ;
break ;
}
2009-08-31 17:26:22 +02:00
if ( ! exe_sections [ i + 1 ] . rsz | | ! ( src = fmap_need_off_once ( map , exe_sections [ i + 1 ] . raw , ssize ) ) ) {
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " Can't read raw data of section %d \n " , i + 1 ) ;
free ( exe_sections ) ;
2009-02-12 13:53:23 +00:00
return CL_ESEEK ;
2007-09-04 00:38:30 +00:00
}
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
dest = src + newedx - exe_sections [ i + 1 ] . rva ;
if ( newedx < exe_sections [ i + 1 ] . rva | | ! CLI_ISCONTAINED ( src , ssize , dest , 4 ) ) {
cli_dbgmsg ( " FSG: New ESP out of bounds \n " ) ;
break ;
}
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
newedx = cli_readint32 ( dest ) - EC32 ( optional_hdr32 . ImageBase ) ;
if ( ! CLI_ISCONTAINED ( exe_sections [ i + 1 ] . rva , exe_sections [ i + 1 ] . rsz , newedx , 4 ) ) {
cli_dbgmsg ( " FSG: New ESP (%x) is wrong \n " , newedx ) ;
break ;
}
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
dest = src + newedx - exe_sections [ i + 1 ] . rva ;
if ( ! CLI_ISCONTAINED ( src , ssize , dest , 32 ) ) {
cli_dbgmsg ( " FSG: New stack out of bounds \n " ) ;
break ;
}
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
newedi = cli_readint32 ( dest ) - EC32 ( optional_hdr32 . ImageBase ) ;
newesi = cli_readint32 ( dest + 4 ) - EC32 ( optional_hdr32 . ImageBase ) ;
newebx = cli_readint32 ( dest + 16 ) - EC32 ( optional_hdr32 . ImageBase ) ;
newedx = cli_readint32 ( dest + 20 ) ;
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
if ( newedi ! = exe_sections [ i ] . rva ) {
cli_dbgmsg ( " FSG: Bad destination buffer (edi is %x should be %x) \n " , newedi , exe_sections [ i ] . rva ) ;
break ;
}
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
if ( newesi < exe_sections [ i + 1 ] . rva | | newesi - exe_sections [ i + 1 ] . rva > = exe_sections [ i + 1 ] . rsz ) {
cli_dbgmsg ( " FSG: Source buffer out of section bounds \n " ) ;
break ;
}
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
if ( ! CLI_ISCONTAINED ( exe_sections [ i + 1 ] . rva , exe_sections [ i + 1 ] . rsz , newebx , 16 ) ) {
cli_dbgmsg ( " FSG: Array of functions out of bounds \n " ) ;
break ;
}
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
newedx = cli_readint32 ( newebx + 12 - exe_sections [ i + 1 ] . rva + src ) - EC32 ( optional_hdr32 . ImageBase ) ;
cli_dbgmsg ( " FSG: found old EP @%x \n " , newedx ) ;
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
if ( ( dest = ( char * ) cli_calloc ( dsize , sizeof ( char ) ) ) = = NULL ) {
free ( exe_sections ) ;
free ( src ) ;
return CL_EMEM ;
}
2004-08-05 01:15:59 +00:00
2009-08-31 17:26:22 +02:00
CLI_UNPTEMP ( " FSG " , ( dest , exe_sections , 0 ) ) ;
CLI_UNPRESULTSFSG2 ( " FSG " , ( 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 ) ) , 1 , ( dest , 0 ) ) ;
2007-09-04 00:38:30 +00:00
break ;
}
2006-01-14 18:21:36 +00:00
2005-08-15 16:21:05 +00:00
2007-09-04 00:38:30 +00:00
while ( found & & ( DCONF & PE_CONF_FSG ) & & epbuff [ 0 ] = = ' \xbe ' & & cli_readint32 ( epbuff + 1 ) - EC32 ( optional_hdr32 . ImageBase ) < min ) {
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
/* FSG support - v. 1.33 (thx trog for the many samples) */
2004-07-06 02:27:22 +00:00
2007-09-04 00:38:30 +00:00
int sectcnt = 0 ;
char * support ;
2007-09-13 11:26:26 +00:00
uint32_t newesi , newedi , oldep , gp , t ;
2007-09-04 00:38:30 +00:00
struct cli_exe_section * sections ;
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
ssize = exe_sections [ i + 1 ] . rsz ;
dsize = exe_sections [ i ] . vsz ;
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
CLI_UNPSIZELIMITS ( " FSG " , MAX ( dsize , ssize ) ) ;
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
if ( ssize < = 0x19 | | dsize < = ssize ) {
cli_dbgmsg ( " FSG: Size mismatch (ssize: %d, dsize: %d) \n " , ssize , dsize ) ;
free ( exe_sections ) ;
return CL_CLEAN ;
}
2004-08-14 10:56:23 +00:00
2009-08-31 17:26:22 +02:00
if ( ! ( t = cli_rawaddr ( cli_readint32 ( epbuff + 1 ) - EC32 ( optional_hdr32 . ImageBase ) , NULL , 0 , & err , fsize , hdr_size ) ) & & err ) {
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " FSG: Support data out of padding area \n " ) ;
break ;
}
2004-08-14 10:56:23 +00:00
2009-08-31 17:26:22 +02:00
gp = exe_sections [ i + 1 ] . raw - t ;
2004-08-14 10:56:23 +00:00
2009-08-31 17:26:22 +02:00
CLI_UNPSIZELIMITS ( " FSG " , gp ) ;
2004-08-14 10:56:23 +00:00
2009-08-31 17:26:22 +02:00
if ( ! ( support = fmap_need_off_once ( map , t , gp ) ) ) {
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " Can't read %d bytes from padding area \n " , gp ) ;
free ( exe_sections ) ;
2009-02-12 13:53:23 +00:00
return CL_EREAD ;
2007-09-04 00:38:30 +00:00
}
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
/* newebx = cli_readint32(support) - EC32(optional_hdr32.ImageBase); Unused */
newedi = cli_readint32 ( support + 4 ) - EC32 ( optional_hdr32 . ImageBase ) ; /* 1st dest */
newesi = cli_readint32 ( support + 8 ) - EC32 ( optional_hdr32 . ImageBase ) ; /* Source */
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
if ( newesi < exe_sections [ i + 1 ] . rva | | newesi - exe_sections [ i + 1 ] . rva > = exe_sections [ i + 1 ] . rsz ) {
cli_dbgmsg ( " FSG: Source buffer out of section bounds \n " ) ;
break ;
}
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
if ( newedi ! = exe_sections [ i ] . rva ) {
cli_dbgmsg ( " FSG: Bad destination (is %x should be %x) \n " , newedi , exe_sections [ i ] . rva ) ;
break ;
}
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
/* Counting original sections */
for ( t = 12 ; t < gp - 4 ; t + = 4 ) {
uint32_t rva = cli_readint32 ( support + t ) ;
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
if ( ! rva )
break ;
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
rva - = EC32 ( optional_hdr32 . ImageBase ) + 1 ;
sectcnt + + ;
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
if ( rva % 0x1000 ) cli_dbgmsg ( " FSG: Original section %d is misaligned \n " , sectcnt ) ;
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
if ( rva < exe_sections [ i ] . rva | | rva - exe_sections [ i ] . rva > = exe_sections [ i ] . vsz ) {
cli_dbgmsg ( " FSG: Original section %d is out of bounds \n " , sectcnt ) ;
break ;
}
}
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
if ( t > = gp - 4 | | cli_readint32 ( support + t ) ) {
break ;
}
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
if ( ( sections = ( struct cli_exe_section * ) cli_malloc ( ( sectcnt + 1 ) * sizeof ( struct cli_exe_section ) ) ) = = NULL ) {
free ( exe_sections ) ;
return CL_EMEM ;
}
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
sections [ 0 ] . rva = newedi ;
for ( t = 1 ; t < = ( uint32_t ) sectcnt ; t + + )
sections [ t ] . rva = cli_readint32 ( support + 8 + t * 4 ) - 1 - EC32 ( optional_hdr32 . ImageBase ) ;
2004-08-14 10:56:23 +00:00
2009-08-31 17:26:22 +02:00
if ( ! exe_sections [ i + 1 ] . rsz | | ! ( src = fmap_need_off_once ( map , exe_sections [ i + 1 ] . raw , ssize ) ) ) {
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " Can't read raw data of section %d \n " , i ) ;
free ( exe_sections ) ;
free ( sections ) ;
2009-02-12 13:53:23 +00:00
return CL_EREAD ;
2007-09-04 00:38:30 +00:00
}
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
if ( ( dest = ( char * ) cli_calloc ( dsize , sizeof ( char ) ) ) = = NULL ) {
free ( exe_sections ) ;
free ( sections ) ;
return CL_EMEM ;
}
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
oldep = vep + 161 + 6 + cli_readint32 ( epbuff + 163 ) ;
cli_dbgmsg ( " FSG: found old EP @%x \n " , oldep ) ;
2004-08-14 10:56:23 +00:00
2009-08-31 17:26:22 +02:00
CLI_UNPTEMP ( " FSG " , ( dest , sections , exe_sections , 0 ) ) ;
CLI_UNPRESULTSFSG1 ( " FSG " , ( 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 ) ) , 1 , ( dest , sections , 0 ) ) ;
2007-09-04 00:38:30 +00:00
break ; /* were done with 1.33 */
}
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
while ( found & & ( DCONF & PE_CONF_FSG ) & & epbuff [ 0 ] = = ' \xbb ' & & cli_readint32 ( epbuff + 1 ) - EC32 ( optional_hdr32 . ImageBase ) < min & & epbuff [ 5 ] = = ' \xbf ' & & epbuff [ 10 ] = = ' \xbe ' & & vep > = exe_sections [ i + 1 ] . rva & & vep - exe_sections [ i + 1 ] . rva > exe_sections [ i + 1 ] . rva - 0xe0 ) {
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
/* FSG support - v. 1.31 */
2006-01-14 18:21:36 +00:00
2007-09-04 00:38:30 +00:00
int sectcnt = 0 ;
2009-08-31 17:26:22 +02:00
uint32_t gp , t = cli_rawaddr ( cli_readint32 ( epbuff + 1 ) - EC32 ( optional_hdr32 . ImageBase ) , NULL , 0 , & err , fsize , hdr_size ) ;
2007-09-04 00:38:30 +00:00
char * support ;
uint32_t newesi = cli_readint32 ( epbuff + 11 ) - EC32 ( optional_hdr32 . ImageBase ) ;
uint32_t newedi = cli_readint32 ( epbuff + 6 ) - EC32 ( optional_hdr32 . ImageBase ) ;
uint32_t oldep = vep - exe_sections [ i + 1 ] . rva ;
struct cli_exe_section * sections ;
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
ssize = exe_sections [ i + 1 ] . rsz ;
dsize = exe_sections [ i ] . vsz ;
2004-08-14 10:56:23 +00:00
2007-09-04 00:38:30 +00:00
if ( err ) {
cli_dbgmsg ( " FSG: Support data out of padding area \n " ) ;
break ;
2004-08-14 10:56:23 +00:00
}
2007-09-04 00:38:30 +00:00
if ( newesi < exe_sections [ i + 1 ] . rva | | newesi - exe_sections [ i + 1 ] . rva > = exe_sections [ i + 1 ] . raw ) {
cli_dbgmsg ( " FSG: Source buffer out of section bounds \n " ) ;
break ;
}
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
if ( newedi ! = exe_sections [ i ] . rva ) {
cli_dbgmsg ( " FSG: Bad destination (is %x should be %x) \n " , newedi , exe_sections [ i ] . rva ) ;
break ;
}
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
CLI_UNPSIZELIMITS ( " FSG " , MAX ( dsize , ssize ) ) ;
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
if ( ssize < = 0x19 | | dsize < = ssize ) {
cli_dbgmsg ( " FSG: Size mismatch (ssize: %d, dsize: %d) \n " , ssize , dsize ) ;
free ( exe_sections ) ;
return CL_CLEAN ;
}
2004-08-16 19:14:14 +00:00
2009-08-31 17:26:22 +02:00
gp = exe_sections [ i + 1 ] . raw - t ;
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
CLI_UNPSIZELIMITS ( " FSG " , gp )
2004-08-16 19:14:14 +00:00
2009-08-31 17:26:22 +02:00
if ( ! ( support = fmap_need_off_once ( map , t , gp ) ) ) {
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " Can't read %d bytes from padding area \n " , gp ) ;
free ( exe_sections ) ;
2009-02-12 13:53:23 +00:00
return CL_EREAD ;
2007-09-04 00:38:30 +00:00
}
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
/* Counting original sections */
for ( t = 0 ; t < gp - 2 ; t + = 2 ) {
uint32_t rva = support [ t ] | ( support [ t + 1 ] < < 8 ) ;
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
if ( rva = = 2 | | rva = = 1 )
break ;
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
rva = ( ( rva - 2 ) < < 12 ) - EC32 ( optional_hdr32 . ImageBase ) ;
sectcnt + + ;
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
if ( rva < exe_sections [ i ] . rva | | rva - exe_sections [ i ] . rva > = exe_sections [ i ] . vsz ) {
cli_dbgmsg ( " FSG: Original section %d is out of bounds \n " , sectcnt ) ;
break ;
}
}
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
if ( t > = gp - 10 | | cli_readint32 ( support + t + 6 ) ! = 2 ) {
break ;
}
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
if ( ( sections = ( struct cli_exe_section * ) cli_malloc ( ( sectcnt + 1 ) * sizeof ( struct cli_exe_section ) ) ) = = NULL ) {
free ( exe_sections ) ;
return CL_EMEM ;
}
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
sections [ 0 ] . rva = newedi ;
for ( t = 0 ; t < = ( uint32_t ) sectcnt - 1 ; t + + ) {
sections [ t + 1 ] . rva = ( ( ( support [ t * 2 ] | ( support [ t * 2 + 1 ] < < 8 ) ) - 2 ) < < 12 ) - EC32 ( optional_hdr32 . ImageBase ) ;
}
2004-08-16 19:14:14 +00:00
2009-08-31 17:26:22 +02:00
if ( ! exe_sections [ i + 1 ] . rsz | | ! ( src = fmap_need_off_once ( map , exe_sections [ i + 1 ] . raw , ssize ) ) ) {
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " FSG: Can't read raw data of section %d \n " , i ) ;
free ( exe_sections ) ;
free ( sections ) ;
2009-02-12 13:53:23 +00:00
return CL_EREAD ;
2007-09-04 00:38:30 +00:00
}
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
if ( ( dest = ( char * ) cli_calloc ( dsize , sizeof ( char ) ) ) = = NULL ) {
free ( exe_sections ) ;
free ( sections ) ;
return CL_EMEM ;
}
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
gp = 0xda + 6 * ( epbuff [ 16 ] = = ' \xe8 ' ) ;
oldep = vep + gp + 6 + cli_readint32 ( src + gp + 2 + oldep ) ;
cli_dbgmsg ( " FSG: found old EP @%x \n " , oldep ) ;
2004-08-16 19:14:14 +00:00
2009-08-31 17:26:22 +02:00
CLI_UNPTEMP ( " FSG " , ( dest , sections , exe_sections , 0 ) ) ;
CLI_UNPRESULTSFSG1 ( " FSG " , ( 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 ) ) , 1 , ( dest , sections , 0 ) ) ;
2007-09-04 00:38:30 +00:00
break ; /* were done with 1.31 */
}
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
if ( found & & ( DCONF & PE_CONF_UPX ) ) {
2006-01-14 18:21:36 +00:00
2007-09-04 00:38:30 +00:00
/* UPX support */
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
/* we assume (i + 1) is UPX1 */
ssize = exe_sections [ i + 1 ] . rsz ;
dsize = exe_sections [ i ] . vsz + exe_sections [ i + 1 ] . vsz ;
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
CLI_UNPSIZELIMITS ( " UPX " , MAX ( dsize , ssize ) ) ;
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
if ( ssize < = 0x19 | | dsize < = ssize | | dsize > CLI_MAX_ALLOCATION ) {
cli_dbgmsg ( " UPX: Size mismatch or dsize too big (ssize: %d, dsize: %d) \n " , ssize , dsize ) ;
free ( exe_sections ) ;
return CL_CLEAN ;
2004-08-16 19:14:14 +00:00
}
2010-01-15 15:06:33 +02:00
if ( ! exe_sections [ i + 1 ] . rsz | | ! ( src = fmap_need_off_once ( map , exe_sections [ i + 1 ] . raw , ssize ) ) ) {
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " UPX: Can't read raw data of section %d \n " , i + 1 ) ;
free ( exe_sections ) ;
2009-02-12 13:53:23 +00:00
return CL_EREAD ;
2007-09-04 00:38:30 +00:00
}
2004-08-16 19:14:14 +00:00
2007-09-04 00:38:30 +00:00
if ( ( dest = ( char * ) cli_calloc ( dsize + 8192 , sizeof ( char ) ) ) = = NULL ) {
free ( exe_sections ) ;
return CL_EMEM ;
}
2006-04-04 22:55:54 +00:00
2007-09-04 00:38:30 +00:00
/* try to detect UPX code */
if ( cli_memstr ( UPX_NRV2B , 24 , epbuff + 0x69 , 13 ) | | cli_memstr ( UPX_NRV2B , 24 , epbuff + 0x69 + 8 , 13 ) ) {
cli_dbgmsg ( " UPX: Looks like a NRV2B decompression routine \n " ) ;
upxfn = upx_inflate2b ;
} else if ( cli_memstr ( UPX_NRV2D , 24 , epbuff + 0x69 , 13 ) | | cli_memstr ( UPX_NRV2D , 24 , epbuff + 0x69 + 8 , 13 ) ) {
cli_dbgmsg ( " UPX: Looks like a NRV2D decompression routine \n " ) ;
upxfn = upx_inflate2d ;
} else if ( cli_memstr ( UPX_NRV2E , 24 , epbuff + 0x69 , 13 ) | | cli_memstr ( UPX_NRV2E , 24 , epbuff + 0x69 + 8 , 13 ) ) {
cli_dbgmsg ( " UPX: Looks like a NRV2E decompression routine \n " ) ;
upxfn = upx_inflate2e ;
}
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
if ( upxfn ) {
int skew = cli_readint32 ( epbuff + 2 ) - EC32 ( optional_hdr32 . ImageBase ) - exe_sections [ i + 1 ] . rva ;
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
if ( epbuff [ 1 ] ! = ' \xbe ' | | skew < = 0 | | skew > 0xfff ) { /* FIXME: legit skews?? */
skew = 0 ;
if ( upxfn ( src , ssize , dest , & dsize , exe_sections [ i ] . rva , exe_sections [ i + 1 ] . rva , vep ) > = 0 )
upx_success = 1 ;
2004-08-05 01:15:59 +00:00
2004-06-12 00:16:01 +00:00
} else {
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " UPX: UPX1 seems skewed by %d bytes \n " , skew ) ;
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 )
upx_success = 1 ;
2004-08-05 01:15:59 +00:00
}
2007-09-04 00:38:30 +00:00
if ( upx_success )
cli_dbgmsg ( " UPX: Successfully decompressed \n " ) ;
else
cli_dbgmsg ( " UPX: Preferred decompressor failed \n " ) ;
}
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
if ( ! upx_success & & upxfn ! = upx_inflate2b ) {
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 ) {
2004-12-03 00:28:16 +00:00
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " UPX: NRV2B decompressor failed \n " ) ;
} else {
upx_success = 1 ;
cli_dbgmsg ( " UPX: Successfully decompressed with NRV2B \n " ) ;
2004-08-05 01:15:59 +00:00
}
2007-09-04 00:38:30 +00:00
}
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
if ( ! upx_success & & upxfn ! = upx_inflate2d ) {
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 ) {
2004-12-03 00:28:16 +00:00
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " UPX: NRV2D decompressor failed \n " ) ;
} else {
upx_success = 1 ;
cli_dbgmsg ( " UPX: Successfully decompressed with NRV2D \n " ) ;
2004-08-05 01:15:59 +00:00
}
2007-09-04 00:38:30 +00:00
}
2004-08-05 01:15:59 +00:00
2007-09-04 00:38:30 +00:00
if ( ! upx_success & & upxfn ! = upx_inflate2e ) {
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 ) {
cli_dbgmsg ( " UPX: NRV2E decompressor failed \n " ) ;
} else {
upx_success = 1 ;
cli_dbgmsg ( " UPX: Successfully decompressed with NRV2E \n " ) ;
2004-07-05 23:50:55 +00:00
}
}
2004-06-12 00:16:01 +00:00
2008-08-01 00:31:29 +00:00
if ( cli_memstr ( UPX_LZMA2 , 20 , epbuff + 0x2f , 20 ) ) {
uint32_t strictdsize = cli_readint32 ( epbuff + 0x21 ) ;
if ( strictdsize < = dsize )
upx_success = upx_inflatelzma ( src , ssize , dest , & strictdsize , exe_sections [ i ] . rva , exe_sections [ i + 1 ] . rva , vep ) > = 0 ;
} else if ( cli_memstr ( UPX_LZMA1 , 20 , epbuff + 0x39 , 20 ) ) {
uint32_t strictdsize = cli_readint32 ( epbuff + 0x2b ) ;
if ( strictdsize < = dsize )
upx_success = upx_inflatelzma ( src , ssize , dest , & strictdsize , exe_sections [ i ] . rva , exe_sections [ i + 1 ] . rva , vep ) > = 0 ;
2008-07-31 02:17:25 +00:00
}
2007-09-04 00:38:30 +00:00
if ( ! upx_success ) {
cli_dbgmsg ( " UPX: All decompressors failed \n " ) ;
free ( dest ) ;
}
}
2006-01-14 18:21:36 +00:00
2007-09-04 00:38:30 +00:00
if ( upx_success ) {
free ( exe_sections ) ;
2004-06-12 00:16:01 +00:00
2007-09-20 23:21:01 +00:00
CLI_UNPTEMP ( " UPX/FSG " , ( dest , 0 ) ) ;
2004-12-03 00:28:16 +00:00
2007-09-04 00:38:30 +00:00
if ( ( unsigned int ) write ( ndesc , dest , dsize ) ! = dsize ) {
cli_dbgmsg ( " UPX/FSG: Can't write %d bytes \n " , dsize ) ;
free ( tempfile ) ;
2004-12-03 00:28:16 +00:00
free ( dest ) ;
2007-09-04 00:38:30 +00:00
close ( ndesc ) ;
2009-02-12 13:53:23 +00:00
return CL_EWRITE ;
2007-09-04 00:38:30 +00:00
}
2004-12-03 00:28:16 +00:00
2007-09-04 00:38:30 +00:00
free ( dest ) ;
lseek ( ndesc , 0 , SEEK_SET ) ;
2004-12-03 00:28:16 +00:00
2008-11-14 22:23:39 +00:00
if ( ctx - > engine - > keeptmp )
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " UPX/FSG: Decompressed data saved in %s \n " , tempfile ) ;
2004-06-12 00:16:01 +00:00
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " ***** Scanning decompressed file ***** \n " ) ;
if ( ( ret = cli_magic_scandesc ( ndesc , ctx ) ) = = CL_VIRUS ) {
2004-12-03 00:28:16 +00:00
close ( ndesc ) ;
2007-09-04 00:38:30 +00:00
CLI_TMPUNLK ( ) ;
2004-12-03 00:28:16 +00:00
free ( tempfile ) ;
2007-09-04 00:38:30 +00:00
return CL_VIRUS ;
2004-08-05 01:15:59 +00:00
}
2007-09-04 00:38:30 +00:00
close ( ndesc ) ;
CLI_TMPUNLK ( ) ;
free ( tempfile ) ;
return ret ;
2004-06-12 00:16:01 +00:00
}
2004-06-11 20:17:18 +00:00
2004-08-02 17:09:06 +00:00
2007-09-04 00:38:30 +00:00
/* Petite */
2004-08-02 17:09:06 +00:00
2007-09-04 00:38:30 +00:00
if ( epsize < 200 ) {
2006-11-26 22:23:11 +00:00
free ( exe_sections ) ;
2007-09-04 00:38:30 +00:00
return CL_CLEAN ;
2004-08-04 20:11:18 +00:00
}
2004-08-02 17:09:06 +00:00
2007-09-04 00:38:30 +00:00
found = 2 ;
if ( epbuff [ 0 ] ! = ' \xb8 ' | | ( uint32_t ) cli_readint32 ( epbuff + 1 ) ! = exe_sections [ nsections - 1 ] . rva + EC32 ( optional_hdr32 . ImageBase ) ) {
if ( nsections < 2 | | epbuff [ 0 ] ! = ' \xb8 ' | | ( uint32_t ) cli_readint32 ( epbuff + 1 ) ! = exe_sections [ nsections - 2 ] . rva + EC32 ( optional_hdr32 . ImageBase ) )
2004-08-02 17:09:06 +00:00
found = 0 ;
else
found = 1 ;
}
2007-09-04 00:38:30 +00:00
if ( found & & ( DCONF & PE_CONF_PETITE ) ) {
2004-08-02 17:09:06 +00:00
cli_dbgmsg ( " Petite: v2.%d compression detected \n " , found ) ;
2007-09-04 00:38:30 +00:00
if ( cli_readint32 ( epbuff + 0x80 ) = = 0x163c988d ) {
2004-08-02 17:09:06 +00:00
cli_dbgmsg ( " Petite: level zero compression is not supported yet \n " ) ;
} else {
dsize = max - min ;
2007-09-04 00:38:30 +00:00
CLI_UNPSIZELIMITS ( " Petite " , dsize ) ;
2004-08-02 17:09:06 +00:00
if ( ( dest = ( char * ) cli_calloc ( dsize , sizeof ( char ) ) ) = = NULL ) {
cli_dbgmsg ( " Petite: Can't allocate %d bytes \n " , dsize ) ;
2006-11-26 22:23:11 +00:00
free ( exe_sections ) ;
2004-08-02 17:09:06 +00:00
return CL_EMEM ;
}
for ( i = 0 ; i < nsections ; i + + ) {
2007-03-14 15:48:19 +00:00
if ( exe_sections [ i ] . raw ) {
2009-08-31 17:26:22 +02:00
if ( ! exe_sections [ i ] . rsz | | fmap_readn ( map , dest + exe_sections [ i ] . rva - min , exe_sections [ i ] . raw , exe_sections [ i ] . ursz ) ! = exe_sections [ i ] . ursz ) {
2006-11-26 22:23:11 +00:00
free ( exe_sections ) ;
2004-08-14 12:29:08 +00:00
free ( dest ) ;
2008-04-06 11:16:07 +00:00
return CL_CLEAN ;
2004-08-14 12:29:08 +00:00
}
}
2004-08-02 17:09:06 +00:00
}
2007-09-20 23:21:01 +00:00
CLI_UNPTEMP ( " Petite " , ( dest , exe_sections , 0 ) ) ;
CLI_UNPRESULTS ( " Petite " , ( petite_inflate2x_1to9 ( dest , min , max - min , exe_sections , nsections - ( found = = 1 ? 1 : 0 ) , EC32 ( optional_hdr32 . ImageBase ) , vep , ndesc , found , EC32 ( optional_hdr32 . DataDirectory [ 2 ] . VirtualAddress ) , EC32 ( optional_hdr32 . DataDirectory [ 2 ] . Size ) ) ) , 0 , ( dest , 0 ) ) ;
2004-08-02 17:09:06 +00:00
}
}
2005-08-05 00:59:37 +00:00
/* PESpin 1.1 */
2007-01-09 20:06:51 +00:00
if ( ( DCONF & PE_CONF_PESPIN ) & & nsections > 1 & &
2007-03-14 14:50:05 +00:00
vep > = exe_sections [ nsections - 1 ] . rva & &
vep < exe_sections [ nsections - 1 ] . rva + exe_sections [ nsections - 1 ] . rsz - 0x3217 - 4 & &
2007-09-04 00:38:30 +00:00
memcmp ( epbuff + 4 , " \xe8 \x00 \x00 \x00 \x00 \x8b \x1c \x24 \x83 \xc3 " , 10 ) = = 0 ) {
2005-08-05 00:59:37 +00:00
2007-09-04 00:38:30 +00:00
char * spinned ;
2006-10-25 02:35:25 +00:00
2007-09-04 00:38:30 +00:00
CLI_UNPSIZELIMITS ( " PEspin " , fsize ) ;
2005-08-05 00:59:37 +00:00
2006-01-14 18:21:36 +00:00
if ( ( spinned = ( char * ) cli_malloc ( fsize ) ) = = NULL ) {
2006-11-26 22:23:11 +00:00
free ( exe_sections ) ;
2005-08-05 00:59:37 +00:00
return CL_EMEM ;
}
2009-08-31 17:26:22 +02:00
if ( ( size_t ) fmap_readn ( map , spinned , 0 , fsize ) ! = fsize ) {
2008-01-05 02:43:07 +00:00
cli_dbgmsg ( " PESpin: Can't read %lu bytes \n " , ( unsigned long ) fsize ) ;
2005-08-05 00:59:37 +00:00
free ( spinned ) ;
2006-11-26 22:23:11 +00:00
free ( exe_sections ) ;
2009-02-12 13:53:23 +00:00
return CL_EREAD ;
2005-08-05 00:59:37 +00:00
}
2007-09-20 23:21:01 +00:00
CLI_UNPTEMP ( " PESpin " , ( spinned , exe_sections , 0 ) ) ;
CLI_UNPRESULTS_ ( " PEspin " , SPINCASE ( ) , ( unspin ( spinned , fsize , exe_sections , nsections - 1 , vep , ndesc , ctx ) ) , 0 , ( spinned , 0 ) ) ;
2005-08-05 00:59:37 +00:00
}
2007-03-14 17:42:55 +00:00
2006-01-14 13:58:35 +00:00
2009-07-15 19:42:01 +03:00
/* yC 1.3 & variants */
2009-12-18 16:27:33 +02:00
if ( ( DCONF & PE_CONF_YC ) & & nsections > 1 & &
2009-07-15 19:42:01 +03:00
( EC32 ( optional_hdr32 . AddressOfEntryPoint ) = = exe_sections [ nsections - 1 ] . rva + 0x60 ) ) {
uint32_t ecx = 0 ;
int16_t offset ;
/* yC 1.3 */
if ( ! memcmp ( epbuff , " \x55 \x8B \xEC \x53 \x56 \x57 \x60 \xE8 \x00 \x00 \x00 \x00 \x5D \x81 \xED " , 15 ) & &
! memcmp ( epbuff + 0x26 , " \x8D \x3A \x8B \xF7 \x33 \xC0 \xEB \x04 \x90 \xEB \x01 \xC2 \xAC " , 13 ) & &
( ( uint8_t ) epbuff [ 0x13 ] = = 0xB9 ) & &
( ( uint16_t ) ( cli_readint16 ( epbuff + 0x18 ) ) = = 0xE981 ) & &
! memcmp ( epbuff + 0x1e , " \x8B \xD5 \x81 \xC2 " , 4 ) ) {
offset = 0 ;
if ( 0x6c - cli_readint32 ( epbuff + 0xf ) + cli_readint32 ( epbuff + 0x22 ) = = 0xC6 )
ecx = cli_readint32 ( epbuff + 0x14 ) - cli_readint32 ( epbuff + 0x1a ) ;
}
/* yC 1.3 variant */
if ( ! ecx & & ! memcmp ( epbuff , " \x55 \x8B \xEC \x83 \xEC \x40 \x53 \x56 \x57 " , 9 ) & &
! memcmp ( epbuff + 0x17 , " \xe8 \x00 \x00 \x00 \x00 \x5d \x81 \xed " , 8 ) & &
( ( uint8_t ) epbuff [ 0x23 ] = = 0xB9 ) ) {
offset = 0x10 ;
if ( 0x6c - cli_readint32 ( epbuff + 0x1f ) + cli_readint32 ( epbuff + 0x32 ) = = 0xC6 )
ecx = cli_readint32 ( epbuff + 0x24 ) - cli_readint32 ( epbuff + 0x2a ) ;
}
/* yC 1.x/modified */
if ( ! ecx & & ! memcmp ( epbuff , " \x60 \xe8 \x00 \x00 \x00 \x00 \x5d \x81 \xed " , 9 ) & &
( ( uint8_t ) epbuff [ 0xd ] = = 0xb9 ) & &
( ( uint16_t ) cli_readint16 ( epbuff + 0x12 ) = = 0xbd8d ) & &
! memcmp ( epbuff + 0x18 , " \x8b \xf7 \xac " , 3 ) ) {
offset = - 0x18 ;
if ( 0x66 - cli_readint32 ( epbuff + 0x9 ) + cli_readint32 ( epbuff + 0x14 ) = = 0xae )
ecx = cli_readint32 ( epbuff + 0xe ) ;
}
if ( ecx > 0x800 & & ecx < 0x2000 & &
! memcmp ( epbuff + 0x63 + offset , " \xaa \xe2 \xcc " , 3 ) & &
( fsize > = exe_sections [ nsections - 1 ] . raw + 0xC6 + ecx + offset ) ) {
2006-01-14 13:58:35 +00:00
2007-09-04 00:38:30 +00:00
char * spinned ;
2006-01-14 13:58:35 +00:00
2007-09-04 00:38:30 +00:00
if ( ( spinned = ( char * ) cli_malloc ( fsize ) ) = = NULL ) {
2006-11-26 22:23:11 +00:00
free ( exe_sections ) ;
2006-01-14 13:58:35 +00:00
return CL_EMEM ;
2007-09-04 00:38:30 +00:00
}
2006-01-14 13:58:35 +00:00
2009-08-31 17:26:22 +02:00
if ( ( size_t ) fmap_readn ( map , spinned , 0 , fsize ) ! = fsize ) {
2008-01-05 02:43:07 +00:00
cli_dbgmsg ( " yC: Can't read %lu bytes \n " , ( unsigned long ) fsize ) ;
2006-01-14 13:58:35 +00:00
free ( spinned ) ;
2006-11-26 22:23:11 +00:00
free ( exe_sections ) ;
2009-02-12 13:53:23 +00:00
return CL_EREAD ;
2006-01-14 13:58:35 +00:00
}
2007-09-04 00:38:30 +00:00
2009-12-08 23:02:49 +02:00
cli_dbgmsg ( " %d,%d,%d,%d \n " , nsections - 1 , e_lfanew , ecx , offset ) ;
2007-09-20 23:21:01 +00:00
CLI_UNPTEMP ( " yC " , ( spinned , exe_sections , 0 ) ) ;
2009-07-15 19:42:01 +03:00
CLI_UNPRESULTS ( " yC " , ( yc_decrypt ( spinned , fsize , exe_sections , nsections - 1 , e_lfanew , ndesc , ecx , offset ) ) , 0 , ( spinned , 0 ) ) ;
}
2006-01-14 13:58:35 +00:00
}
2006-07-16 19:49:42 +00:00
/* WWPack */
2007-12-13 19:45:38 +00:00
while ( ( DCONF & PE_CONF_WWPACK ) & & nsections > 1 & &
2006-11-26 22:23:11 +00:00
vep = = exe_sections [ nsections - 1 ] . rva & &
2007-09-04 00:38:30 +00:00
memcmp ( epbuff , " \x53 \x55 \x8b \xe8 \x33 \xdb \xeb " , 7 ) = = 0 & &
memcmp ( epbuff + 0x68 , " \xe8 \x00 \x00 \x00 \x00 \x58 \x2d \x6d \x00 \x00 \x00 \x50 \x60 \x33 \xc9 \x50 \x58 \x50 \x50 " , 19 ) = = 0 ) {
2007-12-13 19:45:38 +00:00
uint32_t head = exe_sections [ nsections - 1 ] . raw ;
uint8_t * packer ;
2006-07-16 19:49:42 +00:00
2007-12-13 19:45:38 +00:00
ssize = 0 ;
for ( i = 0 ; ; i + + ) {
2009-07-15 19:42:01 +03:00
if ( exe_sections [ i ] . raw < head )
2007-12-13 19:45:38 +00:00
head = exe_sections [ i ] . raw ;
2008-11-07 18:49:47 +00:00
if ( i + 1 = = nsections ) break ;
2007-12-13 19:45:38 +00:00
if ( ssize < exe_sections [ i ] . rva + exe_sections [ i ] . vsz )
ssize = exe_sections [ i ] . rva + exe_sections [ i ] . vsz ;
}
if ( ! head | | ! ssize | | head > ssize ) break ;
2006-07-16 19:49:42 +00:00
2007-12-13 19:45:38 +00:00
CLI_UNPSIZELIMITS ( " WWPack " , ssize ) ;
2006-07-16 19:49:42 +00:00
2007-12-13 19:45:38 +00:00
if ( ! ( src = ( char * ) cli_calloc ( ssize , sizeof ( char ) ) ) ) {
2007-09-04 00:38:30 +00:00
free ( exe_sections ) ;
return CL_EMEM ;
}
2009-08-31 17:26:22 +02:00
if ( ( size_t ) fmap_readn ( map , src , 0 , head ) ! = head ) {
2007-12-13 19:45:38 +00:00
cli_dbgmsg ( " WWPack: Can't read %d bytes from headers \n " , head ) ;
free ( src ) ;
2006-11-26 22:23:11 +00:00
free ( exe_sections ) ;
2009-02-12 13:53:23 +00:00
return CL_EREAD ;
2006-07-16 19:49:42 +00:00
}
2007-12-13 19:45:38 +00:00
for ( i = 0 ; i < ( unsigned int ) nsections - 1 ; i + + ) {
if ( ! exe_sections [ i ] . rsz ) continue ;
if ( ! CLI_ISCONTAINED ( src , ssize , src + exe_sections [ i ] . rva , exe_sections [ i ] . rsz ) ) break ;
2009-08-31 17:26:22 +02:00
if ( fmap_readn ( map , src + exe_sections [ i ] . rva , exe_sections [ i ] . raw , exe_sections [ i ] . rsz ) ! = exe_sections [ i ] . rsz ) break ;
2007-12-13 19:45:38 +00:00
}
2008-11-07 18:49:47 +00:00
if ( i + 1 ! = nsections ) {
2007-12-13 19:45:38 +00:00
cli_dbgmsg ( " WWpack: Probably hacked/damaged file. \n " ) ;
free ( src ) ;
break ;
}
2008-01-05 02:43:07 +00:00
if ( ( packer = ( uint8_t * ) cli_calloc ( exe_sections [ nsections - 1 ] . rsz , sizeof ( char ) ) ) = = NULL ) {
2007-12-13 19:45:38 +00:00
free ( src ) ;
2007-09-04 00:38:30 +00:00
free ( exe_sections ) ;
return CL_EMEM ;
}
2009-08-31 17:26:22 +02:00
if ( ! exe_sections [ nsections - 1 ] . rsz | | ( size_t ) fmap_readn ( map , packer , exe_sections [ nsections - 1 ] . raw , exe_sections [ nsections - 1 ] . rsz ) ! = exe_sections [ nsections - 1 ] . rsz ) {
2007-09-04 00:38:30 +00:00
cli_dbgmsg ( " WWPack: Can't read %d bytes from wwpack sect \n " , exe_sections [ nsections - 1 ] . rsz ) ;
2007-12-13 19:45:38 +00:00
free ( src ) ;
free ( packer ) ;
2007-09-04 00:38:30 +00:00
free ( exe_sections ) ;
2009-02-12 13:53:23 +00:00
return CL_EREAD ;
2007-09-04 00:38:30 +00:00
}
2007-12-13 19:45:38 +00:00
CLI_UNPTEMP ( " WWPack " , ( src , packer , exe_sections , 0 ) ) ;
2008-01-05 02:43:07 +00:00
CLI_UNPRESULTS ( " WWPack " , ( wwunpack ( ( uint8_t * ) src , ssize , packer , exe_sections , nsections - 1 , e_lfanew , ndesc ) ) , 0 , ( src , packer , 0 ) ) ;
2007-12-13 19:45:38 +00:00
break ;
2006-07-16 19:49:42 +00:00
}
2007-09-04 00:38:30 +00:00
2007-06-17 20:55:02 +00:00
/* ASPACK support */
2007-09-04 00:38:30 +00:00
while ( ( DCONF & PE_CONF_ASPACK ) & & ep + 58 + 0x70e < fsize & & ! memcmp ( epbuff , " \x60 \xe8 \x03 \x00 \x00 \x00 \xe9 \xeb " , 8 ) ) {
2007-06-17 20:55:02 +00:00
2007-09-04 00:38:30 +00:00
if ( epsize < 0x3bf | | memcmp ( epbuff + 0x3b9 , " \x68 \x00 \x00 \x00 \x00 \xc3 " , 6 ) ) break ;
2007-06-17 20:55:02 +00:00
ssize = 0 ;
for ( i = 0 ; i < nsections ; i + + )
2007-09-04 00:38:30 +00:00
if ( ssize < exe_sections [ i ] . rva + exe_sections [ i ] . vsz )
ssize = exe_sections [ i ] . rva + exe_sections [ i ] . vsz ;
2007-06-17 20:55:02 +00:00
if ( ! ssize ) break ;
2007-09-04 00:38:30 +00:00
CLI_UNPSIZELIMITS ( " Aspack " , ssize ) ;
2007-06-17 20:55:02 +00:00
if ( ! ( src = ( char * ) cli_calloc ( ssize , sizeof ( char ) ) ) ) {
free ( exe_sections ) ;
return CL_EMEM ;
}
for ( i = 0 ; i < ( unsigned int ) nsections ; i + + ) {
if ( ! exe_sections [ i ] . rsz ) continue ;
if ( ! CLI_ISCONTAINED ( src , ssize , src + exe_sections [ i ] . rva , exe_sections [ i ] . rsz ) ) break ;
2009-08-31 17:26:22 +02:00
if ( fmap_readn ( map , src + exe_sections [ i ] . rva , exe_sections [ i ] . raw , exe_sections [ i ] . rsz ) ! = exe_sections [ i ] . rsz ) break ;
2007-06-17 20:55:02 +00:00
}
if ( i ! = nsections ) {
cli_dbgmsg ( " Aspack: Probably hacked/damaged Aspack file. \n " ) ;
free ( src ) ;
break ;
}
2007-09-20 23:21:01 +00:00
CLI_UNPTEMP ( " Aspack " , ( src , exe_sections , 0 ) ) ;
CLI_UNPRESULTS ( " Aspack " , ( unaspack212 ( ( uint8_t * ) src , ssize , exe_sections , nsections , vep - 1 , EC32 ( optional_hdr32 . ImageBase ) , ndesc ) ) , 1 , ( src , 0 ) ) ;
2007-06-17 20:55:02 +00:00
break ;
}
2006-10-25 02:35:25 +00:00
/* NsPack */
2007-01-09 20:06:51 +00:00
while ( DCONF & PE_CONF_NSPACK ) {
2007-09-04 00:38:30 +00:00
uint32_t eprva = vep ;
uint32_t start_of_stuff , ssize , dsize , rep = ep ;
unsigned int nowinldr ;
2009-08-31 17:26:22 +02:00
char * nbuff ;
2007-09-15 16:27:05 +00:00
char * src = epbuff , * dest ;
2007-09-04 00:38:30 +00:00
if ( * epbuff = = ' \xe9 ' ) { /* bitched headers */
eprva = cli_readint32 ( epbuff + 1 ) + vep + 5 ;
if ( ! ( rep = cli_rawaddr ( eprva , exe_sections , nsections , & err , fsize , hdr_size ) ) & & err ) break ;
2009-08-31 17:26:22 +02:00
if ( ! ( nbuff = fmap_need_off_once ( map , rep , 24 ) ) ) break ;
2007-09-04 00:38:30 +00:00
src = nbuff ;
}
if ( memcmp ( src , " \x9c \x60 \xe8 \x00 \x00 \x00 \x00 \x5d \xb8 \x07 \x00 \x00 \x00 " , 13 ) ) break ;
nowinldr = 0x54 - cli_readint32 ( src + 17 ) ;
cli_dbgmsg ( " NsPack: Found *start_of_stuff @delta-%x \n " , nowinldr ) ;
2009-08-31 17:26:22 +02:00
if ( ! ( nbuff = fmap_need_off_once ( map , rep - nowinldr , 4 ) ) ) break ;
2007-09-04 00:38:30 +00:00
start_of_stuff = rep + cli_readint32 ( nbuff ) ;
2009-08-31 17:26:22 +02:00
if ( ! ( nbuff = fmap_need_off_once ( map , start_of_stuff , 20 ) ) ) break ;
2006-11-26 22:23:11 +00:00
src = nbuff ;
2007-09-04 00:38:30 +00:00
if ( ! cli_readint32 ( nbuff ) ) {
start_of_stuff + = 4 ; /* FIXME: more to do */
src + = 4 ;
}
2006-10-25 02:35:25 +00:00
2007-09-04 00:38:30 +00:00
ssize = cli_readint32 ( src + 5 ) | 0xff ;
dsize = cli_readint32 ( src + 9 ) ;
2006-10-25 02:35:25 +00:00
2007-09-04 00:38:30 +00:00
CLI_UNPSIZELIMITS ( " NsPack " , MAX ( ssize , dsize ) ) ;
2006-10-25 02:35:25 +00:00
2009-08-31 17:26:22 +02:00
if ( ! ssize | | ! dsize | | dsize ! = exe_sections [ 0 ] . vsz ) break ;
2007-09-04 00:38:30 +00:00
if ( ! ( dest = cli_malloc ( dsize ) ) ) break ;
/* memset(dest, 0xfc, dsize); */
2006-10-25 02:35:25 +00:00
2009-08-31 17:26:22 +02:00
if ( ! ( src = fmap_need_off ( map , start_of_stuff , ssize ) ) ) {
2007-09-04 00:38:30 +00:00
free ( dest ) ;
break ;
2006-10-25 02:35:25 +00:00
}
2007-09-04 00:38:30 +00:00
/* memset(src, 0x00, ssize); */
2006-10-25 02:35:25 +00:00
2007-09-04 00:38:30 +00:00
eprva + = 0x27a ;
if ( ! ( rep = cli_rawaddr ( eprva , exe_sections , nsections , & err , fsize , hdr_size ) ) & & err ) {
free ( dest ) ;
break ;
}
2009-08-31 17:26:22 +02:00
if ( ! ( nbuff = fmap_need_off_once ( map , rep , 5 ) ) ) {
2007-09-04 00:38:30 +00:00
free ( dest ) ;
break ;
}
2009-08-31 17:26:22 +02:00
fmap_unneed_off ( map , start_of_stuff , ssize ) ;
2007-09-04 00:38:30 +00:00
eprva = eprva + 5 + cli_readint32 ( nbuff + 1 ) ;
cli_dbgmsg ( " NsPack: OEP = %08x \n " , eprva ) ;
2006-10-25 02:35:25 +00:00
2009-08-31 17:26:22 +02:00
CLI_UNPTEMP ( " NsPack " , ( dest , exe_sections , 0 ) ) ;
CLI_UNPRESULTS ( " NsPack " , ( unspack ( src , dest , ctx , exe_sections [ 0 ] . rva , EC32 ( optional_hdr32 . ImageBase ) , eprva , ndesc ) ) , 0 , ( dest , 0 ) ) ;
2006-10-25 02:35:25 +00:00
break ;
}
2006-07-16 19:49:42 +00:00
2004-05-11 23:30:57 +00:00
/* to be continued ... */
2009-10-02 17:33:11 +03:00
/* Bytecode */
bc_ctx = cli_bytecode_context_alloc ( ) ;
if ( ! bc_ctx ) {
cli_errmsg ( " cli_scanpe: can't allocate memory for bc_ctx \n " ) ;
return CL_EMEM ;
}
pedata . exe_info . section = exe_sections ;
pedata . exe_info . nsections = nsections ;
pedata . exe_info . ep = ep ;
2009-12-11 20:43:58 +02:00
pedata . exe_info . offset = 0 ;
2009-10-02 17:33:11 +03:00
pedata . file_hdr = & file_hdr ;
pedata . opt32 = & pe_opt . opt32 ;
pedata . opt64 = & pe_opt . opt64 ;
pedata . dirs = dirs ;
2009-12-04 16:45:48 +02:00
pedata . e_lfanew = e_lfanew ;
2009-10-02 17:33:11 +03:00
pedata . overlays = overlays ;
pedata . overlays_sz = fsize - overlays ;
2010-01-18 19:31:59 +02:00
pedata . hdr_size = hdr_size ;
2009-10-02 17:33:11 +03:00
cli_bytecode_context_setpe ( bc_ctx , & pedata ) ;
2009-12-02 17:13:07 +02:00
cli_bytecode_context_setctx ( bc_ctx , ctx ) ;
2009-12-03 11:37:38 +02:00
ret = cli_bytecode_runhook ( ctx - > engine , bc_ctx , BC_PE_UNPACKER , map , ctx - > virname ) ;
2009-12-02 17:13:07 +02:00
switch ( ret ) {
case CL_VIRUS :
return CL_VIRUS ;
case CL_SUCCESS :
ndesc = cli_bytecode_context_getresult_file ( bc_ctx , & tempfile ) ;
cli_bytecode_context_destroy ( bc_ctx ) ;
if ( ndesc ! = - 1 ) {
CLI_UNPRESULTS ( " bytecode PE hook " , 1 , 1 , ( 0 ) ) ;
}
break ;
default :
cli_bytecode_context_destroy ( bc_ctx ) ;
}
2009-10-02 17:33:11 +03:00
2006-11-26 22:23:11 +00:00
free ( exe_sections ) ;
2004-06-12 00:16:01 +00:00
return CL_CLEAN ;
2004-05-11 23:30:57 +00:00
}
2004-08-27 00:19:44 +00:00
2009-10-02 18:09:31 +02:00
int cli_peheader ( fmap_t * map , struct cli_exe_info * peinfo )
2004-08-27 00:19:44 +00:00
{
uint16_t e_magic ; /* DOS signature ("MZ") */
uint32_t e_lfanew ; /* address of new exe header */
2006-11-26 22:23:11 +00:00
/* Obsolete - see below
uint32_t min = 0 , max = 0 ;
*/
2004-08-27 00:19:44 +00:00
struct pe_image_file_hdr file_hdr ;
2006-11-26 22:23:11 +00:00
union {
struct pe_image_optional_hdr64 opt64 ;
struct pe_image_optional_hdr32 opt32 ;
} pe_opt ;
2004-08-27 00:19:44 +00:00
struct pe_image_section_hdr * section_hdr ;
int i ;
2005-11-26 22:39:01 +00:00
unsigned int err , pe_plus = 0 ;
2007-03-19 00:35:27 +00:00
uint32_t valign , falign , hdr_size ;
2006-11-26 22:23:11 +00:00
size_t fsize ;
2009-09-01 13:49:36 +02:00
ssize_t at ;
2010-01-04 14:56:04 +01:00
struct pe_image_data_dir * dirs ;
2004-08-27 00:19:44 +00:00
cli_dbgmsg ( " in cli_peheader \n " ) ;
2009-09-01 13:49:36 +02:00
fsize = map - > len - peinfo - > offset ;
if ( fmap_readn ( map , & e_magic , peinfo - > offset , sizeof ( e_magic ) ) ! = sizeof ( e_magic ) ) {
2004-08-27 00:19:44 +00:00
cli_dbgmsg ( " Can't read DOS signature \n " ) ;
2009-09-01 13:49:36 +02:00
return CL_CLEAN ;
2004-08-27 00:19:44 +00:00
}
2009-10-31 19:12:50 +01:00
if ( EC16 ( e_magic ) ! = PE_IMAGE_DOS_SIGNATURE & & EC16 ( e_magic ) ! = PE_IMAGE_DOS_SIGNATURE_OLD ) {
2004-08-27 00:19:44 +00:00
cli_dbgmsg ( " Invalid DOS signature \n " ) ;
return - 1 ;
}
2009-09-01 13:49:36 +02:00
if ( fmap_readn ( map , & e_lfanew , peinfo - > offset + 58 + sizeof ( e_magic ) , sizeof ( e_lfanew ) ) ! = sizeof ( e_lfanew ) ) {
2004-08-27 00:19:44 +00:00
/* truncated header? */
return - 1 ;
}
e_lfanew = EC32 ( e_lfanew ) ;
if ( ! e_lfanew ) {
cli_dbgmsg ( " Not a PE file \n " ) ;
return - 1 ;
}
2009-09-01 13:49:36 +02:00
if ( fmap_readn ( map , & file_hdr , peinfo - > offset + e_lfanew , sizeof ( struct pe_image_file_hdr ) ) ! = sizeof ( struct pe_image_file_hdr ) ) {
2004-08-27 00:19:44 +00:00
/* bad information in e_lfanew - probably not a PE file */
cli_dbgmsg ( " Can't read file header \n " ) ;
return - 1 ;
}
2009-10-31 19:17:22 +01:00
if ( EC32 ( file_hdr . Magic ) ! = PE_IMAGE_NT_SIGNATURE ) {
2004-08-27 00:19:44 +00:00
cli_dbgmsg ( " Invalid PE signature (probably NE file) \n " ) ;
return - 1 ;
}
2007-03-19 00:35:27 +00:00
if ( ( peinfo - > nsections = EC16 ( file_hdr . NumberOfSections ) ) < 1 | | peinfo - > nsections > 96 ) return - 1 ;
2005-11-26 22:39:01 +00:00
2006-11-26 22:23:11 +00:00
if ( EC16 ( file_hdr . SizeOfOptionalHeader ) < sizeof ( struct pe_image_optional_hdr32 ) ) {
cli_dbgmsg ( " SizeOfOptionalHeader too small \n " ) ;
return - 1 ;
}
2009-09-01 13:49:36 +02:00
at = peinfo - > offset + e_lfanew + sizeof ( struct pe_image_file_hdr ) ;
if ( fmap_readn ( map , & optional_hdr32 , at , sizeof ( struct pe_image_optional_hdr32 ) ) ! = sizeof ( struct pe_image_optional_hdr32 ) ) {
2006-11-26 22:23:11 +00:00
cli_dbgmsg ( " Can't read optional file header \n " ) ;
return - 1 ;
}
2009-09-01 13:49:36 +02:00
at + = sizeof ( struct pe_image_optional_hdr32 ) ;
2006-11-26 22:23:11 +00:00
2009-07-31 12:52:41 +02:00
if ( EC16 ( optional_hdr64 . Magic ) = = PE32P_SIGNATURE ) { /* PE+ */
2006-11-26 22:23:11 +00:00
if ( EC16 ( file_hdr . SizeOfOptionalHeader ) ! = sizeof ( struct pe_image_optional_hdr64 ) ) {
cli_dbgmsg ( " Incorrect SizeOfOptionalHeader for PE32+ \n " ) ;
2005-11-26 22:39:01 +00:00
return - 1 ;
}
2009-09-01 13:49:36 +02:00
if ( fmap_readn ( map , & optional_hdr32 + 1 , at , sizeof ( struct pe_image_optional_hdr64 ) - sizeof ( struct pe_image_optional_hdr32 ) ) ! = sizeof ( struct pe_image_optional_hdr64 ) - sizeof ( struct pe_image_optional_hdr32 ) ) {
2006-11-26 22:23:11 +00:00
cli_dbgmsg ( " Can't read optional file header \n " ) ;
2005-11-26 22:39:01 +00:00
return - 1 ;
}
2009-09-01 13:49:36 +02:00
at + = sizeof ( struct pe_image_optional_hdr64 ) - sizeof ( struct pe_image_optional_hdr32 ) ;
2007-03-19 00:35:27 +00:00
hdr_size = EC32 ( optional_hdr64 . SizeOfHeaders ) ;
pe_plus = 1 ;
} else { /* PE */
if ( EC16 ( file_hdr . SizeOfOptionalHeader ) ! = sizeof ( struct pe_image_optional_hdr32 ) ) {
/* Seek to the end of the long header */
2009-09-01 13:49:36 +02:00
at + = EC16 ( file_hdr . SizeOfOptionalHeader ) - sizeof ( struct pe_image_optional_hdr32 ) ;
2007-03-19 00:35:27 +00:00
}
hdr_size = EC32 ( optional_hdr32 . SizeOfHeaders ) ;
2004-08-27 00:19:44 +00:00
}
2006-11-26 22:23:11 +00:00
valign = ( pe_plus ) ? EC32 ( optional_hdr64 . SectionAlignment ) : EC32 ( optional_hdr32 . SectionAlignment ) ;
falign = ( pe_plus ) ? EC32 ( optional_hdr64 . FileAlignment ) : EC32 ( optional_hdr32 . FileAlignment ) ;
2007-03-19 20:00:13 +00:00
hdr_size = PESALIGN ( hdr_size , valign ) ;
2007-03-19 00:35:27 +00:00
2005-09-18 23:19:28 +00:00
peinfo - > section = ( struct cli_exe_section * ) cli_calloc ( peinfo - > nsections , sizeof ( struct cli_exe_section ) ) ;
2004-08-27 00:19:44 +00:00
2004-09-17 23:29:44 +00:00
if ( ! peinfo - > section ) {
2004-08-27 00:19:44 +00:00
cli_dbgmsg ( " Can't allocate memory for section headers \n " ) ;
return - 1 ;
}
2004-09-17 23:29:44 +00:00
section_hdr = ( struct pe_image_section_hdr * ) cli_calloc ( peinfo - > nsections , sizeof ( struct pe_image_section_hdr ) ) ;
2004-08-27 00:19:44 +00:00
if ( ! section_hdr ) {
cli_dbgmsg ( " Can't allocate memory for section headers \n " ) ;
2004-09-17 23:29:44 +00:00
free ( peinfo - > section ) ;
2006-11-20 00:03:16 +00:00
peinfo - > section = NULL ;
2004-08-27 00:19:44 +00:00
return - 1 ;
}
2009-09-01 13:49:36 +02:00
if ( fmap_readn ( map , section_hdr , at , peinfo - > nsections * sizeof ( struct pe_image_section_hdr ) ) ! = peinfo - > nsections * sizeof ( struct pe_image_section_hdr ) ) {
2007-03-19 00:35:27 +00:00
cli_dbgmsg ( " Can't read section header \n " ) ;
cli_dbgmsg ( " Possibly broken PE file \n " ) ;
free ( section_hdr ) ;
free ( peinfo - > section ) ;
peinfo - > section = NULL ;
return - 1 ;
}
2009-09-01 13:49:36 +02:00
at + = sizeof ( struct pe_image_section_hdr ) * peinfo - > nsections ;
2004-08-27 00:19:44 +00:00
2007-03-19 00:35:27 +00:00
for ( i = 0 ; falign ! = 0x200 & & i < peinfo - > nsections ; i + + ) {
/* file alignment fallback mode - blah */
if ( falign & & section_hdr [ i ] . SizeOfRawData & & EC32 ( section_hdr [ i ] . PointerToRawData ) % falign & & ! ( EC32 ( section_hdr [ i ] . PointerToRawData ) % 0x200 ) ) {
falign = 0x200 ;
2004-08-27 00:19:44 +00:00
}
2007-03-19 00:35:27 +00:00
}
2004-08-27 00:19:44 +00:00
2007-03-19 00:35:27 +00:00
for ( i = 0 ; i < peinfo - > nsections ; i + + ) {
peinfo - > section [ i ] . rva = PEALIGN ( EC32 ( section_hdr [ i ] . VirtualAddress ) , valign ) ;
2006-11-26 22:23:11 +00:00
peinfo - > section [ i ] . vsz = PESALIGN ( EC32 ( section_hdr [ i ] . VirtualSize ) , valign ) ;
peinfo - > section [ i ] . raw = PEALIGN ( EC32 ( section_hdr [ i ] . PointerToRawData ) , falign ) ;
peinfo - > section [ i ] . rsz = PESALIGN ( EC32 ( section_hdr [ i ] . SizeOfRawData ) , falign ) ;
2007-03-19 00:35:27 +00:00
if ( ! peinfo - > section [ i ] . vsz & & peinfo - > section [ i ] . rsz )
peinfo - > section [ i ] . vsz = PESALIGN ( EC32 ( section_hdr [ i ] . SizeOfRawData ) , valign ) ;
2006-11-26 22:23:11 +00:00
if ( peinfo - > section [ i ] . rsz & & ! CLI_ISCONTAINED ( 0 , ( uint32_t ) fsize , peinfo - > section [ i ] . raw , peinfo - > section [ i ] . rsz ) )
peinfo - > section [ i ] . rsz = ( fsize - peinfo - > section [ i ] . raw ) * ( fsize > peinfo - > section [ i ] . raw ) ;
2005-07-19 20:36:38 +00:00
}
2005-03-18 21:06:25 +00:00
2010-01-04 14:56:04 +01:00
if ( pe_plus ) {
2005-11-26 22:39:01 +00:00
peinfo - > ep = EC32 ( optional_hdr64 . AddressOfEntryPoint ) ;
2010-01-04 14:56:04 +01:00
dirs = optional_hdr64 . DataDirectory ;
} else {
2005-11-26 22:39:01 +00:00
peinfo - > ep = EC32 ( optional_hdr32 . AddressOfEntryPoint ) ;
2010-01-04 14:56:04 +01:00
dirs = optional_hdr32 . DataDirectory ;
}
2005-11-26 22:39:01 +00:00
2007-03-19 00:35:27 +00:00
if ( ! ( peinfo - > ep = cli_rawaddr ( peinfo - > ep , peinfo - > section , peinfo - > nsections , & err , fsize , hdr_size ) ) & & err ) {
2006-11-26 22:23:11 +00:00
cli_dbgmsg ( " Broken PE file \n " ) ;
2004-08-27 00:19:44 +00:00
free ( section_hdr ) ;
2004-09-17 23:29:44 +00:00
free ( peinfo - > section ) ;
2006-11-20 00:03:16 +00:00
peinfo - > section = NULL ;
2004-08-27 00:19:44 +00:00
return - 1 ;
}
2010-01-05 02:32:43 +01:00
while ( dirs [ 2 ] . Size & & peinfo - > vinfo ) {
2010-01-05 01:01:48 +01:00
struct vinfo_list vlist ;
2010-01-04 14:56:04 +01:00
uint8_t * vptr , * baseptr ;
2010-01-05 01:01:48 +01:00
uint32_t rva , res_sz ;
unsigned int i ;
memset ( & vlist , 0 , sizeof ( vlist ) ) ;
findres ( 0x10 , 0xffffffff , EC32 ( dirs [ 2 ] . VirtualAddress ) , map , peinfo - > section , peinfo - > nsections , hdr_size , versioninfo_cb , & vlist ) ;
if ( ! vlist . count ) break ; /* No version_information */
if ( cli_hashset_init ( peinfo - > vinfo , 32 , 80 ) ) {
cli_errmsg ( " cli_peheader: Unable to init vinfo hashset \n " ) ;
free ( section_hdr ) ;
free ( peinfo - > section ) ;
peinfo - > section = NULL ;
return - 1 ;
}
2010-01-04 14:56:04 +01:00
2010-01-05 01:01:48 +01:00
err = 0 ;
for ( i = 0 ; i < vlist . count ; i + + ) { /* enum all version_information res - RESUMABLE */
2010-01-05 02:04:14 +01:00
cli_dbgmsg ( " cli_peheader: parsing version info @ rva %x (%u/%u) \n " , vlist . rvas [ i ] , i + 1 , vlist . count ) ;
2010-01-05 01:01:48 +01:00
rva = cli_rawaddr ( vlist . rvas [ i ] , peinfo - > section , peinfo - > nsections , & err , fsize , hdr_size ) ;
if ( err )
continue ;
2010-01-04 14:56:04 +01:00
2010-01-05 01:01:48 +01:00
if ( ! ( vptr = fmap_need_off_once ( map , rva , 16 ) ) )
continue ;
2010-01-04 14:56:04 +01:00
2010-01-05 01:01:48 +01:00
baseptr = vptr - rva ;
/* parse resource */
rva = cli_readint32 ( vptr ) ; /* ptr to version_info */
res_sz = cli_readint32 ( vptr + 4 ) ; /* sizeof(resource) */
rva = cli_rawaddr ( rva , peinfo - > section , peinfo - > nsections , & err , fsize , hdr_size ) ;
if ( err )
continue ;
if ( ! ( vptr = fmap_need_off_once ( map , rva , res_sz ) ) )
continue ;
while ( res_sz > 4 ) { /* look for version_info - NOT RESUMABLE (expecting exactly one versioninfo) */
uint32_t vinfo_sz , vinfo_val_sz ;
vinfo_sz = vinfo_val_sz = cli_readint32 ( vptr ) ;
vinfo_sz & = 0xffff ;
if ( vinfo_sz > res_sz )
break ; /* the content is larger than the container */
vinfo_val_sz > > = 16 ;
if ( vinfo_sz < = 6 + 0x20 + 2 + 0x34 | |
vinfo_val_sz ! = 0x34 | |
memcmp ( vptr + 6 , " V \0 S \0 _ \0 V \0 E \0 R \0 S \0 I \0 O \0 N \0 _ \0 I \0 N \0 F \0 O \0 \0 \0 " , 0x20 ) | |
cli_readint32 ( vptr + 0x28 ) ! = 0xfeef04bd ) {
/* - there should be enough room for the header(6), the key "VS_VERSION_INFO"(20), the padding(2) and the value(34)
* - the value should be sizeof ( fixedfileinfo )
* - the key should match
* - there should be some proper magic for fixedfileinfo */
break ; /* there's no point in looking further */
2010-01-04 14:56:04 +01:00
}
2010-01-05 01:01:48 +01:00
/* move to the end of fixedfileinfo where the child elements are located */
vptr + = 6 + 0x20 + 2 + 0x34 ;
vinfo_sz - = 6 + 0x20 + 2 + 0x34 ;
while ( vinfo_sz > 6 ) { /* look for stringfileinfo - NOT RESUMABLE (expecting at most one stringfileinfo) */
uint32_t sfi_sz = cli_readint32 ( vptr ) & 0xffff ;
2010-01-04 14:56:04 +01:00
2010-01-05 01:01:48 +01:00
if ( sfi_sz > vinfo_sz )
break ; /* the content is larger than the container */
2010-01-04 14:56:04 +01:00
2010-01-05 01:01:48 +01:00
/* expecting stringfileinfo to always precede varfileinfo */
if ( sfi_sz < = 6 + 0x1e | | memcmp ( vptr + 6 , " S \0 t \0 r \0 i \0 n \0 g \0 F \0 i \0 l \0 e \0 I \0 n \0 f \0 o \0 \0 \0 " , 0x1e ) ) {
/* - there should be enough room for the header(6) and the key "StringFileInfo"(1e)
* - the key should match */
break ; /* this is an implicit hard fail: parent is not resumable */
2010-01-04 14:56:04 +01:00
}
2010-01-05 01:01:48 +01:00
/* move to the end of stringfileinfo where the child elements are located */
vptr + = 6 + 0x1e ;
sfi_sz - = 6 + 0x1e ;
2010-01-04 14:56:04 +01:00
2010-01-05 01:01:48 +01:00
while ( sfi_sz > 6 ) { /* enum all stringtables - RESUMABLE */
uint32_t st_sz = cli_readint32 ( vptr ) & 0xffff ;
2010-01-04 14:56:04 +01:00
2010-01-05 01:01:48 +01:00
if ( st_sz > sfi_sz | | st_sz < = 24 ) {
2010-01-04 14:56:04 +01:00
/* - the content is larger than the container
2010-01-05 01:01:48 +01:00
- there ' s no room for a stringtables ( headers ( 6 ) + key ( 16 ) + padding ( 2 ) ) */
break ; /* this is an implicit hard fail: parent is not resumable */
2010-01-04 14:56:04 +01:00
}
2010-01-05 01:01:48 +01:00
/* move to the end of stringtable where the child elements are located */
vptr + = 24 ;
st_sz - = 24 ;
while ( st_sz > 6 ) { /* enum all strings - RESUMABLE */
uint32_t s_sz , s_key_sz , s_val_sz ;
s_sz = s_val_sz = cli_readint32 ( vptr ) ;
s_sz & = 0xffff ;
s_val_sz = ( s_val_sz & 0xffff0000 ) > > 15 ;
if ( s_sz > st_sz | | s_sz < = 6 + 2 + 2 | | s_val_sz > s_sz - 6 - 2 - 2 ) {
/* - the content is larger than the container
* - there ' s no room for a minimal string ( headers ( 6 ) + key ( 2 ) + padding ( 2 ) )
* - there ' s no room for the value */
st_sz = 0 ;
sfi_sz = 0 ;
break ; /* force a hard fail */
}
if ( ! s_val_sz ) {
/* skip unset value */
vptr + = s_sz ;
st_sz - = s_sz ;
continue ;
}
/* ~wcstrlen(key) */
for ( s_key_sz = 0 ; s_key_sz < s_sz - 6 - s_val_sz ; s_key_sz + = 2 ) {
if ( vptr [ 6 + s_key_sz ] | | vptr [ 6 + s_key_sz + 1 ] ) continue ;
s_key_sz + = 2 ;
break ;
}
if ( s_key_sz > = s_sz - 6 - s_val_sz ) {
/* key overflow */
vptr + = s_sz ;
st_sz - = s_sz ;
continue ;
}
if ( cli_hashset_addkey ( peinfo - > vinfo , ( uint32_t ) ( vptr - baseptr + 6 ) ) ) {
cli_errmsg ( " cli_peheader: Unable to add rva to vinfo hashset \n " ) ;
cli_hashset_destroy ( peinfo - > vinfo ) ;
free ( section_hdr ) ;
free ( peinfo - > section ) ;
peinfo - > section = NULL ;
return - 1 ;
}
if ( cli_debug_flag ) {
2010-01-05 02:04:14 +01:00
char * k , * v , * s ;
/* FIXME: skip too long strings */
2010-01-05 01:01:48 +01:00
k = cli_utf16toascii ( vptr + 6 , s_key_sz ) ;
if ( k ) {
s_key_sz + = 6 + 3 ;
s_key_sz & = ~ 3 ;
v = cli_utf16toascii ( vptr + s_key_sz , s_val_sz ) ;
if ( v ) {
2010-01-05 02:04:14 +01:00
s = cli_str2hex ( vptr + 6 , s_key_sz + s_val_sz - 6 ) ;
if ( s ) {
2010-01-05 11:13:54 +01:00
cli_dbgmsg ( " VersionInfo (%x): '%s'='%s' - VI:%s \n " , ( uint32_t ) ( vptr - baseptr + 6 ) , k , v , s ) ;
2010-01-05 02:04:14 +01:00
free ( s ) ;
}
2010-01-05 01:01:48 +01:00
free ( v ) ;
}
free ( k ) ;
}
}
2010-01-04 14:56:04 +01:00
vptr + = s_sz ;
st_sz - = s_sz ;
2010-01-05 01:01:48 +01:00
} /* enum all strings - RESUMABLE */
vptr + = st_sz ;
sfi_sz - = st_sz ;
} /* enum all stringtables - RESUMABLE */
break ;
} /* look for stringfileinfo - NOT RESUMABLE */
break ;
} /* look for version_info - NOT RESUMABLE */
} /* enum all version_information res - RESUMABLE */
break ;
} /* while(dirs[2].Size) */
2010-01-04 14:56:04 +01:00
2004-08-27 00:19:44 +00:00
free ( section_hdr ) ;
return 0 ;
}