mirror of
https://github.com/upx/upx
synced 2025-09-28 19:06:07 +08:00
filters for unix(linux)
Modified Files: filteri.cpp filter/ctojr.h linker.cpp linker.h mem.cpp mem.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 packer.cpp packer.h packhead.cpp stub/Makefile stub/macros.ash 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_sh86.asm stub/l_lx_sh86.lds Added Files: filter/ctok.h stub/fold_elf86.asm stub/fold_exec86.asm stub/fold_sh86.asm committer: jreiser <jreiser> 979796725 +0000
This commit is contained in:
parent
4d45677160
commit
df9db96bd1
|
@ -33,7 +33,29 @@
|
|||
**************************************************************************/
|
||||
|
||||
#ifdef U //{
|
||||
static int const N_MRU = 1024; // does not have to be a power of 2
|
||||
#define NOFILT 0 // no filter
|
||||
#define FNOMRU 1 // filter, but not using mru
|
||||
#define MRUFLT 2 // mru filter
|
||||
|
||||
static unsigned
|
||||
f80_call(Filter const *f)
|
||||
{
|
||||
return (1+ (0x0f & f->id)) % 3;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
f80_jmp1(Filter const *f)
|
||||
{
|
||||
return ((1+ (0x0f & f->id)) / 3) % 3;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
f80_jcc2(Filter const *f)
|
||||
{
|
||||
return f80_jmp1(f);
|
||||
}
|
||||
|
||||
static int const N_MRU = 32; // does not have to be a power of 2
|
||||
|
||||
// Adaptively remember recent destinations.
|
||||
static void
|
||||
|
@ -70,7 +92,6 @@ static int F(Filter *f)
|
|||
#ifdef U
|
||||
// filter
|
||||
upx_byte *const b = f->buf;
|
||||
const unsigned addvalue = f->addvalue;
|
||||
#else
|
||||
// scan
|
||||
const upx_byte *b = f->buf;
|
||||
|
@ -80,22 +101,30 @@ static int F(Filter *f)
|
|||
unsigned ic, jc, kc;
|
||||
unsigned calls = 0, noncalls = 0, noncalls2 = 0;
|
||||
unsigned lastnoncall = size, lastcall = 0;
|
||||
unsigned wtally[3]; memset(wtally, 0, sizeof(wtally));
|
||||
|
||||
#ifdef U //{
|
||||
unsigned const f_call = f80_call(f);
|
||||
unsigned const f_jmp1 = f80_jmp1(f);
|
||||
unsigned const f_jcc2 = f80_jcc2(f);
|
||||
|
||||
int hand = 0, tail = 0;
|
||||
unsigned mru[N_MRU];
|
||||
memset(&mru[0], 0, sizeof(mru));
|
||||
f->n_mru = N_MRU;
|
||||
assert(N_MRU<=256);
|
||||
f->n_mru = (MRUFLT==f_call || MRUFLT==f_jmp1 || MRUFLT==f_jcc2) ?
|
||||
N_MRU : 0;
|
||||
#endif //}
|
||||
|
||||
// FIXME: We must fit into 8MB because we steal one bit.
|
||||
// find a 16MB large empty address space
|
||||
{
|
||||
int which;
|
||||
unsigned char buf[256];
|
||||
memset(buf,0,256);
|
||||
|
||||
for (ic = 0; ic < size - 5; ic++)
|
||||
if (CONDF(b,ic,lastcall) && get_le32(b+ic+1)+ic+1 >= size)
|
||||
if (CONDF(which,b,ic,lastcall) && get_le32(b+ic+1)+ic+1 >= size)
|
||||
{
|
||||
buf[b[ic+1]] |= 1;
|
||||
}
|
||||
|
@ -110,14 +139,17 @@ static int F(Filter *f)
|
|||
|
||||
for (ic = 0; ic < size - 5; ic++)
|
||||
{
|
||||
if (!CONDF(b,ic,lastcall))
|
||||
int which;
|
||||
int f_on = 0;
|
||||
if (!CONDF(which,b,ic,lastcall))
|
||||
continue;
|
||||
++wtally[which];
|
||||
jc = get_le32(b+ic+1)+ic+1;
|
||||
// try to detect 'real' calls only
|
||||
if (jc < size)
|
||||
{
|
||||
#ifdef U
|
||||
if (COND2(b,lastcall,ic,ic-1,ic)) { // 6-byte Jcc <disp32>
|
||||
if (2==which && NOFILT!=f_jcc2) { // 6-byte Jcc <disp32>
|
||||
// Prefix 0x0f is constant, but opcode condition 0x80..0x8f
|
||||
// varies. Because we store the destination (or its mru index)
|
||||
// in be32 big endian format, the low-addressed bytes
|
||||
|
@ -130,9 +162,13 @@ static int F(Filter *f)
|
|||
}
|
||||
// FIXME [?]: Extend to 8 bytes if "ADD ESP, byte 4*n" follows CALL.
|
||||
// This will require two related cto's (consecutive, or otherwise).
|
||||
{
|
||||
if ((0==which && MRUFLT==f_call)
|
||||
|| (1==which && MRUFLT==f_jmp1)
|
||||
|| (2==which && MRUFLT==f_jcc2) ) {
|
||||
f_on = 1;
|
||||
// Recode the destination: narrower mru indices
|
||||
// should compress better than wider addresses.
|
||||
// (But not when offset of match is unlimited?)
|
||||
int k;
|
||||
for (k = 0; k < N_MRU; ++k) {
|
||||
int kh = hand + k;
|
||||
|
@ -153,38 +189,45 @@ static int F(Filter *f)
|
|||
}
|
||||
mru[hand] = jc;
|
||||
}
|
||||
} else
|
||||
if ((0==which && NOFILT!=f_call)
|
||||
|| (1==which && NOFILT!=f_jmp1)
|
||||
|| (2==which && NOFILT!=f_jcc2) ) {
|
||||
f_on = 1;
|
||||
set_be32(b+ic+1, jc+cto);
|
||||
}
|
||||
jc += addvalue;
|
||||
#endif
|
||||
if (ic - lastnoncall < 5)
|
||||
{
|
||||
// check the last 4 bytes before this call
|
||||
for (kc = 4; kc; kc--)
|
||||
if (CONDF(b,ic-kc,lastcall) && b[ic-kc+1] == cto8)
|
||||
break;
|
||||
if (kc)
|
||||
{
|
||||
#ifdef U
|
||||
// restore original
|
||||
if (COND2(b,lastcall,ic,ic,ic-1)) {
|
||||
// Unswap prefix and opcode for 6-byte Jcc <disp32>
|
||||
unsigned char const t =
|
||||
b[ic-1];
|
||||
b[ic-1] = b[ic];
|
||||
b[ic] = t;
|
||||
}
|
||||
set_le32(b+ic+1,jc-ic-1);
|
||||
#endif
|
||||
if (b[ic+1] == cto8)
|
||||
return 1; // fail - buffer not restored
|
||||
lastnoncall = ic;
|
||||
noncalls2++;
|
||||
continue;
|
||||
}
|
||||
if (f_on) {
|
||||
if (ic - lastnoncall < 5)
|
||||
{
|
||||
// check the last 4 bytes before this call
|
||||
for (kc = 4; kc; kc--)
|
||||
if (CONDF(which,b,ic-kc,lastcall) && b[ic-kc+1] == cto8)
|
||||
break;
|
||||
if (kc)
|
||||
{
|
||||
#ifdef U
|
||||
// restore original
|
||||
if (2==which) {
|
||||
// Unswap prefix and opcode for 6-byte Jcc <disp32>
|
||||
unsigned char const t =
|
||||
b[ic-1];
|
||||
b[ic-1] = b[ic];
|
||||
b[ic] = t;
|
||||
}
|
||||
set_le32(b+ic+1,jc-ic-1);
|
||||
#endif
|
||||
if (b[ic+1] == cto8)
|
||||
return 1; // fail - buffer not restored
|
||||
lastnoncall = ic;
|
||||
noncalls2++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
calls++;
|
||||
ic += 4;
|
||||
lastcall = ic+1;
|
||||
}
|
||||
calls++;
|
||||
ic += 4;
|
||||
lastcall = ic+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -198,9 +241,11 @@ static int F(Filter *f)
|
|||
f->noncalls = noncalls;
|
||||
f->lastcall = lastcall;
|
||||
|
||||
#ifdef TESTING
|
||||
printf("\ncalls=%d noncalls=%d noncalls2=%d text_size=%x calltrickoffset=%x\n",calls,noncalls,noncalls2,size,cto);
|
||||
#endif
|
||||
/*#ifdef TESTING*/
|
||||
printf("\ncalls=%d noncalls=%d noncalls2=%d text_size=%x calltrickoffset=%x\n",
|
||||
calls,noncalls,noncalls2,size,cto8);
|
||||
printf("CALL/JMP/JCC %d %d %d\n",wtally[0],wtally[1],wtally[2]);
|
||||
/*#endif*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -219,43 +264,62 @@ static int U(Filter *f)
|
|||
const unsigned cto = (unsigned)f->cto << 24;
|
||||
unsigned lastcall = 0;
|
||||
int hand = 0, tail = 0;
|
||||
unsigned const f_call = f80_call(f);
|
||||
unsigned const f_jmp1 = f80_jmp1(f);
|
||||
unsigned const f_jcc2 = f80_jcc2(f);
|
||||
|
||||
unsigned mru[N_MRU];
|
||||
memset(&mru[0], 0, sizeof(mru));
|
||||
|
||||
for (ic = 0; ic < size5; ic++) {
|
||||
if (CONDU(b,ic,lastcall))
|
||||
int which;
|
||||
if (CONDU(which,b,ic,lastcall))
|
||||
{
|
||||
unsigned f_on = 0;
|
||||
jc = get_be32(b+ic+1) - cto;
|
||||
if (b[ic+1] == f->cto)
|
||||
{
|
||||
if (1&jc) { // 1st time at this destination
|
||||
jc >>= 1;
|
||||
if (0 > --hand) {
|
||||
hand = N_MRU -1;
|
||||
}
|
||||
mru[hand] = jc;
|
||||
if ((0==which && MRUFLT==f_call)
|
||||
|| (1==which && MRUFLT==f_jmp1)
|
||||
|| (2==which && MRUFLT==f_jcc2) ) {
|
||||
f_on = 1;
|
||||
if (1&jc) { // 1st time at this destination
|
||||
jc >>= 1;
|
||||
if (0 > --hand) {
|
||||
hand = N_MRU -1;
|
||||
}
|
||||
mru[hand] = jc;
|
||||
}
|
||||
else { // not 1st time at this destination
|
||||
jc >>= 1;
|
||||
int kh = jc + hand;
|
||||
if (N_MRU <= kh) {
|
||||
kh -= N_MRU;
|
||||
}
|
||||
jc = mru[kh];
|
||||
update_mru(jc, kh, mru, hand, tail);
|
||||
}
|
||||
set_le32(b+ic+1,jc-ic-1);
|
||||
} else
|
||||
if ((0==which && NOFILT!=f_call)
|
||||
|| (1==which && NOFILT!=f_jmp1)
|
||||
|| (2==which && NOFILT!=f_jcc2) ) {
|
||||
f_on = 1;
|
||||
set_le32(b+ic+1,jc-ic-1);
|
||||
}
|
||||
else { // not 1st time at this destination
|
||||
jc >>= 1;
|
||||
int kh = jc + hand;
|
||||
if (N_MRU <= kh) {
|
||||
kh -= N_MRU;
|
||||
}
|
||||
jc = mru[kh];
|
||||
update_mru(jc, kh, mru, hand, tail);
|
||||
}
|
||||
set_le32(b+ic+1,jc-ic-1);
|
||||
|
||||
if (COND2(b,lastcall,ic,ic,ic-1)) {
|
||||
if (2==which && NOFILT!=f_jcc2) {
|
||||
// Unswap prefix and opcode for 6-byte Jcc <disp32>
|
||||
unsigned char const t =
|
||||
b[ic-1];
|
||||
b[ic-1] = b[ic];
|
||||
b[ic] = t;
|
||||
b[ic] = t;
|
||||
}
|
||||
|
||||
if (f_on) {
|
||||
f->calls++;
|
||||
ic += 4;
|
||||
f->lastcall = lastcall = ic+1;
|
||||
}
|
||||
f->calls++;
|
||||
ic += 4;
|
||||
f->lastcall = lastcall = ic+1;
|
||||
}
|
||||
else
|
||||
f->noncalls++;
|
||||
|
|
166
src/filter/ctok.h
Normal file
166
src/filter/ctok.h
Normal file
|
@ -0,0 +1,166 @@
|
|||
/* ctok.h -- filter CTO implementation
|
||||
|
||||
This file is part of the UPX executable compressor.
|
||||
|
||||
Copyright (C) 1996-2001 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996-2001 Laszlo Molnar
|
||||
Copyright (C) 2000-2001 John F. Reiser
|
||||
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 John F. Reiser
|
||||
markus@oberhumer.com ml1050@cdata.tvnet.hu jreiser@BitWagon.com
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
// filter / scan
|
||||
**************************************************************************/
|
||||
|
||||
static int F(Filter *f)
|
||||
{
|
||||
#ifdef U
|
||||
// filter
|
||||
upx_byte *b = f->buf;
|
||||
const unsigned addvalue = f->addvalue;
|
||||
#else
|
||||
// scan
|
||||
const upx_byte *b = f->buf;
|
||||
#endif
|
||||
const unsigned size = f->buf_len;
|
||||
unsigned const id = f->id;
|
||||
|
||||
unsigned ic, jc, kc;
|
||||
unsigned calls = 0, noncalls = 0, noncalls2 = 0;
|
||||
unsigned lastnoncall = size, lastcall = 0;
|
||||
|
||||
// find a 16MB large empty address space
|
||||
{
|
||||
unsigned char buf[256];
|
||||
memset(buf,0,256);
|
||||
|
||||
for (ic = 0; ic < size - 5; ic++)
|
||||
if (COND(b,ic,lastcall,id) && get_le32(b+ic+1)+ic+1 >= size)
|
||||
{
|
||||
buf[b[ic+1]] |= 1;
|
||||
}
|
||||
|
||||
if (getcto(f, buf) < 0)
|
||||
return -1;
|
||||
}
|
||||
const unsigned char cto8 = f->cto;
|
||||
#ifdef U
|
||||
const unsigned cto = (unsigned)f->cto << 24;
|
||||
#endif
|
||||
|
||||
for (ic = 0; ic < size - 5; ic++)
|
||||
{
|
||||
if (!COND(b,ic,lastcall,id))
|
||||
continue;
|
||||
jc = get_le32(b+ic+1)+ic+1;
|
||||
// try to detect 'real' calls only
|
||||
if (jc < size)
|
||||
{
|
||||
#ifdef U
|
||||
set_be32(b+ic+1,jc+addvalue+cto);
|
||||
#endif
|
||||
if (ic - lastnoncall < 5)
|
||||
{
|
||||
// check the last 4 bytes before this call
|
||||
for (kc = 4; kc; kc--)
|
||||
if (COND(b,ic-kc,lastcall,id) && b[ic-kc+1] == cto8)
|
||||
break;
|
||||
if (kc)
|
||||
{
|
||||
#ifdef U
|
||||
// restore original
|
||||
set_le32(b+ic+1,jc-ic-1);
|
||||
#endif
|
||||
if (b[ic+1] == cto8)
|
||||
return 1; // fail - buffer not restored
|
||||
lastnoncall = ic;
|
||||
noncalls2++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
calls++;
|
||||
ic += 4;
|
||||
lastcall = ic+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(b[ic+1] != cto8); // this should not happen
|
||||
lastnoncall = ic;
|
||||
noncalls++;
|
||||
}
|
||||
}
|
||||
|
||||
f->calls = calls;
|
||||
f->noncalls = noncalls;
|
||||
f->lastcall = lastcall;
|
||||
|
||||
#ifdef TESTING
|
||||
printf("\ncalls=%d noncalls=%d noncalls2=%d text_size=%x calltrickoffset=%x\n",calls,noncalls,noncalls2,size,cto);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
// unfilter
|
||||
**************************************************************************/
|
||||
|
||||
#ifdef U
|
||||
static int U(Filter *f)
|
||||
{
|
||||
upx_byte *b = f->buf;
|
||||
const unsigned size5 = f->buf_len - 5;
|
||||
const unsigned addvalue = f->addvalue;
|
||||
const unsigned cto = (unsigned)f->cto << 24;
|
||||
unsigned const id = f->id;
|
||||
unsigned lastcall = 0;
|
||||
|
||||
unsigned ic, jc;
|
||||
|
||||
for (ic = 0; ic < size5; ic++)
|
||||
if (COND(b,ic,lastcall,id))
|
||||
{
|
||||
jc = get_be32(b+ic+1);
|
||||
if (b[ic+1] == f->cto)
|
||||
{
|
||||
set_le32(b+ic+1,jc-ic-1-addvalue-cto);
|
||||
f->calls++;
|
||||
ic += 4;
|
||||
f->lastcall = lastcall = ic+1;
|
||||
}
|
||||
else
|
||||
f->noncalls++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#undef F
|
||||
#undef U
|
||||
|
||||
|
||||
/*
|
||||
vi:ts=4:et:nowrap
|
||||
*/
|
||||
|
|
@ -88,9 +88,7 @@
|
|||
// cto calltrick with jmp
|
||||
**************************************************************************/
|
||||
|
||||
#define COND(b,x,lastcall) \
|
||||
(b[x] == 0xe8 || b[x] == 0xe9 \
|
||||
|| (lastcall!=(x) && 0xf==b[(x)-1] && 0x80<=b[x] && b[x]<=0x8f) )
|
||||
#define COND(b,x,lastcall) (b[x] == 0xe8 || b[x] == 0xe9)
|
||||
#define F f_ctoj32_e8e9_bswap_le
|
||||
#define U u_ctoj32_e8e9_bswap_le
|
||||
#include "filter/ctoj.h"
|
||||
|
@ -100,15 +98,37 @@
|
|||
|
||||
|
||||
/*************************************************************************
|
||||
// cto calltrick with jmp and relative renumbering
|
||||
// cto calltrick with jmp, optional jcc
|
||||
**************************************************************************/
|
||||
|
||||
#define COND1(b,x) (b[x] == 0xe8 || b[x] == 0xe9)
|
||||
#define COND2(b,lastcall,x,y,z) \
|
||||
(lastcall!=(x) && 0xf==b[y] && 0x80<=b[z] && b[z]<=0x8f)
|
||||
#define COND1(b,x) (b[x] == 0xe8 || b[x] == 0xe9)
|
||||
#define COND2(b,x,lc) (lc!=(x) && 0xf==b[(x)-1] && 0x80<=b[x] && b[x]<=0x8f)
|
||||
#define COND(b,x,lc,id) (COND1(b,x) || ((9<=(0xf&(id))) && COND2(b,x,lc)))
|
||||
#define F f_ctok32_e8e9_bswap_le
|
||||
#define U u_ctok32_e8e9_bswap_le
|
||||
#include "filter/ctok.h"
|
||||
#define F s_ctok32_e8e9_bswap_le
|
||||
#include "filter/ctok.h"
|
||||
#undef COND
|
||||
#undef COND2
|
||||
#undef COND1
|
||||
|
||||
#define CONDF(b,x,lastcall) (COND1(b,x) || COND2(b,lastcall,x,(x)-1, x ))
|
||||
#define CONDU(b,x,lastcall) (COND1(b,x) || COND2(b,lastcall,x, x ,(x)-1))
|
||||
|
||||
/*************************************************************************
|
||||
// cto calltrick with jmp and jcc and relative renumbering
|
||||
**************************************************************************/
|
||||
|
||||
#define COND_CALL(which,b,x) ((which = 0), b[x] == 0xe8)
|
||||
#define COND_JMP( which,b,x) ((which = 1), b[x] == 0xe9)
|
||||
#define COND_JCC( which,b,lastcall,x,y,z) ((which = 2), \
|
||||
(lastcall!=(x) && 0xf==b[y] && 0x80<=b[z] && b[z]<=0x8f))
|
||||
#define COND1(which,b,x) (COND_CALL(which,b,x) || COND_JMP(which,b,x))
|
||||
#define COND2(which,b,lastcall,x,y,z) COND_JCC(which,b,lastcall,x,y,z)
|
||||
|
||||
#define CONDF(which,b,x,lastcall) \
|
||||
(COND1(which,b,x) || COND2(which,b,lastcall,x,(x)-1, x ))
|
||||
#define CONDU(which,b,x,lastcall) \
|
||||
(COND1(which,b,x) || COND2(which,b,lastcall,x, x ,(x)-1))
|
||||
|
||||
#define F f_ctojr32_e8e9_bswap_le
|
||||
#define U u_ctojr32_e8e9_bswap_le
|
||||
|
@ -120,6 +140,9 @@
|
|||
#undef CONDF
|
||||
#undef COND2
|
||||
#undef COND1
|
||||
#undef COND_JCC
|
||||
#undef COND_JMP
|
||||
#undef COND_CALL
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
|
@ -178,8 +201,19 @@ const FilterImp::FilterEntry FilterImp::filters[] = {
|
|||
// 32-bit cto calltrick with jmp
|
||||
{ 0x36, 6, 0x00ffffff, f_ctoj32_e8e9_bswap_le, u_ctoj32_e8e9_bswap_le, s_ctoj32_e8e9_bswap_le },
|
||||
|
||||
// 32-bit cto calltrick with jmp and relative renumbering
|
||||
// 32-bit calltrick with jmp, optional jcc; runtime can unfilter more than one block
|
||||
{ 0x46, 6, 0x00ffffff, f_ctok32_e8e9_bswap_le, u_ctok32_e8e9_bswap_le, s_ctok32_e8e9_bswap_le },
|
||||
{ 0x49, 6, 0x00ffffff, f_ctok32_e8e9_bswap_le, u_ctok32_e8e9_bswap_le, s_ctok32_e8e9_bswap_le },
|
||||
|
||||
// 32-bit cto calltrick with jmp and jcc(swap 0x0f/0x8Y) and relative renumbering
|
||||
{ 0x80, 8, 0x00ffffff, f_ctojr32_e8e9_bswap_le, u_ctojr32_e8e9_bswap_le, s_ctojr32_e8e9_bswap_le },
|
||||
{ 0x81, 8, 0x00ffffff, f_ctojr32_e8e9_bswap_le, u_ctojr32_e8e9_bswap_le, s_ctojr32_e8e9_bswap_le },
|
||||
{ 0x82, 8, 0x00ffffff, f_ctojr32_e8e9_bswap_le, u_ctojr32_e8e9_bswap_le, s_ctojr32_e8e9_bswap_le },
|
||||
{ 0x83, 8, 0x00ffffff, f_ctojr32_e8e9_bswap_le, u_ctojr32_e8e9_bswap_le, s_ctojr32_e8e9_bswap_le },
|
||||
{ 0x84, 8, 0x00ffffff, f_ctojr32_e8e9_bswap_le, u_ctojr32_e8e9_bswap_le, s_ctojr32_e8e9_bswap_le },
|
||||
{ 0x85, 8, 0x00ffffff, f_ctojr32_e8e9_bswap_le, u_ctojr32_e8e9_bswap_le, s_ctojr32_e8e9_bswap_le },
|
||||
{ 0x86, 8, 0x00ffffff, f_ctojr32_e8e9_bswap_le, u_ctojr32_e8e9_bswap_le, s_ctojr32_e8e9_bswap_le },
|
||||
{ 0x87, 8, 0x00ffffff, f_ctojr32_e8e9_bswap_le, u_ctojr32_e8e9_bswap_le, s_ctojr32_e8e9_bswap_le },
|
||||
|
||||
// simple delta filter
|
||||
{ 0x90, 2, 0, f_sub8_1, u_sub8_1, s_sub8_1 },
|
||||
|
|
|
@ -46,7 +46,6 @@ struct Linker::jump
|
|||
int toffs;
|
||||
};
|
||||
|
||||
|
||||
Linker::Linker(const void *pdata, int plen, int pinfo)
|
||||
{
|
||||
iloader = new char[(ilen = plen) + 4096];
|
||||
|
@ -101,7 +100,7 @@ Linker::~Linker()
|
|||
}
|
||||
|
||||
|
||||
void Linker::addSection(const char *sect)
|
||||
int Linker::addSection(const char *sect)
|
||||
{
|
||||
int ic;
|
||||
while (*sect)
|
||||
|
@ -129,11 +128,12 @@ void Linker::addSection(const char *sect)
|
|||
olen += sections[ic].len;
|
||||
break;
|
||||
}
|
||||
//printf("%8.8s",section);
|
||||
//printf("%8.8s",sect);
|
||||
assert(ic!=nsections);
|
||||
}
|
||||
sect += 8;
|
||||
}
|
||||
return olen;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -35,10 +35,11 @@ class Linker
|
|||
public:
|
||||
Linker(const void *pdata, int plen, int pinfo);
|
||||
virtual ~Linker();
|
||||
void addSection(const char *sect);
|
||||
int addSection(const char *sect);
|
||||
void addSection(const char *sname, const void *sdata, unsigned len);
|
||||
const char *getLoader(int *llen);
|
||||
int getSection(const char *name, int *slen) const;
|
||||
int getLoaderSize() const { return olen; }
|
||||
|
||||
protected:
|
||||
// little endian
|
||||
|
|
41
src/mem.cpp
41
src/mem.cpp
|
@ -47,6 +47,14 @@ MemBuffer::~MemBuffer()
|
|||
this->free();
|
||||
}
|
||||
|
||||
MemBufferIO::MemBufferIO(unsigned size) :
|
||||
MemBuffer(size)
|
||||
{
|
||||
}
|
||||
|
||||
MemBufferIO::~MemBufferIO()
|
||||
{
|
||||
}
|
||||
|
||||
void MemBuffer::free()
|
||||
{
|
||||
|
@ -67,6 +75,39 @@ unsigned MemBuffer::getSize() const
|
|||
}
|
||||
|
||||
|
||||
unsigned MemBufferIO::seek(unsigned offset, int whence)
|
||||
{
|
||||
switch (whence) {
|
||||
default: {
|
||||
assert(false);
|
||||
} break;
|
||||
case SEEK_SET: {
|
||||
assert(offset<=alloc_size);
|
||||
ptr = offset + alloc_ptr;
|
||||
} break;
|
||||
case SEEK_CUR: {
|
||||
assert((offset + (ptr - alloc_ptr))<=alloc_size);
|
||||
ptr += offset;
|
||||
} break;
|
||||
case SEEK_END: {
|
||||
assert((offset + alloc_size)<=alloc_size);
|
||||
ptr = offset + alloc_size + alloc_ptr;
|
||||
} break;
|
||||
}
|
||||
return ptr - alloc_ptr;
|
||||
}
|
||||
|
||||
unsigned MemBufferIO::write(void const *data, unsigned size)
|
||||
{
|
||||
unsigned const avail = getSize();
|
||||
unsigned const len = UPX_MIN(size, avail);
|
||||
if (data!=ptr) {
|
||||
memmove(ptr, data, len);
|
||||
}
|
||||
ptr += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
void MemBuffer::alloc(unsigned size, unsigned base_offset)
|
||||
{
|
||||
#if 0
|
||||
|
|
|
@ -55,6 +55,7 @@ public:
|
|||
private:
|
||||
void alloc(unsigned size, unsigned base_offset);
|
||||
|
||||
protected:
|
||||
unsigned char *ptr;
|
||||
unsigned char *alloc_ptr;
|
||||
unsigned alloc_size;
|
||||
|
@ -71,6 +72,14 @@ private:
|
|||
//static void operator delete[] (void *) {}
|
||||
};
|
||||
|
||||
class MemBufferIO : public MemBuffer {
|
||||
public:
|
||||
MemBufferIO(unsigned size=0);
|
||||
~MemBufferIO();
|
||||
|
||||
unsigned seek(unsigned offset, int whence); // returns new position
|
||||
unsigned write(void const *data, unsigned size); // returns xfer count
|
||||
};
|
||||
|
||||
#endif /* already included */
|
||||
|
||||
|
|
222
src/p_lx_elf.cpp
222
src/p_lx_elf.cpp
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include "file.h"
|
||||
#include "filter.h"
|
||||
#include "linker.h"
|
||||
#include "packer.h"
|
||||
#include "p_elf.h"
|
||||
#include "p_unix.h"
|
||||
|
@ -45,9 +46,9 @@
|
|||
**************************************************************************/
|
||||
|
||||
static const
|
||||
#include "stub/l_le_n2b.h"
|
||||
#include "stub/l_lx_elf86.h"
|
||||
static const
|
||||
#include "stub/l_le_n2d.h"
|
||||
#include "stub/fold_elf86.h"
|
||||
|
||||
|
||||
PackLinuxI386elf::PackLinuxI386elf(InputFile *f) :
|
||||
|
@ -64,7 +65,12 @@ int const *
|
|||
PackLinuxI386elf::getFilters() const
|
||||
{
|
||||
static const int filters[] = {
|
||||
0x80, 0x36, 0x26, 0x24, 0x16, 0x13, 0x14, 0x11, 0x25, 0x15, 0x12,
|
||||
0x49, 0x46,
|
||||
0x83, 0x36, 0x26,
|
||||
0x86, 0x80,
|
||||
0x84, 0x87, 0x81,
|
||||
0x82, 0x85,
|
||||
0x24, 0x16, 0x13, 0x14, 0x11, 0x25, 0x15, 0x12,
|
||||
-1 };
|
||||
return filters;
|
||||
}
|
||||
|
@ -72,103 +78,34 @@ PackLinuxI386elf::getFilters() const
|
|||
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))
|
||||
return linux_i386elf_nrv2b_loader;
|
||||
if (M_IS_NRV2D(ph.method))
|
||||
return linux_i386elf_nrv2d_loader;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int PackLinuxI386elf::getLoaderSize() const
|
||||
{
|
||||
if (0 != lsize) {
|
||||
return lsize;
|
||||
}
|
||||
if (M_IS_NRV2B(ph.method))
|
||||
return sizeof(linux_i386elf_nrv2b_loader);
|
||||
if (M_IS_NRV2D(ph.method))
|
||||
return sizeof(linux_i386elf_nrv2d_loader);
|
||||
return 0;
|
||||
return buildLinuxLoader(
|
||||
linux_i386elf_loader, sizeof(linux_i386elf_loader),
|
||||
linux_i386elf_fold, sizeof(linux_i386elf_fold),
|
||||
ft, getbrk(phdri, ehdri.e_phnum) );
|
||||
}
|
||||
|
||||
|
||||
void PackLinuxI386elf::updateLoader(OutputFile *fo)
|
||||
{
|
||||
#define PAGE_MASK (~0<<12)
|
||||
Elf_LE32_Phdr *const phdro = (Elf_LE32_Phdr *)(sizeof(Elf_LE32_Ehdr)+loader);
|
||||
upx_byte *const ptr = const_cast<upx_byte *>(getLoader());
|
||||
Elf_LE32_Phdr *const phdro = (Elf_LE32_Phdr *)(sizeof(Elf_LE32_Ehdr) + ptr);
|
||||
off_t const totlen = fo->getBytesWritten();
|
||||
phdro->p_filesz = totlen;
|
||||
|
||||
// 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, UPX_MAX3(0x80, d1, d2));
|
||||
#undef PAGE_MASK
|
||||
}
|
||||
|
||||
|
||||
void PackLinuxI386elf::patchLoader()
|
||||
{
|
||||
unsigned char *const ptr = const_cast<unsigned char *>(getLoader());
|
||||
lsize = getLoaderSize();
|
||||
Elf_LE32_Ehdr *const ehdr = (Elf_LE32_Ehdr *)(void *)loader;
|
||||
Elf_LE32_Phdr *const phdr = (Elf_LE32_Phdr *)(1+ehdr);
|
||||
|
||||
// stub/scripts/setfold.pl puts address of 'fold_begin' in 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);
|
||||
|
||||
// compress compiled C-code portion of loader
|
||||
upx_uint const uncLsize = lsize - fold_begin;
|
||||
upx_uint cprLsize;
|
||||
int r = upx_compress(loader + fold_begin, uncLsize, cprLoader, &cprLsize,
|
||||
NULL, ph.method, 10, NULL, NULL);
|
||||
if (r != UPX_E_OK || cprLsize >= uncLsize)
|
||||
throwInternalError("loaded compression failed");
|
||||
|
||||
set_le32(0+fold_begin+loader, uncLsize);
|
||||
set_le32(4+fold_begin+loader, cprLsize);
|
||||
memcpy( 8+fold_begin+loader, cprLoader, cprLsize);
|
||||
lsize = 8 + fold_begin + cprLsize;
|
||||
patchVersion(loader,lsize);
|
||||
|
||||
// Info for OS kernel to set the brk()
|
||||
unsigned const brka = getbrk(phdri, ehdri.e_phnum);
|
||||
phdr[1].p_offset = 0xfff&brka;
|
||||
phdr[1].p_vaddr = brka;
|
||||
phdr[1].p_paddr = brka;
|
||||
phdr[1].p_filesz = 0;
|
||||
phdr[1].p_memsz = 0;
|
||||
|
||||
// The beginning of our loader consists of a elf_hdr (52 bytes) and
|
||||
// two sections elf_phdr (2 * 32 byte), so we have 12 free bytes
|
||||
// from offset 116 to the program start at offset 128.
|
||||
assert(ehdr->e_phoff == sizeof(Elf_LE32_Ehdr));
|
||||
assert(ehdr->e_ehsize == sizeof(Elf_LE32_Ehdr));
|
||||
assert(ehdr->e_phentsize == sizeof(Elf_LE32_Phdr));
|
||||
assert(ehdr->e_phnum == 2);
|
||||
assert(ehdr->e_shnum == 0);
|
||||
assert(lsize > 128 && lsize < 4096);
|
||||
patchVersion(ptr, lsize);
|
||||
|
||||
patchLoaderChecksum();
|
||||
}
|
||||
|
@ -228,10 +165,13 @@ bool PackLinuxI386elf::canPack()
|
|||
return super::canPack();
|
||||
}
|
||||
|
||||
struct cprBlkHdr {
|
||||
unsigned sz_unc; // uncompressed size (0 means EOF)
|
||||
unsigned sz_cpr; // (compressed_size<<8) | cto8
|
||||
};
|
||||
|
||||
void PackLinuxI386elf::packExtent(
|
||||
Extent const &x,
|
||||
OutputFile *fo,
|
||||
unsigned &total_in,
|
||||
unsigned &total_out,
|
||||
Filter *ft
|
||||
|
@ -249,11 +189,13 @@ void PackLinuxI386elf::packExtent(
|
|||
// file is e.g. blocksize + 1 bytes long
|
||||
|
||||
// compress
|
||||
unsigned char *const hdrptr = obuf;
|
||||
obuf.seek(sizeof(cprBlkHdr), SEEK_CUR);
|
||||
ph.u_len = l;
|
||||
ph.overlap_overhead = 0;
|
||||
if (ft) {
|
||||
ft->buf_len = l;
|
||||
compressWithFilters(ft, OVERHEAD);
|
||||
compressWithFilters(ft, OVERHEAD, ((opt->filter > 0) ? -2 : 2));
|
||||
}
|
||||
else {
|
||||
(void) compress(ibuf, obuf); // ignore return value
|
||||
|
@ -273,19 +215,18 @@ void PackLinuxI386elf::packExtent(
|
|||
}
|
||||
|
||||
// write block sizes
|
||||
unsigned char size[8];
|
||||
set_native32(size+0, ph.u_len);
|
||||
set_native32(size+4, ph.c_len);
|
||||
fo->write(size, 8);
|
||||
set_native32(0+hdrptr, ph.u_len);
|
||||
set_native32(4+hdrptr, (ph.c_len<<8) | ph.filter_cto);
|
||||
|
||||
// write compressed data
|
||||
if (ph.c_len < ph.u_len)
|
||||
{
|
||||
fo->write(obuf, ph.c_len);
|
||||
verifyOverlappingDecompression();
|
||||
obuf.write(obuf, ph.c_len);
|
||||
// FIXME: obuf is not discardable!
|
||||
// verifyOverlappingDecompression();
|
||||
}
|
||||
else
|
||||
fo->write(ibuf, ph.u_len);
|
||||
obuf.write(ibuf, ph.u_len);
|
||||
|
||||
total_in += ph.u_len;
|
||||
total_out += ph.c_len;
|
||||
|
@ -300,30 +241,24 @@ void PackLinuxI386elf::pack(OutputFile *fo)
|
|||
progid = 0; // not used
|
||||
|
||||
fi->readx(&ehdri, sizeof(ehdri));
|
||||
assert(ehdri.e_phoff == sizeof(Elf_LE32_Ehdr)); // checked by canPack()
|
||||
off_t const sz_phdrs = ehdri.e_phnum * ehdri.e_phentsize;
|
||||
|
||||
phdri = new Elf_LE32_Phdr[ehdri.e_phnum];
|
||||
fi->seek(ehdri.e_phoff, SEEK_SET);
|
||||
fi->readx(phdri, sz_phdrs);
|
||||
|
||||
// prepare loader
|
||||
lsize = getLoaderSize();
|
||||
loader.alloc(lsize + sizeof(p_info));
|
||||
memcpy(loader,getLoader(),lsize);
|
||||
|
||||
// patch loader, prepare header info, write loader + header info
|
||||
patchLoader(); // can change lsize by packing upx_main
|
||||
p_info *const hbuf = (p_info *)(loader + lsize);
|
||||
set_native32(&hbuf->p_progid, progid);
|
||||
set_native32(&hbuf->p_filesize, file_size);
|
||||
set_native32(&hbuf->p_blocksize, blocksize);
|
||||
fo->write(loader, lsize + sizeof(p_info));
|
||||
|
||||
// init compression buffers
|
||||
ibuf.alloc(blocksize);
|
||||
obuf.allocForCompression(blocksize);
|
||||
{
|
||||
p_info hbuf;
|
||||
set_native32(&hbuf.p_progid, progid);
|
||||
set_native32(&hbuf.p_filesize, file_size);
|
||||
set_native32(&hbuf.p_blocksize, blocksize);
|
||||
obuf.write(&hbuf, sizeof(hbuf));
|
||||
}
|
||||
|
||||
assert(ehdri.e_phoff == sizeof(Elf_LE32_Ehdr)); // checked by canPack()
|
||||
Extent x;
|
||||
unsigned k;
|
||||
|
||||
|
@ -354,52 +289,69 @@ void PackLinuxI386elf::pack(OutputFile *fo)
|
|||
unsigned total_in = 0;
|
||||
unsigned total_out = 0;
|
||||
|
||||
ui_pass = -1;
|
||||
x.offset = 0;
|
||||
x.size = sizeof(Elf_LE32_Ehdr) + sz_phdrs;
|
||||
ui_pass = -1;
|
||||
packExtent(x, fo, total_in, total_out, 0);
|
||||
ui_pass = 0;
|
||||
{
|
||||
int const old_level = ph.level; ph.level = 10;
|
||||
packExtent(x, total_in, total_out, 0);
|
||||
ph.level = old_level;
|
||||
}
|
||||
|
||||
ui_pass = 0;
|
||||
Filter ft(ph.level);
|
||||
ft.addvalue = 0;
|
||||
|
||||
nx = 0;
|
||||
for (k = 0; k < ehdri.e_phnum; ++k) if (PT_LOAD==phdri[k].p_type) {
|
||||
ft.addvalue = (unsigned)phdri[k].p_paddr;
|
||||
if (ft.id < 0x40) {
|
||||
// FIXME: ?? ft.addvalue = phdri[k].p_vaddr;
|
||||
}
|
||||
x.offset = phdri[k].p_offset;
|
||||
x.size = phdri[k].p_filesz;
|
||||
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;
|
||||
if (ft.id < 0x40) {
|
||||
// FIXME: ?? ft.addvalue += delta;
|
||||
}
|
||||
x.offset += delta;
|
||||
x.size -= delta;
|
||||
}
|
||||
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.)
|
||||
packExtent(x, total_in, total_out,
|
||||
((Elf_LE32_Phdr::PF_X & phdri[k].p_flags)
|
||||
? &ft : 0 ) );
|
||||
++nx;
|
||||
}
|
||||
if (ptload0hi < ptload1lo) { // alignment hole?
|
||||
x.offset = ptload0hi;
|
||||
x.size = ptload1lo - ptload0hi;
|
||||
packExtent(x, fo, total_in, total_out, 0);
|
||||
packExtent(x, 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, 0);
|
||||
packExtent(x, total_in, total_out, 0);
|
||||
}
|
||||
|
||||
if ((off_t)total_in != file_size)
|
||||
throwEOFException();
|
||||
|
||||
// write block end marker (uncompressed size 0)
|
||||
fo->write("\x00\x00\x00\x00", 4);
|
||||
set_native32(obuf, 0);
|
||||
obuf.write(obuf, 4);
|
||||
|
||||
// update header with totals
|
||||
ph.u_len = total_in;
|
||||
ph.c_len = total_out;
|
||||
|
||||
upx_byte const *p = getLoader();
|
||||
lsize = getLoaderSize();
|
||||
patchFilter32(const_cast<upx_byte *>(p), lsize, &ft);
|
||||
fo->write(p, lsize);
|
||||
|
||||
unsigned pos = obuf.seek(0, SEEK_CUR);
|
||||
fo->write(obuf - pos, pos);
|
||||
|
||||
// write packheader
|
||||
writePackHeader(fo);
|
||||
|
||||
|
@ -408,6 +360,8 @@ void PackLinuxI386elf::pack(OutputFile *fo)
|
|||
fo->write(obuf, 4);
|
||||
|
||||
updateLoader(fo);
|
||||
fo->seek(0, SEEK_SET);
|
||||
fo->rewrite(p, lsize);
|
||||
|
||||
// finally check the compression ratio
|
||||
if (!checkFinalCompressionRatio(fo))
|
||||
|
@ -417,12 +371,16 @@ void PackLinuxI386elf::pack(OutputFile *fo)
|
|||
|
||||
void PackLinuxI386elf::unpackExtent(unsigned wanted, OutputFile *fo,
|
||||
unsigned &total_in, unsigned &total_out,
|
||||
unsigned &c_adler, unsigned &u_adler)
|
||||
unsigned &c_adler, unsigned &u_adler,
|
||||
bool first_PF_X
|
||||
)
|
||||
{
|
||||
while (wanted) {
|
||||
fi->readx(ibuf, 8);
|
||||
int const sz_unc = ph.u_len = get_native32(ibuf+0);
|
||||
int const sz_cpr = ph.c_len = get_native32(ibuf+4);
|
||||
unsigned const tmp = get_native32(ibuf+4);
|
||||
int const sz_cpr = ph.c_len = tmp>>8;
|
||||
ph.filter_cto = tmp<<24;
|
||||
|
||||
if (sz_unc == 0) { // must never happen while 0!=wanted
|
||||
throwCompressedDataViolation();
|
||||
|
@ -441,6 +399,15 @@ void PackLinuxI386elf::unpackExtent(unsigned wanted, OutputFile *fo,
|
|||
if (sz_cpr < sz_unc)
|
||||
{
|
||||
decompress(ibuf+j, ibuf, false);
|
||||
if (first_PF_X) { // Elf32_Ehdr is never filtered
|
||||
first_PF_X = false; // but everything else might be
|
||||
}
|
||||
else if (ph.filter) {
|
||||
Filter ft(ph.level);
|
||||
ft.init(ph.filter, 0);
|
||||
ft.cto = ph.filter_cto;
|
||||
ft.unfilter(ibuf, sz_unc);
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
// update checksum of uncompressed data
|
||||
|
@ -473,7 +440,9 @@ void PackLinuxI386elf::unpack(OutputFile *fo)
|
|||
ibuf.alloc(blocksize + OVERHEAD);
|
||||
fi->readx(ibuf, 2*4);
|
||||
ph.u_len = get_native32(0+ibuf);
|
||||
ph.c_len = get_native32(4+ibuf);
|
||||
unsigned const tmp = get_native32(4+ibuf);
|
||||
ph.c_len = tmp>>8;
|
||||
ph.filter_cto = tmp<<24;
|
||||
|
||||
// Uncompress Ehdr and Phdrs.
|
||||
fi->readx(ibuf, ph.c_len);
|
||||
|
@ -486,6 +455,7 @@ void PackLinuxI386elf::unpack(OutputFile *fo)
|
|||
off_t ptload0hi=0, ptload1lo=0;
|
||||
|
||||
// decompress PT_LOAD
|
||||
bool first_PF_X = true;
|
||||
fi->seek(- (off_t) (2*4 + ph.c_len), SEEK_CUR);
|
||||
for (unsigned j=0; j < ehdr->e_phnum; ++phdr, ++j) {
|
||||
if (PT_LOAD==phdr->p_type) {
|
||||
|
@ -497,19 +467,29 @@ void PackLinuxI386elf::unpack(OutputFile *fo)
|
|||
}
|
||||
if (fo)
|
||||
fo->seek(phdr->p_offset, SEEK_SET);
|
||||
unpackExtent(phdr->p_filesz, fo, total_in, total_out, c_adler, u_adler);
|
||||
if (Elf_LE32_Phdr::PF_X & phdr->p_flags) {
|
||||
unpackExtent(phdr->p_filesz, fo, total_in, total_out,
|
||||
c_adler, u_adler, first_PF_X);
|
||||
first_PF_X = false;
|
||||
}
|
||||
else {
|
||||
unpackExtent(phdr->p_filesz, fo, total_in, total_out,
|
||||
c_adler, u_adler, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ptload0hi < ptload1lo) { // alignment hole?
|
||||
if (fo)
|
||||
fo->seek(ptload0hi, SEEK_SET);
|
||||
unpackExtent(ptload1lo - ptload0hi, fo, total_in, total_out, c_adler, u_adler);
|
||||
unpackExtent(ptload1lo - ptload0hi, fo, total_in, total_out,
|
||||
c_adler, u_adler, false);
|
||||
}
|
||||
if (total_out != orig_file_size) { // non-PT_LOAD stuff
|
||||
if (fo)
|
||||
fo->seek(0, SEEK_END);
|
||||
unpackExtent(orig_file_size - total_out, fo, total_in, total_out, c_adler, u_adler);
|
||||
unpackExtent(orig_file_size - total_out, fo, total_in, total_out,
|
||||
c_adler, u_adler, false);
|
||||
}
|
||||
|
||||
// check for end-of-file
|
||||
|
|
|
@ -59,15 +59,17 @@ protected:
|
|||
off_t offset;
|
||||
off_t size;
|
||||
};
|
||||
virtual void packExtent(Extent const &x, OutputFile *fo,
|
||||
virtual void packExtent(Extent const &x,
|
||||
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);
|
||||
unsigned &c_adler, unsigned &u_adler, bool first_PF_X);
|
||||
|
||||
protected:
|
||||
#if 0 //{
|
||||
virtual const upx_byte *getLoader() const;
|
||||
virtual int getLoaderSize() const;
|
||||
#endif //}
|
||||
|
||||
virtual void patchLoader();
|
||||
virtual void updateLoader(OutputFile *);
|
||||
|
@ -75,7 +77,6 @@ protected:
|
|||
Elf_LE32_Ehdr ehdri; // from input file
|
||||
Elf_LE32_Phdr *phdri; // for input file
|
||||
|
||||
unsigned n_mru;
|
||||
};
|
||||
|
||||
|
||||
|
|
270
src/p_lx_exc.cpp
270
src/p_lx_exc.cpp
|
@ -4,6 +4,7 @@
|
|||
|
||||
Copyright (C) 1996-2001 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996-2001 Laszlo Molnar
|
||||
Copyright (C) 2001 John F. Reiser
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
|
@ -21,14 +22,16 @@
|
|||
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
|
||||
markus@oberhumer.com ml1050@cdata.tvnet.hu
|
||||
Markus F.X.J. Oberhumer Laszlo Molnar John F. Reiser
|
||||
markus@oberhumer.com ml1050@cdata.tvnet.hu jreiser@BitWagon.com
|
||||
*/
|
||||
|
||||
|
||||
#include "conf.h"
|
||||
|
||||
#include "file.h"
|
||||
#include "filter.h"
|
||||
#include "linker.h"
|
||||
#include "packer.h"
|
||||
#include "p_elf.h"
|
||||
#include "p_unix.h"
|
||||
|
@ -42,9 +45,9 @@
|
|||
**************************************************************************/
|
||||
|
||||
static const
|
||||
#include "stub/l_lx_n2b.h"
|
||||
#include "stub/l_lx_exec86.h"
|
||||
static const
|
||||
#include "stub/l_lx_n2d.h"
|
||||
#include "stub/fold_exec86.h"
|
||||
|
||||
|
||||
const int *PackLinuxI386::getCompressionMethods(int method, int level) const
|
||||
|
@ -61,29 +64,196 @@ const int *PackLinuxI386::getCompressionMethods(int method, int level) const
|
|||
return m_nrv2d;
|
||||
}
|
||||
|
||||
|
||||
const upx_byte *PackLinuxI386::getLoader() const
|
||||
int const *
|
||||
PackLinuxI386::getFilters() const
|
||||
{
|
||||
if (M_IS_NRV2B(ph.method))
|
||||
return linux_i386exec_nrv2b_loader;
|
||||
if (M_IS_NRV2D(ph.method))
|
||||
return linux_i386exec_nrv2d_loader;
|
||||
return NULL;
|
||||
static const int filters[] = {
|
||||
0x49, 0x46,
|
||||
0x83, 0x86, 0x80, 0x84, 0x87, 0x81, 0x82, 0x85,
|
||||
0x24, 0x16, 0x13, 0x14, 0x11, 0x25, 0x15, 0x12,
|
||||
-1 };
|
||||
return filters;
|
||||
}
|
||||
|
||||
struct cprElfhdr {
|
||||
struct Elf_LE32_Ehdr ehdr;
|
||||
struct Elf_LE32_Phdr phdr[2];
|
||||
struct PackUnix::l_info linfo;
|
||||
};
|
||||
|
||||
int PackLinuxI386::getLoaderSize() const
|
||||
int
|
||||
PackLinuxI386::buildLinuxLoader(
|
||||
upx_byte const *const proto,
|
||||
unsigned const szproto,
|
||||
upx_byte const *const fold,
|
||||
unsigned const szfold,
|
||||
Filter const *ft,
|
||||
unsigned const brka
|
||||
)
|
||||
{
|
||||
if (0!=lsize) {
|
||||
return lsize;
|
||||
initLoader(proto, szproto);
|
||||
|
||||
struct cprElfhdr elfhdr = *(struct cprElfhdr const *)fold;
|
||||
memset(&elfhdr.linfo, 0, sizeof(elfhdr.linfo));
|
||||
|
||||
// Info for OS kernel to set the brk()
|
||||
if (brka) {
|
||||
assert(ph.format==UPX_F_LINUX_ELF_i386
|
||||
|| ph.format==UPX_F_LINUX_SH_i386 );
|
||||
if (ph.format==UPX_F_LINUX_SH_i386) {
|
||||
assert(elfhdr.ehdr.e_phnum==1);
|
||||
elfhdr.ehdr.e_phnum = 2;
|
||||
}
|
||||
elfhdr.phdr[1].p_offset = 0xfff&brka;
|
||||
elfhdr.phdr[1].p_vaddr = brka;
|
||||
elfhdr.phdr[1].p_paddr = brka;
|
||||
elfhdr.phdr[1].p_filesz = 0;
|
||||
elfhdr.phdr[1].p_memsz = 0;
|
||||
}
|
||||
if (M_IS_NRV2B(ph.method))
|
||||
return sizeof(linux_i386exec_nrv2b_loader);
|
||||
if (M_IS_NRV2D(ph.method))
|
||||
return sizeof(linux_i386exec_nrv2d_loader);
|
||||
return 0;
|
||||
|
||||
// The beginning of our loader consists of a elf_hdr (52 bytes) and
|
||||
// two sections elf_phdr (2 * 32 byte), so we have 12 free bytes
|
||||
// from offset 116 to the program start at offset 128.
|
||||
assert(elfhdr.ehdr.e_phoff == sizeof(Elf_LE32_Ehdr));
|
||||
assert(elfhdr.ehdr.e_shoff == 0);
|
||||
assert(elfhdr.ehdr.e_ehsize == sizeof(Elf_LE32_Ehdr));
|
||||
assert(elfhdr.ehdr.e_phentsize == sizeof(Elf_LE32_Phdr));
|
||||
assert(elfhdr.ehdr.e_phnum == (unsigned)(1+ (0!=brka)));
|
||||
assert(elfhdr.ehdr.e_shnum == 0);
|
||||
linker->addSection("ELFHEADX", (unsigned char const *)&elfhdr, sizeof(elfhdr));
|
||||
addLoader("ELFHEADX", 0);
|
||||
|
||||
struct {
|
||||
upx_uint sz_unc; // uncompressed
|
||||
upx_uint sz_cpr; // compressed
|
||||
} h = {
|
||||
szfold - sizeof(elfhdr), 0
|
||||
};
|
||||
unsigned char const *const uncLoader = (unsigned char const *)(1+
|
||||
(struct cprElfhdr const *)fold );
|
||||
unsigned char *const cprLoader = new unsigned char[sizeof(h) + h.sz_unc];
|
||||
|
||||
int r = upx_compress(uncLoader, h.sz_unc, sizeof(h) + cprLoader, &h.sz_cpr,
|
||||
NULL, ph.method, 10, NULL, NULL );
|
||||
if (r != UPX_E_OK || h.sz_cpr >= h.sz_unc)
|
||||
throwInternalError("loader compression failed");
|
||||
memcpy(cprLoader, &h, sizeof(h));
|
||||
linker->addSection("FOLDEXEC", cprLoader, sizeof(h) + h.sz_cpr);
|
||||
delete cprLoader;
|
||||
|
||||
n_mru = ft->n_mru;
|
||||
|
||||
addLoader("IDENTSTR", 0);
|
||||
addLoader("LEXEC000", 0);
|
||||
|
||||
if (ft->id) {
|
||||
if (ph.format==UPX_F_LINUX_ELF_i386) { // decompr, unfilter are separate
|
||||
addLoader("LXUNF000", 0);
|
||||
addLoader("LXUNF002", 0);
|
||||
if (0x80==(ft->id & 0xF0)) {
|
||||
if (256==n_mru) {
|
||||
addLoader("MRUBYTE0", 0);
|
||||
}
|
||||
else if (n_mru) {
|
||||
addLoader("LXMRU005", 0);
|
||||
}
|
||||
if (n_mru) {
|
||||
addLoader("LXMRU006", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("LXMRU007", 0);
|
||||
}
|
||||
}
|
||||
else if (0x40==(ft->id & 0xF0)) {
|
||||
addLoader("LXUNF008", 0);
|
||||
}
|
||||
addLoader("LXUNF010", 0);
|
||||
}
|
||||
if (n_mru) {
|
||||
addLoader("LEXEC009", 0);
|
||||
}
|
||||
}
|
||||
addLoader("LEXEC010", 0);
|
||||
addLoader(getDecompressor(), 0);
|
||||
addLoader("LEXEC015", 0);
|
||||
if (ft->id) {
|
||||
if (ph.format==UPX_F_LINUX_ELF_i386) { // decompr, unfilter are separate
|
||||
if (0x80!=(ft->id & 0xF0)) {
|
||||
addLoader("LXUNF042", 0);
|
||||
}
|
||||
}
|
||||
else { // decompr, unfilter not separate
|
||||
if (0x80==(ft->id & 0xF0)) {
|
||||
addLoader("LEXEC110", 0);
|
||||
if (n_mru) {
|
||||
addLoader("LEXEC100", 0);
|
||||
}
|
||||
// bug in APP: jmp and label must be in same .asx/.asy
|
||||
addLoader("LEXEC016", 0);
|
||||
}
|
||||
}
|
||||
addFilter32(ft->id);
|
||||
if (ph.format==UPX_F_LINUX_ELF_i386) { // decompr, unfilter are separate
|
||||
if (0x80==(ft->id & 0xF0)) {
|
||||
if (0==n_mru) {
|
||||
addLoader("LXMRU058", 0);
|
||||
}
|
||||
}
|
||||
addLoader("LXUNF035", 0);
|
||||
}
|
||||
else { // decompr always unfilters
|
||||
addLoader("LEXEC017", 0);
|
||||
}
|
||||
}
|
||||
|
||||
addLoader("LEXEC020", 0);
|
||||
addLoader("FOLDEXEC", 0);
|
||||
|
||||
struct Elf_LE32_Ehdr *const ldrEhdr =
|
||||
(struct Elf_LE32_Ehdr *)const_cast<unsigned char *>(getLoader());
|
||||
unsigned e_entry = getLoaderSectionStart("LEXEC000");
|
||||
ldrEhdr->e_entry = e_entry + elfhdr.phdr[0].p_vaddr;
|
||||
|
||||
char *ptr_cto = e_entry + (char *)ldrEhdr;
|
||||
int sz_cto = getLoaderSize() - e_entry;
|
||||
if (0x20==(ft->id & 0xF0) || 0x30==(ft->id & 0xF0)) { // push byte '?' ; cto8
|
||||
patch_le16(ptr_cto, sz_cto, "\x6a?", 0x6a + (ft->cto << 8));
|
||||
}
|
||||
|
||||
// FIXME ?? patchVersion((char *)ldrEhdr, e_entry);
|
||||
return getLoaderSize();
|
||||
}
|
||||
|
||||
int
|
||||
PackLinuxI386::buildLoader(Filter const *ft)
|
||||
{
|
||||
unsigned const sz_fold = sizeof(linux_i386exec_fold);
|
||||
MemBuffer buf(sz_fold);
|
||||
memcpy(buf, linux_i386exec_fold, sz_fold);
|
||||
|
||||
// patch loader
|
||||
// note: we only can use /proc/<pid>/fd when exetype > 0.
|
||||
// also, we sleep much longer when compressing a script.
|
||||
checkPatch(0,0,0,0); // reset
|
||||
patch_le32(buf,sz_fold,"UPX4",exetype > 0 ? 3 : 15); // sleep time
|
||||
patch_le32(buf,sz_fold,"UPX3",progid);
|
||||
patch_le32(buf,sz_fold,"UPX2",exetype > 0 ? 0 : 0x7fffffff);
|
||||
|
||||
// get fresh filter
|
||||
Filter fold_ft = *ft;
|
||||
fold_ft.init(ft->id, ft->addvalue);
|
||||
int preferred_ctos[2] = {ft->cto, -1};
|
||||
fold_ft.preferred_ctos = preferred_ctos;
|
||||
|
||||
// filter
|
||||
optimizeFilter(&fold_ft, buf, sz_fold);
|
||||
bool success = fold_ft.filter(buf + sizeof(cprElfhdr), sz_fold - sizeof(cprElfhdr));
|
||||
(void)success;
|
||||
|
||||
return buildLinuxLoader(
|
||||
linux_i386exec_loader, sizeof(linux_i386exec_loader),
|
||||
buf, sz_fold, ft, 0 );
|
||||
}
|
||||
|
||||
int PackLinuxI386::getLoaderPrefixSize() const
|
||||
{
|
||||
|
@ -198,58 +368,13 @@ bool PackLinuxI386::canPack()
|
|||
|
||||
void PackLinuxI386::patchLoader()
|
||||
{
|
||||
lsize = getLoaderSize();
|
||||
|
||||
// patch loader
|
||||
// note: we only can use /proc/<pid>/fd when exetype > 0.
|
||||
// also, we sleep much longer when compressing a script.
|
||||
patch_le32(loader,lsize,"UPX4",exetype > 0 ? 3 : 15); // sleep time
|
||||
patch_le32(loader,lsize,"UPX3",exetype > 0 ? 0 : 0x7fffffff);
|
||||
patch_le32(loader,lsize,"UPX2",progid);
|
||||
patchVersion(loader,lsize);
|
||||
|
||||
Elf_LE32_Ehdr *const ehdr = (Elf_LE32_Ehdr *)(void *)loader;
|
||||
Elf_LE32_Phdr *const phdr = (Elf_LE32_Phdr *)(1+ehdr);
|
||||
|
||||
// stub/scripts/setfold.pl puts address of 'fold_begin' in 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);
|
||||
|
||||
// compress compiled C-code portion of loader
|
||||
upx_uint const uncLsize = lsize - fold_begin;
|
||||
upx_uint cprLsize;
|
||||
int r = upx_compress(loader + fold_begin, uncLsize, cprLoader, &cprLsize,
|
||||
NULL, ph.method, 10, NULL, NULL);
|
||||
if (r != UPX_E_OK || cprLsize >= uncLsize)
|
||||
throwInternalError("loaded compression failed");
|
||||
|
||||
memcpy(fold_begin+loader, cprLoader, cprLsize);
|
||||
lsize = fold_begin + cprLsize;
|
||||
phdr->p_filesz = lsize;
|
||||
// phdr->p_memsz is the decompressed size
|
||||
|
||||
// The beginning of our loader consists of a elf_hdr (52 bytes) and
|
||||
// one section elf_phdr (32 byte) now,
|
||||
// another section elf_phdr (32 byte) later, so we have 12 free bytes
|
||||
// from offset 116 to the program start at offset 128.
|
||||
// These 12 bytes are used for l_info by ::patchLoaderChecksum().
|
||||
assert(get_le32(loader + 28) == 52); // e_phoff
|
||||
assert(get_le32(loader + 32) == 0); // e_shoff
|
||||
assert(get_le16(loader + 40) == 52); // e_ehsize
|
||||
assert(get_le16(loader + 42) == 32); // e_phentsize
|
||||
assert(get_le16(loader + 44) == 1); // e_phnum
|
||||
assert(get_le16(loader + 48) == 0); // e_shnum
|
||||
assert(lsize > 128 && lsize < 4096);
|
||||
|
||||
patchLoaderChecksum();
|
||||
}
|
||||
|
||||
|
||||
void PackLinuxI386::patchLoaderChecksum()
|
||||
{
|
||||
l_info *const lp = (l_info *)(loader + getLoaderPrefixSize());
|
||||
unsigned char *const ptr = const_cast<unsigned char *>(getLoader());
|
||||
l_info *const lp = (l_info *)(ptr + getLoaderPrefixSize());
|
||||
// checksum for loader + p_info
|
||||
lp->l_checksum = 0;
|
||||
lp->l_magic = UPX_ELF_MAGIC;
|
||||
|
@ -258,7 +383,7 @@ void PackLinuxI386::patchLoaderChecksum()
|
|||
lp->l_format = (unsigned char) ph.format;
|
||||
// INFO: lp->l_checksum is currently unused
|
||||
unsigned adler = upx_adler32(0,NULL,0);
|
||||
adler = upx_adler32(adler, loader, lsize + sizeof(p_info));
|
||||
adler = upx_adler32(adler, ptr, lsize + sizeof(p_info));
|
||||
lp->l_checksum = adler;
|
||||
}
|
||||
|
||||
|
@ -266,13 +391,18 @@ void PackLinuxI386::patchLoaderChecksum()
|
|||
void PackLinuxI386::updateLoader(OutputFile *fo)
|
||||
{
|
||||
#define PAGE_MASK (~0<<12)
|
||||
Elf_LE32_Ehdr *const ehdr = (Elf_LE32_Ehdr *)(unsigned char *)loader;
|
||||
Elf_LE32_Ehdr *const ehdr = (Elf_LE32_Ehdr *)const_cast<upx_byte *>(getLoader());
|
||||
Elf_LE32_Phdr *const phdr = (Elf_LE32_Phdr *)(1+ehdr);
|
||||
|
||||
ehdr->e_phnum = 2;
|
||||
phdr->p_filesz = lsize;
|
||||
// phdr->p_memsz is the decompressed size
|
||||
assert(lsize > 128 && lsize < 4096);
|
||||
|
||||
// The first Phdr maps the stub (instructions, data, bss) rwx.
|
||||
// The second Phdr maps the overlay r--,
|
||||
// to defend against /usr/bin/strip removing the overlay.
|
||||
Elf_LE32_Phdr *const phdro = 1+(Elf_LE32_Phdr *)(1+ehdr);
|
||||
Elf_LE32_Phdr *const phdro = 1+phdr;
|
||||
|
||||
phdro->p_type = PT_LOAD;
|
||||
phdro->p_offset = lsize;
|
||||
|
@ -282,8 +412,6 @@ void PackLinuxI386::updateLoader(OutputFile *fo)
|
|||
phdro->p_align = (unsigned) (-PAGE_MASK);
|
||||
|
||||
patchLoaderChecksum();
|
||||
fo->seek(0, SEEK_SET);
|
||||
fo->rewrite(loader, 0x80);
|
||||
#undef PAGE_MASK
|
||||
}
|
||||
|
||||
|
|
|
@ -42,14 +42,28 @@ public:
|
|||
virtual int getFormat() const { return UPX_F_LINUX_i386; }
|
||||
virtual const char *getName() const { return "linux/386"; }
|
||||
virtual const int *getCompressionMethods(int method, int level) const;
|
||||
virtual const int *getFilters() const;
|
||||
virtual int buildLoader(const Filter *);
|
||||
|
||||
virtual bool canPack();
|
||||
|
||||
protected:
|
||||
// loader util
|
||||
virtual const upx_byte *getLoader() const;
|
||||
virtual int getLoaderSize() const;
|
||||
virtual int getLoaderPrefixSize() const;
|
||||
virtual int buildLinuxLoader(
|
||||
upx_byte const *const proto, // assembly-only sections
|
||||
unsigned const szproto,
|
||||
upx_byte const *const fold, // linked assembly + C section
|
||||
unsigned const szfold,
|
||||
Filter const *ft,
|
||||
unsigned const brka
|
||||
);
|
||||
|
||||
struct cprElfhdr {
|
||||
struct Elf_LE32_Ehdr ehdr;
|
||||
struct Elf_LE32_Phdr phdr[2];
|
||||
struct PackUnix::l_info linfo;
|
||||
};
|
||||
|
||||
// patch util
|
||||
virtual void patchLoader();
|
||||
|
@ -63,6 +77,8 @@ protected:
|
|||
enum {
|
||||
UPX_ELF_MAGIC = 0x5850557f // "\x7fUPX"
|
||||
};
|
||||
|
||||
unsigned n_mru;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "conf.h"
|
||||
|
||||
#include "file.h"
|
||||
#include "filter.h"
|
||||
#include "packer.h"
|
||||
#include "p_elf.h"
|
||||
#include "p_unix.h"
|
||||
|
@ -44,9 +45,9 @@
|
|||
**************************************************************************/
|
||||
|
||||
static const
|
||||
#include "stub/l_sh_n2b.h"
|
||||
#include "stub/l_lx_sh86.h"
|
||||
static const
|
||||
#include "stub/l_sh_n2d.h"
|
||||
#include "stub/fold_sh86.h"
|
||||
|
||||
|
||||
PackLinuxI386sh::PackLinuxI386sh(InputFile *f) :
|
||||
|
@ -58,76 +59,35 @@ PackLinuxI386sh::~PackLinuxI386sh()
|
|||
{
|
||||
}
|
||||
|
||||
const upx_byte *PackLinuxI386sh::getLoader() const
|
||||
int
|
||||
PackLinuxI386sh::buildLoader(Filter const *ft)
|
||||
{
|
||||
if (M_IS_NRV2B(ph.method))
|
||||
return linux_i386sh_nrv2b_loader;
|
||||
if (M_IS_NRV2D(ph.method))
|
||||
return linux_i386sh_nrv2d_loader;
|
||||
return NULL;
|
||||
}
|
||||
unsigned const sz_fold = sizeof(linux_i386sh_fold);
|
||||
MemBuffer buf(sz_fold);
|
||||
memcpy(buf, linux_i386sh_fold, sz_fold);
|
||||
|
||||
int PackLinuxI386sh::getLoaderSize() const
|
||||
{
|
||||
if (0 != lsize) {
|
||||
return lsize;
|
||||
}
|
||||
if (M_IS_NRV2B(ph.method))
|
||||
return sizeof(linux_i386sh_nrv2b_loader);
|
||||
if (M_IS_NRV2D(ph.method))
|
||||
return sizeof(linux_i386sh_nrv2d_loader);
|
||||
return 0;
|
||||
}
|
||||
checkPatch(0,0,0,0); // reset
|
||||
patch_le32(buf,sz_fold,"UPX3",l_shname);
|
||||
patch_le32(buf,sz_fold,"UPX2",o_shname);
|
||||
|
||||
// get fresh filter
|
||||
Filter fold_ft = *ft;
|
||||
fold_ft.init(ft->id, ft->addvalue);
|
||||
int preferred_ctos[2] = {ft->cto, -1};
|
||||
fold_ft.preferred_ctos = preferred_ctos;
|
||||
|
||||
// filter
|
||||
optimizeFilter(&fold_ft, buf, sz_fold);
|
||||
bool success = fold_ft.filter(buf + sizeof(cprElfhdr), sz_fold - sizeof(cprElfhdr));
|
||||
(void)success;
|
||||
|
||||
return buildLinuxLoader(
|
||||
linux_i386sh_loader, sizeof(linux_i386sh_loader),
|
||||
buf, sz_fold, ft, 0x08048000 );
|
||||
}
|
||||
|
||||
void PackLinuxI386sh::patchLoader()
|
||||
{
|
||||
lsize = getLoaderSize();
|
||||
Elf_LE32_Ehdr *const ehdr = (Elf_LE32_Ehdr *)(void *)loader;
|
||||
Elf_LE32_Phdr *const phdr = (Elf_LE32_Phdr *)(1+ehdr);
|
||||
|
||||
patch_le32(loader,lsize,"UPX3",l_shname);
|
||||
patch_le32(loader,lsize,"UPX2",o_shname);
|
||||
|
||||
// stub/scripts/setfold.pl puts address of 'fold_begin' in 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);
|
||||
|
||||
// compress compiled C-code portion of loader
|
||||
upx_uint const uncLsize = lsize - fold_begin;
|
||||
upx_uint cprLsize;
|
||||
int r = upx_compress(loader + fold_begin, uncLsize, cprLoader, &cprLsize,
|
||||
NULL, ph.method, 10, NULL, NULL);
|
||||
if (r != UPX_E_OK || cprLsize >= uncLsize)
|
||||
throwInternalError("loaded compression failed");
|
||||
|
||||
set_le32(0+fold_begin+loader, uncLsize);
|
||||
set_le32(4+fold_begin+loader, cprLsize);
|
||||
memcpy( 8+fold_begin+loader, cprLoader, cprLsize);
|
||||
lsize = 8 + fold_begin + cprLsize;
|
||||
patchVersion(loader,lsize);
|
||||
|
||||
// Info for OS kernel to set the brk()
|
||||
unsigned const brka = getbrk(phdr, ehdr->e_phnum);
|
||||
phdr[1].p_offset = 0xfff&brka;
|
||||
phdr[1].p_vaddr = brka;
|
||||
phdr[1].p_paddr = brka;
|
||||
phdr[1].p_filesz = 0;
|
||||
phdr[1].p_memsz = 0;
|
||||
|
||||
// The beginning of our loader consists of a elf_hdr (52 bytes) and
|
||||
// two sections elf_phdr (2 * 32 byte), so we have 12 free bytes
|
||||
// from offset 116 to the program start at offset 128.
|
||||
assert(ehdr->e_phoff == sizeof(Elf_LE32_Ehdr));
|
||||
assert(ehdr->e_ehsize == sizeof(Elf_LE32_Ehdr));
|
||||
assert(ehdr->e_phentsize == sizeof(Elf_LE32_Phdr));
|
||||
assert(ehdr->e_phnum == 2);
|
||||
assert(ehdr->e_shnum == 0);
|
||||
assert(lsize > 128 && lsize < 4096);
|
||||
|
||||
patchLoaderChecksum();
|
||||
}
|
||||
|
||||
|
||||
|
@ -181,7 +141,8 @@ void PackLinuxI386sh::pack(OutputFile *fo)
|
|||
PackUnix::pack(fo);
|
||||
|
||||
// update loader
|
||||
Elf_LE32_Phdr *const phdro = (Elf_LE32_Phdr *)(sizeof(Elf_LE32_Ehdr)+loader);
|
||||
Elf_LE32_Ehdr *const ehdr = (Elf_LE32_Ehdr *)const_cast<upx_byte *>(getLoader());
|
||||
Elf_LE32_Phdr *const phdro = (Elf_LE32_Phdr *)(1+ehdr);
|
||||
off_t const totlen = fo->getBytesWritten();
|
||||
phdro[0].p_filesz = totlen;
|
||||
phdro[0].p_memsz = PAGE_MASK & (~PAGE_MASK + totlen);
|
||||
|
@ -196,7 +157,7 @@ void PackLinuxI386sh::pack(OutputFile *fo)
|
|||
|
||||
patchLoaderChecksum();
|
||||
fo->seek(0, SEEK_SET);
|
||||
fo->rewrite(loader, 0x80);
|
||||
fo->rewrite(ehdr, sizeof(cprElfhdr));
|
||||
#undef PAGE_MASK
|
||||
}
|
||||
|
||||
|
|
|
@ -45,16 +45,16 @@ public:
|
|||
virtual int getFormat() const { return UPX_F_LINUX_SH_i386; }
|
||||
virtual const char *getName() const { return "linux/sh386"; }
|
||||
virtual const int *getFilters() const { return NULL; }
|
||||
virtual int buildLoader(const Filter *);
|
||||
|
||||
virtual void pack(OutputFile *fo);
|
||||
|
||||
virtual bool canPack();
|
||||
virtual void pack(OutputFile *fo);
|
||||
// virtual void unpack(OutputFile *fo) { super::unpack(fo); }
|
||||
virtual bool canUnpackVersion(int version) const
|
||||
{ return (version >= 11); }
|
||||
|
||||
protected:
|
||||
virtual const upx_byte *getLoader() const;
|
||||
virtual int getLoaderSize() const;
|
||||
virtual bool getShellName(char *buf);
|
||||
|
||||
virtual void patchLoader();
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "conf.h"
|
||||
|
||||
#include "file.h"
|
||||
#include "filter.h"
|
||||
#include "packer.h"
|
||||
#include "p_unix.h"
|
||||
#include "p_elf.h"
|
||||
|
@ -125,22 +126,16 @@ void PackUnix::pack(OutputFile *fo)
|
|||
// create a pseudo-unique program id for our paranoid stub
|
||||
progid = getRandomId();
|
||||
|
||||
// prepare loader
|
||||
lsize = getLoaderSize();
|
||||
loader.alloc(lsize + sizeof(p_info));
|
||||
memcpy(loader,getLoader(),lsize);
|
||||
|
||||
// patch loader, prepare header info
|
||||
patchLoader(); // can change lsize by packing C-code of upx_main etc.
|
||||
p_info *const hbuf = (p_info *)(loader + lsize);
|
||||
set_native32(&hbuf->p_progid, progid);
|
||||
set_native32(&hbuf->p_filesize, file_size);
|
||||
set_native32(&hbuf->p_blocksize, blocksize);
|
||||
fo->write(loader, lsize + sizeof(p_info));
|
||||
|
||||
// init compression buffers
|
||||
ibuf.alloc(blocksize);
|
||||
obuf.allocForCompression(blocksize);
|
||||
{
|
||||
p_info hbuf;
|
||||
set_native32(&hbuf.p_progid, progid);
|
||||
set_native32(&hbuf.p_filesize, file_size);
|
||||
set_native32(&hbuf.p_blocksize, blocksize);
|
||||
obuf.write(&hbuf, sizeof(hbuf));
|
||||
}
|
||||
|
||||
// compress blocks
|
||||
unsigned total_in = 0;
|
||||
|
@ -148,6 +143,10 @@ void PackUnix::pack(OutputFile *fo)
|
|||
ui_total_passes = (file_size + blocksize - 1) / blocksize;
|
||||
if (ui_total_passes == 1)
|
||||
ui_total_passes = 0;
|
||||
|
||||
Filter ft(ph.level);
|
||||
ft.addvalue = 0;
|
||||
|
||||
fi->seek(0, SEEK_SET);
|
||||
for (;;)
|
||||
{
|
||||
|
@ -159,9 +158,19 @@ void PackUnix::pack(OutputFile *fo)
|
|||
// file is e.g. blocksize + 1 bytes long
|
||||
|
||||
// compress
|
||||
ph.u_len = l;
|
||||
ph.c_len = ph.u_len = l;
|
||||
ph.overlap_overhead = 0;
|
||||
(void) compress(ibuf, obuf); // ignore return value
|
||||
ft.buf_len = l;
|
||||
|
||||
// leave room for block sizes
|
||||
unsigned char size[8];
|
||||
set_native32(size+0, ph.u_len);
|
||||
set_native32(size+4, ph.c_len); // will be rewritten
|
||||
obuf.write(size, 8);
|
||||
|
||||
// If user specified the filter, then use it (-2==strategy).
|
||||
// Else try the first two filters, and pick the better (2==strategy).
|
||||
compressWithFilters(&ft, OVERHEAD, ((opt->filter > 0) ? -2 : 2));
|
||||
|
||||
if (ph.c_len < ph.u_len)
|
||||
{
|
||||
|
@ -177,20 +186,18 @@ void PackUnix::pack(OutputFile *fo)
|
|||
ph.c_adler = upx_adler32(ph.c_adler, ibuf, ph.u_len);
|
||||
}
|
||||
|
||||
// write block sizes
|
||||
unsigned char size[8];
|
||||
set_native32(size+0, ph.u_len);
|
||||
set_native32(size+4, ph.c_len);
|
||||
fo->write(size, 8);
|
||||
// update compressed size
|
||||
set_native32(obuf - 4, ph.c_len);
|
||||
|
||||
// write compressed data
|
||||
if (ph.c_len < ph.u_len)
|
||||
{
|
||||
fo->write(obuf, ph.c_len);
|
||||
verifyOverlappingDecompression();
|
||||
obuf.write(obuf, ph.c_len);
|
||||
// FIXME: obuf is not discardable!
|
||||
// verifyOverlappingDecompression();
|
||||
}
|
||||
else
|
||||
fo->write(ibuf, ph.u_len);
|
||||
obuf.write(ibuf, ph.u_len);
|
||||
|
||||
total_in += ph.u_len;
|
||||
total_out += ph.c_len;
|
||||
|
@ -199,12 +206,21 @@ void PackUnix::pack(OutputFile *fo)
|
|||
throwEOFException();
|
||||
|
||||
// write block end marker (uncompressed size 0)
|
||||
fo->write("\x00\x00\x00\x00", 4);
|
||||
set_native32(obuf, 0);
|
||||
obuf.write(obuf, 4);
|
||||
|
||||
// update header with totals
|
||||
ph.u_len = total_in;
|
||||
ph.c_len = total_out;
|
||||
|
||||
upx_byte const *p = getLoader();
|
||||
lsize = getLoaderSize();
|
||||
patchFilter32(const_cast<upx_byte *>(p), lsize, &ft);
|
||||
fo->write(p, lsize);
|
||||
|
||||
unsigned pos = obuf.seek(0, SEEK_CUR);
|
||||
fo->write(obuf - pos, pos);
|
||||
|
||||
// write packheader
|
||||
writePackHeader(fo);
|
||||
|
||||
|
@ -213,6 +229,8 @@ void PackUnix::pack(OutputFile *fo)
|
|||
fo->write(obuf, 4);
|
||||
|
||||
updateLoader(fo);
|
||||
fo->seek(0, SEEK_SET);
|
||||
fo->rewrite(p, lsize);
|
||||
|
||||
// finally check the compression ratio
|
||||
if (!checkFinalCompressionRatio(fo))
|
||||
|
|
302
src/packer.cpp
302
src/packer.cpp
|
@ -1042,29 +1042,259 @@ const char *Packer::getDecompressor() const
|
|||
}
|
||||
|
||||
|
||||
#define NOFILT 0 // no filter
|
||||
#define FNOMRU 1 // filter, but not using mru
|
||||
#define MRUFLT 2 // mru filter
|
||||
|
||||
static unsigned
|
||||
f80_call(int fid)
|
||||
{
|
||||
return (1+ (0x0f & fid)) % 3;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
f80_jmp1(int fid)
|
||||
{
|
||||
return ((1+ (0x0f & fid)) / 3) % 3;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
f80_jcc2(int fid)
|
||||
{
|
||||
return f80_jmp1(fid);
|
||||
}
|
||||
|
||||
void Packer::addFilter32(int filter_id)
|
||||
{
|
||||
assert(filter_id > 0);
|
||||
assert(isValidFilter(filter_id));
|
||||
|
||||
if ((filter_id & 0xf) % 3 == 0)
|
||||
addLoader("CALLTR00",
|
||||
(filter_id > 0x20) ? "CTCLEVE1" : "",
|
||||
"CALLTR01",
|
||||
(filter_id & 0xf) > 3 ? (filter_id > 0x20 ? "CTBSHR01""CTBSWA01" : "CTBROR01""CTBSWA01") : "",
|
||||
"CALLTR02",
|
||||
NULL
|
||||
);
|
||||
else
|
||||
addLoader("CALLTR10",
|
||||
(filter_id & 0xf) % 3 == 1 ? "CALLTRE8" : "CALLTRE9",
|
||||
"CALLTR11",
|
||||
(filter_id > 0x20) ? "CTCLEVE2" : "",
|
||||
"CALLTR12",
|
||||
(filter_id & 0xf) > 3 ? (filter_id > 0x20 ? "CTBSHR11""CTBSWA11" : "CTBROR11""CTBSWA11") : "",
|
||||
"CALLTR13",
|
||||
NULL
|
||||
);
|
||||
if (filter_id < 0x80) {
|
||||
if ((filter_id & 0xf) % 3 == 0) {
|
||||
if (filter_id < 0x40) {
|
||||
addLoader("CALLTR00",
|
||||
(filter_id > 0x20) ? "CTCLEVE1" : "",
|
||||
"CALLTR01",
|
||||
(filter_id & 0xf) > 3 ? (filter_id > 0x20 ? "CTBSHR01""CTBSWA01" : "CTBROR01""CTBSWA01") : "",
|
||||
"CALLTR02",
|
||||
NULL
|
||||
);
|
||||
}
|
||||
else if (0x40==(0xF0 & filter_id)) {
|
||||
addLoader("CKLLTR00", 0);
|
||||
if (9<=(0xf & filter_id)) {
|
||||
addLoader("CKLLTR10", 0);
|
||||
}
|
||||
addLoader("CKLLTR20", 0);
|
||||
if (9<=(0xf & filter_id)) {
|
||||
addLoader("CKLLTR30", 0);
|
||||
}
|
||||
addLoader("CKLLTR40", 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
addLoader("CALLTR10",
|
||||
(filter_id & 0xf) % 3 == 1 ? "CALLTRE8" : "CALLTRE9",
|
||||
"CALLTR11",
|
||||
(filter_id > 0x20) ? "CTCLEVE2" : "",
|
||||
"CALLTR12",
|
||||
(filter_id & 0xf) > 3 ? (filter_id > 0x20 ? "CTBSHR11""CTBSWA11" : "CTBROR11""CTBSWA11") : "",
|
||||
"CALLTR13",
|
||||
NULL
|
||||
);
|
||||
}
|
||||
if (0x80==(filter_id & 0xF0)) {
|
||||
bool const x386 = (opt->cpu <= opt->CPU_386);
|
||||
unsigned const n_mru = ph.n_mru ? 1+ ph.n_mru : 0;
|
||||
bool const mrupwr2 = (0!=n_mru) && 0==((n_mru -1) & n_mru);
|
||||
unsigned const f_call = f80_call(filter_id);
|
||||
unsigned const f_jmp1 = f80_jmp1(filter_id);
|
||||
unsigned const f_jcc2 = f80_jcc2(filter_id);
|
||||
|
||||
if (NOFILT!=f_jcc2) {
|
||||
addLoader("LXJCC010", 0);
|
||||
if (n_mru) {
|
||||
addLoader("LXMRU045", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("LXMRU046", 0);
|
||||
}
|
||||
if (0==n_mru || MRUFLT!=f_jcc2) {
|
||||
addLoader("LXJCC020", 0);
|
||||
}
|
||||
else { // 0!=n_mru
|
||||
addLoader("LXJCC021", 0);
|
||||
}
|
||||
if (NOFILT!=f_jcc2) {
|
||||
addLoader("LXJCC023", 0);
|
||||
}
|
||||
}
|
||||
addLoader("LXUNF037", 0);
|
||||
if (x386) {
|
||||
if (n_mru) {
|
||||
addLoader("LXUNF386", 0);
|
||||
}
|
||||
addLoader("LXUNF387", 0);
|
||||
if (n_mru) {
|
||||
addLoader("LXUNF388", 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
addLoader("LXUNF486", 0);
|
||||
if (n_mru) {
|
||||
addLoader("LXUNF487", 0);
|
||||
}
|
||||
}
|
||||
if (n_mru) {
|
||||
addLoader("LXMRU065", 0);
|
||||
if (256==n_mru) {
|
||||
addLoader("MRUBYTE3", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("MRUARB30", 0);
|
||||
if (mrupwr2) {
|
||||
addLoader("MRUBITS3", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("MRUARB40", 0);
|
||||
}
|
||||
}
|
||||
addLoader("LXMRU070", 0);
|
||||
if (256==n_mru) {
|
||||
addLoader("MRUBYTE4", 0);
|
||||
}
|
||||
else if (mrupwr2) {
|
||||
addLoader("MRUBITS4", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("MRUARB50", 0);
|
||||
}
|
||||
addLoader("LXMRU080", 0);
|
||||
if (256==n_mru) {
|
||||
addLoader("MRUBYTE5", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("MRUARB60", 0);
|
||||
if (mrupwr2) {
|
||||
addLoader("MRUBITS5", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("MRUARB70", 0);
|
||||
}
|
||||
}
|
||||
addLoader("LXMRU090", 0);
|
||||
if (256==n_mru) {
|
||||
addLoader("MRUBYTE6", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("MRUARB80", 0);
|
||||
if (mrupwr2) {
|
||||
addLoader("MRUBITS6", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("MRUARB90", 0);
|
||||
}
|
||||
}
|
||||
addLoader("LXMRU100", 0);
|
||||
}
|
||||
addLoader("LXUNF040", 0);
|
||||
if (n_mru) {
|
||||
addLoader("LXMRU110", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("LXMRU111", 0);
|
||||
}
|
||||
addLoader("LXUNF041", 0);
|
||||
addLoader("LXUNF042", 0);
|
||||
if (n_mru) {
|
||||
addLoader("LXMRU010", 0);
|
||||
if (NOFILT!=f_jmp1 && NOFILT==f_call) {
|
||||
addLoader("LXJMPA00", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("LXCALLB0", 0);
|
||||
}
|
||||
addLoader("LXUNF021", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("LXMRU022", 0);
|
||||
if (NOFILT!=f_jmp1 && NOFILT==f_call) {
|
||||
addLoader("LXJMPA01", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("LXCALLB1", 0);
|
||||
}
|
||||
}
|
||||
if (n_mru) {
|
||||
if (256!=n_mru && mrupwr2) {
|
||||
addLoader("MRUBITS1", 0);
|
||||
}
|
||||
addLoader("LXMRU030", 0);
|
||||
if (256==n_mru) {
|
||||
addLoader("MRUBYTE1", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("MRUARB10", 0);
|
||||
}
|
||||
addLoader("LXMRU040", 0);
|
||||
}
|
||||
|
||||
addLoader("LXUNF030", 0);
|
||||
if (NOFILT!=f_jcc2) {
|
||||
addLoader("LXJCC000", 0);
|
||||
}
|
||||
if (NOFILT!=f_call || NOFILT!=f_jmp1) { // at least one is filtered
|
||||
// shift opcode origin to zero
|
||||
if (0==n_mru) {
|
||||
addLoader("LXCJ0MRU", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("LXCJ1MRU", 0);
|
||||
}
|
||||
|
||||
// determine if in range
|
||||
if ((NOFILT!=f_call) && (NOFILT!=f_jmp1)) { // unfilter both
|
||||
addLoader("LXCALJMP", 0);
|
||||
}
|
||||
if ((NOFILT==f_call) ^ (NOFILT==f_jmp1)) { // unfilter just one
|
||||
if (0==n_mru) {
|
||||
addLoader("LXCALL00", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("LXCALL01", 0);
|
||||
}
|
||||
}
|
||||
|
||||
// determine if mru applies
|
||||
if (0==n_mru || ! ((FNOMRU==f_call) || (FNOMRU==f_jmp1)) ) {
|
||||
addLoader("LXCJ2MRU", 0); // no mru, or no exceptions
|
||||
}
|
||||
else { // mru on one, but not the other
|
||||
addLoader("LXCJ4MRU", 0);
|
||||
if (MRUFLT==f_jmp1) { // JMP only
|
||||
addLoader("LXCJ6MRU", 0);
|
||||
} else
|
||||
if (MRUFLT==f_call) { // CALL only
|
||||
addLoader("LXCJ7MRU", 0);
|
||||
}
|
||||
addLoader("LXCJ8MRU", 0);
|
||||
}
|
||||
}
|
||||
addLoader("LXUNF034", 0);
|
||||
if (n_mru) {
|
||||
addLoader("LXMRU055", 0);
|
||||
if (256==n_mru) {
|
||||
addLoader("MRUBYTE2", 0);
|
||||
}
|
||||
else if (mrupwr2) {
|
||||
addLoader("MRUBITS2", 0);
|
||||
}
|
||||
else if (n_mru) {
|
||||
addLoader("MRUARB20", 0);
|
||||
}
|
||||
addLoader("LXMRU057", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1222,6 +1452,10 @@ void Packer::compressWithFilters(Filter *parm_ft,
|
|||
ft.init(ph.filter, orig_ft.addvalue);
|
||||
// filter
|
||||
optimizeFilter(&ft, ibuf + filter_off, filter_len);
|
||||
|
||||
unsigned char *const save = new unsigned char[filter_len];
|
||||
memcpy(save, ibuf + filter_off, filter_len);
|
||||
|
||||
bool success = ft.filter(ibuf + filter_off, filter_len);
|
||||
if (ft.id != 0 && ft.calls == 0)
|
||||
{
|
||||
|
@ -1251,6 +1485,7 @@ void Packer::compressWithFilters(Filter *parm_ft,
|
|||
}
|
||||
nfilters_success++;
|
||||
ph.filter_cto = ft.cto;
|
||||
ph.n_mru = ft.n_mru;
|
||||
// compress
|
||||
if (compress(ibuf + compress_buf_off, otemp, max_offset, max_match))
|
||||
{
|
||||
|
@ -1294,6 +1529,11 @@ void Packer::compressWithFilters(Filter *parm_ft,
|
|||
}
|
||||
// restore ibuf[] - unfilter with verify
|
||||
ft.unfilter(ibuf + filter_off, filter_len, true);
|
||||
for (unsigned k = 0; k < filter_len; ++k) {
|
||||
if ((ibuf + filter_off)[k] != save[k]) {
|
||||
printf("mismatch at %d\n", k);
|
||||
}
|
||||
}
|
||||
//
|
||||
if (strategy < 0)
|
||||
break;
|
||||
|
@ -1305,6 +1545,7 @@ void Packer::compressWithFilters(Filter *parm_ft,
|
|||
assert(best_ph.u_len == orig_ph.u_len);
|
||||
assert(best_ph.filter == best_ft.id);
|
||||
assert(best_ph.filter_cto == best_ft.cto);
|
||||
// FIXME assert(best_ph.n_mru == best_ft.n_mru);
|
||||
|
||||
// copy back results
|
||||
this->ph = best_ph;
|
||||
|
@ -1396,10 +1637,27 @@ bool Packer::patchFilter32(void *loader, int lsize, const Filter *ft)
|
|||
if (ft->id == 0)
|
||||
return false;
|
||||
assert(ft->calls > 0);
|
||||
if (ft->id > 0x20)
|
||||
patch_le16(loader, lsize, "??", '?' + (ft->cto << 8));
|
||||
patch_le32(loader, lsize, "TEXL", (ft->id & 0xf) % 3 == 0 ? ft->calls :
|
||||
ft->lastcall - ft->calls * 4);
|
||||
if (ft->id < 0x80) {
|
||||
if (0x40 <= ft->id && ft->id < 0x50 && UPX_F_LINUX_i386==ph.format) {
|
||||
// "push byte '?'"
|
||||
patch_le16(loader, lsize, "\x6a?", 0x6a + (ft->cto << 8));
|
||||
}
|
||||
if (0x20 <= ft->id && ft->id < 0x40) {
|
||||
// 077==modr/m of "cmp [edi], byte '?'" (compare immediate 8 bits)
|
||||
patch_le16(loader, lsize, "\077?", 077 + (ft->cto << 8));
|
||||
}
|
||||
if (ft->id < 0x40) {
|
||||
patch_le32(loader, lsize, "TEXL", (ft->id & 0xf) % 3 == 0 ? ft->calls :
|
||||
ft->lastcall - ft->calls * 4);
|
||||
}
|
||||
}
|
||||
if (0x80==(ft->id & 0xF0)) {
|
||||
int const mru = ph.n_mru ? 1+ ph.n_mru : 0;
|
||||
if (mru && mru!=256) {
|
||||
unsigned const is_pwr2 = (0==((mru -1) & mru));
|
||||
patch_le32(0x80 + (char *)loader, lsize - 0x80, "NMRU", mru - is_pwr2);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ public:
|
|||
int filter;
|
||||
int filter_cto;
|
||||
int header_checksum;
|
||||
int n_mru;
|
||||
|
||||
//
|
||||
unsigned saved_u_adler;
|
||||
|
@ -250,15 +251,15 @@ protected:
|
|||
int ph_version;
|
||||
|
||||
// compression buffers
|
||||
MemBuffer ibuf; // input
|
||||
MemBuffer obuf; // output
|
||||
MemBuffer ibuf; // input
|
||||
MemBufferIO obuf; // output
|
||||
|
||||
// UI handler
|
||||
UiPacker *uip;
|
||||
int ui_pass;
|
||||
int ui_total_passes;
|
||||
|
||||
private:
|
||||
protected:
|
||||
// linker
|
||||
Linker *linker;
|
||||
|
||||
|
|
|
@ -150,7 +150,8 @@ void PackHeader::putPackHeader(upx_bytep p)
|
|||
set_le32(p+24,u_file_size);
|
||||
p[28] = (unsigned char) filter;
|
||||
p[29] = (unsigned char) filter_cto;
|
||||
p[30] = 0;
|
||||
p[30] = (unsigned char) (n_mru ? 0 : n_mru -1);
|
||||
size = 32;
|
||||
}
|
||||
set_le32(p+8,u_adler);
|
||||
set_le32(p+12,c_adler);
|
||||
|
@ -166,7 +167,8 @@ void PackHeader::putPackHeader(upx_bytep p)
|
|||
set_be32(p+24,u_file_size);
|
||||
p[28] = (unsigned char) filter;
|
||||
p[29] = (unsigned char) filter_cto;
|
||||
p[30] = 0;
|
||||
p[30] = (unsigned char) (n_mru ? 0 : n_mru -1);
|
||||
size = 32;
|
||||
}
|
||||
|
||||
p[4] = (unsigned char) version;
|
||||
|
@ -246,6 +248,7 @@ bool PackHeader::fillPackHeader(const upx_bytep buf, int blen)
|
|||
u_file_size = get_le32(p+24);
|
||||
off_filter = 28;
|
||||
filter_cto = p[29];
|
||||
n_mru = p[30] ? 1+ p[30] : 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -257,6 +260,7 @@ bool PackHeader::fillPackHeader(const upx_bytep buf, int blen)
|
|||
u_file_size = get_be32(p+24);
|
||||
off_filter = 28;
|
||||
filter_cto = p[29];
|
||||
n_mru = p[30] ? 1+ p[30] : 0;
|
||||
}
|
||||
|
||||
if (version >= 10)
|
||||
|
|
|
@ -31,9 +31,10 @@ STUBS = \
|
|||
l_tmt.h \
|
||||
l_wcle.h \
|
||||
l_w32pe.h \
|
||||
l_lx_n2b.h l_lx_n2d.h \
|
||||
l_le_n2b.h l_le_n2d.h \
|
||||
l_sh_n2b.h l_sh_n2d.h \
|
||||
l_lx_exec86.h fold_exec86.h \
|
||||
l_lx_elf86.h fold_elf86.h \
|
||||
l_lx_sh86.h fold_sh86.h \
|
||||
l_ext2.h \
|
||||
l_vmlinz.h
|
||||
|
||||
# experimental:
|
||||
|
@ -80,7 +81,7 @@ STRIPELF = ./util/sstrip/sstrip
|
|||
|
||||
# Use gcc 2.95.2 for smallest code.
|
||||
CC_LINUX_CFLAGS = -Wall -W -Wcast-align -Wcast-qual -Wwrite-strings
|
||||
CC_LINUX_CFLAGS += -Werror
|
||||
###CC_LINUX_CFLAGS += -Werror
|
||||
CC_LINUX_CFLAGS += -funsigned-char
|
||||
###CC_LINUX_CFLAGS += -fwritable-strings -save-temps
|
||||
CC_LINUX = gcc272 -O2 -m386 -malign-functions=0 -malign-jumps=0 -malign-loops=0 $(CC_LINUX_CFLAGS)
|
||||
|
@ -170,6 +171,10 @@ l_tmt.h: l_tmt.asx
|
|||
$(NASM) -f bin -o $T.bin $<
|
||||
$(BIN2H) $T.bin nrv_loader $@
|
||||
|
||||
l_ext2.h: l_ext2.asx
|
||||
$(NASM) -f bin -o $T.bin $<
|
||||
$(BIN2H) $T.bin nrv_loader $@
|
||||
|
||||
l_vmlinz.h: l_vmlinz.asx
|
||||
$(NASM) -f bin -o $T.bin $<
|
||||
$(BIN2H) $T.bin nrv_loader $@
|
||||
|
@ -249,66 +254,56 @@ l_t_x2ds.h: l_tos2.s
|
|||
# // linux rules (exec, elf, sh, sep)
|
||||
# ************************************************************************/
|
||||
|
||||
l_lx_n2b.h: l_lx_exec.c l_xe_n2b.o l_lx_exec86.lds Makefile
|
||||
$(CC_LINUX) -DNRV2B -o $T.o -c $<
|
||||
ld -T $(srcdir)/l_lx_exec86.lds -Map $T.map -o $T.bin l_xe_n2b.o $T.o
|
||||
$(SETFOLD) $T.bin
|
||||
l_lx_elf86.h: l_lx_elf86.asx
|
||||
$(NASM) -f bin -o $T.bin $<
|
||||
$(BIN2H) $T.bin linux_i386elf_loader $@
|
||||
|
||||
l_lx_exec86.h: l_lx_exec86.asx
|
||||
$(NASM) -f bin -o $T.bin $<
|
||||
$(BIN2H) $T.bin linux_i386exec_loader $@
|
||||
|
||||
l_lx_sh86.h: l_lx_sh86.asx
|
||||
$(NASM) -f bin -o $T.bin $<
|
||||
$(BIN2H) $T.bin linux_i386sh_loader $@
|
||||
|
||||
l_lx_elf.o: l_lx_elf.c
|
||||
$(CC_LINUX) -c $<
|
||||
|
||||
fold_elf86.o: fold_elf86.asm
|
||||
$(NASM) -f elf -o $@ $<
|
||||
|
||||
fold_elf86.h: l_lx_elf.o fold_elf86.o l_lx_elf86.lds
|
||||
ld -T l_lx_elf86.lds -Map $T.map -o $T.bin $T.o l_lx_elf.o
|
||||
objcopy -S -R .comment -R .note $T.bin
|
||||
./util/sstrip/sstrip $T.bin
|
||||
$(BRANDELF) $T.bin
|
||||
$(BIN2H) $T.bin linux_i386exec_nrv2b_loader $@
|
||||
$(BIN2H) $T.bin linux_i386elf_fold $@
|
||||
|
||||
l_le_n2b.h: l_lx_elf.c l_6e_n2b.o l_lx_elf86.lds
|
||||
$(CC_LINUX) -DNRV2B -o $T.o -c $<
|
||||
ld -T $(srcdir)/l_lx_elf86.lds -Map $T.map -o $T.bin l_6e_n2b.o $T.o
|
||||
$(SETFOLD) $T.bin
|
||||
l_lx_exec.o: l_lx_exec.c
|
||||
$(CC_LINUX) -c $<
|
||||
|
||||
fold_exec86.o: fold_exec86.asm
|
||||
$(NASM) -f elf -o $@ $<
|
||||
|
||||
fold_exec86.h: l_lx_exec.o fold_exec86.o l_lx_exec86.lds
|
||||
ld -T l_lx_exec86.lds -Map $T.map -o $T.bin $T.o l_lx_exec.o
|
||||
objcopy -S -R .comment -R .note $T.bin
|
||||
./util/sstrip/sstrip $T.bin
|
||||
$(BRANDELF) $T.bin
|
||||
$(BIN2H) $T.bin linux_i386elf_nrv2b_loader $@
|
||||
$(BIN2H) $T.bin linux_i386exec_fold $@
|
||||
|
||||
l_sh_n2b.h: l_lx_sh.c l_6h_n2b.o l_lx_sh86.lds
|
||||
$(CC_LINUX) -DNRV2B -o $T.o -c $<
|
||||
ld -T $(srcdir)/l_lx_sh86.lds -Map $T.map -o $T.bin l_6h_n2b.o $T.o
|
||||
$(SETFOLD) $T.bin
|
||||
l_lx_sh.o: l_lx_sh.c
|
||||
$(CC_LINUX) -c $<
|
||||
|
||||
fold_sh86.o: fold_sh86.asm
|
||||
$(NASM) -f elf -o $@ $<
|
||||
|
||||
fold_sh86.h: l_lx_sh.o fold_sh86.o l_lx_sh86.lds
|
||||
ld -T l_lx_sh86.lds -Map $T.map -o $T.bin $T.o l_lx_sh.o
|
||||
objcopy -S -R .comment -R .note $T.bin
|
||||
./util/sstrip/sstrip $T.bin
|
||||
$(BRANDELF) $T.bin
|
||||
$(BIN2H) $T.bin linux_i386sh_nrv2b_loader $@
|
||||
|
||||
l_xe_n2b.o: l_lx_exec86.asm
|
||||
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2B -o $@ $<
|
||||
|
||||
l_6e_n2b.o: l_lx_elf86.asm
|
||||
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2B -o $@ $<
|
||||
|
||||
l_6h_n2b.o: l_lx_sh86.asm
|
||||
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2B -o $@ $<
|
||||
|
||||
|
||||
l_lx_n2d.h: l_lx_exec.c l_xe_n2d.o l_lx_exec86.lds
|
||||
$(CC_LINUX) -DNRV2D -o $T.o -c $<
|
||||
ld -T $(srcdir)/l_lx_exec86.lds -Map $T.map -o $T.bin l_xe_n2d.o $T.o
|
||||
$(SETFOLD) $T.bin
|
||||
$(BRANDELF) $T.bin
|
||||
$(BIN2H) $T.bin linux_i386exec_nrv2d_loader $@
|
||||
|
||||
l_le_n2d.h: l_lx_elf.c l_6e_n2d.o l_lx_elf86.lds
|
||||
$(CC_LINUX) -DNRV2D -o $T.o -c $<
|
||||
ld -T $(srcdir)/l_lx_elf86.lds -Map $T.map -o $T.bin l_6e_n2d.o $T.o
|
||||
$(SETFOLD) $T.bin
|
||||
$(BRANDELF) $T.bin
|
||||
$(BIN2H) $T.bin linux_i386elf_nrv2d_loader $@
|
||||
|
||||
l_sh_n2d.h: l_lx_sh.c l_6h_n2d.o l_lx_sh86.lds
|
||||
$(CC_LINUX) -DNRV2D -o $T.o -c $<
|
||||
ld -T $(srcdir)/l_lx_sh86.lds -Map $T.map -o $T.bin l_6h_n2d.o $T.o
|
||||
$(SETFOLD) $T.bin
|
||||
$(BRANDELF) $T.bin
|
||||
$(BIN2H) $T.bin linux_i386sh_nrv2d_loader $@
|
||||
|
||||
l_xe_n2d.o: l_lx_exec86.asm
|
||||
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2D -o $@ $<
|
||||
|
||||
l_6e_n2d.o: l_lx_elf86.asm
|
||||
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2D -o $@ $<
|
||||
|
||||
l_6h_n2d.o: l_lx_sh86.asm
|
||||
$(NASM) -i$(UCL_I386)/ -f elf -dNRV2D -o $@ $<
|
||||
$(BIN2H) $T.bin linux_i386sh_fold $@
|
||||
|
||||
l_lx_sep.o: l_lx_sep.c
|
||||
$(CC_LINUX) -c $<
|
||||
|
@ -344,25 +339,16 @@ l_t_n2bs.h: n2b_d.ash bits.ash $(DEPS1)
|
|||
l_t_n2d.h: n2d_d.ash bits.ash $(DEPS1)
|
||||
l_t_n2ds.h: n2d_d.ash bits.ash $(DEPS1)
|
||||
l_tmt.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
|
||||
l_ext2.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
|
||||
l_vmlinz.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
|
||||
l_vxd.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
|
||||
l_wcle.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
|
||||
l_w32pe.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
|
||||
|
||||
l_xe_n2b.o: n2b_d32.ash $(DEPS1)
|
||||
l_6e_n2b.o: n2b_d32.ash $(DEPS1)
|
||||
l_6h_n2b.o: n2b_d32.ash $(DEPS1)
|
||||
l_lx_elf86.asx: l_lx_elf86.asm macros.ash macros.asy
|
||||
l_lx_exec86.asx: l_lx_exec86.asm macros.ash macros.asy
|
||||
l_lx_sh86.asx: l_lx_sh86.asm macros.ash macros.asy
|
||||
|
||||
l_xe_n2d.o: n2d_d32.ash $(DEPS1)
|
||||
l_6e_n2d.o: n2d_d32.ash $(DEPS1)
|
||||
l_6h_n2d.o: n2d_d32.ash $(DEPS1)
|
||||
|
||||
l_lx_n2b.h: linux.hh
|
||||
l_lx_n2d.h: linux.hh
|
||||
l_le_n2b.h: linux.hh
|
||||
l_le_n2d.h: linux.hh
|
||||
l_sh_n2b.h: linux.hh
|
||||
l_sh_n2d.h: linux.hh
|
||||
upxb: linux.hh
|
||||
upxd: linux.hh
|
||||
|
||||
|
|
127
src/stub/fold_elf86.asm
Normal file
127
src/stub/fold_elf86.asm
Normal file
|
@ -0,0 +1,127 @@
|
|||
; fold_elf86.asm -- linkage to C code to process Elf binary
|
||||
;
|
||||
; This file is part of the UPX executable compressor.
|
||||
;
|
||||
; Copyright (C) 2000-2001 John F. Reiser
|
||||
; 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 John F. Reiser
|
||||
; markus@oberhumer.com ml1050@cdata.tvnet.hu jreiser@BitWagon.com
|
||||
;
|
||||
|
||||
%define szElf32_Ehdr 0x34
|
||||
%define szElf32_Phdr 8*4
|
||||
%define p_memsz 5*4
|
||||
%define a_val 4
|
||||
|
||||
%define __NR_munmap 91
|
||||
|
||||
;; control just falls through, after this part and compiled C code
|
||||
;; are uncompressed.
|
||||
|
||||
fold_begin:
|
||||
; patchLoader will modify to be
|
||||
; dword sz_uncompressed, sz_compressed
|
||||
; byte compressed_data...
|
||||
|
||||
pop eax ; discard &sz_uncompressed
|
||||
pop eax ; discard sz_uncompressed
|
||||
|
||||
; 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 OVERHEAD 2048
|
||||
%define MAX_ELF_HDR 512
|
||||
|
||||
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
|
||||
|
||||
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 edx, [p_memsz + szElf32_Ehdr + edx]
|
||||
push edx ; argument: uncbuf
|
||||
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
|
||||
push eax ; save entry address
|
||||
|
||||
mov edi, [a_val + edi] ; AT_PHDR
|
||||
find_hatch:
|
||||
push edi
|
||||
EXTERN make_hatch
|
||||
call make_hatch ; find hatch = make_hatch(phdr)
|
||||
pop ecx ; junk the parameter
|
||||
add edi, byte szElf32_Phdr ; prepare to try next Elf32_Phdr
|
||||
test eax,eax
|
||||
jz find_hatch
|
||||
xchg eax,edx ; edx= &hatch
|
||||
|
||||
; _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.
|
||||
; Ulrich Drepper (drepper@cyngus.com) has refused to fix the bugs.
|
||||
; See GNU wwwgnats libc/1165 .
|
||||
|
||||
%define N_STKCLR (0x100 + MAX_ELF_HDR + OVERHEAD)/4
|
||||
lea edi, [esp - 4*N_STKCLR]
|
||||
pusha ; values will be zeroed
|
||||
mov ecx, N_STKCLR
|
||||
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
|
||||
push byte __NR_munmap
|
||||
pop eax
|
||||
jmp edx ; unmap ourselves via escape hatch, then goto entry
|
||||
|
||||
do_auxv: ; entry: %esi=src = &argc; %edi=dst. exit: %edi= &AT_NULL
|
||||
; cld
|
||||
|
||||
L10: ; move argc+argv
|
||||
lodsd
|
||||
stosd
|
||||
test eax,eax
|
||||
jne L10
|
||||
|
||||
L20: ; move envp
|
||||
lodsd
|
||||
stosd
|
||||
test eax,eax
|
||||
jne L20
|
||||
|
||||
L30: ; move existing Elf32_auxv
|
||||
lodsd
|
||||
stosd
|
||||
test eax,eax ; AT_NULL ?
|
||||
lodsd
|
||||
stosd
|
||||
jne L30
|
||||
|
||||
sub edi, byte 8 ; point to AT_NULL
|
||||
ret
|
||||
|
||||
; vi:ts=8:et:nowrap
|
||||
|
46
src/stub/fold_exec86.asm
Normal file
46
src/stub/fold_exec86.asm
Normal file
|
@ -0,0 +1,46 @@
|
|||
; fold_exec86.asm -- linkage to C code to process Elf binary
|
||||
;
|
||||
; This file is part of the UPX executable compressor.
|
||||
;
|
||||
; Copyright (C) 2000-2001 John F. Reiser
|
||||
; 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 John F. Reiser
|
||||
; markus@oberhumer.com ml1050@cdata.tvnet.hu jreiser@BitWagon.com
|
||||
;
|
||||
|
||||
;; control just falls through, after this part and compiled C code
|
||||
;; are uncompressed.
|
||||
|
||||
fold_begin: ;; this label is known to the Makefile
|
||||
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
|
||||
EXTERN upx_main
|
||||
call upx_main ; Call the UPX main function
|
||||
hlt ; Crash if somehow upx_main does return
|
||||
|
||||
; vi:ts=8:et:nowrap
|
134
src/stub/fold_sh86.asm
Normal file
134
src/stub/fold_sh86.asm
Normal file
|
@ -0,0 +1,134 @@
|
|||
; fold_sh86.asm -- Linux program entry point & decompressor (shell script)
|
||||
;
|
||||
; This file is part of the UPX executable compressor.
|
||||
;
|
||||
; Copyright (C) 1996-2001 Markus Franz Xaver Johannes Oberhumer
|
||||
; Copyright (C) 1996-2001 Laszlo Molnar
|
||||
; Copyright (C) 2000-2001 John F. Reiser
|
||||
; 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 John F. Reiser
|
||||
; markus@oberhumer.com ml1050@cdata.tvnet.hu jreiser@BitWagon.com
|
||||
;
|
||||
|
||||
|
||||
BITS 32
|
||||
SECTION .text
|
||||
|
||||
fold_begin:
|
||||
; patchLoader will modify to be
|
||||
; dword sz_uncompressed, sz_compressed
|
||||
; byte compressed_data...
|
||||
|
||||
pop eax ; discard &sz_uncompressed
|
||||
pop eax ; discard sz_uncompressed
|
||||
|
||||
; 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 OVERHEAD 2048
|
||||
%define MAX_ELF_HDR 512
|
||||
%define PAGE_SIZE ( 1<<12)
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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"
|
||||
|
||||
inc ecx
|
||||
push edx ; argv[0] is duplicate of $0
|
||||
|
||||
push ecx ; new argc
|
||||
push eax ; 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.
|
||||
; Ulrich Drepper (drepper@cyngus.com) has refused to fix the bugs.
|
||||
; See GNU wwwgnats libc/1165 .
|
||||
|
||||
%define N_STKCLR (0x100 + MAX_ELF_HDR + OVERHEAD)/4
|
||||
lea edi, [esp - 4*N_STKCLR]
|
||||
pusha ; values will be zeroed
|
||||
mov ecx, N_STKCLR
|
||||
xor eax,eax
|
||||
rep stosd
|
||||
|
||||
; Because the decompressed shell script occupies low memory anyway,
|
||||
; there isn't much payback to unmapping the compressed script and
|
||||
; ourselves the stub. We would need a place to put the escape hatch
|
||||
; "int $0x80; popa; ret", and some kernels do not allow execution
|
||||
; on the stack. So, we would have to dirty a page of the shell
|
||||
; or of /lib/ld-linux.so. It's simpler just to omit the unapping.
|
||||
popa
|
||||
ret
|
||||
|
||||
do_auxv: ; entry: %esi=src = &argc; %edi=dst. exit: %edi= &AT_NULL
|
||||
; cld
|
||||
|
||||
L10: ; move argc+argv
|
||||
lodsd
|
||||
stosd
|
||||
test eax,eax
|
||||
jne L10
|
||||
|
||||
L20: ; move envp
|
||||
lodsd
|
||||
stosd
|
||||
test eax,eax
|
||||
jne L20
|
||||
|
||||
L30: ; move existing Elf32_auxv
|
||||
lodsd
|
||||
stosd
|
||||
test eax,eax ; AT_NULL ?
|
||||
lodsd
|
||||
stosd
|
||||
jne L30
|
||||
|
||||
sub edi, byte 8 ; point to AT_NULL
|
||||
ret
|
||||
|
||||
|
||||
; vi:ts=8:et:nowrap
|
||||
|
|
@ -102,7 +102,11 @@ 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 void f_unfilter(
|
||||
nrv_byte *, // also addvalue
|
||||
nrv_uint,
|
||||
unsigned cto8 // junk in high 24 bits
|
||||
);
|
||||
typedef int f_expand(
|
||||
const nrv_byte *, nrv_uint,
|
||||
nrv_byte *, nrv_uint * );
|
||||
|
@ -116,6 +120,7 @@ unpackExtent(
|
|||
)
|
||||
{
|
||||
while (xo->size) {
|
||||
unsigned cto8;
|
||||
struct {
|
||||
int32_t sz_unc; // uncompressed
|
||||
int32_t sz_cpr; // compressed
|
||||
|
@ -125,6 +130,8 @@ unpackExtent(
|
|||
|
||||
// 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);
|
||||
|
@ -155,7 +162,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);
|
||||
(*f_unf)(xo->buf, out_len, cto8);
|
||||
}
|
||||
xi->buf += h.sz_cpr;
|
||||
xi->size -= h.sz_cpr;
|
||||
|
@ -330,14 +337,19 @@ void *upx_main(
|
|||
Elf32_Ehdr *const ehdr // temp char[MAX_ELF_HDR+OVERHEAD]
|
||||
)
|
||||
{
|
||||
size_t const lsize = *(unsigned short const *)(0x7c + (char const *)my_ehdr);
|
||||
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) };
|
||||
|
||||
size_t const sz_elfhdrs = ((size_t *)xi.buf)[0]; // sizeof(Ehdr+Phdrs), uncompressed
|
||||
size_t const sz_pckhdrs = ((size_t *)xi.buf)[1]; // sizeof(Ehdr+Phdrs), compressed
|
||||
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
|
||||
|
||||
(void)uncbuf; // used by l_lx_sh.c
|
||||
// Uncompress Ehdr and Phdrs.
|
||||
|
|
|
@ -33,42 +33,13 @@
|
|||
%define jmps jmp short
|
||||
%define jmpn jmp near
|
||||
|
||||
; defines for ident.ash and n2b_d32.ash
|
||||
%ifdef SMALL
|
||||
%define __IDENTSMA__
|
||||
%define __N2BSMA10__
|
||||
%define __N2BSMA20__
|
||||
%define __N2BSMA30__
|
||||
%define __N2BSMA40__
|
||||
%define __N2BSMA50__
|
||||
%define __N2BSMA60__
|
||||
%define __N2DSMA10__
|
||||
%define __N2DSMA20__
|
||||
%define __N2DSMA30__
|
||||
%define __N2DSMA40__
|
||||
%define __N2DSMA50__
|
||||
%define __N2DSMA60__
|
||||
%endif
|
||||
|
||||
|
||||
|
||||
%include "ident.ash"
|
||||
|
||||
;;;; names of pseudo-sections for addLoader:
|
||||
;; LXUNFnnn Linux unfilter
|
||||
;; LXNJMPnn omit filtering of 6-byte Jxx (0x0f 0x80..0x8f)
|
||||
;; LXMRUnnn MostRecentlyUsed recoding of destinations
|
||||
;; MRUARBnn arbitrary number of entries in wheel
|
||||
;; MRUBITSn power of 2 entries in wheel (smaller code)
|
||||
;; MRUBYTEn 256 entries in wheel (smallest code)
|
||||
|
||||
; /*************************************************************************
|
||||
; // program entry point
|
||||
; // see glibc/sysdeps/i386/elf/start.S
|
||||
; **************************************************************************/
|
||||
|
||||
GLOBAL _start
|
||||
|
||||
;__LEXEC000__
|
||||
_start:
|
||||
;;;; int3
|
||||
;; How to debug this code: Uncomment the 'int3' breakpoint instruction above.
|
||||
|
@ -89,27 +60,6 @@ _start:
|
|||
;;
|
||||
call main ; push address of decompress subroutine
|
||||
decompress:
|
||||
;__LXUNF000__
|
||||
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 ; save C-convention ebx, ebp, esi, edi; also eax, edx
|
||||
xchg eax, edi ; edi= pointer
|
||||
|
||||
push dword ('?'<<8) | 0x0f ; cto8_0f (cto8 byte is modified)
|
||||
%ifdef __MRUBYTE0__
|
||||
xor ebx, ebx ; zero
|
||||
%else ;__MRUARB00__ (also __MRUBITS0__)
|
||||
mov ebx, 'NMRU' ; modified N_MRU or N_MRU -1
|
||||
%endif ;__LXMRU010__
|
||||
|
||||
xor edx, edx ; zero
|
||||
;__LXUNF010__
|
||||
jmpn unf0
|
||||
;__LXELF010__
|
||||
|
||||
; /*************************************************************************
|
||||
; // C callable decompressor
|
||||
|
@ -120,7 +70,9 @@ decompress:
|
|||
%define OUTP dword [esp+8*4+12]
|
||||
%define OUTS dword [esp+8*4+16]
|
||||
|
||||
decompr0:
|
||||
;__LEXEC009__
|
||||
;; empty section for commonality with l_lx_exec86.asm
|
||||
;__LEXEC010__
|
||||
pusha
|
||||
; cld
|
||||
|
||||
|
@ -129,15 +81,13 @@ decompr0:
|
|||
|
||||
or ebp, byte -1
|
||||
;;; align 8
|
||||
%ifdef NRV2B
|
||||
%include "n2b_d32.ash"
|
||||
%elifdef NRV2D
|
||||
%include "n2d_d32.ash"
|
||||
%else
|
||||
%error
|
||||
%endif
|
||||
|
||||
%include "n2b_d32.ash"
|
||||
%include "n2d_d32.ash"
|
||||
%include "macros.ash"
|
||||
cjt32 0
|
||||
|
||||
;__LEXEC015__
|
||||
; eax is 0 from decompressor code
|
||||
;xor eax, eax ; return code
|
||||
|
||||
|
@ -158,191 +108,17 @@ decompr0:
|
|||
popa
|
||||
ret
|
||||
|
||||
;__LXUNF020__
|
||||
;; continuation of entry prolog for unfilter
|
||||
unf0:
|
||||
;__LXMRU020__
|
||||
push edx ; tail
|
||||
push ebx ; n_mru or n_mru1
|
||||
;__LXUNF025__
|
||||
mov esi, esp
|
||||
ctojr32
|
||||
ckt32 dl
|
||||
;__LEXEC017__
|
||||
popa
|
||||
ret
|
||||
|
||||
%define n_mru [esi]
|
||||
%define n_mru1 [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]
|
||||
|
||||
%ifdef __MRUBITS1__
|
||||
inc ebx ; n_mru1 ==> n_mru
|
||||
%endif ;__LXMRU030__
|
||||
unf1: ; allocate and clear mru[]
|
||||
push edx ; zero
|
||||
%ifdef __MRUBYTE1__
|
||||
dec bl
|
||||
%else ;__MRUARB10__
|
||||
dec ebx
|
||||
%endif ;__LXMRU040__
|
||||
jnz unf1 ; leaves 0=='hand'
|
||||
|
||||
%define tmp ebp
|
||||
|
||||
%define jc eax
|
||||
%define hand ebx
|
||||
%define hand_l al
|
||||
%define kh edx
|
||||
%define kh_l dl
|
||||
|
||||
;__LXUNF030__
|
||||
calltrickloop:
|
||||
mov al, [edi]
|
||||
inc edi
|
||||
%ifndef __LXNJMP00__
|
||||
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 lxunf
|
||||
ct2:
|
||||
sub al, 0xE8 - 0x80 ; base of JMP/CALL <d32>
|
||||
cmp al, 0xE9 - 0xE8 ; span of JMP/CALL <d32>
|
||||
%else ;__LXNJMP10__
|
||||
sub al, 0xE8 ; base of JMP/CALL <d32>
|
||||
cmp al, 0xE9 - 0xE8 ; span of JMP/CALL <d32>
|
||||
%endif ;__LXMRU050__
|
||||
ja unfcount
|
||||
mov al, [edi]
|
||||
cmp al, cto8
|
||||
je lxunf
|
||||
unfcount:
|
||||
dec ecx
|
||||
jg calltrickloop
|
||||
|
||||
mov edi,esp ; clear mru[] portion of stack
|
||||
%ifdef __MRUBYTE2__
|
||||
mov ecx, 3+ 256 ; unused, tail, ct8_0f
|
||||
%elifdef __MRUBITS2__
|
||||
mov ecx, n_mru1
|
||||
add ecx, byte 1+ 3 ; n_mru1, tail, ct8_0f
|
||||
%else ;__MRUARB20__
|
||||
mov ecx, n_mru
|
||||
add ecx, byte 3 ; n_mru, tail, ct8_0f
|
||||
%endif ;__LXMRU060__
|
||||
xor eax,eax
|
||||
rep
|
||||
stosd
|
||||
mov esp,edi
|
||||
popa
|
||||
push ecx
|
||||
push eax
|
||||
push edx
|
||||
ret
|
||||
|
||||
lxunf:
|
||||
mov eax, [edi]
|
||||
shr ax, 8
|
||||
rol eax, 16
|
||||
xchg al, ah
|
||||
;__LXMRU065__
|
||||
shr jc, 1 ; eax= jc, or mru index
|
||||
jnc mru4 ; not 1st time for this jc
|
||||
%ifdef __MRUBYTE3__
|
||||
dec hand_l
|
||||
%else ;__MRUARB30__
|
||||
dec hand
|
||||
%ifdef __MRUBITS3__
|
||||
and hand, n_mru1
|
||||
%else ;__MRUARB40__
|
||||
jge mru3
|
||||
add hand, n_mru
|
||||
mru3:
|
||||
%endif
|
||||
%endif ;__LXMRU070__
|
||||
|
||||
mov [esp + 4*hand], jc ; 1st time: mru[hand] = jc
|
||||
jmps unf_store
|
||||
|
||||
mru4: ; not 1st time for this jc
|
||||
lea kh, [jc + hand] ; kh = jc + hand
|
||||
%ifdef __MRUBYTE4__
|
||||
movzbl kh, kh_l
|
||||
%elifdef __MRUBITS4__
|
||||
and kh, n_mru1
|
||||
%else ;__MRUARB50__
|
||||
cmp kh, n_mru
|
||||
jb mru5
|
||||
sub kh, n_mru
|
||||
mru5:
|
||||
%endif ;__LXMRU080__
|
||||
mov jc, [esp + 4*kh] ; jc = mru[kh]
|
||||
%ifdef __MRUBYTE5__
|
||||
dec hand_l
|
||||
%else ;__MRUARB60__
|
||||
dec hand
|
||||
%ifdef __MRUBITS5__
|
||||
and hand, n_mru1
|
||||
%else ;__MRUARB70__
|
||||
jge mru6
|
||||
add hand, n_mru
|
||||
mru6:
|
||||
%endif
|
||||
%endif ;__LXMRU090__
|
||||
|
||||
mov tmp, [esp + 4*hand] ; tmp = mru[hand]
|
||||
test tmp,tmp
|
||||
jnz mru8
|
||||
|
||||
push jc ; ran out of registers
|
||||
mov eax, tail
|
||||
|
||||
%ifdef __MRUBYTE6__
|
||||
dec al
|
||||
%else ;__MRUARB80__
|
||||
dec eax
|
||||
%ifdef __MRUBITS6__
|
||||
and eax, n_mru1
|
||||
%else ;__MRUARB90__
|
||||
jge mru7
|
||||
add eax, n_mru
|
||||
mru7:
|
||||
%endif
|
||||
%endif ;__LXMRU100__
|
||||
|
||||
xor tmp,tmp
|
||||
mov tail, eax
|
||||
xchg [4+ esp + 4*eax], tmp ; tmp = mru[tail]; mru[tail] = 0
|
||||
pop jc
|
||||
mru8:
|
||||
mov [esp + 4*kh ], tmp ; mru[kh] = tmp
|
||||
mov [esp + 4*hand], jc ; mru[hand] = jc
|
||||
;__LXUNF040__
|
||||
unf_store:
|
||||
sub eax, edi
|
||||
sub ecx, byte 4
|
||||
add eax, addvalue
|
||||
mov [edi], eax
|
||||
add edi, byte 4
|
||||
jmps unfcount
|
||||
|
||||
;__LXELF020__
|
||||
;__LEXEC020__
|
||||
|
||||
%define PAGE_MASK (~0<<12)
|
||||
%define PAGE_SIZE ( 1<<12)
|
||||
|
||||
%define szElf32_Ehdr 0x34
|
||||
%define szElf32_Phdr 8*4
|
||||
%define p_filesz 4*4
|
||||
%define p_memsz 5*4
|
||||
%define a_val 4
|
||||
|
||||
%define MAP_FIXED 0x10
|
||||
%define MAP_PRIVATE 0x02
|
||||
%define MAP_ANONYMOUS 0x20
|
||||
|
@ -366,7 +142,7 @@ unfold:
|
|||
push eax ; &destination
|
||||
|
||||
; mmap a page to hold the decompressed program
|
||||
xor ecx,ecx
|
||||
xor ecx, ecx
|
||||
push ecx
|
||||
push ecx
|
||||
mov ch, PAGE_SIZE >> 8
|
||||
|
@ -390,94 +166,12 @@ unfold:
|
|||
main:
|
||||
pop ebp ; &decompress
|
||||
call unfold
|
||||
fold_begin:
|
||||
; patchLoader will modify to be
|
||||
; dword sz_uncompressed, sz_compressed
|
||||
; byte compressed_data...
|
||||
|
||||
pop eax ; discard &sz_uncompressed
|
||||
pop eax ; discard sz_uncompressed
|
||||
|
||||
; 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 OVERHEAD 2048
|
||||
%define MAX_ELF_HDR 512
|
||||
|
||||
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
|
||||
|
||||
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 edx, [p_memsz + szElf32_Ehdr + edx]
|
||||
push edx ; argument: uncbuf
|
||||
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
|
||||
push eax ; save entry address
|
||||
|
||||
mov edi, [a_val + edi] ; AT_PHDR
|
||||
find_hatch:
|
||||
push edi
|
||||
EXTERN make_hatch
|
||||
call make_hatch ; find hatch = make_hatch(phdr)
|
||||
pop ecx ; junk the parameter
|
||||
add edi, byte szElf32_Phdr ; prepare to try next Elf32_Phdr
|
||||
test eax,eax
|
||||
jz find_hatch
|
||||
xchg eax,edx ; edx= &hatch
|
||||
|
||||
; _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.
|
||||
; Ulrich Drepper (drepper@cyngus.com) has refused to fix the bugs.
|
||||
; See GNU wwwgnats libc/1165 .
|
||||
|
||||
%define N_STKCLR (0x100 + MAX_ELF_HDR + OVERHEAD)/4
|
||||
lea edi, [esp - 4*N_STKCLR]
|
||||
pusha ; values will be zeroed
|
||||
mov ecx, N_STKCLR
|
||||
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
|
||||
push byte __NR_munmap
|
||||
pop eax
|
||||
jmp edx ; unmap ourselves via escape hatch, then goto entry
|
||||
|
||||
do_auxv: ; entry: %esi=src = &argc; %edi=dst. exit: %edi= &AT_NULL
|
||||
; cld
|
||||
|
||||
L10: ; move argc+argv
|
||||
lodsd
|
||||
stosd
|
||||
test eax,eax
|
||||
jne L10
|
||||
|
||||
L20: ; move envp
|
||||
lodsd
|
||||
stosd
|
||||
test eax,eax
|
||||
jne L20
|
||||
|
||||
L30: ; move existing Elf32_auxv
|
||||
lodsd
|
||||
stosd
|
||||
test eax,eax ; AT_NULL ?
|
||||
lodsd
|
||||
stosd
|
||||
jne L30
|
||||
|
||||
sub edi, byte 8 ; point to AT_NULL
|
||||
ret
|
||||
eof:
|
||||
; __XTHEENDX__
|
||||
section .data
|
||||
dd -1
|
||||
dw eof
|
||||
|
||||
; vi:ts=8:et:nowrap
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
ENTRY(_start)
|
||||
/*ENTRY(_start)*/
|
||||
SECTIONS
|
||||
{
|
||||
/* 0x00401000: l_lx_elf86.asm assumes 1 page up from 64KB boundary */
|
||||
|
|
|
@ -101,12 +101,19 @@ static 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;
|
||||
*--p = (d += 'A');
|
||||
v /= 32;
|
||||
} while (--n > 0);
|
||||
return v;
|
||||
}
|
||||
|
||||
static char *
|
||||
do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
|
||||
{
|
||||
(void)len; (void)prot; (void)flags; (void)fd; (void)offset;
|
||||
return mmap((int *)&addr);
|
||||
}
|
||||
|
||||
|
||||
#if defined(__i386__)
|
||||
# define SET2(p, c0, c1) \
|
||||
|
@ -125,6 +132,51 @@ static uint32_t ascii5(char *p, uint32_t v, unsigned n)
|
|||
#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
|
||||
go_self(char const *tmpname, char *argv[], char *envp[])
|
||||
{
|
||||
// FIXME: why not use "/proc/self/fd/XX"? *BSD doesn't have it?
|
||||
|
||||
// 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(procself_buf + 6, getpid());
|
||||
SET4(procself, '/', 'f', 'd', '/');
|
||||
upx_itoa(procself + 4, fdi);
|
||||
}
|
||||
|
||||
// Check for working /proc/self/fd/X by accessing the
|
||||
// temp file again, now via temp fdi.
|
||||
if (UPX2 == 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, argv, envp);
|
||||
// NOTE: if we get here we've lost.
|
||||
}
|
||||
|
||||
// The proc filesystem isn't working. No problem.
|
||||
close(fdi);
|
||||
}
|
||||
return fdi;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
// UPX & NRV stuff
|
||||
**************************************************************************/
|
||||
|
@ -153,59 +205,29 @@ void upx_main(
|
|||
f_expand *const f_decompress
|
||||
)
|
||||
{
|
||||
// file descriptors
|
||||
int fdi, fdo;
|
||||
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 };
|
||||
char *next_unmap = (char *)(PAGE_MASK & (unsigned)xi.buf);
|
||||
struct p_info header;
|
||||
|
||||
// for getpid()
|
||||
pid_t pid;
|
||||
|
||||
// temporary file name (max 14 chars)
|
||||
static char tmpname_buf[] = "/tmp/upxAAAAAAAAAAA";
|
||||
char *tmpname = tmpname_buf;
|
||||
// 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;
|
||||
// file descriptor
|
||||
int fdo;
|
||||
|
||||
// decompression buffer
|
||||
unsigned char *buf;
|
||||
static struct MallocArgs {
|
||||
char *ma_addr;
|
||||
size_t ma_length;
|
||||
int ma_prot;
|
||||
int ma_flags;
|
||||
int ma_fd;
|
||||
off_t ma_offset;
|
||||
} malloc_args = {
|
||||
#if defined(USE_MMAP_FO)
|
||||
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 = {
|
||||
0, -PAGE_MASK, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0
|
||||
};
|
||||
#endif
|
||||
|
||||
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 };
|
||||
|
||||
char *next_unmap = (char *)(PAGE_MASK & (unsigned)xi.buf);
|
||||
struct p_info header;
|
||||
|
||||
// temporary file name
|
||||
char tmpname_buf[20];
|
||||
|
||||
//
|
||||
// ----- Step 0: set /proc/self using /proc/<pid> -----
|
||||
//
|
||||
|
||||
//personality(PER_LINUX);
|
||||
pid = getpid();
|
||||
SET4(procself_buf + 0, '/', 'p', 'r', 'o');
|
||||
SET2(procself_buf + 4, 'c', '/');
|
||||
procself = upx_itoa(procself_buf + 6, pid);
|
||||
*procself++ = '/';
|
||||
|
||||
|
||||
//
|
||||
|
@ -226,7 +248,7 @@ void upx_main(
|
|||
// 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 != UPX2)
|
||||
if (header.p_progid != UPX3)
|
||||
goto error1;
|
||||
|
||||
|
||||
|
@ -234,13 +256,17 @@ void upx_main(
|
|||
// ----- 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)pid, 4); p-=4;
|
||||
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;
|
||||
|
@ -254,7 +280,7 @@ void upx_main(
|
|||
r ^= ((uint32_t) tv.tv_usec) << 12; // shift into high-bits
|
||||
#else
|
||||
// using adjtimex() may cause portability problems
|
||||
static struct timex tx;
|
||||
struct timex tx;
|
||||
adjtimex(&tx);
|
||||
r ^= (uint32_t) tx.time.tv_sec;
|
||||
r ^= ((uint32_t) tx.time.tv_usec) << 12; // shift into high-bits
|
||||
|
@ -294,23 +320,23 @@ void upx_main(
|
|||
//
|
||||
|
||||
#if defined(USE_MMAP_FO)
|
||||
// mmap()ed output file.
|
||||
malloc_args.ma_fd = fdo;
|
||||
// FIXME: packer could set ma_length
|
||||
malloc_args.ma_length = header.p_filesize;
|
||||
buf = mmap((int *)&malloc_args);
|
||||
// FIXME: packer could set length
|
||||
buf = do_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.
|
||||
scratch_page.ma_addr = buf + (PAGE_MASK & (header.p_filesize + ~PAGE_MASK));
|
||||
mmap((int *)&scratch_page);
|
||||
// FIXME: packer could set address delta
|
||||
do_mmap(buf + (PAGE_MASK & (header.p_filesize + ~PAGE_MASK)),
|
||||
-PAGE_MASK, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 );
|
||||
#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);
|
||||
// FIXME: packer could set length
|
||||
buf = do_mmap(0, (header.p_blocksize + OVERHEAD + ~PAGE_MASK) & PAGE_MASK,
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 );
|
||||
if ((unsigned long) buf >= (unsigned long) -4095)
|
||||
goto error;
|
||||
#endif
|
||||
|
@ -429,34 +455,9 @@ void upx_main(
|
|||
// Many thanks to Andi Kleen <ak@muc.de> and
|
||||
// Jamie Lokier <nospam@cern.ch> for this nice idea.
|
||||
|
||||
// Open the temp file.
|
||||
fdi = open(tmpname, O_RDONLY, 0);
|
||||
if (fdi < 0)
|
||||
if (0 > go_self(tmpname, argv, envp))
|
||||
goto error;
|
||||
|
||||
// Compute name of temp fdi.
|
||||
SET3(procself, 'f', 'd', '/');
|
||||
upx_itoa(procself + 3, fdi);
|
||||
|
||||
// Check for working /proc/self/fd/X by accessing the
|
||||
// temp file again, now via temp fdi.
|
||||
#define err fdo
|
||||
err = access(procself_buf, R_OK | X_OK);
|
||||
if (err == UPX3)
|
||||
{
|
||||
// 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, argv, envp);
|
||||
// NOTE: if we get here we've lost.
|
||||
}
|
||||
#undef err
|
||||
|
||||
// The proc filesystem isn't working. No problem.
|
||||
close(fdi);
|
||||
|
||||
|
||||
//
|
||||
// ----- Step 7: start program in /tmp -----
|
||||
|
@ -474,7 +475,7 @@ void upx_main(
|
|||
if (fork() == 0)
|
||||
{
|
||||
// Sleep 3 seconds, then remove the temp file.
|
||||
static const struct timespec ts = { UPX4, 0 };
|
||||
struct timespec ts; ts.tv_sec = UPX4; ts.tv_nsec = 0;
|
||||
nanosleep(&ts, 0);
|
||||
unlink(tmpname);
|
||||
}
|
||||
|
@ -500,4 +501,3 @@ void upx_main(
|
|||
/*
|
||||
vi:ts=4:et:nowrap
|
||||
*/
|
||||
|
||||
|
|
|
@ -33,34 +33,13 @@
|
|||
%define jmps jmp short
|
||||
%define jmpn jmp near
|
||||
|
||||
; defines for ident.ash and n2b_d32.ash
|
||||
%ifdef SMALL
|
||||
%define __IDENTSMA__
|
||||
%define __N2BSMA10__
|
||||
%define __N2BSMA20__
|
||||
%define __N2BSMA30__
|
||||
%define __N2BSMA40__
|
||||
%define __N2BSMA50__
|
||||
%define __N2BSMA60__
|
||||
%define __N2DSMA10__
|
||||
%define __N2DSMA20__
|
||||
%define __N2DSMA30__
|
||||
%define __N2DSMA40__
|
||||
%define __N2DSMA50__
|
||||
%define __N2DSMA60__
|
||||
%endif
|
||||
|
||||
|
||||
|
||||
%include "ident.ash"
|
||||
|
||||
; /*************************************************************************
|
||||
; // program entry point
|
||||
; // see glibc/sysdeps/i386/elf/start.S
|
||||
; **************************************************************************/
|
||||
|
||||
GLOBAL _start
|
||||
|
||||
;__LEXEC000__
|
||||
_start:
|
||||
;;;; int3
|
||||
;; How to debug this code: Uncomment the 'int3' breakpoint instruction above.
|
||||
|
@ -85,19 +64,24 @@ _start:
|
|||
xor ebx, ebx ; PER_LINUX
|
||||
int 0x80
|
||||
%endif
|
||||
|
||||
call main ; push address of decompress subroutine
|
||||
decompress:
|
||||
|
||||
; /*************************************************************************
|
||||
; // C callable decompressor
|
||||
; **************************************************************************/
|
||||
|
||||
%define INP dword [esp+8*4+4]
|
||||
%define INS dword [esp+8*4+8]
|
||||
%define OUTP dword [esp+8*4+12]
|
||||
%define OUTS dword [esp+8*4+16]
|
||||
%define INP dword [esp+8*4+8]
|
||||
%define INS dword [esp+8*4+12]
|
||||
%define OUTP dword [esp+8*4+16]
|
||||
%define OUTS dword [esp+8*4+20]
|
||||
|
||||
decompress:
|
||||
;__LEXEC009__
|
||||
mov eax, 'NMRU' ; free slot in following 'pusha'
|
||||
;__LEXEC010__
|
||||
pusha
|
||||
push byte '?' ; cto8 (sign extension does not matter)
|
||||
; cld
|
||||
|
||||
mov esi, INP
|
||||
|
@ -105,75 +89,81 @@ decompress:
|
|||
|
||||
or ebp, byte -1
|
||||
;;; align 8
|
||||
%ifdef NRV2B
|
||||
%include "n2b_d32.ash"
|
||||
%elifdef NRV2D
|
||||
%include "n2d_d32.ash"
|
||||
%else
|
||||
%error
|
||||
%endif
|
||||
|
||||
%include "n2b_d32.ash"
|
||||
%include "n2d_d32.ash"
|
||||
%include "macros.ash"
|
||||
cjt32 0
|
||||
|
||||
;__LEXEC015__
|
||||
; eax is 0 from decompressor code
|
||||
;xor eax, eax ; return code
|
||||
|
||||
; check compressed size
|
||||
mov edx, INP
|
||||
add edx, INS
|
||||
cmp esi, edx
|
||||
cmp edx, esi
|
||||
jz .ok
|
||||
dec eax
|
||||
.ok:
|
||||
xchg [8*4 + esp], eax ; store success/failure, fetch NMRU
|
||||
|
||||
; write back the uncompressed size
|
||||
sub edi, OUTP
|
||||
mov edx, OUTS
|
||||
mov [edx], edi
|
||||
; write back the uncompressed size, and prepare for unfilter
|
||||
mov edx, OUTS
|
||||
mov ecx, edi
|
||||
mov edi, OUTP
|
||||
sub ecx, edi ; ecx= uncompressed size
|
||||
mov [edx], ecx
|
||||
|
||||
mov [7*4 + esp], eax
|
||||
pop edx ; cto8
|
||||
|
||||
;__LEXEC110__ Jcc and/or possible n_mru
|
||||
push edi ; addvalue
|
||||
push byte 0x0f
|
||||
pop ebx
|
||||
mov bh, dl ; ebx= 0,,cto8,0x0F
|
||||
|
||||
;__LEXEC100__ 0!=n_mru
|
||||
xchg eax, ebx ; eax= ct08_0f; ebx= n_mru {or n_mru1}
|
||||
|
||||
;;LEXEC016 bug in APP: jmp and target must be in same .asx
|
||||
;; jmpn lxunf0 ; logically belongs here
|
||||
|
||||
ctojr32
|
||||
ckt32 dl
|
||||
;__LEXEC017__
|
||||
popa
|
||||
ret
|
||||
|
||||
;__LEXEC020__
|
||||
|
||||
%define PAGE_MASK (~0<<12)
|
||||
%define PAGE_SIZE ( 1<<12)
|
||||
|
||||
%define szElf32_Ehdr 0x34
|
||||
%define szElf32_Phdr 8*4
|
||||
%define p_filesz 4*4
|
||||
%define p_memsz 5*4
|
||||
%define a_val 4
|
||||
|
||||
%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
|
||||
%define __NR_munmap 91
|
||||
|
||||
; Decompress the rest of this loader, and jump to it
|
||||
unfold:
|
||||
pop esi ; &fold_begin = src
|
||||
pop esi ; &{ sz_uncompressed, sz_compressed, compressed_data...}
|
||||
mov ecx, PAGE_MASK
|
||||
push esi ; &dst
|
||||
mov ecx, ebp ; &decompress
|
||||
and ecx, dword PAGE_MASK ; &my_elfhdr
|
||||
mov ebx, ecx ; save &my_elfhdr for later
|
||||
mov ebx, ebp ; &decompress
|
||||
and ebx, ecx ; &my_elfhdr
|
||||
neg ecx ; ecx= PAGE_SIZE
|
||||
|
||||
cld
|
||||
lodsd ; sz_uncompressed
|
||||
lodsd ; sz_compressed
|
||||
|
||||
;; 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, [-PAGE_MASK + ecx] ; high end of page
|
||||
add ecx, [p_filesz + szElf32_Ehdr + ecx] ; beyond src
|
||||
sub ecx, esi ; srclen
|
||||
push ecx ; srclen
|
||||
sub edi, ecx
|
||||
push edi ; &src
|
||||
cld
|
||||
rep movsb
|
||||
|
||||
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
|
||||
|
@ -188,23 +178,14 @@ unfold:
|
|||
|
||||
main:
|
||||
pop ebp ; &decompress
|
||||
push eax ; place to store dstlen
|
||||
push esp ; &dstlen
|
||||
push eax ; sz_uncompressed (junk, actually)
|
||||
push esp ; &sz_uncompressed
|
||||
call unfold
|
||||
fold_begin: ;; this label is known to the Makefile
|
||||
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
|
||||
EXTERN upx_main
|
||||
call upx_main ; Call the UPX main function
|
||||
hlt ; Crash if somehow upx_main does return
|
||||
eof:
|
||||
; __XTHEENDX__
|
||||
section .data
|
||||
dd -1
|
||||
dw eof
|
||||
|
||||
; vi:ts=8:et:nowrap
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
ENTRY(_start)
|
||||
/*ENTRY(_start)*/
|
||||
SECTIONS
|
||||
{
|
||||
/* 0x08048000: customary Linux/x86 Elf .text start */
|
||||
|
|
|
@ -30,37 +30,13 @@
|
|||
BITS 32
|
||||
SECTION .text
|
||||
|
||||
%define jmps jmp short
|
||||
%define jmpn jmp near
|
||||
|
||||
; defines for ident.ash and n2b_d32.ash
|
||||
%ifdef SMALL
|
||||
%define __IDENTSMA__
|
||||
%define __N2BSMA10__
|
||||
%define __N2BSMA20__
|
||||
%define __N2BSMA30__
|
||||
%define __N2BSMA40__
|
||||
%define __N2BSMA50__
|
||||
%define __N2BSMA60__
|
||||
%define __N2DSMA10__
|
||||
%define __N2DSMA20__
|
||||
%define __N2DSMA30__
|
||||
%define __N2DSMA40__
|
||||
%define __N2DSMA50__
|
||||
%define __N2DSMA60__
|
||||
%endif
|
||||
|
||||
|
||||
|
||||
%include "ident.ash"
|
||||
|
||||
; /*************************************************************************
|
||||
; // program entry point
|
||||
; // see glibc/sysdeps/i386/elf/start.S
|
||||
; **************************************************************************/
|
||||
|
||||
GLOBAL _start
|
||||
|
||||
;__LEXEC000__
|
||||
_start:
|
||||
;;;; int3
|
||||
;; How to debug this code: Uncomment the 'int3' breakpoint instruction above.
|
||||
|
@ -79,7 +55,9 @@ _start:
|
|||
;; end
|
||||
;; Step through the code; remember that <Enter> repeats the previous command.
|
||||
;;
|
||||
|
||||
call main ; push address of decompress subroutine
|
||||
decompress:
|
||||
|
||||
; /*************************************************************************
|
||||
; // C callable decompressor
|
||||
|
@ -90,7 +68,7 @@ _start:
|
|||
%define OUTP dword [esp+8*4+12]
|
||||
%define OUTS dword [esp+8*4+16]
|
||||
|
||||
decompress:
|
||||
;__LEXEC010__
|
||||
pusha
|
||||
; cld
|
||||
|
||||
|
@ -99,15 +77,13 @@ decompress:
|
|||
|
||||
or ebp, byte -1
|
||||
;;; align 8
|
||||
%ifdef NRV2B
|
||||
%include "n2b_d32.ash"
|
||||
%elifdef NRV2D
|
||||
%include "n2d_d32.ash"
|
||||
%else
|
||||
%error
|
||||
%endif
|
||||
|
||||
%include "n2b_d32.ash"
|
||||
%include "n2d_d32.ash"
|
||||
%include "macros.ash"
|
||||
cjt32 0
|
||||
|
||||
;__LEXEC015__
|
||||
; eax is 0 from decompressor code
|
||||
;xor eax, eax ; return code
|
||||
|
||||
|
@ -128,15 +104,13 @@ decompress:
|
|||
popa
|
||||
ret
|
||||
|
||||
;__LEXEC020__
|
||||
|
||||
%define PAGE_MASK (~0<<12)
|
||||
%define PAGE_SIZE ( 1<<12)
|
||||
|
||||
%define szElf32_Ehdr 0x34
|
||||
%define szElf32_Phdr 8*4
|
||||
%define p_filesz 4*4
|
||||
%define p_memsz 5*4
|
||||
%define a_val 4
|
||||
|
||||
%define MAP_FIXED 0x10
|
||||
%define MAP_PRIVATE 0x02
|
||||
|
@ -145,7 +119,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:
|
||||
|
@ -186,104 +159,12 @@ unfold:
|
|||
main:
|
||||
pop ebp ; &decompress
|
||||
call unfold
|
||||
fold_begin:
|
||||
; patchLoader will modify to be
|
||||
; dword sz_uncompressed, sz_compressed
|
||||
; byte compressed_data...
|
||||
|
||||
pop eax ; discard &sz_uncompressed
|
||||
pop eax ; discard sz_uncompressed
|
||||
|
||||
; 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 OVERHEAD 2048
|
||||
%define MAX_ELF_HDR 512
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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"
|
||||
|
||||
inc ecx
|
||||
push edx ; argv[0] is duplicate of $0
|
||||
|
||||
push ecx ; new argc
|
||||
push eax ; 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.
|
||||
; Ulrich Drepper (drepper@cyngus.com) has refused to fix the bugs.
|
||||
; See GNU wwwgnats libc/1165 .
|
||||
|
||||
%define N_STKCLR (0x100 + MAX_ELF_HDR + OVERHEAD)/4
|
||||
lea edi, [esp - 4*N_STKCLR]
|
||||
pusha ; values will be zeroed
|
||||
mov ecx, N_STKCLR
|
||||
xor eax,eax
|
||||
rep stosd
|
||||
|
||||
; Because the decompressed shell script occupies low memory anyway,
|
||||
; there isn't much payback to unmapping the compressed script and
|
||||
; ourselves the stub. We would need a place to put the escape hatch
|
||||
; "int $0x80; popa; ret", and some kernels do not allow execution
|
||||
; on the stack. So, we would have to dirty a page of the shell
|
||||
; or of /lib/ld-linux.so. It's simpler just to omit the unapping.
|
||||
popa
|
||||
ret
|
||||
|
||||
do_auxv: ; entry: %esi=src = &argc; %edi=dst. exit: %edi= &AT_NULL
|
||||
; cld
|
||||
|
||||
L10: ; move argc+argv
|
||||
lodsd
|
||||
stosd
|
||||
test eax,eax
|
||||
jne L10
|
||||
|
||||
L20: ; move envp
|
||||
lodsd
|
||||
stosd
|
||||
test eax,eax
|
||||
jne L20
|
||||
|
||||
L30: ; move existing Elf32_auxv
|
||||
lodsd
|
||||
stosd
|
||||
test eax,eax ; AT_NULL ?
|
||||
lodsd
|
||||
stosd
|
||||
jne L30
|
||||
|
||||
sub edi, byte 8 ; point to AT_NULL
|
||||
ret
|
||||
|
||||
eof:
|
||||
; __XTHEENDX__
|
||||
section .data
|
||||
dd -1
|
||||
dw eof
|
||||
|
||||
; vi:ts=8:et:nowrap
|
||||
|
||||
|
|
|
@ -27,18 +27,29 @@
|
|||
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
ENTRY(_start)
|
||||
/*ENTRY(_start)*/
|
||||
SECTIONS
|
||||
{
|
||||
/* 0x00800000: avoid 0x00400000 for shell itself being compressed */
|
||||
. = 0x00800000 + SIZEOF_HEADERS;
|
||||
. = ALIGN(0x80);
|
||||
/*
|
||||
.text : {
|
||||
*(.text)
|
||||
*(.data)
|
||||
}
|
||||
*/
|
||||
.data : { /* put everything together in one Phdr */
|
||||
*(.text)
|
||||
*(.rodata)
|
||||
*(.data)
|
||||
*(.bss)
|
||||
*(COMMON)
|
||||
}
|
||||
/* 0x08048000: customary Linux/x86 Elf .text start */
|
||||
/*
|
||||
. = 0x08048000 + (0xfff & .);
|
||||
.data : {
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -168,6 +168,53 @@ ctend:
|
|||
%endmacro
|
||||
|
||||
|
||||
;; call/jump/jcc trick; also used more than once (and/or optionally), so
|
||||
;; ecx has byte count (not count of applied instances), and
|
||||
;; edi points to buffer.
|
||||
%macro ckt32 1 ; param: where is cto8 (dl, bl, or literal)
|
||||
;__CKLLTR00__
|
||||
mov esi, edi ; base of block
|
||||
jmps ckstart
|
||||
ckloop3:
|
||||
mov al, [edi]
|
||||
inc edi
|
||||
;__CKLLTR10__ Jcc only
|
||||
cmp al, 0x80 ; lo of 6-byte Jcc
|
||||
jb ckloop2
|
||||
cmp al, 0x8f ; hi of 6-byte Jcc
|
||||
ja ckloop2
|
||||
cmp byte [edi -2], 0x0F ; prefix of 6-byte Jcc
|
||||
je ckmark
|
||||
ckloop2:
|
||||
;__CKLLTR20__
|
||||
sub al, 0xE8
|
||||
cmp al, 0xE9 - 0xE8
|
||||
ja ckcount
|
||||
ckmark:
|
||||
cmp byte [edi], %1 ; cto8
|
||||
jnz ckcount
|
||||
mov eax, [edi]
|
||||
|
||||
shr ax, 8
|
||||
rol eax, 16
|
||||
xchg al, ah
|
||||
|
||||
sub eax, edi
|
||||
add eax, esi
|
||||
mov [edi], eax
|
||||
add edi, byte 4
|
||||
ckstart:
|
||||
sub ecx, byte 4
|
||||
;__CKLLTR30__ Jcc only
|
||||
mov al, [edi]
|
||||
inc edi
|
||||
loop ckloop2 ; prefix cannot overlap previous displacement
|
||||
;__CKLLTR40__
|
||||
ckcount:
|
||||
dec ecx
|
||||
jg ckloop3
|
||||
ckend:
|
||||
%endmacro
|
||||
|
||||
;; =============
|
||||
;; ============= 32-BIT RELOCATIONS
|
||||
|
@ -213,4 +260,312 @@ reloc_endx:
|
|||
%endmacro
|
||||
|
||||
|
||||
;; =============
|
||||
;; ============= 32-BIT CALL TRICK UNFILTER WITH MostRecentlyUsed BUFFER
|
||||
;; =============
|
||||
|
||||
;;;; names of pseudo-sections for addLoader:
|
||||
;; LXUNFnnn Linux unfilter
|
||||
;; LXMRUnnn MostRecentlyUsed recoding of destinations
|
||||
;; MRUARBnn arbitrary number of entries in wheel
|
||||
;; MRUBITSn power of 2 entries in wheel (smaller code)
|
||||
;; MRUBYTEn 256 entries in wheel (smallest code)
|
||||
|
||||
%macro ctojr32 0
|
||||
;; I got confused by the syntactic sugar of the fake %ifdefs.
|
||||
;; I can read the section name more easily when it is at the left margin.
|
||||
;; Also, some of the logic to select the sections is not that simple,
|
||||
;; and any mismatch between the logic and the %ifdefs is very confusing.
|
||||
;; Instead, I use comments after the section name, and blank lines for grouping.
|
||||
|
||||
;__LXUNF000__ enter at +0 for decompression; +2 for unfiltering
|
||||
jmps decompr0
|
||||
;__LXUNF002__
|
||||
;; 2+ address of decompress subroutine
|
||||
;; unfilter(upx_byte *, length, cto8)
|
||||
lxunfilter:
|
||||
pop edx ; return address
|
||||
pop eax ; upx_byte *, same as addvalue
|
||||
pop ecx ; length
|
||||
xchg eax, edi ; edi= pointer; eax= saved_edi
|
||||
pusha ; save C-convention ebx, ebp, esi, edi; also eax, edx
|
||||
|
||||
; at most one of the next 2
|
||||
;__MRUBYTE0__ 256==n_mru
|
||||
xor ebx, ebx ; zero
|
||||
;__LXMRU005__ 0!=n_mru
|
||||
mov ebx, 'NMRU' ; modified N_MRU or N_MRU -1
|
||||
|
||||
;__LXMRU006__ 0!=n_mru
|
||||
push byte 0x0f ; prefix of 6-byte Jcc <d32>
|
||||
pop eax
|
||||
mov ah, [esp + 8*4] ; cto8
|
||||
;__LXMRU007__ 0==n_mru
|
||||
push byte 0x0f ; prefix of 6-byte Jcc <d32>
|
||||
pop ebx
|
||||
mov bh, [esp + 8*4] ; cto8
|
||||
|
||||
;__LXUNF008__
|
||||
mov dl, [esp + 8*4] ; cto8
|
||||
|
||||
;__LXUNF010__
|
||||
jmpn lxunf0
|
||||
decompr0:
|
||||
|
||||
;; These %define are only if 0!=n_mru;
|
||||
;; else 0x0F==bl && cto8==bh==dh && 0xE8==dl && addvalue==esi .
|
||||
%define n_mru [esi]
|
||||
%define n_mru1 [esi]
|
||||
%define tail [esi + 4*1]
|
||||
%define cto8_e8e9 [esi + 4*2]
|
||||
%define cto8_0f [esi + 4*3]
|
||||
%define addvalue [esi + 4*4]
|
||||
%define tmp ebp
|
||||
%define hand ebx
|
||||
%define hand_l bl
|
||||
%define kh edx
|
||||
%define kh_l dl
|
||||
|
||||
;__LXJCC010__
|
||||
lxunf2: ; have seen 0x80..0x8f of possible recoded 6-byte Jcc <d32>
|
||||
movzx ebp, word [edi] ; 2 bytes, zero-extended
|
||||
|
||||
;__LXMRU045__ 0!=n_mru
|
||||
sub ebp, cto8_0f
|
||||
;__LXMRU046__ 0==n_mru
|
||||
sub ebp, ebx
|
||||
|
||||
;__LXJCC020__ 0==n_mru, or Jcc excluded ('sub' of equals clears Carry)
|
||||
jne unfcount
|
||||
;__LXJCC021__ 0!=n_mru and Jcc participates; must set Carry
|
||||
sub ebp, byte 1 ; set Carry iff in range
|
||||
jnb unfcount
|
||||
|
||||
;__LXJCC023__ found Jcc; re-swap 0x8Y opcode and 0x0f prefix
|
||||
mov byte [edi -1], bl ; 0x0f prefix
|
||||
dec ecx ; preserve Carry
|
||||
mov byte [edi], al ; Jcc opcode
|
||||
inc edi ; preserve Carry
|
||||
|
||||
;__LXUNF037__
|
||||
%define jc eax
|
||||
|
||||
lxunf: ; in: Carry set iff we should apply mru and 0!=n_mru
|
||||
mov eax, [edi] ; BE32 displacement with cto8 in low 8 bits
|
||||
|
||||
;__LXUNF386__ 0!=n_mru && 386
|
||||
pushf
|
||||
;__LXUNF387__ ==386
|
||||
shr ax, 8
|
||||
rol eax, 16
|
||||
xchg al, ah
|
||||
;__LXUNF388__ 0!=n_mru && 386
|
||||
popf
|
||||
jnc unf_store ; do not apply mru
|
||||
|
||||
;__LXUNF486__ >=486
|
||||
mov al, byte 0
|
||||
bswap eax ; preserve Carry (2-byte instruction)
|
||||
;__LXUNF487__ 0!=n_mru && >=486
|
||||
jnc unf_store ; do not apply mru
|
||||
|
||||
;__LXMRU065__ 0!=n_mru
|
||||
shr jc, 1 ; eax= jc, or mru index
|
||||
jnc mru4 ; not 1st time for this jc
|
||||
;__MRUBYTE3__
|
||||
dec hand_l
|
||||
;__MRUARB30__
|
||||
dec hand
|
||||
;__MRUBITS3__
|
||||
and hand, n_mru1
|
||||
;__MRUARB40__
|
||||
jge mru3
|
||||
add hand, n_mru
|
||||
mru3:
|
||||
;__LXMRU070__
|
||||
|
||||
mov [esp + 4*hand], jc ; 1st time: mru[hand] = jc
|
||||
jmps unf_store
|
||||
|
||||
mru4: ; not 1st time for this jc
|
||||
lea kh, [jc + hand] ; kh = jc + hand
|
||||
;__MRUBYTE4__
|
||||
movzx kh, kh_l
|
||||
;__MRUBITS4__
|
||||
and kh, n_mru1
|
||||
;__MRUARB50__
|
||||
cmp kh, n_mru
|
||||
jb mru5
|
||||
sub kh, n_mru
|
||||
mru5:
|
||||
;__LXMRU080__
|
||||
mov jc, [esp + 4*kh] ; jc = mru[kh]
|
||||
;__MRUBYTE5__
|
||||
dec hand_l
|
||||
;__MRUARB60__
|
||||
dec hand
|
||||
;__MRUBITS5__
|
||||
and hand, n_mru1
|
||||
;__MRUARB70__
|
||||
jge mru6
|
||||
add hand, n_mru
|
||||
mru6:
|
||||
;__LXMRU090__
|
||||
|
||||
mov tmp, [esp + 4*hand] ; tmp = mru[hand]
|
||||
test tmp,tmp
|
||||
jnz mru8
|
||||
|
||||
push jc ; ran out of registers
|
||||
mov eax, tail
|
||||
|
||||
;__MRUBYTE6__
|
||||
dec al
|
||||
;__MRUARB80__
|
||||
dec eax
|
||||
;__MRUBITS6__
|
||||
and eax, n_mru1
|
||||
;__MRUARB90__
|
||||
jge mru7
|
||||
add eax, n_mru
|
||||
mru7:
|
||||
;__LXMRU100__
|
||||
|
||||
xor tmp,tmp
|
||||
mov tail, eax
|
||||
xchg [4+ esp + 4*eax], tmp ; tmp = mru[tail]; mru[tail] = 0
|
||||
pop jc
|
||||
mru8:
|
||||
mov [esp + 4*kh ], tmp ; mru[kh] = tmp
|
||||
mov [esp + 4*hand], jc ; mru[hand] = jc
|
||||
;__LXUNF040__
|
||||
unf_store:
|
||||
sub eax, edi
|
||||
sub ecx, byte 4
|
||||
|
||||
; one of the next2
|
||||
;__LXMRU110__ 0!=n_mru
|
||||
add eax, addvalue
|
||||
;__LXMRU111__ 0==n_mru
|
||||
add eax, esi ; addvalue (same as initial pointer)
|
||||
|
||||
;__LXUNF041__
|
||||
mov [edi], eax
|
||||
add edi, byte 4
|
||||
jmps unfcount
|
||||
;__LXUNF042__
|
||||
lxunf0: ;; continuation of entry prolog for unfilter
|
||||
;__LEXEC016__ bug in APP: jmp and label must be in same .asx/.asy
|
||||
jmp lxunf0 ; this instr does not really go here!
|
||||
|
||||
;__LXMRU010__ 0!=n_mru
|
||||
push eax ; cto8_0f
|
||||
;__LXJMPA00__ only JMP, and not CALL, is filtered
|
||||
mov al, 0xE9
|
||||
;__LXCALLB0__ only CALL, or both CALL and JMP are filtered
|
||||
mov al, 0xE8
|
||||
;__LXUNF021__ common tail
|
||||
push eax ; cto8_e8e9
|
||||
push byte 0 ; tail
|
||||
push ebx ; n_mru or n_mru1
|
||||
mov esi, esp ; flat model "[esi]" saves a byte over "[ebp]"
|
||||
|
||||
;__LXMRU022__ 0==n_mru
|
||||
pop esi ; addvalue
|
||||
mov edx, ebx ; dh= cto8
|
||||
;__LXJMPA01__ only JMP, and not CALL, is filtered
|
||||
mov dl, 0xE9
|
||||
;__LXCALLB1__ only CALL, or both CALL and JMP are filtered
|
||||
mov dl, 0xE8
|
||||
|
||||
|
||||
;__MRUBITS1__
|
||||
inc hand ; n_mru1 ==> n_mru
|
||||
;__LXMRU030__
|
||||
lxunf1: ; allocate and clear mru[]
|
||||
push byte 0
|
||||
|
||||
; one of the next 2, if n_mru
|
||||
;__MRUBYTE1__
|
||||
dec hand_l
|
||||
;__MRUARB10__
|
||||
dec hand
|
||||
|
||||
;__LXMRU040__ 0!=n_mru
|
||||
jnz lxunf1 ; leaves 0=='hand'
|
||||
|
||||
;__LXUNF030__
|
||||
lxctloop:
|
||||
movzx eax, word [edi] ; 2 bytes, zero extended
|
||||
inc edi
|
||||
;__LXJCC000__
|
||||
cmp al, 0x80 ; lo of Jcc <d32>
|
||||
jb lxct1
|
||||
cmp al, 0x8f ; hi of Jcc <d32>
|
||||
jbe lxunf2
|
||||
lxct1:
|
||||
|
||||
;__LXCJ0MRU__ 0==n_mru
|
||||
sub eax, edx
|
||||
;__LXCJ1MRU__ 0!=n_mru
|
||||
sub eax, cto8_e8e9
|
||||
|
||||
; both CALL and JMP are filtered
|
||||
;__LXCALJMP__
|
||||
sub eax, byte 1+ (0xE9 - 0xE8) ; set Carry iff in range (result: -2, -1)
|
||||
|
||||
; only CALL, or only JMP, is filtered
|
||||
;__LXCALL00__ 0==n_mru
|
||||
je lxunf
|
||||
;__LXCALL01__ 0!=n_rmu
|
||||
sub eax, byte 1 ; set Carry iff in range
|
||||
|
||||
;__LXCJ2MRU__ 0==n_mru, or apply mru to all that are filtered here
|
||||
jb lxunf ; only Carry (Borrow) matters
|
||||
;__LXCJ4MRU__ 0!=n_mru, but apply mru only to subset of filtered here
|
||||
jnb unfcount ; was not filtered anyway: do not unfilter
|
||||
|
||||
;we will unfilter, and 0!=n_mru, but should we apply mru?
|
||||
;__LXCJ6MRU__ apply mru to JMP only (0xFF==al)
|
||||
jpe lxct3 ; jump if even number of 1 bits in al
|
||||
;__LXCJ7MRU__ apply mru to CALL only (0xFE==al)
|
||||
jpo lxct3 ; jump if odd number of 1 bits in al
|
||||
;__LXCJ8MRU__ do not apply mru to one or both
|
||||
clc
|
||||
lxct3:
|
||||
jmps lxunf
|
||||
|
||||
;__LXUNF034__
|
||||
unfcount:
|
||||
dec ecx
|
||||
jg lxctloop
|
||||
|
||||
;__LXMRU055__
|
||||
mov edi, esp ; clear mru[] portion of stack
|
||||
;__MRUBYTE2__
|
||||
mov ecx, 4+ 256 ; unused, tail, cto8_e8e9, cto8_0f
|
||||
;__MRUBITS2__
|
||||
mov ecx, n_mru1
|
||||
add ecx, byte 1+ 4 ; n_mru1, tail, cto8_e8e9, cto8_0f
|
||||
;__MRUARB20__
|
||||
mov ecx, n_mru
|
||||
add ecx, byte 4 ; n_mru, tail, cto8_e8e9, cto8_0f
|
||||
;__LXMRU057__
|
||||
xor eax, eax
|
||||
rep
|
||||
stosd
|
||||
mov esp, edi
|
||||
|
||||
;__LXMRU058__ 0==n_mru
|
||||
push esi
|
||||
;__LXUNF035__
|
||||
popa
|
||||
xchg eax, edi
|
||||
push ecx
|
||||
push eax
|
||||
push edx
|
||||
ret
|
||||
|
||||
%endmacro
|
||||
|
||||
; vi:ts=8:et:nowrap
|
||||
|
|
Loading…
Reference in New Issue
Block a user