From 3dfe0ad4784314adcbe077d7a12ba4d0fdb68a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20Moln=C3=A1r?= Date: Thu, 18 May 2006 15:20:37 +0200 Subject: [PATCH] pe: fined grain control over resource compression --- PROJECTS | 3 +-- TODO | 3 --- doc/upx.pod | 16 +++++++++++++++ src/main.cpp | 8 ++++++++ src/options.h | 1 + src/p_armpe.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++++- src/p_w32pe.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 129 insertions(+), 8 deletions(-) diff --git a/PROJECTS b/PROJECTS index dbf0a2d6..2309a17c 100644 --- a/PROJECTS +++ b/PROJECTS @@ -66,8 +66,7 @@ Existing formats: - win32/pe: display a nice dialog box in the stub in case of problems (like importing a DLL or function fails) - - win32/pe: finer control over resource compression, per section - compression + - win32/pe: per section compression Compression ratio: diff --git a/TODO b/TODO index bd4289ca..90459101 100644 --- a/TODO +++ b/TODO @@ -105,9 +105,6 @@ FORMAT WIN32/PE - decrease runtime memory overhead -2 - easy - mfx + ml) new switch(es) : do not compress resource types x,y,z - or resource names a,b,c - 3 - difficult) don't compress the BSS section and other holes. 4 - medium - ml) fix when objectalign < 0x1000 diff --git a/doc/upx.pod b/doc/upx.pod index b1c73380..7519fc39 100644 --- a/doc/upx.pod +++ b/doc/upx.pod @@ -870,6 +870,22 @@ Extra options available for this executable format: --compress-resources=0 Don't compress any resources at all. + --keep-resource=list Don't compress resources specified by the list. + The members of the list are separated by commas. + A list member has the following format: I. + I is the type of the resource. Standard types + must be specified as decimal numbers, user types can be + specified by decimal IDs or strings. I is the + identifier of the resource. It can be a decimal number + or a string. For example: + + --keep-resource=2/MYBITMAP,5,6/12345 + + UPX won't compress the named bitmap resource "MYBITMAP", + it leaves every dialog (5) resource uncompressed, and + it won't touch the string table resource with identifier + 12345. + --force Force compression even when there is an unexpected value in a header field. Use with care. diff --git a/src/main.cpp b/src/main.cpp index d7b9fbe3..58f18ddf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -72,6 +72,7 @@ void init_options(struct options_t *o) o->win32_pe.compress_rt[i] = -1; o->win32_pe.compress_rt[24] = false; // 24 == RT_MANIFEST o->win32_pe.strip_relocs = -1; + o->win32_pe.keep_resource = ""; } static struct options_t global_options; @@ -702,6 +703,11 @@ static int do_option(int optc, const char *arg) opt->win32_pe.strip_relocs = 0; //printf("strip_relocs: %d\n", opt->win32_pe.strip_relocs); break; + case 635: + if (!mfx_optarg || !mfx_optarg[0]) + e_optarg(arg); + opt->win32_pe.keep_resource = mfx_optarg; + break; case 650: opt->atari_tos.split_segments = true; break; @@ -859,6 +865,7 @@ static const struct mfx_option longopts[] = {"compress-resources", 2, 0, 632}, {"strip-loadconf", 0x12, 0, 633}, // OBSOLETE - IGNORED {"strip-relocs", 0x12, 0, 634}, + {"keep-resource", 0x31, 0, 635}, // ps1/exe {"boot-only", 0x10, 0, 670}, {"no-align", 0x10, 0, 671}, @@ -941,6 +948,7 @@ static const struct mfx_option longopts[] = {"compress-resources", 2, 0, 632}, {"strip-loadconf", 0x12, 0, 633}, // OBSOLETE - IGNORED {"strip-relocs", 0x12, 0, 634}, + {"keep-resource", 0x31, 0, 635}, { NULL, 0, NULL, 0 } }; diff --git a/src/options.h b/src/options.h index 086ad764..9fb0ff06 100644 --- a/src/options.h +++ b/src/options.h @@ -139,6 +139,7 @@ struct options_t { int compress_resources; signed char compress_rt[25]; // 25 == RT_LAST int strip_relocs; + const char *keep_resource; } win32_pe; }; diff --git a/src/p_armpe.cpp b/src/p_armpe.cpp index 748db942..7c870bdd 100644 --- a/src/p_armpe.cpp +++ b/src/p_armpe.cpp @@ -1218,10 +1218,10 @@ public: bool clear(); void dump() const { dump(root,0); } -/* unsigned iname() const {return current->parent->id;} const upx_byte *nname() const {return current->parent->name;} +/* unsigned ilang() const {return current->id;} const upx_byte *nlang() const {return current->name;} */ @@ -1420,6 +1420,52 @@ void PackArmPe::processResources(Resource *res,unsigned newaddr) delete [] p; } +static bool match(unsigned itype, const unsigned char *ntype, + unsigned iname, const unsigned char *nname, + const char *keep) +{ + // format of string keep: type1[/name1],type2[/name2], .... + // typex and namex can be string or number + // hopefully resource names do not have '/' or ',' characters inside + + struct helper + { + static bool match(unsigned num, const unsigned char *unistr, + const char *keep) + { + if (!unistr) + return (unsigned) atoi(keep) == num; + + unsigned ic; + for (ic = 0; ic < get_le16(unistr); ic++) + if (unistr[2 + ic * 2] != (unsigned char) keep[ic]) + return false; + return keep[ic] == 0 || keep[ic] == ',' || keep[ic] == '/'; + }; + }; + + // FIXME this comparison is not too exact + while (1) + { + char *delim1 = strchr(keep, '/'); + char *delim2 = strchr(keep, ','); + if (helper::match(itype, ntype, keep)) + { + if (!delim1) + return true; + if (delim2 && delim2 < delim1) + return true; + if (helper::match(iname, nname, delim1 + 1)) + return true; + } + + if (delim2 == NULL) + break; + keep = delim2 + 1; + } + return false; +} + void PackArmPe::processResources(Resource *res) { const unsigned vaddr = IDADDR(PEDIR_RESOURCE); @@ -1488,6 +1534,10 @@ void PackArmPe::processResources(Resource *res) 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 (do_compress) { csize += res->size(); diff --git a/src/p_w32pe.cpp b/src/p_w32pe.cpp index a793966c..541ad255 100644 --- a/src/p_w32pe.cpp +++ b/src/p_w32pe.cpp @@ -1178,10 +1178,10 @@ public: bool clear(); void dump() const { dump(root,0); } -/* + unsigned iname() const {return current->parent->id;} const upx_byte *nname() const {return current->parent->name;} - +/* unsigned ilang() const {return current->id;} const upx_byte *nlang() const {return current->name;} */ @@ -1380,6 +1380,52 @@ void PackW32Pe::processResources(Resource *res,unsigned newaddr) delete [] p; } +static bool match(unsigned itype, const unsigned char *ntype, + unsigned iname, const unsigned char *nname, + const char *keep) +{ + // format of string keep: type1[/name1],type2[/name2], .... + // typex and namex can be string or number + // hopefully resource names do not have '/' or ',' characters inside + + struct helper + { + static bool match(unsigned num, const unsigned char *unistr, + const char *keep) + { + if (!unistr) + return (unsigned) atoi(keep) == num; + + unsigned ic; + for (ic = 0; ic < get_le16(unistr); ic++) + if (unistr[2 + ic * 2] != (unsigned char) keep[ic]) + return false; + return keep[ic] == 0 || keep[ic] == ',' || keep[ic] == '/'; + }; + }; + + // FIXME this comparison is not too exact + while (1) + { + char *delim1 = strchr(keep, '/'); + char *delim2 = strchr(keep, ','); + if (helper::match(itype, ntype, keep)) + { + if (!delim1) + return true; + if (delim2 && delim2 < delim1) + return true; + if (helper::match(iname, nname, delim1 + 1)) + return true; + } + + if (delim2 == NULL) + break; + keep = delim2 + 1; + } + return false; +} + void PackW32Pe::processResources(Resource *res) { const unsigned vaddr = IDADDR(PEDIR_RESOURCE); @@ -1448,6 +1494,10 @@ void PackW32Pe::processResources(Resource *res) 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 (do_compress) { csize += res->size();