From 5b8a9c0b470b42cf2ca2a852cdf603174c9bb7c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20Moln=C3=A1r?= Date: Thu, 22 Aug 2013 22:01:09 +0200 Subject: [PATCH] basic win64 PE support added --- src/conf.h | 2 + src/p_w64pep.cpp | 1568 ++++++++++++++++++++++ src/p_w64pep.h | 87 ++ src/packmast.cpp | 5 + src/pepfile.cpp | 1728 +++++++++++++++++++++++++ src/pepfile.h | 386 ++++++ src/stub/Makefile | 15 + src/stub/amd64-win64.pep.h | 766 +++++++++++ src/stub/src/amd64-win64.pep.S | 431 ++++++ src/stub/src/arch/amd64/nrv2e_d.S | 4 + src/stub/tmp/amd64-win64.pep.bin.dump | 193 +++ 11 files changed, 5185 insertions(+) create mode 100644 src/p_w64pep.cpp create mode 100644 src/p_w64pep.h create mode 100644 src/pepfile.cpp create mode 100644 src/pepfile.h create mode 100644 src/stub/amd64-win64.pep.h create mode 100644 src/stub/src/amd64-win64.pep.S create mode 100644 src/stub/tmp/amd64-win64.pep.bin.dump diff --git a/src/conf.h b/src/conf.h index 862ad105..da2de08c 100644 --- a/src/conf.h +++ b/src/conf.h @@ -487,6 +487,8 @@ private: #define UPX_F_MACH_AMD64 34 #define UPX_F_DYLIB_AMD64 35 +#define UPX_F_WIN64_PEP 36 + #define UPX_F_PLAIN_TEXT 127 #define UPX_F_ATARI_TOS 129 diff --git a/src/p_w64pep.cpp b/src/p_w64pep.cpp new file mode 100644 index 00000000..6a7cead0 --- /dev/null +++ b/src/p_w64pep.cpp @@ -0,0 +1,1568 @@ +/* p_w64pep.cpp -- + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2013 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2013 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 + + + ------------------------------------------------------------------- + + PE+ format extension changes (C) 2010 Stefan Widmann + changes in: + + */ + + +#include "conf.h" +#include "file.h" +#include "filter.h" +#include "packer.h" +#include "pepfile.h" +#include "p_w64pep.h" +#include "linker.h" + +static const +#include "stub/amd64-win64.pep.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 + + +/************************************************************************* +// +**************************************************************************/ + +#if defined(__BORLANDC__) +# undef strcpy +# define strcpy(a,b) strcpy((char *)(a),(const char *)(b)) +#endif + +#if 0 //NEW: Stefan Widmann +//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 + + +#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) + + +/************************************************************************* +// +**************************************************************************/ + +PackW64Pep::PackW64Pep(InputFile *f) : super(f) +{ + oloadconf = NULL; + soloadconf = 0; + isrtm = false; + use_dep_hack = true; + use_clear_dirty_stack = true; + use_tls_callbacks = false; +} + + +PackW64Pep::~PackW64Pep() +{ + delete [] oloadconf; +} + + +const int *PackW64Pep::getCompressionMethods(int /*method*/, int /*level*/) const +{ + // FIXME bool small = ih.codesize + ih.datasize <= 256*1024; + //return Packer::getDefaultCompressionMethods_le32(method, level, small); + static const int m_nrv2e[] = { M_NRV2E_LE32, M_END }; + return m_nrv2e; +} + + +const int *PackW64Pep::getFilters() const +{ + static const int filters[] = { FT_END }; + return filters; +} + + +Linker* PackW64Pep::newLinker() const +{ + return new ElfLinkerAMD64; +} + + +/************************************************************************* +// util +**************************************************************************/ + +int PackW64Pep::readFileHeader() +{ + char buf[6]; + fi->seek(0x200, SEEK_SET); + fi->readx(buf, 6); + isrtm = 0; + return super::readFileHeader(); +} + +/************************************************************************* +// import handling +**************************************************************************/ + +__packed_struct(import_desc) + LE32 oft; // orig first thunk + char _[8]; + LE32 dllname; + LE32 iat; // import address table +__packed_struct_end() + +void PackW64Pep::processImports(unsigned myimport, unsigned) // 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; + LE64 *p = (LE64*) (oimpdlls + im->iat); //changed to LE64 - Stefan Widmann + im->iat += myimport; + + while (*p) + if ((*p++ & 0x8000000000000000ULL) == 0) // changed to 64 bit - Stefan Widmann + p[-1] += myimport; + } +} + +unsigned PackW64Pep::processImports() // pass 1 +{ + static const unsigned char kernel32dll[] = "KERNEL32.DLL"; + static const char llgpa[] = "\x0\x0""LoadLibraryA\x0\x0" + "GetProcAddress\x0\x0" + "VirtualProtect\x0\x0" + "VirtualAlloc\x0\x0" + "VirtualFree\x0\x0\x0"; + 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; + LE64 *lookupt; //changed to LE64* - Stefan Widmann + unsigned npos; + unsigned original_position; + bool isk32; + + 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; + if (!*u1->lookupt) return 1; + if (!*u2->lookupt) 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); + } + }; + + // +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 = (LE64*) (ibuf + (im->oft ? im->oft : im->iat)); //changed to LE64* - Stefan Widmann + dlls[ic].npos = 0; + dlls[ic].original_position = ic; + dlls[ic].isk32 = strcasecmp(kernel32dll,dlls[ic].name) == 0; + + soimport += strlen(dlls[ic].name) + 1 + 4; + + // FIXME use IPTR_I as in p32pe.cpp + for (LE64 *tarr = dlls[ic].lookupt; *tarr; tarr++) //changed to LE64* - Stefan Widmann + { + if (*tarr & 0x8000000000000000ULL) //in PE32+, bit 63 indicates an ordinal + { + importbyordinal = true; + soimport += 2; // ordinal num: 2 bytes + dlls[ic].ordinal = *tarr & 0xffff; + if (dlls[ic].isk32) + kernel32ordinal = true,k32o++; + } + else //it's an import by name + { + 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; + + LE64 *ordinals = (LE64*) (oimpdlls + (dllnum2 + 1) * sizeof(import_desc)); //changed to LE64* - Stefan Widmann + LE64 *lookuptable = ordinals + 6 + k32o + (isdll ? 0 : 1); //changed to LE64* - Stefan Widmann + upx_byte *dllnames = ((upx_byte*) lookuptable) + (dllnum2 - 1) * 16; //double the size per hint - is that correct? - Stefan Widmann + upx_byte *importednames = dllnames + (dllnamelen &~ 1); + + unsigned k32namepos = ptr_diff(dllnames,oimpdlls); + + memcpy(importednames, llgpa, sizeof(llgpa)); + if (!isdll) + memcpy(importednames + sizeof(llgpa) - 1, exitp, sizeof(exitp)); + strcpy(dllnames,kernel32dll); + im->dllname = k32namepos; + im->iat = ptr_diff(ordinals,oimpdlls); + *ordinals++ = ptr_diff(importednames,oimpdlls); // LoadLibraryA + *ordinals++ = ptr_diff(importednames,oimpdlls) + 14; // GetProcAddress + *ordinals++ = ptr_diff(importednames,oimpdlls) + 14 + 16; // VirtualProtect + *ordinals++ = ptr_diff(importednames,oimpdlls) + 14 + 16 + 16; // VirtualAlloc + *ordinals++ = ptr_diff(importednames,oimpdlls) + 14 + 16 + 16 + 14; // VirtualFree + if (!isdll) + *ordinals++ = ptr_diff(importednames,oimpdlls) + sizeof(llgpa) - 3; // ExitProcess + dllnames += sizeof(kernel32dll); + importednames += sizeof(llgpa) - 2 + (isdll ? 0 : sizeof(exitp) - 1); + + im++; + for (ic = 0; ic < dllnum; ic++) + if (idlls[ic]->isk32) + { + idlls[ic]->npos = k32namepos; + if (idlls[ic]->ordinal) + for (LE64 *tarr = idlls[ic]->lookupt; *tarr; tarr++) //changed to LE64* - Stefan Widmann + if (*tarr & 0x8000000000000000ULL) //in PE32+, bit 63 indicates an ordinal - Stefan Widmann + *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 + 0x8000000000000000ULL; //bit 63 indicates an ordinal - Stefan Widmann + 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 + ordinals -= k32o; + upx_byte *ppi = oimport; // preprocessed imports + for (ic = 0; ic < dllnum; ic++) + { + //LE32 *tarr = idlls[ic]->lookupt; + LE64 *tarr = idlls[ic]->lookupt; //changed to LE64* - Stefan Widmann +#if 0 && ENABLE_THIS_AND_UNCOMPRESSION_WILL_BREAK // FIXME + if (!*tarr) // no imports from this dll + continue; +#endif + set_le32(ppi,idlls[ic]->npos); + set_le32(ppi+4,idlls[ic]->iat - rvamin); + ppi += 8; + for (; *tarr; tarr++) + if (*tarr & 0x8000000000000000ULL) //bit 63 indicates ordinal - Stefan Widmann + { + 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(dlls[idlls[ic]->original_position].name,ibuf); + } + } + 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; +} + +/************************************************************************* +// 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 ;-) + +#define TLS_CB_ALIGNMENT 8u // alignment of tls callbacks + +__packed_struct(tls) + LE64 datastart; // VA tls init data start + LE64 dataend; // VA tls init data end + LE64 tlsindex; // VA tls index + LE64 callbacks; // VA tls callbacks + char _[8]; // zero init, characteristics +__packed_struct_end() + +void PackW64Pep::processTls(Interval *iv) // pass 1 +{ + COMPILE_TIME_ASSERT(sizeof(tls) == 40) //size of TLS structure is 40 byte now + COMPILE_TIME_ASSERT_ALIGNED1(tls) + + 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 long long v = get_le64(ibuf + (tlsp->callbacks - ih.imagebase)); + if (v != 0) + { + //count number of callbacks, just for information string - Stefan Widmann + unsigned num_callbacks = 0; + unsigned callback_offset = 0; + while(get_le64(ibuf + (tlsp->callbacks - ih.imagebase) + callback_offset)) + { + //increment number of callbacks + num_callbacks++; + //increment pointer by 8 + callback_offset += 8; + } + info("TLS: %u callback(s) found, adding TLS callback handler", num_callbacks); + //set flag to include necessary sections in loader + use_tls_callbacks = true; + //define linker symbols + tlscb_ptr = tlsp->callbacks; + } + } + + 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; + // if TLS callbacks are used, we need two more QWORDS at the end of the TLS + // ... and those qwords should be correctly aligned + if (use_tls_callbacks) + sotls = ALIGN_UP(sotls, TLS_CB_ALIGNMENT) + 16; + + // the PE loader wants this stuff uncompressed + otls = new upx_byte[sotls]; + memset(otls,0,sotls); + memcpy(otls,ibuf + IDADDR(PEDIR_TLS), sizeof(tls)); + // 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) - (use_tls_callbacks ? 16 : 0),iv->ivnum); + + // makes sure tls index is zero after decompression + if (tlsindex && tlsindex < ih.imagesize) + set_le64(ibuf + tlsindex, 0); //changed to LE64 - Stefan Widmann +} + +void PackW64Pep::processTls(Reloc *rel,const Interval *iv,unsigned newaddr) // pass 2 +{ + if (sotls == 0) + return; + // add new relocation entries + unsigned ic; + for (ic = 0; ic < (use_tls_callbacks ? 32u : 24u); ic += 8) + rel->add(newaddr + ic,10); + + tls * const tlsp = (tls*) otls; + // now the relocation entries in the tls data area + + + // FIXME check this code below!!! + for (ic = 0; ic < iv->ivnum; ic += 4) + { + void *p = otls + iv->ivarr[ic].start - (tlsp->datastart - ih.imagebase) + sizeof(tls); + unsigned long long kc = get_le64(p); //changed to LE64 - Stefan Widmann + if (kc < tlsp->dataend && kc >= tlsp->datastart) + { + kc += newaddr + sizeof(tls) - tlsp->datastart; + set_le64(p,kc + ih.imagebase); //changed to LE64 - Stefan Widmann + rel->add(kc,iv->ivarr[ic].len); + } + else + rel->add(kc - ih.imagebase,iv->ivarr[ic].len); + } + + const unsigned tls_data_size = tlsp->dataend - tlsp->datastart; + tlsp->datastart = newaddr + sizeof(tls) + ih.imagebase; + tlsp->dataend = tlsp->datastart + tls_data_size; + + tlsp->callbacks = (use_tls_callbacks ? newaddr + sotls + ih.imagebase - 16 : 0); + + if (use_tls_callbacks) + { + //set handler offset + set_le32(otls + sotls - 16, tls_handler_offset + ih.imagebase); + //add relocation for TLS handler offset + rel->add(newaddr + sotls - 16, 10); + } +} + + +/************************************************************************* +// Load Configuration handling +**************************************************************************/ + +void PackW64Pep::processLoadConf(Interval *iv) // pass 1 +{ + if (IDSIZE(PEDIR_LOADCONF) == 0) + return; + + const unsigned lcaddr = IDADDR(PEDIR_LOADCONF); + const upx_byte * const loadconf = ibuf + lcaddr; + soloadconf = get_le32(loadconf); + if (soloadconf == 0) + return; + if (soloadconf > 256) + throwCantPack("size of Load Configuration directory unexpected"); + + // if there were relocation entries referring to the load config table + // then we need them for the copy of the table too + unsigned pos,type; + Reloc rel(ibuf + IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC)); + while (rel.next(pos, type)) + if (pos >= lcaddr && pos < lcaddr + soloadconf) + { + iv->add(pos - lcaddr, type); + // printf("loadconf reloc detected: %x\n", pos); + } + + oloadconf = new upx_byte[soloadconf]; + memcpy(oloadconf, loadconf, soloadconf); +} + +void PackW64Pep::processLoadConf(Reloc *rel, const Interval *iv, + unsigned newaddr) // pass2 +{ + // now we have the address of the new load config table + // so we can create the new relocation entries + for (unsigned ic = 0; ic < iv->ivnum; ic++) + { + rel->add(iv->ivarr[ic].start + newaddr, iv->ivarr[ic].len); + //printf("loadconf reloc added: %x %d\n", + // iv->ivarr[ic].start + newaddr, iv->ivarr[ic].len); + } +} + + +/************************************************************************* +// pack +**************************************************************************/ + +bool PackW64Pep::canPack() +{ + //just check if machine type is 0x8664 + if (!readFileHeader() || ih.cpu != 0x8664) // CPU magic of AMD64 is 0x8664 + return false; + return true; +} + + +void PackW64Pep::buildLoader(const Filter *ft) +{ + // recompute tlsindex (see pack() below) + unsigned tmp_tlsindex = tlsindex; + const unsigned oam1 = ih.objectalign - 1; + const unsigned newvsize = (ph.u_len + rvamin + ph.overlap_overhead + oam1) &~ oam1; + if (tlsindex && ((newvsize - ph.c_len - 1024 + oam1) &~ oam1) > tlsindex + 4) + tmp_tlsindex = 0; + + // prepare loader + initLoader(stub_amd64_win64_pep, sizeof(stub_amd64_win64_pep), 2); + addLoader(isdll ? "PEISDLL1" : "", + "PEMAIN01", + icondir_count > 1 ? (icondir_count == 2 ? "PEICONS1" : "PEICONS2") : "", + tmp_tlsindex ? "PETLSHAK" : "", + "PEMAIN02", + //ph.first_offset_found == 1 ? "PEMAIN03" : "", + "NRV_HEAD", + "NRV2E", + //getDecompressorSections(), + /*multipass ? "PEMULTIP" : */ "", + "PEMAIN10", + NULL + ); + if (ft->id) + { + const unsigned texv = ih.codebase - rvamin; + assert(ft->calls > 0); + addLoader(texv ? "PECTTPOS" : "PECTTNUL",NULL); + addFilter32(ft->id); + } + if (soimport) + addLoader("PEIMPORT", + importbyordinal ? "PEIBYORD" : "", + kernel32ordinal ? "PEK32ORD" : "", + importbyordinal ? "PEIMORD1" : "", + "PEIMPOR2", + isdll ? "PEIERDLL" : "PEIEREXE", + "PEIMDONE", + NULL + ); + if (sorelocs) + { + addLoader(soimport == 0 || soimport + cimports != crelocs ? "PERELOC1" : "PERELOC2", + "PERELOC3,RELOC320", + big_relocs ? "REL32BIG" : "", + "RELOC32J", + NULL + ); + //FIXME: the following should be moved out of the above if + addLoader(big_relocs&6 ? "PERLOHI0" : "", + big_relocs&4 ? "PERELLO0" : "", + big_relocs&2 ? "PERELHI0" : "", + NULL + ); + } + if (use_dep_hack) + addLoader("PEDEPHAK", NULL); + + //NEW: TLS callback support PART 1, the callback handler installation - Stefan Widmann + if(use_tls_callbacks) + addLoader("PETLSC", NULL); + + addLoader("PEMAIN20", NULL); + if (use_clear_dirty_stack) + addLoader("CLEARSTACK", NULL); + addLoader("PEMAIN21", NULL); + + //NEW: last loader sections split up to insert TLS callback handler - Stefan Widmann + addLoader(ih.entry ? "PEDOJUMP" : "PERETURN", NULL); + + //NEW: TLS callback support PART 2, the callback handler - Stefan Widmann + if(use_tls_callbacks) + addLoader("PETLSC2", NULL); + + addLoader("IDENTSTR,UPX1HEAD", NULL); + +} + + +void PackW64Pep::pack(OutputFile *fo) +{ + // FIXME: we need to think about better support for --exact + if (opt->exact) + throwCantPackExact(); + + 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 + // subsystem check moved to switch ... case below + if (!opt->force && ( + (ih.cpu != 0x8664) //CPU magic of AMD64 is 0x8664 + || (ih.opthdrsize != 0xF0) //optional header size is 0xF0 in PE32+ files - Stefan Widmann + || (ih.coffmagic != 0x20B) //COFF magic is 0x20B in PE+ files, 0x10B in "normal" 32 bit PE files - Stefan Widmann + || ((ih.flags & EXECUTABLE) == 0) + || ((ih.flags & BITS_32_MACHINE) == 1) //NEW: 32 bit machine flag may not be set - Stefan Widmann + || (ih.entry == 0 && !isdll) + || (ih.ddirsentries != 16) + )) + throwCantPack("unexpected value in PE header (try --force)"); + + switch(ih.subsystem) //let's take a closer look at the subsystem + { + case 1: //NATIVE + { + throwCantPack("win64/native applications are not yet supported"); + break; + } + case 2: //GUI + { + //fine, continue + break; + } + case 3: //CONSOLE + { + //fine, continue + break; + } + case 5: //OS2 - are there any x64/os2 files? + { + throwCantPack("win64/os2 files are not yet supported"); + break; + } + case 7: //POSIX - do win64/posix files exist? + { + throwCantPack("win64/posix files are not yet supported"); + break; + } + case 9: //WINCE - same question: do they exist? + { + throwCantPack("PE32+/wince files are not yet supported"); + break; + } + case 10: //EFI APPLICATION + { + throwCantPack("PE32+/EFIapplication files are not yet supported"); + break; + } + case 11: //EFI BOOT SERVICE DRIVER + { + throwCantPack("PE32+/EFIbootservicedriver files are not yet supported"); + break; + } + case 12: //EFI RUNTIME DRIVER + { + throwCantPack("PE32+/EFIruntimedriver files are not yet supported"); + break; + } + case 13: //EFI ROM + { + throwCantPack("PE32+/EFIROM files are not yet supported"); + break; + } + case 14: //XBOX - will there ever be PE32+ xbox files? + { + throwCantPack("PE32+/xbox files are not yet supported"); + break; + } + case 16: //WINDOWS BOOT APPLICATION + { + throwCantPack("win64/windowsbootapplication files are not yet supported"); + break; + } + default: //UNKNOWN SUBSYSTEM + { + throwCantPack("PE32+/? unknown subsystem"); + break; + } + } + + //remove certificate pointers from directory table + if (IDSIZE(PEDIR_SEC)) + IDSIZE(PEDIR_SEC) = IDADDR(PEDIR_SEC) = 0; + + //check if we have a CLR Runtime Header pointer + if (IDSIZE(PEDIR_COMRT)) + throwCantPack(".NET files (win64/.net) are not yet supported"); + + //FIXME: Relocation stripping disabled yet - Stefan Widmann + opt->win32_pe.strip_relocs = true;//false; +#if 0 //removed - Stefan Widmann + if (isdll) + opt->win32_pe.strip_relocs = false; + else if (opt->win32_pe.strip_relocs < 0) + opt->win32_pe.strip_relocs = (ih.imagebase >= 0x0000000140000000ULL); + if (opt->win32_pe.strip_relocs) + { + if (ih.imagebase < 0x0000000140000000ULL) + throwCantPack("--strip-relocs is not allowed when imagebase < 0x0000000140000000"); + else + ih.flags |= RELOCS_STRIPPED; + } +#endif + + //check if first section's name is "UPX" + if (memcmp(isection[0].name,"UPX",3) == 0) + throwAlreadyPackedByUPX(); + if (!opt->force && IDSIZE(15)) + throwCantPack("file is possibly packed/protected (try --force)"); + if (ih.entry && ih.entry < rvamin) + throwCantPack("run a virus scanner on this file!"); +#if 0 //subsystem check moved to switch ... case above - Stefan Widmann + if (!opt->force && ih.subsystem == 1) + throwCantPack("subsystem 'native' is not supported (try --force)"); +#endif + 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 (!isrtm && ((isection[ic].flags & (PEFL_WRITE|PEFL_SHARED)) + == (PEFL_WRITE|PEFL_SHARED))) + if (!opt->force) + throwCantPack("writable 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; + } + +#if 0 //Stefan Widmann: still necessary? + // check for NeoLite + if (find(ibuf + ih.entry, 64+7, "NeoLite", 7) >= 0) + throwCantPack("file is already compressed with another packer"); +#endif + + 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); + Interval loadconfiv(ibuf); + Export xport((char*)(unsigned char*)ibuf); + + const unsigned dllstrings = processImports(); + processTls(&tlsiv); // call before processRelocs!! + processLoadConf(&loadconfiv); + processResources(&res); + processExports(&xport); + processRelocs(); + + //OutputFile::dump("x1", ibuf, usize); + + // some checks for broken linkers - disable filter if necessary + bool allow_filter = false; +/* + 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 filter_strategy = allow_filter ? 0 : -3; + + // disable filters for files with broken headers + if (ih.codebase + ih.codesize > ph.u_len) + { + ft.buf_len = 1; + filter_strategy = -3; + } + + compressWithFilters(&ft, 2048, NULL_cconf, filter_strategy, + ih.codebase, rvamin, 0, NULL, 0); +// 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; + + 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 + loadconf + // 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 + + // note: there should be no data in section 2 which needs fixup + + // 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 c_len = ((ph.c_len + ic) & 15) == 0 ? ph.c_len : ph.c_len + 16 - ((ph.c_len + ic) & 15); + obuf.clear(ph.c_len, c_len - ph.c_len); + + const unsigned s1size = ALIGN_UP(ic + c_len + codesize,4u) + sotls + soloadconf; + const unsigned s1addr = (newvsize - (ic + c_len) + oam1) &~ oam1; + + const unsigned ncsection = (s1addr + s1size + oam1) &~ oam1; + const unsigned upxsection = s1addr + ic + c_len; + const unsigned myimport = ncsection + soresources - rvamin; + + // patch loader + linker->defineSymbol("original_entry", ih.entry); + if (use_dep_hack) + { + // This works around a "protection" introduced in MSVCRT80, which + // works like this: + // When the compiler detects that it would link in some code from its + // C runtime library which references some data in a read only + // section then it compiles in a runtime check whether that data is + // still in a read only section by looking at the pe header of the + // file. If this check fails the runtime does "interesting" things + // like not running the floating point initialization code - the result + // is a R6002 runtime error. + // These supposed to be read only addresses are covered by the sections + // UPX0 & UPX1 in the compressed files, so we have to patch the PE header + // in the memory. And the page on which the PE header is stored is read + // only so we must make it rw, fix the flags (i.e. clear + // PEFL_WRITE of osection[x].flags), and make it ro again. + + // rva of the most significant byte of member "flags" in section "UPX0" + const unsigned swri = pe_offset + sizeof(oh) + sizeof(pe_section_t) - 1; + // make sure we only touch the minimum number of pages + const unsigned addr = 0u - rvamin + swri; + linker->defineSymbol("swri", addr & 0xfff); // page offset + // check whether osection[0].flags and osection[1].flags + // are on the same page + linker->defineSymbol("vp_size", ((addr & 0xfff) + 0x28 >= 0x1000) ? + 0x2000 : 0x1000); // 2 pages or 1 page + linker->defineSymbol("vp_base", addr &~ 0xfff); // page mask + //NEW: offset of import adjusted - Stefan Widmann + linker->defineSymbol("VirtualProtect", myimport + get_le32(oimpdlls + 16) + 16); + } +// FIXME linker->defineSymbol("reloc_delt", 0u - (unsigned) (ih.imagebase - rvamin)); + linker->defineSymbol("start_of_relocs", crelocs); + //NEW: offset of import adjusted - Stefan Widmann + linker->defineSymbol("ExitProcess", myimport + get_le32(oimpdlls + 16) + 40); + //NEW: offset of import adjusted - Stefan Widmann + linker->defineSymbol("GetProcAddress", myimport + get_le32(oimpdlls + 16) + 8); + linker->defineSymbol("kernel32_ordinals", myimport); + //NEW: offset of import adjusted - Stefan Widmann + linker->defineSymbol("LoadLibraryA", myimport + get_le32(oimpdlls + 16)); + linker->defineSymbol("start_of_imports", myimport); + linker->defineSymbol("compressed_imports", cimports); +#if 0 + //NEW: offset of import adjusted - Stefan Widmann + linker->defineSymbol("VirtualAlloc", myimport + get_le32(oimpdlls + 16) + 24); + //NEW: offset of import adjusted - Stefan Widmann + linker->defineSymbol("VirtualFree", myimport + get_le32(oimpdlls + 16) + 32); +#endif + +//FIXME defineDecompressorSymbols(); +//FIXME defineFilterSymbols(&ft); + linker->defineSymbol("filter_buffer_start", ih.codebase - rvamin); + + // in case of overlapping decompression, this hack is needed, + // because windoze zeroes the word pointed by tlsindex before + // it starts programs + linker->defineSymbol("tls_value", (tlsindex + 4 > s1addr) ? + get_le32(obuf + tlsindex - s1addr - ic) : 0); + linker->defineSymbol("tls_address", tlsindex - rvamin); + + linker->defineSymbol("icon_delta", icondir_count - 1); + linker->defineSymbol("icon_offset", ncsection + icondir_offset - rvamin); + + const unsigned esi0 = s1addr + ic; + linker->defineSymbol("start_of_uncompressed", 0u - esi0 + rvamin); + linker->defineSymbol("start_of_compressed", esi0 + ih.imagebase); + //NEW: TLS callback support - Stefan Widmann + ic = s1addr + s1size - sotls - soloadconf; //moved here, we need the address of the new TLS! + if (use_tls_callbacks) + { + linker->defineSymbol("tls_callbacks_ptr", tlscb_ptr); + linker->defineSymbol("tls_module_base", 0u - rvamin); + } + + linker->defineSymbol(isdll ? "PEISDLL1" : "PEMAIN01", upxsection); + //linker->dumpSymbols(); + relocateLoader(); + + const unsigned lsize = getLoaderSize(); + MemBuffer loader(lsize); + memcpy(loader,getLoader(),lsize); + patchPackHeader(loader, lsize); + + Reloc rel(1024); // new relocations are put here + rel.add(linker->getSymbolOffset("PEMAIN01") + 6, 10); // FIXME + + // 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; //remove debug data + ODSIZE(PEDIR_DEBUG) = 0; + ODADDR(PEDIR_IAT) = 0; //remove IAT pointer + ODSIZE(PEDIR_IAT) = 0; + ODADDR(PEDIR_BOUNDIM) = 0; //remove bound import table + ODSIZE(PEDIR_BOUNDIM) = 0; + + //EXCEPTION DIRECTORY HANDLING - Stefan Widmann + //APPROACH 1: just keep the exception directory, it's only used during runtime, not during init + // -> nothing to do +#if 0 + //APPROACH 2: we remove the exception directory from the header, the stub installs the table + // after decompression by calling RtlAddFunctionTable (see MSDN for details) + ODADDR(PEDIR_EXCEPTION) = 0; + ODSIZE(PEDIR_EXCEPTION) = 0; + //set flag + use_exception_dir = true; + //link code to loader + linker->defineSymbol("exception_ptr", IDADDR(PEDIRE_EXCEPTION)); //stub needs data about function table + linker->defineSymbol("exception_size", IDSIZE(PEDIR_EXCEPTION)); +#endif + + // tls & loadconf are put into section 1 + + //ic = s1addr + s1size - sotls - soloadconf; //ATTENTION: moved upwards to TLS callback handling - Stefan Widmann + //get address of TLS callback handler + if (use_tls_callbacks) + { + tls_handler_offset = linker->getSymbolOffset("PETLSC2"); + //add relocation entry for TLS callback handler + rel.add(tls_handler_offset + 5, 10); + } + + processTls(&rel,&tlsiv,ic); + ODADDR(PEDIR_TLS) = sotls ? ic : 0; + ODSIZE(PEDIR_TLS) = sotls ? 0x28 : 0; // size of TLS is 0x28 in PE32+ - Stefan Widmann + ic += sotls; + + processLoadConf(&rel, &loadconfiv, ic); + ODADDR(PEDIR_LOADCONF) = soloadconf ? ic : 0; + ODSIZE(PEDIR_LOADCONF) = soloadconf; + ic += soloadconf; + + // 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, 0); + 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[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; //no base of data in PE32+ files - Stefan Widmann + oh.codesize = osection[1].vsize; + oh.codebase = osection[1].vaddr; + // oh.headersize = osection[0].rawdataptr; + oh.headersize = rvamin; + if (rvamin < osection[0].rawdataptr) + throwCantPack("object alignment too small"); + + 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); + + info("Image size change: %u -> %u KiB", + ih.imagesize / 1024, oh.imagesize / 1024); + + 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,c_len); + infoWriting("compressed data", c_len); + fo->write(loader,codesize); + if (opt->debug.dump_stub_loader) + OutputFile::dump(opt->debug.dump_stub_loader, loader, codesize); + if ((ic = fo->getBytesWritten() & 3) != 0) + fo->write(ibuf,4 - ic); + fo->write(otls,sotls); + fo->write(oloadconf, soloadconf); + 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) c_len); + 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); + printf("%-13s: loadconf : %8ld bytes\n", getName(), (long) soloadconf); +#endif + + // verify + verifyOverlappingDecompression(); + + // copy the overlay + copyOverlay(fo, overlay, &obuf); + +#if 0 //REMOVED FOR TESTING! Stefan Widmann + // finally check the compression ratio + if (!checkFinalCompressionRatio(fo)) + throwNotCompressible(); +#endif +} + +/************************************************************************* +// unpack +**************************************************************************/ + +int PackW64Pep::canUnpack() +{ + if (!readFileHeader() || ih.cpu != 0x8664) + return false; + + 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); + if (ih.objects < 3) + return -1; + bool is_packed = (ih.objects == 3 && + (IDSIZE(15) || ih.entry > isection[1].vaddr)); + bool found_ph = false; + if (memcmp(isection[0].name,"UPX",3) == 0) + { + // current version + fi->seek(isection[1].rawdataptr - 64, SEEK_SET); + found_ph = readPackHeader(1024); + if (!found_ph) + { + // old versions + fi->seek(isection[2].rawdataptr, SEEK_SET); + found_ph = readPackHeader(1024); + } + } + if (is_packed && found_ph) + return true; + if (!is_packed && !found_ph) + return -1; + if (is_packed && ih.entry < isection[2].vaddr) + { + unsigned char buf[256]; + bool x = false; + + memset(buf, 0, sizeof(buf)); + try { + fi->seek(ih.entry - isection[1].vaddr + isection[1].rawdataptr, SEEK_SET); + fi->read(buf, sizeof(buf)); + + static const unsigned char magic[] = "\x8b\x1e\x83\xee\xfc\x11\xdb"; + // mov ebx, [esi]; sub esi, -4; adc ebx,ebx + + int offset = find(buf, sizeof(buf), magic, 7); + if (offset >= 0 && find(buf + offset + 1, sizeof(buf) - offset - 1, magic, 7) >= 0) + x = true; + } catch (...) { + //x = true; + } + if (x) + throwCantUnpack("file is modified/hacked/protected; take care!!!"); + else + throwCantUnpack("file is possibly modified/hacked/protected; take care!"); + return false; // not reached + } + + // FIXME: what should we say here ? + //throwCantUnpack("file is possibly modified/hacked/protected; take care!"); + return false; +} + + +void PackW64Pep::rebuildImports(upx_byte *& extrainfo) +{ + if (ODADDR(PEDIR_IMPORT) == 0 + || ODSIZE(PEDIR_IMPORT) <= sizeof(import_desc)) + return; + +// const upx_byte * const idata = obuf + get_le32(extrainfo); + OPTR_C(const upx_byte, idata, obuf + get_le32(extrainfo)); + const unsigned inamespos = get_le32(extrainfo + 4); + extrainfo += 8; + + unsigned sdllnames = 0; + +// const upx_byte *import = ibuf + IDADDR(PEDIR_IMPORT) - isection[2].vaddr; +// const upx_byte *p; + IPTR_I(const upx_byte, import, ibuf + IDADDR(PEDIR_IMPORT) - isection[2].vaddr); + OPTR(const upx_byte, p); + + for (p = idata; get_le32(p) != 0; ++p) + { + const upx_byte *dname = get_le32(p) + import; + ICHECK(dname, 1); + const unsigned dlen = strlen(dname); + ICHECK(dname, dlen + 1); + + sdllnames += dlen + 1; + for (p += 8; *p;) + if (*p == 1) + p += strlen(++p) + 1; + else if (*p == 0xff) + p += 3; // ordinal + else + p += 5; + } + sdllnames = ALIGN_UP(sdllnames, 2u); + + upx_byte * const Obuf = obuf - rvamin; + import_desc * const im0 = (import_desc*) (Obuf + ODADDR(PEDIR_IMPORT)); + import_desc *im = im0; + upx_byte *dllnames = Obuf + inamespos; + upx_byte *importednames = dllnames + sdllnames; + upx_byte * const importednames_start = importednames; + + for (p = idata; get_le32(p) != 0; ++p) + { + // restore the name of the dll + const upx_byte *dname = get_le32(p) + import; + ICHECK(dname, 1); + const unsigned dlen = strlen(dname); + ICHECK(dname, dlen + 1); + + const unsigned iatoffs = get_le32(p + 4) + rvamin; + if (inamespos) + { + // now I rebuild the dll names + OCHECK(dllnames, dlen + 1); + strcpy(dllnames, dname); + im->dllname = ptr_diff(dllnames,Obuf); + //;;;printf("\ndll: %s:",dllnames); + dllnames += dlen + 1; + } + else + { + OCHECK(Obuf + im->dllname, dlen + 1); + strcpy(Obuf + im->dllname, dname); + } + im->iat = iatoffs; + +// LE32 *newiat = (LE32 *) (Obuf + iatoffs); + OPTR_I(LE32, newiat, (LE32 *) (Obuf + iatoffs)); + + // restore the imported names+ordinals + for (p += 8; *p; ++newiat) + if (*p == 1) + { + const unsigned ilen = strlen(++p) + 1; + if (inamespos) + { + if (ptr_diff(importednames, importednames_start) & 1) + importednames -= 1; + omemcpy(importednames + 2, p, ilen); + //;;;printf(" %s",importednames+2); + *newiat = ptr_diff(importednames, Obuf); + importednames += 2 + ilen; + } + else + { + OCHECK(Obuf + *newiat + 2, ilen + 1); + strcpy(Obuf + *newiat + 2, p); + } + p += ilen; + } + else if (*p == 0xff) + { + *newiat = get_le16(p + 1) + 0x80000000; + //;;;printf(" %x",(unsigned)*newiat); + p += 3; + } + else + { + *newiat = get_le32(get_le32(p + 1) + import); + assert(*newiat & 0x80000000); + p += 5; + } + *newiat = 0; + im++; + } + //memset(idata,0,p - idata); +} + +/* + extra info added to help uncompression: + + + + - optional \ + - opt / + - optional \ + - optional / + - optional + +*/ + + +/* +vi:ts=4:et +*/ + diff --git a/src/p_w64pep.h b/src/p_w64pep.h new file mode 100644 index 00000000..7ff7e01c --- /dev/null +++ b/src/p_w64pep.h @@ -0,0 +1,87 @@ +/* p_w64pep.h -- + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2013 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2013 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 + + */ + + +#ifndef __UPX_P_W64PEP_H +#define __UPX_P_W64PEP_H 1 + +/************************************************************************* +// w64/pep +**************************************************************************/ + +class PackW64Pep : public PepFile +{ + typedef PepFile super; + +public: + PackW64Pep(InputFile *f); + virtual ~PackW64Pep(); + virtual int getFormat() const { return UPX_F_WIN64_PEP; } + virtual const char *getName() const { return "win64/pep"; } + virtual const char *getFullName(const options_t *) const { return "AMD64-win64.pep"; } + virtual const int *getCompressionMethods(int method, int level) const; + virtual const int *getFilters() const; + + virtual void pack(OutputFile *fo); + + virtual bool canPack(); + virtual int canUnpack(); + +protected: + virtual int readFileHeader(); + + virtual void buildLoader(const Filter *ft); + virtual Linker* newLinker() const; + + virtual unsigned processImports(); + virtual void processImports(unsigned, unsigned); + virtual void rebuildImports(upx_byte *&); + + virtual void processTls(Interval *); //NEW: TLS callback handling - Stefan Widmann + void processTls(Reloc *, const Interval *, unsigned); //NEW: TLS callback handling - Stefan Widmann + + void processLoadConf(Reloc *, const Interval *, unsigned); + void processLoadConf(Interval *); + upx_byte *oloadconf; + unsigned soloadconf; + + unsigned tlscb_ptr; //NEW: TLS callback handling - Stefan Widmann + unsigned tls_handler_offset; + + bool isrtm; + bool use_dep_hack; + bool use_clear_dirty_stack; + bool use_tls_callbacks; //NEW: TLS callback handling - Stefan Widmann +}; + + +#endif /* already included */ + + +/* +vi:ts=4:et +*/ diff --git a/src/packmast.cpp b/src/packmast.cpp index 81440634..5c2cf9ee 100644 --- a/src/packmast.cpp +++ b/src/packmast.cpp @@ -32,6 +32,7 @@ #include "packer.h" #include "lefile.h" #include "pefile.h" +#include "pepfile.h" #include "p_elf.h" #include "p_com.h" @@ -50,6 +51,7 @@ #include "p_vxd.h" #include "p_w16ne.h" #include "p_w32pe.h" +#include "p_w64pep.h" #include "p_vmlinz.h" #include "p_vmlinx.h" #include "p_ps1.h" @@ -179,6 +181,9 @@ Packer* PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const optio return p; delete p; p = NULL; #endif + if ((p = func(new PackW64Pep(f), user)) != NULL) + return p; + delete p; p = NULL; if ((p = func(new PackW32Pe(f), user)) != NULL) return p; delete p; p = NULL; diff --git a/src/pepfile.cpp b/src/pepfile.cpp new file mode 100644 index 00000000..e49eb8c6 --- /dev/null +++ b/src/pepfile.cpp @@ -0,0 +1,1728 @@ +/* pepfile.cpp -- + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2013 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2013 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 + + + ------------------------------------------------------------------- + + PE+ format extension changes (C) 2010 Stefan Widmann + changes in: + */ + + +#include "conf.h" +#include "file.h" +#include "filter.h" +#include "packer.h" +#include "pepfile.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 + +/************************************************************************* +// +**************************************************************************/ + +#if defined(__BORLANDC__) +# undef strcpy +# define strcpy(a,b) strcpy((char *)(a),(const char *)(b)) +#endif + +#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) +{ + if (!p) + throwCantUnpack("unexpected NULL pointer; take care!"); +} +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) + + +/************************************************************************* +// +**************************************************************************/ + +PepFile::PepFile(InputFile *f) : super(f) +{ + bele = &N_BELE_RTP::le_policy; + //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) == 264) + COMPILE_TIME_ASSERT(sizeof(pe_header_t::ddirs_t) == 8) + COMPILE_TIME_ASSERT(sizeof(pe_section_t) == 40) + COMPILE_TIME_ASSERT_ALIGNED1(pe_header_t) + COMPILE_TIME_ASSERT_ALIGNED1(pe_header_t::ddirs_t) + COMPILE_TIME_ASSERT_ALIGNED1(pe_section_t) + 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; + sorelocs = 0; + soxrelocs = 0; + sotls = 0; +} + + +PepFile::~PepFile() +{ + delete [] isection; + delete [] orelocs; + delete [] oimport; + delete [] oimpdlls; + delete [] oexport; + delete [] otls; + delete [] oresources; + delete [] oxrelocs; + //delete res; +} + + +bool PepFile::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 PepFile::readFileHeader() +{ + __packed_struct(exe_header_t) + LE16 mz; + LE16 m512; + LE16 p512; + char _[18]; + LE16 relocoffs; + char __[34]; + LE32 nexepos; + __packed_struct_end() + + COMPILE_TIME_ASSERT(sizeof(exe_header_t) == 64) + COMPILE_TIME_ASSERT_ALIGNED1(exe_header_t) + COMPILE_TIME_ASSERT(sizeof(((exe_header_t*)0)->_) == 18) + COMPILE_TIME_ASSERT(sizeof(((exe_header_t*)0)->__) == 34) + + 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 getFormat(); +} + + +/************************************************************************* +// interval handling +**************************************************************************/ + +PepFile::Interval::Interval(void *b) : capacity(0),base(b),ivarr(NULL),ivnum(0) +{} + +PepFile::Interval::~Interval() +{ + free(ivarr); +} + +void PepFile::Interval::add(const void *start,unsigned len) +{ + add(ptr_diff(start,base),len); +} + +void PepFile::Interval::add(const void *start,const void *end) +{ + add(ptr_diff(start,base),ptr_diff(end,start)); +} + +int __acc_cdecl_qsort PepFile::Interval::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 PepFile::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 PepFile::Interval::add(const Interval *iv) +{ + for (unsigned ic = 0; ic < iv->ivnum; ic++) + add(iv->ivarr[ic].start,iv->ivarr[ic].len); +} + +void PepFile::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 PepFile::Interval::clear() +{ + for (unsigned ic = 0; ic < ivnum; ic++) + memset((char*) base + ivarr[ic].start,0,ivarr[ic].len); +} + +void PepFile::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 +**************************************************************************/ + +__packed_struct(PepFile::Reloc::reloc) + LE32 pagestart; + LE32 size; +__packed_struct_end() + +void PepFile::Reloc::newRelocPos(void *p) +{ + rel = (reloc*) p; + rel1 = (LE16*) ((char*) p + sizeof (reloc)); +} + +PepFile::Reloc::Reloc(upx_byte *s,unsigned si) : + start(s), size(si), rel(NULL), rel1(NULL) +{ + COMPILE_TIME_ASSERT(sizeof(reloc) == 8) + COMPILE_TIME_ASSERT_ALIGNED1(reloc) + memset(counts,0,sizeof(counts)); + unsigned pos,type; + while (next(pos,type)) + counts[type]++; +} + +PepFile::Reloc::Reloc(unsigned rnum) : + start(NULL), size(0), rel(NULL), rel1(NULL) +{ + start = new upx_byte[rnum * 4 + 8192]; + counts[0] = 0; +} + +bool PepFile::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 PepFile::Reloc::add(unsigned pos,unsigned type) +{ + set_le32(start + 1024 + 4 * counts[0]++,(pos << 4) + type); +} + +void PepFile::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*) start; + 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; + //NEW: we do not need any relocs in 64 bit long mode, an empty reloc table is fine - Stefan Widmann + //assert(siz > 0); + start = 0; // safety +} + +void PepFile::processRelocs(Reloc *rel) // pass2 +{ + rel->finish(oxrelocs,soxrelocs); + if (opt->win32_pe.strip_relocs && !isdll) + soxrelocs = 0; +} + +void PepFile::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]]; + + unsigned xcounts[4]; + memset(xcounts, 0, sizeof(xcounts)); + + // prepare sorting + unsigned pos,type; + while (rel.next(pos,type)) + { + if (pos >= ih.imagesize) + continue; // skip out-of-bounds record + if (type < 4) + fix[type][xcounts[type]++] = pos - rvamin; + } + + // remove duplicated records + for (ic = 1; ic <= 3; ic++) + { + qsort(fix[ic], xcounts[ic], 4, le32_compare); + unsigned prev = ~0; + unsigned jc = 0; + for (unsigned kc = 0; kc < xcounts[ic]; kc++) + if (fix[ic][kc] != prev) + prev = fix[ic][jc++] = fix[ic][kc]; + + //printf("xcounts[%u] %u->%u\n", ic, xcounts[ic], jc); + xcounts[ic] = jc; + } + + // preprocess "type 3" relocation records + for (ic = 0; ic < xcounts[3]; ic++) + { + pos = fix[3][ic] + rvamin; + set_le32(ibuf + pos, get_le32(ibuf + pos) - ih.imagebase - rvamin); + } + + 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], xcounts[3], + orelocs, ibuf + rvamin,1, &big_relocs), + orelocs); + delete [] fix[3]; + + // Malware that hides behind UPX often has PE header info that is + // deliberately corrupt. Sometimes it is even tuned to cause us trouble! + // Use an extra check to avoid AccessViolation (SIGSEGV) when appending + // the relocs into one array. + if ((rnum * 4 + 1024) < (sorelocs + 4*(2 + xcounts[2] + xcounts[1]))) + throwCantUnpack("Invalid relocs"); + + // append relocs type "LOW" then "HIGH" + for (ic = 2; ic ; ic--) + { + memcpy(orelocs + sorelocs,fix[ic],4 * xcounts[ic]); + sorelocs += 4 * xcounts[ic]; + delete [] fix[ic]; + + set_le32(orelocs + sorelocs,0); + if (xcounts[ic]) + { + sorelocs += 4; + big_relocs |= 2 * ic; + } + } + info("Relocations: original size: %u bytes, preprocessed size: %u bytes",(unsigned) IDSIZE(PEDIR_RELOC),sorelocs); +} + + +/************************************************************************* +// import handling +**************************************************************************/ + +__packed_struct(import_desc) + LE32 oft; // orig first thunk + char _[8]; + LE32 dllname; + LE32 iat; // import address table +__packed_struct_end() + +void PepFile::processImports(unsigned myimport, unsigned iat_off) // pass 2 +{ + COMPILE_TIME_ASSERT(sizeof(import_desc) == 20) + COMPILE_TIME_ASSERT_ALIGNED1(import_desc) + + // adjust import data + for (import_desc *im = (import_desc*) oimpdlls; im->dllname; im++) + { + if (im->dllname < myimport) + im->dllname += myimport; + LE64 *p = (LE64*) (oimpdlls + im->iat); + im->iat += myimport; + im->oft = im->iat; + + while (*p) + if ((*p++ & 0x8000000000000000ULL) == 0) // import by name? + p[-1] += myimport; + + im->iat = im == (import_desc*) oimpdlls ? iat_off : iat_off + 12; + } +} + +unsigned PepFile::processImports() // pass 1 +{ + static const unsigned char kernel32dll[] = "COREDLL.dll"; + static const char llgpa[] = "\x0\x0""LoadLibraryW\x0\x0" + "GetProcAddressA\x0\x0\x0" + "CacheSync"; + //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; + + 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); + } + }; + + // +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 + 4;// + 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((unsigned) sizeof(llgpa), 2u)); + strcpy(dllnames,kernel32dll); + im->dllname = k32namepos; + im->iat = ptr_diff(ordinals,oimpdlls); + *ordinals++ = ptr_diff(importednames,oimpdlls); // LoadLibraryW + *ordinals++ = ptr_diff(importednames,oimpdlls) + 14; // GetProcAddressA + *ordinals++ = ptr_diff(importednames,oimpdlls) + 14 + 18; // CacheSync + 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 + //ordinals -= k32o; + 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 +**************************************************************************/ + +PepFile::Export::Export(char *_base) : base(_base), iv(_base) +{ + COMPILE_TIME_ASSERT(sizeof(export_dir_t) == 40) + COMPILE_TIME_ASSERT_ALIGNED1(export_dir_t) + ename = functionptrs = ordinals = NULL; + names = NULL; + memset(&edir,0,sizeof(edir)); + size = 0; +} + +PepFile::Export::~Export() +{ + free(ename); + delete [] functionptrs; + delete [] ordinals; + for (unsigned ic = 0; ic < edir.names + edir.functions; ic++) + free(names[ic]); + delete [] names; +} + +void PepFile::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 PepFile::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 PepFile::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(), 4u); + oexport = new upx_byte[soexport]; + memset(oexport, 0, soexport); +} + +void PepFile::processExports(Export *xport,unsigned newoffs) // pass2 +{ + if (soexport) + xport->build((char*) oexport,newoffs); +} + +/************************************************************************* +// resource handling +**************************************************************************/ + +__packed_struct(PepFile::Resource::res_dir_entry) + LE32 tnl; // Type | Name | Language id - depending on level + LE32 child; +__packed_struct_end() + +__packed_struct(PepFile::Resource::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 +__packed_struct_end() + +__packed_struct(PepFile::Resource::res_data) + LE32 offset; + LE32 size; + char _[8]; // codepage, reserved +__packed_struct_end() + +struct PepFile::Resource::upx_rnode +{ + unsigned id; + upx_byte *name; + upx_rnode *parent; +}; + +struct PepFile::Resource::upx_rbranch : public PepFile::Resource::upx_rnode +{ + unsigned nc; + upx_rnode **children; + res_dir data; +}; + +struct PepFile::Resource::upx_rleaf : public PepFile::Resource::upx_rnode +{ + upx_rleaf *next; + unsigned newoffset; + res_data data; +}; + +PepFile::Resource::Resource() : root(NULL) +{} + +PepFile::Resource::Resource(const upx_byte *p) +{ + init(p); + +} + +PepFile::Resource::~Resource() +{ + if (root) destroy (root,0); +} + +unsigned PepFile::Resource::dirsize() const +{ + return ALIGN_UP(dsize + ssize, 4u); +} + +bool PepFile::Resource::next() +{ + // wow, builtin autorewind... :-) + return (current = current ? current->next : head) != NULL; +} + +unsigned PepFile::Resource::itype() const +{ + return current->parent->parent->id; +} + +const upx_byte *PepFile::Resource::ntype() const +{ + return current->parent->parent->name; +} + +unsigned PepFile::Resource::size() const +{ + return ALIGN_UP(current->data.size,4); +} + +unsigned PepFile::Resource::offs() const +{ + return current->data.offset; +} + +unsigned &PepFile::Resource::newoffs() +{ + return current->newoffset; +} + +void PepFile::Resource::dump() const +{ + dump(root,0); +} + +unsigned PepFile::Resource::iname() const +{ + return current->parent->id; +} + +const upx_byte *PepFile::Resource::nname() const +{ + return current->parent->name; +} + +/* + unsigned ilang() const {return current->id;} + const upx_byte *nlang() const {return current->name;} +*/ + +void PepFile::Resource::init(const upx_byte *res) +{ + COMPILE_TIME_ASSERT(sizeof(res_dir_entry) == 8) + COMPILE_TIME_ASSERT(sizeof(res_dir) == 16 + 8) + COMPILE_TIME_ASSERT(sizeof(res_data) == 16) + COMPILE_TIME_ASSERT_ALIGNED1(res_dir_entry) + COMPILE_TIME_ASSERT_ALIGNED1(res_dir) + COMPILE_TIME_ASSERT_ALIGNED1(res_data) + + start = res; + root = head = current = NULL; + dsize = ssize = 0; + check((const res_dir*) start,0); + root = convert(start,NULL,0); +} + +void PepFile::Resource::check(const res_dir *node,unsigned level) +{ + int ic = node->identr + node->namedentr; + if (ic == 0) + return; + 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); +} + +PepFile::Resource::upx_rnode *PepFile::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; + int ic = node->identr + node->namedentr; + if (ic == 0) + return NULL; + + upx_rbranch *branch = new upx_rbranch; + branch->name = NULL; + branch->parent = parent; + branch->nc = ic; + 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); + xcheck(child); + 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 PepFile::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 *PepFile::Resource::build() +{ + newstart = new upx_byte [dirsize()]; + unsigned bpos = 0,spos = dsize; + build(root,bpos,spos,0); + + // dirsize() is 4 bytes aligned, so we may need to zero + // up to 2 bytes to make valgrind happy + while (spos < dirsize()) + newstart[spos++] = 0; + + return newstart; +} + +void PepFile::Resource::destroy(upx_rnode *node,unsigned level) +{ + xcheck(node); + delete [] node->name; node->name = NULL; + if (level != 3) + { + 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; + } + delete node; +} + +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 PepFile::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 PepFile::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 PepFile::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 PepFile::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; +} + +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 *mkeep) + { + if (!unistr) + return (unsigned) atoi(mkeep) == num; + + unsigned ic; + for (ic = 0; ic < get_le16(unistr); ic++) + if (unistr[2 + ic * 2] != (unsigned char) mkeep[ic]) + return false; + return mkeep[ic] == 0 || mkeep[ic] == ',' || mkeep[ic] == '/'; + } + }; + + // FIXME this comparison is not too exact + while (1) + { + char const *delim1 = strchr(keep, '/'); + char const *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 PepFile::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(); + + char *keep_icons = NULL; // icon ids in the first icon group + unsigned iconsin1stdir = 0; + if (opt->win32_pe.compress_icons == 2) + while (res->next()) // there is no rewind() in Resource + if (res->itype() == RT_GROUP_ICON && iconsin1stdir == 0) + { + iconsin1stdir = get_le16(ibuf + res->offs() + 4); + keep_icons = new char[1 + iconsin1stdir * 9]; + *keep_icons = 0; + for (unsigned ic = 0; ic < iconsin1stdir; ic++) + upx_snprintf(keep_icons + strlen(keep_icons), 9, "3/%u,", + get_le16(ibuf + res->offs() + 6 + ic * 14 + 12)); + if (*keep_icons) + keep_icons[strlen(keep_icons) - 1] = 0; + } + + // the icon id which should not be compressed when compress_icons == 1 + unsigned first_icon_id = (unsigned) -1; + if (opt->win32_pe.compress_icons == 1) + while (res->next()) + if (res->itype() == RT_GROUP_ICON && first_icon_id == (unsigned) -1) + first_icon_id = get_le16(ibuf + res->offs() + 6 + 12); + + bool compress_icon = opt->win32_pe.compress_icons > 1; + bool compress_idir = opt->win32_pe.compress_icons == 3; + + // some statistics + unsigned usize = 0; + 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_ICON) // icon + { + if (opt->win32_pe.compress_icons == 0) + do_compress = false; + else if (opt->win32_pe.compress_icons == 1) + if ((first_icon_id == (unsigned) -1 + || first_icon_id == res->iname())) + do_compress = compress_icon; + } + else if (rtype == RT_GROUP_ICON) // icon directory + do_compress = compress_idir && opt->win32_pe.compress_icons; + else if (rtype > 0 && rtype < RT_LAST) + do_compress = opt->win32_pe.compress_rt[rtype] ? true : false; + + if (keep_icons) + do_compress &= !match(res->itype(), res->ntype(), res->iname(), + res->nname(), keep_icons); + do_compress &= !match(res->itype(), res->ntype(), res->iname(), + res->nname(), "TYPELIB,REGISTRY,16"); + do_compress &= !match(res->itype(), res->ntype(), res->iname(), + res->nname(), opt->win32_pe.keep_resource); + + if (do_compress) + { + 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 && opt->win32_pe.compress_icons == 1) + compress_icon = true; + 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); + + delete[] keep_icons; + 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 PepFile::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 PepFile::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 PepFile::stripDebug(unsigned overlaystart) +{ + if (IDADDR(PEDIR_DEBUG) == 0) + return overlaystart; + + __packed_struct(debug_dir_t) + char _[16]; // flags, time/date, version, type + LE32 size; + char __[4]; // rva + LE32 fpos; + __packed_struct_end() + + COMPILE_TIME_ASSERT(sizeof(debug_dir_t) == 28) + COMPILE_TIME_ASSERT_ALIGNED1(debug_dir_t) + COMPILE_TIME_ASSERT(sizeof(((debug_dir_t*)0)->_) == 16) + COMPILE_TIME_ASSERT(sizeof(((debug_dir_t*)0)->__) == 4) + + 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 +**************************************************************************/ + + +/************************************************************************* +// unpack +**************************************************************************/ + +void PepFile::rebuildRelocs(upx_byte *& extrainfo) +{ + if (!ODADDR(PEDIR_RELOC) || !ODSIZE(PEDIR_RELOC) || (oh.flags & RELOCS_STRIPPED)) + return; + + if (ODSIZE(PEDIR_RELOC) == 8) // some tricky dlls use this + { + omemcpy(obuf + ODADDR(PEDIR_RELOC) - rvamin, "\x0\x0\x0\x0\x8\x0\x0\x0", 8); + return; + } + + upx_byte *rdata = obuf + get_le32(extrainfo); + const upx_byte big = extrainfo[4]; + extrainfo += 5; + +// upx_byte *p = rdata; + OPTR_I(upx_byte, p, rdata); + MemBuffer wrkmem; + unsigned relocn = unoptimizeReloc32(&rdata,obuf,&wrkmem,1); + unsigned r16 = 0; + if (big & 6) // 16 bit relocations + { + const LE32 *q = (LE32*) rdata; + while (*q++) + r16++; + if ((big & 6) == 6) + while (*++q) + r16++; + } + Reloc rel(relocn + r16); + + if (big & 6) + { + LE32 *q = (LE32*) rdata; + while (*q) + rel.add(*q++ + rvamin,(big & 4) ? 2 : 1); + if ((big & 6) == 6) + while (*++q) + rel.add(*q + rvamin,1); + rdata = (upx_byte*) q; + } + + //memset(p,0,rdata - p); + + for (unsigned ic = 0; ic < relocn; ic++) + { + p = obuf + get_le32(wrkmem + 4 * ic); + set_le32(p, get_le32((unsigned char *)p) + oh.imagebase + rvamin); + rel.add(rvamin + get_le32(wrkmem + 4 * ic),3); + } + rel.finish (oxrelocs,soxrelocs); + + if (opt->win32_pe.strip_relocs && !isdll) + { + obuf.clear(ODADDR(PEDIR_RELOC) - rvamin, ODSIZE(PEDIR_RELOC)); + ODADDR(PEDIR_RELOC) = 0; + soxrelocs = 0; + // FIXME: try to remove the original relocation section somehow + } + else + omemcpy(obuf + ODADDR(PEDIR_RELOC) - rvamin,oxrelocs,soxrelocs); + delete [] oxrelocs; oxrelocs = NULL; + wrkmem.dealloc(); + + ODSIZE(PEDIR_RELOC) = soxrelocs; +} + +void PepFile::rebuildExports() +{ + if (ODSIZE(PEDIR_EXPORT) == 0 || ODADDR(PEDIR_EXPORT) == IDADDR(PEDIR_EXPORT)) + return; // nothing to do + + opt->win32_pe.compress_exports = 0; + Export xport((char*)(unsigned char*) ibuf - isection[2].vaddr); + processExports(&xport); + processExports(&xport,ODADDR(PEDIR_EXPORT)); + omemcpy(obuf + ODADDR(PEDIR_EXPORT) - rvamin,oexport,soexport); +} + +void PepFile::rebuildTls() +{ + // this is an easy one : just do nothing ;-) +} + +void PepFile::rebuildResources(upx_byte *& extrainfo) +{ + if (ODSIZE(PEDIR_RESOURCE) == 0 || IDSIZE(PEDIR_RESOURCE) == 0) + return; + + icondir_count = get_le16(extrainfo); + extrainfo += 2; + + const unsigned vaddr = IDADDR(PEDIR_RESOURCE); + const upx_byte *r = ibuf - isection[ih.objects - 1].vaddr; + Resource res(r + vaddr); + while (res.next()) + if (res.offs() > vaddr) + { + unsigned origoffs = get_le32(r + res.offs() - 4); + res.newoffs() = origoffs; + omemcpy(obuf + origoffs - rvamin,r + res.offs(),res.size()); + if (icondir_count && res.itype() == RT_GROUP_ICON) + { + set_le16(obuf + origoffs - rvamin + 4,icondir_count); + icondir_count = 0; + } + } + upx_byte *p = res.build(); + OCHECK(obuf + ODADDR(PEDIR_RESOURCE) - rvamin, 16); + // write back when the original is zeroed + if (get_le32(obuf + ODADDR(PEDIR_RESOURCE) - rvamin + 12) == 0) + omemcpy(obuf + ODADDR(PEDIR_RESOURCE) - rvamin,p,res.dirsize()); + delete [] p; +} + +void PepFile::unpack(OutputFile *fo) +{ + //infoHeader("[Processing %s, format %s, %d sections]", fn_basename(fi->getName()), getName(), objs); + + handleStub(fi,fo,pe_offset); + + const unsigned iobjs = ih.objects; + const unsigned overlay = file_size - ALIGN_UP(isection[iobjs - 1].rawdataptr + + isection[iobjs - 1].size, + ih.filealign); + checkOverlay(overlay); + + ibuf.alloc(ph.c_len); + obuf.allocForUncompression(ph.u_len); + fi->seek(isection[1].rawdataptr - 64 + ph.buf_offset + ph.getPackHeaderSize(),SEEK_SET); + fi->readx(ibuf,ph.c_len); + + // decompress + decompress(ibuf,obuf); + upx_byte *extrainfo = obuf + get_le32(obuf + ph.u_len - 4); + //upx_byte * const eistart = extrainfo; + + memcpy(&oh, extrainfo, sizeof (oh)); + extrainfo += sizeof (oh); + unsigned objs = oh.objects; + + if ((int) objs <= 0) + throwCantUnpack("unexpected value in the PE header"); + Array(pe_section_t, osection, objs); + memcpy(osection,extrainfo,sizeof(pe_section_t) * objs); + rvamin = osection[0].vaddr; + extrainfo += sizeof(pe_section_t) * objs; + + // read the noncompressed section + ibuf.dealloc(); + ibuf.alloc(isection[2].size); + fi->seek(isection[2].rawdataptr,SEEK_SET); + fi->readx(ibuf,isection[2].size); + + // unfilter + if (ph.filter) + { + Filter ft(ph.level); + ft.init(ph.filter,oh.codebase - rvamin); + ft.cto = (unsigned char) ph.filter_cto; + OCHECK(obuf + oh.codebase - rvamin, oh.codesize); + ft.unfilter(obuf + oh.codebase - rvamin, oh.codesize); + } + + rebuildImports(extrainfo); + rebuildRelocs(extrainfo); + rebuildTls(); + rebuildExports(); + + if (iobjs == 4) + { + // read the resource section if present + ibuf.dealloc(); + ibuf.alloc(isection[3].size); + fi->seek(isection[3].rawdataptr,SEEK_SET); + fi->readx(ibuf,isection[3].size); + } + + rebuildResources(extrainfo); + + //FIXME: this does bad things if the relocation section got removed + // during compression ... + //memset(eistart,0,extrainfo - eistart + 4); + + // 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; + + // oh.headersize = osection[0].rawdataptr; + // oh.headersize = ALIGN_UP(pe_offset + sizeof(oh) + sizeof(pe_section_t) * objs, oh.filealign); + oh.headersize = rvamin; + oh.chksum = 0; + + //NEW: disable reloc stripping if ASLR is enabled + if(ih.dllflags & IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE) + opt->win32_pe.strip_relocs = false; + + // FIXME: ih.flags is checked here because of a bug in UPX 0.92 + if ((opt->win32_pe.strip_relocs && !isdll) || (ih.flags & RELOCS_STRIPPED)) + { + oh.flags |= RELOCS_STRIPPED; + ODADDR(PEDIR_RELOC) = 0; + ODSIZE(PEDIR_RELOC) = 0; + } + + // write decompressed file + if (fo) + { + unsigned ic; + for (ic = 0; ic < objs && osection[ic].rawdataptr == 0; ic++) + ; + + ibuf.dealloc(); + ibuf.alloc(osection[ic].rawdataptr); + ibuf.clear(); + infoHeader("[Writing uncompressed file]"); + + // write loader + compressed file + fo->write(&oh,sizeof(oh)); + fo->write(osection,objs * sizeof(pe_section_t)); + fo->write(ibuf,osection[ic].rawdataptr - fo->getBytesWritten()); + for (ic = 0; ic < objs; ic++) + if (osection[ic].rawdataptr) + fo->write(obuf + osection[ic].vaddr - rvamin,ALIGN_UP(osection[ic].size,oh.filealign)); + copyOverlay(fo, overlay, &obuf); + } + ibuf.dealloc(); +} + +/* + extra info added to help uncompression: + + + + - optional \ + - opt / + - optional \ + - optional / + - optional + +*/ + + +/* +vi:ts=4:et +*/ + diff --git a/src/pepfile.h b/src/pepfile.h new file mode 100644 index 00000000..769bdf48 --- /dev/null +++ b/src/pepfile.h @@ -0,0 +1,386 @@ +/* pepfile.h -- + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2013 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2013 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 + + + ------------------------------------------------------------------- + + PE+ format extension changes (C) 2010 Stefan Widmann + changes in: + - pe_header_t + */ + + +#ifndef __UPX_PEPFILE_H +#define __UPX_PEPFILE_H 1 + + +/************************************************************************* +// general/pe handling +**************************************************************************/ + +class PepFile : public Packer +{ + typedef Packer super; +protected: + class Interval; + class Reloc; + class Resource; + class Export; + + PepFile(InputFile *f); + virtual ~PepFile(); + virtual int getVersion() const { return 13; } + + virtual void unpack(OutputFile *fo); + + // unpacker capabilities + virtual bool canUnpackVersion(int version) const + { return (version >= 12 && version <= 13); } + +protected: + virtual int readFileHeader(); + virtual bool testUnpackVersion(int version) const; + + unsigned pe_offset; + + virtual unsigned processImports() = 0; + virtual void processImports(unsigned, unsigned) = 0; + virtual void rebuildImports(upx_byte *&) = 0; + upx_byte *oimport; + unsigned soimport; + upx_byte *oimpdlls; + unsigned soimpdlls; + + void processRelocs(); + void processRelocs(Reloc *); + void rebuildRelocs(upx_byte *&); + upx_byte *orelocs; + unsigned sorelocs; + upx_byte *oxrelocs; + unsigned soxrelocs; + + void processExports(Export *); + void processExports(Export *,unsigned); + void rebuildExports(); + upx_byte *oexport; + unsigned soexport; + + void processResources(Resource *); + void processResources(Resource *, unsigned); + void rebuildResources(upx_byte *&); + upx_byte *oresources; + unsigned soresources; + + // virtual void processTls(Interval *); + // void processTls(Reloc *, const Interval *, unsigned); + void rebuildTls(); + upx_byte *otls; + unsigned sotls; + unsigned tlsindex; + + unsigned stripDebug(unsigned); + + unsigned icondir_offset; + int icondir_count; + + bool importbyordinal; + bool kernel32ordinal; + unsigned rvamin; + unsigned cimports; // rva of preprocessed imports + unsigned crelocs; // rva of preprocessed fixups + int big_relocs; + + __packed_struct(pe_header_t) + // 0x0 + char _[4]; // pemagic + LE16 cpu; + LE16 objects; // number of sections + char __[12]; // timestamp + reserved + LE16 opthdrsize; + LE16 flags; // characteristics + // optional header + LE16 coffmagic; // NEW: Stefan Widmann + char ___[2]; // linkerversion + LE32 codesize; + // 0x20 + LE32 datasize; + LE32 bsssize; + LE32 entry; // still a 32 bit RVA + LE32 codebase; + // 0x30 + //LE32 database; // field does not exist in PE+! + // nt specific fields + LE64 imagebase; // LE32 -> LE64 - Stefan Widmann standard is 0x0000000140000000 + 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 _____[36]; // stack + heap sizes + loader flag + // 0x84 + LE32 ddirsentries; // usually 16 + + __packed_struct(ddirs_t) + LE32 vaddr; // dir RVAs and sizes are still 32 bit + LE32 size; + __packed_struct_end() + + ddirs_t ddirs[16]; + __packed_struct_end() + + __packed_struct(pe_section_t) // no change in section description structures + char name[8]; + LE32 vsize; + LE32 vaddr; + LE32 size; + LE32 rawdataptr; + char _[12]; + LE32 flags; + __packed_struct_end() + + 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 + }; + + //NEW: DLL characteristics definition for ASLR, ... - Stefan Widmann + enum { + IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040, + IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY = 0x0080, + IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100, + IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 0x0200, + IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400, + IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0800, + IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 0x2000, + IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 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 + }; + + class Interval : private noncopyable + { + unsigned capacity; + void *base; + public: + struct interval + { + unsigned start, len; + } *ivarr; + + unsigned ivnum; + + Interval(void *b); + ~Interval(); + + void add(unsigned start,unsigned len); + void add(const void *start,unsigned len); + void add(const void *start,const void *end); + 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); + }; + + class Reloc : private noncopyable + { + upx_byte *start; + unsigned size; + + void newRelocPos(void *p); + + struct 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); + }; + + class Resource : private noncopyable + { + struct res_dir_entry; + struct res_dir; + struct res_data; + struct upx_rnode; + struct upx_rbranch; + struct upx_rleaf; + + 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(); + Resource(const upx_byte *p); + ~Resource(); + void init(const upx_byte *); + + unsigned dirsize() const; + bool next(); + + unsigned itype() const; + const upx_byte *ntype() const; + unsigned size() const; + unsigned offs() const; + unsigned &newoffs(); + + upx_byte *build(); + bool clear(); + + void dump() const; + unsigned iname() const; + const upx_byte *nname() const; + /* + unsigned ilang() const {return current->id;} + const upx_byte *nlang() const {return current->name;} + */ + }; + + class Export : private noncopyable + { + __packed_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; + __packed_struct_end() + + 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; } + }; + +}; + +#endif /* already included */ + + +/* +vi:ts=4:et +*/ diff --git a/src/stub/Makefile b/src/stub/Makefile index 6abde424..d43a124c 100644 --- a/src/stub/Makefile +++ b/src/stub/Makefile @@ -56,6 +56,7 @@ STUBS += amd64-linux.elf-fold.h STUBS += amd64-linux.kernel.vmlinux-head.h STUBS += amd64-linux.kernel.vmlinux.h STUBS += amd64-linux.shlib-init.h +STUBS += amd64-win64.pep.h STUBS += arm-darwin.macho-entry.h STUBS += arm-darwin.macho-fold.h STUBS += arm-linux.elf-entry.h @@ -369,6 +370,20 @@ amd64-linux.shlib-init.h : $(srcdir)/src/$$T.S $(call tc,bin2h) tmp/$T.bin $@ +# /*********************************************************************** +# // amd64-win64.pep +# ************************************************************************/ + +amd64-win64.pep.h : tc_list = amd64-linux.elf default +amd64-win64.pep.h : tc_bfdname = elf64-x86-64 + +amd64-win64.pep.h : $(srcdir)/src/$$T.S + $(call tc,gcc) -c -x assembler-with-cpp $< -o tmp/$T.bin +# $(call tc,objdump) -Dr -M intel-mnemonic tmp/$T.bin | $(RTRIM) > tmp/$T.bin.disasmi + $(call tc,f-embed_objinfo,tmp/$T.bin) + $(call tc,bin2h) tmp/$T.bin $@ + + # /*********************************************************************** # // armel-eabi-linux.elf # ************************************************************************/ diff --git a/src/stub/amd64-win64.pep.h b/src/stub/amd64-win64.pep.h new file mode 100644 index 00000000..0da43c90 --- /dev/null +++ b/src/stub/amd64-win64.pep.h @@ -0,0 +1,766 @@ +/* amd64-win64.pep.h + created from amd64-win64.pep.bin, 11619 (0x2d63) bytes + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2013 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2013 Laszlo Molnar + Copyright (C) 2000-2013 John F. Reiser + 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 + + + John F. Reiser + + */ + + +#define STUB_AMD64_WIN64_PEP_SIZE 11619 +#define STUB_AMD64_WIN64_PEP_ADLER32 0x2097635b +#define STUB_AMD64_WIN64_PEP_CRC32 0x71380939 + +unsigned char stub_amd64_win64_pep[11619] = { +/* 0x0000 */ 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 0x0010 */ 1, 0, 62, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 0x0020 */ 0, 0, 0, 0, 0, 0, 0, 0,200, 4, 0, 0, 0, 0, 0, 0, +/* 0x0030 */ 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 64, 0, 59, 0, 56, 0, +/* 0x0040 */ 128,250, 1, 15,133, 0, 0, 0, 0, 83, 86, 87, 85, 72,190, 0, +/* 0x0050 */ 0, 0, 0, 0, 0, 0,128, 72,141,190, 0, 0, 0, 0,102,255, +/* 0x0060 */ 135, 0, 0, 0, 0,102,129,135, 0, 0, 0, 0, 0,128,199,135, +/* 0x0070 */ 0, 0, 0, 0, 0, 0, 0,128, 87, 49,219, 49,201, 72,131,205, +/* 0x0080 */ 255,232, 80, 0, 0, 0, 1,219,116, 2,243,195,139, 30, 72,131, +/* 0x0090 */ 238,252, 17,219,138, 22,243,195, 72,141, 4, 47,131,249, 5,138, +/* 0x00a0 */ 16,118, 33, 72,131,253,252,119, 27,131,233, 4,139, 16, 72,131, +/* 0x00b0 */ 192, 4,131,233, 4,137, 23, 72,141,127, 4,115,239,131,193, 4, +/* 0x00c0 */ 138, 16,116, 16, 72,255,192,136, 23,131,233, 1,138, 16, 72,141, +/* 0x00d0 */ 127, 1,117,240,243,195,252, 65, 91,235, 8, 72,255,198,136, 23, +/* 0x00e0 */ 72,255,199,138, 22, 1,219,117, 10,139, 30, 72,131,238,252, 17, +/* 0x00f0 */ 219,138, 22,114,230,141, 65, 1,235, 7,255,200, 65,255,211, 17, +/* 0x0100 */ 192, 65,255,211, 17,192, 1,219,117, 10,139, 30, 72,131,238,252, +/* 0x0110 */ 17,219,138, 22,115,228,131,232, 3,114, 29,193,224, 8, 15,182, +/* 0x0120 */ 210, 9,208, 72,255,198,131,240,255, 15,132, 0, 0, 0, 0,209, +/* 0x0130 */ 248, 72, 99,232,114, 56,235, 14, 1,219,117, 8,139, 30, 72,131, +/* 0x0140 */ 238,252, 17,219,114, 40,255,193, 1,219,117, 8,139, 30, 72,131, +/* 0x0150 */ 238,252, 17,219,114, 24, 65,255,211, 17,201, 1,219,117, 8,139, +/* 0x0160 */ 30, 72,131,238,252, 17,219,115,237,131,193, 2,235, 5, 65,255, +/* 0x0170 */ 211, 17,201, 72,129,253, 0,251,255,255,131,209, 2,232, 0, 0, +/* 0x0180 */ 0, 0,233, 92,255,255,255, 94, 72,141,190, 0, 0, 0, 0, 72, +/* 0x0190 */ 137,247,185, 0, 0, 0, 0, 72,141,190, 0, 0, 0, 0,139, 7, +/* 0x01a0 */ 9,192,116,255,139, 95, 4, 72,141,140, 48, 0, 0, 0, 0, 72, +/* 0x01b0 */ 1,243, 72,131,199, 8, 72,131,236, 40,255,150, 0, 0, 0, 0, +/* 0x01c0 */ 72,131,196, 40, 72,149,138, 7, 72,255,199, 8,192,116,207,121, +/* 0x01d0 */ 255,122, 16,139, 7, 72,131,199, 4, 72,139,132, 48, 0, 0, 0, +/* 0x01e0 */ 0,235,255, 72, 15,183, 23, 72,131,199, 2,235,255, 72,137,249, +/* 0x01f0 */ 72,137,250,255,200,242,174, 72,137,233, 72,131,236, 40,255,150, +/* 0x0200 */ 0, 0, 0, 0, 72,131,196, 40, 72, 9,192,116, 9, 72,137, 3, +/* 0x0210 */ 72,131,195, 8,235,255, 93, 95, 94, 91, 49,192,195, 72,131,236, +/* 0x0220 */ 40,255,150, 0, 0, 0, 0, 72,141,190, 0, 0, 0, 0, 72,131, +/* 0x0230 */ 199, 4, 72,141, 94,252, 72,139,174, 0, 0, 0, 0, 72,141,190, +/* 0x0240 */ 0, 0, 0, 0,187, 0, 0, 0,128, 80, 73,137,225, 65,184, 4, +/* 0x0250 */ 0, 0, 0, 72,137,218, 72,137,249, 72,131,236, 32,255,213, 72, +/* 0x0260 */ 141,135, 0, 0, 0, 0,128, 32,127,128, 96, 40,127, 76,141, 76, +/* 0x0270 */ 36, 32, 77,139, 1, 72,137,218, 72,137,249,255,213, 72,131,196, +/* 0x0280 */ 40, 72,141,142, 0, 0, 0, 0, 72,141,185, 0, 0, 0, 0, 49, +/* 0x0290 */ 192,170, 73,137,192,186, 1, 0, 0, 0, 80,255,215, 88, 93, 95, +/* 0x02a0 */ 94, 91, 72,141, 68, 36,128,106, 0, 72, 57,196,117,249, 72,131, +/* 0x02b0 */ 236,128,184, 1, 0, 0, 0,195,233, 0, 0, 0, 0,235, 40, 86, +/* 0x02c0 */ 72,190, 0, 0, 0, 0, 0, 0, 0,128,252, 72,173, 72,133,192, +/* 0x02d0 */ 116, 20, 81, 82, 65, 80, 72,131,236, 40,255,208, 72,131,196, 40, +/* 0x02e0 */ 65, 88, 90, 89,235,229, 94,195, 85, 80, 88, 33,161,216,208,213, +/* 0x02f0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 0x0300 */ 0, 0, 0, 0, 0, 0, 0, 45,102,105,108,101, 32,102,111,114, +/* 0x0310 */ 109, 97,116, 32,101,108,102, 54, 52, 45,120, 56, 54, 45, 54, 52, +/* 0x0320 */ 10, 10, 83,101, 99,116,105,111,110,115, 58, 10, 73,100,120, 32, +/* 0x0330 */ 78, 97,109,101, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 83,105, +/* 0x0340 */ 122,101, 32, 32, 32, 32, 32, 32, 86, 77, 65, 32, 32, 32, 32, 32, +/* 0x0350 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 76, 77, 65, 32, 32, 32, +/* 0x0360 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 70,105,108,101, +/* 0x0370 */ 32,111,102,102, 32, 32, 65,108,103,110, 32, 32, 70,108, 97,103, +/* 0x0380 */ 115, 10, 32, 32, 48, 32, 80, 69, 73, 83, 68, 76, 76, 49, 32, 32, +/* 0x0390 */ 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 48, 57, 32, 32, 48, 48, +/* 0x03a0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, +/* 0x03b0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x03c0 */ 32, 32, 48, 48, 48, 48, 48, 48, 52, 48, 32, 32, 50, 42, 42, 48, +/* 0x03d0 */ 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, 82, 69, 76, 79, +/* 0x03e0 */ 67, 44, 32, 82, 69, 65, 68, 79, 78, 76, 89, 10, 32, 32, 49, 32, +/* 0x03f0 */ 80, 69, 77, 65, 73, 78, 48, 49, 32, 32, 32, 32, 32, 32, 48, 48, +/* 0x0400 */ 48, 48, 48, 48, 49, 53, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0410 */ 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, +/* 0x0420 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, +/* 0x0430 */ 48, 48, 52, 57, 32, 32, 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, +/* 0x0440 */ 69, 78, 84, 83, 44, 32, 82, 69, 76, 79, 67, 44, 32, 82, 69, 65, +/* 0x0450 */ 68, 79, 78, 76, 89, 10, 32, 32, 50, 32, 80, 69, 73, 67, 79, 78, +/* 0x0460 */ 83, 49, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 48, 55, +/* 0x0470 */ 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0480 */ 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0490 */ 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 53,101, 32, 32, +/* 0x04a0 */ 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, +/* 0x04b0 */ 82, 69, 76, 79, 67, 44, 32, 82, 69, 65, 68, 79, 78, 76, 89, 10, +/* 0x04c0 */ 32, 32, 51, 32, 80, 69, 73, 67, 79, 78, 83, 50, 32, 32, 32, 32, +/* 0x04d0 */ 32, 32, 48, 48, 48, 48, 48, 48, 48, 57, 32, 32, 48, 48, 48, 48, +/* 0x04e0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, +/* 0x04f0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, +/* 0x0500 */ 48, 48, 48, 48, 48, 48, 54, 53, 32, 32, 50, 42, 42, 48, 32, 32, +/* 0x0510 */ 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, 82, 69, 76, 79, 67, 44, +/* 0x0520 */ 32, 82, 69, 65, 68, 79, 78, 76, 89, 10, 32, 32, 52, 32, 80, 69, +/* 0x0530 */ 84, 76, 83, 72, 65, 75, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, +/* 0x0540 */ 48, 48, 48, 97, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0550 */ 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0560 */ 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, +/* 0x0570 */ 54,101, 32, 32, 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, +/* 0x0580 */ 84, 83, 44, 32, 82, 69, 76, 79, 67, 44, 32, 82, 69, 65, 68, 79, +/* 0x0590 */ 78, 76, 89, 10, 32, 32, 53, 32, 80, 69, 77, 65, 73, 78, 48, 50, +/* 0x05a0 */ 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 48, 49, 32, 32, +/* 0x05b0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x05c0 */ 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x05d0 */ 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 55, 56, 32, 32, 50, 42, +/* 0x05e0 */ 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, 82, 69, +/* 0x05f0 */ 65, 68, 79, 78, 76, 89, 10, 32, 32, 54, 32, 80, 69, 77, 65, 73, +/* 0x0600 */ 78, 48, 51, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 48, +/* 0x0610 */ 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0620 */ 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0630 */ 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 55, 57, 32, +/* 0x0640 */ 32, 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, +/* 0x0650 */ 32, 82, 69, 65, 68, 79, 78, 76, 89, 10, 32, 32, 55, 32, 78, 82, +/* 0x0660 */ 86, 95, 72, 69, 65, 68, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, +/* 0x0670 */ 48, 48, 54, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0680 */ 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0690 */ 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, +/* 0x06a0 */ 55, 57, 32, 32, 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, +/* 0x06b0 */ 84, 83, 44, 32, 82, 69, 65, 68, 79, 78, 76, 89, 10, 32, 32, 56, +/* 0x06c0 */ 32, 78, 82, 86, 50, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, 48, +/* 0x06d0 */ 48, 48, 48, 48, 48, 97,101, 32, 32, 48, 48, 48, 48, 48, 48, 48, +/* 0x06e0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, +/* 0x06f0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, +/* 0x0700 */ 48, 48, 48,100, 57, 32, 32, 50, 42, 42, 48, 32, 32, 67, 79, 78, +/* 0x0710 */ 84, 69, 78, 84, 83, 44, 32, 82, 69, 76, 79, 67, 44, 32, 82, 69, +/* 0x0720 */ 65, 68, 79, 78, 76, 89, 10, 32, 32, 57, 32, 80, 69, 77, 65, 73, +/* 0x0730 */ 78, 49, 48, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 48, +/* 0x0740 */ 49, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0750 */ 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0760 */ 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 49, 56, 55, 32, +/* 0x0770 */ 32, 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, +/* 0x0780 */ 32, 82, 69, 65, 68, 79, 78, 76, 89, 10, 32, 49, 48, 32, 80, 69, +/* 0x0790 */ 67, 84, 84, 80, 79, 83, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, +/* 0x07a0 */ 48, 48, 48, 55, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x07b0 */ 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x07c0 */ 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 49, +/* 0x07d0 */ 56, 56, 32, 32, 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, +/* 0x07e0 */ 84, 83, 44, 32, 82, 69, 76, 79, 67, 44, 32, 82, 69, 65, 68, 79, +/* 0x07f0 */ 78, 76, 89, 10, 32, 49, 49, 32, 80, 69, 67, 84, 84, 78, 85, 76, +/* 0x0800 */ 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 48, 51, 32, 32, +/* 0x0810 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0820 */ 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0830 */ 48, 48, 32, 32, 48, 48, 48, 48, 48, 49, 56,102, 32, 32, 50, 42, +/* 0x0840 */ 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, 82, 69, +/* 0x0850 */ 65, 68, 79, 78, 76, 89, 10, 32, 49, 50, 32, 99,116,111,107, 51, +/* 0x0860 */ 50, 46, 48, 48, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 48, +/* 0x0870 */ 53, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0880 */ 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0890 */ 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 49, 57, 50, 32, +/* 0x08a0 */ 32, 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, +/* 0x08b0 */ 32, 82, 69, 76, 79, 67, 44, 32, 82, 69, 65, 68, 79, 78, 76, 89, +/* 0x08c0 */ 10, 32, 49, 51, 32, 80, 69, 73, 77, 80, 79, 82, 84, 32, 32, 32, +/* 0x08d0 */ 32, 32, 32, 48, 48, 48, 48, 48, 48, 51, 56, 32, 32, 48, 48, 48, +/* 0x08e0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, +/* 0x08f0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, +/* 0x0900 */ 32, 48, 48, 48, 48, 48, 49, 57, 55, 32, 32, 50, 42, 42, 48, 32, +/* 0x0910 */ 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, 82, 69, 76, 79, 67, +/* 0x0920 */ 44, 32, 82, 69, 65, 68, 79, 78, 76, 89, 10, 32, 49, 52, 32, 80, +/* 0x0930 */ 69, 73, 66, 89, 79, 82, 68, 32, 32, 32, 32, 32, 32, 48, 48, 48, +/* 0x0940 */ 48, 48, 48, 48, 50, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0950 */ 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, +/* 0x0960 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, +/* 0x0970 */ 49, 99,102, 32, 32, 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, +/* 0x0980 */ 78, 84, 83, 44, 32, 82, 69, 76, 79, 67, 44, 32, 82, 69, 65, 68, +/* 0x0990 */ 79, 78, 76, 89, 10, 32, 49, 53, 32, 80, 69, 75, 51, 50, 79, 82, +/* 0x09a0 */ 68, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 49, 50, 32, +/* 0x09b0 */ 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x09c0 */ 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x09d0 */ 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 49,100, 49, 32, 32, 50, +/* 0x09e0 */ 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, 82, +/* 0x09f0 */ 69, 76, 79, 67, 44, 32, 82, 69, 65, 68, 79, 78, 76, 89, 10, 32, +/* 0x0a00 */ 49, 54, 32, 80, 69, 73, 77, 79, 82, 68, 49, 32, 32, 32, 32, 32, +/* 0x0a10 */ 32, 48, 48, 48, 48, 48, 48, 48, 97, 32, 32, 48, 48, 48, 48, 48, +/* 0x0a20 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, +/* 0x0a30 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, +/* 0x0a40 */ 48, 48, 48, 48, 49,101, 51, 32, 32, 50, 42, 42, 48, 32, 32, 67, +/* 0x0a50 */ 79, 78, 84, 69, 78, 84, 83, 44, 32, 82, 69, 76, 79, 67, 44, 32, +/* 0x0a60 */ 82, 69, 65, 68, 79, 78, 76, 89, 10, 32, 49, 55, 32, 80, 69, 73, +/* 0x0a70 */ 77, 80, 79, 82, 50, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, +/* 0x0a80 */ 48, 50, 57, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0a90 */ 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0aa0 */ 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 49,101, +/* 0x0ab0 */ 100, 32, 32, 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, +/* 0x0ac0 */ 83, 44, 32, 82, 69, 76, 79, 67, 44, 32, 82, 69, 65, 68, 79, 78, +/* 0x0ad0 */ 76, 89, 10, 32, 49, 56, 32, 80, 69, 73, 69, 82, 68, 76, 76, 32, +/* 0x0ae0 */ 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 48, 55, 32, 32, 48, +/* 0x0af0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, +/* 0x0b00 */ 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0b10 */ 48, 32, 32, 48, 48, 48, 48, 48, 50, 49, 54, 32, 32, 50, 42, 42, +/* 0x0b20 */ 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, 82, 69, 65, +/* 0x0b30 */ 68, 79, 78, 76, 89, 10, 32, 49, 57, 32, 80, 69, 73, 69, 82, 69, +/* 0x0b40 */ 88, 69, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 48, 97, +/* 0x0b50 */ 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0b60 */ 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0b70 */ 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 50, 49,100, 32, 32, +/* 0x0b80 */ 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, +/* 0x0b90 */ 82, 69, 76, 79, 67, 44, 32, 82, 69, 65, 68, 79, 78, 76, 89, 10, +/* 0x0ba0 */ 32, 50, 48, 32, 80, 69, 73, 77, 68, 79, 78, 69, 32, 32, 32, 32, +/* 0x0bb0 */ 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, +/* 0x0bc0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, +/* 0x0bd0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, +/* 0x0be0 */ 48, 48, 48, 48, 48, 50, 50, 55, 32, 32, 50, 42, 42, 48, 32, 32, +/* 0x0bf0 */ 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, 82, 69, 65, 68, 79, 78, +/* 0x0c00 */ 76, 89, 10, 32, 50, 49, 32, 80, 69, 82, 69, 76, 79, 67, 49, 32, +/* 0x0c10 */ 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 48, 55, 32, 32, 48, +/* 0x0c20 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, +/* 0x0c30 */ 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0c40 */ 48, 32, 32, 48, 48, 48, 48, 48, 50, 50, 55, 32, 32, 50, 42, 42, +/* 0x0c50 */ 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, 82, 69, 76, +/* 0x0c60 */ 79, 67, 44, 32, 82, 69, 65, 68, 79, 78, 76, 89, 10, 32, 50, 50, +/* 0x0c70 */ 32, 80, 69, 82, 69, 76, 79, 67, 50, 32, 32, 32, 32, 32, 32, 48, +/* 0x0c80 */ 48, 48, 48, 48, 48, 48, 52, 32, 32, 48, 48, 48, 48, 48, 48, 48, +/* 0x0c90 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, +/* 0x0ca0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, +/* 0x0cb0 */ 48, 48, 50, 50,101, 32, 32, 50, 42, 42, 48, 32, 32, 67, 79, 78, +/* 0x0cc0 */ 84, 69, 78, 84, 83, 44, 32, 82, 69, 65, 68, 79, 78, 76, 89, 10, +/* 0x0cd0 */ 32, 50, 51, 32, 80, 69, 82, 69, 76, 79, 67, 51, 32, 32, 32, 32, +/* 0x0ce0 */ 32, 32, 48, 48, 48, 48, 48, 48, 48, 52, 32, 32, 48, 48, 48, 48, +/* 0x0cf0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, +/* 0x0d00 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, +/* 0x0d10 */ 48, 48, 48, 48, 48, 50, 51, 50, 32, 32, 50, 42, 42, 48, 32, 32, +/* 0x0d20 */ 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, 82, 69, 65, 68, 79, 78, +/* 0x0d30 */ 76, 89, 10, 32, 50, 52, 32, 80, 69, 82, 76, 79, 72, 73, 48, 32, +/* 0x0d40 */ 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, +/* 0x0d50 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, +/* 0x0d60 */ 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0d70 */ 48, 32, 32, 48, 48, 48, 48, 48, 50, 51, 54, 32, 32, 50, 42, 42, +/* 0x0d80 */ 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, 82, 69, 65, +/* 0x0d90 */ 68, 79, 78, 76, 89, 10, 32, 50, 53, 32, 80, 69, 82, 69, 76, 76, +/* 0x0da0 */ 79, 48, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0db0 */ 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0dc0 */ 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0dd0 */ 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 50, 51, 54, 32, 32, +/* 0x0de0 */ 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, +/* 0x0df0 */ 82, 69, 65, 68, 79, 78, 76, 89, 10, 32, 50, 54, 32, 80, 69, 82, +/* 0x0e00 */ 69, 76, 72, 73, 48, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, +/* 0x0e10 */ 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0e20 */ 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0e30 */ 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 50, 51, +/* 0x0e40 */ 54, 32, 32, 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, +/* 0x0e50 */ 83, 44, 32, 82, 69, 65, 68, 79, 78, 76, 89, 10, 32, 50, 55, 32, +/* 0x0e60 */ 80, 69, 68, 69, 80, 72, 65, 75, 32, 32, 32, 32, 32, 32, 48, 48, +/* 0x0e70 */ 48, 48, 48, 48, 52, 98, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0e80 */ 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, +/* 0x0e90 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, +/* 0x0ea0 */ 48, 50, 51, 54, 32, 32, 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, +/* 0x0eb0 */ 69, 78, 84, 83, 44, 32, 82, 69, 76, 79, 67, 44, 32, 82, 69, 65, +/* 0x0ec0 */ 68, 79, 78, 76, 89, 10, 32, 50, 56, 32, 80, 69, 84, 76, 83, 67, +/* 0x0ed0 */ 32, 32, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 49,100, +/* 0x0ee0 */ 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0ef0 */ 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0f00 */ 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 50, 56, 49, 32, 32, +/* 0x0f10 */ 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, +/* 0x0f20 */ 82, 69, 76, 79, 67, 44, 32, 82, 69, 65, 68, 79, 78, 76, 89, 10, +/* 0x0f30 */ 32, 50, 57, 32, 80, 69, 77, 65, 73, 78, 50, 48, 32, 32, 32, 32, +/* 0x0f40 */ 32, 32, 48, 48, 48, 48, 48, 48, 48, 52, 32, 32, 48, 48, 48, 48, +/* 0x0f50 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, +/* 0x0f60 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, +/* 0x0f70 */ 48, 48, 48, 48, 48, 50, 57,101, 32, 32, 50, 42, 42, 48, 32, 32, +/* 0x0f80 */ 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, 82, 69, 65, 68, 79, 78, +/* 0x0f90 */ 76, 89, 10, 32, 51, 48, 32, 67, 76, 69, 65, 82, 83, 84, 65, 67, +/* 0x0fa0 */ 75, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 49, 48, 32, 32, 48, +/* 0x0fb0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, +/* 0x0fc0 */ 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x0fd0 */ 48, 32, 32, 48, 48, 48, 48, 48, 50, 97, 50, 32, 32, 50, 42, 42, +/* 0x0fe0 */ 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, 82, 69, 65, +/* 0x0ff0 */ 68, 79, 78, 76, 89, 10, 32, 51, 49, 32, 80, 69, 77, 65, 73, 78, +/* 0x1000 */ 50, 49, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1010 */ 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1020 */ 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1030 */ 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 50, 98, 50, 32, 32, +/* 0x1040 */ 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, +/* 0x1050 */ 82, 69, 65, 68, 79, 78, 76, 89, 10, 32, 51, 50, 32, 80, 69, 82, +/* 0x1060 */ 69, 84, 85, 82, 78, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, +/* 0x1070 */ 48, 48, 54, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1080 */ 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1090 */ 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 50, 98, +/* 0x10a0 */ 50, 32, 32, 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, +/* 0x10b0 */ 83, 44, 32, 82, 69, 65, 68, 79, 78, 76, 89, 10, 32, 51, 51, 32, +/* 0x10c0 */ 80, 69, 68, 79, 74, 85, 77, 80, 32, 32, 32, 32, 32, 32, 48, 48, +/* 0x10d0 */ 48, 48, 48, 48, 48, 53, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x10e0 */ 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, +/* 0x10f0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, +/* 0x1100 */ 48, 50, 98, 56, 32, 32, 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, +/* 0x1110 */ 69, 78, 84, 83, 44, 32, 82, 69, 76, 79, 67, 44, 32, 82, 69, 65, +/* 0x1120 */ 68, 79, 78, 76, 89, 10, 32, 51, 52, 32, 80, 69, 84, 76, 83, 67, +/* 0x1130 */ 50, 32, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, 48, 50, 98, +/* 0x1140 */ 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1150 */ 48, 48, 32, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1160 */ 48, 48, 48, 48, 32, 32, 48, 48, 48, 48, 48, 50, 98,100, 32, 32, +/* 0x1170 */ 50, 42, 42, 48, 32, 32, 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, +/* 0x1180 */ 82, 69, 76, 79, 67, 44, 32, 82, 69, 65, 68, 79, 78, 76, 89, 10, +/* 0x1190 */ 32, 51, 53, 32, 85, 80, 88, 49, 72, 69, 65, 68, 32, 32, 32, 32, +/* 0x11a0 */ 32, 32, 48, 48, 48, 48, 48, 48, 50, 48, 32, 32, 48, 48, 48, 48, +/* 0x11b0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 48, 48, +/* 0x11c0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, +/* 0x11d0 */ 48, 48, 48, 48, 48, 50,101, 56, 32, 32, 50, 42, 42, 48, 32, 32, +/* 0x11e0 */ 67, 79, 78, 84, 69, 78, 84, 83, 44, 32, 82, 69, 65, 68, 79, 78, +/* 0x11f0 */ 76, 89, 10, 83, 89, 77, 66, 79, 76, 32, 84, 65, 66, 76, 69, 58, +/* 0x1200 */ 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1210 */ 48, 32,108, 32, 32, 32, 32,100, 32, 32, 78, 82, 86, 95, 72, 69, +/* 0x1220 */ 65, 68, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1230 */ 48, 48, 48, 32, 78, 82, 86, 95, 72, 69, 65, 68, 10, 48, 48, 48, +/* 0x1240 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,108, 32, +/* 0x1250 */ 32, 32, 32,100, 32, 32, 80, 69, 77, 65, 73, 78, 49, 48, 9, 48, +/* 0x1260 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, +/* 0x1270 */ 80, 69, 77, 65, 73, 78, 49, 48, 10, 48, 48, 48, 48, 48, 48, 48, +/* 0x1280 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, 32, 32, +/* 0x1290 */ 32, 32, 80, 69, 73, 77, 68, 79, 78, 69, 9, 48, 48, 48, 48, 48, +/* 0x12a0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,105,109,112,111, +/* 0x12b0 */ 114,116,115, 95,100,111,110,101, 10, 48, 48, 48, 48, 48, 48, 48, +/* 0x12c0 */ 48, 48, 48, 48, 48, 48, 48, 50,102, 32,108, 32, 32, 32, 32, 32, +/* 0x12d0 */ 32, 32, 80, 69, 73, 77, 80, 79, 82, 84, 9, 48, 48, 48, 48, 48, +/* 0x12e0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,110,101,120,116, +/* 0x12f0 */ 95,102,117,110, 99, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1300 */ 48, 48, 48, 48, 48, 97, 32,108, 32, 32, 32, 32, 32, 32, 32, 80, +/* 0x1310 */ 69, 73, 77, 79, 82, 68, 49, 9, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1320 */ 48, 48, 48, 48, 48, 48, 48, 48, 32, 98,121,110, 97,109,101, 10, +/* 0x1330 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 50, 48, +/* 0x1340 */ 32,108, 32, 32, 32, 32, 32, 32, 32, 80, 69, 73, 77, 80, 79, 82, +/* 0x1350 */ 50, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1360 */ 48, 48, 32,110,101,120,116, 95,105,109,112, 10, 48, 48, 48, 48, +/* 0x1370 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 97, 32,108, 32, 32, +/* 0x1380 */ 32, 32, 32, 32, 32, 80, 69, 73, 77, 80, 79, 82, 50, 9, 48, 48, +/* 0x1390 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,102, +/* 0x13a0 */ 105,114,115,116, 95,105,109,112, 10, 48, 48, 48, 48, 48, 48, 48, +/* 0x13b0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, 32,100, +/* 0x13c0 */ 32, 32, 80, 69, 77, 65, 73, 78, 50, 49, 9, 48, 48, 48, 48, 48, +/* 0x13d0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, 77, 65, +/* 0x13e0 */ 73, 78, 50, 49, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x13f0 */ 48, 48, 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, 80, 69, +/* 0x1400 */ 84, 76, 83, 67, 50, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1410 */ 48, 48, 48, 48, 48, 48, 32, 80, 69, 84, 76, 83, 67, 50, 10, 48, +/* 0x1420 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, +/* 0x1430 */ 108, 32, 32, 32, 32,100, 32, 32, 80, 69, 73, 83, 68, 76, 76, 49, +/* 0x1440 */ 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1450 */ 48, 32, 80, 69, 73, 83, 68, 76, 76, 49, 10, 48, 48, 48, 48, 48, +/* 0x1460 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, +/* 0x1470 */ 32,100, 32, 32, 80, 69, 77, 65, 73, 78, 48, 49, 9, 48, 48, 48, +/* 0x1480 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, +/* 0x1490 */ 77, 65, 73, 78, 48, 49, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x14a0 */ 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, +/* 0x14b0 */ 80, 69, 73, 67, 79, 78, 83, 49, 9, 48, 48, 48, 48, 48, 48, 48, +/* 0x14c0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, 73, 67, 79, 78, +/* 0x14d0 */ 83, 49, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x14e0 */ 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, 80, 69, 73, 67, +/* 0x14f0 */ 79, 78, 83, 50, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1500 */ 48, 48, 48, 48, 48, 32, 80, 69, 73, 67, 79, 78, 83, 50, 10, 48, +/* 0x1510 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, +/* 0x1520 */ 108, 32, 32, 32, 32,100, 32, 32, 80, 69, 84, 76, 83, 72, 65, 75, +/* 0x1530 */ 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1540 */ 48, 32, 80, 69, 84, 76, 83, 72, 65, 75, 10, 48, 48, 48, 48, 48, +/* 0x1550 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, +/* 0x1560 */ 32,100, 32, 32, 80, 69, 77, 65, 73, 78, 48, 50, 9, 48, 48, 48, +/* 0x1570 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, +/* 0x1580 */ 77, 65, 73, 78, 48, 50, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1590 */ 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, +/* 0x15a0 */ 80, 69, 77, 65, 73, 78, 48, 51, 9, 48, 48, 48, 48, 48, 48, 48, +/* 0x15b0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, 77, 65, 73, 78, +/* 0x15c0 */ 48, 51, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x15d0 */ 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, 78, 82, 86, 50, +/* 0x15e0 */ 69, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x15f0 */ 48, 48, 32, 78, 82, 86, 50, 69, 10, 48, 48, 48, 48, 48, 48, 48, +/* 0x1600 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, 32,100, +/* 0x1610 */ 32, 32, 80, 69, 67, 84, 84, 80, 79, 83, 9, 48, 48, 48, 48, 48, +/* 0x1620 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, 67, 84, +/* 0x1630 */ 84, 80, 79, 83, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1640 */ 48, 48, 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, 80, 69, +/* 0x1650 */ 67, 84, 84, 78, 85, 76, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1660 */ 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, 67, 84, 84, 78, 85, 76, +/* 0x1670 */ 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1680 */ 48, 32,108, 32, 32, 32, 32,100, 32, 32, 99,116,111,107, 51, 50, +/* 0x1690 */ 46, 48, 48, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x16a0 */ 48, 48, 48, 48, 32, 99,116,111,107, 51, 50, 46, 48, 48, 10, 48, +/* 0x16b0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, +/* 0x16c0 */ 108, 32, 32, 32, 32,100, 32, 32, 80, 69, 73, 77, 80, 79, 82, 84, +/* 0x16d0 */ 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x16e0 */ 48, 32, 80, 69, 73, 77, 80, 79, 82, 84, 10, 48, 48, 48, 48, 48, +/* 0x16f0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, +/* 0x1700 */ 32,100, 32, 32, 80, 69, 73, 66, 89, 79, 82, 68, 9, 48, 48, 48, +/* 0x1710 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, +/* 0x1720 */ 73, 66, 89, 79, 82, 68, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1730 */ 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, +/* 0x1740 */ 80, 69, 75, 51, 50, 79, 82, 68, 9, 48, 48, 48, 48, 48, 48, 48, +/* 0x1750 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, 75, 51, 50, 79, +/* 0x1760 */ 82, 68, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1770 */ 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, 80, 69, 73, 77, +/* 0x1780 */ 79, 82, 68, 49, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1790 */ 48, 48, 48, 48, 48, 32, 80, 69, 73, 77, 79, 82, 68, 49, 10, 48, +/* 0x17a0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, +/* 0x17b0 */ 108, 32, 32, 32, 32,100, 32, 32, 80, 69, 73, 77, 80, 79, 82, 50, +/* 0x17c0 */ 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x17d0 */ 48, 32, 80, 69, 73, 77, 80, 79, 82, 50, 10, 48, 48, 48, 48, 48, +/* 0x17e0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, +/* 0x17f0 */ 32,100, 32, 32, 80, 69, 73, 69, 82, 68, 76, 76, 9, 48, 48, 48, +/* 0x1800 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, +/* 0x1810 */ 73, 69, 82, 68, 76, 76, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1820 */ 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, +/* 0x1830 */ 80, 69, 73, 69, 82, 69, 88, 69, 9, 48, 48, 48, 48, 48, 48, 48, +/* 0x1840 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, 73, 69, 82, 69, +/* 0x1850 */ 88, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1860 */ 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, 80, 69, 73, 77, +/* 0x1870 */ 68, 79, 78, 69, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1880 */ 48, 48, 48, 48, 48, 32, 80, 69, 73, 77, 68, 79, 78, 69, 10, 48, +/* 0x1890 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, +/* 0x18a0 */ 108, 32, 32, 32, 32,100, 32, 32, 80, 69, 82, 69, 76, 79, 67, 49, +/* 0x18b0 */ 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x18c0 */ 48, 32, 80, 69, 82, 69, 76, 79, 67, 49, 10, 48, 48, 48, 48, 48, +/* 0x18d0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, +/* 0x18e0 */ 32,100, 32, 32, 80, 69, 82, 69, 76, 79, 67, 50, 9, 48, 48, 48, +/* 0x18f0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, +/* 0x1900 */ 82, 69, 76, 79, 67, 50, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1910 */ 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, +/* 0x1920 */ 80, 69, 82, 69, 76, 79, 67, 51, 9, 48, 48, 48, 48, 48, 48, 48, +/* 0x1930 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, 82, 69, 76, 79, +/* 0x1940 */ 67, 51, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1950 */ 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, 80, 69, 82, 76, +/* 0x1960 */ 79, 72, 73, 48, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1970 */ 48, 48, 48, 48, 48, 32, 80, 69, 82, 76, 79, 72, 73, 48, 10, 48, +/* 0x1980 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, +/* 0x1990 */ 108, 32, 32, 32, 32,100, 32, 32, 80, 69, 82, 69, 76, 76, 79, 48, +/* 0x19a0 */ 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x19b0 */ 48, 32, 80, 69, 82, 69, 76, 76, 79, 48, 10, 48, 48, 48, 48, 48, +/* 0x19c0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, +/* 0x19d0 */ 32,100, 32, 32, 80, 69, 82, 69, 76, 72, 73, 48, 9, 48, 48, 48, +/* 0x19e0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, +/* 0x19f0 */ 82, 69, 76, 72, 73, 48, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1a00 */ 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, +/* 0x1a10 */ 80, 69, 68, 69, 80, 72, 65, 75, 9, 48, 48, 48, 48, 48, 48, 48, +/* 0x1a20 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, 68, 69, 80, 72, +/* 0x1a30 */ 65, 75, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1a40 */ 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, 80, 69, 84, 76, +/* 0x1a50 */ 83, 67, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1a60 */ 48, 48, 48, 32, 80, 69, 84, 76, 83, 67, 10, 48, 48, 48, 48, 48, +/* 0x1a70 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, +/* 0x1a80 */ 32,100, 32, 32, 80, 69, 77, 65, 73, 78, 50, 48, 9, 48, 48, 48, +/* 0x1a90 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, +/* 0x1aa0 */ 77, 65, 73, 78, 50, 48, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1ab0 */ 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, +/* 0x1ac0 */ 67, 76, 69, 65, 82, 83, 84, 65, 67, 75, 9, 48, 48, 48, 48, 48, +/* 0x1ad0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 67, 76, 69, 65, +/* 0x1ae0 */ 82, 83, 84, 65, 67, 75, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1af0 */ 48, 48, 48, 48, 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, +/* 0x1b00 */ 80, 69, 82, 69, 84, 85, 82, 78, 9, 48, 48, 48, 48, 48, 48, 48, +/* 0x1b10 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 80, 69, 82, 69, 84, 85, +/* 0x1b20 */ 82, 78, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1b30 */ 48, 48, 48, 32,108, 32, 32, 32, 32,100, 32, 32, 80, 69, 68, 79, +/* 0x1b40 */ 74, 85, 77, 80, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1b50 */ 48, 48, 48, 48, 48, 32, 80, 69, 68, 79, 74, 85, 77, 80, 10, 48, +/* 0x1b60 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, +/* 0x1b70 */ 108, 32, 32, 32, 32,100, 32, 32, 85, 80, 88, 49, 72, 69, 65, 68, +/* 0x1b80 */ 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1b90 */ 48, 32, 85, 80, 88, 49, 72, 69, 65, 68, 10, 48, 48, 48, 48, 48, +/* 0x1ba0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 32, 32, 32, +/* 0x1bb0 */ 32, 32, 32, 32, 42, 85, 78, 68, 42, 9, 48, 48, 48, 48, 48, 48, +/* 0x1bc0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,115,116, 97,114,116, +/* 0x1bd0 */ 95,111,102, 95, 99,111,109,112,114,101,115,115,101,100, 10, 48, +/* 0x1be0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, +/* 0x1bf0 */ 32, 32, 32, 32, 32, 32, 32, 32, 42, 85, 78, 68, 42, 9, 48, 48, +/* 0x1c00 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,115, +/* 0x1c10 */ 116, 97,114,116, 95,111,102, 95,117,110, 99,111,109,112,114,101, +/* 0x1c20 */ 115,115,101,100, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1c30 */ 48, 48, 48, 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 42, 85, +/* 0x1c40 */ 78, 68, 42, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1c50 */ 48, 48, 48, 48, 32,105, 99,111,110, 95,111,102,102,115,101,116, +/* 0x1c60 */ 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1c70 */ 48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 42, 85, 78, 68, 42, 9, +/* 0x1c80 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1c90 */ 32,105, 99,111,110, 95,100,101,108,116, 97, 10, 48, 48, 48, 48, +/* 0x1ca0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 32, 32, +/* 0x1cb0 */ 32, 32, 32, 32, 32, 42, 85, 78, 68, 42, 9, 48, 48, 48, 48, 48, +/* 0x1cc0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 32,116,108,115, 95, +/* 0x1cd0 */ 97,100,100,114,101,115,115, 10, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1ce0 */ 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x1cf0 */ 32, 42, 85, 78, 68, 42, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1d00 */ 48, 48, 48, 48, 48, 48, 48, 32,116,108,115, 95,118, 97,108,117, +/* 0x1d10 */ 101, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1d20 */ 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 42, 85, 78, 68, 42, +/* 0x1d30 */ 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1d40 */ 48, 32,102,105,108,116,101,114, 95, 98,117,102,102,101,114, 95, +/* 0x1d50 */ 115,116, 97,114,116, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1d60 */ 48, 48, 48, 48, 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 42, +/* 0x1d70 */ 85, 78, 68, 42, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1d80 */ 48, 48, 48, 48, 48, 32,102,105,108,116,101,114, 95,108,101,110, +/* 0x1d90 */ 103,116,104, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1da0 */ 48, 48, 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 42, 85, 78, +/* 0x1db0 */ 68, 42, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1dc0 */ 48, 48, 48, 32, 99,111,109,112,114,101,115,115,101,100, 95,105, +/* 0x1dd0 */ 109,112,111,114,116,115, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1de0 */ 48, 48, 48, 48, 48, 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x1df0 */ 42, 85, 78, 68, 42, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1e00 */ 48, 48, 48, 48, 48, 48, 32,115,116, 97,114,116, 95,111,102, 95, +/* 0x1e10 */ 105,109,112,111,114,116,115, 10, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1e20 */ 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x1e30 */ 32, 42, 85, 78, 68, 42, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1e40 */ 48, 48, 48, 48, 48, 48, 48, 32, 76,111, 97,100, 76,105, 98,114, +/* 0x1e50 */ 97,114,121, 65, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1e60 */ 48, 48, 48, 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 42, 85, +/* 0x1e70 */ 78, 68, 42, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1e80 */ 48, 48, 48, 48, 32,107,101,114,110,101,108, 51, 50, 95,111,114, +/* 0x1e90 */ 100,105,110, 97,108,115, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1ea0 */ 48, 48, 48, 48, 48, 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x1eb0 */ 42, 85, 78, 68, 42, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1ec0 */ 48, 48, 48, 48, 48, 48, 32, 71,101,116, 80,114,111, 99, 65,100, +/* 0x1ed0 */ 100,114,101,115,115, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1ee0 */ 48, 48, 48, 48, 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 42, +/* 0x1ef0 */ 85, 78, 68, 42, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1f00 */ 48, 48, 48, 48, 48, 32, 69,120,105,116, 80,114,111, 99,101,115, +/* 0x1f10 */ 115, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1f20 */ 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 42, 85, 78, 68, 42, +/* 0x1f30 */ 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1f40 */ 48, 32,115,116, 97,114,116, 95,111,102, 95,114,101,108,111, 99, +/* 0x1f50 */ 115, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1f60 */ 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 42, 85, 78, 68, 42, +/* 0x1f70 */ 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1f80 */ 48, 32, 86,105,114,116,117, 97,108, 80,114,111,116,101, 99,116, +/* 0x1f90 */ 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1fa0 */ 48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 42, 85, 78, 68, 42, 9, +/* 0x1fb0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1fc0 */ 32,118,112, 95, 98, 97,115,101, 10, 48, 48, 48, 48, 48, 48, 48, +/* 0x1fd0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 32, 32, 32, 32, 32, 32, 32, +/* 0x1fe0 */ 32, 32, 42, 85, 78, 68, 42, 9, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x1ff0 */ 48, 48, 48, 48, 48, 48, 48, 48, 32,118,112, 95,115,105,122,101, +/* 0x2000 */ 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x2010 */ 48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 42, 85, 78, 68, 42, 9, +/* 0x2020 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x2030 */ 32,115,119,114,105, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x2040 */ 48, 48, 48, 48, 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 42, +/* 0x2050 */ 85, 78, 68, 42, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x2060 */ 48, 48, 48, 48, 48, 32,116,108,115, 95,109,111,100,117,108,101, +/* 0x2070 */ 95, 98, 97,115,101, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x2080 */ 48, 48, 48, 48, 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 42, +/* 0x2090 */ 85, 78, 68, 42, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x20a0 */ 48, 48, 48, 48, 48, 32,111,114,105,103,105,110, 97,108, 95,101, +/* 0x20b0 */ 110,116,114,121, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x20c0 */ 48, 48, 48, 48, 48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 42, 85, +/* 0x20d0 */ 78, 68, 42, 9, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x20e0 */ 48, 48, 48, 48, 32,116,108,115, 95, 99, 97,108,108, 98, 97, 99, +/* 0x20f0 */ 107,115, 95,112,116,114, 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, +/* 0x2100 */ 79, 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, +/* 0x2110 */ 80, 69, 73, 83, 68, 76, 76, 49, 93, 58, 10, 79, 70, 70, 83, 69, +/* 0x2120 */ 84, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, +/* 0x2130 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, +/* 0x2140 */ 76, 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x2150 */ 48, 48, 48, 53, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 80, 67, +/* 0x2160 */ 51, 50, 32, 32, 32, 32, 32, 80, 69, 77, 65, 73, 78, 50, 49, 43, +/* 0x2170 */ 48,120,102,102,102,102,102,102,102,102,102,102,102,102,102,102, +/* 0x2180 */ 102, 99, 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, +/* 0x2190 */ 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 77, 65, +/* 0x21a0 */ 73, 78, 48, 49, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, +/* 0x21b0 */ 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, +/* 0x21c0 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, +/* 0x21d0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 54, +/* 0x21e0 */ 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 54, 52, 32, 32, 32, 32, +/* 0x21f0 */ 32, 32, 32,115,116, 97,114,116, 95,111,102, 95, 99,111,109,112, +/* 0x2200 */ 114,101,115,115,101,100, 43, 48,120, 56, 48, 48, 48, 48, 48, 48, +/* 0x2210 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 10, 48, 48, 48, 48, 48, 48, +/* 0x2220 */ 48, 48, 48, 48, 48, 48, 48, 48, 49, 49, 32, 82, 95, 88, 56, 54, +/* 0x2230 */ 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, 32,115,116, 97, +/* 0x2240 */ 114,116, 95,111,102, 95,117,110, 99,111,109,112,114,101,115,115, +/* 0x2250 */ 101,100, 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, +/* 0x2260 */ 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 73, 67, +/* 0x2270 */ 79, 78, 83, 49, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, +/* 0x2280 */ 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, +/* 0x2290 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, +/* 0x22a0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 51, +/* 0x22b0 */ 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, +/* 0x22c0 */ 32, 32, 32,105, 99,111,110, 95,111,102,102,115,101,116, 10, 10, +/* 0x22d0 */ 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, +/* 0x22e0 */ 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 73, 67, 79, 78, 83, 50, +/* 0x22f0 */ 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, +/* 0x2300 */ 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x2310 */ 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, +/* 0x2320 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 51, 32, 82, 95, 88, +/* 0x2330 */ 56, 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, 32,105, +/* 0x2340 */ 99,111,110, 95,111,102,102,115,101,116, 10, 48, 48, 48, 48, 48, +/* 0x2350 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 55, 32, 82, 95, 88, 56, +/* 0x2360 */ 54, 95, 54, 52, 95, 49, 54, 32, 32, 32, 32, 32, 32, 32,105, 99, +/* 0x2370 */ 111,110, 95,100,101,108,116, 97, 43, 48,120, 48, 48, 48, 48, 48, +/* 0x2380 */ 48, 48, 48, 48, 48, 48, 48, 56, 48, 48, 48, 10, 10, 82, 69, 76, +/* 0x2390 */ 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, +/* 0x23a0 */ 70, 79, 82, 32, 91, 80, 69, 84, 76, 83, 72, 65, 75, 93, 58, 10, +/* 0x23b0 */ 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x23c0 */ 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x23d0 */ 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, +/* 0x23e0 */ 48, 48, 48, 48, 48, 48, 48, 48, 50, 32, 82, 95, 88, 56, 54, 95, +/* 0x23f0 */ 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, 32,116,108,115, 95, +/* 0x2400 */ 97,100,100,114,101,115,115, 10, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x2410 */ 48, 48, 48, 48, 48, 48, 48, 54, 32, 82, 95, 88, 56, 54, 95, 54, +/* 0x2420 */ 52, 95, 51, 50, 32, 32, 32, 32, 32, 32, 32,116,108,115, 95,118, +/* 0x2430 */ 97,108,117,101, 43, 48,120, 48, 48, 48, 48, 48, 48, 48, 48, 56, +/* 0x2440 */ 48, 48, 48, 48, 48, 48, 48, 10, 10, 82, 69, 76, 79, 67, 65, 84, +/* 0x2450 */ 73, 79, 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, +/* 0x2460 */ 91, 78, 82, 86, 50, 69, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, +/* 0x2470 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, +/* 0x2480 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, +/* 0x2490 */ 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x24a0 */ 97, 53, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 80, 67, 51, 50, +/* 0x24b0 */ 32, 32, 32, 32, 32, 78, 82, 86, 95, 72, 69, 65, 68, 43, 48,120, +/* 0x24c0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 98, +/* 0x24d0 */ 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 53, +/* 0x24e0 */ 50, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 80, 67, 51, 50, 32, +/* 0x24f0 */ 32, 32, 32, 32, 80, 69, 77, 65, 73, 78, 49, 48, 43, 48,120,102, +/* 0x2500 */ 102,102,102,102,102,102,102,102,102,102,102,102,102,102, 99, 10, +/* 0x2510 */ 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, +/* 0x2520 */ 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 67, 84, 84, 80, 79, +/* 0x2530 */ 83, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, +/* 0x2540 */ 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, +/* 0x2550 */ 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, +/* 0x2560 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 51, 32, 82, 95, +/* 0x2570 */ 88, 56, 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, 32, +/* 0x2580 */ 102,105,108,116,101,114, 95, 98,117,102,102,101,114, 95,115,116, +/* 0x2590 */ 97,114,116, 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, +/* 0x25a0 */ 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 99,116,111, +/* 0x25b0 */ 107, 51, 50, 46, 48, 48, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, +/* 0x25c0 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, +/* 0x25d0 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, +/* 0x25e0 */ 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x25f0 */ 48, 49, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 51, 50, 32, 32, +/* 0x2600 */ 32, 32, 32, 32, 32,102,105,108,116,101,114, 95,108,101,110,103, +/* 0x2610 */ 116,104, 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, +/* 0x2620 */ 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 73, 77, +/* 0x2630 */ 80, 79, 82, 84, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, +/* 0x2640 */ 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, +/* 0x2650 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, +/* 0x2660 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 51, +/* 0x2670 */ 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, +/* 0x2680 */ 32, 32, 32, 99,111,109,112,114,101,115,115,101,100, 95,105,109, +/* 0x2690 */ 112,111,114,116,115, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x26a0 */ 48, 48, 48, 48, 48, 99, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, +/* 0x26b0 */ 80, 67, 56, 32, 32, 32, 32, 32, 32,105,109,112,111,114,116,115, +/* 0x26c0 */ 95,100,111,110,101, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x26d0 */ 48, 48, 48, 48, 49, 52, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, +/* 0x26e0 */ 51, 50, 83, 32, 32, 32, 32, 32, 32,115,116, 97,114,116, 95,111, +/* 0x26f0 */ 102, 95,105,109,112,111,114,116,115, 10, 48, 48, 48, 48, 48, 48, +/* 0x2700 */ 48, 48, 48, 48, 48, 48, 48, 48, 50, 53, 32, 82, 95, 88, 56, 54, +/* 0x2710 */ 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, 32, 76,111, 97, +/* 0x2720 */ 100, 76,105, 98,114, 97,114,121, 65, 10, 10, 82, 69, 76, 79, 67, +/* 0x2730 */ 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, +/* 0x2740 */ 82, 32, 91, 80, 69, 73, 66, 89, 79, 82, 68, 93, 58, 10, 79, 70, +/* 0x2750 */ 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, +/* 0x2760 */ 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x2770 */ 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x2780 */ 48, 48, 48, 48, 48, 48, 49, 32, 82, 95, 88, 56, 54, 95, 54, 52, +/* 0x2790 */ 95, 80, 67, 56, 32, 32, 32, 32, 32, 32, 98,121,110, 97,109,101, +/* 0x27a0 */ 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, +/* 0x27b0 */ 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 75, 51, 50, 79, +/* 0x27c0 */ 82, 68, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, +/* 0x27d0 */ 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, +/* 0x27e0 */ 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, +/* 0x27f0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 99, 32, 82, +/* 0x2800 */ 95, 88, 56, 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, +/* 0x2810 */ 32,107,101,114,110,101,108, 51, 50, 95,111,114,100,105,110, 97, +/* 0x2820 */ 108,115, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x2830 */ 48, 49, 49, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 80, 67, 56, +/* 0x2840 */ 32, 32, 32, 32, 32, 32,110,101,120,116, 95,105,109,112, 10, 10, +/* 0x2850 */ 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, +/* 0x2860 */ 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 73, 77, 79, 82, 68, 49, +/* 0x2870 */ 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, +/* 0x2880 */ 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x2890 */ 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, +/* 0x28a0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 57, 32, 82, 95, 88, +/* 0x28b0 */ 56, 54, 95, 54, 52, 95, 80, 67, 56, 32, 32, 32, 32, 32, 32,102, +/* 0x28c0 */ 105,114,115,116, 95,105,109,112, 10, 10, 82, 69, 76, 79, 67, 65, +/* 0x28d0 */ 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, +/* 0x28e0 */ 32, 91, 80, 69, 73, 77, 80, 79, 82, 50, 93, 58, 10, 79, 70, 70, +/* 0x28f0 */ 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, +/* 0x2900 */ 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x2910 */ 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x2920 */ 48, 48, 48, 48, 49, 51, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, +/* 0x2930 */ 51, 50, 83, 32, 32, 32, 32, 32, 32, 71,101,116, 80,114,111, 99, +/* 0x2940 */ 65,100,100,114,101,115,115, 10, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x2950 */ 48, 48, 48, 48, 48, 48, 50, 56, 32, 82, 95, 88, 56, 54, 95, 54, +/* 0x2960 */ 52, 95, 80, 67, 56, 32, 32, 32, 32, 32, 32,110,101,120,116, 95, +/* 0x2970 */ 102,117,110, 99, 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, +/* 0x2980 */ 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, +/* 0x2990 */ 73, 69, 82, 69, 88, 69, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, +/* 0x29a0 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, +/* 0x29b0 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, +/* 0x29c0 */ 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x29d0 */ 48, 54, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 51, 50, 83, 32, +/* 0x29e0 */ 32, 32, 32, 32, 32, 69,120,105,116, 80,114,111, 99,101,115,115, +/* 0x29f0 */ 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, +/* 0x2a00 */ 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 82, 69, 76, 79, +/* 0x2a10 */ 67, 49, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, +/* 0x2a20 */ 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, +/* 0x2a30 */ 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, +/* 0x2a40 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 51, 32, 82, +/* 0x2a50 */ 95, 88, 56, 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, +/* 0x2a60 */ 32,115,116, 97,114,116, 95,111,102, 95,114,101,108,111, 99,115, +/* 0x2a70 */ 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, +/* 0x2a80 */ 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 68, 69, 80, 72, +/* 0x2a90 */ 65, 75, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, +/* 0x2aa0 */ 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, +/* 0x2ab0 */ 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, +/* 0x2ac0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 51, 32, 82, +/* 0x2ad0 */ 95, 88, 56, 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, +/* 0x2ae0 */ 32, 86,105,114,116,117, 97,108, 80,114,111,116,101, 99,116, 10, +/* 0x2af0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 97, +/* 0x2b00 */ 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, +/* 0x2b10 */ 32, 32, 32,118,112, 95, 98, 97,115,101, 10, 48, 48, 48, 48, 48, +/* 0x2b20 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,102, 32, 82, 95, 88, 56, +/* 0x2b30 */ 54, 95, 54, 52, 95, 51, 50, 32, 32, 32, 32, 32, 32, 32,118,112, +/* 0x2b40 */ 95,115,105,122,101, 43, 48,120, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x2b50 */ 56, 48, 48, 48, 48, 48, 48, 48, 10, 48, 48, 48, 48, 48, 48, 48, +/* 0x2b60 */ 48, 48, 48, 48, 48, 48, 48, 50, 99, 32, 82, 95, 88, 56, 54, 95, +/* 0x2b70 */ 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, 32,115,119,114,105, +/* 0x2b80 */ 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, +/* 0x2b90 */ 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 84, 76, 83, 67, +/* 0x2ba0 */ 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, +/* 0x2bb0 */ 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x2bc0 */ 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, +/* 0x2bd0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 51, 32, 82, 95, 88, +/* 0x2be0 */ 56, 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, 32,116, +/* 0x2bf0 */ 108,115, 95,109,111,100,117,108,101, 95, 98, 97,115,101, 10, 48, +/* 0x2c00 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 97, 32, +/* 0x2c10 */ 82, 95, 88, 56, 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, +/* 0x2c20 */ 32, 32, 80, 69, 84, 76, 83, 67, 50, 43, 48,120, 48, 48, 48, 48, +/* 0x2c30 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 10, 10, 82, 69, +/* 0x2c40 */ 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, 68, 83, +/* 0x2c50 */ 32, 70, 79, 82, 32, 91, 80, 69, 68, 79, 74, 85, 77, 80, 93, 58, +/* 0x2c60 */ 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x2c70 */ 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x2c80 */ 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, 48, 48, +/* 0x2c90 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 32, 82, 95, 88, 56, 54, +/* 0x2ca0 */ 95, 54, 52, 95, 80, 67, 51, 50, 32, 32, 32, 32, 32,111,114,105, +/* 0x2cb0 */ 103,105,110, 97,108, 95,101,110,116,114,121, 43, 48,120,102,102, +/* 0x2cc0 */ 102,102,102,102,102,102,102,102,102,102,102,102,102, 99, 10, 10, +/* 0x2cd0 */ 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, +/* 0x2ce0 */ 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 84, 76, 83, 67, 50, 93, +/* 0x2cf0 */ 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x2d00 */ 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x2d10 */ 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, 48, +/* 0x2d20 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 53, 32, 82, 95, 88, 56, +/* 0x2d30 */ 54, 95, 54, 52, 95, 54, 52, 32, 32, 32, 32, 32, 32, 32,116,108, +/* 0x2d40 */ 115, 95, 99, 97,108,108, 98, 97, 99,107,115, 95,112,116,114, 43, +/* 0x2d50 */ 48,120, 56, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x2d60 */ 48, 48, 10 +}; diff --git a/src/stub/src/amd64-win64.pep.S b/src/stub/src/amd64-win64.pep.S new file mode 100644 index 00000000..4514f893 --- /dev/null +++ b/src/stub/src/amd64-win64.pep.S @@ -0,0 +1,431 @@ +/* +; AMD64-win64.pep.S -- loader & decompressor for the w64/pe32+ format +; +; This file is part of the UPX executable compressor. +; +; Copyright (C) 1996-2009 Markus Franz Xaver Johannes Oberhumer +; Copyright (C) 1996-2009 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 +; +; +;--------------------------------------------------------------------- +; +; 64 bit modifications (C) 2010 Stefan Widmann +; +; Major changes when porting 32 bit code to 64 bit: +; - there are no pusha/popa instructions +; - since we cannot use pusha/popa, we save rbx, rsi, rdi and rbp instead +; - inc are now being encoded in 2 byte instructions +; - functions use fast call calling convention (parameters are passed in registers) +; rcx, rdx, r8, r9 +; - caller is responsible for stack allocation for callee +; - caller cleans up stack +; - caller must keep the stack 16 byte aligned, 32 bytes shadow space on stack +; For more information about the 64 bit calling convention see http://blogs.msdn.com/oldnewthing/archive/2004/01/14/58579.aspx +*/ + +#include "arch/amd64/macros.S" + +#define IMM8(value) byte ptr 0; \ + .reloc $ - 1, R_X86_64_8, value + +#define IMM16(value) word ptr (1<<15); \ + .reloc $ - 2, R_X86_64_16, (1<<15) + value + +#define IMM32(value) dword ptr (1<<31); \ + .reloc $ - 4, R_X86_64_32, (1<<31) + value + +#define IMM64(value) qword ptr (1<<63); \ + .reloc $ - 8, R_X86_64_64, (1<<63) + value + +#define SHORT(label) $ + 1; .reloc $ - 1, R_X86_64_PC8, label + +.intel_syntax noprefix + +// ============= +// ============= ENTRY POINT +// ============= + +section PEISDLL1 + cmp dl, 1 + jnz reloc_end_jmp +section PEMAIN01 + //; remember to keep stack aligned! + push rbx + push rsi + push rdi + push rbp + movabs rsi, IMM64(start_of_compressed) //; relocated + lea rdi, [rsi + start_of_uncompressed] + +section PEICONS1 + incw [rdi + icon_offset] +section PEICONS2 + add [rdi + icon_offset], IMM16(icon_delta) +section PETLSHAK + mov [rdi + tls_address], IMM32(tls_value) + +section PEMAIN02 + push rdi +section PEMAIN03 + +// ============= +// ============= DECOMPRESSION +// ============= + +.att_syntax +section NRV_HEAD +/* Working registers */ +#define off %eax /* XXX: 2GB */ +#define len %ecx /* XXX: 2GB */ +#define lenq %rcx +#define bits %ebx +#define disp %rbp + + xor bits,bits // empty; force refill + xor len,len // create loop invariant + orq $(~0),disp // -1: initial displacement + call setup // push &getbit [TUNED] +ra_setup: + +#define jnextb0np jnextb0yp +#define jnextb0yp GETBITp; jnc +#define jnextb1np jnextb1yp +#define jnextb1yp GETBITp; jc +#define GETBITp \ + addl bits,bits; jnz 0f; \ + movl (%rsi),bits; subq $-4,%rsi; \ + adcl bits,bits; movb (%rsi),%dl; \ +0: +/* Same, but without prefetch (not useful for length of match.) */ +#define jnextb0n jnextb0y +#define jnextb0y GETBIT; jnc +#define jnextb1n jnextb1y +#define jnextb1y GETBIT; jc +#define GETBIT \ + addl bits,bits; jnz 0f; \ + movl (%rsi),bits; subq $-4,%rsi; \ + adcl bits,bits; \ +0: + +/* rotate next bit into bottom bit of reg */ +#define getnextbp(reg) call *%r11; adcl reg,reg +#define getnextb(reg) getnextbp(reg) + + +getbit: + addl bits,bits; jz refill // Carry= next bit + rep; ret +refill: + movl (%rsi),bits; subq $-4,%rsi // next 32 bits; set Carry + adcl bits,bits // LSB= 1 (CarryIn); CarryOut= next bit + movb (%rsi),%dl // speculate: literal, or bottom 8 bits of offset + rep; ret + +copy: // In: len, %rdi, disp; Out: 0==len, %rdi, disp; trashes %rax, %rdx + leaq (%rdi,disp),%rax; cmpl $5,len // <=3 is forced + movb (%rax),%dl; jbe copy1 // <=5 for better branch predict + cmpq $-4,disp; ja copy1 // 4-byte chunks would overlap + subl $4,len // adjust for termination cases +copy4: + movl (%rax),%edx; addq $4, %rax; subl $4,len + movl %edx,(%rdi); leaq 4(%rdi),%rdi; jnc copy4 + addl $4,len; movb (%rax),%dl; jz copy0 +copy1: + incq %rax; movb %dl,(%rdi); subl $1,len + movb (%rax),%dl + leaq 1(%rdi),%rdi; jnz copy1 +copy0: + rep; ret + +setup: + cld + pop %r11 // addq $ getbit - ra_setup,%r11 # &getbit + +#define NO_METHOD_CHECK + +section NRV2E +#include "arch/amd64/nrv2e_d.S" + + +#if 0 //; FIXME +#include "arch/amd64/nrv2b_d.S" +#include "arch/amd64/nrv2d_d.S" +#include "arch/amd64/nrv2e_d.S" +#include "arch/amd64/lzma_d.S" +#endif + +.intel_syntax noprefix +// ============= +section PEMAIN10 +eof: + pop rsi // load vaddr + +// ============= +// ============= CALLTRICK +// ============= + +section PECTTPOS + lea rdi, [rsi + filter_buffer_start] +section PECTTNUL + mov rdi, rsi + +#if 0 //; FIXME use amd_bxx.S + cjt32 esi +#endif + +section ctok32.00 + mov ecx, offset filter_length +#if 0 //; FIXME + ctok32 esi, (offset filter_cto) +#endif + +// ============= +// ============= IMPORTS +// ============= + +section PEIMPORT + lea rdi, [rsi + compressed_imports] +next_dll: + mov eax, [rdi] + or eax, eax + jz SHORT(imports_done) + mov ebx, [rdi + 4] // iat + lea rcx, [rax + rsi + start_of_imports] + add rbx, rsi + add rdi, 8 + + sub rsp, 0x28 + call [rsi + LoadLibraryA] + add rsp, 0x28 + + xchg rax, rbp +next_func: + mov al, [rdi] + inc rdi + or al, al + jz next_dll +section PEIBYORD + jns SHORT(byname) +section PEK32ORD + jpe not_kernel32 + mov eax, [rdi] + add rdi, 4 + mov rax, [rax + rsi + kernel32_ordinals] + jmp SHORT(next_imp) +not_kernel32: +section PEIMORD1 + movzxw rdx, word ptr [rdi] + add rdi, 2 + jmp SHORT(first_imp) + +byname: +section PEIMPOR2 + mov rcx, rdi // something > 0 + mov rdx, rdi + dec eax + repne + scasb +first_imp: + mov rcx, rbp + + sub rsp, 0x28 + call [rsi + GetProcAddress] + add rsp, 0x28 + + or rax, rax + jz imp_failed +next_imp: + mov [rbx], rax + add rbx, 8 + jmp SHORT(next_func) +imp_failed: +section PEIERDLL + pop rbp + pop rdi + pop rsi + pop rbx + xor eax, eax + ret + +section PEIEREXE + // rcx contains garbage -> garbage return code + sub rsp, 0x28 + call [rsi + ExitProcess] +section PEIMDONE +imports_done: + +// ============= +// ============= RELOCATION +// ============= + +section PERELOC1 + lea rdi, [rsi + start_of_relocs] +section PERELOC2 + add rdi, 4 +section PERELOC3 + lea rbx, [rsi - 4] + +#if 0 //; FIXME + reloc64 rdi, rbx, rsi +#endif + + +// ============= + +// FIXME: depends on that in PERELOC1 edi is set!! +section PERLOHI0 +#if 0 + xchg edi, esi + lea ecx, [rdi + reloc_delt] +#endif + +section PERELLO0 +#if 0 + .byte 0xA9 //test eax, XXXXXXXX +rello0: + add [rdi + rax], cx //why do we just use cx instead of ecx? + lodsd + or eax, eax + jnz rello0 +#endif +// ============= + +section PERELHI0 +#if 0 + shr ecx, 16 + .byte 0xA9 //test eax, XXXXXXXX +relhi0: + add [rdi + rax], cx //why do we just use cx instead of ecx? + lodsd + or eax, eax + jnz relhi0 +#endif + +// ============= +section PEDEPHAK + mov rbp, [rsi + VirtualProtect] + lea rdi, [rsi + vp_base] + mov ebx, IMM32(vp_size) // 0x1000 or 0x2000 + + push rax // provide 8 bytes stack + mov r9, rsp + mov r8d, 4 // PAGE_READWRITE + mov rdx, rbx // size + mov rcx, rdi // address + + sub rsp, 0x20 + call rbp // VirtualProtect + + lea rax, [rdi + swri] + andb [rax], 0x7f // marks UPX0 non writeable + andb [rax + 0x28], 0x7f // marks UPX1 non writeable + + lea r9, [rsp + 0x20] + movq r8, [r9] // original protection + mov rdx, rbx + mov rcx, rdi + + call rbp + add rsp, 0x28 + +// ============= +section PETLSC + lea rcx, [rsi + tls_module_base] //;load module base to rcx + lea rdi, [rcx + tls_handler_start + 1] //;load offset of handler + //;remove jump from TLS handler entry (overwrite displacement) + xor eax, eax + stosb + //;emulate callbacks like PE loader would have done + mov r8, rax //;0 - reserved + mov edx, 1 //;DLL_PROCESS_ATTACH + + push rax //;align stack + call rdi //;contains ptr to callback handler + pop rax + +// ============= +section PEMAIN20 + pop rbp + pop rdi + pop rsi + pop rbx + +// clear the dirty stack +.macro clearstack128 tmp_reg + .local loop + lea \tmp_reg, [rsp - 128] +loop: + push 0 + cmp rsp, \tmp_reg + jnz loop + sub rsp, -128 +.endm + +section CLEARSTACK + clearstack128 rax + +section PEMAIN21 +reloc_end_jmp: + +section PERETURN + mov eax, 1 + ret +section PEDOJUMP + jmp original_entry + +// ============= +section PETLSC2 + //;TLS_CALLBACK(hModule, reason, reserved) +tls_handler_start: + jmp end_of_tls_handler //;this jump is patched to EB 00 (jmp $+2) by stub + push rsi + movabs rsi, IMM64(tls_callbacks_ptr) //;must be relocated + cld //;you never know, this code gets called by the PE loader +walk_tlsc_chain2: + lodsq + test rax, rax + jz done_callbacks + + push rcx + push rdx + push r8 + + sub rsp, 0x28 + call rax + add rsp, 0x28 + + pop r8 + pop rdx + pop rcx + + jmp walk_tlsc_chain2 +done_callbacks: + pop rsi +end_of_tls_handler: + ret + +// ============= +// ============= CUT HERE +// ============= + +#include "include/header.S" + +// vi:ts=8:et:nowrap diff --git a/src/stub/src/arch/amd64/nrv2e_d.S b/src/stub/src/arch/amd64/nrv2e_d.S index 2af15448..9ae3f8a4 100644 --- a/src/stub/src/arch/amd64/nrv2e_d.S +++ b/src/stub/src/arch/amd64/nrv2e_d.S @@ -29,7 +29,11 @@ */ +#ifndef NO_METHOD_CHECK cmpb $ M_NRV2E_LE32,methb; je top_n2e; jmp not_n2e +#else + jmp top_n2e +#endif lit_n2e: incq %rsi; movb %dl,(%rdi) diff --git a/src/stub/tmp/amd64-win64.pep.bin.dump b/src/stub/tmp/amd64-win64.pep.bin.dump new file mode 100644 index 00000000..4bc362f4 --- /dev/null +++ b/src/stub/tmp/amd64-win64.pep.bin.dump @@ -0,0 +1,193 @@ +file format elf64-x86-64 + +Sections: +Idx Name Size VMA LMA File off Algn Flags + 0 PEISDLL1 00000009 0000000000000000 0000000000000000 00000040 2**0 CONTENTS, RELOC, READONLY + 1 PEMAIN01 00000015 0000000000000000 0000000000000000 00000049 2**0 CONTENTS, RELOC, READONLY + 2 PEICONS1 00000007 0000000000000000 0000000000000000 0000005e 2**0 CONTENTS, RELOC, READONLY + 3 PEICONS2 00000009 0000000000000000 0000000000000000 00000065 2**0 CONTENTS, RELOC, READONLY + 4 PETLSHAK 0000000a 0000000000000000 0000000000000000 0000006e 2**0 CONTENTS, RELOC, READONLY + 5 PEMAIN02 00000001 0000000000000000 0000000000000000 00000078 2**0 CONTENTS, READONLY + 6 PEMAIN03 00000000 0000000000000000 0000000000000000 00000079 2**0 CONTENTS, READONLY + 7 NRV_HEAD 00000060 0000000000000000 0000000000000000 00000079 2**0 CONTENTS, READONLY + 8 NRV2E 000000ae 0000000000000000 0000000000000000 000000d9 2**0 CONTENTS, RELOC, READONLY + 9 PEMAIN10 00000001 0000000000000000 0000000000000000 00000187 2**0 CONTENTS, READONLY + 10 PECTTPOS 00000007 0000000000000000 0000000000000000 00000188 2**0 CONTENTS, RELOC, READONLY + 11 PECTTNUL 00000003 0000000000000000 0000000000000000 0000018f 2**0 CONTENTS, READONLY + 12 ctok32.00 00000005 0000000000000000 0000000000000000 00000192 2**0 CONTENTS, RELOC, READONLY + 13 PEIMPORT 00000038 0000000000000000 0000000000000000 00000197 2**0 CONTENTS, RELOC, READONLY + 14 PEIBYORD 00000002 0000000000000000 0000000000000000 000001cf 2**0 CONTENTS, RELOC, READONLY + 15 PEK32ORD 00000012 0000000000000000 0000000000000000 000001d1 2**0 CONTENTS, RELOC, READONLY + 16 PEIMORD1 0000000a 0000000000000000 0000000000000000 000001e3 2**0 CONTENTS, RELOC, READONLY + 17 PEIMPOR2 00000029 0000000000000000 0000000000000000 000001ed 2**0 CONTENTS, RELOC, READONLY + 18 PEIERDLL 00000007 0000000000000000 0000000000000000 00000216 2**0 CONTENTS, READONLY + 19 PEIEREXE 0000000a 0000000000000000 0000000000000000 0000021d 2**0 CONTENTS, RELOC, READONLY + 20 PEIMDONE 00000000 0000000000000000 0000000000000000 00000227 2**0 CONTENTS, READONLY + 21 PERELOC1 00000007 0000000000000000 0000000000000000 00000227 2**0 CONTENTS, RELOC, READONLY + 22 PERELOC2 00000004 0000000000000000 0000000000000000 0000022e 2**0 CONTENTS, READONLY + 23 PERELOC3 00000004 0000000000000000 0000000000000000 00000232 2**0 CONTENTS, READONLY + 24 PERLOHI0 00000000 0000000000000000 0000000000000000 00000236 2**0 CONTENTS, READONLY + 25 PERELLO0 00000000 0000000000000000 0000000000000000 00000236 2**0 CONTENTS, READONLY + 26 PERELHI0 00000000 0000000000000000 0000000000000000 00000236 2**0 CONTENTS, READONLY + 27 PEDEPHAK 0000004b 0000000000000000 0000000000000000 00000236 2**0 CONTENTS, RELOC, READONLY + 28 PETLSC 0000001d 0000000000000000 0000000000000000 00000281 2**0 CONTENTS, RELOC, READONLY + 29 PEMAIN20 00000004 0000000000000000 0000000000000000 0000029e 2**0 CONTENTS, READONLY + 30 CLEARSTACK 00000010 0000000000000000 0000000000000000 000002a2 2**0 CONTENTS, READONLY + 31 PEMAIN21 00000000 0000000000000000 0000000000000000 000002b2 2**0 CONTENTS, READONLY + 32 PERETURN 00000006 0000000000000000 0000000000000000 000002b2 2**0 CONTENTS, READONLY + 33 PEDOJUMP 00000005 0000000000000000 0000000000000000 000002b8 2**0 CONTENTS, RELOC, READONLY + 34 PETLSC2 0000002b 0000000000000000 0000000000000000 000002bd 2**0 CONTENTS, RELOC, READONLY + 35 UPX1HEAD 00000020 0000000000000000 0000000000000000 000002e8 2**0 CONTENTS, READONLY +SYMBOL TABLE: +0000000000000000 l d NRV_HEAD 0000000000000000 NRV_HEAD +0000000000000000 l d PEMAIN10 0000000000000000 PEMAIN10 +0000000000000000 l PEIMDONE 0000000000000000 imports_done +000000000000002f l PEIMPORT 0000000000000000 next_func +000000000000000a l PEIMORD1 0000000000000000 byname +0000000000000020 l PEIMPOR2 0000000000000000 next_imp +000000000000000a l PEIMPOR2 0000000000000000 first_imp +0000000000000000 l d PEMAIN21 0000000000000000 PEMAIN21 +0000000000000000 l d PETLSC2 0000000000000000 PETLSC2 +0000000000000000 l d PEISDLL1 0000000000000000 PEISDLL1 +0000000000000000 l d PEMAIN01 0000000000000000 PEMAIN01 +0000000000000000 l d PEICONS1 0000000000000000 PEICONS1 +0000000000000000 l d PEICONS2 0000000000000000 PEICONS2 +0000000000000000 l d PETLSHAK 0000000000000000 PETLSHAK +0000000000000000 l d PEMAIN02 0000000000000000 PEMAIN02 +0000000000000000 l d PEMAIN03 0000000000000000 PEMAIN03 +0000000000000000 l d NRV2E 0000000000000000 NRV2E +0000000000000000 l d PECTTPOS 0000000000000000 PECTTPOS +0000000000000000 l d PECTTNUL 0000000000000000 PECTTNUL +0000000000000000 l d ctok32.00 0000000000000000 ctok32.00 +0000000000000000 l d PEIMPORT 0000000000000000 PEIMPORT +0000000000000000 l d PEIBYORD 0000000000000000 PEIBYORD +0000000000000000 l d PEK32ORD 0000000000000000 PEK32ORD +0000000000000000 l d PEIMORD1 0000000000000000 PEIMORD1 +0000000000000000 l d PEIMPOR2 0000000000000000 PEIMPOR2 +0000000000000000 l d PEIERDLL 0000000000000000 PEIERDLL +0000000000000000 l d PEIEREXE 0000000000000000 PEIEREXE +0000000000000000 l d PEIMDONE 0000000000000000 PEIMDONE +0000000000000000 l d PERELOC1 0000000000000000 PERELOC1 +0000000000000000 l d PERELOC2 0000000000000000 PERELOC2 +0000000000000000 l d PERELOC3 0000000000000000 PERELOC3 +0000000000000000 l d PERLOHI0 0000000000000000 PERLOHI0 +0000000000000000 l d PERELLO0 0000000000000000 PERELLO0 +0000000000000000 l d PERELHI0 0000000000000000 PERELHI0 +0000000000000000 l d PEDEPHAK 0000000000000000 PEDEPHAK +0000000000000000 l d PETLSC 0000000000000000 PETLSC +0000000000000000 l d PEMAIN20 0000000000000000 PEMAIN20 +0000000000000000 l d CLEARSTACK 0000000000000000 CLEARSTACK +0000000000000000 l d PERETURN 0000000000000000 PERETURN +0000000000000000 l d PEDOJUMP 0000000000000000 PEDOJUMP +0000000000000000 l d UPX1HEAD 0000000000000000 UPX1HEAD +0000000000000000 *UND* 0000000000000000 start_of_compressed +0000000000000000 *UND* 0000000000000000 start_of_uncompressed +0000000000000000 *UND* 0000000000000000 icon_offset +0000000000000000 *UND* 0000000000000000 icon_delta +0000000000000000 *UND* 0000000000000000 tls_address +0000000000000000 *UND* 0000000000000000 tls_value +0000000000000000 *UND* 0000000000000000 filter_buffer_start +0000000000000000 *UND* 0000000000000000 filter_length +0000000000000000 *UND* 0000000000000000 compressed_imports +0000000000000000 *UND* 0000000000000000 start_of_imports +0000000000000000 *UND* 0000000000000000 LoadLibraryA +0000000000000000 *UND* 0000000000000000 kernel32_ordinals +0000000000000000 *UND* 0000000000000000 GetProcAddress +0000000000000000 *UND* 0000000000000000 ExitProcess +0000000000000000 *UND* 0000000000000000 start_of_relocs +0000000000000000 *UND* 0000000000000000 VirtualProtect +0000000000000000 *UND* 0000000000000000 vp_base +0000000000000000 *UND* 0000000000000000 vp_size +0000000000000000 *UND* 0000000000000000 swri +0000000000000000 *UND* 0000000000000000 tls_module_base +0000000000000000 *UND* 0000000000000000 original_entry +0000000000000000 *UND* 0000000000000000 tls_callbacks_ptr + +RELOCATION RECORDS FOR [PEISDLL1]: +OFFSET TYPE VALUE +0000000000000005 R_X86_64_PC32 PEMAIN21+0xfffffffffffffffc + +RELOCATION RECORDS FOR [PEMAIN01]: +OFFSET TYPE VALUE +0000000000000006 R_X86_64_64 start_of_compressed+0x8000000000000000 +0000000000000011 R_X86_64_32S start_of_uncompressed + +RELOCATION RECORDS FOR [PEICONS1]: +OFFSET TYPE VALUE +0000000000000003 R_X86_64_32S icon_offset + +RELOCATION RECORDS FOR [PEICONS2]: +OFFSET TYPE VALUE +0000000000000003 R_X86_64_32S icon_offset +0000000000000007 R_X86_64_16 icon_delta+0x0000000000008000 + +RELOCATION RECORDS FOR [PETLSHAK]: +OFFSET TYPE VALUE +0000000000000002 R_X86_64_32S tls_address +0000000000000006 R_X86_64_32 tls_value+0x0000000080000000 + +RELOCATION RECORDS FOR [NRV2E]: +OFFSET TYPE VALUE +00000000000000a5 R_X86_64_PC32 NRV_HEAD+0x000000000000001b +0000000000000052 R_X86_64_PC32 PEMAIN10+0xfffffffffffffffc + +RELOCATION RECORDS FOR [PECTTPOS]: +OFFSET TYPE VALUE +0000000000000003 R_X86_64_32S filter_buffer_start + +RELOCATION RECORDS FOR [ctok32.00]: +OFFSET TYPE VALUE +0000000000000001 R_X86_64_32 filter_length + +RELOCATION RECORDS FOR [PEIMPORT]: +OFFSET TYPE VALUE +0000000000000003 R_X86_64_32S compressed_imports +000000000000000c R_X86_64_PC8 imports_done +0000000000000014 R_X86_64_32S start_of_imports +0000000000000025 R_X86_64_32S LoadLibraryA + +RELOCATION RECORDS FOR [PEIBYORD]: +OFFSET TYPE VALUE +0000000000000001 R_X86_64_PC8 byname + +RELOCATION RECORDS FOR [PEK32ORD]: +OFFSET TYPE VALUE +000000000000000c R_X86_64_32S kernel32_ordinals +0000000000000011 R_X86_64_PC8 next_imp + +RELOCATION RECORDS FOR [PEIMORD1]: +OFFSET TYPE VALUE +0000000000000009 R_X86_64_PC8 first_imp + +RELOCATION RECORDS FOR [PEIMPOR2]: +OFFSET TYPE VALUE +0000000000000013 R_X86_64_32S GetProcAddress +0000000000000028 R_X86_64_PC8 next_func + +RELOCATION RECORDS FOR [PEIEREXE]: +OFFSET TYPE VALUE +0000000000000006 R_X86_64_32S ExitProcess + +RELOCATION RECORDS FOR [PERELOC1]: +OFFSET TYPE VALUE +0000000000000003 R_X86_64_32S start_of_relocs + +RELOCATION RECORDS FOR [PEDEPHAK]: +OFFSET TYPE VALUE +0000000000000003 R_X86_64_32S VirtualProtect +000000000000000a R_X86_64_32S vp_base +000000000000000f R_X86_64_32 vp_size+0x0000000080000000 +000000000000002c R_X86_64_32S swri + +RELOCATION RECORDS FOR [PETLSC]: +OFFSET TYPE VALUE +0000000000000003 R_X86_64_32S tls_module_base +000000000000000a R_X86_64_32S PETLSC2+0x0000000000000001 + +RELOCATION RECORDS FOR [PEDOJUMP]: +OFFSET TYPE VALUE +0000000000000001 R_X86_64_PC32 original_entry+0xfffffffffffffffc + +RELOCATION RECORDS FOR [PETLSC2]: +OFFSET TYPE VALUE +0000000000000005 R_X86_64_64 tls_callbacks_ptr+0x8000000000000000