1
0
mirror of https://github.com/upx/upx synced 2025-09-28 19:06:07 +08:00

pe: better icon compression handling

This commit is contained in:
László Molnár 2007-02-24 23:25:11 +01:00
parent 5b1c154ee2
commit fe53b135eb
2 changed files with 45 additions and 32 deletions

1
NEWS
View File

@ -6,6 +6,7 @@ Changes in 2.93 beta (XX XXX 2007):
* new formats Mach/i386 and Mach/fat support Mac OS X i686 and
Univeral binaries [i686 and PowerPC only]
* LZMA algorithm support for dos/exe added; use option '--lzma' to enable
* pe: better icon compression handling
Changes in 2.92 beta (23 Jan 2007):
* new option '--ultra-brute' which tries even more variants

View File

@ -50,18 +50,6 @@
# define strcpy(a,b) strcpy((char *)(a),(const char *)(b))
#endif
// Unicode string compare
static bool ustrsame(const void *s1, const void *s2)
{
unsigned len1 = get_le16(s1);
unsigned len2 = get_le16(s2);
if (len1 != len2)
return false;
return memcmp(s1, s2, 2 + 2*len1) == 0;
}
#if (__ACC_CXX_HAVE_PLACEMENT_DELETE) || defined(__DJGPP__)
#include "bptr.h"
#define IPTR(type, var) BoundedPtr<type> var(ibuf, ibuf.getSize())
@ -1245,6 +1233,12 @@ upx_byte *PeFile::Resource::build()
newstart = new upx_byte [dirsize()];
unsigned bpos = 0,spos = dsize;
build(root,bpos,spos,0);
// dirsize() is 4 bytes aligned, so we may need to zero
// up to 2 bytes to make valgrind happy
while (spos < dirsize())
newstart[spos++] = 0;
return newstart;
}
@ -1349,7 +1343,7 @@ static bool match(unsigned itype, const unsigned char *ntype,
if (unistr[2 + ic * 2] != (unsigned char) mkeep[ic])
return false;
return mkeep[ic] == 0 || mkeep[ic] == ',' || mkeep[ic] == '/';
};
}
};
// FIXME this comparison is not too exact
@ -1404,15 +1398,31 @@ void PeFile::processResources(Resource *res)
oresources = new upx_byte[soresources];
upx_byte *ores = oresources + res->dirsize();
char *keep_icons = NULL; // icon ids in the first icon group
unsigned iconsin1stdir = 0;
if (opt->win32_pe.compress_icons == 2)
while (res->next()) // there is no rewind() in Resource
if (res->itype() == RT_GROUP_ICON && iconsin1stdir == 0)
{
iconsin1stdir = get_le16(ibuf + res->offs() + 4);
keep_icons = new char[1 + iconsin1stdir * 9];
*keep_icons = 0;
for (unsigned ic = 0; ic < iconsin1stdir; ic++)
snprintf(keep_icons + strlen(keep_icons), 9, "3/%u,",
get_le16(ibuf + res->offs() + 6 + ic * 14 + 12));
if (*keep_icons)
keep_icons[strlen(keep_icons) - 1] = 0;
}
bool compress_icon = opt->win32_pe.compress_icons == 3;
bool compress_idir = false;
unsigned iconcnt = 0;
// the icon id which should not be compressed when compress_icons == 1
unsigned first_icon_id = (unsigned) -1;
if (opt->win32_pe.compress_icons == 1)
while (res->next())
if (res->itype() == RT_GROUP_ICON && first_icon_id == (unsigned) -1)
first_icon_id = get_le16(ibuf + res->offs() + 6 + 12);
bool compress_icon = opt->win32_pe.compress_icons > 1;
bool compress_idir = opt->win32_pe.compress_icons == 3;
// some statistics
unsigned usize = 0;
@ -1426,26 +1436,27 @@ void PeFile::processResources(Resource *res)
bool do_compress = true;
if (!opt->win32_pe.compress_resources)
do_compress = false;
else if (rtype == RT_VERSION) // version info
do_compress = false;
else if (rtype == RT_ICON) // icon
do_compress = compress_icon && opt->win32_pe.compress_icons;
{
if (opt->win32_pe.compress_icons == 0)
do_compress = false;
else if (opt->win32_pe.compress_icons == 1)
if ((first_icon_id == (unsigned) -1
|| first_icon_id == res->iname()))
do_compress = compress_icon;
}
else if (rtype == RT_GROUP_ICON) // icon directory
do_compress = compress_idir && opt->win32_pe.compress_icons;
else if (rtype > 0 && rtype < RT_LAST)
do_compress = opt->win32_pe.compress_rt[rtype] ? true : false;
else if (res->ntype()) // named resource type
{
const upx_byte * const t = res->ntype();
if (ustrsame(t, "\x7\x0T\x0Y\x0P\x0""E\x0L\x0I\x0""B\x0"))
do_compress = false; // u"TYPELIB"
else if (ustrsame(t, "\x8\x0R\x0""E\x0G\x0I\x0S\x0T\x0R\x0Y\x0"))
do_compress = false; // u"REGISTRY"
}
if (do_compress && opt->win32_pe.keep_resource[0])
do_compress ^= match(res->itype(), res->ntype(), res->iname(),
res->nname(), opt->win32_pe.keep_resource);
if (keep_icons)
do_compress &= !match(res->itype(), res->ntype(), res->iname(),
res->nname(), keep_icons);
do_compress &= !match(res->itype(), res->ntype(), res->iname(),
res->nname(), "TYPELIB,REGISTRY,16");
do_compress &= !match(res->itype(), res->ntype(), res->iname(),
res->nname(), opt->win32_pe.keep_resource);
if (do_compress)
{
@ -1463,8 +1474,8 @@ void PeFile::processResources(Resource *res)
memcpy(ores, ibuf + res->offs(), res->size());
ibuf.fill(res->offs(), res->size(), FILLVAL);
res->newoffs() = ptr_diff(ores,oresources);
if (rtype == RT_ICON)
compress_icon = (++iconcnt >= iconsin1stdir || opt->win32_pe.compress_icons == 1);
if (rtype == RT_ICON && opt->win32_pe.compress_icons == 1)
compress_icon = true;
else if (rtype == RT_GROUP_ICON)
{
if (opt->win32_pe.compress_icons == 1)
@ -1479,6 +1490,7 @@ void PeFile::processResources(Resource *res)
}
soresources = ptr_diff(ores,oresources);
delete[] keep_icons;
if (!res->clear())
{
// The area occupied by the resource directory is not continuous