mirror of
https://github.com/upx/upx
synced 2025-09-28 19:06:07 +08:00
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 <jreiser> 978846586 +0000
This commit is contained in:
parent
4d2b35c9ee
commit
ce1b58d293
|
@ -98,6 +98,7 @@ void Filter::init(int id_, unsigned addvalue_)
|
||||||
this->preferred_ctos = NULL;
|
this->preferred_ctos = NULL;
|
||||||
// clear input/output parameters
|
// clear input/output parameters
|
||||||
this->cto = 0;
|
this->cto = 0;
|
||||||
|
this->n_mru = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,7 @@ public:
|
||||||
unsigned wrongcalls;
|
unsigned wrongcalls;
|
||||||
unsigned firstcall;
|
unsigned firstcall;
|
||||||
unsigned lastcall;
|
unsigned lastcall;
|
||||||
|
unsigned n_mru; // ctojr only
|
||||||
|
|
||||||
// Read only.
|
// Read only.
|
||||||
int id;
|
int id;
|
||||||
|
|
|
@ -85,6 +85,7 @@ static int F(Filter *f)
|
||||||
int hand = 0, tail = 0;
|
int hand = 0, tail = 0;
|
||||||
unsigned mru[N_MRU];
|
unsigned mru[N_MRU];
|
||||||
memset(&mru[0], 0, sizeof(mru));
|
memset(&mru[0], 0, sizeof(mru));
|
||||||
|
f->n_mru = N_MRU;
|
||||||
#endif //}
|
#endif //}
|
||||||
|
|
||||||
// FIXME: We must fit into 8MB because we steal one bit.
|
// FIXME: We must fit into 8MB because we steal one bit.
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
|
#include "filter.h"
|
||||||
#include "packer.h"
|
#include "packer.h"
|
||||||
#include "p_elf.h"
|
#include "p_elf.h"
|
||||||
#include "p_unix.h"
|
#include "p_unix.h"
|
||||||
|
@ -59,6 +60,27 @@ PackLinuxI386elf::~PackLinuxI386elf()
|
||||||
delete[] phdri;
|
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
|
const upx_byte *PackLinuxI386elf::getLoader() const
|
||||||
{
|
{
|
||||||
if (M_IS_NRV2B(ph.method))
|
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()
|
// pre-calculate for benefit of runtime disappearing act via munmap()
|
||||||
phdro->p_memsz = PAGE_MASK & (~PAGE_MASK + totlen);
|
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();
|
patchLoaderChecksum();
|
||||||
fo->seek(0, SEEK_SET);
|
fo->seek(0, SEEK_SET);
|
||||||
fo->rewrite(loader, 0x80);
|
fo->rewrite(loader, UPX_MAX3(0x80, d1, d2));
|
||||||
#undef PAGE_MASK
|
#undef PAGE_MASK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +233,8 @@ void PackLinuxI386elf::packExtent(
|
||||||
Extent const &x,
|
Extent const &x,
|
||||||
OutputFile *fo,
|
OutputFile *fo,
|
||||||
unsigned &total_in,
|
unsigned &total_in,
|
||||||
unsigned &total_out
|
unsigned &total_out,
|
||||||
|
Filter *ft
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
fi->seek(x.offset, SEEK_SET);
|
fi->seek(x.offset, SEEK_SET);
|
||||||
|
@ -222,7 +251,13 @@ void PackLinuxI386elf::packExtent(
|
||||||
// compress
|
// compress
|
||||||
ph.u_len = l;
|
ph.u_len = l;
|
||||||
ph.overlap_overhead = 0;
|
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)
|
if (ph.c_len < ph.u_len)
|
||||||
{
|
{
|
||||||
|
@ -322,29 +357,37 @@ void PackLinuxI386elf::pack(OutputFile *fo)
|
||||||
x.offset = 0;
|
x.offset = 0;
|
||||||
x.size = sizeof(Elf_LE32_Ehdr) + sz_phdrs;
|
x.size = sizeof(Elf_LE32_Ehdr) + sz_phdrs;
|
||||||
ui_pass = -1;
|
ui_pass = -1;
|
||||||
packExtent(x, fo, total_in, total_out);
|
packExtent(x, fo, total_in, total_out, 0);
|
||||||
ui_pass = 0;
|
ui_pass = 0;
|
||||||
|
|
||||||
|
Filter ft(ph.level);
|
||||||
|
|
||||||
nx = 0;
|
nx = 0;
|
||||||
for (k = 0; k < ehdri.e_phnum; ++k) if (PT_LOAD==phdri[k].p_type) {
|
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.offset = phdri[k].p_offset;
|
||||||
x.size = phdri[k].p_filesz;
|
x.size = phdri[k].p_filesz;
|
||||||
if (0 == nx) {
|
if (0 == nx) { // 1st PT_LOAD must cover Ehdr at 0==p_offset
|
||||||
x.offset += sizeof(Elf_LE32_Ehdr) + sz_phdrs;
|
unsigned const delta = sizeof(Elf_LE32_Ehdr) + sz_phdrs;
|
||||||
x.size -= 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;
|
++nx;
|
||||||
}
|
}
|
||||||
if (ptload0hi < ptload1lo) { // alignment hole?
|
if (ptload0hi < ptload1lo) { // alignment hole?
|
||||||
x.offset = ptload0hi;
|
x.offset = ptload0hi;
|
||||||
x.size = ptload1lo - 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
|
if ((off_t)total_in < file_size) { // non-PT_LOAD stuff
|
||||||
x.offset = total_in;
|
x.offset = total_in;
|
||||||
x.size = file_size - 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)
|
if ((off_t)total_in != file_size)
|
||||||
|
|
|
@ -44,7 +44,8 @@ public:
|
||||||
virtual int getVersion() const { return 11; }
|
virtual int getVersion() const { return 11; }
|
||||||
virtual int getFormat() const { return UPX_F_LINUX_ELF_i386; }
|
virtual int getFormat() const { return UPX_F_LINUX_ELF_i386; }
|
||||||
virtual const char *getName() const { return "linux/elf386"; }
|
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 pack(OutputFile *fo);
|
||||||
virtual void unpack(OutputFile *fo);
|
virtual void unpack(OutputFile *fo);
|
||||||
|
@ -59,7 +60,7 @@ protected:
|
||||||
off_t size;
|
off_t size;
|
||||||
};
|
};
|
||||||
virtual void packExtent(Extent const &x, OutputFile *fo,
|
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,
|
virtual void unpackExtent(unsigned wanted, OutputFile *fo,
|
||||||
unsigned &total_in, unsigned &total_out,
|
unsigned &total_in, unsigned &total_out,
|
||||||
unsigned &c_adler, unsigned &u_adler);
|
unsigned &c_adler, unsigned &u_adler);
|
||||||
|
@ -73,6 +74,8 @@ protected:
|
||||||
|
|
||||||
Elf_LE32_Ehdr ehdri; // from input file
|
Elf_LE32_Ehdr ehdri; // from input file
|
||||||
Elf_LE32_Phdr *phdri; // for input file
|
Elf_LE32_Phdr *phdri; // for input file
|
||||||
|
|
||||||
|
unsigned n_mru;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,7 @@ do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
|
||||||
// UPX & NRV stuff
|
// UPX & NRV stuff
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
typedef void f_unfilter(nrv_byte *, nrv_uint); // 1st param is also addvalue
|
||||||
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 * );
|
||||||
|
@ -110,7 +111,8 @@ static void
|
||||||
unpackExtent(
|
unpackExtent(
|
||||||
struct Extent *const xi, // input
|
struct Extent *const xi, // input
|
||||||
struct Extent *const xo, // output
|
struct Extent *const xo, // output
|
||||||
f_expand *const f_decompress
|
f_expand *const f_decompress,
|
||||||
|
f_unfilter *f_unf
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
while (xo->size) {
|
while (xo->size) {
|
||||||
|
@ -148,6 +150,13 @@ ERR_LAB
|
||||||
int const j = (*f_decompress)(xi->buf, h.sz_cpr, xo->buf, &out_len);
|
int const j = (*f_decompress)(xi->buf, h.sz_cpr, xo->buf, &out_len);
|
||||||
if (j != 0 || out_len != (nrv_uint)h.sz_unc)
|
if (j != 0 || out_len != (nrv_uint)h.sz_unc)
|
||||||
err_exit(7);
|
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->buf += h.sz_cpr;
|
||||||
xi->size -= 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;
|
base = (unsigned long)addr;
|
||||||
}
|
}
|
||||||
if (xi) {
|
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
|
bzero(addr, frag); // fragment at lo end
|
||||||
frag = (-mlen) &~ PAGE_MASK; // distance to next page boundary
|
frag = (-mlen) &~ PAGE_MASK; // distance to next page boundary
|
||||||
|
@ -333,7 +343,7 @@ void *upx_main(
|
||||||
// Uncompress Ehdr and Phdrs.
|
// Uncompress Ehdr and Phdrs.
|
||||||
xo.size = sz_elfhdrs; xo.buf = (char *)ehdr;
|
xo.size = sz_elfhdrs; xo.buf = (char *)ehdr;
|
||||||
xi.size = 2*sizeof(size_t) + sz_pckhdrs;
|
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.
|
// Prepare to decompress the Elf headers again, into the first PT_LOAD.
|
||||||
xi.buf -= 2*sizeof(size_t) + sz_pckhdrs;
|
xi.buf -= 2*sizeof(size_t) + sz_pckhdrs;
|
||||||
|
|
|
@ -80,6 +80,21 @@ _start:
|
||||||
;; Step through the code; remember that <Enter> repeats the previous command.
|
;; Step through the code; remember that <Enter> repeats the previous command.
|
||||||
;;
|
;;
|
||||||
call main ; push address of decompress subroutine
|
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
|
; // C callable decompressor
|
||||||
|
@ -90,7 +105,7 @@ _start:
|
||||||
%define OUTP dword [esp+8*4+12]
|
%define OUTP dword [esp+8*4+12]
|
||||||
%define OUTS dword [esp+8*4+16]
|
%define OUTS dword [esp+8*4+16]
|
||||||
|
|
||||||
decompress:
|
decompr0:
|
||||||
pusha
|
pusha
|
||||||
; cld
|
; cld
|
||||||
|
|
||||||
|
@ -128,6 +143,122 @@ decompress:
|
||||||
popa
|
popa
|
||||||
ret
|
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 <d32>
|
||||||
|
cmp al, 0x8f - 0x80 ; span of Jcc <d32>
|
||||||
|
ja ct2 ; not Jcc <d32>
|
||||||
|
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 <d32>
|
||||||
|
cmp al, 0xE9 - 0xE8 ; span of JMP/CALL <d32>
|
||||||
|
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_MASK (~0<<12)
|
||||||
%define PAGE_SIZE ( 1<<12)
|
%define PAGE_SIZE ( 1<<12)
|
||||||
|
@ -274,6 +405,5 @@ L30: ; move existing Elf32_auxv
|
||||||
sub edi, byte 8 ; point to AT_NULL
|
sub edi, byte 8 ; point to AT_NULL
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
; vi:ts=8:et:nowrap
|
; vi:ts=8:et:nowrap
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user