📄 pefile.cpp
字号:
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 PeFile::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++) 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 PeFile::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 PeFile::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 PeFile::stripDebug(unsigned overlaystart){ if (IDADDR(PEDIR_DEBUG) == 0) return overlaystart; struct debug_dir_t { char _[16]; // flags, time/date, version, type LE32 size; char __[4]; // rva LE32 fpos; } __attribute_packed; const debug_dir_t *dd = (const debug_dir_t*) (ibuf + IDADDR(PEDIR_DEBUG)); for (unsigned ic = 0; ic < IDSIZE(PEDIR_DEBUG) / sizeof(debug_dir_t); ic++, dd++) if (overlaystart == dd->fpos) overlaystart += dd->size; ibuf.fill(IDADDR(PEDIR_DEBUG), IDSIZE(PEDIR_DEBUG), FILLVAL); return overlaystart;}/*************************************************************************// pack**************************************************************************//*************************************************************************// unpack**************************************************************************/void PeFile::rebuildRelocs(upx_byte *& extrainfo){ if (!ODADDR(PEDIR_RELOC) || !ODSIZE(PEDIR_RELOC) || (oh.flags & RELOCS_STRIPPED)) return; if (ODSIZE(PEDIR_RELOC) == 8) // some tricky dlls use this { omemcpy(obuf + ODADDR(PEDIR_RELOC) - rvamin, "\x0\x0\x0\x0\x8\x0\x0\x0", 8); return; } upx_byte *rdata = obuf + get_le32(extrainfo); const upx_byte big = extrainfo[4]; extrainfo += 5;// upx_byte *p = rdata; OPTR_I(upx_byte, p, rdata); MemBuffer wrkmem; unsigned relocn = unoptimizeReloc32(&rdata,obuf,&wrkmem,1); unsigned r16 = 0; if (big & 6) // 16 bit relocations { const LE32 *q = (LE32*) rdata; while (*q++) r16++; if ((big & 6) == 6) while (*++q) r16++; } Reloc rel(relocn + r16); if (big & 6) { LE32 *q = (LE32*) rdata; while (*q) rel.add(*q++ + rvamin,(big & 4) ? 2 : 1); if ((big & 6) == 6) while (*++q) rel.add(*q + rvamin,1); rdata = (upx_byte*) q; } //memset(p,0,rdata - p); for (unsigned ic = 0; ic < relocn; ic++) { p = obuf + get_le32(wrkmem + 4 * ic); set_le32(p, get_le32((unsigned char *)p) + oh.imagebase + rvamin); rel.add(rvamin + get_le32(wrkmem + 4 * ic),3); } rel.finish (oxrelocs,soxrelocs); if (opt->win32_pe.strip_relocs && !isdll) { obuf.clear(ODADDR(PEDIR_RELOC) - rvamin, ODSIZE(PEDIR_RELOC)); ODADDR(PEDIR_RELOC) = 0; soxrelocs = 0; // FIXME: try to remove the original relocation section somehow } else omemcpy(obuf + ODADDR(PEDIR_RELOC) - rvamin,oxrelocs,soxrelocs); delete [] oxrelocs; oxrelocs = NULL; wrkmem.dealloc(); ODSIZE(PEDIR_RELOC) = soxrelocs;}void PeFile::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 PeFile::rebuildTls(){ // this is an easy one : just do nothing ;-)}void PeFile::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(); // 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 PeFile::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; 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; 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; // 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: <ih sizeof(pe_head)> <pe_section_t objs*sizeof(pe_section_t)> <start of compressed imports 4> - optional \ <start of the names from uncompressed imports> - opt / <start of compressed relocs 4> - optional \ <relocation type indicator 1> - optional / <icondir_count 2> - optional <offset of extra info 4>*//*vi:ts=4:et*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -