📄 p_w32pe.cpp
字号:
// 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;}/*************************************************************************// 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**************************************************************************/bool PackW32Pe::canPack(){ if (!readFileHeader() || ih.cpu < 0x14c || ih.cpu > 0x150) return false; return true;}void PackW32Pe::buildLoader(const Filter *ft){ // recompute tlsindex (see pack() below) unsigned tmp_tlsindex = tlsindex; const unsigned oam1 = ih.objectalign - 1; const unsigned newvsize = (ph.u_len + rvamin + ph.overlap_overhead + oam1) &~ oam1; if (tlsindex && ((newvsize - ph.c_len - 1024 + oam1) &~ oam1) > tlsindex + 4) tmp_tlsindex = 0; // prepare loader initLoader(stub_i386_win32_pe, sizeof(stub_i386_win32_pe), 2); addLoader(isdll ? "PEISDLL1" : "", "PEMAIN01", icondir_count > 1 ? (icondir_count == 2 ? "PEICONS1" : "PEICONS2") : "", tmp_tlsindex ? "PETLSHAK" : "", "PEMAIN02", ph.first_offset_found == 1 ? "PEMAIN03" : "", getDecompressorSections(), /*multipass ? "PEMULTIP" : */ "", "PEMAIN10", NULL ); if (ft->id) { const unsigned texv = ih.codebase - rvamin; assert(ft->calls > 0); addLoader(texv ? "PECTTPOS" : "PECTTNUL",NULL); addFilter32(ft->id); } if (soimport) addLoader("PEIMPORT", importbyordinal ? "PEIBYORD" : "", kernel32ordinal ? "PEK32ORD" : "", importbyordinal ? "PEIMORD1" : "", "PEIMPOR2", isdll ? "PEIERDLL" : "PEIEREXE", "PEIMDONE", NULL ); if (sorelocs) { addLoader(soimport == 0 || soimport + cimports != crelocs ? "PERELOC1" : "PERELOC2", "PERELOC3,RELOC320", big_relocs ? "REL32BIG" : "", "RELOC32J", NULL ); //FIXME: the following should be moved out of the above if addLoader(big_relocs&6 ? "PERLOHI0" : "", big_relocs&4 ? "PERELLO0" : "", big_relocs&2 ? "PERELHI0" : "", NULL ); } if (use_dep_hack) addLoader("PEDEPHAK", NULL); addLoader("PEMAIN20", NULL); if (use_clear_dirty_stack) addLoader("CLEARSTACK", NULL); addLoader("PEMAIN21", NULL); addLoader(ih.entry ? "PEDOJUMP" : "PERETURN", "IDENTSTR,UPX1HEAD", NULL );}void PackW32Pe::pack(OutputFile *fo){ // FIXME: we need to think about better support for --exact if (opt->exact) throwCantPackExact(); const unsigned objs = ih.objects; isection = new pe_section_t[objs]; fi->seek(pe_offset+sizeof(ih),SEEK_SET); fi->readx(isection,sizeof(pe_section_t)*objs); rvamin = isection[0].vaddr; infoHeader("[Processing %s, format %s, %d sections]", fn_basename(fi->getName()), getName(), objs); // check the PE header // FIXME: add more checks if (!opt->force && ( (ih.cpu < 0x14c || ih.cpu > 0x150) || (ih.opthdrsize != 0xe0) || ((ih.flags & EXECUTABLE) == 0) || (ih.subsystem != 2 && ih.subsystem != 3 && ih.subsystem != 1 && ih.subsystem != 9) || (ih.entry == 0 && !isdll) || (ih.ddirsentries != 16) || IDSIZE(PEDIR_EXCEPTION) // is this used on i386?// || IDSIZE(PEDIR_COPYRIGHT) )) throwCantPack("unexpected value in PE header (try --force)"); if (ih.subsystem == 9) throwCantPack("x86/wince files are not yet supported"); if (IDSIZE(PEDIR_SEC)) IDSIZE(PEDIR_SEC) = IDADDR(PEDIR_SEC) = 0; 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 >= 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 (!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 (!isrtm && ((isection[ic].flags & (PEFL_WRITE|PEFL_SHARED)) == (PEFL_WRITE|PEFL_SHARED))) if (!opt->force) throwCantPack("writeable shared sections not supported (try --force)"); if (jc && isection[ic].rawdataptr - jc > ih.filealign) throwCantPack("superfluous data between sections"); fi->seek(isection[ic].rawdataptr,SEEK_SET); jc = isection[ic].size; if (jc > isection[ic].vsize) jc = isection[ic].vsize; if (isection[ic].vsize == 0) // hack for some tricky programs - may this break other progs? jc = isection[ic].vsize = isection[ic].size; if (isection[ic].vaddr + jc > ibuf.getSize()) throwInternalError("buffer too small 1"); fi->readx(ibuf + isection[ic].vaddr,jc); jc += isection[ic].rawdataptr; } // check for NeoLite if (find(ibuf + ih.entry, 64+7, "NeoLite", 7) >= 0) throwCantPack("file is already compressed with another packer"); unsigned overlay = file_size - stripDebug(overlaystart); if (overlay >= (unsigned) file_size) {#if 0 if (overlay < file_size + ih.filealign) overlay = 0; else if (!opt->force) throwNotCompressible("overlay problem (try --force)");#endif overlay = 0; } checkOverlay(overlay); Resource res; Interval tlsiv(ibuf); 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; const unsigned myimport = ncsection + soresources - rvamin; // patch loader linker->defineSymbol("original_entry", ih.entry); if (use_dep_hack) { // This works around a "protection" introduced in MSVCRT80, which // works like this: // When the compiler detects that it would link in some code from its // C runtime library which references some data in a read only // section then it compiles in a runtime check whether that data is // still in a read only section by looking at the pe header of the // file. If this check fails the runtime does "interesting" things // like not running the floating point initialization code - the result // is an R6002 runtime error. // These supposed to be read only addresses are covered by the sections // UPX0 & UPX1 in the compressed files, so we have to patch the PE header // in the memory. And the page on which the PE header is stored is read // only so we must make it rw, fix the flags (i.e. clear // PEFL_WRITE of osection[x].flags), and make it ro again.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -