More whitespace changes

remotes/push_mirror/always-on-json^2
Shawn Webb 11 years ago
parent f98a68afe8
commit 017f34901b
  1. 685
      libclamav/pe.c

@ -111,8 +111,8 @@ if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) { \
#define CLI_TMPUNLK() if(!ctx->engine->keeptmp) { \
if (cli_unlink(tempfile)) { \
free(tempfile); \
return CL_EUNLINK; \
free(tempfile); \
return CL_EUNLINK; \
} \
}
@ -126,70 +126,70 @@ if((ndesc = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) { \
#define FSGCASE(NAME,FREESEC) \
case 0: /* Unpacked and NOT rebuilt */ \
cli_dbgmsg(NAME": Successfully decompressed\n"); \
close(ndesc); \
if (cli_unlink(tempfile)) { \
free(exe_sections); \
free(tempfile); \
FREESEC; \
return CL_EUNLINK; \
} \
free(tempfile); \
FREESEC; \
found = 0; \
upx_success = 1; \
break; /* FSG ONLY! - scan raw data after upx block */
cli_dbgmsg(NAME": Successfully decompressed\n"); \
close(ndesc); \
if (cli_unlink(tempfile)) { \
free(exe_sections); \
free(tempfile); \
FREESEC; \
return CL_EUNLINK; \
} \
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); \
if (cli_unlink(tempfile)) { \
free(exe_sections); \
free(tempfile); \
return CL_EUNLINK; \
} \
cli_dbgmsg("PESpin: Size exceeded\n"); \
free(tempfile); \
break; \
free(spinned); \
close(ndesc); \
if (cli_unlink(tempfile)) { \
free(exe_sections); \
free(tempfile); \
return CL_EUNLINK; \
} \
cli_dbgmsg("PESpin: Size exceeded\n"); \
free(tempfile); \
break; \
#define CLI_UNPRESULTS_(NAME,FSGSTUFF,EXPR,GOOD,FREEME) \
switch(EXPR) { \
case GOOD: /* Unpacked and rebuilt */ \
if(ctx->engine->keeptmp) \
cli_dbgmsg(NAME": Unpacked and rebuilt executable saved in %s\n", tempfile); \
else \
cli_dbgmsg(NAME": Unpacked and rebuilt executable\n"); \
cli_multifree FREEME; \
if(ctx->engine->keeptmp) \
cli_dbgmsg(NAME": Unpacked and rebuilt executable saved in %s\n", tempfile); \
else \
cli_dbgmsg(NAME": Unpacked and rebuilt executable\n"); \
cli_multifree FREEME; \
free(exe_sections); \
lseek(ndesc, 0, SEEK_SET); \
cli_dbgmsg("***** Scanning rebuilt PE file *****\n"); \
SHA_OFF; \
if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) { \
close(ndesc); \
CLI_TMPUNLK(); \
free(tempfile); \
SHA_RESET; \
return CL_VIRUS; \
} \
SHA_RESET; \
close(ndesc); \
CLI_TMPUNLK(); \
free(tempfile); \
return CL_CLEAN; \
lseek(ndesc, 0, SEEK_SET); \
cli_dbgmsg("***** Scanning rebuilt PE file *****\n"); \
SHA_OFF; \
if(cli_magic_scandesc(ndesc, ctx) == CL_VIRUS) { \
close(ndesc); \
CLI_TMPUNLK(); \
free(tempfile); \
SHA_RESET; \
return CL_VIRUS; \
} \
SHA_RESET; \
close(ndesc); \
CLI_TMPUNLK(); \
free(tempfile); \
return CL_CLEAN; \
\
FSGSTUFF; \
\
default: \
cli_dbgmsg(NAME": Unpacking failed\n"); \
close(ndesc); \
if (cli_unlink(tempfile)) { \
free(exe_sections); \
free(tempfile); \
cli_multifree FREEME; \
return CL_EUNLINK; \
} \
cli_multifree FREEME; \
cli_dbgmsg(NAME": Unpacking failed\n"); \
close(ndesc); \
if (cli_unlink(tempfile)) { \
free(exe_sections); \
free(tempfile); \
cli_multifree FREEME; \
return CL_EUNLINK; \
} \
cli_multifree FREEME; \
free(tempfile); \
}
@ -227,7 +227,7 @@ static int versioninfo_cb(void *opaque, uint32_t type, uint32_t name, uint32_t l
cli_dbgmsg("versioninfo_cb: type: %x, name: %x, lang: %x, rva: %x\n", type, name, lang, rva);
vlist->rvas[vlist->count] = rva;
if(++vlist->count == sizeof(vlist->rvas) / sizeof(vlist->rvas[0]))
return 1;
return 1;
return 0;
}
@ -238,24 +238,25 @@ uint32_t cli_rawaddr(uint32_t rva, const struct cli_exe_section *shp, uint16_t n
uint32_t ret;
if (rva<hdr_size) { /* Out of section EP - mapped to imagebase+rva */
if (rva >= fsize) {
*err=1;
return 0;
}
if (rva >= fsize) {
*err=1;
return 0;
}
*err=0;
return rva;
return rva;
}
for(i = nos-1; i >= 0; i--) {
if(shp[i].rsz && shp[i].rva <= rva && shp[i].rsz > rva - shp[i].rva) {
found = 1;
break;
}
found = 1;
break;
}
}
if(!found) {
*err = 1;
return 0;
*err = 1;
return 0;
}
ret = rva - shp[i].rva + shp[i].raw;
@ -263,61 +264,6 @@ uint32_t cli_rawaddr(uint32_t rva, const struct cli_exe_section *shp, uint16_t n
return ret;
}
/*
static int cli_ddump(int desc, int offset, int size, const char *file) {
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");
return -1;
}
if(lseek(desc, offset, SEEK_SET) == -1) {
cli_dbgmsg("lseek() failed\n");
lseek(desc, pos, SEEK_SET);
return -1;
}
if((ndesc = open(file, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
cli_dbgmsg("Can't create file %s\n", file);
lseek(desc, pos, SEEK_SET);
return -1;
}
while((bread = cli_readn(desc, buff, FILEBUFF)) > 0) {
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);
cli_unlink(file);
return -1;
}
break;
} else {
if(write(ndesc, buff, bread) == -1) {
cli_dbgmsg("Can't write to file\n");
lseek(desc, pos, SEEK_SET);
close(ndesc);
cli_unlink(file);
return -1;
}
}
sum += bread;
}
close(ndesc);
lseek(desc, pos, SEEK_SET);
return 0;
}
*/
/*
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
@ -2885,91 +2831,94 @@ int cli_scanpe(cli_ctx *ctx)
int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo)
{
uint16_t e_magic; /* DOS signature ("MZ") */
uint32_t e_lfanew; /* address of new exe header */
/* Obsolete - see below
uint32_t min = 0, max = 0;
*/
struct pe_image_file_hdr file_hdr;
union {
struct pe_image_optional_hdr64 opt64;
struct pe_image_optional_hdr32 opt32;
} pe_opt;
struct pe_image_section_hdr *section_hdr;
unsigned int i;
unsigned int err, pe_plus = 0;
uint32_t valign, falign, hdr_size;
size_t fsize;
ssize_t at;
struct pe_image_data_dir *dirs;
uint16_t e_magic; /* DOS signature ("MZ") */
uint32_t e_lfanew; /* address of new exe header */
/* Obsolete - see below
uint32_t min = 0, max = 0;
*/
struct pe_image_file_hdr file_hdr;
union {
struct pe_image_optional_hdr64 opt64;
struct pe_image_optional_hdr32 opt32;
} pe_opt;
struct pe_image_section_hdr *section_hdr;
unsigned int i;
unsigned int err, pe_plus = 0;
uint32_t valign, falign, hdr_size;
size_t fsize;
ssize_t at;
struct pe_image_data_dir *dirs;
cli_dbgmsg("in cli_peheader\n");
fsize = map->len - peinfo->offset;
if(fmap_readn(map, &e_magic, peinfo->offset, sizeof(e_magic)) != sizeof(e_magic)) {
cli_dbgmsg("Can't read DOS signature\n");
return -1;
cli_dbgmsg("Can't read DOS signature\n");
return -1;
}
if(EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE && EC16(e_magic) != PE_IMAGE_DOS_SIGNATURE_OLD) {
cli_dbgmsg("Invalid DOS signature\n");
return -1;
cli_dbgmsg("Invalid DOS signature\n");
return -1;
}
if(fmap_readn(map, &e_lfanew, peinfo->offset + 58 + sizeof(e_magic), sizeof(e_lfanew)) != sizeof(e_lfanew)) {
/* truncated header? */
return -1;
/* truncated header? */
return -1;
}
e_lfanew = EC32(e_lfanew);
if(!e_lfanew) {
cli_dbgmsg("Not a PE file\n");
return -1;
cli_dbgmsg("Not a PE file\n");
return -1;
}
if(fmap_readn(map, &file_hdr, peinfo->offset + e_lfanew, sizeof(struct pe_image_file_hdr)) != sizeof(struct pe_image_file_hdr)) {
/* bad information in e_lfanew - probably not a PE file */
cli_dbgmsg("Can't read file header\n");
return -1;
/* bad information in e_lfanew - probably not a PE file */
cli_dbgmsg("Can't read file header\n");
return -1;
}
if(EC32(file_hdr.Magic) != PE_IMAGE_NT_SIGNATURE) {
cli_dbgmsg("Invalid PE signature (probably NE file)\n");
return -1;
cli_dbgmsg("Invalid PE signature (probably NE file)\n");
return -1;
}
if ( (peinfo->nsections = EC16(file_hdr.NumberOfSections)) < 1 || peinfo->nsections > 96 ) return -1;
if (EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) {
cli_dbgmsg("SizeOfOptionalHeader too small\n");
return -1;
return -1;
}
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)) {
cli_dbgmsg("Can't read optional file header\n");
return -1;
return -1;
}
at += sizeof(struct pe_image_optional_hdr32);
if(EC16(optional_hdr64.Magic)==PE32P_SIGNATURE) { /* PE+ */
if(EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr64)) {
cli_dbgmsg("Incorrect SizeOfOptionalHeader for PE32+\n");
return -1;
}
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)) {
cli_dbgmsg("Can't read optional file header\n");
return -1;
}
at += sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32);
hdr_size = EC32(optional_hdr64.SizeOfHeaders);
pe_plus=1;
cli_dbgmsg("Incorrect SizeOfOptionalHeader for PE32+\n");
return -1;
}
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)) {
cli_dbgmsg("Can't read optional file header\n");
return -1;
}
at += sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32);
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 */
at += EC16(file_hdr.SizeOfOptionalHeader)-sizeof(struct pe_image_optional_hdr32);
}
hdr_size = EC32(optional_hdr32.SizeOfHeaders);
if (EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr32)) {
/* Seek to the end of the long header */
at += EC16(file_hdr.SizeOfOptionalHeader)-sizeof(struct pe_image_optional_hdr32);
}
hdr_size = EC32(optional_hdr32.SizeOfHeaders);
}
valign = (pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment);
@ -2980,249 +2929,253 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo)
peinfo->section = (struct cli_exe_section *) cli_calloc(peinfo->nsections, sizeof(struct cli_exe_section));
if(!peinfo->section) {
cli_dbgmsg("Can't allocate memory for section headers\n");
return -1;
cli_dbgmsg("Can't allocate memory for section headers\n");
return -1;
}
section_hdr = (struct pe_image_section_hdr *) cli_calloc(peinfo->nsections, sizeof(struct pe_image_section_hdr));
if(!section_hdr) {
cli_dbgmsg("Can't allocate memory for section headers\n");
free(peinfo->section);
peinfo->section = NULL;
return -1;
cli_dbgmsg("Can't allocate memory for section headers\n");
free(peinfo->section);
peinfo->section = NULL;
return -1;
}
if(fmap_readn(map, section_hdr, at, peinfo->nsections * sizeof(struct pe_image_section_hdr)) != peinfo->nsections * sizeof(struct pe_image_section_hdr)) {
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;
cli_dbgmsg("Possibly broken PE file\n");
free(section_hdr);
free(peinfo->section);
peinfo->section = NULL;
return -1;
}
at += sizeof(struct pe_image_section_hdr)*peinfo->nsections;
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;
}
/* 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;
}
}
for(i = 0; i < peinfo->nsections; i++) {
peinfo->section[i].rva = PEALIGN(EC32(section_hdr[i].VirtualAddress), valign);
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);
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);
if (!peinfo->section[i].vsz && peinfo->section[i].rsz)
peinfo->section[i].vsz=PESALIGN(EC32(section_hdr[i].SizeOfRawData), valign);
if (!peinfo->section[i].vsz && peinfo->section[i].rsz)
peinfo->section[i].vsz=PESALIGN(EC32(section_hdr[i].SizeOfRawData), valign);
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);
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);
}
if(pe_plus) {
peinfo->ep = EC32(optional_hdr64.AddressOfEntryPoint);
dirs = optional_hdr64.DataDirectory;
peinfo->ep = EC32(optional_hdr64.AddressOfEntryPoint);
dirs = optional_hdr64.DataDirectory;
} else {
peinfo->ep = EC32(optional_hdr32.AddressOfEntryPoint);
dirs = optional_hdr32.DataDirectory;
peinfo->ep = EC32(optional_hdr32.AddressOfEntryPoint);
dirs = optional_hdr32.DataDirectory;
}
if(!(peinfo->ep = cli_rawaddr(peinfo->ep, peinfo->section, peinfo->nsections, &err, fsize, hdr_size)) && err) {
cli_dbgmsg("Broken PE file\n");
free(section_hdr);
free(peinfo->section);
peinfo->section = NULL;
return -1;
cli_dbgmsg("Broken PE file\n");
free(section_hdr);
free(peinfo->section);
peinfo->section = NULL;
return -1;
}
if(EC16(file_hdr.Characteristics) & 0x2000 || !dirs[2].Size)
peinfo->res_addr = 0;
peinfo->res_addr = 0;
else
peinfo->res_addr = EC32(dirs[2].VirtualAddress);
peinfo->res_addr = EC32(dirs[2].VirtualAddress);
while(dirs[2].Size) {
struct vinfo_list vlist;
const uint8_t *vptr, *baseptr;
uint32_t rva, res_sz;
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;
}
struct vinfo_list vlist;
const uint8_t *vptr, *baseptr;
uint32_t rva, res_sz;
err = 0;
for(i=0; i<vlist.count; i++) { /* enum all version_information res - RESUMABLE */
cli_dbgmsg("cli_peheader: parsing version info @ rva %x (%u/%u)\n", vlist.rvas[i], i+1, vlist.count);
rva = cli_rawaddr(vlist.rvas[i], peinfo->section, peinfo->nsections, &err, fsize, hdr_size);
if(err)
continue;
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(!(vptr = fmap_need_off_once(map, rva, 16)))
continue;
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;
}
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, got_varfileinfo = 0;
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\0S\0_\0V\0E\0R\0S\0I\0O\0N\0_\0I\0N\0F\0O\0\0\0", 0x20) ||
(unsigned int)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 */
}
err = 0;
for(i=0; i<vlist.count; i++) { /* enum all version_information res - RESUMABLE */
cli_dbgmsg("cli_peheader: parsing version info @ rva %x (%u/%u)\n", vlist.rvas[i], i+1, vlist.count);
rva = cli_rawaddr(vlist.rvas[i], peinfo->section, peinfo->nsections, &err, fsize, hdr_size);
if(err)
continue;
/* move to the end of fixedfileinfo where the child elements are located */
vptr += 6 + 0x20 + 2 + 0x34;
vinfo_sz -= 6 + 0x20 + 2 + 0x34;
if(!(vptr = fmap_need_off_once(map, rva, 16)))
continue;
while(vinfo_sz > 6) { /* look for stringfileinfo - NOT RESUMABLE (expecting at most one stringfileinfo) */
uint32_t sfi_sz = cli_readint32(vptr) & 0xffff;
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, got_varfileinfo = 0;
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\0S\0_\0V\0E\0R\0S\0I\0O\0N\0_\0I\0N\0F\0O\0\0\0", 0x20) ||
(unsigned int)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 */
}
if(sfi_sz > vinfo_sz)
break; /* the content is larger than the container */
/* move to the end of fixedfileinfo where the child elements are located */
vptr += 6 + 0x20 + 2 + 0x34;
vinfo_sz -= 6 + 0x20 + 2 + 0x34;
if(!got_varfileinfo && sfi_sz > 6 + 0x18 && !memcmp(vptr+6, "V\0a\0r\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0", 0x18)) {
/* skip varfileinfo as it sometimes appear before stringtableinfo */
vptr += sfi_sz;
vinfo_sz -= sfi_sz;
got_varfileinfo = 1;
continue;
}
while(vinfo_sz > 6) { /* look for stringfileinfo - NOT RESUMABLE (expecting at most one stringfileinfo) */
uint32_t sfi_sz = cli_readint32(vptr) & 0xffff;
if(sfi_sz <= 6 + 0x1e || memcmp(vptr+6, "S\0t\0r\0i\0n\0g\0F\0i\0l\0e\0I\0n\0f\0o\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 */
}
if(sfi_sz > vinfo_sz)
break; /* the content is larger than the container */
/* move to the end of stringfileinfo where the child elements are located */
vptr += 6 + 0x1e;
sfi_sz -= 6 + 0x1e;
if(!got_varfileinfo && sfi_sz > 6 + 0x18 && !memcmp(vptr+6, "V\0a\0r\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0", 0x18)) {
/* skip varfileinfo as it sometimes appear before stringtableinfo */
vptr += sfi_sz;
vinfo_sz -= sfi_sz;
got_varfileinfo = 1;
continue;
}
while(sfi_sz > 6) { /* enum all stringtables - RESUMABLE */
uint32_t st_sz = cli_readint32(vptr) & 0xffff;
const uint8_t *next_vptr = vptr + st_sz;
uint32_t next_sfi_sz = sfi_sz - st_sz;
if(sfi_sz <= 6 + 0x1e || memcmp(vptr+6, "S\0t\0r\0i\0n\0g\0F\0i\0l\0e\0I\0n\0f\0o\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 */
}
if(st_sz > sfi_sz || st_sz <= 24) {
/* - the content is larger than the container
- there's no room for a stringtables (headers(6) + key(16) + padding(2)) */
break; /* this is an implicit hard fail: parent is not resumable */
}
/* move to the end of stringfileinfo where the child elements are located */
vptr += 6 + 0x1e;
sfi_sz -= 6 + 0x1e;
/* 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 = (cli_readint32(vptr) & 0xffff) + 3;
s_sz &= ~3;
if(s_sz > st_sz || s_sz <= 6 + 2 + 8) {
/* - the content is larger than the container
* - there's no room for a minimal string
* - there's no room for the value */
st_sz = 0;
sfi_sz = 0;
break; /* force a hard fail */
}
/* ~wcstrlen(key) */
for(s_key_sz = 6; s_key_sz+1 < s_sz; s_key_sz += 2) {
if(vptr[s_key_sz] || vptr[s_key_sz+1]) continue;
s_key_sz += 2;
break;
}
s_key_sz += 3;
s_key_sz &= ~3;
if(s_key_sz >= s_sz) {
/* key overflow */
vptr += s_sz;
st_sz -= s_sz;
continue;
}
s_val_sz = s_sz - s_key_sz;
s_key_sz -= 6;
if(s_val_sz <= 2) {
/* skip unset value */
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) {
char *k, *v, *s;
/* FIXME: skip too long strings */
k = cli_utf16toascii((const char*)vptr + 6, s_key_sz);
if(k) {
v = cli_utf16toascii((const char*)vptr + s_key_sz + 6, s_val_sz);
if(v) {
s = cli_str2hex((const char*)vptr + 6, s_key_sz + s_val_sz - 6);
if(s) {
cli_dbgmsg("VersionInfo (%x): '%s'='%s' - VI:%s\n", (uint32_t)(vptr - baseptr + 6), k, v, s);
free(s);
}
free(v);
}
free(k);
}
}
vptr += s_sz;
st_sz -= s_sz;
} /* enum all strings - RESUMABLE */
vptr = next_vptr;
sfi_sz = next_sfi_sz * (sfi_sz != 0);
} /* 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(sfi_sz > 6) { /* enum all stringtables - RESUMABLE */
uint32_t st_sz = cli_readint32(vptr) & 0xffff;
const uint8_t *next_vptr = vptr + st_sz;
uint32_t next_sfi_sz = sfi_sz - st_sz;
if(st_sz > sfi_sz || st_sz <= 24) {
/* - the content is larger than the container
- there's no room for a stringtables (headers(6) + key(16) + padding(2)) */
break; /* this is an implicit hard fail: parent is not resumable */
}
/* 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 = (cli_readint32(vptr) & 0xffff) + 3;
s_sz &= ~3;
if(s_sz > st_sz || s_sz <= 6 + 2 + 8) {
/* - the content is larger than the container
* - there's no room for a minimal string
* - there's no room for the value */
st_sz = 0;
sfi_sz = 0;
break; /* force a hard fail */
}
/* ~wcstrlen(key) */
for(s_key_sz = 6; s_key_sz+1 < s_sz; s_key_sz += 2) {
if(vptr[s_key_sz] || vptr[s_key_sz+1])
continue;
s_key_sz += 2;
break;
}
s_key_sz += 3;
s_key_sz &= ~3;
if(s_key_sz >= s_sz) {
/* key overflow */
vptr += s_sz;
st_sz -= s_sz;
continue;
}
s_val_sz = s_sz - s_key_sz;
s_key_sz -= 6;
if(s_val_sz <= 2) {
/* skip unset value */
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) {
char *k, *v, *s;
/* FIXME: skip too long strings */
k = cli_utf16toascii((const char*)vptr + 6, s_key_sz);
if(k) {
v = cli_utf16toascii((const char*)vptr + s_key_sz + 6, s_val_sz);
if(v) {
s = cli_str2hex((const char*)vptr + 6, s_key_sz + s_val_sz - 6);
if(s) {
cli_dbgmsg("VersionInfo (%x): '%s'='%s' - VI:%s\n", (uint32_t)(vptr - baseptr + 6), k, v, s);
free(s);
}
free(v);
}
free(k);
}
}
vptr += s_sz;
st_sz -= s_sz;
} /* enum all strings - RESUMABLE */
vptr = next_vptr;
sfi_sz = next_sfi_sz * (sfi_sz != 0);
} /* 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) */
free(section_hdr);

Loading…
Cancel
Save