Put upx stub loader at high end of ELF output file on linux,

and allow for block-by-block specification of filter and parameters.
	linker.cpp linker.h mem.cpp mem.h p_elf.h
	p_lx_elf.cpp p_lx_elf.h
	p_lx_exc.cpp p_lx_exc.h
	p_lx_sh.cpp  p_lx_sh.h
	p_unix.cpp p_unix.h
	packer.cpp packer.h
	stub/fold_elf86.asm stub/fold_exec86.asm stub/fold_sh86.asm
	stub/l_lx_elf.c  stub/l_lx_elf86.asm  stub/l_lx_elf86.lds
	stub/l_lx_exec.c stub/l_lx_exec86.asm stub/l_lx_exec86.lds
	stub/l_lx_sh.c   stub/l_lx_sh86.asm   stub/l_lx_sh86.lds
	stub/linux.hh

committer: jreiser <jreiser> 981084316 +0000
This commit is contained in:
John Reiser
2001-02-02 03:25:16 +00:00
parent 9005e50049
commit 40fddf1715
28 changed files with 797 additions and 614 deletions
+17 -11
View File
@@ -26,7 +26,10 @@
%define szElf32_Ehdr 0x34
%define szElf32_Phdr 8*4
%define e_entry (16 + 2*2 + 4)
%define p_memsz 5*4
%define szl_info 12
%define szp_info 12
%define a_val 4
%define __NR_munmap 91
@@ -34,7 +37,7 @@
;; control just falls through, after this part and compiled C code
;; are uncompressed.
fold_begin:
fold_begin: ; enter: %ebx= &Elf32_Ehdr of this program
; patchLoader will modify to be
; dword sz_uncompressed, sz_compressed
; byte compressed_data...
@@ -45,6 +48,7 @@ fold_begin:
; Move argc,argv,envp down so that we can insert more Elf_auxv entries.
; ld-linux.so.2 depends on AT_PHDR and AT_ENTRY, for instance
%define PAGE_SIZE ( 1<<12)
%define OVERHEAD 2048
%define MAX_ELF_HDR 512
@@ -53,18 +57,19 @@ fold_begin:
mov edi, esp
call do_auxv
mov eax, [p_memsz + 2*szElf32_Phdr + szElf32_Ehdr + ebx] ; size of PT_DYNAMIC
sub esp, dword MAX_ELF_HDR + OVERHEAD
mov ecx, [e_entry + ebx] ; beyond compressed data
push esp ; argument: temp space
lea eax, [szElf32_Ehdr + 3*szElf32_Phdr + szl_info + szp_info + ebx + eax] ; 1st &b_info
push edi ; argument: AT_next
sub ecx, eax ; length of compressed data
push ebp ; argument: &decompress
push edx ; argument: my_elfhdr
add edx, [p_memsz + szElf32_Ehdr + edx]
push edx ; argument: uncbuf
push ecx ; argument: sz_compressed
push eax ; argument: 1st &b_info
EXTERN upx_main
call upx_main ; entry = upx_main(uncbuf, my_elfhdr, &decompress, AT_next, tmp_ehdr)
pop esi ; decompression buffer == (p_vaddr + p_memsz) of stub
pop ebx ; my_elfhdr
add esp, dword 3*4 + MAX_ELF_HDR + OVERHEAD ; remove 3 params, temp space
call upx_main ; entry = upx_main(b1st_info, sz_cpr, &decompress, AT_next, tmp_ehdr)
add esp, dword 5*4 + MAX_ELF_HDR + OVERHEAD ; remove 5 params, temp space
push eax ; save entry address
mov edi, [a_val + edi] ; AT_PHDR
@@ -90,9 +95,10 @@ EXTERN make_hatch
xor eax,eax
rep stosd
mov ecx,esi ; my p_vaddr + p_memsz
mov bh,0 ; round down to 64KB boundary
sub ecx,ebx ; length to unmap
xor ecx, ecx ; 0
mov ch, PAGE_SIZE>>8 ; 0x1000
add ecx, [p_memsz + szElf32_Ehdr + ebx] ; length to unmap
mov bh, 0 ; from 0x401000 to 0x400000
push byte __NR_munmap
pop eax
jmp edx ; unmap ourselves via escape hatch, then goto entry
+15 -7
View File
@@ -27,18 +27,26 @@
;; control just falls through, after this part and compiled C code
;; are uncompressed.
fold_begin: ;; this label is known to the Makefile
%define szElf32_Ehdr 0x34
%define szElf32_Phdr 8*4
%define e_entry (16 + 2*2 + 4)
%define p_vaddr 2*4
%define p_memsz 5*4
%define szl_info 12
%define szp_info 12
fold_begin: ; enter: %ebx= &Elf32_Ehdr of this program
pop eax ; discard &dstlen
pop eax ; discard dstlen
pop eax ; Pop the argument count
mov ecx, esp ; argv starts just at the current stack top
lea edx, [ecx+eax*4+4] ; envp = &argv[argc + 1]
push eax ; Restore the stack
push ebp ; argument: &decompress
push ebx ; argument: &my_elfhdr
push edx ; argument: envp
push ecx ; argument: argv
lea edx, [esp+eax*4+4] ; envp = &argv[argc + 1]
mov esi, [e_entry + ebx]
add ebx, szElf32_Ehdr + szElf32_Phdr + szl_info
sub esi, ebx ; length
lea edi, [2 + ebp] ; f_unfilter, maybe
pusha ; (f_unf, cprLen, f_decpr, xx, cprSrc, envp, argv, argc)
EXTERN upx_main
call upx_main ; Call the UPX main function
hlt ; Crash if somehow upx_main does return
+23 -18
View File
@@ -30,11 +30,15 @@
BITS 32
SECTION .text
fold_begin:
; patchLoader will modify to be
; dword sz_uncompressed, sz_compressed
; byte compressed_data...
%define szElf32_Ehdr 0x34
%define szElf32_Phdr 8*4
%define e_entry (16 + 2*2 + 4)
%define p_memsz 5*4
%define szl_info 12
%define szp_info 12
fold_begin: ; enter: %ebx= uncDst
; also edx= szElf32_Ehdr + 2*szElf32_Phdr + &Elf32_Ehdr
pop eax ; discard &sz_uncompressed
pop eax ; discard sz_uncompressed
@@ -48,39 +52,40 @@ fold_begin:
mov esi, esp
sub esp, byte 6*8 ; AT_PHENT, AT_PHNUM, AT_PAGESZ, AT_ENTRY, AT_PHDR, AT_NULL
mov edi, esp
call do_auxv
call do_auxv ; edi= &AT_NEXT
sub esp, dword MAX_ELF_HDR + OVERHEAD
push esp ; argument: temp space
push edi ; argument: AT_next
push ebp ; argument: &decompress
push edx ; argument: my_elfhdr
add ecx, PAGE_SIZE ; uncompressed stub fits in this
push ecx ; argument: uncbuf
xchg eax, ebx ; eax= uncDst
lea edx, [szl_info + szp_info + edx] ; cprSrc
mov ecx, [ edx] ; sz_unc
mov ebx, [4+ edx] ; sz_cpr
mov esi, eax ; extra copy of uncDst
pusha ; (&AT_NEXT,uncDst,f_decpr,&ehdr,{sz_cpr,cprSrc},{sz_unc,uncDst})
EXTERN upx_main
call upx_main ; entry = upx_main(uncbuf, my_elfhdr, &decompress, AT_next, tmp_ehdr)
pop esi ; decompression buffer
pop ebx ; my_elfhdr
add esp, dword 3*4 + MAX_ELF_HDR + OVERHEAD ; remove 3 params, temp space
call upx_main ; entry = upx_main(...)
pop ecx ; junk
push eax ; save entry address
popa ; edi= entry address; esi= uncDst
add esp, dword MAX_ELF_HDR + OVERHEAD ; remove temp space
pop ecx ; argc
pop edx ; $0 filename, to become argv[0]
push edx ; restore $0 filename
add esi, byte 3
inc ecx
push esi ; &uncompressed shell script
sub esi, byte 3
mov [esi], word 0x632d ; "-c"
inc ecx
push esi ; "-c"
push esi ; &"-c"
inc ecx
push edx ; argv[0] is duplicate of $0
push ecx ; new argc
push eax ; save entry address
push edi ; save entry address
; _dl_start and company (ld-linux.so.2) assumes that it has virgin stack,
; and does not initialize all its stack local variables to zero.
+19 -28
View File
@@ -120,18 +120,12 @@ unpackExtent(
)
{
while (xo->size) {
unsigned cto8;
struct {
int32_t sz_unc; // uncompressed
int32_t sz_cpr; // compressed
} h;
struct b_info h;
// Note: if h.sz_unc == h.sz_cpr then the block was not
// compressible and is stored in its uncompressed form.
// Read and check block sizes.
xread(xi, (char *)&h, sizeof(h));
cto8 = h.sz_cpr;
h.sz_cpr >>= 8;
if (h.sz_unc == 0) { // uncompressed size 0 -> EOF
if (h.sz_cpr != UPX_MAGIC_LE32) // h.sz_cpr must be h->magic
err_exit(2);
@@ -144,7 +138,7 @@ unpackExtent(
ERR_LAB
}
if (h.sz_cpr > h.sz_unc
|| h.sz_unc > (int32_t)xo->size ) {
|| h.sz_unc > xo->size ) {
err_exit(5);
}
// Now we have:
@@ -162,7 +156,7 @@ ERR_LAB
&& ((512 < out_len) // this block is longer than Ehdr+Phdrs
|| (xo->size==(unsigned)h.sz_unc) ) // block is last in Extent
) {
(*f_unf)(xo->buf, out_len, cto8);
(*f_unf)(xo->buf, out_len, h.b_cto8);
}
xi->buf += h.sz_cpr;
xi->size -= h.sz_cpr;
@@ -322,46 +316,43 @@ ERR_LAB
**************************************************************************/
void *upx_main(
char *const uncbuf,
Elf32_Ehdr const *const my_ehdr,
char /*const*/ *const b1st_info,
unsigned const sz_compressed,
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr
) __asm__("upx_main");
void *upx_main(
char *const uncbuf,
Elf32_Ehdr const *const my_ehdr, // to get compressed size and data
char /*const*/ *const b1st_info,
unsigned const sz_compressed,
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr // temp char[MAX_ELF_HDR+OVERHEAD]
)
{
struct cprElfhdr {
Elf32_Ehdr ehdr;
Elf32_Phdr phdr[2];
struct l_info linfo;
};
size_t const lsize = ((struct cprElfhdr const *)my_ehdr)->linfo.l_lsize;
Elf32_Phdr const *phdr = (Elf32_Phdr const *)(1+ehdr);
Elf32_Addr entry;
struct Extent xo;
struct Extent xi = { 0, sizeof(struct p_info) + lsize + CONST_CAST(char *, my_ehdr) };
struct Extent xi = { 0, b1st_info }; // location of 1st b_info
size_t const sz_elfhdrs = ((size_t *)xi.buf)[0]; // sizeof(Ehdr+Phdrs), uncompressed
size_t const sz_pckhdrs = ((size_t *)xi.buf)[1]>>8; // sizeof(Ehdr+Phdrs), compressed
// sizeof(Ehdr+Phdrs), uncompressed
size_t const sz_elfhdrs = ((size_t *)xi.buf)[0];
// sizeof(Ehdr+Phdrs), compressed; including b_info header
size_t const sz_pckhdrs = sizeof(struct b_info) + ((size_t *)xi.buf)[1];
(void)uncbuf; // used by l_lx_sh.c
// Uncompress Ehdr and Phdrs.
xo.size = sz_elfhdrs; xo.buf = (char *)ehdr;
xi.size = 2*sizeof(size_t) + sz_pckhdrs;
xo.size = sz_elfhdrs; xo.buf = (char *)ehdr;
xi.size = sz_pckhdrs;
unpackExtent(&xi, &xo, f_decompress, 0);
// Prepare to decompress the Elf headers again, into the first PT_LOAD.
xi.buf -= 2*sizeof(size_t) + sz_pckhdrs;
xi.size = ((Elf32_Phdr const *)(1 + my_ehdr))->p_filesz - lsize;
xi.buf -= sz_pckhdrs;
xi.size = sz_compressed;
// av[0].a_un.a_val is set again by do_xmap if PT_PHDR is present
// av[0].a_un.a_val is set again by do_xmap if PT_PHDR is present.
// Caller of upx_main assumes that AT_PHDR will be set into av[0] .
av[0].a_type = AT_PHDR; av[0].a_un.a_ptr = 1+(Elf32_Ehdr *)phdr->p_vaddr;
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;
+6 -8
View File
@@ -116,7 +116,6 @@ decompress:
;__LEXEC020__
%define PAGE_MASK (~0<<12)
%define PAGE_SIZE ( 1<<12)
%define MAP_FIXED 0x10
@@ -126,7 +125,6 @@ decompress:
%define PROT_WRITE 2
%define PROT_EXEC 4
%define __NR_mmap 90
%define __NR_munmap 91
; Decompress the rest of this loader, and jump to it
unfold:
@@ -135,10 +133,7 @@ unfold:
lodsd
push eax ; sz_uncompressed (junk, actually)
push esp ; &sz_uncompressed
mov eax, ebp ; &decompress
and eax, dword PAGE_MASK ; &my_elfhdr
mov edx, eax ; need my_elfhdr later
mov ah,0 ; round down to 64KB boundary
mov eax, 0x400000
push eax ; &destination
; mmap a page to hold the decompressed program
@@ -148,16 +143,19 @@ unfold:
mov ch, PAGE_SIZE >> 8
push byte MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS
push byte PROT_READ | PROT_WRITE | PROT_EXEC
push ecx
push ecx ; length
push eax ; destination
mov ebx, esp ; address of parameter vector for __NR_mmap
push byte __NR_mmap
pop eax
mov ebx, esp
int 0x80
xchg eax, ebx
mov bh, PAGE_SIZE>>8 ; ebx= 0x401000
add esp, byte 6*4 ; discard args to mmap
lodsd
push eax ; sz_compressed
lodsd ; junk cto8, algo, unused[2]
push esi ; &compressed_data
call ebp ; decompress(&src, srclen, &dst, &dstlen)
pop eax ; discard &compressed_data
+10 -4
View File
@@ -28,17 +28,23 @@
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
/*ENTRY(_start)*/
PHDRS
{
text PT_LOAD FILEHDR PHDRS ;
data PT_LOAD ; /* for setting brk(0) */
null PT_NULL; /* changed to PT_DYNAMIC for ldd */
}
SECTIONS
{
/* 0x00401000: l_lx_elf86.asm assumes 1 page up from 64KB boundary */
. = 0x00401000 + SIZEOF_HEADERS;
. = ALIGN(0x80);
. = 0x00401000 + SIZEOF_HEADERS + 12; /* 12==sizeof(l_info) */
.text : {
*(.text)
*(.data)
}
} : text
/* 0x08048000: customary Linux/x86 Elf .text start */
/* PackLinuxI386::buildLinuxLoader will overwrite the address anyway. */
. = 0x08048000 + (0xfff & .);
.data : {
}
} : data
}
+33 -20
View File
@@ -139,7 +139,7 @@ do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
static int
go_self(char const *tmpname, char *argv[], char *envp[])
{
// FIXME: why not use "/proc/self/fd/XX"? *BSD doesn't have it?
// Old FreeBSD does not have /proc/self, so use /proc/<pid> instead.
// Open the temp file.
int const fdi = open(tmpname, O_RDONLY, 0);
@@ -181,6 +181,11 @@ go_self(char const *tmpname, char *argv[], char *envp[])
// 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 );
@@ -193,16 +198,24 @@ typedef int f_expand(
**************************************************************************/
void upx_main(
char *argv[],
f_unfilter *const f_unf,
unsigned cprLen,
f_expand *const f_decompress,
int junk2,
char /*const*/ *cprSrc,
char *envp[],
Elf32_Ehdr const *const my_ehdr,
f_expand *const f_decompress
char *argv[],
int argc
) __asm__("upx_main");
void upx_main(
char *argv[],
f_unfilter *const f_unf,
unsigned cprLen,
f_expand *const f_decompress,
int junk,
char /*const*/ *cprSrc,
char *envp[],
Elf32_Ehdr const *const my_ehdr,
f_expand *const f_decompress
char *argv[],
int argc
)
{
// file descriptor
@@ -213,9 +226,7 @@ void upx_main(
char *tmpname;
Elf32_Phdr const *const phdr = (Elf32_Phdr const *)
(my_ehdr->e_phoff + (char const *)my_ehdr);
struct Extent xi = { phdr[1].p_memsz, (char *)phdr[1].p_vaddr };
struct Extent xi = { cprLen, cprSrc };
char *next_unmap = (char *)(PAGE_MASK & (unsigned)xi.buf);
struct p_info header;
@@ -223,6 +234,8 @@ void upx_main(
// temporary file name
char tmpname_buf[20];
(void)junk;
//
// ----- Step 0: set /proc/self using /proc/<pid> -----
//
@@ -347,18 +360,13 @@ void upx_main(
for (;;)
{
struct {
int32_t sz_unc; // uncompressed
int32_t sz_cpr; // compressed
} h;
// Note: if h.sz_unc == h.sz_cpr then the block was not
// compressible and is stored in its uncompressed form.
struct b_info h;
int i;
// Read and check block sizes.
{
register char *__d0, *__d1;
__asm__ __volatile__( "movsl; movsl"
__asm__ __volatile__( "movsl; movsl; movsl"
: "=&D" (__d0), "=&S" (__d1)
: "0" (&h), "1" (xi.buf)
: "memory");
@@ -373,9 +381,10 @@ void upx_main(
goto error;
break;
}
if (h.sz_cpr <= 0)
goto error;
if (h.sz_cpr > h.sz_unc || h.sz_unc > (int32_t)header.p_blocksize)
// 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);
@@ -387,6 +396,9 @@ void upx_main(
i = (*f_decompress)(xi.buf, h.sz_cpr, buf, &out_len);
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
{
@@ -486,6 +498,7 @@ void upx_main(
waitpid(-1, (int *)0, 0);
// Execute the original program.
(void)argc;
execve(tmpname, argv, envp);
+38 -33
View File
@@ -138,49 +138,53 @@ decompress:
;__LEXEC020__
%define PAGE_MASK (~0<<12)
%define PAGE_SIZE ( 1<<12)
%define MAP_FIXED 0x10
%define MAP_PRIVATE 0x02
%define MAP_ANONYMOUS 0x20
%define PROT_READ 1
%define PROT_WRITE 2
%define PROT_EXEC 4
%define __NR_mmap 90
; Decompress the rest of this loader, and jump to it
unfold:
pop esi ; &{ sz_uncompressed, sz_compressed, compressed_data...}
mov ecx, PAGE_MASK
push esi ; &dst
mov ebx, ebp ; &decompress
and ebx, ecx ; &my_elfhdr
neg ecx ; ecx= PAGE_SIZE
cld
lodsd ; sz_uncompressed
lodsd ; sz_compressed
lodsd
push eax ; sz_uncompressed (junk, actually)
push esp ; &sz_uncompressed
mov eax, 0x400000
push eax ; &destination
;; Compressed code now begins at fold_begin.
;; We want decompressed code to begin at fold_begin, too.
;; Move the compressed code to the high end of the page.
;; Assume non-overlapping so that forward movsb is OK.
lea edi, [ecx + ebx] ; high end of page
push eax ; srclen (of both movsb and decompress)
sub edi, eax ; dst of movsb
push edi ; &src for decompression (after movsb)
xchg ecx, eax ; ecx= len of movsb
rep movsb
call ebp ; decompress(&src, srclen, &dst, &dstlen)
pop eax ; discard &src
pop eax ; discard srclen
pop eax ; &dst == fold_begin
;; icache lookahead of compressed code after "call unfold" is still there.
;; Synchronize with dcache of decompressed code.
pushf
push cs
push eax
iret ; back to fold_begin!
; mmap a page to hold the decompressed program
xor ecx, ecx
push ecx
push ecx
mov ch, PAGE_SIZE >> 8
push byte MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS
push byte PROT_READ | PROT_WRITE | PROT_EXEC
push ecx ; length
push eax ; destination
mov ebx, esp ; address of parameter vector for __NR_mmap
push byte __NR_mmap
pop eax
int 0x80
xchg eax, ebx
mov bh, PAGE_SIZE>>8 ; ebx= 0x401000
add esp, byte 6*4 ; discard args to mmap
lodsd
push eax ; sz_compressed
lodsd ; junk cto8, algo, unused[2]
push esi ; &compressed_data
call ebp ; decompress(&src, srclen, &dst, &dstlen)
pop eax ; discard &compressed_data
pop eax ; discard sz_compressed
ret ; &destination
main:
pop ebp ; &decompress
push eax ; sz_uncompressed (junk, actually)
push esp ; &sz_uncompressed
call unfold
eof:
@@ -190,3 +194,4 @@ eof:
dw eof
; vi:ts=8:et:nowrap
+2 -3
View File
@@ -30,9 +30,8 @@ OUTPUT_ARCH(i386)
/*ENTRY(_start)*/
SECTIONS
{
/* 0x08048000: customary Linux/x86 Elf .text start */
. = 0x08048000 + SIZEOF_HEADERS;
. = ALIGN(0x80); /* room for Ehdr, 2*Phdr, l_info */
/* 0x00401000: l_lx_exec86.asm assumes 1 page up from 64KB boundary */
. = 0x00401000 + SIZEOF_HEADERS + 12; /* 12==sizeof(l_info) */
.data : { /* put everything together in one Phdr */
*(.text)
*(.rodata)
+18 -35
View File
@@ -114,10 +114,7 @@ unpackExtent(
)
{
while (xo->size) {
struct {
int32_t sz_unc; // uncompressed
int32_t sz_cpr; // compressed
} h;
struct b_info h;
// Note: if h.sz_unc == h.sz_cpr then the block was not
// compressible and is stored in its uncompressed form.
@@ -135,7 +132,7 @@ unpackExtent(
ERR_LAB
}
if (h.sz_cpr > h.sz_unc
|| h.sz_unc > (int32_t)xo->size ) {
|| h.sz_unc > xo->size ) {
err_exit(5);
}
// Now we have:
@@ -272,48 +269,34 @@ ERR_LAB
**************************************************************************/
void *upx_main(
char *const uncbuf,
Elf32_Ehdr const *const my_ehdr,
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr
unsigned const junk,
f_expand *const f_decompress,
Elf32_Ehdr *const ehdr, // temp char[MAX_ELF_HDR]
struct Extent xi,
struct Extent xo
) __asm__("upx_main");
void *upx_main(
char *const uncbuf, // place to put decompressed shell script
Elf32_Ehdr const *const my_ehdr, // to get compressed size and data
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr // temp char[MAX_ELF_HDR]
unsigned const junk,
f_expand *const f_decompress,
Elf32_Ehdr *const ehdr, // temp char[MAX_ELF_HDR]
struct Extent xi,
struct Extent xo
)
{
// 'fn' and 'efn' must not suffer constant-propagation by gcc
// UPX2 = offset to name_of_shell
// UPX3 = strlen(name_of_shell)
char * /*const*/ volatile fn = UPX2 + xo.buf; // past "-c" and "#!"
char * /*const*/ volatile efn = UPX3 + fn; // &terminator
Elf32_Addr entry;
size_t const lsize = sizeof(struct p_info) +
*(unsigned short const *)(0x7c + (char const *)my_ehdr);
struct Extent xi = { // describe compressed shell script
((Elf32_Phdr const *)(1 + my_ehdr))->p_filesz - lsize,
lsize + CONST_CAST(char *, my_ehdr)
};
struct Extent xo = { ((struct p_info *)xi.buf)[-1].p_filesize, uncbuf };
// Allocate space for decompressed shell script.
// "1+": guarantee '\0' terminator at end of decompressed script
if (xo.buf != do_mmap(xo.buf, 1+3+xo.size, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0)) {
err_exit(20);
ERR_LAB
}
// Uncompress shell script
xo.buf += 3; // leave room for "-c" argument
(void)junk;
unpackExtent(&xi, &xo, f_decompress);
{ // Map shell program
// 'fn' and 'efn' must not suffer constant-propagation by gcc
// UPX2 = 3 + offset to name_of_shell
// UPX3 = strlen(name_of_shell)
char * /*const*/ volatile fn = UPX2 + uncbuf; // past "-c" and "#!"
char * /*const*/ volatile efn = UPX3 + fn; // &terminator
char const c = *efn; *efn = 0; // terminator
entry = getexec(fn, ehdr, av);
*efn = c; // replace terminator character
+27 -21
View File
@@ -106,12 +106,8 @@ decompress:
;__LEXEC020__
%define PAGE_MASK (~0<<12)
%define PAGE_SIZE ( 1<<12)
%define szElf32_Ehdr 0x34
%define p_memsz 5*4
%define MAP_FIXED 0x10
%define MAP_PRIVATE 0x02
%define MAP_ANONYMOUS 0x20
@@ -120,42 +116,52 @@ decompress:
%define PROT_EXEC 4
%define __NR_mmap 90
%define szElf32_Ehdr 0x34
%define szElf32_Phdr 8*4
%define e_entry (16 + 2*2 + 4)
%define p_memsz 5*4
%define szl_info 12
%define szp_info 12
%define p_filesize 4
; Decompress the rest of this loader, and jump to it
unfold:
pop esi ; &{ sz_uncompressed, sz_compressed, compressed_data...}
cld
lodsd
push eax ; sz_uncompressed (junk, actually)
push eax ; sz_uncompressed of folded stub (junk, actually)
push esp ; &sz_uncompressed
mov eax, ebp ; &decompress
and eax, dword PAGE_MASK ; &my_elfhdr
mov edx, eax ; need my_elfhdr later
add eax, [p_memsz + szElf32_Ehdr + eax]
mov edx, 0x00800000 ; origin of this program
mov eax, [p_memsz + szElf32_Ehdr + edx] ; length of loaded pages
add eax, edx
add edx, szElf32_Ehdr + 2*szElf32_Phdr ; convenient ptr
push eax ; &destination
; mmap a page to hold the decompressed program
xor ecx,ecx
push ecx
push ecx
mov ch, PAGE_SIZE >> 8
; mmap space for unfolded stub, and uncompressed script
mov ecx, [szl_info + p_filesize + edx] ; script size
add ecx, 1+ 3+ (3 -1)+ PAGE_SIZE ; '\0' + "-c" + decompr_overrun + stub
push eax ; offset (ignored when MAP_ANONYMOUS)
push eax ; fd (ignored when MAP_ANONYMOUS)
push byte MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS
push byte PROT_READ | PROT_WRITE | PROT_EXEC
push ecx
push ecx ; length
push eax ; destination
mov ebx, esp ; address of parameter vector for __NR_mmap
push byte __NR_mmap
pop eax
mov ebx, esp
int 0x80
lea ebx, [3+ PAGE_SIZE + eax] ; place for uncompressed script
add esp, byte 6*4 ; discard args to mmap
lodsd
push eax ; sz_compressed
push eax ; sz_compressed of folded stub
lodsd ; junk cto8, algo, unused[2]
push esi ; &compressed_data
call ebp ; decompress(&src, srclen, &dst, &dstlen)
pop ecx ; discard &compressed_data
pop ecx ; discard sz_compressed
pop ecx ; &destination
jmp ecx ; goto fold_begin at p_vaddr + p_memsz
pop eax ; discard &compressed_data
pop eax ; discard sz_compressed
ret ; &destination
main:
pop ebp ; &decompress
call unfold
-6
View File
@@ -46,10 +46,4 @@ SECTIONS
*(.bss)
*(COMMON)
}
/* 0x08048000: customary Linux/x86 Elf .text start */
/*
. = 0x08048000 + (0xfff & .);
.data : {
}
*/
}
+9
View File
@@ -88,6 +88,15 @@ typedef unsigned int nrv_uint32;
// From ../p_unix.h
struct b_info { // 12-byte header before each compressed block
unsigned sz_unc; // uncompressed_size
unsigned sz_cpr; // compressed_size
unsigned char b_method; // compression algorithm
unsigned char b_ftid; // filter id
unsigned char b_cto8; // filter parameter
unsigned char b_unused;
};
struct l_info // 12-byte trailer in header for loader (offset 116)
{
uint32_t l_checksum;