⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i386-bsd.elf.execve-main.c

📁 UPX 源代码
💻 C
字号:
/* i386-bsd.elf.execve-main.c -- generic stub loader for *BSD using execve()   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>   John F. Reiser   <jreiser@users.sourceforge.net> */#include "include/bsd.h"/*************************************************************************// configuration section**************************************************************************/// mmap() the temporary output file#define USE_MMAP_FO/*************************************************************************// file util**************************************************************************/struct Extent {    int  size;  // must be first to match size[0] uncompressed size    char *buf;};#if !defined(USE_MMAP_FO)#if 1static __inline__ int xwrite(int fd, const void *buf, int count){    // note: we can assert(count > 0);    do {        int n = write(fd, buf, count);        if (n == -EINTR)            continue;        if (n <= 0)            break;        buf += n;               // gcc extension: add to void *        count -= n;    } while (count > 0);    return count;}#else#define xwrite(fd,buf,count)    ((count) - write(fd,buf,count))#endif#endif /* !USE_MMAP_FO *//*************************************************************************// util**************************************************************************/#if 1extern char *__attribute__((regparm(2), stdcall))  // be ruthlessupx_itoa(unsigned long v, char *buf);#else// Some versions of gcc optimize the division and/or remainder using// a multiplication by (2**32)/10, and use a relocatable 32-bit address// to reference the constant.  We require no relocations because we move// the code at runtime.  See upx_itoa.S for replacement [also smaller.]static char *upx_itoa(unsigned long v, char *buf){//    const unsigned TEN = 10;    volatile unsigned TEN = 10;  // an ugly way to achieve no relocation    char *p = buf;    {        unsigned long k = v;        do {            p++;            k /= TEN;        } while (k > 0);    }    buf = p;    *p = 0;    {        unsigned long k = v;        do {            *--p = '0' + k % TEN;            k /= TEN;        } while (k > 0);    }    return buf;}#endifstatic uint32_t ascii5(char *p, uint32_t v, unsigned n){    do {        unsigned char d = v % 32;        if (d >= 26) d -= 43;       // 43 == 'Z' - '0' + 1        *--p = (d += 'A');        v /= 32;    } while (--n > 0);    return v;}#if defined(__i386__)#  define SET2(p, c0, c1) \        * (unsigned short *) (p) = ((c1)<<8 | (c0))#  define SET4(p, c0, c1, c2, c3) \        * (uint32_t *) (p) = ((c3)<<24 | (c2)<<16 | (c1)<<8 | (c0))#  define SET3(p, c0, c1, c2) \        SET4(p, c0, c1, c2, 0)#else#  define SET2(p, c0, c1) \        (p)[0] = c0, (p)[1] = c1#  define SET3(p, c0, c1, c2) \        (p)[0] = c0, (p)[1] = c1, (p)[2] = c2#  define SET4(p, c0, c1, c2, c3) \        (p)[0] = c0, (p)[1] = c1, (p)[2] = c2, (p)[3] = c3#endif// go_self is a separate subroutine to spread the burden of local arrays.// Otherwise the size of the stack frame in upx_main exceeds 128 bytes,// which causes too many offsets to expand from 1 byte to 4.static int#if (ACC_CC_GNUC >= 0x030300)__attribute__((__noinline__, __used__, __stdcall__))#endifgo_self(char const *tmpname, char *argv[], char *envp[]){    // Old FreeBSD does not have /proc/self, so use /proc/<pid> instead.    // Open the temp file.    int const fdi = open(tmpname, O_RDONLY, 0);    if (0 <= fdi) {        // 17 chars for "/proc/PPPPP/fd/XX" should be enough, but we        // play safe in case there will be 32-bit pid_t at some time.        //char procself_buf[17+1];        char procself_buf[31+1];        // Compute name of temp fdi.        SET4(procself_buf + 0, '/', 'p', 'r', 'o');        SET4(procself_buf + 4, 'c', '/',  0 ,  0 );        {            char *const procself = upx_itoa(getpid(), procself_buf + 6);            SET4(procself, '/', 'f', 'd', '/');            upx_itoa(fdi, procself + 4);        }        // Check for working /proc/self/fd/X by accessing the        // temp file again, now via temp fdi.        if (UPX2 == (unsigned) access(procself_buf, R_OK | X_OK)) {            // Now it's safe to unlink the temp file (as it is still open).            unlink(tmpname);            // Set the file close-on-exec.            fcntl(fdi, F_SETFD, FD_CLOEXEC);            // Execute the original program via /proc/self/fd/X.            execve(procself_buf, (char const *const *)argv, (char const *const *)envp);            // NOTE: if we get here we've lost.        }        // The proc filesystem isn't working. No problem.        close(fdi);    }    return fdi;}/*************************************************************************// UPX & NRV stuff**************************************************************************/typedef void f_unfilter(    nrv_byte *,  // also addvalue    nrv_uint,    unsigned cto8  // junk in high 24 bits);typedef int f_expand(    const nrv_byte *src, nrv_uint  src_len,          nrv_byte *dst, nrv_uint *dst_len, int method );/*************************************************************************// upx_main - called by our entry code//// This function is optimized for size.**************************************************************************/void upx_main(    struct Extent xi,    f_expand *const f_decompress,    int junk2,    f_unfilter *const f_unf,    char *envp[],    char *argv[],    int argc) __asm__("upx_main");void upx_main(    struct Extent xi,    f_expand *const f_decompress,    int junk,    f_unfilter *const f_unf,    char *envp[],    char *argv[],    int argc){    // file descriptor    int fdo;    // decompression buffer    unsigned char *buf;    char *tmpname;    struct p_info header;    // temporary file name    char tmpname_buf[20];    (void)junk;    //    // ----- Step 0: set /proc/self using /proc/<pid> -----    //    //personality(PER_LINUX);    //    // ----- Step 1: prepare input file -----    //    // Read header.    {        register char *__d0, *__d1;        __asm__ __volatile__( "movsl; movsl; movsl"            : "=&D" (__d0), "=&S" (__d1)            : "0" (&header), "1" (xi.buf)            : "memory");        xi.buf   = __d1;        xi.size -= sizeof(header);    }    // Paranoia. Make sure this is actually our expected executable    // by checking the random program id. (The id is both stored    // in the header and patched into this stub.)    if (header.p_progid != UPX3)        goto error1;    //    // ----- Step 2: prepare temporary output file -----    //    tmpname = tmpname_buf;    SET4(tmpname + 0, '/', 't', 'm', 'p');    SET4(tmpname + 4, '/', 'u', 'p', 'x');    // Compute name of temporary output file in tmpname[].    // Protect against Denial-of-Service attacks.    {        char *p = tmpname_buf + sizeof(tmpname_buf) - 1;        // Compute the last 4 characters (20 bits) from getpid().        uint32_t r = ascii5(p, (uint32_t)getpid(), 4); *p = '\0'; p -= 4;        // Provide 4 random bytes from our program id.        r ^= header.p_progid;        // Mix in 4 runtime random bytes.        // Don't consume precious bytes from /dev/urandom.        {#if 1            struct timeval tv;            gettimeofday(&tv, 0);            r ^= (uint32_t) tv.tv_sec;            r ^= ((uint32_t) tv.tv_usec) << 12;      // shift into high-bits#else            // using adjtimex() may cause portability problems            struct timex tx;            adjtimex(&tx);            r ^= (uint32_t) tx.time.tv_sec;            r ^= ((uint32_t) tx.time.tv_usec) << 12; // shift into high-bits            r ^= (uint32_t) tx.errcnt;#endif        }        // Compute 7 more characters from the 32 random bits.        ascii5(p, r, 7);    }    // Just in case, remove the file.    {        int err = unlink(tmpname);        if (err != -ENOENT && err != 0)            goto error1;    }    // Create the temporary output file.#if defined(USE_MMAP_FO)    fdo = open(tmpname, O_RDWR | O_CREAT | O_EXCL, 0700);#else    fdo = open(tmpname, O_WRONLY | O_CREAT | O_EXCL, 0700);#endif#if 0    // Save some bytes of code - the ftruncate() below will fail anyway.    if (fdo < 0)        goto error;#endif    // Set expected uncompressed file size.    if (ftruncate(fdo, header.p_filesize) != 0)        goto error;    //    // ----- Step 3: setup memory -----    //#if defined(USE_MMAP_FO)    // FIXME: packer could set length    buf = (unsigned char *)mmap(0, header.p_filesize,        PROT_READ | PROT_WRITE, MAP_SHARED, fdo, 0);    if ((unsigned long) buf >= (unsigned long) -4095)        goto error;    // Decompressor can overrun the output by 3 bytes.    // Defend against SIGSEGV by using a scratch page.    // FIXME: packer could set address delta    mmap(buf + (PAGE_MASK & (header.p_filesize + ~PAGE_MASK)),        -PAGE_MASK, PROT_READ | PROT_WRITE,        MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0 );#else    // Temporary decompression buffer.    // FIXME: packer could set length    buf = mmap(0, (header.p_blocksize + OVERHEAD + ~PAGE_MASK) & PAGE_MASK,        PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0 );    if ((unsigned long) buf >= (unsigned long) -4095)        goto error;#endif    //    // ----- Step 4: decompress blocks -----    //    for (;;)    {        struct b_info h;        // Read and check block sizes.        {            register char *__d0, *__d1;            __asm__ __volatile__( "movsl; movsl; movsl"                : "=&D" (__d0), "=&S" (__d1)                : "0" (&h), "1" (xi.buf)                : "memory");            xi.buf   = __d1;            xi.size -= sizeof(h);        }        if (h.sz_unc == 0)                      // uncompressed size 0 -> EOF        {            if (h.sz_cpr != UPX_MAGIC_LE32)     // h.sz_cpr must be h->magic                goto error;            if (header.p_filesize != 0)         // all bytes must be written                goto error;            break;        }        //   Note: if sz_unc == sz_cpr then the block was not        //   compressible and is stored in its uncompressed form.        if (h.sz_cpr > h.sz_unc || h.sz_cpr > header.p_blocksize)            goto error;        // Now we have:        //   assert(h.sz_cpr <= h.sz_unc);        //   assert(h.sz_unc > 0 && h.sz_unc <= blocksize);        //   assert(h.sz_cpr > 0 && h.sz_cpr <= blocksize);        if (h.sz_cpr < h.sz_unc) { // Decompress block.            nrv_uint out_len = h.sz_unc;  // EOF for lzma            int i = (*f_decompress)((unsigned char *)xi.buf, h.sz_cpr, buf,                &out_len, *(int *)(void *)&h.b_method);            if (i != 0 || out_len != (nrv_uint)h.sz_unc)                goto error;            // Right now, unfilter is combined with decompression.            // (*f_unfilter)(buf, out_len, cto8);            (void)f_unf;        }        else        {            // Incompressible block#if defined(USE_MMAP_FO)            //memcpy(buf, xi.buf, h.sz_unc);            register unsigned long int __d0, __d1, __d2;            __asm__ __volatile__( "rep; movsb"                : "=&c" (__d0), "=&D" (__d1), "=&S" (__d2)                : "0" (h.sz_unc), "1" (buf), "2" (xi.buf)                : "memory");#endif        }#if defined(USE_MMAP_FO)        // unmap part of the output        munmap(buf, h.sz_unc);        buf     += h.sz_unc;#else        // write output file        if (xwrite(fdo, buf, h.sz_unc) != 0)            goto error;#endif        header.p_filesize -= h.sz_unc;        xi.buf  += h.sz_cpr;        xi.size -= h.sz_cpr;        if (xi.size < 0) {// error exit is here in the middle to keep the jumps short.        error:            (void) unlink(tmpname);        error1:            // Note: the kernel will close all open files and            //       unmap any allocated memory.            for (;;)                (void) exit(127);        }    }    //    // ----- Step 5: release resources -----    //#if !defined(USE_MMAP_FO)    // Free our temporary decompression buffer.    munmap(buf, malloc_args.ma_length);#endif    if (close(fdo) != 0)        goto error;    //    // ----- Step 6: try to start program via /proc/self/fd/X -----    //    // Many thanks to Andi Kleen <ak@muc.de> and    // Jamie Lokier <nospam@cern.ch> for this nice idea.    if (0 > go_self(tmpname, argv, envp))        goto error;    //    // ----- Step 7: start program in /tmp  -----    //    // Fork off a subprocess to clean up.    // We have to do this double-fork trick to keep a zombie from    // hanging around if the spawned original program doesn't check for    // subprocesses (as well as to prevent the real program from getting    // confused about this subprocess it shouldn't have).    // Thanks to Adam Ierymenko <api@one.net> for this solution.    if (fork() == 0)    {        if (fork() == 0)        {            // Sleep 3 seconds, then remove the temp file.            struct timespec ts; ts.tv_sec = UPX4; ts.tv_nsec = 0;            nanosleep(&ts, 0);            unlink(tmpname);        }        exit(0);    }    // Wait for the first fork()'d process to die.    waitpid(-1, (int *)0, 0);    // Execute the original program.    (void)argc;    execve(tmpname, (char const *const *)argv, (char const *const *)envp);    //    // ----- Step 8: error exit -----    //    // If we return from execve() there was an error. Give up.    goto error;}/*vi:ts=4:et:nowrap*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -