Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
// 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;
}
Esempio n. 4
0
File: p_sys.cpp Progetto: BpLife/upx
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;
}
Esempio n. 5
0
// 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;
}