diff --git a/src/p_armpe.cpp b/src/p_armpe.cpp index 2c40d84e..718a499d 100644 --- a/src/p_armpe.cpp +++ b/src/p_armpe.cpp @@ -39,65 +39,6 @@ static const static const #include "stub/arm.v4t-wince.pe.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, 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) - - /************************************************************************* // **************************************************************************/ @@ -109,8 +50,7 @@ PackArmPe::PackArmPe(InputFile *f) : super(f) PackArmPe::~PackArmPe() -{ -} +{} const int *PackArmPe::getCompressionMethods(int method, int level) const @@ -148,6 +88,10 @@ Linker* PackArmPe::newLinker() const // import handling **************************************************************************/ +void PackArmPe::processImports(unsigned myimport, unsigned iat_off) // pass 2 +{ + PeFile::processImports(myimport, iat_off); + __packed_struct(import_desc) LE32 oft; // orig first thunk char _[8]; @@ -155,293 +99,23 @@ __packed_struct(import_desc) LE32 iat; // import address table __packed_struct_end() -void PackArmPe::processImports(unsigned myimport, unsigned iat_off) // pass 2 -{ COMPILE_TIME_ASSERT(sizeof(import_desc) == 20); // adjust import data for (import_desc *im = (import_desc*) oimpdlls; im->dllname; im++) { - if (im->dllname < myimport) - im->dllname += myimport; - LE32 *p = (LE32*) (oimpdlls + im->iat); - im->iat += myimport; im->oft = im->iat; - - while (*p) - if ((*p++ & 0x80000000) == 0) // import by name? - p[-1] += myimport; - im->iat = im == (import_desc*) oimpdlls ? iat_off : iat_off + 12; } } -unsigned PackArmPe::processImports() // pass 1 +void PackArmPe::addKernelImports() { - 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; - 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 = (LE32*) (ibuf + (im->oft ? im->oft : im->iat)); - 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; - - for (IPTR_I(LE32, tarr, dlls[ic].lookupt); *tarr; tarr += 1) - { - if (*tarr & 0x80000000) - { - importbyordinal = true; - soimport += 2; // ordinal num: 2 bytes - dlls[ic].ordinal = *tarr & 0xffff; - //if (dlls[ic].isk32) - // kernel32ordinal = true,k32o++; - } - else - { - IPTR_I(const upx_byte, n, ibuf + *tarr + 2); - unsigned len = strlen(n); - soimport += len + 1; - if (dlls[ic].shname == NULL || len < strlen (dlls[ic].shname)) - dlls[ic].shname = n; - } - 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 0 && ENABLE_THIS_AND_UNCOMPRESSION_WILL_BREAK - 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 & 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(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; + addKernelImport("COREDLL.DLL", "LoadLibraryW"); + addKernelImport("COREDLL.DLL", "GetProcAddressA"); + addKernelImport("COREDLL.DLL", "CacheSync"); } - void PackArmPe::processTls(Interval *) // pass 1 { if ((sotls = ALIGN_UP(IDSIZE(PEDIR_TLS),4u)) == 0) @@ -509,260 +183,29 @@ void PackArmPe::buildLoader(const Filter *ft) addLoader("IDENTSTR,UPX1HEAD", NULL); } - -void PackArmPe::pack(OutputFile *fo) +bool PackArmPe::handleForceOption() { - // 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 - if (!opt->force && ( - (ih.cpu != 0x1c0 && ih.cpu != 0x1c2) + return (ih.cpu != 0x1c0 && ih.cpu != 0x1c2) || (ih.opthdrsize != 0xe0) || ((ih.flags & EXECUTABLE) == 0) - || (ih.subsystem != 9) || (ih.entry == 0 /*&& !isdll*/) || (ih.ddirsentries != 16) // || IDSIZE(PEDIR_EXCEPTION) // is this used on arm? // || IDSIZE(PEDIR_COPYRIGHT) - )) - throwCantPack("unexpected value in PE header (try --force)"); - - if (IDSIZE(PEDIR_SEC)) - IDSIZE(PEDIR_SEC) = IDADDR(PEDIR_SEC) = 0; - // throwCantPack("compressing certificate info is not supported"); - - if (IDSIZE(PEDIR_COMRT)) - throwCantPack(".NET files (win32/net) are not yet supported"); - - if (isdll) - opt->win32_pe.strip_relocs = false; - else if (opt->win32_pe.strip_relocs < 0) - opt->win32_pe.strip_relocs = (ih.imagebase >= 0x10000); - if (opt->win32_pe.strip_relocs) - { - if (ih.imagebase < 0x10000) - throwCantPack("--strip-relocs is not allowed when imagebase < 0x10000"); - else - ih.flags |= RELOCS_STRIPPED; - } - - 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 (!opt->force && ih.subsystem == 1) - throwCantPack("subsystem 'native' is not supported (try --force)"); - if (ih.filealign < 0x200) - throwCantPack("filealign < 0x200 is not yet supported"); - - handleStub(fi,fo,pe_offset); - const unsigned usize = ih.imagesize; - const unsigned xtrasize = UPX_MAX(ih.datasize, 65536u) + IDSIZE(PEDIR_IMPORT) + IDSIZE(PEDIR_BOUNDIM) + IDSIZE(PEDIR_IAT) + IDSIZE(PEDIR_DELAYIMP) + IDSIZE(PEDIR_RELOC); - ibuf.alloc(usize + xtrasize); - - // BOUND IMPORT support. FIXME: is this ok? - fi->seek(0,SEEK_SET); - fi->readx(ibuf,isection[0].rawdataptr); - - Interval holes(ibuf); - - unsigned ic,jc,overlaystart = 0; - ibuf.clear(0, usize); - for (ic = jc = 0; ic < objs; ic++) - { - if (isection[ic].rawdataptr && overlaystart < isection[ic].rawdataptr + isection[ic].size) - overlaystart = ALIGN_UP(isection[ic].rawdataptr + isection[ic].size,ih.filealign); - if (isection[ic].vsize == 0) - isection[ic].vsize = isection[ic].size; - if ((isection[ic].flags & PEFL_BSS) || isection[ic].rawdataptr == 0 - || (isection[ic].flags & PEFL_INFO)) - { - holes.add(isection[ic].vaddr,isection[ic].vsize); - continue; - } - if (isection[ic].vaddr + isection[ic].size > usize) - throwCantPack("section size problem"); - if (((isection[ic].flags & (PEFL_WRITE|PEFL_SHARED)) - == (PEFL_WRITE|PEFL_SHARED))) - if (!opt->force) - throwCantPack("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; - } - - // check for NeoLite - if (find(ibuf + ih.entry, 64+7, "NeoLite", 7) >= 0) - throwCantPack("file is already compressed with another packer"); - - unsigned overlay = file_size - stripDebug(overlaystart); - if (overlay >= (unsigned) file_size) - { -#if 0 - if (overlay < file_size + ih.filealign) - overlay = 0; - else if (!opt->force) - throwNotCompressible("overlay problem (try --force)"); -#endif - overlay = 0; - } - checkOverlay(overlay); - - Resource res; - Interval tlsiv(ibuf); - Export xport((char*)(unsigned char*)ibuf); - - const unsigned dllstrings = processImports(); - processTls(&tlsiv); // call before processRelocs!! - processResources(&res); - processExports(&xport); - processRelocs(); - - //OutputFile::dump("x1", ibuf, usize); - - // some checks for broken linkers - disable filter if necessary - bool allow_filter = true; - if (ih.codebase == ih.database - || ih.codebase + ih.codesize > ih.imagesize - || (isection[virta2objnum(ih.codebase,isection,objs)].flags & PEFL_CODE) == 0) - allow_filter = false; - - const unsigned oam1 = ih.objectalign - 1; - - // FIXME: disabled: the uncompressor would not allocate enough memory - //objs = tryremove(IDADDR(PEDIR_RELOC),objs); - - // FIXME: if the last object has a bss then this won't work - // newvsize = (isection[objs-1].vaddr + isection[objs-1].size + oam1) &~ oam1; - // temporary solution: - unsigned newvsize = (isection[objs-1].vaddr + isection[objs-1].vsize + oam1) &~ oam1; - - //fprintf(stderr,"newvsize=%x objs=%d\n",newvsize,objs); - if (newvsize + soimport + sorelocs > ibuf.getSize()) - throwInternalError("buffer too small 2"); - memcpy(ibuf+newvsize,oimport,soimport); - memcpy(ibuf+newvsize+soimport,orelocs,sorelocs); - - cimports = newvsize - rvamin; // rva of preprocessed imports - crelocs = cimports + soimport; // rva of preprocessed fixups - - ph.u_len = newvsize + soimport + sorelocs; - - // some extra data for uncompression support - unsigned s = 0; - upx_byte * const p1 = ibuf + ph.u_len; - memcpy(p1 + s,&ih,sizeof (ih)); - s += sizeof (ih); - memcpy(p1 + s,isection,ih.objects * sizeof(*isection)); - s += ih.objects * sizeof(*isection); - if (soimport) - { - set_le32(p1 + s,cimports); - set_le32(p1 + s + 4,dllstrings); - s += 8; - } - if (sorelocs) - { - set_le32(p1 + s,crelocs); - p1[s + 4] = (unsigned char) (big_relocs & 6); - s += 5; - } - if (soresources) - { - set_le16(p1 + s,icondir_count); - s += 2; - } - // end of extra data - set_le32(p1 + s,ptr_diff(p1,ibuf) - rvamin); - s += 4; - ph.u_len += s; - obuf.allocForCompression(ph.u_len); - - // prepare packheader - ph.u_len -= rvamin; - // prepare filter - Filter ft(ph.level); - ft.buf_len = ih.codesize; - ft.addvalue = ih.codebase - rvamin; - // compress - int 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; - } + ; +} +void PackArmPe::callCompressWithFilters(Filter &ft, int filter_strategy, unsigned ih_codebase) +{ // limit stack size needed for runtime decompression upx_compress_config_t cconf; cconf.reset(); cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28 KiB stack compressWithFilters(&ft, 2048, &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; - */ + ih_codebase, rvamin, 0, NULL, 0); +} - const unsigned lsize = getLoaderSize(); - - int identsize = 0; - const unsigned codesize = getLoaderSection("IDENTSTR",&identsize); - assert(identsize > 0); - getLoaderSection("UPX1HEAD",(int*)&ic); - identsize += ic; - - pe_section_t osection[4]; - // section 0 : bss - // 1 : [ident + header] + packed_data + unpacker + tls - // 2 : not compressed data - // 3 : resource data -- wince 5 needs a new section for this - - // 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; - const unsigned s1addr = (newvsize - (ic + c_len) + oam1) &~ oam1; - - const unsigned ncsection = (s1addr + s1size + oam1) &~ oam1; - const unsigned upxsection = s1addr + ic + c_len; - - Reloc rel(1024); // new relocations are put here +void PackArmPe::addNewRelocations(Reloc &rel, unsigned upxsection) +{ static const char* symbols_to_relocate[] = { "ONAM", "BIMP", "BREL", "FIBE", "FIBS", "ENTR", "DST0", "SRC0" }; @@ -772,65 +215,16 @@ void PackArmPe::pack(OutputFile *fo) if (off != 0xdeaddead) rel.add(off + upxsection, 3); } +} - // new PE header - memcpy(&oh,&ih,sizeof(oh)); - oh.filealign = 0x200; // identsplit depends on this - memset(osection,0,sizeof(osection)); - - oh.entry = upxsection; - oh.objects = 4; - oh.chksum = 0; - - // fill the data directory - ODADDR(PEDIR_DEBUG) = 0; - ODSIZE(PEDIR_DEBUG) = 0; - ODADDR(PEDIR_IAT) = 0; - ODSIZE(PEDIR_IAT) = 0; - ODADDR(PEDIR_BOUNDIM) = 0; - ODSIZE(PEDIR_BOUNDIM) = 0; - - - // tls is put into section 1 - ic = s1addr + s1size - sotls; - super::processTls(&rel,&tlsiv,ic); - ODADDR(PEDIR_TLS) = sotls ? ic : 0; - ODSIZE(PEDIR_TLS) = sotls ? 0x18 : 0; - ic += sotls; - - // these are put into section 2 - - ic = ncsection; - - // wince wants relocation data at the beginning of a section - processRelocs(&rel); - ODADDR(PEDIR_RELOC) = soxrelocs ? ic : 0; - ODSIZE(PEDIR_RELOC) = soxrelocs; - ic += soxrelocs; - - processImports(ic, linker->getSymbolOffset("IATT") + upxsection); - 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; - - ic = (ic + oam1) &~ oam1; - const unsigned res_start = ic; - if (soresources) - processResources(&res,ic); - ODADDR(PEDIR_RESOURCE) = soresources ? ic : 0; - ODSIZE(PEDIR_RESOURCE) = soresources; - ic += soresources; +unsigned PackArmPe::getProcessImportParam(unsigned upxsection) +{ + return linker->getSymbolOffset("IATT") + upxsection; +} +void PackArmPe::defineSymbols(unsigned ncsection, unsigned, unsigned, + unsigned ic, Reloc &, unsigned s1addr) +{ const unsigned onam = ncsection + soxrelocs + ih.imagebase; linker->defineSymbol("start_of_dll_names", onam); linker->defineSymbol("start_of_imports", ih.imagebase + rvamin + cimports); @@ -841,311 +235,23 @@ void PackArmPe::pack(OutputFile *fo) linker->defineSymbol("uncompressed_length", ph.u_len); linker->defineSymbol("start_of_uncompressed", ih.imagebase + rvamin); linker->defineSymbol("compressed_length", ph.c_len); - linker->defineSymbol("start_of_compressed", ih.imagebase + s1addr + identsize - identsplit); + linker->defineSymbol("start_of_compressed", ih.imagebase + s1addr + ic); defineDecompressorSymbols(); - relocateLoader(); +} - MemBuffer loader(lsize); - memcpy(loader, getLoader(), lsize); - patchPackHeader(loader, lsize); - - // this is computed here, because soxrelocs changes some lines above - const unsigned ncsize = soxrelocs + soimpdlls + soexport; - const unsigned fam1 = oh.filealign - 1; - - // fill the sections - strcpy(osection[0].name,"UPX0"); - strcpy(osection[1].name,"UPX1"); - strcpy(osection[2].name, "UPX2"); - strcpy(osection[3].name, ".rsrc"); - - osection[0].vaddr = rvamin; - osection[1].vaddr = s1addr; - osection[2].vaddr = ncsection; - osection[3].vaddr = res_start; - - osection[0].size = 0; - osection[1].size = (s1size + fam1) &~ fam1; - osection[2].size = (ncsize + fam1) &~ fam1; - osection[3].size = (soresources + fam1) &~ fam1; - - osection[0].vsize = osection[1].vaddr - osection[0].vaddr; - //osection[1].vsize = (osection[1].size + oam1) &~ oam1; - //osection[2].vsize = (osection[2].size + oam1) &~ oam1; - osection[1].vsize = osection[1].size; - osection[2].vsize = osection[2].size; - osection[3].vsize = osection[3].size; - - osection[0].rawdataptr = 0; - osection[1].rawdataptr = (pe_offset + sizeof(oh) + sizeof(osection) + fam1) &~ fam1; - osection[2].rawdataptr = osection[1].rawdataptr + osection[1].size; - osection[3].rawdataptr = osection[2].rawdataptr + osection[2].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_READ); - osection[3].flags = (unsigned) (PEFL_DATA|PEFL_READ); - - oh.imagesize = (osection[3].vaddr + osection[3].vsize + oam1) &~ oam1; - oh.bsssize = osection[0].vsize; - oh.datasize = osection[2].vsize + osection[3].vsize; +void PackArmPe::setOhDataBase(const pe_section_t *osection) +{ oh.database = osection[2].vaddr; - oh.codesize = osection[1].vsize; - oh.codebase = osection[1].vaddr; +} + +void PackArmPe::setOhHeaderSize(const pe_section_t *osection) +{ oh.headersize = osection[1].rawdataptr; - 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]"); - - if (soresources == 0) - { - oh.objects = 3; - memset(&osection[3], 0, sizeof(osection[3])); - } - // write loader + compressed file - fo->write(&oh,sizeof(oh)); - fo->write(osection,sizeof(osection)); - // some alignment - if (identsplit == identsize) - { - unsigned n = osection[1].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); - if ((ic = fo->getBytesWritten() & fam1) != 0) - fo->write(ibuf,oh.filealign - ic); - fo->write(oxrelocs,soxrelocs); - fo->write(oimpdlls,soimpdlls); - fo->write(oexport,soexport); - - if ((ic = fo->getBytesWritten() & fam1) != 0) - fo->write(ibuf,oh.filealign - ic); - - fo->write(oresources,soresources); - if ((ic = fo->getBytesWritten() & fam1) != 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); -#endif - - // verify - verifyOverlappingDecompression(); - - // copy the overlay - copyOverlay(fo, overlay, &obuf); - - // finally check the compression ratio - if (!checkFinalCompressionRatio(fo)) - throwNotCompressible(); } - -/************************************************************************* -// unpack -**************************************************************************/ - -int PackArmPe::canUnpack() +void PackArmPe::pack(OutputFile *fo) { - if (!readFileHeader() || (ih.cpu != 0x1c0 && ih.cpu != 0x1c2)) - 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 || ih.objects == 4) && - (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)); - - // FIXME this is for x86 - 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 PackArmPe::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->oft = 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); + super::pack0(fo, 1U << 9, 0x10000, true); } /* diff --git a/src/p_armpe.h b/src/p_armpe.h index 6df2e3e6..4b535c39 100644 --- a/src/p_armpe.h +++ b/src/p_armpe.h @@ -34,9 +34,9 @@ // arm/pe **************************************************************************/ -class PackArmPe : public PeFile +class PackArmPe : public PeFile32 { - typedef PeFile super; + typedef PeFile32 super; public: PackArmPe(InputFile *f); @@ -47,18 +47,26 @@ public: virtual const int *getCompressionMethods(int method, int level) const; virtual const int *getFilters() const; + virtual bool handleForceOption(); + virtual void callCompressWithFilters(Filter &, int filter_strategy, + unsigned ih_codebase); + virtual void defineSymbols(unsigned ncsection, unsigned upxsection, + unsigned sizeof_oh, unsigned isize_isplit, + Reloc &rel, unsigned s1addr); + virtual void addNewRelocations(Reloc &, unsigned upxsection); + virtual unsigned getProcessImportParam(unsigned upxsection); + virtual void setOhDataBase(const pe_section_t *osection); + virtual void setOhHeaderSize(const pe_section_t *osection); virtual void pack(OutputFile *fo); virtual bool canPack(); - virtual int canUnpack(); protected: 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 addKernelImports(); virtual void processTls(Interval *); diff --git a/src/p_w32pe.cpp b/src/p_w32pe.cpp index 8df821b9..00243199 100644 --- a/src/p_w32pe.cpp +++ b/src/p_w32pe.cpp @@ -37,100 +37,16 @@ static const #include "stub/i386-win32.pe.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 1 -//static -unsigned my_strlen(const char *s) -{ - size_t l = strlen((const char*)s); assert((unsigned) l == l); return (unsigned) l; -} -static unsigned my_strlen(const unsigned char *s) -{ - size_t l = strlen((const char*)s); assert((unsigned) l == l); return (unsigned) l; -} -#undef strlen -#define strlen my_strlen -#endif - - -#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) - - /************************************************************************* // **************************************************************************/ PackW32Pe::PackW32Pe(InputFile *f) : super(f) -{ - oloadconf = NULL; - soloadconf = 0; - isrtm = false; - use_dep_hack = true; - use_clear_dirty_stack = true; - use_tls_callbacks = false; -} +{} PackW32Pe::~PackW32Pe() -{ - delete [] oloadconf; -} +{} const int *PackW32Pe::getCompressionMethods(int method, int level) const @@ -169,490 +85,6 @@ int PackW32Pe::readFileHeader() return super::readFileHeader(); } -//new: processTLS moved to p_w32pe.cpp for TLS callback support -/************************************************************************* -// 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 4u // alignment of tls callbacks - -__packed_struct(tls) - LE32 datastart; // VA tls init data start - LE32 dataend; // VA tls init data end - LE32 tlsindex; // VA tls index - LE32 callbacks; // VA tls callbacks - char _[8]; // zero init, characteristics -__packed_struct_end() - -void PackW32Pe::processTls(Interval *iv) // pass 1 -{ - COMPILE_TIME_ASSERT(sizeof(tls) == 24) - 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 v = get_le32(ibuf + tlsp->callbacks - ih.imagebase); - - //NEW: TLS callback support - Stefan Widmann - if(v != 0) - { - //count number of callbacks, just for information string - Stefan Widmann - unsigned num_callbacks = 0; - unsigned callback_offset = 0; - while(get_le32(ibuf + tlsp->callbacks - ih.imagebase + callback_offset)) - { - //increment number of callbacks - num_callbacks++; - //increment pointer by 4 - callback_offset += 4; - } - 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 DWORDS at the end of the TLS - // ... and those dwords should be correctly aligned - if (use_tls_callbacks) - sotls = ALIGN_UP(sotls, TLS_CB_ALIGNMENT) + 8; - - // 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; - //NEW: subtract two dwords if TLS callbacks are used - Stefan Widmann - info("TLS: %u bytes tls data and %u relocations added",sotls - (unsigned) sizeof(tls) - (use_tls_callbacks ? 8 : 0),iv->ivnum); - - // makes sure tls index is zero after decompression - if (tlsindex && tlsindex < ih.imagesize) - set_le32(ibuf + tlsindex, 0); -} - -void PackW32Pe::processTls(Reloc *rel,const Interval *iv,unsigned newaddr) // pass 2 -{ - if (sotls == 0) - return; - // add new relocation entries - unsigned ic; - //NEW: if TLS callbacks are used, relocate the VA of the callback chain, too - Stefan Widmann - for (ic = 0; ic < (use_tls_callbacks ? 16u : 12u); ic += 4) - rel->add(newaddr + ic,3); - - tls * const tlsp = (tls*) otls; - // now the relocation entries in the tls data area - for (ic = 0; ic < iv->ivnum; ic += 4) - { - void *p = otls + iv->ivarr[ic].start - (tlsp->datastart - ih.imagebase) + sizeof(tls); - unsigned kc = get_le32(p); - if (kc < tlsp->dataend && kc >= tlsp->datastart) - { - kc += newaddr + sizeof(tls) - tlsp->datastart; - set_le32(p,kc + ih.imagebase); - rel->add(kc,iv->ivarr[ic].len); - } - else - rel->add(kc - ih.imagebase,iv->ivarr[ic].len); - } - - const unsigned tls_data_size = tlsp->dataend - tlsp->datastart; - tlsp->datastart = newaddr + sizeof(tls) + ih.imagebase; - tlsp->dataend = tlsp->datastart + tls_data_size; - - //NEW: if we have TLS callbacks to handle, we create a pointer to the new callback chain - Stefan Widmann - tlsp->callbacks = (use_tls_callbacks ? newaddr + sotls + ih.imagebase - 8 : 0); - - if(use_tls_callbacks) - { - //set handler offset - set_le32(otls + sotls - 8, tls_handler_offset + ih.imagebase); - //add relocation for TLS handler offset - rel->add(newaddr + sotls - 8, 3); - } -} - -/************************************************************************* -// import handling -**************************************************************************/ - -__packed_struct(import_desc) - LE32 oft; // orig first thunk - char _[8]; - LE32 dllname; - LE32 iat; // import address table -__packed_struct_end() - -void PackW32Pe::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; - LE32 *p = (LE32*) (oimpdlls + im->iat); - im->iat += myimport; - - while (*p) - if ((*p++ & 0x80000000) == 0) // import by name? - p[-1] += myimport; - } -} - -unsigned PackW32Pe::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; - LE32 *lookupt; - 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 = (LE32*) (ibuf + (im->oft ? im->oft : im->iat)); - 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; - - for (IPTR_I(LE32, tarr, dlls[ic].lookupt); *tarr; tarr += 1) - { - if (*tarr & 0x80000000) - { - importbyordinal = true; - soimport += 2; // ordinal num: 2 bytes - dlls[ic].ordinal = *tarr & 0xffff; - if (dlls[ic].isk32) - kernel32ordinal = true,k32o++; - } - else - { - IPTR_I(const upx_byte, n, ibuf + *tarr + 2); - unsigned len = strlen(n); - soimport += len + 1; - if (dlls[ic].shname == NULL || len < strlen (dlls[ic].shname)) - dlls[ic].shname = n; - } - 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 + 6 + 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, 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 (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 0 && ENABLE_THIS_AND_UNCOMPRESSION_WILL_BREAK - 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 & 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(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; -} - - -/************************************************************************* -// Load Configuration handling -**************************************************************************/ - -void PackW32Pe::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 PackW32Pe::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 **************************************************************************/ @@ -730,12 +162,6 @@ void PackW32Pe::buildLoader(const Filter *ft) if (use_clear_dirty_stack) addLoader("CLEARSTACK", NULL); addLoader("PEMAIN21", NULL); -#if 0 - addLoader(ih.entry ? "PEDOJUMP" : "PERETURN", - "IDENTSTR,UPX1HEAD", - NULL - ); -#endif //NEW: last loader sections split up to insert TLS callback handler - Stefan Widmann addLoader(ih.entry ? "PEDOJUMP" : "PERETURN", NULL); @@ -747,27 +173,9 @@ void PackW32Pe::buildLoader(const Filter *ft) } - -void PackW32Pe::pack(OutputFile *fo) +bool PackW32Pe::handleForceOption() { - // 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 - //NEW: subsystem check moved to switch ... case below, check of COFF magic, 32 bit machine flag check - Stefan Widmann - if (!opt->force && ( - (ih.cpu < 0x14c || ih.cpu > 0x150) + return (ih.cpu < 0x14c || ih.cpu > 0x150) || (ih.opthdrsize != 0xe0) || ((ih.flags & EXECUTABLE) == 0) || ((ih.flags & BITS_32_MACHINE) == 0) //NEW: 32 bit machine flag must be set - Stefan Widmann @@ -776,308 +184,13 @@ void PackW32Pe::pack(OutputFile *fo) || (ih.ddirsentries != 16) || IDSIZE(PEDIR_EXCEPTION) // is this used on i386? // || IDSIZE(PEDIR_COPYRIGHT) - )) - throwCantPack("unexpected value in PE header (try --force)"); + ; +} - switch(ih.subsystem) //let's take a closer look at the subsystem - { - case 1: //NATIVE - { - if(!opt->force) - { - throwCantPack("win32/native applications are not yet supported"); - } - break; - } - case 2: //GUI - { - //fine, continue - break; - } - case 3: //CONSOLE - { - //fine, continue - break; - } - case 5: //OS2 - { - throwCantPack("win32/os2 files are not yet supported"); - break; - } - case 7: //POSIX - do x32/posix files exist? - { - throwCantPack("win32/posix files are not yet supported"); - break; - } - case 9: //WINCE x86 files - { - 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 we ever see a XBOX file? - { - throwCantPack("PE32/xbox files are not yet supported"); - break; - } - case 16: //WINDOWS BOOT APPLICATION - { - throwCantPack("PE32/windowsbootapplication files are not yet supported"); - break; - } - default: //UNKNOWN SUBSYSTEM - { - throwCantPack("PE32/? unknown subsystem"); - break; - } - } - - //remove certificate directory entry - if (IDSIZE(PEDIR_SEC)) - IDSIZE(PEDIR_SEC) = IDADDR(PEDIR_SEC) = 0; - - //check CLR Runtime Header directory entry - if (IDSIZE(PEDIR_COMRT)) - throwCantPack(".NET files (win32/.net) are not yet supported"); - - //NEW: disable reloc stripping if ASLR is enabled - if(ih.dllflags & IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE) - opt->win32_pe.strip_relocs = false; - else if (isdll) //do never strip relocations from DLLs - opt->win32_pe.strip_relocs = false; - else if (opt->win32_pe.strip_relocs < 0) - opt->win32_pe.strip_relocs = (ih.imagebase >= 0x400000); - if (opt->win32_pe.strip_relocs) - { - if (ih.imagebase < 0x400000) - throwCantPack("--strip-relocs is not allowed when imagebase < 0x400000"); - else - ih.flags |= RELOCS_STRIPPED; - } - - if (memcmp(isection[0].name,"UPX",3) == 0) - throwAlreadyPackedByUPX(); - if (!opt->force && IDSIZE(15)) - 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; - } - - // check for NeoLite - if (find(ibuf + ih.entry, 64+7, "NeoLite", 7) >= 0) - throwCantPack("file is already compressed with another packer"); - - unsigned overlay = file_size - stripDebug(overlaystart); - if (overlay >= (unsigned) file_size) - { -#if 0 - if (overlay < file_size + ih.filealign) - overlay = 0; - else if (!opt->force) - throwNotCompressible("overlay problem (try --force)"); -#endif - overlay = 0; - } - checkOverlay(overlay); - - Resource res; - Interval tlsiv(ibuf); - 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 = true; - if (ih.codebase == ih.database - || ih.codebase + ih.codesize > ih.imagesize - || (isection[virta2objnum(ih.codebase,isection,objs)].flags & PEFL_CODE) == 0) - allow_filter = false; - - const unsigned oam1 = ih.objectalign - 1; - - // FIXME: disabled: the uncompressor would not allocate enough memory - //objs = tryremove(IDADDR(PEDIR_RELOC),objs); - - // FIXME: if the last object has a bss then this won't work - // newvsize = (isection[objs-1].vaddr + isection[objs-1].size + oam1) &~ oam1; - // temporary solution: - unsigned newvsize = (isection[objs-1].vaddr + isection[objs-1].vsize + oam1) &~ oam1; - - //fprintf(stderr,"newvsize=%x objs=%d\n",newvsize,objs); - if (newvsize + soimport + sorelocs > ibuf.getSize()) - throwInternalError("buffer too small 2"); - memcpy(ibuf+newvsize,oimport,soimport); - memcpy(ibuf+newvsize+soimport,orelocs,sorelocs); - - cimports = newvsize - rvamin; // rva of preprocessed imports - crelocs = cimports + soimport; // rva of preprocessed fixups - - ph.u_len = newvsize + soimport + sorelocs; - - // some extra data for uncompression support - unsigned s = 0; - upx_byte * const p1 = ibuf + ph.u_len; - memcpy(p1 + s,&ih,sizeof (ih)); - s += sizeof (ih); - memcpy(p1 + s,isection,ih.objects * sizeof(*isection)); - s += ih.objects * sizeof(*isection); - if (soimport) - { - set_le32(p1 + s,cimports); - set_le32(p1 + s + 4,dllstrings); - s += 8; - } - if (sorelocs) - { - set_le32(p1 + s,crelocs); - p1[s + 4] = (unsigned char) (big_relocs & 6); - s += 5; - } - if (soresources) - { - set_le16(p1 + s,icondir_count); - s += 2; - } - // end of extra data - set_le32(p1 + s,ptr_diff(p1,ibuf) - rvamin); - s += 4; - ph.u_len += s; - obuf.allocForCompression(ph.u_len); - - // prepare packheader - ph.u_len -= rvamin; - // prepare filter - Filter ft(ph.level); - ft.buf_len = ih.codesize; - ft.addvalue = ih.codebase - rvamin; - // compress - int 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; +void PackW32Pe::defineSymbols(unsigned ncsection, unsigned upxsection, + unsigned sizeof_oh, unsigned ic, + Reloc &, unsigned s1addr) +{ const unsigned myimport = ncsection + soresources - rvamin; // patch loader @@ -1100,7 +213,7 @@ void PackW32Pe::pack(OutputFile *fo) // 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; + 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 @@ -1109,23 +222,23 @@ void PackW32Pe::pack(OutputFile *fo) linker->defineSymbol("vp_size", ((addr & 0xfff) + 0x28 >= 0x1000) ? 0x2000 : 0x1000); // 2 pages or 1 page linker->defineSymbol("vp_base", addr &~ 0xfff); // page mask - linker->defineSymbol("VirtualProtect", myimport + get_le32(oimpdlls + 16) + 8); + linker->defineSymbol("VirtualProtect", -rvamin + + ilinkerGetAddress("kernel32.dll", "VirtualProtect")); } linker->defineSymbol("reloc_delt", 0u - (unsigned) ih.imagebase - rvamin); linker->defineSymbol("start_of_relocs", crelocs); - linker->defineSymbol("ExitProcess", myimport + get_le32(oimpdlls + 16) + 20); - linker->defineSymbol("GetProcAddress", myimport + get_le32(oimpdlls + 16) + 4); + if (!isdll) + linker->defineSymbol("ExitProcess", -rvamin + + ilinkerGetAddress("kernel32.dll", "ExitProcess")); + linker->defineSymbol("GetProcAddress", -rvamin + + ilinkerGetAddress("kernel32.dll", "GetProcAddress")); linker->defineSymbol("kernel32_ordinals", myimport); - linker->defineSymbol("LoadLibraryA", myimport + get_le32(oimpdlls + 16)); + linker->defineSymbol("LoadLibraryA", -rvamin + + ilinkerGetAddress("kernel32.dll", "LoadLibraryA")); linker->defineSymbol("start_of_imports", myimport); linker->defineSymbol("compressed_imports", cimports); -#if 0 - linker->defineSymbol("VirtualAlloc", myimport + get_le32(oimpdlls + 16) + 12); - linker->defineSymbol("VirtualFree", myimport + get_le32(oimpdlls + 16) + 16); -#endif defineDecompressorSymbols(); - defineFilterSymbols(&ft); linker->defineSymbol("filter_buffer_start", ih.codebase - rvamin); // in case of overlapping decompression, this hack is needed, @@ -1142,407 +255,43 @@ void PackW32Pe::pack(OutputFile *fo) 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) - { + if (use_tls_callbacks) + { //esi is ih.imagebase + rvamin linker->defineSymbol("tls_callbacks_ptr", tlscb_ptr); - //linker->defineSymbol("tls_callbacks_off", ic + sotls - 8 - rvamin); 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 +void PackW32Pe::addNewRelocations(Reloc &rel, unsigned) +{ rel.add(linker->getSymbolOffset("PEMAIN01") + 2, 3); - - // new PE header - memcpy(&oh,&ih,sizeof(oh)); - oh.filealign = 0x200; // identsplit depends on this - memset(osection,0,sizeof(osection)); - - oh.entry = upxsection; - oh.objects = 3; - oh.chksum = 0; - - // fill the data directory - ODADDR(PEDIR_DEBUG) = 0; - ODSIZE(PEDIR_DEBUG) = 0; - ODADDR(PEDIR_IAT) = 0; - ODSIZE(PEDIR_IAT) = 0; - ODADDR(PEDIR_BOUNDIM) = 0; - ODSIZE(PEDIR_BOUNDIM) = 0; - - // 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 + 4, 3); } +} - processTls(&rel,&tlsiv,ic); - ODADDR(PEDIR_TLS) = sotls ? ic : 0; - ODSIZE(PEDIR_TLS) = sotls ? 0x18 : 0; - 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; +void PackW32Pe::setOhDataBase(const pe_section_t *osection) +{ oh.database = osection[2].vaddr; - 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); - - // finally check the compression ratio - if (!checkFinalCompressionRatio(fo)) - throwNotCompressible(); } - -/************************************************************************* -// unpack -**************************************************************************/ - -int PackW32Pe::canUnpack() +void PackW32Pe::setOhHeaderSize(const pe_section_t *) { - if (!readFileHeader() || ih.cpu < 0x14c || ih.cpu > 0x150) - 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; + oh.headersize = rvamin; // FIXME } - -void PackW32Pe::rebuildImports(upx_byte *& extrainfo) +void PackW32Pe::pack(OutputFile *fo) { - 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); + super::pack0(fo, 0x0c, 0x400000, false); } -/* - extra info added to help uncompression: - - - - - optional \ - - opt / - - optional \ - - optional / - - optional - -*/ - - /* vi:ts=4:et */ diff --git a/src/p_w32pe.h b/src/p_w32pe.h index 3dc0bfbb..00887872 100644 --- a/src/p_w32pe.h +++ b/src/p_w32pe.h @@ -34,9 +34,9 @@ // w32/pe **************************************************************************/ -class PackW32Pe : public PeFile +class PackW32Pe : public PeFile32 { - typedef PeFile super; + typedef PeFile32 super; public: PackW32Pe(InputFile *f); @@ -47,36 +47,22 @@ public: virtual const int *getCompressionMethods(int method, int level) const; virtual const int *getFilters() const; + virtual bool handleForceOption(); + virtual void defineSymbols(unsigned ncsection, unsigned upxsection, + unsigned sizeof_oh, unsigned isize_isplit, + Reloc &rel, unsigned s1addr); + virtual void addNewRelocations(Reloc &, unsigned upxsection); + virtual void setOhDataBase(const pe_section_t *osection); + virtual void setOhHeaderSize(const pe_section_t *osection); 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 }; diff --git a/src/p_w64pep.cpp b/src/p_w64pep.cpp index 35e5450d..89f8c342 100644 --- a/src/p_w64pep.cpp +++ b/src/p_w64pep.cpp @@ -35,108 +35,23 @@ #include "file.h" #include "filter.h" #include "packer.h" -#include "pepfile.h" +#include "pefile.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() -{ - oimpdlls = NULL; // this is now a pointer to ImportLinker output - delete [] oloadconf; -} +{} const int *PackW64Pep::getCompressionMethods(int method, int level) const @@ -159,692 +74,6 @@ Linker* PackW64Pep::newLinker() const } -/************************************************************************* -// 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() - -/* - ImportLinker: 32 and 64 bit import table building. - Import entries (dll name + proc name/ordinal pairs) can be - added in arbitrary order. - - Internally it works by creating sections with special names, - and adding relocation entries between those sections. The special - names ensure that when the import table is built in the memory - from those sections, a correct table can be generated simply by - sorting the sections by name, and adding all of them to the output - in the sorted order. - */ - -class ImportLinker : public ElfLinkerAMD64 -{ - struct tstr : private ::noncopyable - { - char *s; - explicit tstr(char *str) : s(str) {} - ~tstr() { delete [] s; } - operator char *() const { return s; } - }; - - // encoding of dll and proc names are required, so that our special - // control characters in the name of sections can work as intended - static char *encode_name(const char *name, char *buf) - { - char *b = buf; - while (*name) - { - *b++ = 'a' + ((*name >> 4) & 0xf); - *b++ = 'a' + (*name & 0xf); - name++; - } - *b = 0; - return buf; - } - - static char *name_for_dll(const char *dll, char first_char) - { - assert(dll); - unsigned l = strlen(dll); - assert(l > 0); - - char *name = new char[3 * l + 2]; - assert(name); - name[0] = first_char; - char *n = name + 1 + 2 * l; - do { - *n++ = tolower(*dll); - } while(*dll++); - return encode_name(name + 1 + 2 * l, name + 1) - 1; - } - - static char *name_for_proc(const char *dll, const char *proc, - char first_char, char separator) - { - unsigned len = 1 + 2 * strlen(dll) + 1 + 2 * strlen(proc) + 1 + 1; - tstr dlln(name_for_dll(dll, first_char)); - char *procn = new char[len]; - upx_snprintf(procn, len - 1, "%s%c", (const char*) dlln, separator); - encode_name(proc, procn + strlen(procn)); - return procn; - } - - static const char zeros[sizeof(import_desc)]; - - enum { - // the order of identifiers is very important below!! - descriptor_id = 'D', - thunk_id, - dll_name_id, - proc_name_id, - ordinal_id, - - thunk_separator_first, - thunk_separator, - thunk_separator_last, - procname_separator, - }; - - unsigned thunk_size; // 4 or 8 bytes - - void add(const char *dll, const char *proc, unsigned ordinal) - { - tstr sdll(name_for_dll(dll, dll_name_id)); - tstr desc_name(name_for_dll(dll, descriptor_id)); - - char tsep = thunk_separator; - if (findSection(sdll, false) == NULL) - { - tsep = thunk_separator_first; - addSection(sdll, dll, strlen(dll) + 1, 0); // name of the dll - addSymbol(sdll, sdll, 0); - - addSection(desc_name, zeros, sizeof(zeros), 0); // descriptor - addRelocation(desc_name, offsetof(import_desc, dllname), - "R_X86_64_32", sdll, 0); - } - tstr thunk(name_for_proc(dll, proc, thunk_id, tsep)); - addSection(thunk, zeros, thunk_size, 0); - addSymbol(thunk, thunk, 0); - if (tsep == thunk_separator_first) - { - addRelocation(desc_name, offsetof(import_desc, iat), - "R_X86_64_32", thunk, 0); - - tstr last_thunk(name_for_proc(dll, "X", thunk_id, thunk_separator_last)); - addSection(last_thunk, zeros, thunk_size, 0); - } - - const char *reltype = thunk_size == 4 ? "R_X86_64_32" : "R_X86_64_64"; - if (ordinal != 0u) - { - addRelocation(thunk, 0, reltype, "*UND*", - ordinal | (1ull << (thunk_size * 8 - 1))); - } - else - { - tstr proc_name(name_for_proc(dll, proc, proc_name_id, procname_separator)); - addSection(proc_name, zeros, 2, 1); // 2 bytes of word aligned "hint" - addSymbol(proc_name, proc_name, 0); - addRelocation(thunk, 0, reltype, proc_name, 0); - - strcat(proc_name, "X"); - addSection(proc_name, proc, strlen(proc), 0); // the name of the symbol - } - } - - static int __acc_cdecl_qsort compare(const void *p1, const void *p2) - { - const Section *s1 = * (const Section * const *) p1; - const Section *s2 = * (const Section * const *) p2; - return strcmp(s1->name, s2->name); - } - - virtual void alignCode(unsigned len) { alignWithByte(len, 0); } - - const Section *getThunk(const char *dll, const char *proc, char tsep) const - { - assert(dll); - assert(proc); - tstr thunk(name_for_proc(dll, proc, thunk_id, tsep)); - return findSection(thunk, false); - } - -public: - explicit ImportLinker(unsigned thunk_size_) : thunk_size(thunk_size_) - { - assert(thunk_size == 4 || thunk_size == 8); - addSection("*UND*", NULL, 0, 0); - addSymbol("*UND*", "*UND*", 0); - addSection("*ZSTART", NULL, 0, 0); - addSymbol("*ZSTART", "*ZSTART", 0); - Section *s = addSection("Dzero", zeros, sizeof(import_desc), 0); - assert(s->name[0] == descriptor_id); - - // one trailing 00 byte after the last proc name - addSection("Zzero", zeros, 1, 0); - } - - template - void add(const C *dll, unsigned ordinal) - { - ACC_COMPILE_TIME_ASSERT(sizeof(C) == 1) // "char" or "unsigned char" - assert(ordinal > 0 && ordinal < 0x10000); - char ord[1+5+1]; - upx_snprintf(ord, sizeof(ord), "%c%05u", ordinal_id, ordinal); - add((const char*) dll, ord, ordinal); - } - - template - void add(const C1 *dll, const C2 *proc) - { - ACC_COMPILE_TIME_ASSERT(sizeof(C1) == 1) // "char" or "unsigned char" - ACC_COMPILE_TIME_ASSERT(sizeof(C2) == 1) // "char" or "unsigned char" - assert(proc); - add((const char*) dll, (const char*) proc, 0); - } - - unsigned build() - { - assert(output == NULL); - int osize = 4 + 2 * nsections; // upper limit for alignments - for (unsigned ic = 0; ic < nsections; ic++) - osize += sections[ic]->size; - output = new upx_byte[osize]; - - // sort the sections by name before adding them all - qsort(sections, nsections, sizeof (Section*), ImportLinker::compare); - - for (unsigned ic = 0; ic < nsections; ic++) - addLoader(sections[ic]->name); - addLoader("+40D"); - assert(outputlen <= osize); - - //OutputFile::dump("il0.imp", output, outputlen); - return outputlen; - } - - void relocate(unsigned myimport) - { - assert(nsections > 0); - assert(output); - defineSymbol("*ZSTART", /*0xffffffffff1000ull + 0 * */ myimport); - ElfLinkerAMD64::relocate(); - //OutputFile::dump("il1.imp", output, outputlen); - } - - template - upx_uint64_t getAddress(const C1 *dll, const C2 *proc) const - { - ACC_COMPILE_TIME_ASSERT(sizeof(C1) == 1) // "char" or "unsigned char" - ACC_COMPILE_TIME_ASSERT(sizeof(C2) == 1) // "char" or "unsigned char" - const Section *s = getThunk((const char*) dll, (const char*) proc, - thunk_separator_first); - if (s == NULL && (s = getThunk((const char*) dll,(const char*) proc, - thunk_separator)) == NULL) - throwInternalError("entry not found"); - return s->offset; - } - - template - upx_uint64_t getAddress(const C *dll, unsigned ordinal) const - { - ACC_COMPILE_TIME_ASSERT(sizeof(C) == 1) // "char" or "unsigned char" - assert(ordinal > 0 && ordinal < 0x10000); - char ord[1+5+1]; - upx_snprintf(ord, sizeof(ord), "%c%05u", ordinal_id, ordinal); - - const Section *s = getThunk((const char*) dll, ord, thunk_separator_first); - if (s == NULL - && (s = getThunk((const char*) dll, ord, thunk_separator)) == NULL) - throwInternalError("entry not found"); - return s->offset; - } - - template - upx_uint64_t getAddress(const C *dll) const - { - ACC_COMPILE_TIME_ASSERT(sizeof(C) == 1) // "char" or "unsigned char" - tstr sdll(name_for_dll((const char*) dll, dll_name_id)); - return findSection(sdll, true)->offset; - } -}; -const char ImportLinker::zeros[sizeof(import_desc)] = { 0 }; - -ImportLinker ilinker(8); - -void PackW64Pep::processImports(unsigned myimport, unsigned) // pass 2 -{ - COMPILE_TIME_ASSERT(sizeof(import_desc) == 20); - - ilinker.relocate(myimport); - int len; - oimpdlls = ilinker.getLoader(&len); - assert(len == (int) soimpdlls); - //OutputFile::dump("x1.imp", oimpdlls, soimpdlls); -} - -unsigned PackW64Pep::processImports() // pass 1 -{ - static const unsigned char kernel32dll[] = "KERNEL32.DLL"; - - 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; - 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; - for (ic = 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)); - 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++) - { - if (*tarr & (1ULL << 63)) - { - importbyordinal = true; - soimport += 2; // ordinal num: 2 bytes - dlls[ic].ordinal = *tarr & 0xffff; - } - 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); - - qsort(idlls,dllnum,sizeof (udll*),udll::compare); - - info("Processing imports: %d DLLs", dllnum); - - // create the new import table - ilinker.add(kernel32dll, "LoadLibraryA"); - ilinker.add(kernel32dll, "GetProcAddress"); - if (!isdll) - ilinker.add(kernel32dll, "ExitProcess"); - ilinker.add(kernel32dll, "VirtualProtect"); - - for (ic = 0; ic < dllnum; ic++) - { - if (idlls[ic]->isk32) - { - // for kernel32.dll we need to put all the imported - // ordinals into the output import table, as on - // some versions of windows GetProcAddress does not resolve them - if (idlls[ic]->ordinal) - for (LE64 *tarr = idlls[ic]->lookupt; *tarr; tarr++) - if (*tarr & (1ULL << 63)) - { - ilinker.add(kernel32dll, *tarr & 0xffff); - kernel32ordinal = true; - } - } - else - { - if (idlls[ic]->ordinal) - ilinker.add(idlls[ic]->name, idlls[ic]->ordinal); - else if (idlls[ic]->shname) - ilinker.add(idlls[ic]->name, idlls[ic]->shname); - else - throwInternalError("should not happen"); - } - } - - soimpdlls = ilinker.build(); - - Interval names(ibuf),iats(ibuf),lookups(ibuf); - - // create the preprocessed data - upx_byte *ppi = oimport; // preprocessed imports - for (ic = 0; ic < dllnum; ic++) - { - LE64 *tarr = idlls[ic]->lookupt; -#if 0 && ENABLE_THIS_AND_UNCOMPRESSION_WILL_BREAK // FIXME - if (!*tarr) // no imports from this dll - continue; -#endif - set_le32(ppi, ilinker.getAddress(idlls[ic]->name)); - set_le32(ppi+4,idlls[ic]->iat - rvamin); - ppi += 8; - for (; *tarr; tarr++) - if (*tarr & (1ULL << 63)) - { - unsigned ord = *tarr & 0xffff; - if (idlls[ic]->isk32) - { - *ppi++ = 0xfe; // signed + odd parity - set_le32(ppi, ilinker.getAddress(idlls[ic]->name, ord)); - ppi += 4; - } - else - { - *ppi++ = 0xff; - set_le16(ppi, ord); - 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); - - 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"); - upx_uint64_t 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_le32(ibuf + tlsindex, 0); -} - -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); - upx_uint64_t 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_le64(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 **************************************************************************/ @@ -945,329 +174,22 @@ void PackW64Pep::buildLoader(const Filter *ft) addLoader("IDENTSTR,UPX1HEAD", NULL); } - -void PackW64Pep::pack(OutputFile *fo) +bool PackW64Pep::handleForceOption() { - // FIXME: we need to think about better support for --exact - if (opt->exact) - throwCantPackExact(); + return (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) + ; +} - 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 = 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; - } - - 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 = true; - if (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,8u) + 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; +void PackW64Pep::defineSymbols(unsigned ncsection, unsigned upxsection, + unsigned sizeof_oh, unsigned ic, + Reloc &, unsigned s1addr) +{ const unsigned myimport = ncsection + soresources - rvamin; // patch loader @@ -1290,7 +212,7 @@ void PackW64Pep::pack(OutputFile *fo) // 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; + 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 @@ -1299,18 +221,18 @@ void PackW64Pep::pack(OutputFile *fo) linker->defineSymbol("vp_size", ((addr & 0xfff) + 0x28 >= 0x1000) ? 0x2000 : 0x1000); // 2 pages or 1 page linker->defineSymbol("vp_base", addr &~ 0xfff); // page mask - linker->defineSymbol("VirtualProtect", myimport + - ilinker.getAddress("kernel32.dll", "VirtualProtect")); + linker->defineSymbol("VirtualProtect", + ilinkerGetAddress("kernel32.dll", "VirtualProtect")); } linker->defineSymbol("start_of_relocs", crelocs); if (!isdll) - linker->defineSymbol("ExitProcess", myimport + - ilinker.getAddress("kernel32.dll", "ExitProcess")); - linker->defineSymbol("GetProcAddress", myimport + - ilinker.getAddress("kernel32.dll", "GetProcAddress")); + linker->defineSymbol("ExitProcess", + ilinkerGetAddress("kernel32.dll", "ExitProcess")); + linker->defineSymbol("GetProcAddress", + ilinkerGetAddress("kernel32.dll", "GetProcAddress")); linker->defineSymbol("kernel32_ordinals", myimport); - linker->defineSymbol("LoadLibraryA", myimport + - ilinker.getAddress("kernel32.dll", "LoadLibraryA")); + linker->defineSymbol("LoadLibraryA", + ilinkerGetAddress("kernel32.dll", "LoadLibraryA")); linker->defineSymbol("start_of_imports", myimport); linker->defineSymbol("compressed_imports", cimports); @@ -1319,7 +241,6 @@ void PackW64Pep::pack(OutputFile *fo) linker->defineSymbol("lzma_c_len", ph.c_len - 2); linker->defineSymbol("lzma_u_len", ph.u_len); } - defineFilterSymbols(&ft); linker->defineSymbol("filter_buffer_start", ih.codebase - rvamin); // in case of overlapping decompression, this hack is needed, @@ -1335,8 +256,7 @@ void PackW64Pep::pack(OutputFile *fo) const unsigned esi0 = s1addr + ic; linker->defineSymbol("start_of_uncompressed", 0u - esi0 + rvamin); linker->defineSymbol("start_of_compressed", esi0); - //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 - ih.imagebase); @@ -1344,387 +264,20 @@ void PackW64Pep::pack(OutputFile *fo) } linker->defineSymbol("START", 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 - - // 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; - - // tls & loadconf are put into section 1 - - //ic = s1addr + s1size - sotls - soloadconf; //ATTENTION: moved upwards to TLS callback handling - Stefan Widmann - if (use_tls_callbacks) - tls_handler_offset = linker->getSymbolOffset("PETLSC2"); - - 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() & 7) != 0) - fo->write(ibuf,8 - 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 (!checkFinalCompressionRatio(fo)) - throwNotCompressible(); } -/************************************************************************* -// unpack -**************************************************************************/ - -int PackW64Pep::canUnpack() +void PackW64Pep::setOhHeaderSize(const pe_section_t *) { - 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; + oh.headersize = rvamin; // FIXME } - -void PackW64Pep::rebuildImports(upx_byte *& extrainfo) +void PackW64Pep::pack(OutputFile *fo) { - 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; - - OPTR_I(LE64, newiat, (LE64 *) (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) + (1ULL << 63); - //;;;printf(" %llx",(unsigned long long)*newiat); - p += 3; - } - else - { - *newiat = get_le64(get_le32(p + 1) + import); - assert(*newiat & (1ULL << 63)); - p += 5; - } - *newiat = 0; - im++; - } - //memset(idata,0,p - idata); + // FIXME: Relocation stripping disabled for now - Stefan Widmann + opt->win32_pe.strip_relocs = false; + super::pack0(fo, 0x0c, 0x0000000140000000ULL); } -/* - 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 index 083989d0..05fe2923 100644 --- a/src/p_w64pep.h +++ b/src/p_w64pep.h @@ -33,9 +33,9 @@ // w64/pep **************************************************************************/ -class PackW64Pep : public PepFile +class PackW64Pep : public PeFile64 { - typedef PepFile super; + typedef PeFile64 super; public: PackW64Pep(InputFile *f); @@ -46,36 +46,19 @@ public: virtual const int *getCompressionMethods(int method, int level) const; virtual const int *getFilters() const; + virtual bool handleForceOption(); + virtual void defineSymbols(unsigned ncsection, unsigned upxsection, + unsigned sizeof_oh, unsigned isize_isplit, + Reloc &rel, unsigned s1addr); + virtual void setOhDataBase(const pe_section_t *) {} + virtual void setOhHeaderSize(const pe_section_t *osection); 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 }; diff --git a/src/packmast.cpp b/src/packmast.cpp index e546fef6..b5ed45ef 100644 --- a/src/packmast.cpp +++ b/src/packmast.cpp @@ -32,7 +32,6 @@ #include "packer.h" #include "lefile.h" #include "pefile.h" -#include "pepfile.h" #include "p_elf.h" #include "p_com.h" diff --git a/src/pefile.cpp b/src/pefile.cpp index 05445fde..58a4f36a 100644 --- a/src/pefile.cpp +++ b/src/pefile.cpp @@ -31,13 +31,7 @@ #include "filter.h" #include "packer.h" #include "pefile.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) +#include "linker.h" #define FILLVAL 0 @@ -50,6 +44,20 @@ # define strcpy(a,b) strcpy((char *)(a),(const char *)(b)) #endif +#if 1 +//static +unsigned my_strlen(const char *s) +{ + size_t l = strlen((const char*)s); assert((unsigned) l == l); return (unsigned) l; +} +static unsigned my_strlen(const unsigned char *s) +{ + size_t l = strlen((const char*)s); assert((unsigned) l == l); return (unsigned) l; +} +#undef strlen +#define strlen my_strlen +#endif + #if (__ACC_CXX_HAVE_PLACEMENT_DELETE) || defined(__DJGPP__) #include "bptr.h" #define IPTR(type, var) BoundedPtr var(ibuf, ibuf.getSize()) @@ -103,13 +111,9 @@ static void xcheck(size_t poff, size_t plen, const void *b, size_t blen) PeFile::PeFile(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) == 248) - COMPILE_TIME_ASSERT(sizeof(pe_header_t::ddirs_t) == 8) + COMPILE_TIME_ASSERT(sizeof(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(ddirs_t) COMPILE_TIME_ASSERT_ALIGNED1(pe_section_t) COMPILE_TIME_ASSERT(RT_LAST == TABLESIZE(opt->win32_pe.compress_rt)) @@ -130,20 +134,15 @@ PeFile::PeFile(InputFile *f) : super(f) sorelocs = 0; soxrelocs = 0; sotls = 0; -} + isdll = false; + ilinker = NULL; + use_tls_callbacks = false; + oloadconf = NULL; + soloadconf = 0; - -PeFile::~PeFile() -{ - delete [] isection; - delete [] orelocs; - delete [] oimport; - delete [] oimpdlls; - delete [] oexport; - delete [] otls; - delete [] oresources; - delete [] oxrelocs; - //delete res; + use_dep_hack = true; + use_clear_dirty_stack = true; + isrtm = false; } @@ -202,7 +201,7 @@ int PeFile::readFileHeader() if (ic == 20) return 0; fi->seek(pe_offset,SEEK_SET); - fi->readx(&ih,sizeof(ih)); + readPeHeader(); fi->seek(0x200,SEEK_SET); fi->readx(&h,6); return getFormat(); @@ -366,18 +365,18 @@ void PeFile::Reloc::finish(upx_byte *&p,unsigned &siz) p = start; siz = ptr_diff(rel1,start) &~ 3; siz -= 8; - assert(siz > 0); + // siz can be 0 in 64-bit mode // assert(siz > 0); start = 0; // safety } void PeFile::processRelocs(Reloc *rel) // pass2 { rel->finish(oxrelocs,soxrelocs); - if (opt->win32_pe.strip_relocs && !isdll) + if (opt->win32_pe.strip_relocs && !isdll /*FIXME ASLR*/) soxrelocs = 0; } -void PeFile::processRelocs() // pass1 +void PeFile32::processRelocs() // pass1 { big_relocs = 0; @@ -468,6 +467,107 @@ void PeFile::processRelocs() // pass1 info("Relocations: original size: %u bytes, preprocessed size: %u bytes",(unsigned) IDSIZE(PEDIR_RELOC),sorelocs); } +// FIXME - this is too similar to PeFile32::processRelocs +void PeFile64::processRelocs() // pass1 +{ + big_relocs = 0; + + Reloc rel(ibuf + IDADDR(PEDIR_RELOC),IDSIZE(PEDIR_RELOC)); + const unsigned *counts = rel.getcounts(); + unsigned rnum = 0; + + unsigned ic; + for (ic = 1; ic < 16; ic++) + rnum += counts[ic]; + + 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; + } + + for (ic = 15; ic; ic--) + if (ic != 10 && counts[ic]) + infoWarning("skipping unsupported relocation type %d (%d)",ic,counts[ic]); + + LE32 *fix[16]; + for (ic = 15; ic; ic--) + fix[ic] = new LE32 [counts[ic]]; + + unsigned xcounts[16]; + memset(xcounts, 0, sizeof(xcounts)); + + // prepare sorting + unsigned pos,type; + while (rel.next(pos,type)) + { + // FIXME add check for relocations which try to modify the + // PE header or other relocation records + + if (pos >= ih.imagesize) + continue; // skip out-of-bounds record + if (type < 16) + fix[type][xcounts[type]++] = pos - rvamin; + } + + // remove duplicated records + for (ic = 1; ic <= 15; 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 10" relocation records + for (ic = 0; ic < xcounts[10]; ic++) + { + pos = fix[10][ic] + rvamin; + set_le64(ibuf + pos, get_le64(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(optimizeReloc64((upx_byte*) fix[10], xcounts[10], + orelocs, ibuf + rvamin,1, &big_relocs), + orelocs); + + for (ic = 15; ic; ic--) + delete [] fix[ic]; + +#if 0 + // 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; + } + } +#endif + info("Relocations: original size: %u bytes, preprocessed size: %u bytes",(unsigned) IDSIZE(PEDIR_RELOC),sorelocs); +} /************************************************************************* // import handling @@ -480,35 +580,285 @@ __packed_struct(import_desc) LE32 iat; // import address table __packed_struct_end() -void PeFile::processImports(unsigned myimport, unsigned iat_off) // pass 2 +/* + ImportLinker: 32 and 64 bit import table building. + Import entries (dll name + proc name/ordinal pairs) can be + added in arbitrary order. + + Internally it works by creating sections with special names, + and adding relocation entries between those sections. The special + names ensure that when the import table is built in the memory + from those sections, a correct table can be generated simply by + sorting the sections by name, and adding all of them to the output + in the sorted order. + */ + +class PeFile::ImportLinker : public ElfLinkerAMD64 { - 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++) + struct tstr : private ::noncopyable { - if (im->dllname < myimport) - im->dllname += myimport; - LE32 *p = (LE32*) (oimpdlls + im->iat); - im->iat += myimport; - im->oft = im->iat; + char *s; + explicit tstr(char *str) : s(str) {} + ~tstr() { delete [] s; } + operator char *() const { return s; } + }; - while (*p) - if ((*p++ & 0x80000000) == 0) // import by name? - p[-1] += myimport; - - im->iat = im == (import_desc*) oimpdlls ? iat_off : iat_off + 12; + // encoding of dll and proc names are required, so that our special + // control characters in the name of sections can work as intended + static char *encode_name(const char *name, char *buf) + { + char *b = buf; + while (*name) + { + *b++ = 'a' + ((*name >> 4) & 0xf); + *b++ = 'a' + (*name & 0xf); + name++; + } + *b = 0; + return buf; } + + static char *name_for_dll(const char *dll, char first_char) + { + assert(dll); + unsigned l = strlen(dll); + assert(l > 0); + + char *name = new char[3 * l + 2]; + assert(name); + name[0] = first_char; + char *n = name + 1 + 2 * l; + do { + *n++ = tolower(*dll); + } while(*dll++); + return encode_name(name + 1 + 2 * l, name + 1) - 1; + } + + static char *name_for_proc(const char *dll, const char *proc, + char first_char, char separator) + { + unsigned len = 1 + 2 * strlen(dll) + 1 + 2 * strlen(proc) + 1 + 1; + tstr dlln(name_for_dll(dll, first_char)); + char *procn = new char[len]; + upx_snprintf(procn, len - 1, "%s%c", (const char*) dlln, separator); + encode_name(proc, procn + strlen(procn)); + return procn; + } + + static const char zeros[sizeof(import_desc)]; + + enum { + // the order of identifiers is very important below!! + descriptor_id = 'D', + thunk_id, + dll_name_id, + proc_name_id, + ordinal_id, + + thunk_separator_first, + thunk_separator, + thunk_separator_last, + procname_separator, + }; + + unsigned thunk_size; // 4 or 8 bytes + + void add(const char *dll, const char *proc, unsigned ordinal) + { + tstr sdll(name_for_dll(dll, dll_name_id)); + tstr desc_name(name_for_dll(dll, descriptor_id)); + + char tsep = thunk_separator; + if (findSection(sdll, false) == NULL) + { + tsep = thunk_separator_first; + addSection(sdll, dll, strlen(dll) + 1, 0); // name of the dll + addSymbol(sdll, sdll, 0); + + addSection(desc_name, zeros, sizeof(zeros), 0); // descriptor + addRelocation(desc_name, offsetof(import_desc, dllname), + "R_X86_64_32", sdll, 0); + } + tstr thunk(name_for_proc(dll, proc, thunk_id, tsep)); + if (findSection(thunk, false) != NULL) + return; // we already have this dll/proc + addSection(thunk, zeros, thunk_size, 0); + addSymbol(thunk, thunk, 0); + if (tsep == thunk_separator_first) + { + addRelocation(desc_name, offsetof(import_desc, iat), + "R_X86_64_32", thunk, 0); + + tstr last_thunk(name_for_proc(dll, "X", thunk_id, thunk_separator_last)); + addSection(last_thunk, zeros, thunk_size, 0); + } + + const char *reltype = thunk_size == 4 ? "R_X86_64_32" : "R_X86_64_64"; + if (ordinal != 0u) + { + addRelocation(thunk, 0, reltype, "*UND*", + ordinal | (1ull << (thunk_size * 8 - 1))); + } + else + { + tstr proc_name(name_for_proc(dll, proc, proc_name_id, procname_separator)); + addSection(proc_name, zeros, 2, 1); // 2 bytes of word aligned "hint" + addSymbol(proc_name, proc_name, 0); + addRelocation(thunk, 0, reltype, proc_name, 0); + + strcat(proc_name, "X"); + addSection(proc_name, proc, strlen(proc), 0); // the name of the symbol + } + } + + static int __acc_cdecl_qsort compare(const void *p1, const void *p2) + { + const Section *s1 = * (const Section * const *) p1; + const Section *s2 = * (const Section * const *) p2; + return strcmp(s1->name, s2->name); + } + + virtual void alignCode(unsigned len) { alignWithByte(len, 0); } + + const Section *getThunk(const char *dll, const char *proc, char tsep) const + { + assert(dll); + assert(proc); + tstr thunk(name_for_proc(dll, proc, thunk_id, tsep)); + return findSection(thunk, false); + } + +public: + explicit ImportLinker(unsigned thunk_size_) : thunk_size(thunk_size_) + { + assert(thunk_size == 4 || thunk_size == 8); + addSection("*UND*", NULL, 0, 0); + addSymbol("*UND*", "*UND*", 0); + addSection("*ZSTART", NULL, 0, 0); + addSymbol("*ZSTART", "*ZSTART", 0); + Section *s = addSection("Dzero", zeros, sizeof(import_desc), 0); + assert(s->name[0] == descriptor_id); + + // one trailing 00 byte after the last proc name + addSection("Zzero", zeros, 1, 0); + } + + template + void add(const C *dll, unsigned ordinal) + { + ACC_COMPILE_TIME_ASSERT(sizeof(C) == 1) // "char" or "unsigned char" + assert(ordinal > 0 && ordinal < 0x10000); + char ord[1+5+1]; + upx_snprintf(ord, sizeof(ord), "%c%05u", ordinal_id, ordinal); + add((const char*) dll, ord, ordinal); + } + + template + void add(const C1 *dll, const C2 *proc) + { + ACC_COMPILE_TIME_ASSERT(sizeof(C1) == 1) // "char" or "unsigned char" + ACC_COMPILE_TIME_ASSERT(sizeof(C2) == 1) // "char" or "unsigned char" + assert(proc); + add((const char*) dll, (const char*) proc, 0); + } + + unsigned build() + { + assert(output == NULL); + int osize = 4 + 2 * nsections; // upper limit for alignments + for (unsigned ic = 0; ic < nsections; ic++) + osize += sections[ic]->size; + output = new upx_byte[osize]; + outputlen = 0; + + // sort the sections by name before adding them all + qsort(sections, nsections, sizeof (Section*), ImportLinker::compare); + + for (unsigned ic = 0; ic < nsections; ic++) + addLoader(sections[ic]->name); + addLoader("+40D"); + assert(outputlen <= osize); + + //OutputFile::dump("il0.imp", output, outputlen); + return outputlen; + } + + void relocate(unsigned myimport) + { + assert(nsections > 0); + assert(output); + defineSymbol("*ZSTART", /*0xffffffffff1000ull + 0 * */ myimport); + ElfLinkerAMD64::relocate(); + //OutputFile::dump("il1.imp", output, outputlen); + } + + template + upx_uint64_t getAddress(const C1 *dll, const C2 *proc) const + { + ACC_COMPILE_TIME_ASSERT(sizeof(C1) == 1) // "char" or "unsigned char" + ACC_COMPILE_TIME_ASSERT(sizeof(C2) == 1) // "char" or "unsigned char" + const Section *s = getThunk((const char*) dll, (const char*) proc, + thunk_separator_first); + if (s == NULL && (s = getThunk((const char*) dll,(const char*) proc, + thunk_separator)) == NULL) + throwInternalError("entry not found"); + return s->offset; + } + + template + upx_uint64_t getAddress(const C *dll, unsigned ordinal) const + { + ACC_COMPILE_TIME_ASSERT(sizeof(C) == 1) // "char" or "unsigned char" + assert(ordinal > 0 && ordinal < 0x10000); + char ord[1+5+1]; + upx_snprintf(ord, sizeof(ord), "%c%05u", ordinal_id, ordinal); + + const Section *s = getThunk((const char*) dll, ord, thunk_separator_first); + if (s == NULL + && (s = getThunk((const char*) dll, ord, thunk_separator)) == NULL) + throwInternalError("entry not found"); + return s->offset; + } + + template + upx_uint64_t getAddress(const C *dll) const + { + ACC_COMPILE_TIME_ASSERT(sizeof(C) == 1) // "char" or "unsigned char" + tstr sdll(name_for_dll((const char*) dll, dll_name_id)); + return findSection(sdll, true)->offset; + } +}; +const char PeFile::ImportLinker::zeros[sizeof(import_desc)] = { 0 }; + +void PeFile::addKernelImport(const char *dll, const char *name) +{ + ilinker->add(dll, name); } -unsigned PeFile::processImports() // pass 1 +void PeFile::addKernelImports() { - 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"; + addKernelImport("KERNEL32.DLL", "LoadLibraryA"); + addKernelImport("KERNEL32.DLL", "GetProcAddress"); + if (!isdll) + addKernelImport("KERNEL32.DLL", "ExitProcess"); + addKernelImport("KERNEL32.DLL", "VirtualProtect"); +} + +void PeFile::processImports(unsigned myimport, unsigned) // pass 2 +{ + COMPILE_TIME_ASSERT(sizeof(import_desc) == 20); + + ilinker->relocate(myimport); + int len; + oimpdlls = ilinker->getLoader(&len); + assert(len == (int) soimpdlls); + //OutputFile::dump("x1.imp", oimpdlls, soimpdlls); +} + +template +unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1 +{ + static const unsigned char kernel32dll[] = "KERNEL32.DLL"; unsigned dllnum = 0; import_desc *im = (import_desc*) (ibuf + IDADDR(PEDIR_IMPORT)); @@ -526,8 +876,8 @@ unsigned PeFile::processImports() // pass 1 const upx_byte *shname; unsigned ordinal; unsigned iat; - LE32 *lookupt; - unsigned npos; + LEXX *lookupt; + unsigned original_position; bool isk32; static int __acc_cdecl_qsort compare(const void *p1, const void *p2) @@ -536,6 +886,8 @@ unsigned PeFile::processImports() // pass 1 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; @@ -552,33 +904,32 @@ unsigned PeFile::processImports() // pass 1 soimport = 1024; // safety - unsigned ic,k32o; - for (ic = k32o = 0; dllnum && im->dllname; ic++, im++) + unsigned ic; + for (ic = 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].lookupt = (LEXX*) (ibuf + (im->oft ? im->oft : im->iat)); + dlls[ic].original_position = ic; dlls[ic].isk32 = strcasecmp(kernel32dll,dlls[ic].name) == 0; soimport += strlen(dlls[ic].name) + 1 + 4; - for (LE32 *tarr = dlls[ic].lookupt; *tarr; tarr++) + for (IPTR_I(LEXX, tarr, dlls[ic].lookupt); *tarr; tarr += 1) { - if (*tarr & 0x80000000) + if (*tarr & ord_mask) { importbyordinal = true; soimport += 2; // ordinal num: 2 bytes dlls[ic].ordinal = *tarr & 0xffff; - //if (dlls[ic].isk32) - // kernel32ordinal = true,k32o++; } - else + else //it's an import by name { - unsigned len = strlen(ibuf + *tarr + 2); + IPTR_I(const upx_byte, n, ibuf + *tarr + 2); + unsigned len = strlen(n); soimport += len + 1; if (dlls[ic].shname == NULL || len < strlen (dlls[ic].shname)) dlls[ic].shname = ibuf + *tarr + 2; @@ -588,106 +939,71 @@ unsigned PeFile::processImports() // pass 1 } 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); + ilinker = new ImportLinker(sizeof(LEXX)); // create the new import table - im = (import_desc*) oimpdlls; + addKernelImports(); - 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; - /* + // for kernel32.dll we need to put all the imported + // ordinals into the output import table, as on + // some versions of windows GetProcAddress does not resolve them if (idlls[ic]->ordinal) - for (LE32 *tarr = idlls[ic]->lookupt; *tarr; tarr++) - if (*tarr & 0x80000000) - *ordinals++ = *tarr; - */ + for (LEXX *tarr = idlls[ic]->lookupt; *tarr; tarr++) + if (*tarr & ord_mask) + { + ilinker->add(kernel32dll, *tarr & 0xffff); + kernel32ordinal = true; + } } - 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; + ilinker->add(idlls[ic]->name, idlls[ic]->ordinal); 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++; + ilinker->add(idlls[ic]->name, idlls[ic]->shname); + else + throwInternalError("should not happen"); } - soimpdlls = ALIGN_UP(ptr_diff(importednames,oimpdlls),4); + } + + soimpdlls = ilinker->build(); 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; + LEXX *tarr = idlls[ic]->lookupt; +#if 0 && ENABLE_THIS_AND_UNCOMPRESSION_WILL_BREAK // FIXME if (!*tarr) // no imports from this dll continue; - set_le32(ppi,idlls[ic]->npos); +#endif + set_le32(ppi, ilinker->getAddress(idlls[ic]->name)); set_le32(ppi+4,idlls[ic]->iat - rvamin); ppi += 8; for (; *tarr; tarr++) - if (*tarr & 0x80000000) + if (*tarr & ord_mask) { - /*if (idlls[ic]->isk32) + unsigned ord = *tarr & 0xffff; + if (idlls[ic]->isk32) { *ppi++ = 0xfe; // signed + odd parity - set_le32(ppi,ptr_diff(ordinals,oimpdlls)); - ordinals++; + set_le32(ppi, ilinker->getAddress(idlls[ic]->name, ord)); ppi += 4; } - else*/ + else { *ppi++ = 0xff; - set_le16(ppi,*tarr & 0xffff); + set_le16(ppi, ord); ppi += 2; } } @@ -718,7 +1034,6 @@ unsigned PeFile::processImports() // pass 1 soimport = 0; //OutputFile::dump("x0.imp", oimport, soimport); - //OutputFile::dump("x1.imp", oimpdlls, soimpdlls); unsigned ilen = 0; names.flatten(); @@ -738,7 +1053,7 @@ unsigned PeFile::processImports() // pass 1 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 + im->dllname = ptr_diff(dlls[idlls[ic]->original_position].name,ibuf); } } else @@ -760,7 +1075,6 @@ unsigned PeFile::processImports() // pass 1 return names.ivnum == 1 ? names.ivarr[0].start : 0; } - /************************************************************************* // export handling **************************************************************************/ @@ -916,40 +1230,87 @@ void PeFile::processExports(Export *xport,unsigned newoffs) // pass2 // the virtual memory manager only for pages which are not yet loaded. // of course it was impossible to debug this ;-) -__packed_struct(tls) - LE32 datastart; // VA tls init data start - LE32 dataend; // VA tls init data end - LE32 tlsindex; // VA tls index - LE32 callbacks; // VA tls callbacks - char _[8]; // zero init, characteristics -__packed_struct_end() - -void PeFile::processTls(Interval *iv) // pass 1 +template <> +struct PeFile::tls_traits { - COMPILE_TIME_ASSERT(sizeof(tls) == 24) + __packed_struct(tls) + LE32 datastart; // VA tls init data start + LE32 dataend; // VA tls init data end + LE32 tlsindex; // VA tls index + LE32 callbacks; // VA tls callbacks + char _[8]; // zero init, characteristics + __packed_struct_end() + + static const unsigned sotls = 24; + static const unsigned cb_size = 4; + typedef unsigned cb_value_t; + static const unsigned reloc_type = 3; +}; + +template <> +struct PeFile::tls_traits +{ + __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() + + static const unsigned sotls = 40; + static const unsigned cb_size = 8; + typedef upx_uint64_t cb_value_t; + static const unsigned reloc_type = 10; +}; + +template +void PeFile::processTls1(Interval *iv, + typename tls_traits::cb_value_t imagebase, + unsigned imagesize) // pass 1 +{ + typedef typename tls_traits::tls tls; + typedef typename tls_traits::cb_value_t cb_value_t; + const unsigned cb_size = tls_traits::cb_size; + + COMPILE_TIME_ASSERT(sizeof(tls) == tls_traits::sotls) 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) + if (tlsp->callbacks < imagebase) throwCantPack("invalid TLS callback"); - else if (tlsp->callbacks - ih.imagebase + 4 >= ih.imagesize) + else if (tlsp->callbacks - imagebase + 4 >= imagesize) throwCantPack("invalid TLS callback"); - unsigned v = get_le32(ibuf + tlsp->callbacks - ih.imagebase); - if (v != 0) + cb_value_t v = *(LEXX*)(ibuf + (tlsp->callbacks - imagebase)); + + if(v != 0) { - //fprintf(stderr, "TLS callbacks: 0x%0x -> 0x%0x\n", (int)tlsp->callbacks, v); - throwCantPack("TLS callbacks are not supported"); + //count number of callbacks, just for information string - Stefan Widmann + unsigned num_callbacks = 0; + unsigned callback_offset = 0; + while(*(LEXX*)(ibuf + tlsp->callbacks - imagebase + callback_offset)) + { + //increment number of callbacks + num_callbacks++; + callback_offset += cb_size; + } + 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; + const unsigned tlsdatastart = tlsp->datastart - imagebase; + const unsigned tlsdataend = tlsp->dataend - imagebase; // now some ugly stuff: find the relocation entries in the tls data area unsigned pos,type; @@ -959,51 +1320,120 @@ void PeFile::processTls(Interval *iv) // pass 1 iv->add(pos,type); sotls = sizeof(tls) + tlsdataend - tlsdatastart; + // if TLS callbacks are used, we need two more {D|Q}WORDS at the end of the TLS + // ... and those dwords should be correctly aligned + if (use_tls_callbacks) + sotls = ALIGN_UP(sotls, cb_size) + 2 * cb_size; // the PE loader wants this stuff uncompressed otls = new upx_byte[sotls]; memset(otls,0,sotls); - memcpy(otls,ibuf + IDADDR(PEDIR_TLS),0x18); + 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),iv->ivnum); + tlsindex = tlsp->tlsindex - imagebase; + //NEW: subtract two dwords if TLS callbacks are used - Stefan Widmann + info("TLS: %u bytes tls data and %u relocations added", + sotls - (unsigned) sizeof(tls) - (use_tls_callbacks ? 2 * cb_size : 0),iv->ivnum); // makes sure tls index is zero after decompression - if (tlsindex && tlsindex < ih.imagesize) + if (tlsindex && tlsindex < imagesize) set_le32(ibuf + tlsindex, 0); } -void PeFile::processTls(Reloc *rel,const Interval *iv,unsigned newaddr) // pass 2 +template +void PeFile::processTls2(Reloc *rel,const Interval *iv,unsigned newaddr, + typename tls_traits::cb_value_t imagebase) // pass 2 { + typedef typename tls_traits::tls tls; + typedef typename tls_traits::cb_value_t cb_value_t; + const unsigned cb_size = tls_traits::cb_size; + const unsigned reloc_type = tls_traits::reloc_type; + if (sotls == 0) return; // add new relocation entries unsigned ic; - for (ic = 0; ic < 12; ic += 4) - rel->add(newaddr + ic,3); + //NEW: if TLS callbacks are used, relocate the VA of the callback chain, too - Stefan Widmann + for (ic = 0; ic < (use_tls_callbacks ? 4 * cb_size : 3 * cb_size); ic += cb_size) + rel->add(newaddr + ic, reloc_type); tls * const tlsp = (tls*) otls; // now the relocation entries in the tls data area for (ic = 0; ic < iv->ivnum; ic += 4) { - void *p = otls + iv->ivarr[ic].start - (tlsp->datastart - ih.imagebase) + sizeof(tls); - unsigned kc = get_le32(p); + void *p = otls + iv->ivarr[ic].start - (tlsp->datastart - imagebase) + sizeof(tls); + cb_value_t kc = *(LEXX*)(p); if (kc < tlsp->dataend && kc >= tlsp->datastart) { kc += newaddr + sizeof(tls) - tlsp->datastart; - set_le32(p,kc + ih.imagebase); + *(LEXX*)(p) = kc + imagebase; rel->add(kc,iv->ivarr[ic].len); } else - rel->add(kc - ih.imagebase,iv->ivarr[ic].len); + rel->add(kc - imagebase,iv->ivarr[ic].len); } - tlsp->datastart = newaddr + sizeof(tls) + ih.imagebase; - tlsp->dataend = newaddr + sotls + ih.imagebase; - tlsp->callbacks = 0; // note: TLS callbacks are not implemented in Windows 95/98/ME + const unsigned tls_data_size = tlsp->dataend - tlsp->datastart; + tlsp->datastart = newaddr + sizeof(tls) + imagebase; + tlsp->dataend = tlsp->datastart + tls_data_size; + + //NEW: if we have TLS callbacks to handle, we create a pointer to the new callback chain - Stefan Widmann + tlsp->callbacks = (use_tls_callbacks ? newaddr + sotls + imagebase - 2 * cb_size : 0); + + if (use_tls_callbacks) + { + //set handler offset + *(LEXX*)(otls + sotls - 2 * cb_size) = tls_handler_offset + imagebase; + //add relocation for TLS handler offset + rel->add(newaddr + sotls - 2 * cb_size, reloc_type); + } } +/************************************************************************* +// Load Configuration handling +**************************************************************************/ + +void PeFile::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 PeFile::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); + } +} /************************************************************************* // resource handling @@ -1568,14 +1998,536 @@ unsigned PeFile::stripDebug(unsigned overlaystart) // pack **************************************************************************/ +void PeFile::readSectionHeaders(unsigned objs, unsigned sizeof_ih) +{ + 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); +} + +void PeFile::checkHeaderValues(unsigned subsystem, unsigned mask, + unsigned ih_entry, unsigned ih_filealign) +{ + if ((1u << subsystem) & ~mask) + { + char buf[100]; + upx_snprintf(buf, sizeof(buf), "PE: subsystem %u is not supported", + subsystem); + throwCantPack(buf); + } + //check CLR Runtime Header directory entry + if (IDSIZE(PEDIR_COMRT)) + throwCantPack(".NET files are not yet supported"); + + 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 (ih_filealign < 0x200) + throwCantPack("filealign < 0x200 is not yet supported"); +} + +unsigned PeFile::handleStripRelocs(upx_uint64_t ih_imagebase, + upx_uint64_t default_imagebase, + unsigned dllflags) +{ + if (dllflags & IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE) + opt->win32_pe.strip_relocs = false; + else if (isdll) //do never strip relocations from DLLs + opt->win32_pe.strip_relocs = false; + else if (opt->win32_pe.strip_relocs < 0) + opt->win32_pe.strip_relocs = (ih_imagebase >= default_imagebase); + if (opt->win32_pe.strip_relocs) + { + if (ih_imagebase < default_imagebase) + throwCantPack("--strip-relocs is not allowed with this imagebase"); + else + return RELOCS_STRIPPED; + } + return 0; +} + +unsigned PeFile::readSections(unsigned objs, unsigned usize, + unsigned ih_filealign, unsigned ih_datasize) +{ + 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; + } + return overlaystart; +} + +void PeFile::callCompressWithFilters(Filter &ft, int filter_strategy, unsigned ih_codebase) +{ + compressWithFilters(&ft, 2048, NULL_cconf, filter_strategy, + ih_codebase, rvamin, 0, NULL, 0); +} + +void PeFile::callProcessRelocs(Reloc &rel, unsigned &ic) +{ + // wince wants relocation data at the beginning of a section + PeFile::processRelocs(&rel); + ODADDR(PEDIR_RELOC) = soxrelocs ? ic : 0; + ODSIZE(PEDIR_RELOC) = soxrelocs; + ic += soxrelocs; +} + +void PeFile::callProcessResources(Resource &res, unsigned &ic) +{ + if (soresources) + processResources(&res,ic); + ODADDR(PEDIR_RESOURCE) = soresources ? ic : 0; + ODSIZE(PEDIR_RESOURCE) = soresources; + ic += soresources; +} + +template +void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh, + unsigned subsystem_mask, upx_uint64_t default_imagebase, + bool last_section_rsrc_only) +{ + // FIXME: we need to think about better support for --exact + if (opt->exact) + throwCantPackExact(); + + const unsigned objs = ih.objects; + readSectionHeaders(objs, sizeof(ih)); + if (!opt->force && handleForceOption()) + throwCantPack("unexpected value in PE header (try --force)"); + checkHeaderValues(ih.subsystem, subsystem_mask, ih.entry, ih.filealign); + + //remove certificate directory entry + if (IDSIZE(PEDIR_SEC)) + IDSIZE(PEDIR_SEC) = IDADDR(PEDIR_SEC) = 0; + + ih.flags |= handleStripRelocs(ih.imagebase, default_imagebase, ih.dllflags); + + handleStub(fi,fo,pe_offset); + unsigned overlaystart = readSections(objs, ih.imagesize, ih.filealign, ih.datasize); + unsigned overlay = file_size - stripDebug(overlaystart); + if (overlay >= (unsigned) file_size) + 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 = true; + if (/*FIXME 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; + } + + callCompressWithFilters(ft, filter_strategy, ih.codebase); +// 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); + unsigned ic; + getLoaderSection("UPX1HEAD",(int*)&ic); + identsize += ic; + + const unsigned oobjs = last_section_rsrc_only ? 4 : 3; + pe_section_t osection[oobjs]; + // section 0 : bss + // 1 : [ident + header] + packed_data + unpacker + tls + loadconf + // 2 : not compressed data + // 3 : resource data -- wince 5 needs a new section for this + + // the last section 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 the last section 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, (unsigned) sizeof(LEXX)) + 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; + + Reloc rel(1024); // new relocations are put here + addNewRelocations(rel, upxsection); + + // 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 = oobjs; + oh.chksum = 0; + + // fill the data directory + ODADDR(PEDIR_DEBUG) = 0; + ODSIZE(PEDIR_DEBUG) = 0; + ODADDR(PEDIR_IAT) = 0; + ODSIZE(PEDIR_IAT) = 0; + ODADDR(PEDIR_BOUNDIM) = 0; + ODSIZE(PEDIR_BOUNDIM) = 0; + + // tls & loadconf are put into section 1 + ic = s1addr + s1size - sotls - soloadconf; + processTls(&rel,&tlsiv,ic); + ODADDR(PEDIR_TLS) = sotls ? ic : 0; + ODSIZE(PEDIR_TLS) = sotls ? (sizeof(LEXX) == 4 ? 0x18 : 0x28) : 0; + ic += sotls; + + processLoadConf(&rel, &loadconfiv, ic); + ODADDR(PEDIR_LOADCONF) = soloadconf ? ic : 0; + ODSIZE(PEDIR_LOADCONF) = soloadconf; + ic += soloadconf; + + const bool rel_at_sections_start = oobjs == 4; + + ic = ncsection; + if (!last_section_rsrc_only) + callProcessResources(res, ic); + if (rel_at_sections_start) + callProcessRelocs(rel, ic); + + processImports(ic, getProcessImportParam(upxsection)); + 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; + + if (!rel_at_sections_start) + callProcessRelocs(rel, ic); + + // when the resource is put alone into section 3 + const unsigned res_start = (ic + oam1) &~ oam1;; + if (last_section_rsrc_only) + callProcessResources(res, ic); + + defineSymbols(ncsection, upxsection, sizeof(oh), + identsize - identsplit, rel, s1addr); + defineFilterSymbols(&ft); + relocateLoader(); + const unsigned lsize = getLoaderSize(); + MemBuffer loader(lsize); + memcpy(loader,getLoader(),lsize); + patchPackHeader(loader, lsize); + + const unsigned ncsize = soxrelocs + soimpdlls + soexport + + (!last_section_rsrc_only ? soresources : 0); + const unsigned fam1 = 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, !last_section_rsrc_only && soresources ? ".rsrc" : "UPX2"); + + osection[0].vaddr = rvamin; + osection[1].vaddr = s1addr; + osection[2].vaddr = ncsection; + + osection[0].size = 0; + osection[1].size = (s1size + fam1) &~ fam1; + osection[2].size = (ncsize + fam1) &~ fam1; + + osection[0].vsize = osection[1].vaddr - osection[0].vaddr; + if (oobjs == 3) + { + osection[1].vsize = (osection[1].size + oam1) &~ oam1; + osection[2].vsize = (osection[2].size + ncsize_virt_increase + oam1) &~ oam1; + oh.imagesize = osection[2].vaddr + osection[2].vsize; + osection[0].rawdataptr = (pe_offset + sizeof(oh) + sizeof(osection) + fam1) &~ fam1; + osection[1].rawdataptr = osection[0].rawdataptr; + } + else + { + osection[1].vsize = osection[1].size; + osection[2].vsize = osection[2].size; + oh.imagesize = (osection[3].vaddr + osection[3].vsize + oam1) &~ oam1; + osection[0].rawdataptr = 0; + osection[1].rawdataptr = (pe_offset + sizeof(oh) + sizeof(osection) + fam1) &~ fam1; + } + 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); + + if (oobjs == 4) + { + strcpy(osection[3].name, ".rsrc"); + osection[3].vaddr = res_start; + osection[3].size = (soresources + fam1) &~ fam1; + osection[3].vsize = osection[3].size; + osection[3].rawdataptr = osection[2].rawdataptr + osection[2].size; + osection[2].flags = (unsigned) (PEFL_DATA|PEFL_READ); + osection[3].flags = (unsigned) (PEFL_DATA|PEFL_READ); + if (soresources == 0) + { + oh.objects = 3; + memset(&osection[3], 0, sizeof(osection[3])); + } + } + + oh.bsssize = osection[0].vsize; + oh.datasize = osection[2].vsize + (oobjs > 3 ? osection[3].vsize : 0); + setOhDataBase(osection); + oh.codesize = osection[1].vsize; + oh.codebase = osection[1].vaddr; + setOhHeaderSize(osection); + 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[oobjs == 3 ? 0 : 1].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() & (sizeof(LEXX) - 1)) != 0) + fo->write(ibuf, sizeof(LEXX) - ic); + fo->write(otls,sotls); + fo->write(oloadconf, soloadconf); + if ((ic = fo->getBytesWritten() & fam1) != 0) + fo->write(ibuf,oh.filealign - ic); + if (!last_section_rsrc_only) + fo->write(oresources,soresources); + else + fo->write(oxrelocs,soxrelocs); + fo->write(oimpdlls,soimpdlls); + fo->write(oexport,soexport); + fo->write(oxrelocs,soxrelocs); + if (!last_section_rsrc_only) + fo->write(oxrelocs,soxrelocs); + + if ((ic = fo->getBytesWritten() & fam1) != 0) + fo->write(ibuf,oh.filealign - ic); + + if (last_section_rsrc_only) + { + fo->write(oresources,soresources); + if ((ic = fo->getBytesWritten() & fam1) != 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); + + // finally check the compression ratio + if (!checkFinalCompressionRatio(fo)) + throwNotCompressible(); +} /************************************************************************* // unpack **************************************************************************/ -void PeFile::rebuildRelocs(upx_byte *& extrainfo) +void PeFile::rebuildRelocs(upx_byte *& extrainfo, unsigned bits, + unsigned flags, upx_uint64_t imagebase) { - if (!ODADDR(PEDIR_RELOC) || !ODSIZE(PEDIR_RELOC) || (oh.flags & RELOCS_STRIPPED)) + assert(bits == 32 || bits == 64); + if (!ODADDR(PEDIR_RELOC) || !ODSIZE(PEDIR_RELOC) || (flags & RELOCS_STRIPPED)) return; if (ODSIZE(PEDIR_RELOC) == 8) // some tricky dlls use this @@ -1591,7 +2543,7 @@ void PeFile::rebuildRelocs(upx_byte *& extrainfo) // upx_byte *p = rdata; OPTR_I(upx_byte, p, rdata); MemBuffer wrkmem; - unsigned relocn = unoptimizeReloc32(&rdata,obuf,&wrkmem,1); + unsigned relocn = unoptimizeReloc(&rdata,obuf,&wrkmem,1,bits); unsigned r16 = 0; if (big & 6) // 16 bit relocations { @@ -1620,8 +2572,11 @@ void PeFile::rebuildRelocs(upx_byte *& extrainfo) 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); + if (bits == 32) + set_le32(p, get_le32((unsigned char *)p) + imagebase + rvamin); + else + set_le64(p, get_le64((unsigned char *)p) + imagebase + rvamin); + rel.add(rvamin + get_le32(wrkmem + 4 * ic), bits == 32 ? 3 : 10); } rel.finish (oxrelocs,soxrelocs); @@ -1657,7 +2612,7 @@ void PeFile::rebuildTls() // this is an easy one : just do nothing ;-) } -void PeFile::rebuildResources(upx_byte *& extrainfo) +void PeFile::rebuildResources(upx_byte *& extrainfo, unsigned lastvaddr) { if (ODSIZE(PEDIR_RESOURCE) == 0 || IDSIZE(PEDIR_RESOURCE) == 0) return; @@ -1666,7 +2621,7 @@ void PeFile::rebuildResources(upx_byte *& extrainfo) extrainfo += 2; const unsigned vaddr = IDADDR(PEDIR_RESOURCE); - const upx_byte *r = ibuf - isection[ih.objects - 1].vaddr; + const upx_byte *r = ibuf - lastvaddr; Resource res(r + vaddr); while (res.next()) if (res.offs() > vaddr) @@ -1688,7 +2643,122 @@ void PeFile::rebuildResources(upx_byte *& extrainfo) delete [] p; } -void PeFile::unpack(OutputFile *fo) +template +void PeFile::rebuildImports(upx_byte *& extrainfo, + ord_mask_t ord_mask, bool set_oft) +{ + 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; + if (set_oft) + im->oft = iatoffs; + + OPTR_I(LEXX, newiat, (LEXX *) (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) + ord_mask; + //;;;printf(" %x",(unsigned)*newiat); + p += 3; + } + else + { + *newiat = *(const LEXX*)(get_le32(p + 1) + import); + assert(*newiat & ord_mask); + p += 5; + } + *newiat = 0; + im++; + } + //memset(idata,0,p - idata); +} + +template +void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh, + ord_mask_t ord_mask, bool set_oft) { //infoHeader("[Processing %s, format %s, %d sections]", fn_basename(fi->getName()), getName(), objs); @@ -1737,8 +2807,8 @@ void PeFile::unpack(OutputFile *fo) ft.unfilter(obuf + oh.codebase - rvamin, oh.codesize); } - rebuildImports(extrainfo); - rebuildRelocs(extrainfo); + rebuildImports(extrainfo, ord_mask, set_oft); + rebuildRelocs(extrainfo, sizeof(ih.imagebase) * 8, oh.flags, oh.imagebase); rebuildTls(); rebuildExports(); @@ -1751,7 +2821,7 @@ void PeFile::unpack(OutputFile *fo) fi->readx(ibuf,isection[3].size); } - rebuildResources(extrainfo); + rebuildResources(extrainfo, isection[ih.objects - 1].vaddr); //FIXME: this does bad things if the relocation section got removed // during compression ... @@ -1806,6 +2876,200 @@ void PeFile::unpack(OutputFile *fo) ibuf.dealloc(); } +int PeFile::canUnpack0(unsigned max_sections, LE16 &ih_objects, + LE32 &ih_entry, unsigned ihsize) +{ + if (!canPack()) + return false; + + unsigned objs = ih_objects; + isection = new pe_section_t[objs]; + fi->seek(pe_offset + ihsize, SEEK_SET); + fi->readx(isection,sizeof(pe_section_t)*objs); + if (ih_objects < 3) + return -1; + bool is_packed = ((ih_objects == 3 || ih_objects == max_sections) && + (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)); + + // FIXME this is for x86 + 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; +} + +upx_uint64_t PeFile::ilinkerGetAddress(const char *d, const char *n) const +{ + return ilinker->getAddress(d, n); +} + +PeFile::~PeFile() +{ + delete [] isection; + delete [] orelocs; + delete [] oimport; + oimpdlls = NULL; + delete [] oexport; + delete [] otls; + delete [] oresources; + delete [] oxrelocs; + delete [] oloadconf; + delete ilinker; + //delete res; +} + + +/************************************************************************* +// PeFile32 +**************************************************************************/ + +PeFile32::PeFile32(InputFile *f) : super(f) +{ + COMPILE_TIME_ASSERT(sizeof(pe_header_t) == 248) + COMPILE_TIME_ASSERT_ALIGNED1(pe_header_t) + + iddirs = ih.ddirs; + oddirs = oh.ddirs; +} + +PeFile32::~PeFile32() +{} + +void PeFile32::readPeHeader() +{ + fi->readx(&ih,sizeof(ih)); + isdll = ((ih.flags & DLL_FLAG) != 0); +} + +void PeFile32::pack0(OutputFile *fo, unsigned subsystem_mask, + upx_uint64_t default_imagebase, + bool last_section_rsrc_only) +{ + super::pack0(fo, ih, oh, subsystem_mask, + default_imagebase, last_section_rsrc_only); +} + +void PeFile32::unpack(OutputFile *fo) +{ + bool set_oft = getFormat() == UPX_F_WINCE_ARM_PE; + unpack0(fo, ih, oh, 1U << 31, set_oft); +} + +int PeFile32::canUnpack() +{ + return canUnpack0(getFormat() == UPX_F_WINCE_ARM_PE ? 4 : 3, + ih.objects, ih.entry, sizeof(ih)); +} + +unsigned PeFile32::processImports() // pass 1 +{ + return processImports0(1u << 31); +} + +void PeFile32::processTls(Interval *iv) +{ + processTls1(iv, ih.imagebase, ih.imagesize); +} + +void PeFile32::processTls(Reloc *r, const Interval *iv, unsigned a) +{ + processTls2(r, iv, a, ih.imagebase); +} + +/************************************************************************* +// PeFile64 +**************************************************************************/ + +PeFile64::PeFile64(InputFile *f) : super(f) +{ + COMPILE_TIME_ASSERT(sizeof(pe_header_t) == 264) + COMPILE_TIME_ASSERT_ALIGNED1(pe_header_t) + + iddirs = ih.ddirs; + oddirs = oh.ddirs; +} + +PeFile64::~PeFile64() +{} + +void PeFile64::readPeHeader() +{ + fi->readx(&ih,sizeof(ih)); + isdll = ((ih.flags & DLL_FLAG) != 0); +} + +void PeFile64::pack0(OutputFile *fo, unsigned subsystem_mask, + upx_uint64_t default_imagebase) +{ + super::pack0(fo, ih, oh, subsystem_mask, default_imagebase, false); +} + +void PeFile64::unpack(OutputFile *fo) +{ + unpack0(fo, ih, oh, 1ULL << 63, false); +} + +int PeFile64::canUnpack() +{ + return canUnpack0(3, ih.objects, ih.entry, sizeof(ih)); +} + +unsigned PeFile64::processImports() // pass 1 +{ + return processImports0(1ULL << 63); +} + +void PeFile64::processTls(Interval *iv) +{ + processTls1(iv, ih.imagebase, ih.imagesize); +} + +void PeFile64::processTls(Reloc *r, const Interval *iv, unsigned a) +{ + processTls2(r, iv, a, ih.imagebase); +} + /* extra info added to help uncompression: diff --git a/src/pefile.h b/src/pefile.h index a0b1d9ae..b5be3f81 100644 --- a/src/pefile.h +++ b/src/pefile.h @@ -42,34 +42,79 @@ protected: class Reloc; class Resource; class Export; + class ImportLinker; + struct pe_section_t; PeFile(InputFile *f); virtual ~PeFile(); virtual int getVersion() const { return 13; } - virtual void unpack(OutputFile *fo); + void readSectionHeaders(unsigned objs, unsigned sizeof_ih); + unsigned readSections(unsigned objs, unsigned usize, + unsigned ih_filealign, unsigned ih_datasize); + void checkHeaderValues(unsigned subsystem, unsigned mask, + unsigned ih_entry, unsigned ih_filealign); + unsigned handleStripRelocs(upx_uint64_t ih_imagebase, + upx_uint64_t default_imagebase, + unsigned dllflags); + + virtual bool handleForceOption() = 0; + virtual void callCompressWithFilters(Filter &, int filter_strategy, + unsigned ih_codebase); + virtual void defineSymbols(unsigned ncsection, unsigned upxsection, + unsigned sizeof_oh, unsigned isize_isplit, + Reloc &rel, unsigned s1addr) = 0; + virtual void addNewRelocations(Reloc &, unsigned) {} + void callProcessRelocs(Reloc &rel, unsigned &ic); + void callProcessResources(Resource &res, unsigned &ic); + virtual unsigned getProcessImportParam(unsigned) { return 0; } + virtual void setOhDataBase(const pe_section_t *osection) = 0; + virtual void setOhHeaderSize(const pe_section_t *osection) = 0; + + template + void pack0(OutputFile *fo, ht &ih, ht &oh, + unsigned subsystem_mask, upx_uint64_t default_imagebase, + bool last_section_rsrc_only); + + template + void unpack0(OutputFile *fo, const ht &ih, ht &oh, + ord_mask_t ord_mask, bool set_oft); // unpacker capabilities virtual bool canUnpackVersion(int version) const { return (version >= 12 && version <= 13); } + int canUnpack0(unsigned max_sections, LE16 &ih_objects, + LE32 &ih_entry, unsigned ihsize); + protected: virtual int readFileHeader(); virtual bool testUnpackVersion(int version) const; + virtual void readPeHeader() = 0; unsigned pe_offset; + template + unsigned processImports0(ord_mask_t ord_mask); + + template + void rebuildImports(upx_byte *& extrainfo, + ord_mask_t ord_mask, bool set_oft); virtual unsigned processImports() = 0; - virtual void processImports(unsigned, unsigned) = 0; - virtual void rebuildImports(upx_byte *&) = 0; + virtual void processImports(unsigned, unsigned); upx_byte *oimport; unsigned soimport; upx_byte *oimpdlls; unsigned soimpdlls; + ImportLinker *ilinker; + void addKernelImport(const char *, const char *); + virtual void addKernelImports(); + upx_uint64_t ilinkerGetAddress(const char *, const char *) const; - void processRelocs(); + virtual void processRelocs() = 0; void processRelocs(Reloc *); - void rebuildRelocs(upx_byte *&); + void rebuildRelocs(upx_byte *&, unsigned bits, + unsigned flags, upx_uint64_t imagebase); upx_byte *orelocs; unsigned sorelocs; upx_byte *oxrelocs; @@ -83,16 +128,34 @@ protected: void processResources(Resource *); void processResources(Resource *, unsigned); - void rebuildResources(upx_byte *&); + void rebuildResources(upx_byte *&, unsigned); upx_byte *oresources; unsigned soresources; - virtual void processTls(Interval *); - void processTls(Reloc *, const Interval *, unsigned); + template + struct tls_traits; + template + void processTls1(Interval *iv, + typename tls_traits::cb_value_t imagebase, + unsigned imagesize); // pass 1 + template + void processTls2(Reloc *rel,const Interval *iv,unsigned newaddr, + typename tls_traits::cb_value_t imagebase); // pass 2 + virtual void processTls(Interval *iv) = 0; + virtual void processTls(Reloc *r, const Interval *iv, unsigned a) = 0; + void rebuildTls(); upx_byte *otls; unsigned sotls; unsigned tlsindex; + unsigned tlscb_ptr; + unsigned tls_handler_offset; + bool use_tls_callbacks; + + void processLoadConf(Reloc *, const Interval *, unsigned); + void processLoadConf(Interval *); + upx_byte *oloadconf; + unsigned soloadconf; unsigned stripDebug(unsigned); @@ -106,49 +169,17 @@ protected: unsigned crelocs; // rva of preprocessed fixups int big_relocs; - __packed_struct(pe_header_t) - // 0x0 - char _[4]; // pemagic - LE16 cpu; - LE16 objects; - char __[12]; // timestamp + reserved - LE16 opthdrsize; - LE16 flags; - // optional header - LE16 coffmagic; // NEW: Stefan Widmann - char ___[2]; // linkerversion - LE32 codesize; - // 0x20 - LE32 datasize; - LE32 bsssize; - LE32 entry; - LE32 codebase; - // 0x30 - LE32 database; - // nt specific fields - LE32 imagebase; - LE32 objectalign; - LE32 filealign; // should set to 0x200 ? - // 0x40 - char ____[16]; // versions - // 0x50 - LE32 imagesize; - LE32 headersize; - LE32 chksum; // should set to 0 - LE16 subsystem; - LE16 dllflags; - // 0x60 - char _____[20]; // stack + heap sizes - // 0x74 - LE32 ddirsentries; // usually 16 - - __packed_struct(ddirs_t) - LE32 vaddr; - LE32 size; - __packed_struct_end() - - ddirs_t ddirs[16]; + __packed_struct(ddirs_t) + LE32 vaddr; + LE32 size; __packed_struct_end() + ddirs_t *iddirs; + ddirs_t *oddirs; + + LE32 &IDSIZE(unsigned x) { return iddirs[x].size; } + LE32 &IDADDR(unsigned x) { return iddirs[x].vaddr; } + LE32 &ODSIZE(unsigned x) { return oddirs[x].size; } + LE32 &ODADDR(unsigned x) { return oddirs[x].vaddr; } __packed_struct(pe_section_t) char name[8]; @@ -160,8 +191,12 @@ protected: LE32 flags; __packed_struct_end() - pe_header_t ih, oh; pe_section_t *isection; + bool isdll; + bool isrtm; + bool use_dep_hack; + bool use_clear_dirty_stack; + static unsigned virta2objnum (unsigned, pe_section_t *, unsigned); unsigned tryremove (unsigned, unsigned); @@ -372,6 +407,128 @@ protected: }; +class PeFile32 : public PeFile +{ + typedef PeFile super; +protected: + PeFile32(InputFile *f); + virtual ~PeFile32(); + void pack0(OutputFile *fo, unsigned subsystem_mask, + upx_uint64_t default_imagebase, bool last_section_rsrc_only); + virtual void unpack(OutputFile *fo); + virtual int canUnpack(); + + virtual void readPeHeader(); + + virtual unsigned processImports(); + virtual void processRelocs(); + virtual void processTls(Interval *); + void processTls(Reloc *, const Interval *, unsigned); + + __packed_struct(pe_header_t) + // 0x0 + char _[4]; // pemagic + LE16 cpu; + LE16 objects; + char __[12]; // timestamp + reserved + LE16 opthdrsize; + LE16 flags; + // optional header + LE16 coffmagic; // NEW: Stefan Widmann + char ___[2]; // linkerversion + LE32 codesize; + // 0x20 + LE32 datasize; + LE32 bsssize; + LE32 entry; + LE32 codebase; + // 0x30 + LE32 database; + // nt specific fields + LE32 imagebase; + LE32 objectalign; + LE32 filealign; // should set to 0x200 ? + // 0x40 + char ____[16]; // versions + // 0x50 + LE32 imagesize; + LE32 headersize; + LE32 chksum; // should set to 0 + LE16 subsystem; + LE16 dllflags; + // 0x60 + char _____[20]; // stack + heap sizes + // 0x74 + LE32 ddirsentries; // usually 16 + + ddirs_t ddirs[16]; + __packed_struct_end() + + pe_header_t ih, oh; +}; + +class PeFile64 : public PeFile +{ + typedef PeFile super; +protected: + PeFile64(InputFile *f); + virtual ~PeFile64(); + + void pack0(OutputFile *fo, unsigned subsystem_mask, + upx_uint64_t default_imagebase); + + virtual void unpack(OutputFile *fo); + virtual int canUnpack(); + + virtual void readPeHeader(); + + virtual unsigned processImports(); + virtual void processRelocs(); + virtual void processTls(Interval *); + void processTls(Reloc *, const Interval *, unsigned); + + __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 + + ddirs_t ddirs[16]; + __packed_struct_end() + + pe_header_t ih, oh; +}; + #endif /* already included */ diff --git a/src/pepfile.cpp b/src/pepfile.cpp deleted file mode 100644 index 447b9b53..00000000 --- a/src/pepfile.cpp +++ /dev/null @@ -1,1738 +0,0 @@ -/* pepfile.cpp -- - - This file is part of the UPX executable compressor. - - Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1996-2014 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(); - unsigned rnum = 0; - - unsigned ic; - for (ic = 1; ic < 16; ic++) - rnum += counts[ic]; - - 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; - } - - for (ic = 15; ic; ic--) - if (ic != 10 && counts[ic]) - infoWarning("skipping unsupported relocation type %d (%d)",ic,counts[ic]); - - LE32 *fix[16]; - for (ic = 15; ic; ic--) - fix[ic] = new LE32 [counts[ic]]; - - unsigned xcounts[16]; - memset(xcounts, 0, sizeof(xcounts)); - - // prepare sorting - unsigned pos,type; - while (rel.next(pos,type)) - { - // FIXME add check for relocations which try to modify the - // PE header or other relocation records - - if (pos >= ih.imagesize) - continue; // skip out-of-bounds record - if (type < 16) - fix[type][xcounts[type]++] = pos - rvamin; - } - - // remove duplicated records - for (ic = 1; ic <= 15; 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 10" relocation records - for (ic = 0; ic < xcounts[10]; ic++) - { - pos = fix[10][ic] + rvamin; - set_le64(ibuf + pos, get_le64(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(optimizeReloc64((upx_byte*) fix[10], xcounts[10], - orelocs, ibuf + rvamin,1, &big_relocs), - orelocs); - - for (ic = 15; ic; ic--) - delete [] fix[ic]; - -#if 0 - // 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; - } - } -#endif - 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 = unoptimizeReloc64(&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_le64(p, get_le64((unsigned char *)p) + oh.imagebase + rvamin); - rel.add(rvamin + get_le32(wrkmem + 4 * ic),10); - } - 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 deleted file mode 100644 index c89df51f..00000000 --- a/src/pepfile.h +++ /dev/null @@ -1,386 +0,0 @@ -/* pepfile.h -- - - This file is part of the UPX executable compressor. - - Copyright (C) 1996-2014 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1996-2014 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/amd64-win64.pep.h b/src/stub/amd64-win64.pep.h index 59fe923c..7545cb34 100644 --- a/src/stub/amd64-win64.pep.h +++ b/src/stub/amd64-win64.pep.h @@ -1,5 +1,5 @@ /* amd64-win64.pep.h - created from amd64-win64.pep.bin, 21168 (0x52b0) bytes + created from amd64-win64.pep.bin, 21244 (0x52fc) bytes This file is part of the UPX executable compressor. @@ -31,11 +31,11 @@ */ -#define STUB_AMD64_WIN64_PEP_SIZE 21168 -#define STUB_AMD64_WIN64_PEP_ADLER32 0x11b3b4f8 -#define STUB_AMD64_WIN64_PEP_CRC32 0xa0ed3bbf +#define STUB_AMD64_WIN64_PEP_SIZE 21244 +#define STUB_AMD64_WIN64_PEP_ADLER32 0x8f35c2d8 +#define STUB_AMD64_WIN64_PEP_CRC32 0x26033695 -unsigned char stub_amd64_win64_pep[21168] = { +unsigned char stub_amd64_win64_pep[21244] = { /* 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,176, 27, 0, 0, 0, 0, 0, 0, @@ -414,20 +414,20 @@ unsigned char stub_amd64_win64_pep[21168] = { /* 0x1770 */ 233, 4,138, 7, 72,131,199, 1, 72,255,201,117,217,235, 5, 72, /* 0x1780 */ 255,201,117,190, 72,131,236, 40, 72,141,190, 0, 0, 0, 0,139, /* 0x1790 */ 7, 9,192,116,255,139, 95, 4, 72,141,140, 48, 0, 0, 0, 0, -/* 0x17a0 */ 72, 1,243, 72,131,199, 8,255,150, 0, 0, 0, 0, 72,149,138, +/* 0x17a0 */ 72, 1,243, 72,131,199, 8,255, 21, 0, 0, 0, 0, 72,149,138, /* 0x17b0 */ 7, 72,255,199, 8,192,116,215,121,255,122, 16,139, 7, 72,131, /* 0x17c0 */ 199, 4, 72,139,132, 48, 0, 0, 0, 0,235,255, 72, 15,183, 23, /* 0x17d0 */ 72,131,199, 2,235,255, 72,137,249, 72,137,250,255,200,242,174, -/* 0x17e0 */ 72,137,233,255,150, 0, 0, 0, 0, 72, 9,192,116, 9, 72,137, +/* 0x17e0 */ 72,137,233,255, 21, 0, 0, 0, 0, 72, 9,192,116, 9, 72,137, /* 0x17f0 */ 3, 72,131,195, 8,235,255, 72,131,196, 40, 93, 95, 94, 91, 49, -/* 0x1800 */ 192,195,255,166, 0, 0, 0, 0, 72,131,196, 40, 72,141,190, 0, +/* 0x1800 */ 192,195,255, 37, 0, 0, 0, 0, 72,131,196, 40, 72,141,190, 0, /* 0x1810 */ 0, 0, 0, 72,131,199, 4, 72,141, 94,252, 49,192,138, 7, 72, /* 0x1820 */ 255,199, 9,192,116,255, 60,239,119, 17, 72, 1,195, 72,139, 3, /* 0x1830 */ 72, 15,200, 72, 1,240, 72,137, 3,235,224, 36, 15,193,224, 16, /* 0x1840 */ 102,139, 7, 72,131,199, 2, 9,192,117,255,139, 7, 72,131,199, /* 0x1850 */ 4,235,255, 72,135,247, 72,141,143, 0, 0, 0, 0,235, 4,102, /* 0x1860 */ 1, 12, 7,173, 9,192,117,247,193,233, 16,235, 4,102, 1, 12, -/* 0x1870 */ 7,173, 9,192,117,247, 72,139,174, 0, 0, 0, 0, 72,141,190, +/* 0x1870 */ 7,173, 9,192,117,247, 72,139, 45, 0, 0, 0, 0, 72,141,190, /* 0x1880 */ 0, 0, 0, 0,187, 0, 0, 0,128, 80, 73,137,225, 65,184, 4, /* 0x1890 */ 0, 0, 0, 72,137,218, 72,137,249, 72,131,236, 32,255,213, 72, /* 0x18a0 */ 141,135, 0, 0, 0, 0,128, 32,127,128, 96, 40,127, 76,141, 76, @@ -1223,140 +1223,145 @@ unsigned char stub_amd64_win64_pep[21168] = { /* 0x4a00 */ 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, 32,115,116, /* 0x4a10 */ 97,114,116, 95,111,102, 95,105,109,112,111,114,116,115, 10, 48, /* 0x4a20 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 50, 53, 32, -/* 0x4a30 */ 82, 95, 88, 56, 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, -/* 0x4a40 */ 32, 32, 76,111, 97,100, 76,105, 98,114, 97,114,121, 65, 10, 10, -/* 0x4a50 */ 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, -/* 0x4a60 */ 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 73, 66, 89, 79, 82, 68, -/* 0x4a70 */ 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, -/* 0x4a80 */ 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, -/* 0x4a90 */ 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, -/* 0x4aa0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 32, 82, 95, 88, -/* 0x4ab0 */ 56, 54, 95, 54, 52, 95, 80, 67, 56, 32, 32, 32, 32, 32, 32, 98, -/* 0x4ac0 */ 121,110, 97,109,101, 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, -/* 0x4ad0 */ 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, -/* 0x4ae0 */ 69, 75, 51, 50, 79, 82, 68, 93, 58, 10, 79, 70, 70, 83, 69, 84, -/* 0x4af0 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, -/* 0x4b00 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, -/* 0x4b10 */ 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, -/* 0x4b20 */ 48, 48, 99, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 51, 50, 83, -/* 0x4b30 */ 32, 32, 32, 32, 32, 32,107,101,114,110,101,108, 51, 50, 95,111, -/* 0x4b40 */ 114,100,105,110, 97,108,115, 10, 48, 48, 48, 48, 48, 48, 48, 48, -/* 0x4b50 */ 48, 48, 48, 48, 48, 48, 49, 49, 32, 82, 95, 88, 56, 54, 95, 54, -/* 0x4b60 */ 52, 95, 80, 67, 56, 32, 32, 32, 32, 32, 32,110,101,120,116, 95, -/* 0x4b70 */ 105,109,112, 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, -/* 0x4b80 */ 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 73, -/* 0x4b90 */ 77, 79, 82, 68, 49, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, -/* 0x4ba0 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, -/* 0x4bb0 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, -/* 0x4bc0 */ 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, -/* 0x4bd0 */ 57, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 80, 67, 56, 32, 32, -/* 0x4be0 */ 32, 32, 32, 32,102,105,114,115,116, 95,105,109,112, 10, 10, 82, -/* 0x4bf0 */ 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, 68, -/* 0x4c00 */ 83, 32, 70, 79, 82, 32, 91, 80, 69, 73, 77, 80, 79, 82, 50, 93, -/* 0x4c10 */ 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, 32, -/* 0x4c20 */ 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, -/* 0x4c30 */ 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, 48, -/* 0x4c40 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,102, 32, 82, 95, 88, 56, -/* 0x4c50 */ 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, 32, 71,101, -/* 0x4c60 */ 116, 80,114,111, 99, 65,100,100,114,101,115,115, 10, 48, 48, 48, -/* 0x4c70 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 50, 48, 32, 82, 95, -/* 0x4c80 */ 88, 56, 54, 95, 54, 52, 95, 80, 67, 56, 32, 32, 32, 32, 32, 32, -/* 0x4c90 */ 110,101,120,116, 95,102,117,110, 99, 10, 10, 82, 69, 76, 79, 67, -/* 0x4ca0 */ 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, -/* 0x4cb0 */ 82, 32, 91, 80, 69, 73, 69, 82, 69, 88, 69, 93, 58, 10, 79, 70, -/* 0x4cc0 */ 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, -/* 0x4cd0 */ 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, -/* 0x4ce0 */ 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, -/* 0x4cf0 */ 48, 48, 48, 48, 48, 48, 50, 32, 82, 95, 88, 56, 54, 95, 54, 52, -/* 0x4d00 */ 95, 51, 50, 83, 32, 32, 32, 32, 32, 32, 69,120,105,116, 80,114, -/* 0x4d10 */ 111, 99,101,115,115, 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, -/* 0x4d20 */ 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, -/* 0x4d30 */ 69, 82, 69, 76, 79, 67, 49, 93, 58, 10, 79, 70, 70, 83, 69, 84, -/* 0x4d40 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, -/* 0x4d50 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, -/* 0x4d60 */ 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, -/* 0x4d70 */ 48, 48, 51, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 51, 50, 83, -/* 0x4d80 */ 32, 32, 32, 32, 32, 32,115,116, 97,114,116, 95,111,102, 95,114, -/* 0x4d90 */ 101,108,111, 99,115, 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, -/* 0x4da0 */ 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, -/* 0x4db0 */ 69, 82, 69, 76, 79, 67, 51, 93, 58, 10, 79, 70, 70, 83, 69, 84, -/* 0x4dc0 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, -/* 0x4dd0 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, -/* 0x4de0 */ 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, -/* 0x4df0 */ 48, 48,101, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 80, 67, 56, -/* 0x4e00 */ 32, 32, 32, 32, 32, 32,114,101,108,111, 99, 95,101,110,100,120, -/* 0x4e10 */ 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, -/* 0x4e20 */ 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 82, 69, 76, 54, 52, 66, -/* 0x4e30 */ 73, 71, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, -/* 0x4e40 */ 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, -/* 0x4e50 */ 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, -/* 0x4e60 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 51, 32, 82, -/* 0x4e70 */ 95, 88, 56, 54, 95, 54, 52, 95, 80, 67, 56, 32, 32, 32, 32, 32, -/* 0x4e80 */ 32,114,101,108,111, 99, 95, 97,100,100, 10, 10, 82, 69, 76, 79, -/* 0x4e90 */ 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, -/* 0x4ea0 */ 79, 82, 32, 91, 82, 69, 76, 79, 67, 54, 52, 74, 93, 58, 10, 79, -/* 0x4eb0 */ 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, -/* 0x4ec0 */ 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, -/* 0x4ed0 */ 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, -/* 0x4ee0 */ 48, 48, 48, 48, 48, 48, 48, 49, 32, 82, 95, 88, 56, 54, 95, 54, -/* 0x4ef0 */ 52, 95, 80, 67, 56, 32, 32, 32, 32, 32, 32,114,101,108,111, 99, -/* 0x4f00 */ 95, 97,100,100, 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, -/* 0x4f10 */ 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, -/* 0x4f20 */ 82, 76, 79, 72, 73, 48, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, -/* 0x4f30 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, -/* 0x4f40 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, -/* 0x4f50 */ 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, -/* 0x4f60 */ 48, 54, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 51, 50, 83, 32, -/* 0x4f70 */ 32, 32, 32, 32, 32,114,101,108,111, 99, 95,100,101,108,116, 10, -/* 0x4f80 */ 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, -/* 0x4f90 */ 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 68, 69, 80, 72, 65, -/* 0x4fa0 */ 75, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, -/* 0x4fb0 */ 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, -/* 0x4fc0 */ 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, -/* 0x4fd0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 51, 32, 82, 95, -/* 0x4fe0 */ 88, 56, 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, 32, -/* 0x4ff0 */ 86,105,114,116,117, 97,108, 80,114,111,116,101, 99,116, 10, 48, -/* 0x5000 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 97, 32, -/* 0x5010 */ 82, 95, 88, 56, 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, -/* 0x5020 */ 32, 32,118,112, 95, 98, 97,115,101, 10, 48, 48, 48, 48, 48, 48, -/* 0x5030 */ 48, 48, 48, 48, 48, 48, 48, 48, 48,102, 32, 82, 95, 88, 56, 54, -/* 0x5040 */ 95, 54, 52, 95, 51, 50, 32, 32, 32, 32, 32, 32, 32,118,112, 95, -/* 0x5050 */ 115,105,122,101, 43, 48,120, 48, 48, 48, 48, 48, 48, 48, 48, 56, -/* 0x5060 */ 48, 48, 48, 48, 48, 48, 48, 10, 48, 48, 48, 48, 48, 48, 48, 48, -/* 0x5070 */ 48, 48, 48, 48, 48, 48, 50, 99, 32, 82, 95, 88, 56, 54, 95, 54, -/* 0x5080 */ 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, 32,115,119,114,105, 10, -/* 0x5090 */ 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, -/* 0x50a0 */ 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 84, 76, 83, 67, 93, -/* 0x50b0 */ 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, 32, -/* 0x50c0 */ 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, -/* 0x50d0 */ 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, 48, -/* 0x50e0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 50, 32, 82, 95, 88, 56, -/* 0x50f0 */ 54, 95, 54, 52, 95, 80, 67, 51, 50, 32, 32, 32, 32, 32, 80, 69, -/* 0x5100 */ 84, 76, 83, 67, 50, 45, 48,120, 48, 48, 48, 48, 48, 48, 48, 48, -/* 0x5110 */ 48, 48, 48, 48, 48, 48, 48, 53, 10, 48, 48, 48, 48, 48, 48, 48, -/* 0x5120 */ 48, 48, 48, 48, 48, 48, 48, 48, 97, 32, 82, 95, 88, 56, 54, 95, -/* 0x5130 */ 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, 32,116,108,115, 95, -/* 0x5140 */ 109,111,100,117,108,101, 95, 98, 97,115,101, 10, 48, 48, 48, 48, -/* 0x5150 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 54, 32, 82, 95, 88, -/* 0x5160 */ 56, 54, 95, 54, 52, 95, 80, 67, 51, 50, 32, 32, 32, 32, 32, 80, -/* 0x5170 */ 69, 84, 76, 83, 67, 50, 45, 48,120, 48, 48, 48, 48, 48, 48, 48, -/* 0x5180 */ 48, 48, 48, 48, 48, 48, 48, 48, 52, 10, 10, 82, 69, 76, 79, 67, -/* 0x5190 */ 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, -/* 0x51a0 */ 82, 32, 91, 80, 69, 68, 79, 74, 85, 77, 80, 93, 58, 10, 79, 70, -/* 0x51b0 */ 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, -/* 0x51c0 */ 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, -/* 0x51d0 */ 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, -/* 0x51e0 */ 48, 48, 48, 48, 48, 48, 49, 32, 82, 95, 88, 56, 54, 95, 54, 52, -/* 0x51f0 */ 95, 80, 67, 51, 50, 32, 32, 32, 32, 32,111,114,105,103,105,110, -/* 0x5200 */ 97,108, 95,101,110,116,114,121, 45, 48,120, 48, 48, 48, 48, 48, -/* 0x5210 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 52, 10, 10, 82, 69, 76, -/* 0x5220 */ 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, -/* 0x5230 */ 70, 79, 82, 32, 91, 80, 69, 84, 76, 83, 67, 50, 93, 58, 10, 79, -/* 0x5240 */ 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, -/* 0x5250 */ 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, -/* 0x5260 */ 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, -/* 0x5270 */ 48, 48, 48, 48, 48, 48, 48, 53, 32, 82, 95, 88, 56, 54, 95, 54, -/* 0x5280 */ 52, 95, 80, 67, 51, 50, 32, 32, 32, 32, 32,116,108,115, 95, 99, -/* 0x5290 */ 97,108,108, 98, 97, 99,107,115, 95,112,116,114, 45, 48,120, 48, -/* 0x52a0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 52, 10 +/* 0x4a30 */ 82, 95, 88, 56, 54, 95, 54, 52, 95, 80, 67, 51, 50, 32, 32, 32, +/* 0x4a40 */ 32, 32, 76,111, 97,100, 76,105, 98,114, 97,114,121, 65, 45, 48, +/* 0x4a50 */ 120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x4a60 */ 52, 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, +/* 0x4a70 */ 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 73, 66, 89, +/* 0x4a80 */ 79, 82, 68, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, +/* 0x4a90 */ 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, +/* 0x4aa0 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, +/* 0x4ab0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 32, +/* 0x4ac0 */ 82, 95, 88, 56, 54, 95, 54, 52, 95, 80, 67, 56, 32, 32, 32, 32, +/* 0x4ad0 */ 32, 32, 98,121,110, 97,109,101, 10, 10, 82, 69, 76, 79, 67, 65, +/* 0x4ae0 */ 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, +/* 0x4af0 */ 32, 91, 80, 69, 75, 51, 50, 79, 82, 68, 93, 58, 10, 79, 70, 70, +/* 0x4b00 */ 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, +/* 0x4b10 */ 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x4b20 */ 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x4b30 */ 48, 48, 48, 48, 48, 99, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, +/* 0x4b40 */ 51, 50, 83, 32, 32, 32, 32, 32, 32,107,101,114,110,101,108, 51, +/* 0x4b50 */ 50, 95,111,114,100,105,110, 97,108,115, 10, 48, 48, 48, 48, 48, +/* 0x4b60 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 49, 32, 82, 95, 88, 56, +/* 0x4b70 */ 54, 95, 54, 52, 95, 80, 67, 56, 32, 32, 32, 32, 32, 32,110,101, +/* 0x4b80 */ 120,116, 95,105,109,112, 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, +/* 0x4b90 */ 79, 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, +/* 0x4ba0 */ 80, 69, 73, 77, 79, 82, 68, 49, 93, 58, 10, 79, 70, 70, 83, 69, +/* 0x4bb0 */ 84, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, +/* 0x4bc0 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, +/* 0x4bd0 */ 76, 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x4be0 */ 48, 48, 48, 57, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 80, 67, +/* 0x4bf0 */ 56, 32, 32, 32, 32, 32, 32,102,105,114,115,116, 95,105,109,112, +/* 0x4c00 */ 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, +/* 0x4c10 */ 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 73, 77, 80, 79, +/* 0x4c20 */ 82, 50, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, +/* 0x4c30 */ 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, +/* 0x4c40 */ 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, +/* 0x4c50 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,102, 32, 82, +/* 0x4c60 */ 95, 88, 56, 54, 95, 54, 52, 95, 80, 67, 51, 50, 32, 32, 32, 32, +/* 0x4c70 */ 32, 71,101,116, 80,114,111, 99, 65,100,100,114,101,115,115, 45, +/* 0x4c80 */ 48,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x4c90 */ 48, 52, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x4ca0 */ 48, 50, 48, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 80, 67, 56, +/* 0x4cb0 */ 32, 32, 32, 32, 32, 32,110,101,120,116, 95,102,117,110, 99, 10, +/* 0x4cc0 */ 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, +/* 0x4cd0 */ 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 73, 69, 82, 69, 88, +/* 0x4ce0 */ 69, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, +/* 0x4cf0 */ 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, +/* 0x4d00 */ 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, +/* 0x4d10 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 50, 32, 82, 95, +/* 0x4d20 */ 88, 56, 54, 95, 54, 52, 95, 80, 67, 51, 50, 32, 32, 32, 32, 32, +/* 0x4d30 */ 69,120,105,116, 80,114,111, 99,101,115,115, 45, 48,120, 48, 48, +/* 0x4d40 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 52, 10, 10, +/* 0x4d50 */ 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, +/* 0x4d60 */ 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 82, 69, 76, 79, 67, 49, +/* 0x4d70 */ 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, +/* 0x4d80 */ 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x4d90 */ 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, +/* 0x4da0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 51, 32, 82, 95, 88, +/* 0x4db0 */ 56, 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, 32,115, +/* 0x4dc0 */ 116, 97,114,116, 95,111,102, 95,114,101,108,111, 99,115, 10, 10, +/* 0x4dd0 */ 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, +/* 0x4de0 */ 68, 83, 32, 70, 79, 82, 32, 91, 80, 69, 82, 69, 76, 79, 67, 51, +/* 0x4df0 */ 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, +/* 0x4e00 */ 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x4e10 */ 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, +/* 0x4e20 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,101, 32, 82, 95, 88, +/* 0x4e30 */ 56, 54, 95, 54, 52, 95, 80, 67, 56, 32, 32, 32, 32, 32, 32,114, +/* 0x4e40 */ 101,108,111, 99, 95,101,110,100,120, 10, 10, 82, 69, 76, 79, 67, +/* 0x4e50 */ 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, +/* 0x4e60 */ 82, 32, 91, 82, 69, 76, 54, 52, 66, 73, 71, 93, 58, 10, 79, 70, +/* 0x4e70 */ 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, +/* 0x4e80 */ 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x4e90 */ 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x4ea0 */ 48, 48, 48, 48, 48, 48, 51, 32, 82, 95, 88, 56, 54, 95, 54, 52, +/* 0x4eb0 */ 95, 80, 67, 56, 32, 32, 32, 32, 32, 32,114,101,108,111, 99, 95, +/* 0x4ec0 */ 97,100,100, 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, +/* 0x4ed0 */ 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 82, 69, 76, +/* 0x4ee0 */ 79, 67, 54, 52, 74, 93, 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, +/* 0x4ef0 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, +/* 0x4f00 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, +/* 0x4f10 */ 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x4f20 */ 49, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 80, 67, 56, 32, 32, +/* 0x4f30 */ 32, 32, 32, 32,114,101,108,111, 99, 95, 97,100,100, 10, 10, 82, +/* 0x4f40 */ 69, 76, 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, 68, +/* 0x4f50 */ 83, 32, 70, 79, 82, 32, 91, 80, 69, 82, 76, 79, 72, 73, 48, 93, +/* 0x4f60 */ 58, 10, 79, 70, 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x4f70 */ 32, 32, 32, 84, 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x4f80 */ 32, 32, 32, 32, 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, 48, +/* 0x4f90 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 54, 32, 82, 95, 88, 56, +/* 0x4fa0 */ 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, 32,114,101, +/* 0x4fb0 */ 108,111, 99, 95,100,101,108,116, 10, 10, 82, 69, 76, 79, 67, 65, +/* 0x4fc0 */ 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, +/* 0x4fd0 */ 32, 91, 80, 69, 68, 69, 80, 72, 65, 75, 93, 58, 10, 79, 70, 70, +/* 0x4fe0 */ 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, +/* 0x4ff0 */ 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x5000 */ 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x5010 */ 48, 48, 48, 48, 48, 51, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, +/* 0x5020 */ 80, 67, 51, 50, 32, 32, 32, 32, 32, 86,105,114,116,117, 97,108, +/* 0x5030 */ 80,114,111,116,101, 99,116, 45, 48,120, 48, 48, 48, 48, 48, 48, +/* 0x5040 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 52, 10, 48, 48, 48, 48, 48, +/* 0x5050 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 97, 32, 82, 95, 88, 56, +/* 0x5060 */ 54, 95, 54, 52, 95, 51, 50, 83, 32, 32, 32, 32, 32, 32,118,112, +/* 0x5070 */ 95, 98, 97,115,101, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x5080 */ 48, 48, 48, 48, 48,102, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, +/* 0x5090 */ 51, 50, 32, 32, 32, 32, 32, 32, 32,118,112, 95,115,105,122,101, +/* 0x50a0 */ 43, 48,120, 48, 48, 48, 48, 48, 48, 48, 48, 56, 48, 48, 48, 48, +/* 0x50b0 */ 48, 48, 48, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x50c0 */ 48, 48, 50, 99, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 51, 50, +/* 0x50d0 */ 83, 32, 32, 32, 32, 32, 32,115,119,114,105, 10, 10, 82, 69, 76, +/* 0x50e0 */ 79, 67, 65, 84, 73, 79, 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, +/* 0x50f0 */ 70, 79, 82, 32, 91, 80, 69, 84, 76, 83, 67, 93, 58, 10, 79, 70, +/* 0x5100 */ 70, 83, 69, 84, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, +/* 0x5110 */ 89, 80, 69, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +/* 0x5120 */ 32, 86, 65, 76, 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x5130 */ 48, 48, 48, 48, 48, 48, 50, 32, 82, 95, 88, 56, 54, 95, 54, 52, +/* 0x5140 */ 95, 80, 67, 51, 50, 32, 32, 32, 32, 32, 80, 69, 84, 76, 83, 67, +/* 0x5150 */ 50, 45, 48,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x5160 */ 48, 48, 48, 53, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x5170 */ 48, 48, 48, 48, 97, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 51, +/* 0x5180 */ 50, 83, 32, 32, 32, 32, 32, 32,116,108,115, 95,109,111,100,117, +/* 0x5190 */ 108,101, 95, 98, 97,115,101, 10, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x51a0 */ 48, 48, 48, 48, 48, 48, 49, 54, 32, 82, 95, 88, 56, 54, 95, 54, +/* 0x51b0 */ 52, 95, 80, 67, 51, 50, 32, 32, 32, 32, 32, 80, 69, 84, 76, 83, +/* 0x51c0 */ 67, 50, 45, 48,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x51d0 */ 48, 48, 48, 48, 52, 10, 10, 82, 69, 76, 79, 67, 65, 84, 73, 79, +/* 0x51e0 */ 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, 91, 80, +/* 0x51f0 */ 69, 68, 79, 74, 85, 77, 80, 93, 58, 10, 79, 70, 70, 83, 69, 84, +/* 0x5200 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, 32, +/* 0x5210 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, 76, +/* 0x5220 */ 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x5230 */ 48, 48, 49, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 80, 67, 51, +/* 0x5240 */ 50, 32, 32, 32, 32, 32,111,114,105,103,105,110, 97,108, 95,101, +/* 0x5250 */ 110,116,114,121, 45, 48,120, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x5260 */ 48, 48, 48, 48, 48, 48, 52, 10, 10, 82, 69, 76, 79, 67, 65, 84, +/* 0x5270 */ 73, 79, 78, 32, 82, 69, 67, 79, 82, 68, 83, 32, 70, 79, 82, 32, +/* 0x5280 */ 91, 80, 69, 84, 76, 83, 67, 50, 93, 58, 10, 79, 70, 70, 83, 69, +/* 0x5290 */ 84, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 84, 89, 80, 69, +/* 0x52a0 */ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 86, 65, +/* 0x52b0 */ 76, 85, 69, 10, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, +/* 0x52c0 */ 48, 48, 48, 53, 32, 82, 95, 88, 56, 54, 95, 54, 52, 95, 80, 67, +/* 0x52d0 */ 51, 50, 32, 32, 32, 32, 32,116,108,115, 95, 99, 97,108,108, 98, +/* 0x52e0 */ 97, 99,107,115, 95,112,116,114, 45, 48,120, 48, 48, 48, 48, 48, +/* 0x52f0 */ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 52, 10 }; diff --git a/src/stub/src/amd64-win64.pep.S b/src/stub/src/amd64-win64.pep.S index f3076c6a..ca545470 100644 --- a/src/stub/src/amd64-win64.pep.S +++ b/src/stub/src/amd64-win64.pep.S @@ -247,7 +247,7 @@ next_dll: add rbx, rsi add rdi, 8 - call [rsi + LoadLibraryA] + call [rip + LoadLibraryA] xchg rax, rbp next_func: @@ -279,7 +279,7 @@ section PEIMPOR2 first_imp: mov rcx, rbp - call [rsi + GetProcAddress] + call [rip + GetProcAddress] #if 1 ;// FIXME: is this error handling really needed? @@ -302,7 +302,7 @@ section PEIERDLL section PEIEREXE // rcx contains garbage -> garbage return code - jmp [rsi + ExitProcess] + jmp [rip + ExitProcess] section PEIMDONE imports_done: add rsp, 0x28 @@ -377,7 +377,7 @@ relhi0: // ============= section PEDEPHAK - mov rbp, [rsi + VirtualProtect] + mov rbp, [rip + VirtualProtect] lea rdi, [rsi + vp_base] mov ebx, IMM32(vp_size) // 0x1000 or 0x2000 diff --git a/src/stub/tmp/amd64-win64.pep.bin.dump b/src/stub/tmp/amd64-win64.pep.bin.dump index 38a8c2f7..89d33578 100644 --- a/src/stub/tmp/amd64-win64.pep.bin.dump +++ b/src/stub/tmp/amd64-win64.pep.bin.dump @@ -194,7 +194,7 @@ OFFSET TYPE VALUE 0000000000000007 R_X86_64_32S compressed_imports 0000000000000010 R_X86_64_PC8 imports_done 0000000000000018 R_X86_64_32S start_of_imports -0000000000000025 R_X86_64_32S LoadLibraryA +0000000000000025 R_X86_64_PC32 LoadLibraryA-0x0000000000000004 RELOCATION RECORDS FOR [PEIBYORD]: OFFSET TYPE VALUE @@ -211,12 +211,12 @@ OFFSET TYPE VALUE RELOCATION RECORDS FOR [PEIMPOR2]: OFFSET TYPE VALUE -000000000000000f R_X86_64_32S GetProcAddress +000000000000000f R_X86_64_PC32 GetProcAddress-0x0000000000000004 0000000000000020 R_X86_64_PC8 next_func RELOCATION RECORDS FOR [PEIEREXE]: OFFSET TYPE VALUE -0000000000000002 R_X86_64_32S ExitProcess +0000000000000002 R_X86_64_PC32 ExitProcess-0x0000000000000004 RELOCATION RECORDS FOR [PERELOC1]: OFFSET TYPE VALUE @@ -240,7 +240,7 @@ OFFSET TYPE VALUE RELOCATION RECORDS FOR [PEDEPHAK]: OFFSET TYPE VALUE -0000000000000003 R_X86_64_32S VirtualProtect +0000000000000003 R_X86_64_PC32 VirtualProtect-0x0000000000000004 000000000000000a R_X86_64_32S vp_base 000000000000000f R_X86_64_32 vp_size+0x0000000080000000 000000000000002c R_X86_64_32S swri