upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1, upx_uint64_t extra2) { assert(element_size > 0); if (element_size > UPX_RSIZE_MAX) throwCantPack("mem_size 1; take care"); if (n > UPX_RSIZE_MAX) throwCantPack("mem_size 2; take care"); if (extra1 > UPX_RSIZE_MAX) throwCantPack("mem_size 3; take care"); if (extra2 > UPX_RSIZE_MAX) throwCantPack("mem_size 4; take care"); upx_uint64_t bytes = element_size * n + extra1 + extra2; // cannot overflow if (bytes > UPX_RSIZE_MAX) throwCantPack("mem_size 5; take care"); return ACC_ICONV(upx_rsize_t, bytes); }
bool PackTos::canPack() { if (!readFileHeader()) return false; unsigned char buf[768]; fi->readx(buf, sizeof(buf)); checkAlreadyPacked(buf, sizeof(buf)); if (!checkFileHeader()) throwCantPack("unsupported header flags"); if (file_size < 1024) throwCantPack("program is too small"); return true; }
void PackWcle::encodeEntryTable() { unsigned count,object,n; upx_byte *p = ientries; n = 0; while (*p) { count = *p; n += count; if (p[1] == 0) // unused bundle p += 2; else if (p[1] == 3) // 32-bit bundle { object = get_le16(p+2)-1; set_le16(p+2,1); p += 4; for (; count; count--, p += 5) set_le32(p+1,IOT(object,my_base_address) + get_le32(p+1)); } else throwCantPack("unsupported bundle type in entry table"); } //if (Opt_debug) printf("%d entries encoded.\n",n); UNUSED(n); soentries = ptr_diff(p, ientries) + 1; oentries = ientries; ientries = NULL; }
bool PackCom::canPack() { unsigned char buf[128]; fi->readx(buf, sizeof(buf)); if (memcmp(buf,"MZ",2) == 0 || memcmp(buf,"ZM",2) == 0 // .exe || memcmp (buf,"\xff\xff\xff\xff",4) == 0) // .sys return false; if (!fn_has_ext(fi->getName(),"com")) return false; checkAlreadyPacked(buf, sizeof(buf)); if (file_size < 1024) throwCantPack("file is too small"); if (file_size > 0xFF00) throwCantPack("file is too big for dos/com"); return true; }
void PackArmPe::processTls(Interval *) // pass 1 { if ((sotls = ALIGN_UP(IDSIZE(PEDIR_TLS),4u)) == 0) return; // never should happen on wince throwCantPack("Static TLS entries found. Send a report please."); }
// common part of canPack(), enhanced by subclasses bool PackUnix::canPack() { if (exetype == 0) return false; #if defined(__unix__) // must be executable by owner if ((fi->st.st_mode & S_IXUSR) == 0) throwCantPack("file not executable; try 'chmod +x'"); #endif if (file_size < 4096) throwCantPack("file is too small"); // info: currently the header is 36 (32+4) bytes before EOF unsigned char buf[256]; fi->seek(-(off_t)sizeof(buf), SEEK_END); fi->readx(buf, sizeof(buf)); checkAlreadyPacked(buf, sizeof(buf)); return true; }
bool PackTos::checkFileHeader() { const unsigned f = ih.fh_flag; //printf("flags: 0x%x, text: %d, data: %d, bss: %d, sym: %d\n", f, (int)ih.fh_text, (int)ih.fh_data, (int)ih.fh_bss, (int)ih.fh_sym); if ((ih.fh_text & 1) || (ih.fh_data & 1)) throwCantPack("odd size values in text/data"); if (f & F_OS_SPECIAL) throwCantPack("I won't pack F_OS_SPECIAL programs"); if ((f & F_PROTMODE) > F_PROT_I) throwCantPack("invalid protection mode"); if ((f & F_PROTMODE) != F_PROT_P) { if (opt->force < 1) throwCantPack("no private memory protection; use option '-f' to force packing"); } if (f & F_SHTEXT) { if (opt->force < 1) throwCantPack("shared text segment; use option '-f' to force packing"); } #if 0 // fh_reserved seems to be unused if (ih.fh_reserved != 0) { if (opt->force < 1) throwCantPack("reserved header field set; use option '-f' to force packing"); } #endif return true; }
static const #include "stub/i086-dos16.sys.h" /************************************************************************* // **************************************************************************/ bool PackSys::canPack() { unsigned char buf[128]; fi->readx(buf, sizeof(buf)); if (memcmp (buf,"\xff\xff\xff\xff",4) != 0) return false; if (!fn_has_ext(fi->getName(),"sys")) return false; checkAlreadyPacked(buf, sizeof(buf)); if (file_size < 1024) throwCantPack("file is too small"); if (file_size > 0x10000) throwCantPack("file is too big for dos/sys"); return true; }
void PackVmlinuzI386::readKernel() { int klen = decompressKernel(); if (klen <= 0) throwCantPack("kernel decompression failed"); //OutputFile::dump("kernel.img", ibuf, klen); // copy the setup boot code setup_buf.alloc(setup_size); memcpy(setup_buf, obuf, setup_size); //OutputFile::dump("setup.img", setup_buf, setup_size); obuf.dealloc(); obuf.allocForCompression(klen); ph.u_len = klen; ph.filter = 0; }
void PackWcle::readObjectTable() { LeFile::readObjectTable(); // temporary copy of the object descriptors iobject_desc.alloc(objects*sizeof(*iobject_table)); memcpy(iobject_desc,iobject_table,objects*sizeof(*iobject_table)); unsigned ic,jc,virtual_size; for (ic = jc = virtual_size = 0; ic < objects; ic++) { jc += IOT(ic,npages); IOT(ic,my_base_address) = virtual_size; virtual_size += (IOT(ic,virtual_size)+mps-1) &~ (mps-1); } if (pages != jc) throwCantPack("bad page number"); }
void PackCom::patchLoader(OutputFile *fo, upx_byte *loader, int lsize, unsigned calls) { const int e_len = getLoaderSectionStart("COMCUTPO"); const int d_len = lsize - e_len; assert(e_len > 0 && e_len < 128); assert(d_len > 0 && d_len < 256); const unsigned upper_end = ph.u_len + ph.overlap_overhead + d_len + 0x100; unsigned stacksize = 0x60; if (upper_end + stacksize > 0xfffe) stacksize = 0x56; if (upper_end + stacksize > 0xfffe) throwCantPack("file is too big for dos/com"); linker->defineSymbol("calltrick_calls", calls); linker->defineSymbol("sp_limit", upper_end + stacksize); linker->defineSymbol("bytes_to_copy", ph.c_len + lsize); linker->defineSymbol("copy_source", ph.c_len + lsize + 0x100); linker->defineSymbol("copy_destination", upper_end); linker->defineSymbol("neg_e_len", 0 - e_len); linker->defineSymbol("NRV2B160", ph.u_len + ph.overlap_overhead); relocateLoader(); loader = getLoader(); // some day we could use the relocation stuff for patchPackHeader too patchPackHeader(loader,e_len); // write loader + compressed file fo->write(loader,e_len); // entry fo->write(obuf,ph.c_len); fo->write(loader+e_len,d_len); // decompressor #if 0 printf("%-13s: entry : %8ld bytes\n", getName(), (long) e_len); printf("%-13s: compressed : %8ld bytes\n", getName(), (long) ph.c_len); printf("%-13s: decompressor : %8ld bytes\n", getName(), (long) d_len); #endif }
// read full kernel into obuf[], gzip-decompress into ibuf[], // return decompressed size int PackVmlinuzI386::decompressKernel() { // read whole kernel image obuf.alloc(file_size); fi->seek(0, SEEK_SET); fi->readx(obuf, file_size); { const upx_byte *base = NULL; unsigned relocated = 0; // See startup_32: in linux/arch/i386/boot/compressed/head.S const upx_byte *p = &obuf[setup_size]; unsigned cpa_0 = 0; unsigned cpa_1 = 0; int j; if (0x205<=h.version) { cpa_0 = h.kernel_alignment; cpa_1 = 0u - cpa_0; } else for ((p = &obuf[setup_size]), (j= 0); j < 0x200; ++j, ++p) { if (0==memcmp("\x89\xeb\x81\xc3", p, 4) && 0==memcmp("\x81\xe3", 8+ p, 2)) { // movl %ebp,%ebx // addl $imm.w,%ebx // andl $imm.w,%ebx cpa_0 = 1+ get_te32( 4+ p); cpa_1 = get_te32(10+ p); break; } } for ((p = &obuf[setup_size]), (j= 0); j < 0x200; ++j, ++p) { if (0==memcmp("\x8d\x83", p, 2) // leal d32(%ebx),%eax && 0==memcmp("\xff\xe0", 6+ p, 2) // jmp *%eax ) { relocated = get_te32(2+ p); } if (0==memcmp("\xE8\x00\x00\x00\x00\x5D", p, 6)) { // "call 1f; 1f: pop %ebp" determines actual execution address. // linux-2.6.21 (spring 2007) and later; upx stub needs work // unless LOAD_PHYSICAL_ADDR is known. // Allowed code is: linux-2.6.23/arch/x86/head_32.S 2008-01-01 // call 1f // 1: popl %ebp // subl $1b, %ebp # 32-bit immediate // movl $LOAD_PHYSICAL_ADDR, %ebx // if (0==memcmp("\x81\xed", 6+ p, 2) // subl $imm.w,%ebp && 0==memcmp("\xbb", 12+ p, 1) ) { // movl $imm.w,%ebx physical_start = get_te32(13+ p); } else if (0==memcmp("\x81\xed", 6+ p, 2) // subl $imm.w,%ebp && is_pow2(cpa_0) && (0u-cpa_0)==cpa_1) { base = (5+ p) - get_te32(8+ p); config_physical_align = cpa_0; } else { throwCantPack("Unrecognized relocatable kernel"); } } // Find "ljmp $__BOOT_CS,$__PHYSICAL_START" if any. if (0==memcmp("\xEA\x00\x00", p, 3) && 0==(0xf & p[3]) && 0==p[4]) { /* whole megabyte < 16 MiB */ physical_start = get_te32(1+ p); break; } } if (base && relocated) { p = base + relocated; for (j = 0; j < 0x200; ++j, ++p) { if (0==memcmp("\x01\x9c\x0b", p, 3) // addl %ebx,d32(%ebx,%ecx) ) { page_offset = 0u - get_te32(3+ p); } if (0==memcmp("\x89\xeb", p, 2) // movl %ebp,%ebx && 0==memcmp("\x81\xeb", 2+ p, 2) // subl $imm32,%ebx ) { physical_start = get_te32(4+ p); } } } } checkAlreadyPacked(obuf + setup_size, UPX_MIN(file_size - setup_size, (off_t)1024)); int gzoff = setup_size; if (0x208<=h.version) { gzoff += h.payload_offset; } for (; gzoff < file_size; gzoff++) { // find gzip header (2 bytes magic + 1 byte method "deflated") int off = find(obuf + gzoff, file_size - gzoff, "\x1F\x8B\x08", 3); if (off < 0) break; gzoff += off; const int gzlen = (h.version < 0x208) ? (file_size - gzoff) : h.payload_length; if (gzlen < 256) break; // check gzip flag byte unsigned char flags = obuf[gzoff + 3]; if ((flags & 0xe0) != 0) // reserved bits set continue; //printf("found gzip header at offset %d\n", gzoff); // try to decompress int klen; int fd; off_t fd_pos; for (;;) { klen = -1; fd = -1; fd_pos = -1; // open fi->seek(gzoff, SEEK_SET); fd = dup(fi->getFd()); if (fd < 0) break; gzFile zf = gzdopen(fd, "rb"); if (zf == NULL) break; // estimate gzip-decompressed kernel size & alloc buffer if (ibuf.getSize() == 0) ibuf.alloc(gzlen * 3); // decompress klen = gzread(zf, ibuf, ibuf.getSize()); fd_pos = lseek(fd, 0, SEEK_CUR); gzclose(zf); fd = -1; if (klen != (int)ibuf.getSize()) break; // realloc and try again unsigned s = ibuf.getSize(); ibuf.dealloc(); ibuf.alloc(3 * s / 2); } if (fd >= 0) (void) close(fd); if (klen <= 0) continue; if (klen <= gzlen) continue; if (0x208<=h.version && 0==memcmp("\177ELF", ibuf, 4)) { // Full ELF in theory; for now, try to handle as .bin at physical_start. // Check for PT_LOAD.p_paddr being ascending and adjacent. Elf_LE32_Ehdr const *const ehdr = (Elf_LE32_Ehdr const *)(void const *)ibuf; Elf_LE32_Phdr const *phdr = (Elf_LE32_Phdr const *)(ehdr->e_phoff + (char const *)ehdr); Elf_LE32_Shdr const *shdr = (Elf_LE32_Shdr const *)(ehdr->e_shoff + (char const *)ehdr); unsigned hi_paddr = 0, lo_paddr = 0; unsigned delta_off = 0; for (unsigned j=0; j < ehdr->e_phnum; ++j, ++phdr) { if (phdr->PT_LOAD==phdr->p_type) { unsigned step = (hi_paddr + phdr->p_align - 1) & ~(phdr->p_align - 1); if (0==hi_paddr) { // first PT_LOAD if (physical_start!=phdr->p_paddr) { return 0; } delta_off = phdr->p_paddr - phdr->p_offset; lo_paddr = phdr->p_paddr; hi_paddr = phdr->p_filesz + phdr->p_paddr; } else if (step==phdr->p_paddr && delta_off==(phdr->p_paddr - phdr->p_offset)) { hi_paddr = phdr->p_filesz + phdr->p_paddr; } else { return 0; // Not equivalent to a .bin. Too complex for now. } } } // FIXME: ascending order is only a convention; might need sorting. for (unsigned j=1; j < ehdr->e_shnum; ++j) { if (shdr->SHT_PROGBITS==shdr->sh_type) { // SHT_REL might be intermixed if (shdr->SHF_EXECINSTR & shdr[j].sh_flags) { filter_len += shdr[j].sh_size; // FIXME: include sh_addralign } else { break; } } } memmove(ibuf, (lo_paddr - delta_off) + ibuf, hi_paddr - lo_paddr); // FIXME: set_size // FIXME: .bss ? Apparently handled by head.S } if (opt->force > 0) return klen; // some checks if (fd_pos != file_size) { //printf("fd_pos: %ld, file_size: %ld\n", (long)fd_pos, (long)file_size); // linux-2.6.21.5/arch/i386/boot/compressed/vmlinux.lds // puts .data.compressed ahead of .text, .rodata, etc; // so piggy.o need not be last in bzImage. Alas. //throwCantPack("trailing bytes after kernel image; use option '-f' to force packing"); } // see /usr/src/linux/arch/i386/kernel/head.S // 2.4.x: [cli;] cld; mov $...,%eax if (memcmp(ibuf, "\xFC\xB8", 2) == 0) goto head_ok; if (memcmp(ibuf, "\xFA\xFC\xB8", 3) == 0) goto head_ok; // 2.6.21.5 CONFIG_PARAVIRT mov %cs,%eax; test $3,%eax; jne ...; if (memcmp(ibuf, "\x8c\xc8\xa9\x03\x00\x00\x00\x0f\x85", 9) == 0) goto head_ok; if (memcmp(ibuf, "\x8c\xc8\xa8\x03\x0f\x85", 6) == 0) goto head_ok; // 2.6.x: [cli;] cld; lgdt ... if (memcmp(ibuf, "\xFC\x0F\x01", 3) == 0) goto head_ok; if (memcmp(ibuf, "\xFA\xFC\x0F\x01", 4) == 0) goto head_ok; // 2.6.x+grsecurity+strongswan+openwall+trustix: ljmp $0x10,... if (ibuf[0] == 0xEA && memcmp(ibuf+5, "\x10\x00", 2) == 0) goto head_ok; // x86_64 2.6.x if (0xB8==ibuf[0] // mov $...,%eax && 0x8E==ibuf[5] && 0xD8==ibuf[6] // mov %eax,%ds && 0x0F==ibuf[7] && 0x01==ibuf[8] && 020==(070 & ibuf[9]) // lgdtl && 0xB8==ibuf[14] // mov $...,%eax && 0x0F==ibuf[19] && 0xA2==ibuf[20] // cpuid ) goto head_ok; // cmpw $0x207,0x206(%esi) Debian vmlinuz-2.6.24-12-generic if (0==memcmp("\x66\x81\xbe\x06\x02\x00\x00\x07\x02", ibuf, 9)) goto head_ok; // testb $0x40,0x211(%esi) Fedora vmlinuz-2.6.25-0.218.rc8.git7.fc9.i686 if (0==memcmp("\xf6\x86\x11\x02\x00\x00\x40", ibuf, 7)) goto head_ok; // rex.W prefix for x86_64 if (0x48==ibuf[0]) throwCantPack("x86_64 bzImage is not yet supported"); throwCantPack("unrecognized kernel architecture; use option '-f' to force packing"); head_ok: // FIXME: more checks for special magic bytes in ibuf ??? // FIXME: more checks for kernel architecture ??? return klen; } return 0; }
void PackTos::pack(OutputFile *fo) { unsigned t; unsigned nrelocs = 0; unsigned relocsize = 0; unsigned overlay = 0; const unsigned i_text = ih.fh_text; const unsigned i_data = ih.fh_data; const unsigned i_sym = ih.fh_sym; const unsigned i_bss = ih.fh_bss; symbols.reset(); symbols.need_reloc = false; // prepare symbols for buildLoader() - worst case symbols.loop1.init(65536 + 1); symbols.loop2.init((160 - 1) / 4); symbols.loop3.init(65536 + 1); symbols.up21_d4 = 65536 + 1; symbols.up21_a6 = 65536 + 1; symbols.up31_base_d4 = 65536 + 1; symbols.up31_base_a6 = 65536 + 1; // read file const unsigned isize = file_size - i_sym; ibuf.alloc(isize); fi->seek(FH_SIZE, SEEK_SET); // read text + data t = i_text + i_data; fi->readx(ibuf,t); // skip symbols if (i_sym && opt->exact) throwCantPackExact(); fi->seek(i_sym,SEEK_CUR); // read relocations + overlay overlay = file_size - (FH_SIZE + i_text + i_data + i_sym); fi->readx(ibuf+t,overlay); #if 0 || (TESTING) printf("text: %d, data: %d, sym: %d, bss: %d, flags=0x%x\n", i_text, i_data, i_sym, i_bss, (int)ih.fh_flag); printf("xx1 reloc: %d, overlay: %d, fixup: %d\n", relocsize, overlay, overlay >= 4 ? (int)get_be32(ibuf+t) : -1); #endif // Check relocs (see load_and_reloc() in freemint/sys/memory.c). // Must work around TOS bugs and lots of broken programs. if (overlay < 4) { // Bug workaround: Whatever this is, silently keep it in // the (unused) relocations for byte-identical unpacking. relocsize = overlay; overlay = 0; } else if (get_be32(ibuf+t) == 0) { // Bug workaround - check the empty fixup before testing fh_reloc. relocsize = 4; overlay -= 4; } else if (ih.fh_reloc != 0) relocsize = 0; else { int r = check_relocs(ibuf+t, overlay, t, &nrelocs, &relocsize, &overlay); if (r != 0) throwCantPack("bad relocation table"); symbols.need_reloc = true; } #if 0 || (TESTING) printf("xx2: %d relocs: %d, overlay: %d, t: %d\n", nrelocs, relocsize, overlay, t); #endif checkOverlay(overlay); // Append original fileheader. t += relocsize; ih.fh_sym = 0; // we stripped all symbols memcpy(ibuf+t, &ih, FH_SIZE); t += FH_SIZE; #if 0 || (TESTING) printf("xx3 reloc: %d, overlay: %d, t: %d\n", relocsize, overlay, t); #endif assert(t <= isize); // Now the data in ibuf[0..t] looks like this: // text + data + relocs + original file header // After compression this will become the first part of the // data segement. The second part will be the decompressor. // alloc buffer (4096 is for decompressor and the various alignments) obuf.allocForCompression(t, 4096); // prepare packheader ph.u_len = t; // prepare filter Filter ft(ph.level); // compress (max_match = 65535) upx_compress_config_t cconf; cconf.reset(); cconf.conf_ucl.max_match = 65535; cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28 KiB stack compressWithFilters(&ft, 512, &cconf); // // multipass buildLoader() // // save initial loader const unsigned initial_lsize = getLoaderSize(); unsigned last_lsize = initial_lsize; MemBuffer last_loader(last_lsize); memcpy(last_loader, getLoader(), last_lsize); unsigned o_text, o_data, o_bss; unsigned e_len, d_len, d_off; for (;;) { // The decompressed data will now get placed at this offset: unsigned offset = (ph.u_len + ph.overlap_overhead) - ph.c_len; // get loader const unsigned lsize = getLoaderSize(); e_len = getLoaderSectionStart("CUTPOINT"); d_len = lsize - e_len; assert((e_len & 3) == 0 && (d_len & 1) == 0); // compute section sizes o_text = e_len; o_data = ph.c_len; o_bss = i_bss; // word align len of compressed data while (o_data & 1) { obuf[o_data++] = 0; offset++; } // append decompressor (part 2 of loader) d_off = o_data; ////memcpy(obuf + d_off, getLoader() + e_len, d_len); // must be done after relocation o_data += d_len; // dword align the len of the final data segment while (o_data & 3) { obuf[o_data++] = 0; offset++; } // dword align offset while (offset & 3) offset++; // new bss if (i_text + i_data + i_bss > o_text + o_data + o_bss) o_bss = (i_text + i_data + i_bss) - (o_text + o_data); // dirty bss unsigned dirty_bss = (o_data + offset) - (i_text + i_data); //printf("real dirty_bss: %d\n", dirty_bss); // dword align (or 16 - for speedup when clearing the dirty bss) const unsigned dirty_bss_align = opt->small ? 4 : 16; while (dirty_bss & (dirty_bss_align - 1)) dirty_bss++; // adjust bss, assert room for some stack unsigned stack = 512 + getDecompressorWrkmemSize(); if (dirty_bss + stack > o_bss) o_bss = dirty_bss + stack; // dword align the len of the final bss segment while (o_bss & 3) o_bss++; // update symbols for buildLoader() if (opt->small) { symbols.loop1.init(o_data / 4); symbols.loop2.init(0); } else { symbols.loop1.init(o_data / 160); symbols.loop2.init((o_data % 160) / 4); } symbols.loop3.init(dirty_bss / dirty_bss_align); symbols.up21_d4 = o_data + offset; symbols.up31_base_d4 = d_off + offset; symbols.up21_a6 = symbols.up21_d4 - (i_text + i_data); symbols.up31_base_a6 = symbols.up31_base_d4 - (i_text + i_data); assert((int)symbols.up21_a6 > 0); assert((int)symbols.up31_base_a6 > 0); const unsigned c = linker->getSymbolOffset("code_on_stack"); unsigned d; d = linker->getSymbolOffset("flush_cache_rts") - c; symbols.flush_cache_rts_offset = d; d = linker->getSymbolOffset("clear_dirty_stack_loop") - c; symbols.clear_dirty_stack_len = (d + 3) / 4 + 32 - 1; d = linker->getSymbolOffset("code_on_stack_end") - c; symbols.copy_to_stack_len = d / 2 - 1; // now re-build loader buildLoader(&ft); unsigned new_lsize = getLoaderSize(); //printf("buildLoader %d %d\n", new_lsize, initial_lsize); assert(new_lsize <= initial_lsize); if (new_lsize == last_lsize && memcmp(getLoader(), last_loader, last_lsize) == 0) break; last_lsize = new_lsize; memcpy(last_loader, getLoader(), last_lsize); } // // define symbols and reloc // defineDecompressorSymbols(); linker->defineSymbol("loop1_count", symbols.loop1.value); linker->defineSymbol("loop2_count", symbols.loop2.value); linker->defineSymbol("loop3_count", symbols.loop3.value); linker->defineSymbol("orig_p_tlen", i_text); linker->defineSymbol("orig_p_dlen", i_data); linker->defineSymbol("orig_p_blen", i_bss); if (symbols.up21_a6 <= 32767) linker->defineSymbol("up21_a6", symbols.up21_a6); else linker->defineSymbol("up21_d4", symbols.up21_d4); if (symbols.up31_a6 <= 32767) linker->defineSymbol("up31_a6", symbols.up31_a6); else if (symbols.up31_d4 <= 32767) linker->defineSymbol("up31_d4", symbols.up31_d4); else if (symbols.up31_a6 <= 65534) linker->defineSymbol("up31_a6", symbols.up31_a6 - 32767); else linker->defineSymbol("up31_d4", symbols.up31_d4); #if 0 printf("relocsize = %d\n", relocsize); printf("upx21(d4) = %d\n", symbols.up21_d4); printf("upx21(a6) = %d\n", symbols.up21_a6); printf("upx31(d4) = %d\n", symbols.up31_d4); printf("upx31(a6) = %d\n", symbols.up31_a6); #endif linker->defineSymbol("flush_cache_rts_offset", symbols.flush_cache_rts_offset); linker->defineSymbol("copy_to_stack_len", symbols.copy_to_stack_len); linker->defineSymbol("clear_dirty_stack_len", symbols.clear_dirty_stack_len); relocateLoader(); // // write // // set new file_hdr memcpy(&oh, &ih, FH_SIZE); if (opt->atari_tos.split_segments) { oh.fh_text = o_text; oh.fh_data = o_data; } else { // put everything into the text segment oh.fh_text = o_text + o_data; oh.fh_data = 0; } oh.fh_bss = o_bss; oh.fh_sym = 0; oh.fh_reserved = 0; // only keep the following flags: oh.fh_flag = ih.fh_flag & (F_FASTLOAD | F_ALTALLOC | F_SMALLTPA | F_ALLOCZERO | F_KEEP); // add an empty relocation fixup to workaround a bug in some TOS versions oh.fh_reloc = 0; #if 0 || (TESTING) printf("old text: %6d, data: %6d, bss: %6d, reloc: %d, overlay: %d\n", i_text, i_data, i_bss, relocsize, overlay); printf("new text: %6d, data: %6d, bss: %6d, flag=0x%x\n", o_text, o_data, o_bss, (int)oh.fh_flag); linker->dumpSymbols(); #endif // prepare loader MemBuffer loader(o_text); memcpy(loader, getLoader(), o_text); patchPackHeader(loader, o_text); // write new file header, loader and compressed file fo->write(&oh, FH_SIZE); fo->write(loader, o_text); // entry if (opt->debug.dump_stub_loader) OutputFile::dump(opt->debug.dump_stub_loader, loader, o_text); memcpy(obuf + d_off, getLoader() + e_len, d_len); // copy decompressor fo->write(obuf, o_data); // compressed + decompressor // write empty relocation fixup fo->write("\x00\x00\x00\x00", 4); // verify verifyOverlappingDecompression(); // copy the overlay copyOverlay(fo, overlay, &obuf); // finally check the compression ratio if (!checkFinalCompressionRatio(fo)) throwNotCompressible(); }
void PackTmt::pack(OutputFile *fo) { big_relocs = 0; Packer::handleStub(fi,fo,adam_offset); const unsigned usize = ih.imagesize; const unsigned rsize = ih.relocsize; ibuf.alloc(usize+rsize+128); obuf.allocForCompression(usize+rsize+128); MemBuffer wrkmem; wrkmem.alloc(rsize+EXTRA_INFO); // relocations fi->seek(adam_offset+sizeof(ih),SEEK_SET); fi->readx(ibuf,usize); fi->readx(wrkmem+4,rsize); const unsigned overlay = file_size - fi->tell(); if (find_le32(ibuf,128,get_le32("UPX ")) >= 0) throwAlreadyPacked(); if (rsize == 0) throwCantPack("file is already compressed with another packer"); checkOverlay(overlay); unsigned relocsize = 0; //if (rsize) { for (unsigned ic=4; ic<=rsize; ic+=4) set_le32(wrkmem+ic,get_le32(wrkmem+ic)-4); relocsize = ptr_diff(optimizeReloc32(wrkmem+4,rsize/4,wrkmem,ibuf,1,&big_relocs), wrkmem); } wrkmem[relocsize++] = 0; set_le32(wrkmem+relocsize,ih.entry); // save original entry point relocsize += 4; set_le32(wrkmem+relocsize,relocsize+4); relocsize += 4; memcpy(ibuf+usize,wrkmem,relocsize); // prepare packheader ph.u_len = usize + relocsize; // prepare filter Filter ft(ph.level); ft.buf_len = usize; // compress upx_compress_config_t cconf; cconf.reset(); // limit stack size needed for runtime decompression cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28 KiB stack compressWithFilters(&ft, 512, &cconf); const unsigned lsize = getLoaderSize(); const unsigned s_point = getLoaderSection("TMTMAIN1"); int e_len = getLoaderSectionStart("TMTCUTPO"); const unsigned d_len = lsize - e_len; assert(e_len > 0 && s_point > 0); // patch loader linker->defineSymbol("original_entry", ih.entry); defineDecompressorSymbols(); defineFilterSymbols(&ft); linker->defineSymbol("bytes_to_copy", ph.c_len + d_len); linker->defineSymbol("copy_dest", 0u - (ph.u_len + ph.overlap_overhead + d_len - 1)); linker->defineSymbol("copy_source", ph.c_len + lsize - 1); //fprintf(stderr,"\nelen=%x dlen=%x copy_len=%x copy_to=%x oo=%x jmp_pos=%x ulen=%x c_len=%x \n\n", // e_len,d_len,copy_len,copy_to,ph.overlap_overhead,jmp_pos,ph.u_len,ph.c_len); linker->defineSymbol("TMTCUTPO", ph.u_len + ph.overlap_overhead); relocateLoader(); MemBuffer loader(lsize); memcpy(loader,getLoader(),lsize); patchPackHeader(loader,e_len); memcpy(&oh,&ih,sizeof(oh)); oh.imagesize = ph.c_len + lsize; // new size oh.entry = s_point; // new entry point oh.relocsize = 4; // write loader + compressed file fo->write(&oh,sizeof(oh)); fo->write(loader,e_len); fo->write(obuf,ph.c_len); fo->write(loader+lsize-d_len,d_len); // decompressor char rel_entry[4]; set_le32(rel_entry,5 + s_point); fo->write(rel_entry,sizeof (rel_entry)); // verify verifyOverlappingDecompression(); // copy the overlay copyOverlay(fo, overlay, &obuf); // finally check the compression ratio if (!checkFinalCompressionRatio(fo)) throwNotCompressible(); }
void throwCantUnpack(const char *msg) { // UGLY, but makes things easier throwCantPack(msg); }
void throwCantPackExact() { throwCantPack("option '--exact' does not work with this file"); }
void PackWcle::pack(OutputFile *fo) { handleStub(fo); if (ih.byte_order || ih.word_order || ih.exe_format_level || ih.cpu_type < 2 || ih.cpu_type > 5 || ih.target_os != 1 || ih.module_type != 0x200 || ih.object_iterate_data_map_offset || ih.resource_entries || ih.module_directives_entries || ih.imported_modules_count || ih.object_table_entries > 255) throwCantPack("watcom/le: unexpected value in header"); readObjectTable(); readPageMap(); readResidentNames(); readEntryTable(); readFixupPageTable(); readFixups(); readImage(); readNonResidentNames(); // if (find_le32(iimage,20,get_le32("UPX ")) >= 0) if (find_le32(iimage,UPX_MIN(soimage,256u),UPX_MAGIC_LE32) >= 0) throwAlreadyPacked(); if (ih.init_ss_object != objects) throwCantPack("the stack is not in the last object"); preprocessFixups(); const unsigned text_size = IOT(ih.init_cs_object-1,npages) * mps; const unsigned text_vaddr = IOT(ih.init_cs_object-1,my_base_address); // attach some useful data at the end of preprocessed fixups ifixups[sofixups++] = (unsigned char) (ih.automatic_data_object & 0xff); unsigned ic = objects*sizeof(*iobject_table); memcpy(ifixups+sofixups,iobject_desc,ic); iobject_desc.dealloc(); sofixups += ic; set_le32(ifixups+sofixups,ih.init_esp_offset+IOT(ih.init_ss_object-1,my_base_address)); // old stack pointer set_le32(ifixups+sofixups+4,ih.init_eip_offset+text_vaddr); // real entry point set_le32(ifixups+sofixups+8,mps*pages); // virtual address of unpacked relocations ifixups[sofixups+12] = (unsigned char) (unsigned) objects; sofixups += 13; // prepare filter Filter ft(ph.level); ft.buf_len = text_size; ft.addvalue = text_vaddr; // compress encodeImage(&ft); const unsigned lsize = getLoaderSize(); neweip = getLoaderSection("WCLEMAIN"); int e_len = getLoaderSectionStart("WCLECUTP"); const unsigned d_len = lsize - e_len; assert(e_len > 0 && e_len < RESERVED); memmove(oimage+e_len,oimage+RESERVED,soimage); soimage += lsize; opages = (soimage+mps-1)/mps; oh.bytes_on_last_page = soimage%mps; encodeObjectTable(); encodeFixups(); encodeFixupPageTable(); encodePageMap(); encodeEntryTable(); encodeResidentNames(); encodeNonResidentNames(); // patch loader ic = (OOT(0,virtual_size) - d_len) &~ 15; assert(ic > ((ph.u_len + ph.overlap_overhead + 31) &~ 15)); linker->defineSymbol("WCLECUTP", ic); linker->defineSymbol("original_entry", ih.init_eip_offset + text_vaddr); linker->defineSymbol("original_stack", ih.init_esp_offset + IOT(ih.init_ss_object - 1, my_base_address)); linker->defineSymbol("start_of_relocs", mps*pages); defineDecompressorSymbols(); defineFilterSymbols(&ft); linker->defineSymbol("filter_buffer_start", text_vaddr); unsigned jpos = (((ph.c_len + 3) &~ 3) + d_len + 3) / 4; linker->defineSymbol("words_to_copy", jpos); linker->defineSymbol("copy_dest", ((ic + d_len + 3) &~ 3) - 4); linker->defineSymbol("copy_source", e_len + jpos * 4 - 4); relocateLoader(); MemBuffer loader(lsize); memcpy(loader, getLoader(), lsize); patchPackHeader(loader, lsize); memcpy(oimage, loader, e_len); memcpy(oimage + soimage - d_len, loader + e_len, d_len); writeFile(fo, opt->watcom_le.le); // verify verifyOverlappingDecompression(oimage + e_len, oimage.getSize() - e_len); // copy the overlay const unsigned overlaystart = ih.data_pages_offset + exe_offset + getImageSize(); const unsigned overlay = file_size - overlaystart - ih.non_resident_name_table_length; checkOverlay(overlay); copyOverlay(fo, overlay, &oimage); // finally check the compression ratio if (!checkFinalCompressionRatio(fo)) throwNotCompressible(); }
void PackWcle::preprocessFixups() { big_relocs = 0; unsigned ic,jc; Array(unsigned, counts, objects+2); countFixups(counts); for (ic = jc = 0; ic < objects; ic++) jc += counts[ic]; if (jc == 0) { // FIXME: implement this throwCantPack("files without relocations are not supported"); } ByteArray(rl, jc); ByteArray(srf, counts[objects+0]+1); ByteArray(slf, counts[objects+1]+1); upx_byte *selector_fixups = srf; upx_byte *selfrel_fixups = slf; unsigned rc = 0; upx_byte *fix = ifixups; for (ic = jc = 0; ic < pages; ic++) { while ((unsigned)(fix - ifixups) < get_le32(ifpage_table+ic+1)) { const int fixp2 = get_le16_signed(fix+2); unsigned value; switch (*fix) { case 2: // selector fixup if (fixp2 < 0) { // cross page selector fixup dputc('S',stdout); fix += 5; break; } dputc('s',stdout); memcpy(selector_fixups,"\x8C\xCB\x66\x89\x9D",5); // mov bx, cs ; mov [xxx+ebp], bx if (IOT(fix[4]-1,flags) & LEOF_WRITE) selector_fixups[1] = 0xDB; // ds set_le32(selector_fixups+5,jc+fixp2); selector_fixups += 9; fix += 5; break; case 5: // 16-bit offset if ((unsigned)fixp2 < 4096 && IOT(fix[4]-1,my_base_address) == jc) dputc('6',stdout); else throwCantPack("unsupported 16-bit offset relocation"); fix += (fix[1] & 0x10) ? 9 : 7; break; case 6: // 16:32 pointer if (fixp2 < 0) { // cross page pointer fixup dputc('P',stdout); fix += (fix[1] & 0x10) ? 9 : 7; break; } dputc('p',stdout); memcpy(iimage+jc+fixp2,fix+5,(fix[1] & 0x10) ? 4 : 2); set_le32(rl+4*rc++,jc+fixp2); set_le32(iimage+jc+fixp2,get_le32(iimage+jc+fixp2)+IOT(fix[4]-1,my_base_address)); memcpy(selector_fixups,"\x8C\xCA\x66\x89\x95",5); if (IOT(fix[4]-1,flags) & LEOF_WRITE) selector_fixups[1] = 0xDA; // ds set_le32(selector_fixups+5,jc+fixp2+4); selector_fixups += 9; fix += (fix[1] & 0x10) ? 9 : 7; break; case 7: // 32-bit offset if (fixp2 < 0) { fix += (fix[1] & 0x10) ? 9 : 7; break; } //if (memcmp(iimage+jc+fixp2,fix+5,(fix[1] & 0x10) ? 4 : 2)) // throwCantPack("illegal fixup offset"); // work around a pmwunlite bug: remove duplicated fixups // FIXME: fix the other cases too if (rc == 0 || get_le32(rl+4*rc-4) != jc+fixp2) { set_le32(rl+4*rc++,jc+fixp2); set_le32(iimage+jc+fixp2,get_le32(iimage+jc+fixp2)+IOT(fix[4]-1,my_base_address)); } fix += (fix[1] & 0x10) ? 9 : 7; break; case 8: // 32-bit self relative fixup if (fixp2 < 0) { // cross page self relative fixup dputc('R',stdout); fix += (fix[1] & 0x10) ? 9 : 7; break; } value = get_le32(fix+5); if (fix[1] == 0) value &= 0xffff; set_le32(iimage+jc+fixp2,(value+IOT(fix[4]-1,my_base_address))-jc-fixp2-4); set_le32(selfrel_fixups,jc+fixp2); selfrel_fixups += 4; dputc('r',stdout); fix += (fix[1] & 0x10) ? 9 : 7; break; default: throwCantPack("unsupported fixup record"); } } jc += mps; } // resize ifixups if it's too small if (sofixups < 1000) { delete[] ifixups; ifixups = new upx_byte[1000]; } fix = optimizeReloc32 (rl,rc,ifixups,iimage,1,&big_relocs); has_extra_code = srf != selector_fixups; // FIXME: this could be removed if has_extra_code = false // but then we'll need a flag *selector_fixups++ = 0xC3; // ret memcpy(fix,srf,selector_fixups-srf); // copy selector fixup code fix += selector_fixups-srf; memcpy(fix,slf,selfrel_fixups-slf); // copy self-relative fixup positions fix += selfrel_fixups-slf; set_le32(fix,0xFFFFFFFFUL); fix += 4; sofixups = ptr_diff(fix, ifixups); }
void throwFilterException() { throwCantPack("filter problem"); }
void PackArmPe::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 != 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; } // 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; */ 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 static const char* symbols_to_relocate[] = { "ONAM", "BIMP", "BREL", "FIBE", "FIBS", "ENTR", "DST0", "SRC0" }; for (unsigned s2r = 0; s2r < TABLESIZE(symbols_to_relocate); s2r++) { unsigned off = linker->getSymbolOffset(symbols_to_relocate[s2r]); 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; const unsigned onam = ncsection + soxrelocs + ih.imagebase; linker->defineSymbol("start_of_dll_names", onam); linker->defineSymbol("start_of_imports", ih.imagebase + rvamin + cimports); linker->defineSymbol("start_of_relocs", crelocs + rvamin + ih.imagebase); linker->defineSymbol("filter_buffer_end", ih.imagebase + ih.codebase + ih.codesize); linker->defineSymbol("filter_buffer_start", ih.imagebase + ih.codebase); linker->defineSymbol("original_entry", ih.entry + ih.imagebase); 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); 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; oh.database = osection[2].vaddr; oh.codesize = osection[1].vsize; oh.codebase = osection[1].vaddr; 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(); }