From 572314bf3fe624c1c3f46a65b419bb0ba75a18e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20Moln=C3=A1r?= Date: Fri, 9 Sep 2005 08:49:41 +0000 Subject: [PATCH] support for arm/WinCE ("arm/pe") exes committer: ml1050 1126255781 +0000 --- PROJECTS | 2 - README | 2 +- README.1ST | 1 + src/conf.h | 1 + src/p_armpe.cpp | 2052 ++++++++++++++++++++++++++++++++++++++++++ src/p_armpe.h | 251 ++++++ src/packmast.cpp | 3 + src/stub/.cvsignore | 2 + src/stub/Makefile | 22 +- src/stub/l_armpe.asm | 53 ++ src/stub/l_armpe.h | 100 ++ src/stub/l_armpe_c.c | 326 +++++++ src/stub/l_armpe_s.S | 17 + 13 files changed, 2827 insertions(+), 5 deletions(-) create mode 100644 src/p_armpe.cpp create mode 100644 src/p_armpe.h create mode 100644 src/stub/l_armpe.asm create mode 100644 src/stub/l_armpe.h create mode 100644 src/stub/l_armpe_c.c create mode 100644 src/stub/l_armpe_s.S diff --git a/PROJECTS b/PROJECTS index fe2ee1c9..5f31fe22 100644 --- a/PROJECTS +++ b/PROJECTS @@ -42,8 +42,6 @@ More formats: - freebsd/386 (generic), freebsd/elf386 (specialized). Probably could share most of the linux code. - - Windows CE - - add support for self-extracting HTML pages using a Javascript stub (like the AlgART HTML Packer "AHP") diff --git a/README b/README index cb200b7a..645dfcae 100644 --- a/README +++ b/README @@ -149,7 +149,7 @@ Markus & Laszlo Markus F.X.J. Oberhumer Laszlo Molnar - markus@oberhumer.com ml1050@cdata.tvnet.hu + markus@oberhumer.com ml1050@users.sourceforge.net diff --git a/README.1ST b/README.1ST index f56627a6..24bdab3f 100644 --- a/README.1ST +++ b/README.1ST @@ -30,4 +30,5 @@ The main news since 1.25 are: shell-to-memory decompression ("linux/sh386") - support for playstation exes ("ps1/exe") - lots of new bugs ;-) take care + - support for arm/WinCE ("arm/pe") exes diff --git a/src/conf.h b/src/conf.h index c87c9cfd..4b8700d7 100644 --- a/src/conf.h +++ b/src/conf.h @@ -454,6 +454,7 @@ inline void operator delete[](void *p) #define UPX_F_PS1_EXE 18 #define UPX_F_VMLINUX_i386 19 #define UPX_F_LINUX_ELFI_i386 20 +#define UPX_F_WINCE_ARM_PE 21 #define UPX_F_ATARI_TOS 129 #define UPX_F_SOLARIS_SPARC 130 diff --git a/src/p_armpe.cpp b/src/p_armpe.cpp new file mode 100644 index 00000000..94dd8d4c --- /dev/null +++ b/src/p_armpe.cpp @@ -0,0 +1,2052 @@ +/* p_armpe.cpp -- + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2004 Laszlo Molnar + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + 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; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer Laszlo Molnar + + */ + + +#include "conf.h" +#include "file.h" +#include "filter.h" +#include "packer.h" +#include "p_armpe.h" + +static const +#include "stub/l_armpe.h" + +#define IDSIZE(x) ih.ddirs[x].size +#define IDADDR(x) ih.ddirs[x].vaddr +#define ODSIZE(x) oh.ddirs[x].size +#define ODADDR(x) oh.ddirs[x].vaddr + +#define isdll ((ih.flags & DLL_FLAG) != 0) + +#define FILLVAL 0 + + +// Some defines to keep the namespace clean. +// It would be better to use inner classes except for Interval, which +// could be used elsewhere too. + +#define Interval PackArmPe_Interval +#define Reloc PackArmPe_Reloc +#define Resource PackArmPe_Resource +#define import_desc PackArmPe_import_desc +#define Export PackArmPe_Export +#define tls PackArmPe_tls + + +/************************************************************************* +// +**************************************************************************/ + +#if defined(__BORLANDC__) +# undef strcpy +# define strcpy(a,b) strcpy((char *)(a),(const char *)(b)) +#endif + +#if 1 +static unsigned my_strlen(const char *s) +{ + size_t l = strlen((const char*)s); assert((unsigned) l == l); return (unsigned) l; +} +static unsigned my_strlen(const unsigned char *s) +{ + size_t l = strlen((const char*)s); assert((unsigned) l == l); return (unsigned) l; +} +#undef strlen +#define strlen my_strlen +#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 var(ibuf, ibuf.getSize()) +#define OPTR(type, var) BoundedPtr var(obuf, obuf.getSize()) +#define IPTR_I(type, var, v) BoundedPtr var(ibuf, ibuf.getSize(), v) +#define OPTR_I(type, var, v) BoundedPtr var(obuf, obuf.getSize(), v) +#define IPTR_C(type, var, v) const BoundedPtr var(ibuf, ibuf.getSize(), v) +#define OPTR_C(type, var, v) const BoundedPtr var(obuf, obuf.getSize(), v) +#else +#define IPTR(type, var) type* var = 0 +#define OPTR(type, var) type* var = 0 +#define IPTR_I(type, var, v) type* var = (v) +#define OPTR_I(type, var, v) type* var = (v) +#define IPTR_C(type, var, v) type* const var = (v) +#define OPTR_C(type, var, v) type* const var = (v) +#endif + +static void xcheck(const void *p, size_t plen, const void *b, size_t blen) +{ + const char *pp = (const char *) p; + const char *bb = (const char *) b; + if (pp < bb || pp > bb + blen || pp + plen > bb + blen) + throwCantUnpack("pointer out of range; take care!"); +} +#if 0 +static void xcheck(size_t poff, size_t plen, const void *b, size_t blen) +{ + ACC_UNUSED(b); + if (poff > blen || poff + plen > blen) + throwCantUnpack("pointer out of range; take care!"); +} +#endif +#define ICHECK(x, size) xcheck(x, size, ibuf, ibuf.getSize()) +#define OCHECK(x, size) xcheck(x, size, obuf, obuf.getSize()) + +#define imemset(a,b,c) ICHECK(a,c), memset(a,b,c) +#define omemset(a,b,c) OCHECK(a,c), memset(a,b,c) +#define imemcpy(a,b,c) ICHECK(a,c), memcpy(a,b,c) +#define omemcpy(a,b,c) OCHECK(a,c), memcpy(a,b,c) + + +/************************************************************************* +// +**************************************************************************/ + +PackArmPe::PackArmPe(InputFile *f) : super(f) +{ + //printf("pe_header_t %d\n", (int) sizeof(pe_header_t)); + //printf("pe_section_t %d\n", (int) sizeof(pe_section_t)); + COMPILE_TIME_ASSERT(sizeof(pe_header_t) == 248); + COMPILE_TIME_ASSERT(sizeof(pe_section_t) == 40); + COMPILE_TIME_ASSERT(RT_LAST == TABLESIZE(opt->win32_pe.compress_rt)); + + isection = NULL; + oimport = NULL; + oimpdlls = NULL; + orelocs = NULL; + oexport = NULL; + otls = NULL; + oresources = NULL; + oxrelocs = NULL; + icondir_offset = 0; + icondir_count = 0; + importbyordinal = false; + kernel32ordinal = false; + tlsindex = 0; + big_relocs = 0; + soxrelocs = 0; +} + + +PackArmPe::~PackArmPe() +{ + delete [] isection; + delete [] orelocs; + delete [] oimport; + delete [] oimpdlls; + delete [] oexport; + delete [] otls; + delete [] oresources; + delete [] oxrelocs; + //delete res; +} + + +const int *PackArmPe::getCompressionMethods(int method, int level) const +{ + static const int m_nrv2e[] = { M_NRV2E_8, -1 }; + return m_nrv2e; +} + + +const int *PackArmPe::getFilters() const +{ + return 0; +} + + +bool PackArmPe::testUnpackVersion(int version) const +{ + if (version != ph_version && ph_version != -1) + throwCantUnpack("program has been modified; run a virus checker!"); + if (!canUnpackVersion(version)) + throwCantUnpack("this program is packed with an obsolete version and cannot be unpacked"); + return true; +} + + +/************************************************************************* +// util +**************************************************************************/ + +int PackArmPe::readFileHeader() +{ + struct exe_header_t + { + LE16 mz; + LE16 m512; + LE16 p512; + char _[18]; + LE16 relocoffs; + char __[34]; + LE32 nexepos; + } + __attribute_packed; + COMPILE_TIME_ASSERT(sizeof(exe_header_t) == 64); + + exe_header_t h; + int ic; + pe_offset = 0; + + for (ic = 0; ic < 20; ic++) + { + fi->seek(pe_offset,SEEK_SET); + fi->readx(&h,sizeof(h)); + + if (h.mz == 'M' + 'Z'*256) // dos exe + { + if (h.relocoffs >= 0x40) // new format exe + pe_offset += h.nexepos; + else + pe_offset += h.p512*512+h.m512 - h.m512 ? 512 : 0; + } + else if (get_le32(&h) == 'P' + 'E'*256) + break; + else + return 0; + } + if (ic == 20) + return 0; + fi->seek(pe_offset,SEEK_SET); + fi->readx(&ih,sizeof(ih)); + fi->seek(0x200,SEEK_SET); + fi->readx(&h,6); + return UPX_F_WINCE_ARM_PE; +} + + +/************************************************************************* +// interval handling +**************************************************************************/ + +class Interval +{ + unsigned capacity; + void *base; +public: + struct interval + { + unsigned start, len; + } *ivarr; + + unsigned ivnum; + + Interval(void *b) : capacity(0),base(b),ivarr(NULL),ivnum(0) {} + ~Interval() {free(ivarr);} + + void add(unsigned start,unsigned len); + void add(const void *start,unsigned len) {add(ptr_diff(start,base),len);} + void add(const void *start,const void *end) {add(ptr_diff(start,base),ptr_diff(end,start));} + void add(const Interval *iv); + void flatten(); + + void clear(); + void dump() const; + +private: + static int __acc_cdecl_qsort compare(const void *p1,const void *p2) + { + const interval *i1 = (const interval*) p1; + const interval *i2 = (const interval*) p2; + if (i1->start < i2->start) return -1; + if (i1->start > i2->start) return 1; + if (i1->len < i2->len) return 1; + if (i1->len > i2->len) return -1; + return 0; + } +}; + +void Interval::add(unsigned start,unsigned len) +{ + if (ivnum == capacity) + ivarr = (interval*) realloc(ivarr,(capacity += 15) * sizeof (interval)); + ivarr[ivnum].start = start; + ivarr[ivnum++].len = len; +} + +void Interval::add(const Interval *iv) +{ + for (unsigned ic = 0; ic < iv->ivnum; ic++) + add(iv->ivarr[ic].start,iv->ivarr[ic].len); +} + +void Interval::flatten() +{ + if (!ivnum) + return; + qsort(ivarr,ivnum,sizeof (interval),Interval::compare); + for (unsigned ic = 0; ic < ivnum - 1; ic++) + { + unsigned jc; + for (jc = ic + 1; jc < ivnum && ivarr[ic].start + ivarr[ic].len >= ivarr[jc].start; jc++) + if (ivarr[ic].start + ivarr[ic].len < ivarr[jc].start + ivarr[jc].len) + ivarr[ic].len = ivarr[jc].start + ivarr[jc].len - ivarr[ic].start; + if (jc > ic + 1) + { + memmove(ivarr + ic + 1, ivarr + jc,sizeof(interval) * (ivnum - jc)); + ivnum -= jc - ic - 1; + } + } +} + +void Interval::clear() +{ + for (unsigned ic = 0; ic < ivnum; ic++) + memset((char*) base + ivarr[ic].start,0,ivarr[ic].len); +} + +void Interval::dump() const +{ + printf("%d intervals:\n",ivnum); + for (unsigned ic = 0; ic < ivnum; ic++) + printf("%x %x\n",ivarr[ic].start,ivarr[ic].len); +} + + +/************************************************************************* +// relocation handling +**************************************************************************/ +#if 0 +class Reloc +{ + upx_byte *start; + unsigned size; + + struct reloc + { + LE32 pagestart; + LE32 size; + } + __attribute_packed; + + void newRelocPos(void *p) + { + rel = (reloc*) p; + rel1 = (LE16*) ((char*) p + sizeof (reloc)); + } + + reloc *rel; + LE16 *rel1; + unsigned counts[16]; + +public: + Reloc(upx_byte *,unsigned); + Reloc(unsigned rnum); + // + bool next(unsigned &pos,unsigned &type); + const unsigned *getcounts() const { return counts; } + // + void add(unsigned pos,unsigned type); + void finish(upx_byte *&p,unsigned &size); +}; + +Reloc::Reloc(upx_byte *s,unsigned si) : + start(s), size(si), rel(NULL), rel1(NULL) +{ + COMPILE_TIME_ASSERT(sizeof(reloc) == 8); + memset(counts,0,sizeof(counts)); + unsigned pos,type; + while (next(pos,type)) + counts[type]++; +} + +Reloc::Reloc(unsigned rnum) : + start(NULL), size(0), rel(NULL), rel1(NULL) +{ + start = new upx_byte[rnum * 4 + 8192]; + counts[0] = 0; +} + +bool Reloc::next(unsigned &pos,unsigned &type) +{ + if (!rel) + newRelocPos(start); + if (ptr_diff(rel, start) >= (int) size || rel->pagestart == 0) + return rel = 0,false; // rewind + + pos = rel->pagestart + (*rel1 & 0xfff); + type = *rel1++ >> 12; + //printf("%x %d\n",pos,type); + if (ptr_diff(rel1,rel) >= (int) rel->size) + newRelocPos(rel1); + return type == 0 ? next(pos,type) : true; +} + +void Reloc::add(unsigned pos,unsigned type) +{ + set_le32(start + 1024 + 4 * counts[0]++,(pos << 4) + type); +} + +void Reloc::finish(upx_byte *&p,unsigned &siz) +{ + unsigned prev = 0xffffffff; + set_le32(start + 1024 + 4 * counts[0]++,0xf0000000); + qsort(start + 1024,counts[0],4,le32_compare); + + rel = (reloc*) start; + rel1 = (LE16*) rel; + for (unsigned ic = 0; ic < counts[0]; ic++) + { + unsigned pos = get_le32(start + 1024 + 4 * ic); + if ((pos ^ prev) >= 0x10000) + { + prev = pos; + *rel1 = 0; + rel->size = ALIGN_UP(ptr_diff(rel1,rel),4); + newRelocPos((char *)rel + rel->size); + rel->pagestart = (pos >> 4) &~ 0xfff; + } + *rel1++ = (pos << 12) + ((pos >> 4) & 0xfff); + } + p = start; + siz = ptr_diff(rel1,start) &~ 3; + siz -= 8; + assert(siz > 0); + start = 0; // safety +} + +void PackArmPe::processRelocs(Reloc *rel) // pass2 +{ + rel->finish(oxrelocs,soxrelocs); + if (opt->win32_pe.strip_relocs && !isdll) + soxrelocs = 0; +} + +void PackArmPe::processRelocs() // pass1 +{ + big_relocs = 0; + + Reloc rel(ibuf + IDADDR(PEDIR_RELOC),IDSIZE(PEDIR_RELOC)); + const unsigned *counts = rel.getcounts(); + const unsigned rnum = counts[1] + counts[2] + counts[3]; + + if ((opt->win32_pe.strip_relocs && !isdll) || rnum == 0) + { + if (IDSIZE(PEDIR_RELOC)) + ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL); + orelocs = new upx_byte [1]; + sorelocs = 0; + return; + } + + unsigned ic; + for (ic = 15; ic > 3; ic--) + if (counts[ic]) + infoWarning("skipping unsupported relocation type %d (%d)",ic,counts[ic]); + + LE32 *fix[4]; + for (; ic; ic--) + fix[ic] = new LE32 [counts[ic]]; + + // prepare sorting + unsigned pos,type; + while (rel.next(pos,type)) + { + if (type == 3) + set_le32(ibuf + pos,get_le32(ibuf + pos) - ih.imagebase - rvamin); + if (type < 4) + *fix[type]++ = pos - rvamin; + } + fix[3] -= counts[3]; + + ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL); + orelocs = new upx_byte [rnum * 4 + 1024]; // 1024 - safety + sorelocs = ptr_diff(optimizeReloc32((upx_byte*) fix[3],counts[3],orelocs,ibuf + rvamin,1,&big_relocs),orelocs); + + // append relocs type "LOW" then "HIGH" + for (ic = 2; ic ; ic--) + { + fix[ic] -= counts[ic]; + memcpy(orelocs + sorelocs,fix[ic],4 * counts[ic]); + sorelocs += 4 * counts[ic]; + delete [] fix[ic]; + + set_le32(orelocs + sorelocs,0); + if (counts[ic]) + { + sorelocs += 4; + big_relocs |= 2 * ic; + } + } + delete [] fix[3]; + info("Relocations: original size: %u bytes, preprocessed size: %u bytes",(unsigned) IDSIZE(PEDIR_RELOC),sorelocs); +} +#endif + +/************************************************************************* +// import handling +**************************************************************************/ + +struct import_desc +{ + LE32 oft; // orig first thunk + char _[8]; + LE32 dllname; + LE32 iat; // import address table +} +__attribute_packed; + +void PackArmPe::processImports(unsigned myimport) // pass 2 +{ + COMPILE_TIME_ASSERT(sizeof(import_desc) == 20); + + // adjust import data + for (import_desc *im = (import_desc*) oimpdlls; im->dllname; im++) + { + if (im->dllname < myimport) + im->dllname += myimport; + LE32 *p = (LE32*) (oimpdlls + im->iat); + im->iat += myimport; + im->oft = im->iat; + + while (*p) + if ((*p++ & 0x80000000) == 0) // import by name? + p[-1] += myimport; + } +} + +unsigned PackArmPe::processImports() // pass 1 +{ + static const unsigned char kernel32dll[] = "COREDLL.dll"; + static const char llgpa[] = "\x0\x0""LoadLibraryW\x0\x0""GetProcAddressA"; + //static const char exitp[] = "ExitProcess\x0\x0\x0"; + + unsigned dllnum = 0; + import_desc *im = (import_desc*) (ibuf + IDADDR(PEDIR_IMPORT)); + import_desc * const im_save = im; + if (IDADDR(PEDIR_IMPORT)) + { + while (im->dllname) + dllnum++, im++; + im = im_save; + } + + struct udll + { + const upx_byte *name; + const upx_byte *shname; + unsigned ordinal; + unsigned iat; + LE32 *lookupt; + unsigned npos; + bool isk32; + unsigned _; // padding to 32 + + static int __acc_cdecl_qsort compare(const void *p1, const void *p2) + { + const udll *u1 = * (const udll * const *) p1; + const udll *u2 = * (const udll * const *) p2; + if (u1->isk32) return -1; + if (u2->isk32) return 1; + int rc = strcasecmp(u1->name,u2->name); + if (rc) return rc; + if (u1->ordinal) return -1; + if (u2->ordinal) return 1; + if (!u1->shname) return 1; + if (!u2->shname) return -1; + return strlen(u1->shname) - strlen(u2->shname); + } + } + __attribute_packed; + + // +1 for dllnum=0 + Array(struct udll, dlls, dllnum+1); + Array(struct udll *, idlls, dllnum+1); + + soimport = 1024; // safety + + unsigned ic,k32o; + for (ic = k32o = 0; dllnum && im->dllname; ic++, im++) + { + idlls[ic] = dlls + ic; + dlls[ic].name = ibuf + im->dllname; + dlls[ic].shname = NULL; + dlls[ic].ordinal = 0; + dlls[ic].iat = im->iat; + dlls[ic].lookupt = (LE32*) (ibuf + (im->oft ? im->oft : im->iat)); + dlls[ic].npos = 0; + dlls[ic].isk32 = strcasecmp(kernel32dll,dlls[ic].name) == 0; + + soimport += strlen(dlls[ic].name) + 1 + 4; + + for (LE32 *tarr = dlls[ic].lookupt; *tarr; tarr++) + { + if (*tarr & 0x80000000) + { + importbyordinal = true; + soimport += 2; // ordinal num: 2 bytes + dlls[ic].ordinal = *tarr & 0xffff; + + //if (dlls[ic].isk32) + // kernel32ordinal = true,k32o++; + } + else + { + unsigned len = strlen(ibuf + *tarr + 2); + soimport += len + 1; + if (dlls[ic].shname == NULL || len < strlen (dlls[ic].shname)) + dlls[ic].shname = ibuf + *tarr + 2; + } + soimport++; // separator + } + } + oimport = new upx_byte[soimport]; + memset(oimport,0,soimport); + oimpdlls = new upx_byte[soimport]; + memset(oimpdlls,0,soimport); + + qsort(idlls,dllnum,sizeof (udll*),udll::compare); + + unsigned dllnamelen = sizeof (kernel32dll); + unsigned dllnum2 = 1; + for (ic = 0; ic < dllnum; ic++) + if (!idlls[ic]->isk32 && (ic == 0 || strcasecmp(idlls[ic - 1]->name,idlls[ic]->name))) + { + dllnum2++; + dllnamelen += strlen(idlls[ic]->name) + 1; + } + //fprintf(stderr,"dllnum=%d dllnum2=%d soimport=%d\n",dllnum,dllnum2,soimport); // + + info("Processing imports: %d DLLs", dllnum); + + // create the new import table + im = (import_desc*) oimpdlls; + + LE32 *ordinals = (LE32*) (oimpdlls + (dllnum2 + 1) * sizeof(import_desc)); + LE32 *lookuptable = ordinals + 3;// + k32o + (isdll ? 0 : 1); + upx_byte *dllnames = ((upx_byte*) lookuptable) + (dllnum2 - 1) * 8; + upx_byte *importednames = dllnames + (dllnamelen &~ 1); + + unsigned k32namepos = ptr_diff(dllnames,oimpdlls); + + memcpy(importednames, llgpa, ALIGN_UP(sizeof(llgpa), 2)); + strcpy(dllnames,kernel32dll); + im->dllname = k32namepos; + im->iat = ptr_diff(ordinals,oimpdlls); + *ordinals++ = ptr_diff(importednames,oimpdlls); + *ordinals++ = ptr_diff(importednames,oimpdlls) + 14; + dllnames += sizeof(kernel32dll); + importednames += sizeof(llgpa); + + im++; + for (ic = 0; ic < dllnum; ic++) + if (idlls[ic]->isk32) + { + idlls[ic]->npos = k32namepos; + /* + if (idlls[ic]->ordinal) + for (LE32 *tarr = idlls[ic]->lookupt; *tarr; tarr++) + if (*tarr & 0x80000000) + *ordinals++ = *tarr; + */ + } + else if (ic && strcasecmp(idlls[ic-1]->name,idlls[ic]->name) == 0) + idlls[ic]->npos = idlls[ic-1]->npos; + else + { + im->dllname = idlls[ic]->npos = ptr_diff(dllnames,oimpdlls); + im->iat = ptr_diff(lookuptable,oimpdlls); + + strcpy(dllnames,idlls[ic]->name); + dllnames += strlen(idlls[ic]->name)+1; + if (idlls[ic]->ordinal) + *lookuptable = idlls[ic]->ordinal + 0x80000000; + else if (idlls[ic]->shname) + { + if (ptr_diff(importednames,oimpdlls) & 1) + importednames--; + *lookuptable = ptr_diff(importednames,oimpdlls); + importednames += 2; + strcpy(importednames,idlls[ic]->shname); + importednames += strlen(idlls[ic]->shname) + 1; + } + lookuptable += 2; + im++; + } + soimpdlls = ALIGN_UP(ptr_diff(importednames,oimpdlls),4); + + Interval names(ibuf),iats(ibuf),lookups(ibuf); + // create the preprocessed data + upx_byte *ppi = oimport; // preprocessed imports + for (ic = 0; ic < dllnum; ic++) + { + LE32 *tarr = idlls[ic]->lookupt; + if (!*tarr) // no imports from this dll + continue; + set_le32(ppi,idlls[ic]->npos); + set_le32(ppi+4,idlls[ic]->iat - rvamin); + ppi += 8; + for (; *tarr; tarr++) + if (*tarr & 0x80000000) + { + /*if (idlls[ic]->isk32) + { + *ppi++ = 0xfe; // signed + odd parity + set_le32(ppi,ptr_diff(ordinals,oimpdlls)); + ordinals++; + ppi += 4; + } + else*/ + { + *ppi++ = 0xff; + set_le16(ppi,*tarr & 0xffff); + ppi += 2; + } + } + else + { + *ppi++ = 1; + unsigned len = strlen(ibuf + *tarr + 2) + 1; + memcpy(ppi,ibuf + *tarr + 2,len); + ppi += len; + names.add(*tarr,len + 2 + 1); + } + ppi++; + + unsigned esize = ptr_diff((char *)tarr, (char *)idlls[ic]->lookupt); + lookups.add(idlls[ic]->lookupt,esize); + if (ptr_diff(ibuf + idlls[ic]->iat, (char *)idlls[ic]->lookupt)) + { + memcpy(ibuf + idlls[ic]->iat, idlls[ic]->lookupt, esize); + iats.add(idlls[ic]->iat,esize); + } + names.add(idlls[ic]->name,strlen(idlls[ic]->name) + 1 + 1); + } + ppi += 4; + assert(ppi < oimport+soimport); + soimport = ptr_diff(ppi,oimport); + + if (soimport == 4) + soimport = 0; + + //OutputFile::dump("x0.imp", oimport, soimport); + //OutputFile::dump("x1.imp", oimpdlls, soimpdlls); + + unsigned ilen = 0; + names.flatten(); + if (names.ivnum > 1) + { + // The area occupied by the dll and imported names is not continuous + // so to still support uncompression, I can't zero the iat area. + // This decreases compression ratio, so FIXME somehow. + infoWarning("can't remove unneeded imports"); + ilen += sizeof(import_desc) * dllnum; +#if defined(DEBUG) + if (opt->verbose > 3) + names.dump(); +#endif + // do some work for the unpacker + im = im_save; + for (ic = 0; ic < dllnum; ic++, im++) + { + memset(im,FILLVAL,sizeof(*im)); + im->dllname = ptr_diff(idlls[ic]->name,ibuf); // I only need this info + } + } + else + { + iats.add(im_save,sizeof(import_desc) * dllnum); + // zero unneeded data + iats.clear(); + lookups.clear(); + } + names.clear(); + + iats.add(&names); + iats.add(&lookups); + iats.flatten(); + for (ic = 0; ic < iats.ivnum; ic++) + ilen += iats.ivarr[ic].len; + + info("Imports: original size: %u bytes, preprocessed size: %u bytes",ilen,soimport); + return names.ivnum == 1 ? names.ivarr[0].start : 0; +} + + +/************************************************************************* +// export handling +**************************************************************************/ +#if 0 +class Export +{ + struct export_dir_t + { + char _[12]; // flags, timedate, version + LE32 name; + char __[4]; // ordinal base + LE32 functions; + LE32 names; + LE32 addrtable; + LE32 nameptrtable; + LE32 ordinaltable; + } + __attribute_packed; + + export_dir_t edir; + char *ename; + char *functionptrs; + char *ordinals; + char **names; + + char *base; + unsigned size; + Interval iv; + +public: + Export(char *_base); + ~Export(); + + void convert(unsigned eoffs,unsigned esize); + void build(char *base,unsigned newoffs); + unsigned getsize() const { return size; } + +private: + // disable copy and assignment + Export(const Export&); + Export& operator=(const Export&); +}; + +Export::Export(char *_base) : base(_base), iv(_base) +{ + COMPILE_TIME_ASSERT(sizeof(export_dir_t) == 40); + ename = functionptrs = ordinals = NULL; + names = NULL; + memset(&edir,0,sizeof(edir)); + size = 0; +} + +Export::~Export() +{ + free(ename); + delete [] functionptrs; + delete [] ordinals; + for (unsigned ic = 0; ic < edir.names + edir.functions; ic++) + free(names[ic]); + delete [] names; +} + +void Export::convert(unsigned eoffs,unsigned esize) +{ + memcpy(&edir,base + eoffs,sizeof(export_dir_t)); + size = sizeof(export_dir_t); + iv.add(eoffs,size); + + unsigned len = strlen(base + edir.name) + 1; + ename = strdup(base + edir.name); + size += len; + iv.add(edir.name,len); + + len = 4 * edir.functions; + functionptrs = new char[len + 1]; + memcpy(functionptrs,base + edir.addrtable,len); + size += len; + iv.add(edir.addrtable,len); + + unsigned ic; + names = new char* [edir.names + edir.functions + 1]; + for (ic = 0; ic < edir.names; ic++) + { + char *n = base + get_le32(base + edir.nameptrtable + ic * 4); + len = strlen(n) + 1; + names[ic] = strdup(n); + size += len; + iv.add(get_le32(base + edir.nameptrtable + ic * 4),len); + } + iv.add(edir.nameptrtable,4 * edir.names); + size += 4 * edir.names; + + LE32 *fp = (LE32*) functionptrs; + // export forwarders + for (ic = 0; ic < edir.functions; ic++) + if (fp[ic] >= eoffs && fp[ic] < eoffs + esize) + { + char *forw = base + fp[ic]; + len = strlen(forw) + 1; + iv.add(forw,len); + size += len; + names[ic + edir.names] = strdup(forw); + } + else + names[ic + edir.names] = NULL; + + len = 2 * edir.names; + ordinals = new char[len + 1]; + memcpy(ordinals,base + edir.ordinaltable,len); + size += len; + iv.add(edir.ordinaltable,len); + iv.flatten(); + if (iv.ivnum == 1) + iv.clear(); +#if defined(DEBUG) + else + iv.dump(); +#endif +} + +void Export::build(char *newbase, unsigned newoffs) +{ + char * const functionp = newbase + sizeof(edir); + char * const namep = functionp + 4 * edir.functions; + char * const ordinalp = namep + 4 * edir.names; + char * const enamep = ordinalp + 2 * edir.names; + char * exports = enamep + strlen(ename) + 1; + + edir.addrtable = newoffs + ptr_diff(functionp, newbase); + edir.ordinaltable = newoffs + ptr_diff(ordinalp, newbase); + memcpy(ordinalp,ordinals,2 * edir.names); + + edir.name = newoffs + ptr_diff(enamep, newbase); + strcpy(enamep,ename); + edir.nameptrtable = newoffs + ptr_diff(namep, newbase); + unsigned ic; + for (ic = 0; ic < edir.names; ic++) + { + strcpy(exports,names[ic]); + set_le32(namep + 4 * ic,newoffs + ptr_diff(exports, newbase)); + exports += strlen(exports) + 1; + } + + memcpy(functionp,functionptrs,4 * edir.functions); + for (ic = 0; ic < edir.functions; ic++) + if (names[edir.names + ic]) + { + strcpy(exports,names[edir.names + ic]); + set_le32(functionp + 4 * ic,newoffs + ptr_diff(exports, newbase)); + exports += strlen(exports) + 1; + } + + memcpy(newbase,&edir,sizeof(edir)); + assert(exports - newbase == (int) size); +} + +void PackArmPe::processExports(Export *xport) // pass1 +{ + soexport = ALIGN_UP(IDSIZE(PEDIR_EXPORT),4); + if (soexport == 0) + return; + if (!isdll && opt->win32_pe.compress_exports) + { + infoWarning("exports compressed, --compress-exports=0 might be needed"); + soexport = 0; + return; + } + xport->convert(IDADDR(PEDIR_EXPORT),IDSIZE(PEDIR_EXPORT)); + soexport = ALIGN_UP(xport->getsize(),4); + oexport = new upx_byte[soexport]; + memset(oexport, 0, soexport); +} + +void PackArmPe::processExports(Export *xport,unsigned newoffs) // pass2 +{ + if (soexport) + xport->build((char*) oexport,newoffs); +} + + +/************************************************************************* +// TLS handling +**************************************************************************/ + +// thanks for theowl for providing me some docs, so that now I understand +// what I'm doing here :) + +// 1999-10-17: this was tricky to find: +// when the fixup records and the tls area are on the same page, then +// the tls area is not relocated, because the relocation is done by +// the virtual memory manager only for pages which are not yet loaded. +// of course it was impossible to debug this ;-) + +struct tls +{ + LE32 datastart; // VA tls init data start + LE32 dataend; // VA tls init data end + LE32 tlsindex; // VA tls index + LE32 callbacks; // VA tls callbacks + char _[8]; // zero init, characteristics +} +__attribute_packed; + +void PackArmPe::processTls(Interval *iv) // pass 1 +{ + COMPILE_TIME_ASSERT(sizeof(tls) == 24); + + if ((sotls = ALIGN_UP(IDSIZE(PEDIR_TLS),4)) == 0) + return; + + const tls * const tlsp = (const tls*) (ibuf + IDADDR(PEDIR_TLS)); + // note: TLS callbacks are not implemented in Windows 95/98/ME + if (tlsp->callbacks) + { + if (tlsp->callbacks < ih.imagebase) + throwCantPack("invalid TLS callback"); + else if (tlsp->callbacks - ih.imagebase + 4 >= ih.imagesize) + throwCantPack("invalid TLS callback"); + unsigned v = get_le32(ibuf + tlsp->callbacks - ih.imagebase); + if (v != 0) + { + //fprintf(stderr, "TLS callbacks: 0x%0x -> 0x%0x\n", (int)tlsp->callbacks, v); + throwCantPack("TLS callbacks are not supported"); + } + } + + const unsigned tlsdatastart = tlsp->datastart - ih.imagebase; + const unsigned tlsdataend = tlsp->dataend - ih.imagebase; + + // now some ugly stuff: find the relocation entries in the tls data area + unsigned pos,type; + Reloc rel(ibuf + IDADDR(PEDIR_RELOC),IDSIZE(PEDIR_RELOC)); + while (rel.next(pos,type)) + if (pos >= tlsdatastart && pos < tlsdataend) + iv->add(pos,type); + + sotls = sizeof(tls) + tlsdataend - tlsdatastart; + + // the PE loader wants this stuff uncompressed + otls = new upx_byte[sotls]; + memset(otls,0,sotls); + memcpy(otls,ibuf + IDADDR(PEDIR_TLS),0x18); + // WARNING: this can acces data in BSS + memcpy(otls + sizeof(tls),ibuf + tlsdatastart,sotls - sizeof(tls)); + tlsindex = tlsp->tlsindex - ih.imagebase; + info("TLS: %u bytes tls data and %u relocations added",sotls - (unsigned) sizeof(tls),iv->ivnum); +} + +void PackArmPe::processTls(Reloc *rel,const Interval *iv,unsigned newaddr) // pass 2 +{ + if (sotls == 0) + return; + // add new relocation entries + unsigned ic; + for (ic = 0; ic < 12; ic += 4) + rel->add(newaddr + ic,3); + + tls * const tlsp = (tls*) otls; + // now the relocation entries in the tls data area + for (ic = 0; ic < iv->ivnum; ic += 4) + { + void *p = otls + iv->ivarr[ic].start - (tlsp->datastart - ih.imagebase) + sizeof(tls); + unsigned kc = get_le32(p); + if (kc < tlsp->dataend && kc >= tlsp->datastart) + { + kc += newaddr + sizeof(tls) - tlsp->datastart; + set_le32(p,kc + ih.imagebase); + rel->add(kc,iv->ivarr[ic].len); + } + else + rel->add(kc - ih.imagebase,iv->ivarr[ic].len); + } + + tlsp->datastart = newaddr + sizeof(tls) + ih.imagebase; + tlsp->dataend = newaddr + sotls + ih.imagebase; + tlsp->callbacks = 0; // note: TLS callbacks are not implemented in Windows 95/98/ME +} +#endif + +/************************************************************************* +// resource handling +**************************************************************************/ + +class Resource +{ + struct res_dir_entry + { + LE32 tnl; // Type | Name | Language id - depending on level + LE32 child; + } + __attribute_packed; + struct res_dir + { + char _[12]; // flags, timedate, version + LE16 namedentr; + LE16 identr; + + unsigned Sizeof() const { return 16 + sizeof(res_dir_entry)*(namedentr + identr); } + res_dir_entry entries[1]; + // it's usually safe to assume that every res_dir contains + // at least one res_dir_entry - check() complains otherwise + } + __attribute_packed; + struct res_data + { + LE32 offset; + LE32 size; + char _[8]; // codepage, reserved + } + __attribute_packed; + // + struct upx_rnode + { + unsigned id; + upx_byte *name; + upx_rnode *parent; + }; + struct upx_rbranch : public upx_rnode + { + unsigned nc; + upx_rnode **children; + res_dir data; + }; + struct upx_rleaf : public upx_rnode + { + upx_rleaf *next; + unsigned newoffset; + res_data data; + }; + + const upx_byte *start; + upx_byte *newstart; + upx_rnode *root; + upx_rleaf *head; + upx_rleaf *current; + unsigned dsize; + unsigned ssize; + + void check(const res_dir*,unsigned); + upx_rnode *convert(const void *,upx_rnode *,unsigned); + void build(const upx_rnode *,unsigned &,unsigned &,unsigned); + void clear(upx_byte *,unsigned,Interval *); + void dump(const upx_rnode *,unsigned) const; + void destroy(upx_rnode *urd,unsigned level); + +public: + Resource() : root(NULL) {} + Resource(const upx_byte *p) {init(p);} + ~Resource() {if (root) destroy (root,0);} + void init(const upx_byte *); + + unsigned dirsize() const {return ALIGN_UP(dsize + ssize,4);} + bool next() {return (current = current ? current->next : head) != NULL;} // wow, builtin autorewind... :-) + + unsigned itype() const {return current->parent->parent->id;} + const upx_byte *ntype() const {return current->parent->parent->name;} + unsigned size() const {return ALIGN_UP(current->data.size,4);} + unsigned offs() const {return current->data.offset;} + unsigned &newoffs() {return current->newoffset;} + + upx_byte *build(); + 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;} +*/ +}; + +void Resource::init(const upx_byte *res) +{ + COMPILE_TIME_ASSERT(sizeof(res_dir_entry) == 8); + COMPILE_TIME_ASSERT(sizeof(res_dir) == 16 + sizeof(res_dir_entry)); + COMPILE_TIME_ASSERT(sizeof(res_data) == 16); + + start = res; + root = head = current = NULL; + dsize = ssize = 0; + check((const res_dir*) start,0); + root = convert(start,NULL,0); +} + +void Resource::check(const res_dir *node,unsigned level) +{ + int ic = node->identr + node->namedentr; + if (ic == 0) + { + //throwCantPack("unsupported resource structure"); + throwCantPack("empty resource sections are not supported"); + } + for (const res_dir_entry *rde = node->entries; --ic >= 0; rde++) + if (((rde->child & 0x80000000) == 0) ^ (level == 2)) + throwCantPack("unsupported resource structure"); + else if (level != 2) + check((const res_dir*) (start + (rde->child & 0x7fffffff)),level + 1); +} + +Resource::upx_rnode *Resource::convert(const void *rnode,upx_rnode *parent,unsigned level) +{ + if (level == 3) + { + const res_data *node = (const res_data *) rnode; + upx_rleaf *leaf = new upx_rleaf; + leaf->name = NULL; + leaf->parent = parent; + leaf->next = head; + leaf->newoffset = 0; + leaf->data = *node; + + head = leaf; // append node to a linked list for traversal + dsize += sizeof(res_data); + return leaf; + } + + const res_dir *node = (const res_dir *) rnode; + upx_rbranch *branch = new upx_rbranch; + branch->name = NULL; + branch->parent = parent; + int ic = branch->nc = node->identr + node->namedentr; + branch->children = new upx_rnode*[ic]; + branch->data = *node; + + for (const res_dir_entry *rde = node->entries + ic - 1; --ic >= 0; rde--) + { + upx_rnode *child = convert(start + (rde->child & 0x7fffffff),branch,level + 1); + branch->children[ic] = child; + child->id = rde->tnl; + if (child->id & 0x80000000) + { + const upx_byte *p = start + (child->id & 0x7fffffff); + const unsigned len = 2 + 2 * get_le16(p); + child->name = new upx_byte[len]; + memcpy(child->name,p,len); // copy unicode string + ssize += len; // size of unicode strings + } + } + dsize += node->Sizeof(); + return branch; +} + +void Resource::build(const upx_rnode *node,unsigned &bpos,unsigned &spos,unsigned level) +{ + if (level == 3) + { + res_data *l = (res_data*) (newstart + bpos); + const upx_rleaf *leaf = (const upx_rleaf*) node; + *l = leaf->data; + if (leaf->newoffset) + l->offset = leaf->newoffset; + bpos += sizeof(*l); + return; + } + res_dir * const b = (res_dir*) (newstart + bpos); + const upx_rbranch *branch = (const upx_rbranch*) node; + *b = branch->data; + bpos += b->Sizeof(); + res_dir_entry *be = b->entries; + for (unsigned ic = 0; ic < branch->nc; ic++, be++) + { + be->tnl = branch->children[ic]->id; + be->child = bpos + ((level < 2) ? 0x80000000 : 0); + + const upx_byte *p; + if ((p = branch->children[ic]->name) != 0) + { + be->tnl = spos + 0x80000000; + memcpy(newstart + spos,p,get_le16(p) * 2 + 2); + spos += get_le16(p) * 2 + 2; + } + + build(branch->children[ic],bpos,spos,level + 1); + } +} + +upx_byte *Resource::build() +{ + newstart = new upx_byte [dirsize()]; + unsigned bpos = 0,spos = dsize; + build(root,bpos,spos,0); + return newstart; +} + +void Resource::destroy(upx_rnode *node,unsigned level) +{ + delete [] node->name; node->name = NULL; + if (level == 3) + return; + upx_rbranch * const branch = (upx_rbranch *) node; + for (int ic = branch->nc; --ic >= 0; ) + destroy(branch->children[ic],level + 1); + delete [] branch->children; branch->children = NULL; +} + +static void lame_print_unicode(const upx_byte *p) +{ + for (unsigned ic = 0; ic < get_le16(p); ic++) + printf("%c",(char)p[ic * 2 + 2]); +} + +void Resource::dump(const upx_rnode *node,unsigned level) const +{ + if (level) + { + for (unsigned ic = 1; ic < level; ic++) + printf("\t\t"); + if (node->name) + lame_print_unicode(node->name); + else + printf("0x%x",node->id); + printf("\n"); + } + if (level == 3) + return; + const upx_rbranch * const branch = (const upx_rbranch *) node; + for (unsigned ic = 0; ic < branch->nc; ic++) + dump(branch->children[ic],level + 1); +} + +void Resource::clear(upx_byte *node,unsigned level,Interval *iv) +{ + if (level == 3) + iv->add(node,sizeof (res_data)); + else + { + const res_dir * const rd = (res_dir*) node; + const unsigned n = rd->identr + rd->namedentr; + const res_dir_entry *rde = rd->entries; + for (unsigned ic = 0; ic < n; ic++, rde++) + clear(newstart + (rde->child & 0x7fffffff),level + 1,iv); + iv->add(rd,rd->Sizeof()); + } +} + +bool Resource::clear() +{ + newstart = const_cast (start); + Interval iv(newstart); + clear(newstart,0,&iv); + iv.flatten(); + if (iv.ivnum == 1) + iv.clear(); +#if defined(DEBUG) + if (opt->verbose > 3) + iv.dump(); +#endif + return iv.ivnum == 1; +} + +void PackArmPe::processResources(Resource *res,unsigned newaddr) +{ + if (IDSIZE(PEDIR_RESOURCE) == 0) + return; + while (res->next()) + if (res->newoffs()) + res->newoffs() += newaddr; + upx_byte *p = res->build(); + memcpy(oresources,p,res->dirsize()); + delete [] p; +} + +void PackArmPe::processResources(Resource *res) +{ + const unsigned vaddr = IDADDR(PEDIR_RESOURCE); + if ((soresources = IDSIZE(PEDIR_RESOURCE)) == 0) + return; + + // setup default options for resource compression + if (opt->win32_pe.compress_resources < 0) + opt->win32_pe.compress_resources = true; + if (!opt->win32_pe.compress_resources) + { + opt->win32_pe.compress_icons = false; + for (int i = 0; i < RT_LAST; i++) + opt->win32_pe.compress_rt[i] = false; + } + if (opt->win32_pe.compress_rt[RT_STRING] < 0) + { + // by default, don't compress RT_STRINGs of screensavers (".scr") + opt->win32_pe.compress_rt[RT_STRING] = true; + if (fn_has_ext(fi->getName(),"scr")) + opt->win32_pe.compress_rt[RT_STRING] = false; + } + + res->init(ibuf + vaddr); + + for (soresources = res->dirsize(); res->next(); soresources += 4 + res->size()) + ; + oresources = new upx_byte[soresources]; + upx_byte *ores = oresources + res->dirsize(); + + 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); + + bool compress_icon = false, compress_idir = false; + unsigned iconcnt = 0; + + // some statistics + unsigned usize = 0; + unsigned csize = 0; + unsigned unum = 0; + unsigned cnum = 0; + + while (res->next()) + { + const unsigned rtype = res->itype(); + 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; + 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) + { + csize += res->size(); + cnum++; + continue; + } + + usize += res->size(); + unum++; + + set_le32(ores,res->offs()); // save original offset + ores += 4; + ICHECK(ibuf + res->offs(), res->size()); + 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); + else if (rtype == RT_GROUP_ICON) + { + if (opt->win32_pe.compress_icons == 1) + { + icondir_offset = 4 + ptr_diff(ores,oresources); + icondir_count = get_le16(oresources + icondir_offset); + set_le16(oresources + icondir_offset,1); + } + compress_idir = true; + } + ores += res->size(); + } + soresources = ptr_diff(ores,oresources); + + if (!res->clear()) + { + // The area occupied by the resource directory is not continuous + // so to still support uncompression, I can't zero this area. + // This decreases compression ratio, so FIXME somehow. + infoWarning("can't remove unneeded resource directory"); + } + info("Resources: compressed %u (%u bytes), not compressed %u (%u bytes)",cnum,csize,unum,usize); +} + + +unsigned PackArmPe::virta2objnum(unsigned addr,pe_section_t *sect,unsigned objs) +{ + unsigned ic; + for (ic = 0; ic < objs; ic++) + { + if (sect->vaddr <= addr && sect->vaddr + sect->vsize > addr) + return ic; + sect++; + } + //throwCantPack("virta2objnum() failed"); + return ic; +} + + +unsigned PackArmPe::tryremove (unsigned vaddr,unsigned objs) +{ + unsigned ic = virta2objnum(vaddr,isection,objs); + if (ic && ic == objs - 1) + { + //fprintf(stderr,"removed section: %d size: %lx\n",ic,(long)isection[ic].size); + info("removed section: %d size: 0x%lx",ic,(long)isection[ic].size); + objs--; + } + return objs; +} + + +unsigned PackArmPe::stripDebug(unsigned overlaystart) +{ + if (IDADDR(PEDIR_DEBUG) == 0) + return overlaystart; + + struct debug_dir_t + { + char _[16]; // flags, time/date, version, type + LE32 size; + char __[4]; // rva + LE32 fpos; + } + __attribute_packed; + + const debug_dir_t *dd = (const debug_dir_t*) (ibuf + IDADDR(PEDIR_DEBUG)); + for (unsigned ic = 0; ic < IDSIZE(PEDIR_DEBUG) / sizeof(debug_dir_t); ic++, dd++) + if (overlaystart == dd->fpos) + overlaystart += dd->size; + ibuf.fill(IDADDR(PEDIR_DEBUG), IDSIZE(PEDIR_DEBUG), FILLVAL); + return overlaystart; +} + + +/************************************************************************* +// pack +**************************************************************************/ + +bool PackArmPe::canPack() +{ + if (!readFileHeader() || ih.cpu != 0x1c0) + return false; + return true; +} + + +int PackArmPe::buildLoader(const Filter *ft) +{ + // prepare loader + initLoader(nrv_loader, sizeof(nrv_loader), -1, 2); + addLoader("ARMWPE00,ARMWPE99," + "IDENTSTR,UPX1HEAD", + NULL + ); + return getLoaderSize(); +} + + +void PackArmPe::pack(OutputFile *fo) +{ + if (opt->win32_pe.strip_loadconf < 0) + opt->win32_pe.strip_loadconf = false; + + const unsigned objs = ih.objects; + isection = new pe_section_t[objs]; + fi->seek(pe_offset+sizeof(ih),SEEK_SET); + fi->readx(isection,sizeof(pe_section_t)*objs); + + rvamin = isection[0].vaddr; + + infoHeader("[Processing %s, format %s, %d sections]", fn_basename(fi->getName()), getName(), objs); + + // check the PE header + // FIXME: add more checks + if (!opt->force && ( + ih.opthdrsize != 0xE0 + || (ih.flags & EXECUTABLE) == 0 + || ih.subsystem != 9 + || (ih.entry == 0 && !isdll) + || ih.ddirsentries != 16 + /*|| IDSIZE(PEDIR_EXCEPTION*/) // is this used on i386? +// || IDSIZE(PEDIR_COPYRIGHT) + ) + throwCantPack("unexpected value in PE header (try --force)"); + + if (IDSIZE(PEDIR_SEC)) + throwCantPack("compressing certificate info is not supported"); + if (IDSIZE(PEDIR_COMRT)) + throwCantPack(".NET files (win32/net) are not yet supported"); +#if 1 + if (IDSIZE(PEDIR_EXPORT)) + IDSIZE(PEDIR_EXPORT) = IDADDR(PEDIR_EXPORT) = 0; +#else + if (IDSIZE(PEDIR_EXPORT)) + throwCantPack("exports not yet supported"); +#endif + if (IDSIZE(PEDIR_RELOC)) + throwCantPack("relocations not yet supported"); + + // Structured Exception Handling + if (!opt->win32_pe.strip_loadconf && IDSIZE(PEDIR_LOADCONF)) + throwCantPack("Structured Exception Handling present (try --strip-loadconf)"); + + if (isdll) + opt->win32_pe.strip_relocs = false; + else if (opt->win32_pe.strip_relocs < 0) + opt->win32_pe.strip_relocs = (ih.imagebase >= 0x400000); + if (opt->win32_pe.strip_relocs) + if (ih.imagebase < 0x400000) + throwCantPack("--strip-relocs is not allowed when imagebase < 0x400000"); + else + ih.flags |= RELOCS_STRIPPED; + + if (memcmp(isection[0].name,"UPX",3) == 0) + throwAlreadyPackedByUPX(); + if (!opt->force && (IDSIZE(15) || ih.entry > isection[1].vaddr)) + throwCantPack("file is possibly packed/protected (try --force)"); + if (ih.entry && ih.entry < rvamin) + throwCantPack("run a virus scanner on this file!"); + if (!opt->force && ih.subsystem == 1) + throwCantPack("subsystem `native' is not supported (try --force)"); + if (ih.filealign < 0x200) + throwCantPack("filealign < 0x200 is not yet supported"); + + handleStub(fi,fo,pe_offset); + const unsigned usize = ih.imagesize; + const unsigned xtrasize = UPX_MAX(ih.datasize, 65536u) + IDSIZE(PEDIR_IMPORT) + IDSIZE(PEDIR_BOUNDIM) + IDSIZE(PEDIR_IAT) + IDSIZE(PEDIR_DELAYIMP) + IDSIZE(PEDIR_RELOC); + ibuf.alloc(usize + xtrasize); + + // BOUND IMPORT support. FIXME: is this ok? + fi->seek(0,SEEK_SET); + fi->readx(ibuf,isection[0].rawdataptr); + + Interval holes(ibuf); + + unsigned ic,jc,overlaystart = 0; + ibuf.clear(0, usize); + for (ic = jc = 0; ic < objs; ic++) + { + if (isection[ic].rawdataptr && overlaystart < isection[ic].rawdataptr + isection[ic].size) + overlaystart = ALIGN_UP(isection[ic].rawdataptr + isection[ic].size,ih.filealign); + if (isection[ic].vsize == 0) + isection[ic].vsize = isection[ic].size; + if ((isection[ic].flags & PEFL_BSS) || isection[ic].rawdataptr == 0 + || (isection[ic].flags & PEFL_INFO)) + { + holes.add(isection[ic].vaddr,isection[ic].vsize); + continue; + } + if (isection[ic].vaddr + isection[ic].size > usize) + throwCantPack("section size problem"); + if (((isection[ic].flags & (PEFL_WRITE|PEFL_SHARED)) + == (PEFL_WRITE|PEFL_SHARED))) + if (!opt->force) + throwCantPack("writeable shared sections not supported (try --force)"); + if (jc && isection[ic].rawdataptr - jc > ih.filealign) + throwCantPack("superfluous data between sections"); + fi->seek(isection[ic].rawdataptr,SEEK_SET); + jc = isection[ic].size; + if (jc > isection[ic].vsize) + jc = isection[ic].vsize; + if (isection[ic].vsize == 0) // hack for some tricky programs - may this break other progs? + jc = isection[ic].vsize = isection[ic].size; + if (isection[ic].vaddr + jc > ibuf.getSize()) + throwInternalError("buffer too small 1"); + fi->readx(ibuf + isection[ic].vaddr,jc); + jc += isection[ic].rawdataptr; + } + + // check for NeoLite + if (find(ibuf + ih.entry, 64+7, "NeoLite", 7) >= 0) + throwCantPack("file is already compressed with another packer"); + + unsigned overlay = file_size - stripDebug(overlaystart); + if (overlay >= (unsigned) file_size) + { +#if 0 + if (overlay < file_size + ih.filealign) + overlay = 0; + else if (!opt->force) + throwNotCompressible("overlay problem (try --force)"); +#endif + overlay = 0; + } + checkOverlay(overlay); + + Resource res; + Interval tlsiv(ibuf); + //Export xport((char*)(unsigned char*)ibuf); + + const unsigned dllstrings = processImports(); + //processTls(&tlsiv); // call before processRelocs!! + processResources(&res); + //processExports(&xport); + //processRelocs(); + + //OutputFile::dump("x1", ibuf, usize); + + // some checks for broken linkers - disable filter if neccessary + bool allow_filter = true; + if (ih.codebase == ih.database + || ih.codebase + ih.codesize > ih.imagesize + || (isection[virta2objnum(ih.codebase,isection,objs)].flags & PEFL_CODE) == 0) + allow_filter = false; + + const unsigned oam1 = ih.objectalign - 1; + + // FIXME: disabled: the uncompressor would not allocate enough memory + //objs = tryremove(IDADDR(PEDIR_RELOC),objs); + + // FIXME: if the last object has a bss then this won't work + // newvsize = (isection[objs-1].vaddr + isection[objs-1].size + oam1) &~ oam1; + // temporary solution: + unsigned newvsize = (isection[objs-1].vaddr + isection[objs-1].vsize + oam1) &~ oam1; + + //fprintf(stderr,"newvsize=%x objs=%d\n",newvsize,objs); + if (newvsize + soimport + sorelocs > ibuf.getSize()) + throwInternalError("buffer too small 2"); + memcpy(ibuf+newvsize,oimport,soimport); + memcpy(ibuf+newvsize+soimport,orelocs,sorelocs); + + cimports = newvsize - rvamin; // rva of preprocessed imports + crelocs = cimports + soimport; // rva of preprocessed fixups + + ph.u_len = newvsize + soimport + sorelocs; + + // some extra data for uncompression support + unsigned s = 0; + upx_byte * const p1 = ibuf + ph.u_len; + memcpy(p1 + s,&ih,sizeof (ih)); + s += sizeof (ih); + memcpy(p1 + s,isection,ih.objects * sizeof(*isection)); + s += ih.objects * sizeof(*isection); + if (soimport) + { + set_le32(p1 + s,cimports); + set_le32(p1 + s + 4,dllstrings); + s += 8; + } + if (sorelocs) + { + set_le32(p1 + s,crelocs); + p1[s + 4] = (unsigned char) (big_relocs & 6); + s += 5; + } + if (soresources) + { + set_le16(p1 + s,icondir_count); + s += 2; + } + // end of extra data + set_le32(p1 + s,ptr_diff(p1,ibuf) - rvamin); + s += 4; + ph.u_len += s; + obuf.allocForCompression(ph.u_len); + + // prepare packheader + ph.u_len -= rvamin; + // prepare filter + Filter ft(ph.level); + ft.buf_len = ih.codesize; + ft.addvalue = ih.codebase - rvamin; + // compress + int strategy = allow_filter ? 0 : -3; + compressWithFilters(&ft, 2048, strategy, + NULL, 0, 0, ih.codebase, rvamin); +// info: see buildLoader() + newvsize = (ph.u_len + rvamin + ph.overlap_overhead + oam1) &~ oam1; + if (tlsindex && ((newvsize - ph.c_len - 1024 + oam1) &~ oam1) > tlsindex + 4) + tlsindex = 0; + + const unsigned lsize = getLoaderSize(); + MemBuffer loader(lsize); + memcpy(loader,getLoader(),lsize); + patchPackHeader(loader, lsize); + + int identsize = 0; + const unsigned codesize = getLoaderSection("IDENTSTR",&identsize); + assert(identsize > 0); + getLoaderSection("UPX1HEAD",(int*)&ic); + identsize += ic; + + pe_section_t osection[3]; + // section 0 : bss + // 1 : [ident + header] + packed_data + unpacker + tls + // 2 : not compressed data + + // section 2 should start with the resource data, because lots of lame + // windoze codes assume that resources starts on the beginning of a section + + // identsplit - number of ident + (upx header) bytes to put into the PE header + int identsplit = pe_offset + sizeof(osection) + sizeof(oh); + if ((identsplit & 0x1ff) == 0) + identsplit = 0; + else if (((identsplit + identsize) ^ identsplit) < 0x200) + identsplit = identsize; + else + identsplit = ALIGN_GAP(identsplit, 0x200); + ic = identsize - identsplit; + + const unsigned clen = ((ph.c_len + ic) & 15) == 0 ? ph.c_len : ph.c_len + 16 - ((ph.c_len + ic) & 15); + obuf.clear(ph.c_len, clen - ph.c_len); + + const unsigned s1size = ALIGN_UP(ic + clen + codesize,4) + sotls; + const unsigned s1addr = (newvsize - (ic + clen) + oam1) &~ oam1; + + const unsigned ncsection = (s1addr + s1size + oam1) &~ oam1; + const unsigned upxsection = s1addr + ic + clen; + const unsigned myimport = ncsection + soresources - rvamin; + + // patch loader + patch_le32(loader, codesize, "DSTL", ph.u_len); + patch_le32(loader, codesize, "SRCL", ph.c_len); + + patch_le32(loader, codesize, "ENTR", ih.entry + ih.imagebase); + patch_le32(loader, codesize, "LOAD", ih.imagebase + rvamin + myimport + get_le32(oimpdlls + 16)); + patch_le32(loader, codesize, "GETP", ih.imagebase + rvamin + myimport + get_le32(oimpdlls + 16) + 4); + patch_le32(loader, codesize, "ONAM", ih.imagebase + myimport + rvamin); + patch_le32(loader, codesize, "BIMP", ih.imagebase + rvamin + cimports); + patch_le32(loader, codesize, "DST0", ih.imagebase + rvamin); + patch_le32(loader, codesize, "SRC0", ih.imagebase + s1addr + ic); +#if 0 + if (ih.entry) + { + unsigned jmp_pos = find_le32(loader,codesize + 4,get_le32("JMPO")); + patch_le32(loader,codesize + 4,"JMPO",ih.entry - upxsection - jmp_pos - 4); + } + if (big_relocs & 6) + patch_le32(loader,codesize,"DELT", 0u - (unsigned) ih.imagebase - rvamin); + if (sorelocs && (soimport == 0 || soimport + cimports != crelocs)) + patch_le32(loader,codesize,"BREL",crelocs); + if (soimport) + { + if (!isdll) + patch_le32(loader,codesize,"EXIT",myimport + get_le32(oimpdlls + 16) + 8); + patch_le32(loader,codesize,"GETP",myimport + get_le32(oimpdlls + 16) + 4); + if (kernel32ordinal) + patch_le32(loader,codesize,"K32O",myimport); + patch_le32(loader,codesize,"LOAD",myimport + get_le32(oimpdlls + 16)); + patch_le32(loader,codesize,"IMPS",myimport); + patch_le32(loader,codesize,"BIMP",cimports); + } + + if (patchFilter32(loader, codesize, &ft)) + { + const unsigned texv = ih.codebase - rvamin; + if (texv) + patch_le32(loader, codesize, "TEXV", texv); + } + if (tlsindex) + { + // in case of overlapping decompression, this hack is needed, + // because windoze zeroes the word pointed by tlsindex before + // it starts programs + if (tlsindex + 4 > s1addr) + patch_le32(loader,codesize,"TLSV",get_le32(obuf + tlsindex - s1addr - ic)); + else + patch_le32(loader,codesize,"TLSV",0); // bad guess + patch_le32(loader,codesize,"TLSA",tlsindex - rvamin); + } + if (icondir_count > 1) + { + if (icondir_count > 2) + patch_le16(loader,codesize,"DR",icondir_count - 1); + patch_le32(loader,codesize,"ICON",ncsection + icondir_offset - rvamin); + } + + const unsigned esi0 = s1addr + ic; + patch_le32(loader,codesize,"EDI0", 0u - esi0 + rvamin); + patch_le32(loader,codesize,"ESI0", esi0 + ih.imagebase); + ic = getLoaderSection("PEMAIN01") + 2 + upxsection; +#endif + //Reloc rel(1024); // new relocations are put here + //rel.add(ic,3); + + // new PE header + memcpy(&oh,&ih,sizeof(oh)); + oh.filealign = 0x200; // identsplit depends on this + memset(osection,0,sizeof(osection)); + + oh.entry = upxsection; + oh.objects = 3; + oh.chksum = 0; + + // fill the data directory + ODADDR(PEDIR_DEBUG) = 0; + ODSIZE(PEDIR_DEBUG) = 0; + ODADDR(PEDIR_IAT) = 0; + ODSIZE(PEDIR_IAT) = 0; + ODADDR(PEDIR_BOUNDIM) = 0; + ODSIZE(PEDIR_BOUNDIM) = 0; + + if (opt->win32_pe.strip_loadconf) + { + ODADDR(PEDIR_LOADCONF) = 0; + ODSIZE(PEDIR_LOADCONF) = 0; + } + + // tls is put into section 1 + + ic = s1addr + s1size - sotls; + //processTls(&rel,&tlsiv,ic); + ODADDR(PEDIR_TLS) = sotls ? ic : 0; + ODSIZE(PEDIR_TLS) = sotls ? 0x18 : 0; + ic += sotls; + + // these are put into section 2 + + ic = ncsection; + if (soresources) + processResources(&res,ic); + ODADDR(PEDIR_RESOURCE) = soresources ? ic : 0; + ODSIZE(PEDIR_RESOURCE) = soresources; + ic += soresources; + processImports(ic); + ODADDR(PEDIR_IMPORT) = ic; + ODSIZE(PEDIR_IMPORT) = soimpdlls; + ic += soimpdlls; + //processExports(&xport,ic); + ODADDR(PEDIR_EXPORT) = soexport ? ic : 0; + ODSIZE(PEDIR_EXPORT) = soexport; + if (!isdll && opt->win32_pe.compress_exports) + { + ODADDR(PEDIR_EXPORT) = IDADDR(PEDIR_EXPORT); + ODSIZE(PEDIR_EXPORT) = IDSIZE(PEDIR_EXPORT); + } + ic += soexport; + //processRelocs(&rel); + ODADDR(PEDIR_RELOC) = soxrelocs ? ic : 0; + ODSIZE(PEDIR_RELOC) = soxrelocs; + ic += soxrelocs; + + // this is computed here, because soxrelocs changes some lines above + const unsigned ncsize = soresources + soimpdlls + soexport + soxrelocs; + ic = oh.filealign - 1; + + // this one is tricky: it seems windoze touches 4 bytes after + // the end of the relocation data - so we have to increase + // the virtual size of this section + const unsigned ncsize_virt_increase = (ncsize & oam1) == 0 ? 8 : 0; + + // fill the sections + strcpy(osection[0].name,"UPX0"); + strcpy(osection[1].name,"UPX1"); + // after some windoze debugging I found that the name of the sections + // DOES matter :( .rsrc is used by oleaut32.dll (TYPELIBS) + // and because of this lame dll, the resource stuff must be the + // first in the 3rd section - the author of this dll seems to be + // too idiot to use the data directories... M$ suxx 4 ever! + // ... even worse: exploder.exe in NiceTry also depends on this to + // locate version info + + strcpy(osection[2].name,soresources ? ".rsrc" : "UPX2"); + + osection[0].vaddr = rvamin; + osection[1].vaddr = s1addr; + osection[2].vaddr = ncsection; + + osection[0].size = 0; + osection[1].size = (s1size + ic) &~ ic; + osection[2].size = (ncsize + ic) &~ ic; + + osection[0].vsize = osection[1].vaddr - osection[0].vaddr; + //osection[1].vsize = (osection[1].size + oam1) &~ oam1; + //osection[2].vsize = (osection[2].size + ncsize_virt_increase + oam1) &~ oam1; + osection[1].vsize = osection[1].size; + osection[2].vsize = osection[2].size + ncsize_virt_increase; + + osection[0].rawdataptr = (pe_offset + sizeof(oh) + sizeof(osection) + ic) &~ ic; + osection[1].rawdataptr = osection[0].rawdataptr; + osection[2].rawdataptr = osection[1].rawdataptr + osection[1].size; + + osection[0].flags = (unsigned) (PEFL_BSS|PEFL_EXEC|PEFL_WRITE|PEFL_READ); + osection[1].flags = (unsigned) (PEFL_DATA|PEFL_EXEC|PEFL_WRITE|PEFL_READ); + osection[2].flags = (unsigned) (PEFL_DATA|PEFL_WRITE|PEFL_READ); + + oh.imagesize = osection[2].vaddr + osection[2].vsize; + oh.bsssize = osection[0].vsize; + oh.datasize = osection[2].vsize; + oh.database = osection[2].vaddr; + oh.codesize = osection[1].vsize; + oh.codebase = osection[1].vaddr; + // oh.headersize = osection[0].rawdataptr; + oh.headersize = rvamin; + + if (opt->win32_pe.strip_relocs && !isdll) + oh.flags |= RELOCS_STRIPPED; + + //for (ic = 0; ic < oh.filealign; ic += 4) + // set_le32(ibuf + ic,get_le32("UPX ")); + ibuf.clear(0, oh.filealign); + + infoHeader("[Writing compressed file]"); + + // write loader + compressed file + fo->write(&oh,sizeof(oh)); + fo->write(osection,sizeof(osection)); + // some alignment + if (identsplit == identsize) + { + unsigned n = osection[0].rawdataptr - fo->getBytesWritten() - identsize; + assert(n <= oh.filealign); + fo->write(ibuf, n); + } + fo->write(loader + codesize,identsize); + infoWriting("loader", fo->getBytesWritten()); + fo->write(obuf,clen); + infoWriting("compressed data", clen); + fo->write(loader,codesize); + if ((ic = fo->getBytesWritten() & 3) != 0) + fo->write(ibuf,4 - ic); + fo->write(otls,sotls); + if ((ic = fo->getBytesWritten() & (oh.filealign-1)) != 0) + fo->write(ibuf,oh.filealign - ic); + fo->write(oresources,soresources); + fo->write(oimpdlls,soimpdlls); + fo->write(oexport,soexport); + fo->write(oxrelocs,soxrelocs); + + if ((ic = fo->getBytesWritten() & (oh.filealign-1)) != 0) + fo->write(ibuf,oh.filealign - ic); + +#if 0 + printf("%-13s: program hdr : %8ld bytes\n", getName(), (long) sizeof(oh)); + printf("%-13s: sections : %8ld bytes\n", getName(), (long) sizeof(osection)); + printf("%-13s: ident : %8ld bytes\n", getName(), (long) identsize); + printf("%-13s: compressed : %8ld bytes\n", getName(), (long) clen); + printf("%-13s: decompressor : %8ld bytes\n", getName(), (long) codesize); + printf("%-13s: tls : %8ld bytes\n", getName(), (long) sotls); + printf("%-13s: resources : %8ld bytes\n", getName(), (long) soresources); + printf("%-13s: imports : %8ld bytes\n", getName(), (long) soimpdlls); + printf("%-13s: exports : %8ld bytes\n", getName(), (long) soexport); + printf("%-13s: relocs : %8ld bytes\n", getName(), (long) soxrelocs); +#endif + + // verify + verifyOverlappingDecompression(); + + // copy the overlay + copyOverlay(fo, overlay, &obuf); + + // finally check the compression ratio + if (!checkFinalCompressionRatio(fo)) + throwNotCompressible(); +} + + +/************************************************************************* +// unpack +**************************************************************************/ + +int PackArmPe::canUnpack() +{ + return false; +} + +void PackArmPe::unpack(OutputFile *) +{} + +/* +vi:ts=4:et +*/ diff --git a/src/p_armpe.h b/src/p_armpe.h new file mode 100644 index 00000000..365ceabc --- /dev/null +++ b/src/p_armpe.h @@ -0,0 +1,251 @@ +/* p_armpe.h -- + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2004 Laszlo Molnar + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + 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; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer Laszlo Molnar + markus@oberhumer.com ml1050@users.sourceforge.net + */ + + +#ifndef __UPX_P_ARMPE_H +#define __UPX_P_ARMPE_H + + +class PackArmPe_Interval; +class PackArmPe_Reloc; +class PackArmPe_Resource; +class PackArmPe_Export; + + +/************************************************************************* +// w32/pe +**************************************************************************/ + +class PackArmPe : public Packer +{ + typedef Packer super; + +public: + PackArmPe(InputFile *f); + ~PackArmPe(); + virtual int getVersion() const { return 13; } + virtual int getFormat() const { return UPX_F_WINCE_ARM_PE; } + virtual const char *getName() const { return "arm/pe"; } + virtual const int *getCompressionMethods(int method, int level) const; + virtual const int *getFilters() const; + + virtual void pack(OutputFile *fo); + virtual void unpack(OutputFile *fo); + + virtual bool canPack(); + virtual int canUnpack(); + + // unpacker capabilities + virtual bool canUnpackVersion(int version) const + { return false; } + +protected: + virtual int readFileHeader(); + virtual bool testUnpackVersion(int version) const; + + virtual int buildLoader(const Filter *ft); + + unsigned pe_offset; + + unsigned processImports(); + void processImports(unsigned); + void rebuildImports(upx_byte *&); + upx_byte *oimport; + unsigned soimport; + upx_byte *oimpdlls; + unsigned soimpdlls; + + void processRelocs(); + void processRelocs(PackArmPe_Reloc *); + void rebuildRelocs(upx_byte *&); + upx_byte *orelocs; + unsigned sorelocs; + upx_byte *oxrelocs; + unsigned soxrelocs; + + void processExports(PackArmPe_Export *); + void processExports(PackArmPe_Export *,unsigned); + void rebuildExports(); + upx_byte *oexport; + unsigned soexport; + + void processResources(PackArmPe_Resource *); + void processResources(PackArmPe_Resource *, unsigned); + void rebuildResources(upx_byte *&); + upx_byte *oresources; + unsigned soresources; + + void processTls(PackArmPe_Interval *); + void processTls(PackArmPe_Reloc *,const PackArmPe_Interval *,unsigned); + void rebuildTls(); + upx_byte *otls; + unsigned sotls; + + unsigned stripDebug(unsigned); + + unsigned icondir_offset; + int icondir_count; + + bool importbyordinal; + bool kernel32ordinal; + unsigned tlsindex; + unsigned rvamin; + unsigned cimports; // rva of preprocessed imports + unsigned crelocs; // rva of preprocessed fixups + int big_relocs; + + struct pe_header_t + { + // 0x0 + char _[4]; // pemagic + LE16 cpu; + LE16 objects; + char __[12]; // timestamp + reserved + LE16 opthdrsize; + LE16 flags; + // optional header + char ___[4]; // coffmagic + linkerversion + LE32 codesize; + // 0x20 + LE32 datasize; + LE32 bsssize; + LE32 entry; + LE32 codebase; + // 0x30 + LE32 database; + // nt specific fields + LE32 imagebase; + LE32 objectalign; + LE32 filealign; // should set to 0x200 ? + // 0x40 + char ____[16]; // versions + // 0x50 + LE32 imagesize; + LE32 headersize; + LE32 chksum; // should set to 0 + LE16 subsystem; + LE16 dllflags; + // 0x60 + char _____[20]; // stack + heap sizes + // 0x74 + LE32 ddirsentries; // usually 16 + + struct ddirs_t + { + LE32 vaddr; + LE32 size; + } + __attribute_packed; + + struct ddirs_t ddirs[16]; + } + __attribute_packed; + + struct pe_section_t + { + char name[8]; + LE32 vsize; + LE32 vaddr; + LE32 size; + LE32 rawdataptr; + char _[12]; + LE32 flags; + } + __attribute_packed; + + pe_header_t ih, oh; + pe_section_t *isection; + + static unsigned virta2objnum (unsigned, pe_section_t *, unsigned); + unsigned tryremove (unsigned, unsigned); + + enum { + PEDIR_EXPORT = 0, + PEDIR_IMPORT = 1, + PEDIR_RESOURCE = 2, + PEDIR_EXCEPTION = 3, // Exception table + PEDIR_SEC = 4, // Certificate table (file pointer) + PEDIR_RELOC = 5, + PEDIR_DEBUG = 6, + PEDIR_COPYRIGHT = 7, // Architecture-specific data + PEDIR_GLOBALPTR = 8, // Global pointer + PEDIR_TLS = 9, + PEDIR_LOADCONF = 10, // Load Config Table + PEDIR_BOUNDIM = 11, + PEDIR_IAT = 12, + PEDIR_DELAYIMP = 13, // Delay Import Descriptor + PEDIR_COMRT = 14 // Com+ Runtime Header + }; + + enum { + PEFL_CODE = 0x20, + PEFL_DATA = 0x40, + PEFL_BSS = 0x80, + PEFL_INFO = 0x200, + PEFL_EXTRELS = 0x01000000, // extended relocations + PEFL_DISCARD = 0x02000000, + PEFL_NOCACHE = 0x04000000, + PEFL_NOPAGE = 0x08000000, + PEFL_SHARED = 0x10000000, + PEFL_EXEC = 0x20000000, + PEFL_READ = 0x40000000, + PEFL_WRITE = 0x80000000 + }; + + enum { + RELOCS_STRIPPED = 0x0001, + EXECUTABLE = 0x0002, + LNUM_STRIPPED = 0x0004, + LSYMS_STRIPPED = 0x0008, + AGGRESSIVE_TRIM = 0x0010, + TWO_GIGS_AWARE = 0x0020, + FLITTLE_ENDIAN = 0x0080, + BITS_32_MACHINE = 0x0100, + DEBUG_STRIPPED = 0x0200, + REMOVABLE_SWAP = 0x0400, + SYSTEM_PROGRAM = 0x1000, + DLL_FLAG = 0x2000, + FBIG_ENDIAN = 0x8000 + }; + + // predefined resource types + enum { + RT_CURSOR = 1, RT_BITMAP, RT_ICON, RT_MENU, RT_DIALOG, RT_STRING, + RT_FONTDIR, RT_FONT, RT_ACCELERATOR, RT_RCDATA, RT_MESSAGETABLE, + RT_GROUP_CURSOR, RT_GROUP_ICON = 14, RT_VERSION = 16, RT_DLGINCLUDE, + RT_PLUGPLAY = 19, RT_VXD, RT_ANICURSOR, RT_ANIICON, RT_HTML, + RT_MANIFEST, RT_LAST + }; +}; + + +#endif /* already included */ + + +/* +vi:ts=4:et +*/ diff --git a/src/packmast.cpp b/src/packmast.cpp index 068758ca..ed49683d 100644 --- a/src/packmast.cpp +++ b/src/packmast.cpp @@ -53,6 +53,7 @@ #include "p_vmlinx.h" #include "p_ps1.h" #include "p_mach.h" +#include "p_armpe.h" /************************************************************************* @@ -170,6 +171,8 @@ static Packer* try_packers(InputFile *f, try_function func) #endif if ((p = func(new PackW16Ne(f),f)) != NULL) return p; + if ((p = func(new PackArmPe(f),f)) != NULL) + return p; if ((p = func(new PackW32Pe(f),f)) != NULL) return p; } diff --git a/src/stub/.cvsignore b/src/stub/.cvsignore index be92bcbf..cf849a7e 100644 --- a/src/stub/.cvsignore +++ b/src/stub/.cvsignore @@ -12,3 +12,5 @@ stamp-h stubify.exe upxb upxd +*.out +*.ah diff --git a/src/stub/Makefile b/src/stub/Makefile index 4beaaa83..5bfd0520 100644 --- a/src/stub/Makefile +++ b/src/stub/Makefile @@ -46,7 +46,8 @@ STUBS = \ l_lx_pti86.h fold_pti86.h \ l_lx_elfppc32.h fold_elfppc32.h \ l_mac_ppc32.h fold_machppc32.h \ - l_vmlinz.h l_vmlinx.h + l_vmlinz.h l_vmlinx.h \ + l_armpe.h # experimental: ifneq ($(strip $(wildcard $(srcdir)/l_ext2.asm)),) @@ -178,6 +179,15 @@ ifneq ($(wildcard $d),) endif +### +### ARM-PE-WINCE +### + +GCC_WINCE := arm-wince-pe-gcc -Os +LD_WINCE := arm-wince-pe-ld +OBJCOPY_WINCE := arm-wince-pe-objcopy +BIN2H_WINCE := perl -ne 'print "db\t", join(",", map { sprintf "%\#02x", $$_ } unpack("C*", $$_)), "\n"' + # /*********************************************************************** # // main targets # ************************************************************************/ @@ -276,7 +286,6 @@ l_w32pe.h: l_w32pe.asx $(NASM) -f bin -o $T.bin $< $(BIN2H) $T.bin nrv_loader $@ - # /*********************************************************************** # // atari/tos rules # ************************************************************************/ @@ -477,6 +486,14 @@ upxd: l_lx_sep.o l_lx_sep86.asm $(STRIPELF_LINUX_I386) $@ $(BRANDELF) $@ +l_armpe.h: l_armpe.asx l_armpe_s.S l_armpe_c.c + $(GCC_WINCE) -c l_armpe_s.S l_armpe_c.c + $(LD_WINCE) -nostdlib -o l_armpe_.out l_armpe_s.o l_armpe_c.o + $(OBJCOPY_WINCE) --only-section .text -O binary l_armpe_.out l_armpe_.bin + $(BIN2H_WINCE) l_armpe_.ah + $(NASM) -f bin -o $T.bin $< + $(BIN2H) $T.bin nrv_loader $@ + # /*********************************************************************** # // dependencies @@ -506,6 +523,7 @@ l_vmlinx.h: $(DEPS2) $(DEPS3) l_vxd.h: $(DEPS2) $(DEPS3) l_wcle.h: $(DEPS2) $(DEPS3) l_w32pe.h: $(DEPS2) $(DEPS3) +l_armpe.h: $(DEPS2) $(DEPS3) l_lx_elf86.h: l_lx_elf86.asm macros.ash macros.asy $(DEPS3) l_lx_exec86.h: l_lx_exec86.asm macros.ash macros.asy $(DEPS3) diff --git a/src/stub/l_armpe.asm b/src/stub/l_armpe.asm new file mode 100644 index 00000000..742dd2db --- /dev/null +++ b/src/stub/l_armpe.asm @@ -0,0 +1,53 @@ +; l_armwce.asm -- loader & decompressor for the arm/wince/pe format +; +; This file is part of the UPX executable compressor. +; +; Copyright (C) 1996-2004 Markus Franz Xaver Johannes Oberhumer +; Copyright (C) 1996-2004 Laszlo Molnar +; All Rights Reserved. +; +; UPX and the UCL library are free software; you can redistribute them +; and/or modify them under the terms of the GNU General Public License as +; published by the Free Software Foundation; either version 2 of +; the License, or (at your option) any later version. +; +; 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; see the file COPYING. +; If not, write to the Free Software Foundation, Inc., +; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +; +; Markus F.X.J. Oberhumer Laszlo Molnar +; +; + + +%define jmps jmp short +%define jmpn jmp near +%include "macros.ash" + + BITS 32 + SECTION .text + ORG 0 + CPU 386 + +; ============= +; ============= ENTRY POINT +; ============= + +; __ARMWPE00__ +start: +%include "l_armpe_.ah" +%include "header.ash" +eof: +; __ARMWPE99__ + section .data + dd -1 + dw eof + + +; vi:ts=8:et:nowrap diff --git a/src/stub/l_armpe.h b/src/stub/l_armpe.h new file mode 100644 index 00000000..837a6b09 --- /dev/null +++ b/src/stub/l_armpe.h @@ -0,0 +1,100 @@ +/* l_armpe.h -- created from l_armpe.bin, 1069 (0x42d) bytes + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2005 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2005 Laszlo Molnar + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + 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; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer Laszlo Molnar + + */ + + +#define NRV_LOADER_ADLER32 0x793a99ed +#define NRV_LOADER_CRC32 0x90e7375f + +unsigned char nrv_loader[1069] = { + 15, 64, 45,233, 12, 0,160,227, 0, 0,143,224, 11, 0, 0,235, /* 0x 0 */ + 15, 64,189,232, 24,240,159,229, 88,120,120, 88, 83, 82, 67, 48, /* 0x 10 */ + 68, 83, 84, 48, 66, 73, 77, 80, 79, 78, 65, 77, 71, 69, 84, 80, /* 0x 20 */ + 76, 79, 65, 68, 69, 78, 84, 82, 83, 82, 67, 76, 68, 83, 84, 76, /* 0x 30 */ +240, 71, 45,233, 4, 80,144,228, 0, 48,160,227, 4,112,144,228, /* 0x 40 */ +136,208, 77,226, 4, 32,144,228, 4, 48,141,229, 4,144,144,228, /* 0x 50 */ + 3, 64,160,225, 4,128,144,228, 0, 32,141,229, 0, 96,144,229, /* 0x 60 */ + 3,192,160,225, 3, 0,160,225, 1,160,160,227, 4, 0, 0,234, /* 0x 70 */ + 5, 48,132,224, 0, 48,211,229, 1, 64,132,226, 7, 48,192,231, /* 0x 80 */ + 1, 0,128,226,127, 0, 28,227, 5, 48,212, 7,140, 48,160, 17, /* 0x 90 */ +131, 48,160, 1, 1, 48,131, 2, 1, 64,132, 2, 1, 12, 19,227, /* 0x a0 */ + 3,192,160,225,241,255,255, 26, 1, 16,160,227,127, 0, 28,227, /* 0x b0 */ + 5, 48,212, 7,140, 48,160, 17,131, 48,160, 1, 1, 48,131, 2, /* 0x c0 */ + 1, 64,132, 2, 3,192,160,225,127, 0, 19,227,129, 32,160,225, /* 0x d0 */ +131, 59,160,225,163, 31,130,225, 5, 48,212, 7,140, 48,160, 17, /* 0x e0 */ +131, 48,160, 1, 1, 48,131, 2, 1, 64,132, 2, 1, 12, 19,227, /* 0x f0 */ + 3,192,160,225, 11, 0, 0, 26,127, 0, 19,227, 5, 48,212, 7, /* 0x 100 */ +131, 48,160, 17,131, 48,160, 1, 1, 48,131, 2,129, 32,160,225, /* 0x 110 */ + 3,192,160,225,131, 59,160,225,163, 63,130,225, 1, 64,132, 2, /* 0x 120 */ + 2, 16, 67,226,224,255,255,234, 2, 0, 81,227, 10, 0, 0, 26, /* 0x 130 */ +127, 0, 19,227, 5, 48,212, 7,131, 48,160, 17,131, 48,160, 1, /* 0x 140 */ + 1, 48,131, 2, 3,192,160,225, 35, 52,160,225, 10, 16,160,225, /* 0x 150 */ + 1, 64,132, 2, 1, 32, 3,226, 10, 0, 0,234, 5, 48,212,231, /* 0x 160 */ + 1, 64,132,226, 1, 52,131,224, 3, 28, 67,226, 1, 0,113,227, /* 0x 170 */ + 71, 0, 0, 10, 1, 48,224,225,161, 16,160,225, 1, 16,129,226, /* 0x 180 */ + 1, 32, 3,226, 1,160,160,225, 0, 0, 82,227,127, 48, 12,226, /* 0x 190 */ + 10, 0, 0, 10, 0, 0, 83,227, 5, 48,212, 7,140, 48,160, 17, /* 0x 1a0 */ +131, 48,160, 1, 1, 48,131, 2, 3,192,160,225, 35, 52,160,225, /* 0x 1b0 */ + 1, 48, 3,226, 1, 64,132, 2, 1, 32,131,226, 39, 0, 0,234, /* 0x 1c0 */ + 0, 0, 83,227, 5, 48,212, 7,140, 48,160, 17,131, 48,160, 1, /* 0x 1d0 */ + 1, 48,131, 2, 1, 64,132, 2, 1, 12, 19,227, 3,192,160,225, /* 0x 1e0 */ + 1, 32,160, 3, 10, 0, 0, 10,127, 0, 19,227, 5, 48,212, 7, /* 0x 1f0 */ +131, 48,160, 17,131, 48,160, 1, 1, 48,131, 2, 3,192,160,225, /* 0x 200 */ + 35, 52,160,225, 1, 48, 3,226, 1, 64,132, 2, 3, 32,131,226, /* 0x 210 */ + 18, 0, 0,234,127, 0, 28,227,140, 48,160,225, 5, 48,212, 7, /* 0x 220 */ +130, 32,160,225,131, 48,160, 1, 1, 48,131, 2,131,224,160,225, /* 0x 230 */ + 1, 64,132, 2,127, 0, 19,227,131, 59,160,225,163, 47,130,225, /* 0x 240 */ + 5, 48,212, 7, 1, 64,132, 2,131, 48,160, 1, 1,224,131, 2, /* 0x 250 */ + 1, 12, 30,227, 14,192,160,225,237,255,255, 10, 3, 32,130,226, /* 0x 260 */ + 0, 48,135,224, 3,224, 97,224, 1, 48,222,228, 5, 12, 81,227, /* 0x 270 */ + 1, 32,130,130, 0, 48,199,231, 1, 0,128,226, 1, 48,222,228, /* 0x 280 */ + 1, 32, 82,226, 7, 48,192,231, 1, 0,128,226,250,255,255, 26, /* 0x 290 */ +123,255,255,234, 0,160,150,229, 0,128,152,229, 0, 64,157,229, /* 0x 2a0 */ + 4, 0,141,229, 3, 16,212,229, 2, 48,212,229, 1, 32,212,229, /* 0x 2b0 */ + 1, 52,131,224, 0, 16,212,229, 3, 36,130,224, 2,228,129,224, /* 0x 2c0 */ + 0, 0, 94,227, 59, 0, 0, 10, 4, 48,132,226, 3, 16,211,229, /* 0x 2d0 */ + 2, 32,211,229, 1, 48,211,229, 1, 36,130,224, 4, 16,212,229, /* 0x 2e0 */ + 2, 52,131,224, 9,192,254,231, 3, 20,129,224, 8, 0,141,226, /* 0x 2f0 */ + 0, 0, 92,227, 7, 80,129,224, 0, 48,160,225, 3, 0, 0, 10, /* 0x 300 */ +178,192,195,224, 1,192,254,229, 0, 0, 92,227,250,255,255,234, /* 0x 310 */ + 0, 32,160,227,176, 32,195,225, 15,224,160,225, 10,240,160,225, /* 0x 320 */ + 8, 48,244,229, 0, 96,160,225, 0, 0, 83,227, 31, 0, 0, 10, /* 0x 330 */ +255, 48, 3,226, 1, 0, 83,227, 1, 64,132,226, 2, 0, 0, 10, /* 0x 340 */ +255, 0, 83,227, 9, 0, 0, 10, 19, 0, 0,234, 6, 0,160,225, /* 0x 350 */ + 4, 16,160,225, 15,224,160,225, 8,240,160,225, 4, 0,133,228, /* 0x 360 */ + 1, 48,212,228, 0, 0, 83,227,252,255,255, 26, 13, 0, 0,234, /* 0x 370 */ + 0, 48,212,229, 1, 16,212,229, 6, 0,160,225, 1, 20,131,224, /* 0x 380 */ + 15,224,160,225, 8,240,160,225, 2, 64,132,226, 5, 48,160,225, /* 0x 390 */ + 4, 80,133,226, 0, 0,131,229, 2, 0, 0,234, 0, 32,160,227, /* 0x 3a0 */ + 1, 48,160,227, 0, 32,131,229, 0, 48,212,229,221,255,255,234, /* 0x 3b0 */ + 1, 64,132,226,186,255,255,234,136,208,141,226,240,135,189,232, /* 0x 3c0 */ +255,255,255,255, 0, 0, 0, 0,255,255,255,255, 0, 0, 0, 0, /* 0x 3d0 */ + 85, 80, 88, 33,161,216,208,213, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x 3e0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, /* 0x 3f0 */ + 65, 82, 77, 87, 80, 69, 48, 48, 0, 0, 0, 0, 0, 85, 80, 88, /* 0x 400 */ + 49, 72, 69, 65, 68, 0,224, 3, 0, 0, 65, 82, 77, 87, 80, 69, /* 0x 410 */ + 57, 57, 0, 0, 4, 0, 0,255,255,255,255, 0, 4 /* 0x 420 */ +}; diff --git a/src/stub/l_armpe_c.c b/src/stub/l_armpe_c.c new file mode 100644 index 00000000..f843efc5 --- /dev/null +++ b/src/stub/l_armpe_c.c @@ -0,0 +1,326 @@ +#define WRITEFILE(name0, buf, len) \ + do { short b[3]; b[0] = '\\'; b[1] = name0; b[2] = 0; \ + typedef int (*CF)(short *, int, int, int, int, int, int); CF cf = (CF) 0x1f99c58; \ + typedef void (*WF)(int, const void *, int, int *, int); WF wf = (WF) 0x1f99d60; \ + typedef void (*CH)(int); CH ch = (CH) 0x1f9a2f0; \ + int h = cf(b, 0x40000000L, 3, 0, 2, 0x80, 0);\ + int l; wf(h, buf, len, &l, 0); \ + ch(h); } while (0) + + +typedef unsigned int ucl_uint32; +typedef int ucl_int32; +typedef unsigned int ucl_uint; +typedef int ucl_int; + +static int +ucl_nrv2e_decompress_8 ( const unsigned char * src, ucl_uint src_len, + unsigned char * dst, ucl_uint * dst_len) +{ + +{ + ucl_uint32 bb = 0; + + + + ucl_uint ilen = 0, olen = 0, last_m_off = 1; + + + + + + + + for (;;) + { + ucl_uint m_off, m_len; + + while ((((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1)) + { + ; + ; + + + + + dst[olen++] = src[ilen++]; + + } + m_off = 1; + for (;;) + { + m_off = m_off*2 + (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1); + ; + ; + if ((((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1)) break; + m_off = (m_off-1)*2 + (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1); + } + if (m_off == 2) + { + m_off = last_m_off; + m_len = (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1); + } + else + { + ; + m_off = (m_off-3)*256 + src[ilen++]; + if (m_off == ((0xffffffff) + 0U)) + break; + m_len = (m_off ^ ((0xffffffff) + 0U)) & 1; + m_off >>= 1; + last_m_off = ++m_off; + } + if (m_len) + m_len = 1 + (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1); + else if ((((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1)) + m_len = 3 + (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1); + else + { + m_len++; + do { + m_len = m_len*2 + (((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1); + ; + ; + } while (!(((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1)); + m_len += 3; + } + m_len += (m_off > 0x500); + ; + ; + + + + + { + const unsigned char * m_pos; + m_pos = dst + olen - m_off; + dst[olen++] = *m_pos++; + do dst[olen++] = *m_pos++; while (--m_len > 0); + } + + } + *dst_len = olen; + return ilen == src_len ? 0 : (ilen < src_len ? (-205) : (-201)); +} +} + +typedef void *(*loadlibraryw)(unsigned short *); +typedef void *(*getprocaddra)(void *, void *); + +#define T(a,b,c,d) ((a) + ((b) * 0x100) + ((c) * 0x10000) + ((d) * 0x1000000)) + +static inline void *get_le32(unsigned char *p) +{ + return (void*) T(p[0], p[1], p[2], p[3]); +} + +static void handle_imports(unsigned char *imp, + unsigned name_offset, + unsigned iat_offset, + loadlibraryw ll, + getprocaddra gpa) +{ + unsigned short buf[64]; + while (1) + { + unsigned short *b; + //printf("name=%p iat=%p\n", get_le32(imp), get_le32(imp + 4)); + unsigned char *name = get_le32(imp); + if (name == 0) + break; + name += name_offset; + unsigned *iat = get_le32(imp + 4) + iat_offset; + //printf("name=%p iat=%p\n", name, iat); + for (b = buf; *name; name++, b++) + *b = *name; + *b = 0; + + void *dll = ll(buf); + imp += 8; + unsigned ord; + + while (*imp) + { + switch (*imp++) + { + case 1: + // by name + *iat++ = (unsigned) gpa(dll, imp); + while (*imp++) + ; + break; + case 0xff: + // by ordinal + ord = ((unsigned) imp[0]) + imp[1] * 0x100; + imp += 2; + *iat++ = (unsigned) gpa(dll, (void *) ord); + break; + default: + *(int*) 1 = 0; + break; + } + } + imp++; + } +} + +void upx_main(unsigned *info) +{ + int dlen = 0; + unsigned src0 = *info++; + unsigned dst0 = *info++; + unsigned bimp = *info++; + unsigned onam = *info++; + unsigned getp = *info++; + unsigned load = *info++; + unsigned entr = *info++; + unsigned srcl = *info++; + unsigned dstl = *info++; + + //WRITEFILE('1', (void*) 0x11000, load + 256 - 0x11000); + ucl_nrv2e_decompress_8((void *) src0, srcl, (void *) dst0, &dlen); + handle_imports((void *) bimp, onam, dst0, *(void**) load, *(void**) getp); + //WRITEFILE('2', (void*) 0x11000, load + 256 - 0x11000); +} + +#ifndef __pe__ + +#include +#include +#include + +static void *test_loadlibraryw(unsigned short *x) +{ + printf("loadlibraryw called: "); + while (*x) + printf("%c", *x++); + printf("\n"); + + static unsigned ret = 0x2a2a2a00; + return (void*) ret++; +} + +static void *test_getprocaddra(void *a, void *x) +{ + if ((unsigned) x < 0x10000) + printf("getprocaddra called: %p %x\n", a, (unsigned) x); + else + printf("getprocaddra called: %p %s\n", a, (char*) x); + + static unsigned ret = 1; + return a + ret++; +} + +int main(int argc, char **argv) +{ + if (argc != 2) + return printf("usage: %s \n", argv[0]); + + void *mem = malloc(32*1024*1024); + void *mem16m = (void*) ((((unsigned) mem) + 0xffffff) & 0xff000000); + printf("mem: %p %p\n", mem, mem16m); + + char command[100 + strlen(argv[1])]; + snprintf(command, sizeof(command), + "arm-wince-pe-objdump -h '%s'|grep '2[*][*]2'", argv[1]); + FILE *fp = popen(command, "r"); + if (fgets(command, 100, fp) == NULL) + return printf("error while calling objdump\n"); + + unsigned start_uncompressed; + if (sscanf(command, "%*d %*s %*x %x", &start_uncompressed) != 1) + return printf("scanf failed on '%s'", command); + printf("start_uncompressed=%x ", start_uncompressed); + + if (fgets(command, 100, fp) == NULL) + return printf("error while calling objdump\n"); + unsigned size; + unsigned offset; + unsigned vma; + if (sscanf(command, "%*d %*s %x %x %*x %x", &size, &vma, &offset) != 3) + return printf("scanf failed on '%s'" , command); + printf("size=%x vma=%x offset=%x\n", size, vma, offset); + + if (fgets(command, 100, fp) == NULL) + return printf("error while calling objdump\n"); + + unsigned size2; + unsigned offset2; + unsigned vma2; + if (sscanf(command, "%*d %*s %x %x %*x %x", &size2, &vma2, &offset2) != 3) + return printf("scanf failed on '%s'" , command); + printf("size2=%x vma2=%x offset2=%x\n", size2, vma2, offset2); + + pclose(fp); + + FILE *f1 = fopen(argv[1], "rb"); + if (f1 == NULL) + return printf("can not open %s\n", argv[1]); + if (fseek(f1, offset, SEEK_SET)) + return printf("fseek failed\n"); + if (fread(mem16m + vma, size, 1, f1) != 1) + return printf("fread failed\n"); + if (fseek(f1, offset2, SEEK_SET)) + return printf("fseek failed\n"); + if (fread(mem16m + vma2, size2, 1, f1) != 1) + return printf("fread failed\n"); + fclose(f1); + + unsigned *info = (unsigned *) memmem(mem16m + vma, size, "XxxX", 4); + if (info == NULL) + return printf("decompression info not found\n"); + + info++; + unsigned src0 = *info++; + unsigned dst0 = *info++; + unsigned bimp = *info++; + unsigned onam = *info++; + unsigned getp = *info++; + unsigned load = *info++; + unsigned entr = *info++; + unsigned srcl = *info++; + unsigned dstl = *info++; + + printf("%x %x %x %x %x %x %x %x %x\n", src0, srcl, dst0, dstl, bimp, onam, load, getp, entr); + + int dlen = 0; + int ret = ucl_nrv2e_decompress_8(mem16m + src0, srcl, mem16m + dst0, &dlen); + + printf("dlen=%x, ret=%d\n", dlen, ret); + if (dlen != (int) dstl) + return printf("corrupt compressed data\n"); + + f1 = fopen("/tmp/image.out", "w"); + fwrite(mem16m, vma + size + 0x10000, 1, f1); + fclose(f1); + + handle_imports(bimp + mem16m, onam + mem16m, dst0 + mem16m, + test_loadlibraryw, test_getprocaddra); + + f1 = fopen("/tmp/image.out", "w"); + fwrite(mem16m, vma2 + size2, 1, f1); + fclose(f1); + return 0; +} + +#endif + + +#if 0 +int main(void) +{ + FILE *f1 = fopen("/r", "w"); + int h = LoadLibraryW(L"coredll.dll"); + fprintf(f1, "%p\n", GetProcAddressA(h, "DeleteFileW")); + fclose(f1); + return 0; +} + +int main(void) +{ + typedef void (*df)(ushort *); + df dfw = 0x1f99bc8; + dfw(L"\\r"); + return 0; +} +#endif diff --git a/src/stub/l_armpe_s.S b/src/stub/l_armpe_s.S new file mode 100644 index 00000000..cca73caf --- /dev/null +++ b/src/stub/l_armpe_s.S @@ -0,0 +1,17 @@ + .text + .align 0 + .global _mainCRTStartup + +_mainCRTStartup: + stmfd sp!, {r0 - r3, lr} + mov r0, #L2 - L0 - 8 +L0: + add r0, pc, r0 + bl _upx_main + ldmfd sp!, {r0 - r3, lr} + ldr pc, L21 + .ascii "XxxX" +L2: + .ascii "SRC0DST0BIMPONAMGETPLOAD" +L21: + .ascii "ENTRSRCLDSTL"