📄 pefile.cpp
字号:
/* pefile.cpp -- This file is part of the UPX executable compressor. Copyright (C) 1996-2007 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1996-2007 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 <mfx@users.sourceforge.net> <ml1050@users.sourceforge.net> */#include "conf.h"#include "file.h"#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)#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<type> var(ibuf, ibuf.getSize())#define OPTR(type, var) BoundedPtr<type> var(obuf, obuf.getSize())#define IPTR_I(type, var, v) BoundedPtr<type> var(ibuf, ibuf.getSize(), v)#define OPTR_I(type, var, v) BoundedPtr<type> var(obuf, obuf.getSize(), v)#define IPTR_C(type, var, v) const BoundedPtr<type> var(ibuf, ibuf.getSize(), v)#define OPTR_C(type, var, v) const BoundedPtr<type> 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)#endifstatic 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 0static 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)/*************************************************************************//**************************************************************************/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(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;}PeFile::~PeFile(){ delete [] isection; delete [] orelocs; delete [] oimport; delete [] oimpdlls; delete [] oexport; delete [] otls; delete [] oresources; delete [] oxrelocs; //delete res;}bool PeFile::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 PeFile::readFileHeader(){ struct exe_header_t { LE16 mz; LE16 m512; LE16 p512; char _[18]; LE16 relocoffs; char __[34]; LE32 nexepos; } __attribute_packed; COMPILE_TIME_ASSERT(sizeof(exe_header_t) == 64); exe_header_t h; int ic; pe_offset = 0; for (ic = 0; ic < 20; ic++) { fi->seek(pe_offset,SEEK_SET); fi->readx(&h,sizeof(h)); if (h.mz == 'M' + 'Z'*256) // dos exe { if (h.relocoffs >= 0x40) // new format exe pe_offset += h.nexepos; else pe_offset += h.p512*512+h.m512 - h.m512 ? 512 : 0; } else if (get_le32(&h) == 'P' + 'E'*256) break; else return 0; } if (ic == 20) return 0; fi->seek(pe_offset,SEEK_SET); fi->readx(&ih,sizeof(ih)); fi->seek(0x200,SEEK_SET); fi->readx(&h,6); return getFormat();}/*************************************************************************// interval handling**************************************************************************/PeFile::Interval::Interval(void *b) : capacity(0),base(b),ivarr(NULL),ivnum(0){}PeFile::Interval::~Interval(){ free(ivarr);}void PeFile::Interval::add(const void *start,unsigned len){ add(ptr_diff(start,base),len);}void PeFile::Interval::add(const void *start,const void *end){ add(ptr_diff(start,base),ptr_diff(end,start));}int __acc_cdecl_qsort PeFile::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 PeFile::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 PeFile::Interval::add(const Interval *iv){ for (unsigned ic = 0; ic < iv->ivnum; ic++) add(iv->ivarr[ic].start,iv->ivarr[ic].len);}void PeFile::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 PeFile::Interval::clear(){ for (unsigned ic = 0; ic < ivnum; ic++) memset((char*) base + ivarr[ic].start,0,ivarr[ic].len);}void PeFile::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**************************************************************************/struct PeFile::Reloc::reloc{ LE32 pagestart; LE32 size;}__attribute_packed;void PeFile::Reloc::newRelocPos(void *p){ rel = (reloc*) p; rel1 = (LE16*) ((char*) p + sizeof (reloc));}PeFile::Reloc::Reloc(upx_byte *s,unsigned si) : start(s), size(si), rel(NULL), rel1(NULL){ COMPILE_TIME_ASSERT(sizeof(reloc) == 8); memset(counts,0,sizeof(counts)); unsigned pos,type; while (next(pos,type)) counts[type]++;}PeFile::Reloc::Reloc(unsigned rnum) : start(NULL), size(0), rel(NULL), rel1(NULL){ start = new upx_byte[rnum * 4 + 8192]; counts[0] = 0;}bool PeFile::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 PeFile::Reloc::add(unsigned pos,unsigned type){ set_le32(start + 1024 + 4 * counts[0]++,(pos << 4) + type);}void PeFile::Reloc::finish(upx_byte *&p,unsigned &siz){ unsigned prev = 0xffffffff; set_le32(start + 1024 + 4 * counts[0]++,0xf0000000); qsort(start + 1024,counts[0],4,le32_compare); rel = (reloc*) start; rel1 = (LE16*) rel; for (unsigned ic = 0; ic < counts[0]; ic++) { unsigned pos = get_le32(start + 1024 + 4 * ic); if ((pos ^ prev) >= 0x10000) { prev = pos; *rel1 = 0; rel->size = ALIGN_UP(ptr_diff(rel1,rel),4); newRelocPos((char *)rel + rel->size); rel->pagestart = (pos >> 4) &~ 0xfff; } *rel1++ = (pos << 12) + ((pos >> 4) & 0xfff); } p = start; siz = ptr_diff(rel1,start) &~ 3; siz -= 8; assert(siz > 0); start = 0; // safety}void PeFile::processRelocs(Reloc *rel) // pass2{ rel->finish(oxrelocs,soxrelocs); if (opt->win32_pe.strip_relocs && !isdll) soxrelocs = 0;}void PeFile::processRelocs() // pass1{ big_relocs = 0; Reloc rel(ibuf + IDADDR(PEDIR_RELOC),IDSIZE(PEDIR_RELOC)); const unsigned *counts = rel.getcounts(); const unsigned rnum = counts[1] + counts[2] + counts[3]; if ((opt->win32_pe.strip_relocs && !isdll) || rnum == 0) { if (IDSIZE(PEDIR_RELOC)) ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL); orelocs = new upx_byte [1]; sorelocs = 0; return; } unsigned ic; for (ic = 15; ic > 3; ic--) if (counts[ic]) infoWarning("skipping unsupported relocation type %d (%d)",ic,counts[ic]); LE32 *fix[4]; for (; ic; ic--) fix[ic] = new LE32 [counts[ic]]; unsigned xcounts[4]; memset(xcounts, 0, sizeof(xcounts)); // prepare sorting unsigned pos,type; while (rel.next(pos,type)) { if (pos >= ih.imagesize) continue; // skip out-of-bounds record if (type < 4) fix[type][xcounts[type]++] = pos - rvamin; } // remove duplicated records for (ic = 1; ic <= 3; ic++) { qsort(fix[ic], xcounts[ic], 4, le32_compare); unsigned prev = ~0; unsigned jc = 0; for (unsigned kc = 0; kc < xcounts[ic]; kc++) if (fix[ic][kc] != prev) prev = fix[ic][jc++] = fix[ic][kc]; //printf("xcounts[%u] %u->%u\n", ic, xcounts[ic], jc); xcounts[ic] = jc; } // preprocess "type 3" relocation records for (ic = 0; ic < xcounts[3]; ic++) { pos = fix[3][ic] + rvamin; set_le32(ibuf + pos, get_le32(ibuf + pos) - ih.imagebase - rvamin); } ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL); orelocs = new upx_byte [rnum * 4 + 1024]; // 1024 - safety sorelocs = ptr_diff(optimizeReloc32((upx_byte*) fix[3], xcounts[3], orelocs, ibuf + rvamin,1, &big_relocs), orelocs); delete [] fix[3]; // 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -