1
0
mirror of https://github.com/upx/upx synced 2025-09-28 19:06:07 +08:00

Cleaned up the Linux C stub loaders by putting more stuff into linux.hh.

committer: mfx <mfx> 962045590 +0000
This commit is contained in:
Markus F.X.J. Oberhumer 2000-06-26 18:53:10 +00:00
parent 957ef351c4
commit 51b162f069
10 changed files with 150 additions and 116 deletions

View File

@ -1,3 +1,5 @@
*.00?
*.upx *.upx
.gdbinit
upx upx
upx.map upx.map

View File

@ -120,6 +120,8 @@ void PackLinuxI386elf::patchLoader()
// stub/scripts/setfold.pl puts address of 'fold_begin' in phdr[1].p_offset // stub/scripts/setfold.pl puts address of 'fold_begin' in phdr[1].p_offset
off_t const fold_begin = phdr[1].p_offset; off_t const fold_begin = phdr[1].p_offset;
assert(fold_begin > 0);
assert(fold_begin < (off_t)lsize);
MemBuffer cprLoader(lsize); MemBuffer cprLoader(lsize);
// compress compiled C-code portion of loader // compress compiled C-code portion of loader

View File

@ -101,6 +101,8 @@ void PackLinuxI386sh::patchLoader()
// stub/scripts/setfold.pl puts address of 'fold_begin' in phdr[1].p_offset // stub/scripts/setfold.pl puts address of 'fold_begin' in phdr[1].p_offset
off_t const fold_begin = phdri[1].p_offset; off_t const fold_begin = phdri[1].p_offset;
assert(fold_begin > 0);
assert(fold_begin < (off_t)lsize);
MemBuffer cprLoader(lsize); MemBuffer cprLoader(lsize);
// compress compiled C-code portion of loader // compress compiled C-code portion of loader

View File

@ -425,6 +425,8 @@ void PackLinuxI386::patchLoader()
// stub/scripts/setfold.pl puts address of 'fold_begin' in phdr[1].p_offset // stub/scripts/setfold.pl puts address of 'fold_begin' in phdr[1].p_offset
off_t const fold_begin = phdr[1].p_offset; off_t const fold_begin = phdr[1].p_offset;
assert(fold_begin > 0);
assert(fold_begin < (off_t)lsize);
MemBuffer cprLoader(lsize); MemBuffer cprLoader(lsize);
// compress compiled C-code portion of loader // compress compiled C-code portion of loader

View File

@ -188,24 +188,21 @@ l_w32pe.h: l_w32pe.asx
l_lx_n2b.h: l_lx_exec.c l_xe_n2b.o l_lx_exec86.lds Makefile l_lx_n2b.h: l_lx_exec.c l_xe_n2b.o l_lx_exec86.lds Makefile
$(CC_LINUX) -DNRV2B -o $T.o -c $< $(CC_LINUX) -DNRV2B -o $T.o -c $<
ld -T l_lx_exec86.lds -Map $T.map -o $T.bin \ ld -T l_lx_exec86.lds -Map $T.map -o $T.bin l_xe_n2b.o $T.o
l_xe_n2b.o $T.o
$(SETFOLD) $T.bin $(SETFOLD) $T.bin
$(BRANDELF) $T.bin $(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386exec_nrv2b_loader $@ $(BIN2H) $T.bin linux_i386exec_nrv2b_loader $@
l_le_n2b.h: l_lx_elf.c l_6e_n2b.o l_lx_elf86.lds l_le_n2b.h: l_lx_elf.c l_6e_n2b.o l_lx_elf86.lds
$(CC_LINUX) -DNRV2B -o $T.o -c $< $(CC_LINUX) -DNRV2B -o $T.o -c $<
ld -T l_lx_elf86.lds -Map $T.map -o $T.bin \ ld -T l_lx_elf86.lds -Map $T.map -o $T.bin l_6e_n2b.o $T.o
l_6e_n2b.o $T.o
$(SETFOLD) $T.bin $(SETFOLD) $T.bin
$(BRANDELF) $T.bin $(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386elf_nrv2b_loader $@ $(BIN2H) $T.bin linux_i386elf_nrv2b_loader $@
l_sh_n2b.h: l_lx_sh.c l_6h_n2b.o l_lx_sh86.lds l_sh_n2b.h: l_lx_sh.c l_6h_n2b.o l_lx_sh86.lds
$(CC_LINUX) -DNRV2B -o $T.o -c $< $(CC_LINUX) -DNRV2B -o $T.o -c $<
ld -T l_lx_sh86.lds -Map $T.map -o $T.bin \ ld -T l_lx_sh86.lds -Map $T.map -o $T.bin l_6h_n2b.o $T.o
l_6h_n2b.o $T.o
$(SETFOLD) $T.bin $(SETFOLD) $T.bin
$(BRANDELF) $T.bin $(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386sh_nrv2b_loader $@ $(BIN2H) $T.bin linux_i386sh_nrv2b_loader $@
@ -222,24 +219,21 @@ l_6h_n2b.o: l_lx_sh86.asm
l_lx_n2d.h: l_lx_exec.c l_xe_n2d.o l_lx_exec86.lds l_lx_n2d.h: l_lx_exec.c l_xe_n2d.o l_lx_exec86.lds
$(CC_LINUX) -DNRV2D -o $T.o -c $< $(CC_LINUX) -DNRV2D -o $T.o -c $<
ld -T l_lx_exec86.lds -Map $T.map -o $T.bin \ ld -T l_lx_exec86.lds -Map $T.map -o $T.bin l_xe_n2d.o $T.o
l_xe_n2d.o $T.o
$(SETFOLD) $T.bin $(SETFOLD) $T.bin
$(BRANDELF) $T.bin $(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386exec_nrv2d_loader $@ $(BIN2H) $T.bin linux_i386exec_nrv2d_loader $@
l_le_n2d.h: l_lx_elf.c l_6e_n2d.o l_lx_elf86.lds l_le_n2d.h: l_lx_elf.c l_6e_n2d.o l_lx_elf86.lds
$(CC_LINUX) -DNRV2D -o $T.o -c $< $(CC_LINUX) -DNRV2D -o $T.o -c $<
ld -T l_lx_elf86.lds -Map $T.map -o $T.bin \ ld -T l_lx_elf86.lds -Map $T.map -o $T.bin l_6e_n2d.o $T.o
l_6e_n2d.o $T.o
$(SETFOLD) $T.bin $(SETFOLD) $T.bin
$(BRANDELF) $T.bin $(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386elf_nrv2d_loader $@ $(BIN2H) $T.bin linux_i386elf_nrv2d_loader $@
l_sh_n2d.h: l_lx_sh.c l_6h_n2d.o l_lx_sh86.lds l_sh_n2d.h: l_lx_sh.c l_6h_n2d.o l_lx_sh86.lds
$(CC_LINUX) -DNRV2D -o $T.o -c $< $(CC_LINUX) -DNRV2D -o $T.o -c $<
ld -T l_lx_sh86.lds -Map $T.map -o $T.bin \ ld -T l_lx_sh86.lds -Map $T.map -o $T.bin l_6h_n2d.o $T.o
l_6h_n2d.o $T.o
$(SETFOLD) $T.bin $(SETFOLD) $T.bin
$(BRANDELF) $T.bin $(BRANDELF) $T.bin
$(BIN2H) $T.bin linux_i386sh_nrv2d_loader $@ $(BIN2H) $T.bin linux_i386sh_nrv2d_loader $@

View File

@ -31,10 +31,6 @@
*/ */
#if !defined(__linux__) || !defined(__i386__)
# error "this stub must be compiled under linux/i386"
#endif
#include "linux.hh" #include "linux.hh"
@ -46,9 +42,6 @@
// it at an address different from it load address: there must be no // it at an address different from it load address: there must be no
// static data, and no string constants. // static data, and no string constants.
#define PAGEMASK (~0u<<12) // discards the offset, keeps the page
#define PAGESIZE ( 1u<<12)
#define MAX_ELF_HDR 512 // Elf32_Ehdr + n*Elf32_Phdr must fit in this #define MAX_ELF_HDR 512 // Elf32_Ehdr + n*Elf32_Phdr must fit in this
@ -188,7 +181,7 @@ make_hatch(Elf32_Phdr const *const phdr)
// Try page fragmentation just beyond .text . // Try page fragmentation just beyond .text .
if ( ( (hatch = (void *)(phdr->p_memsz + phdr->p_vaddr)), if ( ( (hatch = (void *)(phdr->p_memsz + phdr->p_vaddr)),
( phdr->p_memsz==phdr->p_filesz // don't pollute potential .bss ( phdr->p_memsz==phdr->p_filesz // don't pollute potential .bss
&& 4<=(~PAGEMASK & -(int)hatch) ) ) // space left on page && 4<=(~PAGE_MASK & -(int)hatch) ) ) // space left on page
// Try Elf32_Ehdr.e_ident[12..15] . warning: 'const' cast away // Try Elf32_Ehdr.e_ident[12..15] . warning: 'const' cast away
|| ( (hatch = (void *)(&((Elf32_Ehdr *)phdr->p_vaddr)->e_ident[12])), || ( (hatch = (void *)(&((Elf32_Ehdr *)phdr->p_vaddr)->e_ident[12])),
(phdr->p_offset==0) ) ) { (phdr->p_offset==0) ) ) {
@ -230,7 +223,7 @@ do_xmap(int const fdi, Elf32_Ehdr const *const ehdr, struct Extent *const xi,
size_t mlen = xo.size = phdr->p_filesz; size_t mlen = xo.size = phdr->p_filesz;
char *addr = xo.buf = (char *)phdr->p_vaddr; char *addr = xo.buf = (char *)phdr->p_vaddr;
char *haddr = phdr->p_memsz + (char *)phdr->p_vaddr; char *haddr = phdr->p_memsz + (char *)phdr->p_vaddr;
size_t frag = (int)addr &~ PAGEMASK; size_t frag = (int)addr &~ PAGE_MASK;
mlen += frag; mlen += frag;
addr -= frag; addr -= frag;
if (ET_DYN==ehdr->e_type) { if (ET_DYN==ehdr->e_type) {
@ -255,7 +248,7 @@ do_xmap(int const fdi, Elf32_Ehdr const *const ehdr, struct Extent *const xi,
unpackExtent(xi, &xo, (f_expand *)fdi); unpackExtent(xi, &xo, (f_expand *)fdi);
} }
bzero(addr, frag); // fragment at lo end bzero(addr, frag); // fragment at lo end
frag = (-mlen) &~ PAGEMASK; // distance to next page boundary frag = (-mlen) &~ PAGE_MASK; // distance to next page boundary
bzero(mlen+addr, frag); // fragment at hi end bzero(mlen+addr, frag); // fragment at hi end
if (xi) { if (xi) {
make_hatch(phdr); make_hatch(phdr);
@ -284,7 +277,7 @@ ERR_LAB
if (xi) { // cleanup if decompressor overrun crosses page boundary if (xi) { // cleanup if decompressor overrun crosses page boundary
mlen += 3; mlen += 3;
addr += mlen; addr += mlen;
mlen &= ~PAGEMASK; mlen &= ~PAGE_MASK;
if (mlen<=3) { // page fragment was overrun buffer only if (mlen<=3) { // page fragment was overrun buffer only
munmap(addr - mlen, mlen); munmap(addr - mlen, mlen);
} }
@ -354,7 +347,7 @@ void *upx_main(
av[0].a_type = AT_PHDR; // av[0].a_un.a_val is set by do_xmap av[0].a_type = AT_PHDR; // av[0].a_un.a_val is set by do_xmap
av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize; av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize;
av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum; av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum;
av[3].a_type = AT_PAGESZ; av[3].a_un.a_val = PAGESIZE; av[3].a_type = AT_PAGESZ; av[3].a_un.a_val = PAGE_SIZE;
av[4].a_type = AT_ENTRY; av[4].a_un.a_val = ehdr->e_entry; av[4].a_type = AT_ENTRY; av[4].a_un.a_val = ehdr->e_entry;
av[5].a_type = AT_NULL; av[5].a_type = AT_NULL;
entry = do_xmap((int)f_decompress, ehdr, &xi, av); entry = do_xmap((int)f_decompress, ehdr, &xi, av);

View File

@ -25,18 +25,17 @@
*/ */
#if !defined(__linux__) || !defined(__i386__)
# error "this stub must be compiled under linux/i386"
#endif
#include "linux.hh" #include "linux.hh"
#include <elf.h>
/************************************************************************* /*************************************************************************
// configuration section // configuration section
**************************************************************************/ **************************************************************************/
// mmap() the temporary output file
#define USE_MMAP_FO
/************************************************************************* /*************************************************************************
// file util // file util
**************************************************************************/ **************************************************************************/
@ -46,6 +45,29 @@ struct Extent {
char *buf; char *buf;
}; };
#if !defined(USE_MMAP_FO)
#if 1
static __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 // util
**************************************************************************/ **************************************************************************/
@ -72,15 +94,16 @@ static char *upx_itoa(char *buf, unsigned long v)
return buf; return buf;
} }
static uint32_t ascii5(uint32_t r, unsigned k, char *p)
static uint32_t ascii5(char *p, uint32_t v, unsigned n)
{ {
do { do {
unsigned char d = r % 32; unsigned char d = v % 32;
if (d >= 26) d += '0' - 'Z' - 1; if (d >= 26) d += '0' - 'Z' - 1;
*--p += d; *--p += d;
r /= 32; v /= 32;
} while (--k > 0); } while (--n > 0);
return r; return v;
} }
@ -105,17 +128,11 @@ static uint32_t ascii5(uint32_t r, unsigned k, char *p)
// UPX & NRV stuff // UPX & NRV stuff
**************************************************************************/ **************************************************************************/
// patch constants for our loader (le32 format)
#define UPX1 0x31585055 // "UPX1"
#define UPX2 0x32585055 // "UPX2"
#define UPX3 0x33585055 // "UPX4"
#define UPX4 0x34585055 // "UPX4"
#define UPX5 0x35585055 // "UPX5"
typedef int f_expand( typedef int f_expand(
const nrv_byte *src, nrv_uint src_len, const nrv_byte *src, nrv_uint src_len,
nrv_byte *dst, nrv_uint *dst_len ); nrv_byte *dst, nrv_uint *dst_len );
/************************************************************************* /*************************************************************************
// upx_main - called by our entry code // upx_main - called by our entry code
// //
@ -135,7 +152,6 @@ void upx_main(
f_expand *const f_decompress f_expand *const f_decompress
) )
{ {
#define PAGE_MASK (~0<<12)
// file descriptors // file descriptors
int fdi, fdo; int fdi, fdo;
Elf32_Phdr const *const phdr = (Elf32_Phdr const *) Elf32_Phdr const *const phdr = (Elf32_Phdr const *)
@ -150,7 +166,10 @@ void upx_main(
// temporary file name (max 14 chars) // temporary file name (max 14 chars)
static char tmpname_buf[] = "/tmp/upxAAAAAAAAAAA"; static char tmpname_buf[] = "/tmp/upxAAAAAAAAAAA";
char *tmpname = tmpname_buf; char *tmpname = tmpname_buf;
char procself_buf[24]; // /proc/PPPPP/fd/XX // 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];
char *procself; char *procself;
// decompression buffer // decompression buffer
@ -163,12 +182,18 @@ void upx_main(
int ma_fd; int ma_fd;
off_t ma_offset; off_t ma_offset;
} malloc_args = { } malloc_args = {
#if defined(USE_MMAP_FO)
0, 0, PROT_READ | PROT_WRITE, MAP_SHARED, 0, 0 0, 0, PROT_READ | PROT_WRITE, MAP_SHARED, 0, 0
#else
0, 0, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0
#endif
}; };
#if defined(USE_MMAP_FO)
static struct MallocArgs scratch_page = { static struct MallocArgs scratch_page = {
0, -PAGE_MASK, PROT_READ | PROT_WRITE, 0, -PAGE_MASK, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0
}; };
#endif
// //
// ----- Step 0: set /proc/self using /proc/<pid> ----- // ----- Step 0: set /proc/self using /proc/<pid> -----
@ -188,11 +213,11 @@ void upx_main(
// Read header. // Read header.
{ {
register char *__d0, *__d1; register char *__d0, *__d1;
__asm__ __volatile__( "movsl; movsl; movsl" __asm__ __volatile__( "movsl; movsl; movsl"
: "=&D" (__d0), "=&S" (__d1) : "=&D" (__d0), "=&S" (__d1)
: "0" (&header), "1" (xi.buf) : "0" (&header), "1" (xi.buf)
: "memory"); : "memory");
xi.buf = __d1; xi.buf = __d1;
xi.size -= sizeof(header); xi.size -= sizeof(header);
} }
@ -214,7 +239,7 @@ void upx_main(
char *p = tmpname_buf + sizeof(tmpname_buf) - 1; char *p = tmpname_buf + sizeof(tmpname_buf) - 1;
// Compute the last 4 characters (20 bits) from getpid(). // Compute the last 4 characters (20 bits) from getpid().
uint32_t r = ascii5((uint32_t)pid, 4, p); p-=4; uint32_t r = ascii5(p, (uint32_t)pid, 4); p-=4;
// Provide 4 random bytes from our program id. // Provide 4 random bytes from our program id.
r ^= header.p_progid; r ^= header.p_progid;
@ -236,7 +261,7 @@ void upx_main(
#endif #endif
} }
// Compute 7 more characters from the 32 random bits. // Compute 7 more characters from the 32 random bits.
ascii5(r, 7, p); ascii5(p, r, 7);
} }
// Just in case, remove the file. // Just in case, remove the file.
@ -247,7 +272,11 @@ void upx_main(
} }
// Create the temporary output file. // Create the temporary output file.
#if defined(USE_MMAP_FO)
fdo = open(tmpname, O_RDWR | O_CREAT | O_EXCL, 0700); fdo = open(tmpname, O_RDWR | O_CREAT | O_EXCL, 0700);
#else
fdo = open(tmpname, O_WRONLY | O_CREAT | O_EXCL, 0700);
#endif
#if 0 #if 0
// Save some bytes of code - the ftruncate() below will fail anyway. // Save some bytes of code - the ftruncate() below will fail anyway.
if (fdo < 0) if (fdo < 0)
@ -263,8 +292,11 @@ void upx_main(
// ----- Step 3: setup memory ----- // ----- Step 3: setup memory -----
// //
#if defined(USE_MMAP_FO)
// mmap()ed output file.
malloc_args.ma_fd = fdo; malloc_args.ma_fd = fdo;
malloc_args.ma_length = header.p_filesize; // could packer do this? // FIXME: packer could set ma_length
malloc_args.ma_length = header.p_filesize;
buf = mmap((int *)&malloc_args); buf = mmap((int *)&malloc_args);
if ((unsigned long) buf >= (unsigned long) -4095) if ((unsigned long) buf >= (unsigned long) -4095)
goto error; goto error;
@ -273,6 +305,14 @@ void upx_main(
// Defend against SIGSEGV by using a scratch page. // Defend against SIGSEGV by using a scratch page.
scratch_page.ma_addr = buf + (PAGE_MASK & (header.p_filesize + ~PAGE_MASK)); scratch_page.ma_addr = buf + (PAGE_MASK & (header.p_filesize + ~PAGE_MASK));
mmap((int *)&scratch_page); mmap((int *)&scratch_page);
#else
// Temporary decompression buffer.
// FIXME: packer could set ma_length
malloc_args.ma_length = (header.p_blocksize + OVERHEAD + ~PAGE_MASK) & PAGE_MASK;
buf = mmap((int *)&malloc_args);
if ((unsigned long) buf >= (unsigned long) -4095)
goto error;
#endif
// //
// ----- Step 4: decompress blocks ----- // ----- Step 4: decompress blocks -----
@ -290,19 +330,19 @@ void upx_main(
// Read and check block sizes. // Read and check block sizes.
{ {
register char *__d0, *__d1; register char *__d0, *__d1;
__asm__ __volatile__( "movsl; movsl" __asm__ __volatile__( "movsl; movsl"
: "=&D" (__d0), "=&S" (__d1) : "=&D" (__d0), "=&S" (__d1)
: "0" (&h), "1" (xi.buf) : "0" (&h), "1" (xi.buf)
: "memory"); : "memory");
xi.buf = __d1; xi.buf = __d1;
xi.size -= sizeof(h); xi.size -= sizeof(h);
} }
if (h.sz_unc == 0) // uncompressed size 0 -> EOF if (h.sz_unc == 0) // uncompressed size 0 -> EOF
{ {
if (h.sz_cpr != UPX_MAGIC_LE32) // h.sz_cpr must be h->magic if (h.sz_cpr != UPX_MAGIC_LE32) // h.sz_cpr must be h->magic
goto error; goto error;
if (header.p_filesize != 0) // all bytes must be written if (header.p_filesize != 0) // all bytes must be written
goto error; goto error;
break; break;
} }
@ -321,16 +361,29 @@ void upx_main(
if (i != 0 || out_len != (nrv_uint)h.sz_unc) if (i != 0 || out_len != (nrv_uint)h.sz_unc)
goto error; goto error;
} }
else { // Incompressible block else
{
// Incompressible block
#if defined(USE_MMAP_FO)
//memcpy(buf, xi.buf, h.sz_unc); //memcpy(buf, xi.buf, h.sz_unc);
register unsigned long int __d0, __d1, __d2; register unsigned long int __d0, __d1, __d2;
__asm__ __volatile__( "rep; movsb" __asm__ __volatile__( "rep; movsb"
: "=&c" (__d0), "=&D" (__d1), "=&S" (__d2) : "=&c" (__d0), "=&D" (__d1), "=&S" (__d2)
: "0" (h.sz_unc), "1" (buf), "2" (xi.buf) : "0" (h.sz_unc), "1" (buf), "2" (xi.buf)
: "memory"); : "memory");
#endif
} }
#if defined(USE_MMAP_FO)
// unmap part of the output
munmap(buf, h.sz_unc); munmap(buf, h.sz_unc);
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; header.p_filesize -= h.sz_unc;
xi.buf += h.sz_cpr; xi.buf += h.sz_cpr;
@ -358,6 +411,12 @@ void upx_main(
// ----- Step 5: release resources ----- // ----- 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) if (close(fdo) != 0)
goto error; goto error;
@ -390,7 +449,7 @@ void upx_main(
fcntl(fdi, F_SETFD, FD_CLOEXEC); fcntl(fdi, F_SETFD, FD_CLOEXEC);
// Execute the original program via /proc/self/fd/X. // Execute the original program via /proc/self/fd/X.
execve(procself_buf, argv, envp); execve(procself_buf, argv, envp);
// If we get here we've lost. // NOTE: if we get here we've lost.
} }
#undef err #undef err

View File

@ -7,7 +7,6 @@
Integration of virtual exec() with decompression is Integration of virtual exec() with decompression is
Copyright (C) 2000 John F. Reiser. All rights reserved. Copyright (C) 2000 John F. Reiser. All rights reserved.
<jreiser@BitWagon.com>
UPX and the UCL library are free software; you can redistribute them 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 and/or modify them under the terms of the GNU General Public License as
@ -27,39 +26,20 @@
Markus F.X.J. Oberhumer Laszlo Molnar Markus F.X.J. Oberhumer Laszlo Molnar
markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu markus.oberhumer@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu
John F. Reiser
jreiser@BitWagon.com
*/ */
#if !defined(__linux__) || !defined(__i386__)
# error "this stub must be compiled under linux/i386"
#endif
#include <sys/types.h>
#include <fcntl.h>
#include <linux/errno.h>
#include <linux/mman.h>
#include <linux/unistd.h>
#include "linux.hh" #include "linux.hh"
/************************************************************************* /*************************************************************************
// configuration section // configuration section
**************************************************************************/ **************************************************************************/
// must be the same as in p_linux.cpp !
#define OVERHEAD 2048
#define PAGEMASK (~0u<<12) // discards the offset, keeps the page
#define PAGESIZE ( 1u<<12)
#define MAX_ELF 512 // Elf32_Ehdr + n*Elf32_Phdr must fit in this #define MAX_ELF 512 // Elf32_Ehdr + n*Elf32_Phdr must fit in this
#undef int32_t
#undef uint32_t
#define int32_t int
#define uint32_t unsigned int
#define SEEK_SET 0
#define SEEK_CUR 1
/************************************************************************* /*************************************************************************
// file util // file util
@ -139,14 +119,11 @@ do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
return mmap((int *)&addr); return mmap((int *)&addr);
} }
/************************************************************************* /*************************************************************************
// UPX & NRV stuff // UPX & NRV stuff
**************************************************************************/ **************************************************************************/
// patch & magic constants for our loader (le32 format)
#define UPX_MAGIC_LE32 0x21585055 // "UPX!"
typedef int f_expand( typedef int f_expand(
const nrv_byte *, nrv_uint, const nrv_byte *, nrv_uint,
nrv_byte *, nrv_uint * ); nrv_byte *, nrv_uint * );
@ -217,8 +194,6 @@ ERR_LAB
} }
} }
#include <elf.h>
// Create (or find) an escape hatch to use when munmapping ourselves the stub. // Create (or find) an escape hatch to use when munmapping ourselves the stub.
// Called by do_xmap to create it, and by assembler code to find it. // Called by do_xmap to create it, and by assembler code to find it.
void * void *
@ -237,7 +212,7 @@ make_hatch(Elf32_Phdr const *const phdr)
// Try page fragmentation just beyond .text . // Try page fragmentation just beyond .text .
if ( ( (hatch = (void *)(phdr->p_memsz + phdr->p_vaddr)), if ( ( (hatch = (void *)(phdr->p_memsz + phdr->p_vaddr)),
( phdr->p_memsz==phdr->p_filesz // don't pollute potential .bss ( phdr->p_memsz==phdr->p_filesz // don't pollute potential .bss
&& 4<=(~PAGEMASK & -(int)hatch) ) ) // space left on page && 4<=(~PAGE_MASK & -(int)hatch) ) ) // space left on page
// Try Elf32_Ehdr.e_ident[12..15] . warning: 'const' cast away // Try Elf32_Ehdr.e_ident[12..15] . warning: 'const' cast away
|| ( (hatch = (void *)(&((Elf32_Ehdr *)phdr->p_vaddr)->e_ident[12])), || ( (hatch = (void *)(&((Elf32_Ehdr *)phdr->p_vaddr)->e_ident[12])),
(phdr->p_offset==0) ) ) { (phdr->p_offset==0) ) ) {
@ -278,7 +253,7 @@ do_xmap(int fdi, Elf32_Ehdr const *const ehdr, f_expand *const f_decompress,
size_t mlen = x.size = phdr->p_filesz; size_t mlen = x.size = phdr->p_filesz;
char *addr = x.buf = (char *)phdr->p_vaddr; char *addr = x.buf = (char *)phdr->p_vaddr;
char *haddr = phdr->p_memsz + (char *)phdr->p_vaddr; char *haddr = phdr->p_memsz + (char *)phdr->p_vaddr;
size_t frag = (int)addr &~ PAGEMASK; size_t frag = (int)addr &~ PAGE_MASK;
mlen += frag; mlen += frag;
addr -= frag; addr -= frag;
if (ET_DYN==ehdr->e_type) { if (ET_DYN==ehdr->e_type) {
@ -301,7 +276,7 @@ do_xmap(int fdi, Elf32_Ehdr const *const ehdr, f_expand *const f_decompress,
unpackExtent(&x, fdi, f_decompress); unpackExtent(&x, fdi, f_decompress);
} }
bzero(addr, frag); // fragment at lo end bzero(addr, frag); // fragment at lo end
frag = (-mlen) &~ PAGEMASK; // distance to next page boundary frag = (-mlen) &~ PAGE_MASK; // distance to next page boundary
bzero(mlen+addr, frag); // fragment at hi end bzero(mlen+addr, frag); // fragment at hi end
if (f_decompress) { if (f_decompress) {
make_hatch(phdr); make_hatch(phdr);
@ -330,7 +305,7 @@ ERR_LAB
if (f_decompress) { // cleanup if decompressor overrun crosses page boundary if (f_decompress) { // cleanup if decompressor overrun crosses page boundary
mlen += 3; mlen += 3;
addr += mlen; addr += mlen;
mlen &= ~PAGEMASK; mlen &= ~PAGE_MASK;
if (mlen<=3) { // page fragment was overrun buffer only if (mlen<=3) { // page fragment was overrun buffer only
munmap(addr - mlen, mlen); munmap(addr - mlen, mlen);
} }
@ -422,7 +397,7 @@ ERR_LAB
av[0].a_type = AT_PHDR; av[0].a_un.a_val = 0; // updated by do_xmap av[0].a_type = AT_PHDR; av[0].a_un.a_val = 0; // updated by do_xmap
av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize; av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize;
av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum; av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum;
av[3].a_type = AT_PAGESZ; av[3].a_un.a_val = PAGESIZE; av[3].a_type = AT_PAGESZ; av[3].a_un.a_val = PAGE_SIZE;
av[4].a_type = AT_ENTRY; av[4].a_un.a_val = ehdr->e_entry; av[4].a_type = AT_ENTRY; av[4].a_un.a_val = ehdr->e_entry;
av[5].a_type = AT_NULL; av[5].a_type = AT_NULL;
entry = do_xmap(fdi, ehdr, f_decompress, av); entry = do_xmap(fdi, ehdr, f_decompress, av);

View File

@ -31,10 +31,6 @@
*/ */
#if !defined(__linux__) || !defined(__i386__)
# error "this stub must be compiled under linux/i386"
#endif
#include "linux.hh" #include "linux.hh"
@ -46,9 +42,6 @@
// it at an address different from it load address: there must be no // it at an address different from it load address: there must be no
// static data, and no string constants. // static data, and no string constants.
#define PAGEMASK (~0u<<12) // discards the offset, keeps the page
#define PAGESIZE ( 1u<<12)
#define MAX_ELF_HDR 512 // Elf32_Ehdr + n*Elf32_Phdr must fit in this #define MAX_ELF_HDR 512 // Elf32_Ehdr + n*Elf32_Phdr must fit in this
@ -113,7 +106,6 @@ do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
// UPX & NRV stuff // UPX & NRV stuff
**************************************************************************/ **************************************************************************/
typedef int f_expand( typedef int f_expand(
const nrv_byte *, nrv_uint, const nrv_byte *, nrv_uint,
nrv_byte *, nrv_uint * ); nrv_byte *, nrv_uint * );
@ -202,7 +194,7 @@ do_xmap(int const fdi, Elf32_Ehdr const *const ehdr, Elf32_auxv_t *const a)
size_t mlen = xo.size = phdr->p_filesz; size_t mlen = xo.size = phdr->p_filesz;
char *addr = xo.buf = (char *)phdr->p_vaddr; char *addr = xo.buf = (char *)phdr->p_vaddr;
char *haddr = phdr->p_memsz + (char *)phdr->p_vaddr; char *haddr = phdr->p_memsz + (char *)phdr->p_vaddr;
size_t frag = (int)addr &~ PAGEMASK; size_t frag = (int)addr &~ PAGE_MASK;
mlen += frag; mlen += frag;
addr -= frag; addr -= frag;
if (ET_DYN==ehdr->e_type) { if (ET_DYN==ehdr->e_type) {
@ -222,7 +214,7 @@ do_xmap(int const fdi, Elf32_Ehdr const *const ehdr, Elf32_auxv_t *const a)
base = (unsigned long)addr; base = (unsigned long)addr;
} }
bzero(addr, frag); // fragment at lo end bzero(addr, frag); // fragment at lo end
frag = (-mlen) &~ PAGEMASK; // distance to next page boundary frag = (-mlen) &~ PAGE_MASK; // distance to next page boundary
bzero(mlen+addr, frag); // fragment at hi end bzero(mlen+addr, frag); // fragment at hi end
if (phdr->p_memsz != phdr->p_filesz) { // .bss if (phdr->p_memsz != phdr->p_filesz) { // .bss
if (ET_DYN==ehdr->e_type) { // PT_INTERP whole pages of .bss? if (ET_DYN==ehdr->e_type) { // PT_INTERP whole pages of .bss?
@ -322,9 +314,6 @@ void *upx_main(
// 'fn' and 'efn' must not suffer constant-propagation by gcc // 'fn' and 'efn' must not suffer constant-propagation by gcc
// UPX2 = 3 + offset to name_of_shell // UPX2 = 3 + offset to name_of_shell
// UPX3 = strlen(name_of_shell) // UPX3 = strlen(name_of_shell)
// patch & magic constants for our loader (le32 format)
#define UPX2 0x32585055 // "UPX2"
#define UPX3 0x33585055 // "UPX3"
char * /*const*/ volatile fn = UPX2 + uncbuf; // past "-c" and "#!" char * /*const*/ volatile fn = UPX2 + uncbuf; // past "-c" and "#!"
char * /*const*/ volatile efn = UPX3 + fn; // &terminator char * /*const*/ volatile efn = UPX3 + fn; // &terminator
char const c = *efn; *efn = 0; // terminator char const c = *efn; *efn = 0; // terminator
@ -334,7 +323,7 @@ void *upx_main(
av[0].a_type = AT_PHDR; // av[0].a_un.a_val is set by do_xmap av[0].a_type = AT_PHDR; // av[0].a_un.a_val is set by do_xmap
av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize; av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize;
av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum; av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum;
av[3].a_type = AT_PAGESZ; av[3].a_un.a_val = PAGESIZE; av[3].a_type = AT_PAGESZ; av[3].a_un.a_val = PAGE_SIZE;
av[4].a_type = AT_ENTRY; av[4].a_un.a_val = entry; av[4].a_type = AT_ENTRY; av[4].a_un.a_val = entry;
av[5].a_type = AT_NULL; av[5].a_type = AT_NULL;
} }
@ -347,6 +336,7 @@ void *upx_main(
break; break;
} }
} }
return (void *)entry; return (void *)entry;
} }

View File

@ -55,9 +55,15 @@
// !!! must be the same as in p_unix.h !!! // !!! must be the same as in p_unix.h !!!
#define OVERHEAD 2048 #define OVERHEAD 2048
#define UPX_MAGIC_LE32 0x21585055 // "UPX!" #define UPX_MAGIC_LE32 0x21585055 // "UPX!"
// patch constants for our loader (le32 format)
#define UPX1 0x31585055 // "UPX1"
#define UPX2 0x32585055 // "UPX2"
#define UPX3 0x33585055 // "UPX4"
#define UPX4 0x34585055 // "UPX4"
#define UPX5 0x35585055 // "UPX5"
#undef int32_t #undef int32_t
#undef uint32_t #undef uint32_t
@ -74,13 +80,15 @@ typedef unsigned int nrv_uint32;
// From ../p_unix.h // From ../p_unix.h
struct l_info { // 12-byte trailer in header for loader struct l_info // 12-byte trailer in header for loader (offset 116)
{
uint32_t l_checksum; uint32_t l_checksum;
uint32_t l_magic; uint32_t l_magic;
uint16_t l_lsize; uint16_t l_lsize;
uint8_t l_version; uint8_t l_version;
uint8_t l_format; uint8_t l_format;
}; };
struct p_info // 12-byte packed program header follows stub loader struct p_info // 12-byte packed program header follows stub loader
{ {
uint32_t p_progid; uint32_t p_progid;
@ -89,6 +97,13 @@ struct p_info // 12-byte packed program header follows stub loader
}; };
#define SEEK_SET 0
#define SEEK_CUR 1
#define PAGE_MASK (~0u<<12) // discards the offset, keeps the page
#define PAGE_SIZE ( 1u<<12)
/************************************************************************* /*************************************************************************
// syscalls // syscalls
// //