From ce1b58d29356fcc46c763b4caf24a2389441ff09 Mon Sep 17 00:00:00 2001 From: John Reiser Date: Sun, 7 Jan 2001 05:49:46 +0000 Subject: [PATCH] filters for linux/elf386; filter.cpp filter.h p_lx_elf.cpp p_lx_elf.h filter/ctojr.h stub/l_lx_elf.c stub/l_lx_elf86.asm committer: jreiser 978846586 +0000 --- src/filter.cpp | 1 + src/filter.h | 1 + src/filter/ctojr.h | 1 + src/p_lx_elf.cpp | 63 ++++++++++++++++--- src/p_lx_elf.h | 7 ++- src/stub/l_lx_elf.c | 16 ++++- src/stub/l_lx_elf86.asm | 134 +++++++++++++++++++++++++++++++++++++++- 7 files changed, 206 insertions(+), 17 deletions(-) diff --git a/src/filter.cpp b/src/filter.cpp index 0631242b..90b49df3 100644 --- a/src/filter.cpp +++ b/src/filter.cpp @@ -98,6 +98,7 @@ void Filter::init(int id_, unsigned addvalue_) this->preferred_ctos = NULL; // clear input/output parameters this->cto = 0; + this->n_mru = 0; } diff --git a/src/filter.h b/src/filter.h index e47d1739..f26f9879 100644 --- a/src/filter.h +++ b/src/filter.h @@ -86,6 +86,7 @@ public: unsigned wrongcalls; unsigned firstcall; unsigned lastcall; + unsigned n_mru; // ctojr only // Read only. int id; diff --git a/src/filter/ctojr.h b/src/filter/ctojr.h index ebd46351..a155b54c 100644 --- a/src/filter/ctojr.h +++ b/src/filter/ctojr.h @@ -85,6 +85,7 @@ static int F(Filter *f) int hand = 0, tail = 0; unsigned mru[N_MRU]; memset(&mru[0], 0, sizeof(mru)); + f->n_mru = N_MRU; #endif //} // FIXME: We must fit into 8MB because we steal one bit. diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index 09a6c324..48f8797a 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -30,6 +30,7 @@ #include "conf.h" #include "file.h" +#include "filter.h" #include "packer.h" #include "p_elf.h" #include "p_unix.h" @@ -59,6 +60,27 @@ PackLinuxI386elf::~PackLinuxI386elf() delete[] phdri; } +int const * +PackLinuxI386elf::getFilters() const +{ + static const int filters[] = { + 0x80, 0x36, 0x26, 0x24, 0x16, 0x13, 0x14, 0x11, 0x25, 0x15, 0x12, + -1 }; + return filters; +} + +int +PackLinuxI386elf::buildLoader(const Filter *ft) +{ + if (ft) { + n_mru = ft->n_mru; + } + else { + n_mru = 0; + } + return super::buildLoader(ft); +} + const upx_byte *PackLinuxI386elf::getLoader() const { if (M_IS_NRV2B(ph.method)) @@ -91,9 +113,15 @@ void PackLinuxI386elf::updateLoader(OutputFile *fo) // pre-calculate for benefit of runtime disappearing act via munmap() phdro->p_memsz = PAGE_MASK & (~PAGE_MASK + totlen); + int d1=0x80, d2=0x80; + if (this->n_mru) { + int const bytes = ('?'<<8) | 0x0f; + d1 += 4+ patch_le32(d1+loader, 400, "NMRU", this->n_mru); + d2 += 4+ patch_le32(d2+loader, 400, &bytes, (ph.filter_cto<<8)|0x0f); + } patchLoaderChecksum(); fo->seek(0, SEEK_SET); - fo->rewrite(loader, 0x80); + fo->rewrite(loader, UPX_MAX3(0x80, d1, d2)); #undef PAGE_MASK } @@ -205,7 +233,8 @@ void PackLinuxI386elf::packExtent( Extent const &x, OutputFile *fo, unsigned &total_in, - unsigned &total_out + unsigned &total_out, + Filter *ft ) { fi->seek(x.offset, SEEK_SET); @@ -222,7 +251,13 @@ void PackLinuxI386elf::packExtent( // compress ph.u_len = l; ph.overlap_overhead = 0; - (void) compress(ibuf, obuf); // ignore return value + if (ft) { + ft->buf_len = l; + compressWithFilters(ft, OVERHEAD); + } + else { + (void) compress(ibuf, obuf); // ignore return value + } if (ph.c_len < ph.u_len) { @@ -322,29 +357,37 @@ void PackLinuxI386elf::pack(OutputFile *fo) x.offset = 0; x.size = sizeof(Elf_LE32_Ehdr) + sz_phdrs; ui_pass = -1; - packExtent(x, fo, total_in, total_out); + packExtent(x, fo, total_in, total_out, 0); ui_pass = 0; + Filter ft(ph.level); + nx = 0; for (k = 0; k < ehdri.e_phnum; ++k) if (PT_LOAD==phdri[k].p_type) { + ft.addvalue = (unsigned)phdri[k].p_paddr; x.offset = phdri[k].p_offset; x.size = phdri[k].p_filesz; - if (0 == nx) { - x.offset += sizeof(Elf_LE32_Ehdr) + sz_phdrs; - x.size -= sizeof(Elf_LE32_Ehdr) + sz_phdrs; + if (0 == nx) { // 1st PT_LOAD must cover Ehdr at 0==p_offset + unsigned const delta = sizeof(Elf_LE32_Ehdr) + sz_phdrs; + ft.addvalue += delta; + x.offset += delta; + x.size -= delta; } - packExtent(x, fo, total_in, total_out); + packExtent(x, fo, total_in, total_out, + ((Elf_LE32_Phdr::PF_X & phdri[k].p_flags) ? &ft : 0) ); + // FIXME: All PF_X Phdrs must use same ft.cto + // (There is usually only one such Phdr, so we're mostly lucky.) ++nx; } if (ptload0hi < ptload1lo) { // alignment hole? x.offset = ptload0hi; x.size = ptload1lo - ptload0hi; - packExtent(x, fo, total_in, total_out); + packExtent(x, fo, total_in, total_out, 0); } if ((off_t)total_in < file_size) { // non-PT_LOAD stuff x.offset = total_in; x.size = file_size - total_in; - packExtent(x, fo, total_in, total_out); + packExtent(x, fo, total_in, total_out, 0); } if ((off_t)total_in != file_size) diff --git a/src/p_lx_elf.h b/src/p_lx_elf.h index f208fcdf..39669f19 100644 --- a/src/p_lx_elf.h +++ b/src/p_lx_elf.h @@ -44,7 +44,8 @@ public: virtual int getVersion() const { return 11; } virtual int getFormat() const { return UPX_F_LINUX_ELF_i386; } virtual const char *getName() const { return "linux/elf386"; } - virtual const int *getFilters() const { return NULL; } + virtual const int *getFilters() const; + virtual int buildLoader(const Filter *); virtual void pack(OutputFile *fo); virtual void unpack(OutputFile *fo); @@ -59,7 +60,7 @@ protected: off_t size; }; virtual void packExtent(Extent const &x, OutputFile *fo, - unsigned &total_in, unsigned &total_out); + unsigned &total_in, unsigned &total_out, Filter *); virtual void unpackExtent(unsigned wanted, OutputFile *fo, unsigned &total_in, unsigned &total_out, unsigned &c_adler, unsigned &u_adler); @@ -73,6 +74,8 @@ protected: Elf_LE32_Ehdr ehdri; // from input file Elf_LE32_Phdr *phdri; // for input file + + unsigned n_mru; }; diff --git a/src/stub/l_lx_elf.c b/src/stub/l_lx_elf.c index a5e6fdf2..859c23a5 100644 --- a/src/stub/l_lx_elf.c +++ b/src/stub/l_lx_elf.c @@ -102,6 +102,7 @@ do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) // UPX & NRV stuff **************************************************************************/ +typedef void f_unfilter(nrv_byte *, nrv_uint); // 1st param is also addvalue typedef int f_expand( const nrv_byte *, nrv_uint, nrv_byte *, nrv_uint * ); @@ -110,7 +111,8 @@ static void unpackExtent( struct Extent *const xi, // input struct Extent *const xo, // output - f_expand *const f_decompress + f_expand *const f_decompress, + f_unfilter *f_unf ) { while (xo->size) { @@ -148,6 +150,13 @@ ERR_LAB int const j = (*f_decompress)(xi->buf, h.sz_cpr, xo->buf, &out_len); if (j != 0 || out_len != (nrv_uint)h.sz_unc) err_exit(7); + // Skip Ehdr+Phdrs: separate 1st block, not filtered + if (f_unf // have filter + && ((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); + } xi->buf += h.sz_cpr; xi->size -= h.sz_cpr; } @@ -241,7 +250,8 @@ do_xmap(int const fdi, Elf32_Ehdr const *const ehdr, struct Extent *const xi, base = (unsigned long)addr; } if (xi) { - unpackExtent(xi, &xo, (f_expand *)fdi); + unpackExtent(xi, &xo, (f_expand *)fdi, + ((phdr->p_flags & PF_X) ? (f_unfilter *)(2+ fdi) : 0)); } bzero(addr, frag); // fragment at lo end frag = (-mlen) &~ PAGE_MASK; // distance to next page boundary @@ -333,7 +343,7 @@ void *upx_main( // Uncompress Ehdr and Phdrs. xo.size = sz_elfhdrs; xo.buf = (char *)ehdr; xi.size = 2*sizeof(size_t) + sz_pckhdrs; - unpackExtent(&xi, &xo, f_decompress); + 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; diff --git a/src/stub/l_lx_elf86.asm b/src/stub/l_lx_elf86.asm index 711e5323..5bc43772 100644 --- a/src/stub/l_lx_elf86.asm +++ b/src/stub/l_lx_elf86.asm @@ -80,6 +80,21 @@ _start: ;; Step through the code; remember that repeats the previous command. ;; call main ; push address of decompress subroutine +decompress: + jmps decompr0 + ;; 2+ address of decompress subroutine + ;; unfilter(upx_byte *, length) + pop edx ; return address + pop eax ; upx_byte *, same as addvalue + pop ecx ; length + pusha + xchg eax,edi ; edi= pointer + + push dword ('?'<<8) | 0x0f ; cto8_0f (cto8 byte is modified) + mov ebx, 'NMRU' ; modified + + xor edx,edx + jmp unf0 ; /************************************************************************* ; // C callable decompressor @@ -90,7 +105,7 @@ _start: %define OUTP dword [esp+8*4+12] %define OUTS dword [esp+8*4+16] -decompress: +decompr0: pusha ; cld @@ -128,6 +143,122 @@ decompress: popa ret +;; continuation of entry prolog for unfilter +unf0: + push edx ; tail + push ebx ; n_mru + mov esi,esp + +%define n_mru [esi] +%define tail [esi + 4*1] +%define cto8_0f [esi + 4*2] +%define cto8 [esi + 4*2 +1] +%define addvalue [esi + 4*3 + 7*4] + +unf1: ; allocate and clear mru[] + push edx + dec ebx + jnz unf1 ; leaves 0=='hand' + +%define tmp ebp + +%define jc eax +%define hand ebx +%define kh edx + +calltrickloop: + mov al, [edi] + inc edi + sub al, 0x80 ; base of Jcc + cmp al, 0x8f - 0x80 ; span of Jcc + ja ct2 ; not Jcc + mov edx, [edi] ; often unaligned + cmp dx, cto8_0f + jne unfcount + mov byte [edi -1], dl ; 0x0f prefix + add al, 0x80 ; reconstitute Jcc + dec ecx + mov byte [edi], al ; Jcc opcode + inc edi + jmps ct4 +ct2: + sub al, 0xE8 - 0x80 ; base of JMP/CALL + cmp al, 0xE9 - 0xE8 ; span of JMP/CALL + ja unfcount +ct3: + mov al, [edi] + cmp al, cto8 + jnz unfcount +ct4: + mov eax, [edi] + shr ax, 8 + rol eax, 16 + xchg al, ah + + shr jc, 1 ; eax= jc, or mru index + jnc ct6 ; not 1st time for this jc + dec hand + jge ct5 + add hand, n_mru +ct5: + mov [esp + 4*hand], jc ; 1st time: mru[hand] = jc + jmps ct_store + +ct6: ; not 1st time for this jc + lea kh, [jc + hand] ; kh = jc + hand + cmp kh, n_mru + jb ct7 + sub kh, n_mru +ct7: + mov jc, [esp + 4*kh] ; jc = mru[kh] + dec hand + jge ct8 + add hand, n_mru +ct8: + mov tmp, [esp + 4*hand] ; tmp = mru[hand] + push jc ; ran out of registers + test tmp,tmp + jnz ctmp1 + + mov eax, tail + dec eax + jge ct9 + add eax, n_mru +ct9: + xor tmp,tmp + mov tail, eax + xchg [4+ esp + 4*eax], tmp ; tmp = mru[tail]; mru[tail] = 0 +ctmp1: + pop jc + mov [esp + 4*kh ], tmp ; mru[kh] = tmp + mov [esp + 4*hand], jc ; mru[hand] = jc + +ct_store: + sub eax, edi + sub ecx, byte 4 + add eax, addvalue + mov [edi], eax + add edi, byte 4 +unfcount: + dec ecx + ;; jg calltrickloop + db 0x0f, 0x8f + dd calltrickloop - unfdone +unfdone: + + mov edi,esp ; clear mru[] portion of stack + mov ecx, n_mru + add ecx, byte 3 ; n_mru, tail, ct8_0f + xor eax,eax + rep + stosd + mov esp,edi + popa + push ecx + push eax + push edx + ret + %define PAGE_MASK (~0<<12) %define PAGE_SIZE ( 1<<12) @@ -274,6 +405,5 @@ L30: ; move existing Elf32_auxv sub edi, byte 8 ; point to AT_NULL ret - ; vi:ts=8:et:nowrap