📄 p_exe.cpp
字号:
/* p_exe.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 markus@oberhumer.com ml1050@users.sourceforge.net */#include "conf.h"#include "file.h"#include "filter.h"#include "packer.h"#include "p_exe.h"#include "linker.h"static const#include "stub/i086-dos16.exe.h"#define RSFCRI 4096 // Reserved Space For Compressed Relocation Info#define MAXMATCH 0x2000#define MAXRELOCS (0x8000-MAXMATCH)#define DI_LIMIT 0xff00 // see the assembly why/*************************************************************************//**************************************************************************/PackExe::PackExe(InputFile *f) : super(f){ bele = &N_BELE_RTP::le_policy; COMPILE_TIME_ASSERT(sizeof(exe_header_t) == 32); ih_exesize = ih_imagesize = ih_overlay = 0; stack_for_lzma = 0; use_clear_dirty_stack = false; // disable lzma for "--brute" unless explicitly given "--lzma" if (opt->all_methods_use_lzma && !opt->method_lzma_seen) opt->all_methods_use_lzma = false;}const int *PackExe::getCompressionMethods(int method, int level) const{ bool small = ih_imagesize <= 256*1024; return Packer::getDefaultCompressionMethods_8(method, level, small);}const int *PackExe::getFilters() const{ return NULL;}int PackExe::fillExeHeader(struct exe_header_t *eh) const{#define oh (*eh) // fill new exe header int flag = 0; if (!opt->dos_exe.no_reloc && !M_IS_LZMA(ph.method)) flag |= USEJUMP; if (ih.relocs == 0) flag |= NORELOC; memset(&oh,0,sizeof(oh)); oh.ident = 'M' + 'Z' * 256; oh.headsize16 = 2; unsigned minsp = 0x200; if (M_IS_LZMA(ph.method)) minsp = stack_for_lzma; minsp = ALIGN_UP(minsp, 16u); assert(minsp < 0xff00); if (oh.sp > minsp) minsp = oh.sp; if (minsp < 0xff00 - 2) minsp = ALIGN_UP(minsp, 2u); oh.sp = minsp; unsigned destpara = (ph.u_len + ph.overlap_overhead - ph.c_len + 31) / 16; oh.ss = ph.c_len/16 + destpara; if (ih.ss*16 + ih.sp < 0x100000 && ih.ss > oh.ss && ih.sp > 0x200) oh.ss = ih.ss; if (oh.ss*16 + 0x50 < ih.ss*16 + ih.sp && oh.ss*16 + 0x200 > ih.ss*16 + ih.sp) oh.ss += 0x20; if (oh.ss != ih.ss) flag |= SS; if (oh.sp != ih.sp || M_IS_LZMA(ph.method)) flag |= SP; return flag;#undef oh}void PackExe::addLoaderEpilogue(int flag){ addLoader("EXEMAIN5", NULL); if (relocsize) addLoader(ph.u_len <= DI_LIMIT || (ph.u_len & 0x7fff) >= relocsize ? "EXENOADJ" : "EXEADJUS", "EXERELO1", has_9a ? "EXEREL9A" : "", "EXERELO2", ih_exesize > 0xFE00 ? "EXEREBIG" : "", "EXERELO3", NULL ); addLoader("EXEMAIN8", device_driver ? "DEVICEEND" : "", (flag & SS) ? "EXESTACK" : "", (flag & SP) ? "EXESTASP" : "", (flag & USEJUMP) ? "EXEJUMPF" : "", NULL ); if (!(flag & USEJUMP)) addLoader(ih.cs ? "EXERCSPO" : "", "EXERETIP", NULL ); linker->defineSymbol("original_cs", ih.cs); linker->defineSymbol("original_ip", ih.ip); linker->defineSymbol("original_sp", ih.sp); linker->defineSymbol("original_ss", ih.ss); linker->defineSymbol("reloc_size", (ph.u_len <= DI_LIMIT || (ph.u_len & 0x7fff) >= relocsize ? 0 : MAXRELOCS) - relocsize);}void PackExe::buildLoader(const Filter *){ // get flag exe_header_t dummy_oh; int flag = fillExeHeader(&dummy_oh); initLoader(stub_i086_dos16_exe, sizeof(stub_i086_dos16_exe)); if (M_IS_LZMA(ph.method)) { addLoader("LZMA_DEC00", opt->small ? "LZMA_DEC10" : "LZMA_DEC20", "LZMA_DEC30", use_clear_dirty_stack ? "LZMA_DEC31" : "", "LZMA_DEC32", ph.u_len > 0xffff ? "LZMA_DEC33" : "", NULL ); addLoaderEpilogue(flag); defineDecompressorSymbols(); const unsigned lsize0 = getLoaderSize(); // Lzma decompression code starts at ss:0x10, and its size is // lsize bytes. It also needs getDecompressorWrkmemSize() bytes // during uncompression. It also uses some stack, so 0x100 // more bytes are allocated stack_for_lzma = 0x10 + lsize0 + getDecompressorWrkmemSize() + 0x100; stack_for_lzma = ALIGN_UP(stack_for_lzma, 16u); unsigned clear_dirty_stack_low = 0x10 + lsize0; clear_dirty_stack_low = ALIGN_UP(clear_dirty_stack_low, 2u); if (use_clear_dirty_stack) linker->defineSymbol("clear_dirty_stack_low", clear_dirty_stack_low); relocateLoader(); const unsigned lsize = getLoaderSize(); assert(lsize0 == lsize); MemBuffer loader(lsize); memcpy(loader, getLoader(), lsize); MemBuffer compressed_lzma; compressed_lzma.allocForCompression(lsize); unsigned c_len_lzma = MemBuffer::getSizeForCompression(lsize); int r = upx_compress(loader, lsize, compressed_lzma, &c_len_lzma, NULL, M_NRV2B_LE16, 9, NULL, NULL); assert(r == UPX_E_OK); assert(c_len_lzma < lsize); info("lzma+relocator code compressed: %u -> %u", lsize, c_len_lzma); // reinit the loader initLoader(stub_i086_dos16_exe, sizeof(stub_i086_dos16_exe)); // prepare loader if (device_driver) addLoader("DEVICEENTRY,LZMADEVICE,DEVICEENTRY2", NULL); linker->addSection("COMPRESSED_LZMA", compressed_lzma, c_len_lzma, 0); addLoader("LZMAENTRY,NRV2B160,NRVDDONE,NRVDECO1,NRVGTD00,NRVDECO2", NULL); } else if (device_driver) addLoader("DEVICEENTRY,DEVICEENTRY2", NULL); addLoader("EXEENTRY", M_IS_LZMA(ph.method) && device_driver ? "LONGSUB" : "SHORTSUB", "JNCDOCOPY", relocsize ? "EXERELPU" : "", "EXEMAIN4", M_IS_LZMA(ph.method) ? "" : "EXEMAIN4B", "EXEMAIN4C", M_IS_LZMA(ph.method) ? "COMPRESSED_LZMA_START,COMPRESSED_LZMA" : "", "+G5DXXXX,UPX1HEAD,EXECUTPO", NULL ); if (ph.method == M_NRV2B_8) addLoader("NRV2B16S", // decompressor ph.u_len > DI_LIMIT ? "N2B64K01" : "", "NRV2BEX1", opt->cpu == opt->CPU_8086 ? "N2BX8601" : "N2B28601", "NRV2BEX2", opt->cpu == opt->CPU_8086 ? "N2BX8602" : "N2B28602", "NRV2BEX3", ph.c_len > 0xffff ? "N2B64K02" : "", "NRV2BEX9", NULL ); else if (ph.method == M_NRV2D_8) addLoader("NRV2D16S", ph.u_len > DI_LIMIT ? "N2D64K01" : "", "NRV2DEX1", opt->cpu == opt->CPU_8086 ? "N2DX8601" : "N2D28601", "NRV2DEX2", opt->cpu == opt->CPU_8086 ? "N2DX8602" : "N2D28602", "NRV2DEX3", ph.c_len > 0xffff ? "N2D64K02" : "", "NRV2DEX9", NULL ); else if (ph.method == M_NRV2E_8) addLoader("NRV2E16S", ph.u_len > DI_LIMIT ? "N2E64K01" : "", "NRV2EEX1", opt->cpu == opt->CPU_8086 ? "N2EX8601" : "N2E28601", "NRV2EEX2", opt->cpu == opt->CPU_8086 ? "N2EX8602" : "N2E28602", "NRV2EEX3", ph.c_len > 0xffff ? "N2E64K02" : "", "NRV2EEX9", NULL ); else if M_IS_LZMA(ph.method) return; else throwInternalError("unknown compression method"); addLoaderEpilogue(flag);}/*************************************************************************//**************************************************************************/int PackExe::readFileHeader(){ ih_exesize = ih_imagesize = ih_overlay = 0; fi->readx(&ih,sizeof(ih)); if (ih.ident != 'M' + 'Z'*256 && ih.ident != 'Z' + 'M'*256) return 0; ih_exesize = ih.m512 + ih.p512*512 - (ih.m512 ? 512 : 0); ih_imagesize = ih_exesize - ih.headsize16*16; ih_overlay = file_size - ih_exesize; if (ih.m512+ih.p512*512u < sizeof (ih)) throwCantPack("illegal exe header"); if (file_size < (off_t)ih_exesize || ih_imagesize <= 0 || ih_imagesize > ih_exesize) throwCantPack("exe header corrupted");#if 0 printf("dos/exe header: %d %d %d\n", ih_exesize, ih_imagesize, ih_overlay);#endif return UPX_F_DOS_EXE;}bool PackExe::canPack(){ if (fn_has_ext(fi->getName(),"sys")) return false; if (!readFileHeader()) return false; if (file_size < 1024) throwCantPack("file is too small"); fi->seek(0x3c,SEEK_SET); LE32 offs; fi->readx(&offs,sizeof (offs)); if (ih.relocoffs >= 0x40 && offs) { if (opt->dos_exe.force_stub) opt->overlay = opt->COPY_OVERLAY; else throwCantPack("can't pack new-exe"); } return true;}/*************************************************************************//**************************************************************************/staticunsigned optimize_relocs(upx_byte *b, const unsigned size, const upx_byte *relocs, const unsigned nrelocs, upx_byte *crel, bool *has_9a){ if (opt->exact) throwCantPackExact(); upx_byte * const crel_save = crel; unsigned i; unsigned seg_high = 0;#if 0 unsigned seg_low = 0xffffffff; unsigned off_low = 0xffffffff; unsigned off_high = 0; unsigned linear_low = 0xffffffff; unsigned linear_high = 0;#endif // pass 1 - find 0x9a bounds for (i = 0; i < nrelocs; i++) { unsigned addr = get_le32(relocs+4*i); if (addr >= size - 1) throwCantPack("unexpected relocation 1"); if (addr >= 3 && b[addr-3] == 0x9a) { unsigned seg = get_le16(b+addr); if (seg > seg_high) seg_high = seg;#if 0 if (seg < seg_low) seg_low = seg; unsigned off = get_le16(b+addr-2); if (off < off_low) off_low = off; if (off > off_high) off_high = off; unsigned l = (seg << 4) + off; if (l < linear_low) linear_low = l; if (l > linear_high) linear_high = l;#endif } } //printf("%d %d\n", seg_low, seg_high); //printf("%d %d\n", off_low, off_high); //printf("%d %d\n", linear_low, linear_high); // pass 2 - reloc crel += 4; // to be filled in later unsigned ones = 0; unsigned es = 0, di, t; i = 0; do { unsigned addr = get_le32(relocs+4*i); set_le16(crel,di = addr & 0x0f); set_le16(crel+2,(addr >> 4) - es); es = addr >> 4; crel += 4; for (++i; i < nrelocs; i++) { addr = get_le32(relocs+4*i); //printf ("%x\n",es*16+di); if ((addr - es*16 > 0xfffe) || (i == nrelocs - 1 && addr - es * 16 > 0xff00) ) { // segment change t = 1+(0xffff-di)/254; memset(crel,1,t); crel += t; ones += t-1; // -1 is used to help the assembly stuff break; } unsigned offs = addr - es*16; if (offs >= 3 && b[es*16 + offs-3] == 0x9a && offs > di + 3) { for (t = di; t < offs-3; t++) if (b[es*16+t] == 0x9a && get_le16(b+es*16+t+3) <= seg_high) break; if (t == offs-3) { // code 0: search for 0x9a *crel++ = 0; di = offs; *has_9a = true; continue; } } t = offs - di; if (t < 2) throwCantPack("unexpected relocation 2"); while (t >= 256) { // code 1: add 254, don't reloc *crel++ = 1; t -= 254; ones++; } *crel++ = (unsigned char) t; di = offs; } } while (i < nrelocs); *crel++ = 1; ones++; set_le16 (crel_save,ones); set_le16 (crel_save+2,seg_high); //OutputFile::dump("x.rel", crel_save, crel - crel_save); return (unsigned) (crel - crel_save);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -