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:
+126
-62
@@ -33,7 +33,29 @@
|
|||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
#ifdef U //{
|
#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.
|
// Adaptively remember recent destinations.
|
||||||
static void
|
static void
|
||||||
@@ -70,7 +92,6 @@ static int F(Filter *f)
|
|||||||
#ifdef U
|
#ifdef U
|
||||||
// filter
|
// filter
|
||||||
upx_byte *const b = f->buf;
|
upx_byte *const b = f->buf;
|
||||||
const unsigned addvalue = f->addvalue;
|
|
||||||
#else
|
#else
|
||||||
// scan
|
// scan
|
||||||
const upx_byte *b = f->buf;
|
const upx_byte *b = f->buf;
|
||||||
@@ -80,22 +101,30 @@ static int F(Filter *f)
|
|||||||
unsigned ic, jc, kc;
|
unsigned ic, jc, kc;
|
||||||
unsigned calls = 0, noncalls = 0, noncalls2 = 0;
|
unsigned calls = 0, noncalls = 0, noncalls2 = 0;
|
||||||
unsigned lastnoncall = size, lastcall = 0;
|
unsigned lastnoncall = size, lastcall = 0;
|
||||||
|
unsigned wtally[3]; memset(wtally, 0, sizeof(wtally));
|
||||||
|
|
||||||
#ifdef U //{
|
#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;
|
int hand = 0, tail = 0;
|
||||||
unsigned mru[N_MRU];
|
unsigned mru[N_MRU];
|
||||||
memset(&mru[0], 0, sizeof(mru));
|
memset(&mru[0], 0, sizeof(mru));
|
||||||
f->n_mru = N_MRU;
|
assert(N_MRU<=256);
|
||||||
|
f->n_mru = (MRUFLT==f_call || MRUFLT==f_jmp1 || MRUFLT==f_jcc2) ?
|
||||||
|
N_MRU : 0;
|
||||||
#endif //}
|
#endif //}
|
||||||
|
|
||||||
// FIXME: We must fit into 8MB because we steal one bit.
|
// FIXME: We must fit into 8MB because we steal one bit.
|
||||||
// find a 16MB large empty address space
|
// find a 16MB large empty address space
|
||||||
{
|
{
|
||||||
|
int which;
|
||||||
unsigned char buf[256];
|
unsigned char buf[256];
|
||||||
memset(buf,0,256);
|
memset(buf,0,256);
|
||||||
|
|
||||||
for (ic = 0; ic < size - 5; ic++)
|
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;
|
buf[b[ic+1]] |= 1;
|
||||||
}
|
}
|
||||||
@@ -110,14 +139,17 @@ static int F(Filter *f)
|
|||||||
|
|
||||||
for (ic = 0; ic < size - 5; ic++)
|
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;
|
continue;
|
||||||
|
++wtally[which];
|
||||||
jc = get_le32(b+ic+1)+ic+1;
|
jc = get_le32(b+ic+1)+ic+1;
|
||||||
// try to detect 'real' calls only
|
// try to detect 'real' calls only
|
||||||
if (jc < size)
|
if (jc < size)
|
||||||
{
|
{
|
||||||
#ifdef U
|
#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
|
// Prefix 0x0f is constant, but opcode condition 0x80..0x8f
|
||||||
// varies. Because we store the destination (or its mru index)
|
// varies. Because we store the destination (or its mru index)
|
||||||
// in be32 big endian format, the low-addressed bytes
|
// 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.
|
// FIXME [?]: Extend to 8 bytes if "ADD ESP, byte 4*n" follows CALL.
|
||||||
// This will require two related cto's (consecutive, or otherwise).
|
// 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
|
// Recode the destination: narrower mru indices
|
||||||
// should compress better than wider addresses.
|
// should compress better than wider addresses.
|
||||||
|
// (But not when offset of match is unlimited?)
|
||||||
int k;
|
int k;
|
||||||
for (k = 0; k < N_MRU; ++k) {
|
for (k = 0; k < N_MRU; ++k) {
|
||||||
int kh = hand + k;
|
int kh = hand + k;
|
||||||
@@ -153,38 +189,45 @@ static int F(Filter *f)
|
|||||||
}
|
}
|
||||||
mru[hand] = jc;
|
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
|
#endif
|
||||||
if (ic - lastnoncall < 5)
|
if (f_on) {
|
||||||
{
|
if (ic - lastnoncall < 5)
|
||||||
// check the last 4 bytes before this call
|
{
|
||||||
for (kc = 4; kc; kc--)
|
// check the last 4 bytes before this call
|
||||||
if (CONDF(b,ic-kc,lastcall) && b[ic-kc+1] == cto8)
|
for (kc = 4; kc; kc--)
|
||||||
break;
|
if (CONDF(which,b,ic-kc,lastcall) && b[ic-kc+1] == cto8)
|
||||||
if (kc)
|
break;
|
||||||
{
|
if (kc)
|
||||||
#ifdef U
|
{
|
||||||
// restore original
|
#ifdef U
|
||||||
if (COND2(b,lastcall,ic,ic,ic-1)) {
|
// restore original
|
||||||
// Unswap prefix and opcode for 6-byte Jcc <disp32>
|
if (2==which) {
|
||||||
unsigned char const t =
|
// Unswap prefix and opcode for 6-byte Jcc <disp32>
|
||||||
b[ic-1];
|
unsigned char const t =
|
||||||
b[ic-1] = b[ic];
|
b[ic-1];
|
||||||
b[ic] = t;
|
b[ic-1] = b[ic];
|
||||||
}
|
b[ic] = t;
|
||||||
set_le32(b+ic+1,jc-ic-1);
|
}
|
||||||
#endif
|
set_le32(b+ic+1,jc-ic-1);
|
||||||
if (b[ic+1] == cto8)
|
#endif
|
||||||
return 1; // fail - buffer not restored
|
if (b[ic+1] == cto8)
|
||||||
lastnoncall = ic;
|
return 1; // fail - buffer not restored
|
||||||
noncalls2++;
|
lastnoncall = ic;
|
||||||
continue;
|
noncalls2++;
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
calls++;
|
||||||
|
ic += 4;
|
||||||
|
lastcall = ic+1;
|
||||||
}
|
}
|
||||||
calls++;
|
|
||||||
ic += 4;
|
|
||||||
lastcall = ic+1;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -198,9 +241,11 @@ static int F(Filter *f)
|
|||||||
f->noncalls = noncalls;
|
f->noncalls = noncalls;
|
||||||
f->lastcall = lastcall;
|
f->lastcall = lastcall;
|
||||||
|
|
||||||
#ifdef TESTING
|
/*#ifdef TESTING*/
|
||||||
printf("\ncalls=%d noncalls=%d noncalls2=%d text_size=%x calltrickoffset=%x\n",calls,noncalls,noncalls2,size,cto);
|
printf("\ncalls=%d noncalls=%d noncalls2=%d text_size=%x calltrickoffset=%x\n",
|
||||||
#endif
|
calls,noncalls,noncalls2,size,cto8);
|
||||||
|
printf("CALL/JMP/JCC %d %d %d\n",wtally[0],wtally[1],wtally[2]);
|
||||||
|
/*#endif*/
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,43 +264,62 @@ static int U(Filter *f)
|
|||||||
const unsigned cto = (unsigned)f->cto << 24;
|
const unsigned cto = (unsigned)f->cto << 24;
|
||||||
unsigned lastcall = 0;
|
unsigned lastcall = 0;
|
||||||
int hand = 0, tail = 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];
|
unsigned mru[N_MRU];
|
||||||
memset(&mru[0], 0, sizeof(mru));
|
memset(&mru[0], 0, sizeof(mru));
|
||||||
|
|
||||||
for (ic = 0; ic < size5; ic++) {
|
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;
|
jc = get_be32(b+ic+1) - cto;
|
||||||
if (b[ic+1] == f->cto)
|
if (b[ic+1] == f->cto)
|
||||||
{
|
{
|
||||||
if (1&jc) { // 1st time at this destination
|
if ((0==which && MRUFLT==f_call)
|
||||||
jc >>= 1;
|
|| (1==which && MRUFLT==f_jmp1)
|
||||||
if (0 > --hand) {
|
|| (2==which && MRUFLT==f_jcc2) ) {
|
||||||
hand = N_MRU -1;
|
f_on = 1;
|
||||||
}
|
if (1&jc) { // 1st time at this destination
|
||||||
mru[hand] = jc;
|
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
|
if (2==which && NOFILT!=f_jcc2) {
|
||||||
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)) {
|
|
||||||
// Unswap prefix and opcode for 6-byte Jcc <disp32>
|
// Unswap prefix and opcode for 6-byte Jcc <disp32>
|
||||||
unsigned char const t =
|
unsigned char const t =
|
||||||
b[ic-1];
|
b[ic-1];
|
||||||
b[ic-1] = b[ic];
|
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
|
else
|
||||||
f->noncalls++;
|
f->noncalls++;
|
||||||
|
|||||||
@@ -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
|
||||||
|
*/
|
||||||
|
|
||||||
+44
-10
@@ -88,9 +88,7 @@
|
|||||||
// cto calltrick with jmp
|
// cto calltrick with jmp
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
#define COND(b,x,lastcall) \
|
#define COND(b,x,lastcall) (b[x] == 0xe8 || b[x] == 0xe9)
|
||||||
(b[x] == 0xe8 || b[x] == 0xe9 \
|
|
||||||
|| (lastcall!=(x) && 0xf==b[(x)-1] && 0x80<=b[x] && b[x]<=0x8f) )
|
|
||||||
#define F f_ctoj32_e8e9_bswap_le
|
#define F f_ctoj32_e8e9_bswap_le
|
||||||
#define U u_ctoj32_e8e9_bswap_le
|
#define U u_ctoj32_e8e9_bswap_le
|
||||||
#include "filter/ctoj.h"
|
#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 COND1(b,x) (b[x] == 0xe8 || b[x] == 0xe9)
|
||||||
#define COND2(b,lastcall,x,y,z) \
|
#define COND2(b,x,lc) (lc!=(x) && 0xf==b[(x)-1] && 0x80<=b[x] && b[x]<=0x8f)
|
||||||
(lastcall!=(x) && 0xf==b[y] && 0x80<=b[z] && b[z]<=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 F f_ctojr32_e8e9_bswap_le
|
||||||
#define U u_ctojr32_e8e9_bswap_le
|
#define U u_ctojr32_e8e9_bswap_le
|
||||||
@@ -120,6 +140,9 @@
|
|||||||
#undef CONDF
|
#undef CONDF
|
||||||
#undef COND2
|
#undef COND2
|
||||||
#undef COND1
|
#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
|
// 32-bit cto calltrick with jmp
|
||||||
{ 0x36, 6, 0x00ffffff, f_ctoj32_e8e9_bswap_le, u_ctoj32_e8e9_bswap_le, s_ctoj32_e8e9_bswap_le },
|
{ 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 },
|
{ 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
|
// simple delta filter
|
||||||
{ 0x90, 2, 0, f_sub8_1, u_sub8_1, s_sub8_1 },
|
{ 0x90, 2, 0, f_sub8_1, u_sub8_1, s_sub8_1 },
|
||||||
|
|||||||
+3
-3
@@ -46,7 +46,6 @@ struct Linker::jump
|
|||||||
int toffs;
|
int toffs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Linker::Linker(const void *pdata, int plen, int pinfo)
|
Linker::Linker(const void *pdata, int plen, int pinfo)
|
||||||
{
|
{
|
||||||
iloader = new char[(ilen = plen) + 4096];
|
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;
|
int ic;
|
||||||
while (*sect)
|
while (*sect)
|
||||||
@@ -129,11 +128,12 @@ void Linker::addSection(const char *sect)
|
|||||||
olen += sections[ic].len;
|
olen += sections[ic].len;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//printf("%8.8s",section);
|
//printf("%8.8s",sect);
|
||||||
assert(ic!=nsections);
|
assert(ic!=nsections);
|
||||||
}
|
}
|
||||||
sect += 8;
|
sect += 8;
|
||||||
}
|
}
|
||||||
|
return olen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -35,10 +35,11 @@ class Linker
|
|||||||
public:
|
public:
|
||||||
Linker(const void *pdata, int plen, int pinfo);
|
Linker(const void *pdata, int plen, int pinfo);
|
||||||
virtual ~Linker();
|
virtual ~Linker();
|
||||||
void addSection(const char *sect);
|
int addSection(const char *sect);
|
||||||
void addSection(const char *sname, const void *sdata, unsigned len);
|
void addSection(const char *sname, const void *sdata, unsigned len);
|
||||||
const char *getLoader(int *llen);
|
const char *getLoader(int *llen);
|
||||||
int getSection(const char *name, int *slen) const;
|
int getSection(const char *name, int *slen) const;
|
||||||
|
int getLoaderSize() const { return olen; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// little endian
|
// little endian
|
||||||
|
|||||||
+41
@@ -47,6 +47,14 @@ MemBuffer::~MemBuffer()
|
|||||||
this->free();
|
this->free();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MemBufferIO::MemBufferIO(unsigned size) :
|
||||||
|
MemBuffer(size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MemBufferIO::~MemBufferIO()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void MemBuffer::free()
|
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)
|
void MemBuffer::alloc(unsigned size, unsigned base_offset)
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
void alloc(unsigned size, unsigned base_offset);
|
void alloc(unsigned size, unsigned base_offset);
|
||||||
|
|
||||||
|
protected:
|
||||||
unsigned char *ptr;
|
unsigned char *ptr;
|
||||||
unsigned char *alloc_ptr;
|
unsigned char *alloc_ptr;
|
||||||
unsigned alloc_size;
|
unsigned alloc_size;
|
||||||
@@ -71,6 +72,14 @@ private:
|
|||||||
//static void operator delete[] (void *) {}
|
//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 */
|
#endif /* already included */
|
||||||
|
|
||||||
|
|||||||
+101
-121
@@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
|
#include "linker.h"
|
||||||
#include "packer.h"
|
#include "packer.h"
|
||||||
#include "p_elf.h"
|
#include "p_elf.h"
|
||||||
#include "p_unix.h"
|
#include "p_unix.h"
|
||||||
@@ -45,9 +46,9 @@
|
|||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
static const
|
static const
|
||||||
#include "stub/l_le_n2b.h"
|
#include "stub/l_lx_elf86.h"
|
||||||
static const
|
static const
|
||||||
#include "stub/l_le_n2d.h"
|
#include "stub/fold_elf86.h"
|
||||||
|
|
||||||
|
|
||||||
PackLinuxI386elf::PackLinuxI386elf(InputFile *f) :
|
PackLinuxI386elf::PackLinuxI386elf(InputFile *f) :
|
||||||
@@ -64,7 +65,12 @@ int const *
|
|||||||
PackLinuxI386elf::getFilters() const
|
PackLinuxI386elf::getFilters() const
|
||||||
{
|
{
|
||||||
static const int filters[] = {
|
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 };
|
-1 };
|
||||||
return filters;
|
return filters;
|
||||||
}
|
}
|
||||||
@@ -72,103 +78,34 @@ PackLinuxI386elf::getFilters() const
|
|||||||
int
|
int
|
||||||
PackLinuxI386elf::buildLoader(const Filter *ft)
|
PackLinuxI386elf::buildLoader(const Filter *ft)
|
||||||
{
|
{
|
||||||
if (ft) {
|
return buildLinuxLoader(
|
||||||
n_mru = ft->n_mru;
|
linux_i386elf_loader, sizeof(linux_i386elf_loader),
|
||||||
}
|
linux_i386elf_fold, sizeof(linux_i386elf_fold),
|
||||||
else {
|
ft, getbrk(phdri, ehdri.e_phnum) );
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PackLinuxI386elf::updateLoader(OutputFile *fo)
|
void PackLinuxI386elf::updateLoader(OutputFile *fo)
|
||||||
{
|
{
|
||||||
#define PAGE_MASK (~0<<12)
|
#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();
|
off_t const totlen = fo->getBytesWritten();
|
||||||
phdro->p_filesz = totlen;
|
phdro->p_filesz = totlen;
|
||||||
|
|
||||||
// pre-calculate for benefit of runtime disappearing act via munmap()
|
// pre-calculate for benefit of runtime disappearing act via munmap()
|
||||||
phdro->p_memsz = PAGE_MASK & (~PAGE_MASK + totlen);
|
phdro->p_memsz = PAGE_MASK & (~PAGE_MASK + totlen);
|
||||||
|
|
||||||
int d1=0x80, d2=0x80;
|
|
||||||
if (this->n_mru) {
|
|
||||||
int const bytes = ('?'<<8) | 0x0f;
|
|
||||||
d1 += 4+ patch_le32(d1+loader, 400, "NMRU", this->n_mru);
|
|
||||||
d2 += 4+ patch_le32(d2+loader, 400, &bytes, (ph.filter_cto<<8)|0x0f);
|
|
||||||
}
|
|
||||||
patchLoaderChecksum();
|
patchLoaderChecksum();
|
||||||
fo->seek(0, SEEK_SET);
|
|
||||||
fo->rewrite(loader, UPX_MAX3(0x80, d1, d2));
|
|
||||||
#undef PAGE_MASK
|
#undef PAGE_MASK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PackLinuxI386elf::patchLoader()
|
void PackLinuxI386elf::patchLoader()
|
||||||
{
|
{
|
||||||
|
unsigned char *const ptr = const_cast<unsigned char *>(getLoader());
|
||||||
lsize = getLoaderSize();
|
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);
|
assert(lsize > 128 && lsize < 4096);
|
||||||
|
patchVersion(ptr, lsize);
|
||||||
|
|
||||||
patchLoaderChecksum();
|
patchLoaderChecksum();
|
||||||
}
|
}
|
||||||
@@ -228,10 +165,13 @@ bool PackLinuxI386elf::canPack()
|
|||||||
return super::canPack();
|
return super::canPack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct cprBlkHdr {
|
||||||
|
unsigned sz_unc; // uncompressed size (0 means EOF)
|
||||||
|
unsigned sz_cpr; // (compressed_size<<8) | cto8
|
||||||
|
};
|
||||||
|
|
||||||
void PackLinuxI386elf::packExtent(
|
void PackLinuxI386elf::packExtent(
|
||||||
Extent const &x,
|
Extent const &x,
|
||||||
OutputFile *fo,
|
|
||||||
unsigned &total_in,
|
unsigned &total_in,
|
||||||
unsigned &total_out,
|
unsigned &total_out,
|
||||||
Filter *ft
|
Filter *ft
|
||||||
@@ -249,11 +189,13 @@ void PackLinuxI386elf::packExtent(
|
|||||||
// file is e.g. blocksize + 1 bytes long
|
// file is e.g. blocksize + 1 bytes long
|
||||||
|
|
||||||
// compress
|
// compress
|
||||||
|
unsigned char *const hdrptr = obuf;
|
||||||
|
obuf.seek(sizeof(cprBlkHdr), SEEK_CUR);
|
||||||
ph.u_len = l;
|
ph.u_len = l;
|
||||||
ph.overlap_overhead = 0;
|
ph.overlap_overhead = 0;
|
||||||
if (ft) {
|
if (ft) {
|
||||||
ft->buf_len = l;
|
ft->buf_len = l;
|
||||||
compressWithFilters(ft, OVERHEAD);
|
compressWithFilters(ft, OVERHEAD, ((opt->filter > 0) ? -2 : 2));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
(void) compress(ibuf, obuf); // ignore return value
|
(void) compress(ibuf, obuf); // ignore return value
|
||||||
@@ -273,19 +215,18 @@ void PackLinuxI386elf::packExtent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write block sizes
|
// write block sizes
|
||||||
unsigned char size[8];
|
set_native32(0+hdrptr, ph.u_len);
|
||||||
set_native32(size+0, ph.u_len);
|
set_native32(4+hdrptr, (ph.c_len<<8) | ph.filter_cto);
|
||||||
set_native32(size+4, ph.c_len);
|
|
||||||
fo->write(size, 8);
|
|
||||||
|
|
||||||
// write compressed data
|
// write compressed data
|
||||||
if (ph.c_len < ph.u_len)
|
if (ph.c_len < ph.u_len)
|
||||||
{
|
{
|
||||||
fo->write(obuf, ph.c_len);
|
obuf.write(obuf, ph.c_len);
|
||||||
verifyOverlappingDecompression();
|
// FIXME: obuf is not discardable!
|
||||||
|
// verifyOverlappingDecompression();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fo->write(ibuf, ph.u_len);
|
obuf.write(ibuf, ph.u_len);
|
||||||
|
|
||||||
total_in += ph.u_len;
|
total_in += ph.u_len;
|
||||||
total_out += ph.c_len;
|
total_out += ph.c_len;
|
||||||
@@ -300,30 +241,24 @@ void PackLinuxI386elf::pack(OutputFile *fo)
|
|||||||
progid = 0; // not used
|
progid = 0; // not used
|
||||||
|
|
||||||
fi->readx(&ehdri, sizeof(ehdri));
|
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;
|
off_t const sz_phdrs = ehdri.e_phnum * ehdri.e_phentsize;
|
||||||
|
|
||||||
phdri = new Elf_LE32_Phdr[ehdri.e_phnum];
|
phdri = new Elf_LE32_Phdr[ehdri.e_phnum];
|
||||||
fi->seek(ehdri.e_phoff, SEEK_SET);
|
fi->seek(ehdri.e_phoff, SEEK_SET);
|
||||||
fi->readx(phdri, sz_phdrs);
|
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
|
// init compression buffers
|
||||||
ibuf.alloc(blocksize);
|
ibuf.alloc(blocksize);
|
||||||
obuf.allocForCompression(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;
|
Extent x;
|
||||||
unsigned k;
|
unsigned k;
|
||||||
|
|
||||||
@@ -354,52 +289,69 @@ void PackLinuxI386elf::pack(OutputFile *fo)
|
|||||||
unsigned total_in = 0;
|
unsigned total_in = 0;
|
||||||
unsigned total_out = 0;
|
unsigned total_out = 0;
|
||||||
|
|
||||||
|
ui_pass = -1;
|
||||||
x.offset = 0;
|
x.offset = 0;
|
||||||
x.size = sizeof(Elf_LE32_Ehdr) + sz_phdrs;
|
x.size = sizeof(Elf_LE32_Ehdr) + sz_phdrs;
|
||||||
ui_pass = -1;
|
{
|
||||||
packExtent(x, fo, total_in, total_out, 0);
|
int const old_level = ph.level; ph.level = 10;
|
||||||
ui_pass = 0;
|
packExtent(x, total_in, total_out, 0);
|
||||||
|
ph.level = old_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_pass = 0;
|
||||||
Filter ft(ph.level);
|
Filter ft(ph.level);
|
||||||
|
ft.addvalue = 0;
|
||||||
|
|
||||||
nx = 0;
|
nx = 0;
|
||||||
for (k = 0; k < ehdri.e_phnum; ++k) if (PT_LOAD==phdri[k].p_type) {
|
for (k = 0; k < ehdri.e_phnum; ++k) if (PT_LOAD==phdri[k].p_type) {
|
||||||
ft.addvalue = (unsigned)phdri[k].p_paddr;
|
if (ft.id < 0x40) {
|
||||||
|
// FIXME: ?? ft.addvalue = phdri[k].p_vaddr;
|
||||||
|
}
|
||||||
x.offset = phdri[k].p_offset;
|
x.offset = phdri[k].p_offset;
|
||||||
x.size = phdri[k].p_filesz;
|
x.size = phdri[k].p_filesz;
|
||||||
if (0 == nx) { // 1st PT_LOAD must cover Ehdr at 0==p_offset
|
if (0 == nx) { // 1st PT_LOAD must cover Ehdr at 0==p_offset
|
||||||
unsigned const delta = sizeof(Elf_LE32_Ehdr) + sz_phdrs;
|
unsigned const delta = sizeof(Elf_LE32_Ehdr) + sz_phdrs;
|
||||||
ft.addvalue += delta;
|
if (ft.id < 0x40) {
|
||||||
|
// FIXME: ?? ft.addvalue += delta;
|
||||||
|
}
|
||||||
x.offset += delta;
|
x.offset += delta;
|
||||||
x.size -= delta;
|
x.size -= delta;
|
||||||
}
|
}
|
||||||
packExtent(x, fo, total_in, total_out,
|
packExtent(x, total_in, total_out,
|
||||||
((Elf_LE32_Phdr::PF_X & phdri[k].p_flags) ? &ft : 0) );
|
((Elf_LE32_Phdr::PF_X & phdri[k].p_flags)
|
||||||
// FIXME: All PF_X Phdrs must use same ft.cto
|
? &ft : 0 ) );
|
||||||
// (There is usually only one such Phdr, so we're mostly lucky.)
|
|
||||||
++nx;
|
++nx;
|
||||||
}
|
}
|
||||||
if (ptload0hi < ptload1lo) { // alignment hole?
|
if (ptload0hi < ptload1lo) { // alignment hole?
|
||||||
x.offset = ptload0hi;
|
x.offset = ptload0hi;
|
||||||
x.size = ptload1lo - ptload0hi;
|
x.size = ptload1lo - ptload0hi;
|
||||||
packExtent(x, fo, total_in, total_out, 0);
|
packExtent(x, total_in, total_out, 0);
|
||||||
}
|
}
|
||||||
if ((off_t)total_in < file_size) { // non-PT_LOAD stuff
|
if ((off_t)total_in < file_size) { // non-PT_LOAD stuff
|
||||||
x.offset = total_in;
|
x.offset = total_in;
|
||||||
x.size = file_size - total_in;
|
x.size = file_size - total_in;
|
||||||
packExtent(x, fo, total_in, total_out, 0);
|
packExtent(x, total_in, total_out, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((off_t)total_in != file_size)
|
if ((off_t)total_in != file_size)
|
||||||
throwEOFException();
|
throwEOFException();
|
||||||
|
|
||||||
// write block end marker (uncompressed size 0)
|
// 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
|
// update header with totals
|
||||||
ph.u_len = total_in;
|
ph.u_len = total_in;
|
||||||
ph.c_len = total_out;
|
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
|
// write packheader
|
||||||
writePackHeader(fo);
|
writePackHeader(fo);
|
||||||
|
|
||||||
@@ -408,6 +360,8 @@ void PackLinuxI386elf::pack(OutputFile *fo)
|
|||||||
fo->write(obuf, 4);
|
fo->write(obuf, 4);
|
||||||
|
|
||||||
updateLoader(fo);
|
updateLoader(fo);
|
||||||
|
fo->seek(0, SEEK_SET);
|
||||||
|
fo->rewrite(p, lsize);
|
||||||
|
|
||||||
// finally check the compression ratio
|
// finally check the compression ratio
|
||||||
if (!checkFinalCompressionRatio(fo))
|
if (!checkFinalCompressionRatio(fo))
|
||||||
@@ -417,12 +371,16 @@ void PackLinuxI386elf::pack(OutputFile *fo)
|
|||||||
|
|
||||||
void PackLinuxI386elf::unpackExtent(unsigned wanted, OutputFile *fo,
|
void PackLinuxI386elf::unpackExtent(unsigned wanted, OutputFile *fo,
|
||||||
unsigned &total_in, unsigned &total_out,
|
unsigned &total_in, unsigned &total_out,
|
||||||
unsigned &c_adler, unsigned &u_adler)
|
unsigned &c_adler, unsigned &u_adler,
|
||||||
|
bool first_PF_X
|
||||||
|
)
|
||||||
{
|
{
|
||||||
while (wanted) {
|
while (wanted) {
|
||||||
fi->readx(ibuf, 8);
|
fi->readx(ibuf, 8);
|
||||||
int const sz_unc = ph.u_len = get_native32(ibuf+0);
|
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
|
if (sz_unc == 0) { // must never happen while 0!=wanted
|
||||||
throwCompressedDataViolation();
|
throwCompressedDataViolation();
|
||||||
@@ -441,6 +399,15 @@ void PackLinuxI386elf::unpackExtent(unsigned wanted, OutputFile *fo,
|
|||||||
if (sz_cpr < sz_unc)
|
if (sz_cpr < sz_unc)
|
||||||
{
|
{
|
||||||
decompress(ibuf+j, ibuf, false);
|
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;
|
j = 0;
|
||||||
}
|
}
|
||||||
// update checksum of uncompressed data
|
// update checksum of uncompressed data
|
||||||
@@ -473,7 +440,9 @@ void PackLinuxI386elf::unpack(OutputFile *fo)
|
|||||||
ibuf.alloc(blocksize + OVERHEAD);
|
ibuf.alloc(blocksize + OVERHEAD);
|
||||||
fi->readx(ibuf, 2*4);
|
fi->readx(ibuf, 2*4);
|
||||||
ph.u_len = get_native32(0+ibuf);
|
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.
|
// Uncompress Ehdr and Phdrs.
|
||||||
fi->readx(ibuf, ph.c_len);
|
fi->readx(ibuf, ph.c_len);
|
||||||
@@ -486,6 +455,7 @@ void PackLinuxI386elf::unpack(OutputFile *fo)
|
|||||||
off_t ptload0hi=0, ptload1lo=0;
|
off_t ptload0hi=0, ptload1lo=0;
|
||||||
|
|
||||||
// decompress PT_LOAD
|
// decompress PT_LOAD
|
||||||
|
bool first_PF_X = true;
|
||||||
fi->seek(- (off_t) (2*4 + ph.c_len), SEEK_CUR);
|
fi->seek(- (off_t) (2*4 + ph.c_len), SEEK_CUR);
|
||||||
for (unsigned j=0; j < ehdr->e_phnum; ++phdr, ++j) {
|
for (unsigned j=0; j < ehdr->e_phnum; ++phdr, ++j) {
|
||||||
if (PT_LOAD==phdr->p_type) {
|
if (PT_LOAD==phdr->p_type) {
|
||||||
@@ -497,19 +467,29 @@ void PackLinuxI386elf::unpack(OutputFile *fo)
|
|||||||
}
|
}
|
||||||
if (fo)
|
if (fo)
|
||||||
fo->seek(phdr->p_offset, SEEK_SET);
|
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 (ptload0hi < ptload1lo) { // alignment hole?
|
||||||
if (fo)
|
if (fo)
|
||||||
fo->seek(ptload0hi, SEEK_SET);
|
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 (total_out != orig_file_size) { // non-PT_LOAD stuff
|
||||||
if (fo)
|
if (fo)
|
||||||
fo->seek(0, SEEK_END);
|
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
|
// check for end-of-file
|
||||||
|
|||||||
+4
-3
@@ -59,15 +59,17 @@ protected:
|
|||||||
off_t offset;
|
off_t offset;
|
||||||
off_t size;
|
off_t size;
|
||||||
};
|
};
|
||||||
virtual void packExtent(Extent const &x, OutputFile *fo,
|
virtual void packExtent(Extent const &x,
|
||||||
unsigned &total_in, unsigned &total_out, Filter *);
|
unsigned &total_in, unsigned &total_out, Filter *);
|
||||||
virtual void unpackExtent(unsigned wanted, OutputFile *fo,
|
virtual void unpackExtent(unsigned wanted, OutputFile *fo,
|
||||||
unsigned &total_in, unsigned &total_out,
|
unsigned &total_in, unsigned &total_out,
|
||||||
unsigned &c_adler, unsigned &u_adler);
|
unsigned &c_adler, unsigned &u_adler, bool first_PF_X);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
#if 0 //{
|
||||||
virtual const upx_byte *getLoader() const;
|
virtual const upx_byte *getLoader() const;
|
||||||
virtual int getLoaderSize() const;
|
virtual int getLoaderSize() const;
|
||||||
|
#endif //}
|
||||||
|
|
||||||
virtual void patchLoader();
|
virtual void patchLoader();
|
||||||
virtual void updateLoader(OutputFile *);
|
virtual void updateLoader(OutputFile *);
|
||||||
@@ -75,7 +77,6 @@ protected:
|
|||||||
Elf_LE32_Ehdr ehdri; // from input file
|
Elf_LE32_Ehdr ehdri; // from input file
|
||||||
Elf_LE32_Phdr *phdri; // for input file
|
Elf_LE32_Phdr *phdri; // for input file
|
||||||
|
|
||||||
unsigned n_mru;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+199
-71
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
Copyright (C) 1996-2001 Markus Franz Xaver Johannes Oberhumer
|
Copyright (C) 1996-2001 Markus Franz Xaver Johannes Oberhumer
|
||||||
Copyright (C) 1996-2001 Laszlo Molnar
|
Copyright (C) 1996-2001 Laszlo Molnar
|
||||||
|
Copyright (C) 2001 John F. Reiser
|
||||||
All Rights Reserved.
|
All Rights Reserved.
|
||||||
|
|
||||||
UPX and the UCL library are free software; you can redistribute them
|
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.,
|
If not, write to the Free Software Foundation, Inc.,
|
||||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
Markus F.X.J. Oberhumer Laszlo Molnar
|
Markus F.X.J. Oberhumer Laszlo Molnar John F. Reiser
|
||||||
markus@oberhumer.com ml1050@cdata.tvnet.hu
|
markus@oberhumer.com ml1050@cdata.tvnet.hu jreiser@BitWagon.com
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
|
#include "filter.h"
|
||||||
|
#include "linker.h"
|
||||||
#include "packer.h"
|
#include "packer.h"
|
||||||
#include "p_elf.h"
|
#include "p_elf.h"
|
||||||
#include "p_unix.h"
|
#include "p_unix.h"
|
||||||
@@ -42,9 +45,9 @@
|
|||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
static const
|
static const
|
||||||
#include "stub/l_lx_n2b.h"
|
#include "stub/l_lx_exec86.h"
|
||||||
static const
|
static const
|
||||||
#include "stub/l_lx_n2d.h"
|
#include "stub/fold_exec86.h"
|
||||||
|
|
||||||
|
|
||||||
const int *PackLinuxI386::getCompressionMethods(int method, int level) const
|
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;
|
return m_nrv2d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int const *
|
||||||
const upx_byte *PackLinuxI386::getLoader() const
|
PackLinuxI386::getFilters() const
|
||||||
{
|
{
|
||||||
if (M_IS_NRV2B(ph.method))
|
static const int filters[] = {
|
||||||
return linux_i386exec_nrv2b_loader;
|
0x49, 0x46,
|
||||||
if (M_IS_NRV2D(ph.method))
|
0x83, 0x86, 0x80, 0x84, 0x87, 0x81, 0x82, 0x85,
|
||||||
return linux_i386exec_nrv2d_loader;
|
0x24, 0x16, 0x13, 0x14, 0x11, 0x25, 0x15, 0x12,
|
||||||
return NULL;
|
-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) {
|
initLoader(proto, szproto);
|
||||||
return lsize;
|
|
||||||
|
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);
|
// The beginning of our loader consists of a elf_hdr (52 bytes) and
|
||||||
if (M_IS_NRV2D(ph.method))
|
// two sections elf_phdr (2 * 32 byte), so we have 12 free bytes
|
||||||
return sizeof(linux_i386exec_nrv2d_loader);
|
// from offset 116 to the program start at offset 128.
|
||||||
return 0;
|
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
|
int PackLinuxI386::getLoaderPrefixSize() const
|
||||||
{
|
{
|
||||||
@@ -198,58 +368,13 @@ bool PackLinuxI386::canPack()
|
|||||||
|
|
||||||
void PackLinuxI386::patchLoader()
|
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()
|
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
|
// checksum for loader + p_info
|
||||||
lp->l_checksum = 0;
|
lp->l_checksum = 0;
|
||||||
lp->l_magic = UPX_ELF_MAGIC;
|
lp->l_magic = UPX_ELF_MAGIC;
|
||||||
@@ -258,7 +383,7 @@ void PackLinuxI386::patchLoaderChecksum()
|
|||||||
lp->l_format = (unsigned char) ph.format;
|
lp->l_format = (unsigned char) ph.format;
|
||||||
// INFO: lp->l_checksum is currently unused
|
// INFO: lp->l_checksum is currently unused
|
||||||
unsigned adler = upx_adler32(0,NULL,0);
|
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;
|
lp->l_checksum = adler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,13 +391,18 @@ void PackLinuxI386::patchLoaderChecksum()
|
|||||||
void PackLinuxI386::updateLoader(OutputFile *fo)
|
void PackLinuxI386::updateLoader(OutputFile *fo)
|
||||||
{
|
{
|
||||||
#define PAGE_MASK (~0<<12)
|
#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;
|
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 first Phdr maps the stub (instructions, data, bss) rwx.
|
||||||
// The second Phdr maps the overlay r--,
|
// The second Phdr maps the overlay r--,
|
||||||
// to defend against /usr/bin/strip removing the overlay.
|
// 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_type = PT_LOAD;
|
||||||
phdro->p_offset = lsize;
|
phdro->p_offset = lsize;
|
||||||
@@ -282,8 +412,6 @@ void PackLinuxI386::updateLoader(OutputFile *fo)
|
|||||||
phdro->p_align = (unsigned) (-PAGE_MASK);
|
phdro->p_align = (unsigned) (-PAGE_MASK);
|
||||||
|
|
||||||
patchLoaderChecksum();
|
patchLoaderChecksum();
|
||||||
fo->seek(0, SEEK_SET);
|
|
||||||
fo->rewrite(loader, 0x80);
|
|
||||||
#undef PAGE_MASK
|
#undef PAGE_MASK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-2
@@ -42,14 +42,28 @@ public:
|
|||||||
virtual int getFormat() const { return UPX_F_LINUX_i386; }
|
virtual int getFormat() const { return UPX_F_LINUX_i386; }
|
||||||
virtual const char *getName() const { return "linux/386"; }
|
virtual const char *getName() const { return "linux/386"; }
|
||||||
virtual const int *getCompressionMethods(int method, int level) const;
|
virtual const int *getCompressionMethods(int method, int level) const;
|
||||||
|
virtual const int *getFilters() const;
|
||||||
|
virtual int buildLoader(const Filter *);
|
||||||
|
|
||||||
virtual bool canPack();
|
virtual bool canPack();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// loader util
|
// loader util
|
||||||
virtual const upx_byte *getLoader() const;
|
|
||||||
virtual int getLoaderSize() const;
|
|
||||||
virtual int getLoaderPrefixSize() 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
|
// patch util
|
||||||
virtual void patchLoader();
|
virtual void patchLoader();
|
||||||
@@ -63,6 +77,8 @@ protected:
|
|||||||
enum {
|
enum {
|
||||||
UPX_ELF_MAGIC = 0x5850557f // "\x7fUPX"
|
UPX_ELF_MAGIC = 0x5850557f // "\x7fUPX"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
unsigned n_mru;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+29
-68
@@ -30,6 +30,7 @@
|
|||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
|
#include "filter.h"
|
||||||
#include "packer.h"
|
#include "packer.h"
|
||||||
#include "p_elf.h"
|
#include "p_elf.h"
|
||||||
#include "p_unix.h"
|
#include "p_unix.h"
|
||||||
@@ -44,9 +45,9 @@
|
|||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
static const
|
static const
|
||||||
#include "stub/l_sh_n2b.h"
|
#include "stub/l_lx_sh86.h"
|
||||||
static const
|
static const
|
||||||
#include "stub/l_sh_n2d.h"
|
#include "stub/fold_sh86.h"
|
||||||
|
|
||||||
|
|
||||||
PackLinuxI386sh::PackLinuxI386sh(InputFile *f) :
|
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))
|
unsigned const sz_fold = sizeof(linux_i386sh_fold);
|
||||||
return linux_i386sh_nrv2b_loader;
|
MemBuffer buf(sz_fold);
|
||||||
if (M_IS_NRV2D(ph.method))
|
memcpy(buf, linux_i386sh_fold, sz_fold);
|
||||||
return linux_i386sh_nrv2d_loader;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int PackLinuxI386sh::getLoaderSize() const
|
checkPatch(0,0,0,0); // reset
|
||||||
{
|
patch_le32(buf,sz_fold,"UPX3",l_shname);
|
||||||
if (0 != lsize) {
|
patch_le32(buf,sz_fold,"UPX2",o_shname);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 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()
|
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);
|
PackUnix::pack(fo);
|
||||||
|
|
||||||
// update loader
|
// 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();
|
off_t const totlen = fo->getBytesWritten();
|
||||||
phdro[0].p_filesz = totlen;
|
phdro[0].p_filesz = totlen;
|
||||||
phdro[0].p_memsz = PAGE_MASK & (~PAGE_MASK + totlen);
|
phdro[0].p_memsz = PAGE_MASK & (~PAGE_MASK + totlen);
|
||||||
@@ -196,7 +157,7 @@ void PackLinuxI386sh::pack(OutputFile *fo)
|
|||||||
|
|
||||||
patchLoaderChecksum();
|
patchLoaderChecksum();
|
||||||
fo->seek(0, SEEK_SET);
|
fo->seek(0, SEEK_SET);
|
||||||
fo->rewrite(loader, 0x80);
|
fo->rewrite(ehdr, sizeof(cprElfhdr));
|
||||||
#undef PAGE_MASK
|
#undef PAGE_MASK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -45,16 +45,16 @@ public:
|
|||||||
virtual int getFormat() const { return UPX_F_LINUX_SH_i386; }
|
virtual int getFormat() const { return UPX_F_LINUX_SH_i386; }
|
||||||
virtual const char *getName() const { return "linux/sh386"; }
|
virtual const char *getName() const { return "linux/sh386"; }
|
||||||
virtual const int *getFilters() const { return NULL; }
|
virtual const int *getFilters() const { return NULL; }
|
||||||
|
virtual int buildLoader(const Filter *);
|
||||||
|
|
||||||
|
virtual void pack(OutputFile *fo);
|
||||||
|
|
||||||
virtual bool canPack();
|
virtual bool canPack();
|
||||||
virtual void pack(OutputFile *fo);
|
|
||||||
// virtual void unpack(OutputFile *fo) { super::unpack(fo); }
|
// virtual void unpack(OutputFile *fo) { super::unpack(fo); }
|
||||||
virtual bool canUnpackVersion(int version) const
|
virtual bool canUnpackVersion(int version) const
|
||||||
{ return (version >= 11); }
|
{ return (version >= 11); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual const upx_byte *getLoader() const;
|
|
||||||
virtual int getLoaderSize() const;
|
|
||||||
virtual bool getShellName(char *buf);
|
virtual bool getShellName(char *buf);
|
||||||
|
|
||||||
virtual void patchLoader();
|
virtual void patchLoader();
|
||||||
|
|||||||
+42
-24
@@ -29,6 +29,7 @@
|
|||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
|
#include "filter.h"
|
||||||
#include "packer.h"
|
#include "packer.h"
|
||||||
#include "p_unix.h"
|
#include "p_unix.h"
|
||||||
#include "p_elf.h"
|
#include "p_elf.h"
|
||||||
@@ -125,22 +126,16 @@ void PackUnix::pack(OutputFile *fo)
|
|||||||
// create a pseudo-unique program id for our paranoid stub
|
// create a pseudo-unique program id for our paranoid stub
|
||||||
progid = getRandomId();
|
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
|
// init compression buffers
|
||||||
ibuf.alloc(blocksize);
|
ibuf.alloc(blocksize);
|
||||||
obuf.allocForCompression(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
|
// compress blocks
|
||||||
unsigned total_in = 0;
|
unsigned total_in = 0;
|
||||||
@@ -148,6 +143,10 @@ void PackUnix::pack(OutputFile *fo)
|
|||||||
ui_total_passes = (file_size + blocksize - 1) / blocksize;
|
ui_total_passes = (file_size + blocksize - 1) / blocksize;
|
||||||
if (ui_total_passes == 1)
|
if (ui_total_passes == 1)
|
||||||
ui_total_passes = 0;
|
ui_total_passes = 0;
|
||||||
|
|
||||||
|
Filter ft(ph.level);
|
||||||
|
ft.addvalue = 0;
|
||||||
|
|
||||||
fi->seek(0, SEEK_SET);
|
fi->seek(0, SEEK_SET);
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@@ -159,9 +158,19 @@ void PackUnix::pack(OutputFile *fo)
|
|||||||
// file is e.g. blocksize + 1 bytes long
|
// file is e.g. blocksize + 1 bytes long
|
||||||
|
|
||||||
// compress
|
// compress
|
||||||
ph.u_len = l;
|
ph.c_len = ph.u_len = l;
|
||||||
ph.overlap_overhead = 0;
|
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)
|
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);
|
ph.c_adler = upx_adler32(ph.c_adler, ibuf, ph.u_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
// write block sizes
|
// update compressed size
|
||||||
unsigned char size[8];
|
set_native32(obuf - 4, ph.c_len);
|
||||||
set_native32(size+0, ph.u_len);
|
|
||||||
set_native32(size+4, ph.c_len);
|
|
||||||
fo->write(size, 8);
|
|
||||||
|
|
||||||
// write compressed data
|
// write compressed data
|
||||||
if (ph.c_len < ph.u_len)
|
if (ph.c_len < ph.u_len)
|
||||||
{
|
{
|
||||||
fo->write(obuf, ph.c_len);
|
obuf.write(obuf, ph.c_len);
|
||||||
verifyOverlappingDecompression();
|
// FIXME: obuf is not discardable!
|
||||||
|
// verifyOverlappingDecompression();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fo->write(ibuf, ph.u_len);
|
obuf.write(ibuf, ph.u_len);
|
||||||
|
|
||||||
total_in += ph.u_len;
|
total_in += ph.u_len;
|
||||||
total_out += ph.c_len;
|
total_out += ph.c_len;
|
||||||
@@ -199,12 +206,21 @@ void PackUnix::pack(OutputFile *fo)
|
|||||||
throwEOFException();
|
throwEOFException();
|
||||||
|
|
||||||
// write block end marker (uncompressed size 0)
|
// 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
|
// update header with totals
|
||||||
ph.u_len = total_in;
|
ph.u_len = total_in;
|
||||||
ph.c_len = total_out;
|
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
|
// write packheader
|
||||||
writePackHeader(fo);
|
writePackHeader(fo);
|
||||||
|
|
||||||
@@ -213,6 +229,8 @@ void PackUnix::pack(OutputFile *fo)
|
|||||||
fo->write(obuf, 4);
|
fo->write(obuf, 4);
|
||||||
|
|
||||||
updateLoader(fo);
|
updateLoader(fo);
|
||||||
|
fo->seek(0, SEEK_SET);
|
||||||
|
fo->rewrite(p, lsize);
|
||||||
|
|
||||||
// finally check the compression ratio
|
// finally check the compression ratio
|
||||||
if (!checkFinalCompressionRatio(fo))
|
if (!checkFinalCompressionRatio(fo))
|
||||||
|
|||||||
+280
-22
@@ -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)
|
void Packer::addFilter32(int filter_id)
|
||||||
{
|
{
|
||||||
assert(filter_id > 0);
|
assert(filter_id > 0);
|
||||||
assert(isValidFilter(filter_id));
|
assert(isValidFilter(filter_id));
|
||||||
|
|
||||||
if ((filter_id & 0xf) % 3 == 0)
|
if (filter_id < 0x80) {
|
||||||
addLoader("CALLTR00",
|
if ((filter_id & 0xf) % 3 == 0) {
|
||||||
(filter_id > 0x20) ? "CTCLEVE1" : "",
|
if (filter_id < 0x40) {
|
||||||
"CALLTR01",
|
addLoader("CALLTR00",
|
||||||
(filter_id & 0xf) > 3 ? (filter_id > 0x20 ? "CTBSHR01""CTBSWA01" : "CTBROR01""CTBSWA01") : "",
|
(filter_id > 0x20) ? "CTCLEVE1" : "",
|
||||||
"CALLTR02",
|
"CALLTR01",
|
||||||
NULL
|
(filter_id & 0xf) > 3 ? (filter_id > 0x20 ? "CTBSHR01""CTBSWA01" : "CTBROR01""CTBSWA01") : "",
|
||||||
);
|
"CALLTR02",
|
||||||
else
|
NULL
|
||||||
addLoader("CALLTR10",
|
);
|
||||||
(filter_id & 0xf) % 3 == 1 ? "CALLTRE8" : "CALLTRE9",
|
}
|
||||||
"CALLTR11",
|
else if (0x40==(0xF0 & filter_id)) {
|
||||||
(filter_id > 0x20) ? "CTCLEVE2" : "",
|
addLoader("CKLLTR00", 0);
|
||||||
"CALLTR12",
|
if (9<=(0xf & filter_id)) {
|
||||||
(filter_id & 0xf) > 3 ? (filter_id > 0x20 ? "CTBSHR11""CTBSWA11" : "CTBROR11""CTBSWA11") : "",
|
addLoader("CKLLTR10", 0);
|
||||||
"CALLTR13",
|
}
|
||||||
NULL
|
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);
|
ft.init(ph.filter, orig_ft.addvalue);
|
||||||
// filter
|
// filter
|
||||||
optimizeFilter(&ft, ibuf + filter_off, filter_len);
|
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);
|
bool success = ft.filter(ibuf + filter_off, filter_len);
|
||||||
if (ft.id != 0 && ft.calls == 0)
|
if (ft.id != 0 && ft.calls == 0)
|
||||||
{
|
{
|
||||||
@@ -1251,6 +1485,7 @@ void Packer::compressWithFilters(Filter *parm_ft,
|
|||||||
}
|
}
|
||||||
nfilters_success++;
|
nfilters_success++;
|
||||||
ph.filter_cto = ft.cto;
|
ph.filter_cto = ft.cto;
|
||||||
|
ph.n_mru = ft.n_mru;
|
||||||
// compress
|
// compress
|
||||||
if (compress(ibuf + compress_buf_off, otemp, max_offset, max_match))
|
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
|
// restore ibuf[] - unfilter with verify
|
||||||
ft.unfilter(ibuf + filter_off, filter_len, true);
|
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)
|
if (strategy < 0)
|
||||||
break;
|
break;
|
||||||
@@ -1305,6 +1545,7 @@ void Packer::compressWithFilters(Filter *parm_ft,
|
|||||||
assert(best_ph.u_len == orig_ph.u_len);
|
assert(best_ph.u_len == orig_ph.u_len);
|
||||||
assert(best_ph.filter == best_ft.id);
|
assert(best_ph.filter == best_ft.id);
|
||||||
assert(best_ph.filter_cto == best_ft.cto);
|
assert(best_ph.filter_cto == best_ft.cto);
|
||||||
|
// FIXME assert(best_ph.n_mru == best_ft.n_mru);
|
||||||
|
|
||||||
// copy back results
|
// copy back results
|
||||||
this->ph = best_ph;
|
this->ph = best_ph;
|
||||||
@@ -1396,10 +1637,27 @@ bool Packer::patchFilter32(void *loader, int lsize, const Filter *ft)
|
|||||||
if (ft->id == 0)
|
if (ft->id == 0)
|
||||||
return false;
|
return false;
|
||||||
assert(ft->calls > 0);
|
assert(ft->calls > 0);
|
||||||
if (ft->id > 0x20)
|
if (ft->id < 0x80) {
|
||||||
patch_le16(loader, lsize, "??", '?' + (ft->cto << 8));
|
if (0x40 <= ft->id && ft->id < 0x50 && UPX_F_LINUX_i386==ph.format) {
|
||||||
patch_le32(loader, lsize, "TEXL", (ft->id & 0xf) % 3 == 0 ? ft->calls :
|
// "push byte '?'"
|
||||||
ft->lastcall - ft->calls * 4);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-3
@@ -74,6 +74,7 @@ public:
|
|||||||
int filter;
|
int filter;
|
||||||
int filter_cto;
|
int filter_cto;
|
||||||
int header_checksum;
|
int header_checksum;
|
||||||
|
int n_mru;
|
||||||
|
|
||||||
//
|
//
|
||||||
unsigned saved_u_adler;
|
unsigned saved_u_adler;
|
||||||
@@ -250,15 +251,15 @@ protected:
|
|||||||
int ph_version;
|
int ph_version;
|
||||||
|
|
||||||
// compression buffers
|
// compression buffers
|
||||||
MemBuffer ibuf; // input
|
MemBuffer ibuf; // input
|
||||||
MemBuffer obuf; // output
|
MemBufferIO obuf; // output
|
||||||
|
|
||||||
// UI handler
|
// UI handler
|
||||||
UiPacker *uip;
|
UiPacker *uip;
|
||||||
int ui_pass;
|
int ui_pass;
|
||||||
int ui_total_passes;
|
int ui_total_passes;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
// linker
|
// linker
|
||||||
Linker *linker;
|
Linker *linker;
|
||||||
|
|
||||||
|
|||||||
+6
-2
@@ -150,7 +150,8 @@ void PackHeader::putPackHeader(upx_bytep p)
|
|||||||
set_le32(p+24,u_file_size);
|
set_le32(p+24,u_file_size);
|
||||||
p[28] = (unsigned char) filter;
|
p[28] = (unsigned char) filter;
|
||||||
p[29] = (unsigned char) filter_cto;
|
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+8,u_adler);
|
||||||
set_le32(p+12,c_adler);
|
set_le32(p+12,c_adler);
|
||||||
@@ -166,7 +167,8 @@ void PackHeader::putPackHeader(upx_bytep p)
|
|||||||
set_be32(p+24,u_file_size);
|
set_be32(p+24,u_file_size);
|
||||||
p[28] = (unsigned char) filter;
|
p[28] = (unsigned char) filter;
|
||||||
p[29] = (unsigned char) filter_cto;
|
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;
|
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);
|
u_file_size = get_le32(p+24);
|
||||||
off_filter = 28;
|
off_filter = 28;
|
||||||
filter_cto = p[29];
|
filter_cto = p[29];
|
||||||
|
n_mru = p[30] ? 1+ p[30] : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -257,6 +260,7 @@ bool PackHeader::fillPackHeader(const upx_bytep buf, int blen)
|
|||||||
u_file_size = get_be32(p+24);
|
u_file_size = get_be32(p+24);
|
||||||
off_filter = 28;
|
off_filter = 28;
|
||||||
filter_cto = p[29];
|
filter_cto = p[29];
|
||||||
|
n_mru = p[30] ? 1+ p[30] : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version >= 10)
|
if (version >= 10)
|
||||||
|
|||||||
+58
-72
@@ -31,9 +31,10 @@ STUBS = \
|
|||||||
l_tmt.h \
|
l_tmt.h \
|
||||||
l_wcle.h \
|
l_wcle.h \
|
||||||
l_w32pe.h \
|
l_w32pe.h \
|
||||||
l_lx_n2b.h l_lx_n2d.h \
|
l_lx_exec86.h fold_exec86.h \
|
||||||
l_le_n2b.h l_le_n2d.h \
|
l_lx_elf86.h fold_elf86.h \
|
||||||
l_sh_n2b.h l_sh_n2d.h \
|
l_lx_sh86.h fold_sh86.h \
|
||||||
|
l_ext2.h \
|
||||||
l_vmlinz.h
|
l_vmlinz.h
|
||||||
|
|
||||||
# experimental:
|
# experimental:
|
||||||
@@ -80,7 +81,7 @@ STRIPELF = ./util/sstrip/sstrip
|
|||||||
|
|
||||||
# Use gcc 2.95.2 for smallest code.
|
# Use gcc 2.95.2 for smallest code.
|
||||||
CC_LINUX_CFLAGS = -Wall -W -Wcast-align -Wcast-qual -Wwrite-strings
|
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 += -funsigned-char
|
||||||
###CC_LINUX_CFLAGS += -fwritable-strings -save-temps
|
###CC_LINUX_CFLAGS += -fwritable-strings -save-temps
|
||||||
CC_LINUX = gcc272 -O2 -m386 -malign-functions=0 -malign-jumps=0 -malign-loops=0 $(CC_LINUX_CFLAGS)
|
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 $<
|
$(NASM) -f bin -o $T.bin $<
|
||||||
$(BIN2H) $T.bin nrv_loader $@
|
$(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
|
l_vmlinz.h: l_vmlinz.asx
|
||||||
$(NASM) -f bin -o $T.bin $<
|
$(NASM) -f bin -o $T.bin $<
|
||||||
$(BIN2H) $T.bin nrv_loader $@
|
$(BIN2H) $T.bin nrv_loader $@
|
||||||
@@ -249,66 +254,56 @@ l_t_x2ds.h: l_tos2.s
|
|||||||
# // linux rules (exec, elf, sh, sep)
|
# // linux rules (exec, elf, sh, sep)
|
||||||
# ************************************************************************/
|
# ************************************************************************/
|
||||||
|
|
||||||
l_lx_n2b.h: l_lx_exec.c l_xe_n2b.o l_lx_exec86.lds Makefile
|
l_lx_elf86.h: l_lx_elf86.asx
|
||||||
$(CC_LINUX) -DNRV2B -o $T.o -c $<
|
$(NASM) -f bin -o $T.bin $<
|
||||||
ld -T $(srcdir)/l_lx_exec86.lds -Map $T.map -o $T.bin l_xe_n2b.o $T.o
|
$(BIN2H) $T.bin linux_i386elf_loader $@
|
||||||
$(SETFOLD) $T.bin
|
|
||||||
|
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
|
$(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
|
l_lx_exec.o: l_lx_exec.c
|
||||||
$(CC_LINUX) -DNRV2B -o $T.o -c $<
|
$(CC_LINUX) -c $<
|
||||||
ld -T $(srcdir)/l_lx_elf86.lds -Map $T.map -o $T.bin l_6e_n2b.o $T.o
|
|
||||||
$(SETFOLD) $T.bin
|
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
|
$(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
|
l_lx_sh.o: l_lx_sh.c
|
||||||
$(CC_LINUX) -DNRV2B -o $T.o -c $<
|
$(CC_LINUX) -c $<
|
||||||
ld -T $(srcdir)/l_lx_sh86.lds -Map $T.map -o $T.bin l_6h_n2b.o $T.o
|
|
||||||
$(SETFOLD) $T.bin
|
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
|
$(BRANDELF) $T.bin
|
||||||
$(BIN2H) $T.bin linux_i386sh_nrv2b_loader $@
|
$(BIN2H) $T.bin linux_i386sh_fold $@
|
||||||
|
|
||||||
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 $@ $<
|
|
||||||
|
|
||||||
l_lx_sep.o: l_lx_sep.c
|
l_lx_sep.o: l_lx_sep.c
|
||||||
$(CC_LINUX) -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_n2d.h: n2d_d.ash bits.ash $(DEPS1)
|
||||||
l_t_n2ds.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_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_vmlinz.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
|
||||||
l_vxd.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_wcle.h: n2b_d32.asy n2d_d32.asy $(DEPS2)
|
||||||
l_w32pe.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_lx_elf86.asx: l_lx_elf86.asm macros.ash macros.asy
|
||||||
l_6e_n2b.o: n2b_d32.ash $(DEPS1)
|
l_lx_exec86.asx: l_lx_exec86.asm macros.ash macros.asy
|
||||||
l_6h_n2b.o: n2b_d32.ash $(DEPS1)
|
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
|
upxb: linux.hh
|
||||||
upxd: linux.hh
|
upxd: linux.hh
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
+17
-5
@@ -102,7 +102,11 @@ do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
|
|||||||
// UPX & NRV stuff
|
// UPX & NRV stuff
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
typedef void f_unfilter(nrv_byte *, nrv_uint); // 1st param is also addvalue
|
typedef void f_unfilter(
|
||||||
|
nrv_byte *, // also addvalue
|
||||||
|
nrv_uint,
|
||||||
|
unsigned cto8 // junk in high 24 bits
|
||||||
|
);
|
||||||
typedef int f_expand(
|
typedef int f_expand(
|
||||||
const nrv_byte *, nrv_uint,
|
const nrv_byte *, nrv_uint,
|
||||||
nrv_byte *, nrv_uint * );
|
nrv_byte *, nrv_uint * );
|
||||||
@@ -116,6 +120,7 @@ unpackExtent(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
while (xo->size) {
|
while (xo->size) {
|
||||||
|
unsigned cto8;
|
||||||
struct {
|
struct {
|
||||||
int32_t sz_unc; // uncompressed
|
int32_t sz_unc; // uncompressed
|
||||||
int32_t sz_cpr; // compressed
|
int32_t sz_cpr; // compressed
|
||||||
@@ -125,6 +130,8 @@ unpackExtent(
|
|||||||
|
|
||||||
// Read and check block sizes.
|
// Read and check block sizes.
|
||||||
xread(xi, (char *)&h, sizeof(h));
|
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_unc == 0) { // uncompressed size 0 -> EOF
|
||||||
if (h.sz_cpr != UPX_MAGIC_LE32) // h.sz_cpr must be h->magic
|
if (h.sz_cpr != UPX_MAGIC_LE32) // h.sz_cpr must be h->magic
|
||||||
err_exit(2);
|
err_exit(2);
|
||||||
@@ -155,7 +162,7 @@ ERR_LAB
|
|||||||
&& ((512 < out_len) // this block is longer than Ehdr+Phdrs
|
&& ((512 < out_len) // this block is longer than Ehdr+Phdrs
|
||||||
|| (xo->size==(unsigned)h.sz_unc) ) // block is last in Extent
|
|| (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->buf += h.sz_cpr;
|
||||||
xi->size -= 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]
|
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_Phdr const *phdr = (Elf32_Phdr const *)(1+ehdr);
|
||||||
Elf32_Addr entry;
|
Elf32_Addr entry;
|
||||||
struct Extent xo;
|
struct Extent xo;
|
||||||
struct Extent xi = { 0, sizeof(struct p_info) + lsize + CONST_CAST(char *, my_ehdr) };
|
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_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_pckhdrs = ((size_t *)xi.buf)[1]>>8; // sizeof(Ehdr+Phdrs), compressed
|
||||||
|
|
||||||
(void)uncbuf; // used by l_lx_sh.c
|
(void)uncbuf; // used by l_lx_sh.c
|
||||||
// Uncompress Ehdr and Phdrs.
|
// Uncompress Ehdr and Phdrs.
|
||||||
|
|||||||
+21
-327
@@ -33,42 +33,13 @@
|
|||||||
%define jmps jmp short
|
%define jmps jmp short
|
||||||
%define jmpn jmp near
|
%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
|
; // program entry point
|
||||||
; // see glibc/sysdeps/i386/elf/start.S
|
; // see glibc/sysdeps/i386/elf/start.S
|
||||||
; **************************************************************************/
|
; **************************************************************************/
|
||||||
|
|
||||||
GLOBAL _start
|
GLOBAL _start
|
||||||
|
;__LEXEC000__
|
||||||
_start:
|
_start:
|
||||||
;;;; int3
|
;;;; int3
|
||||||
;; How to debug this code: Uncomment the 'int3' breakpoint instruction above.
|
;; How to debug this code: Uncomment the 'int3' breakpoint instruction above.
|
||||||
@@ -89,27 +60,6 @@ _start:
|
|||||||
;;
|
;;
|
||||||
call main ; push address of decompress subroutine
|
call main ; push address of decompress subroutine
|
||||||
decompress:
|
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
|
; // C callable decompressor
|
||||||
@@ -120,7 +70,9 @@ decompress:
|
|||||||
%define OUTP dword [esp+8*4+12]
|
%define OUTP dword [esp+8*4+12]
|
||||||
%define OUTS dword [esp+8*4+16]
|
%define OUTS dword [esp+8*4+16]
|
||||||
|
|
||||||
decompr0:
|
;__LEXEC009__
|
||||||
|
;; empty section for commonality with l_lx_exec86.asm
|
||||||
|
;__LEXEC010__
|
||||||
pusha
|
pusha
|
||||||
; cld
|
; cld
|
||||||
|
|
||||||
@@ -129,15 +81,13 @@ decompr0:
|
|||||||
|
|
||||||
or ebp, byte -1
|
or ebp, byte -1
|
||||||
;;; align 8
|
;;; 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
|
; eax is 0 from decompressor code
|
||||||
;xor eax, eax ; return code
|
;xor eax, eax ; return code
|
||||||
|
|
||||||
@@ -158,191 +108,17 @@ decompr0:
|
|||||||
popa
|
popa
|
||||||
ret
|
ret
|
||||||
|
|
||||||
;__LXUNF020__
|
ctojr32
|
||||||
;; continuation of entry prolog for unfilter
|
ckt32 dl
|
||||||
unf0:
|
;__LEXEC017__
|
||||||
;__LXMRU020__
|
popa
|
||||||
push edx ; tail
|
ret
|
||||||
push ebx ; n_mru or n_mru1
|
|
||||||
;__LXUNF025__
|
|
||||||
mov esi, esp
|
|
||||||
|
|
||||||
%define n_mru [esi]
|
;__LEXEC020__
|
||||||
%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__
|
|
||||||
|
|
||||||
%define PAGE_MASK (~0<<12)
|
%define PAGE_MASK (~0<<12)
|
||||||
%define PAGE_SIZE ( 1<<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_FIXED 0x10
|
||||||
%define MAP_PRIVATE 0x02
|
%define MAP_PRIVATE 0x02
|
||||||
%define MAP_ANONYMOUS 0x20
|
%define MAP_ANONYMOUS 0x20
|
||||||
@@ -366,7 +142,7 @@ unfold:
|
|||||||
push eax ; &destination
|
push eax ; &destination
|
||||||
|
|
||||||
; mmap a page to hold the decompressed program
|
; mmap a page to hold the decompressed program
|
||||||
xor ecx,ecx
|
xor ecx, ecx
|
||||||
push ecx
|
push ecx
|
||||||
push ecx
|
push ecx
|
||||||
mov ch, PAGE_SIZE >> 8
|
mov ch, PAGE_SIZE >> 8
|
||||||
@@ -390,94 +166,12 @@ unfold:
|
|||||||
main:
|
main:
|
||||||
pop ebp ; &decompress
|
pop ebp ; &decompress
|
||||||
call unfold
|
call unfold
|
||||||
fold_begin:
|
|
||||||
; patchLoader will modify to be
|
|
||||||
; dword sz_uncompressed, sz_compressed
|
|
||||||
; byte compressed_data...
|
|
||||||
|
|
||||||
pop eax ; discard &sz_uncompressed
|
eof:
|
||||||
pop eax ; discard sz_uncompressed
|
; __XTHEENDX__
|
||||||
|
section .data
|
||||||
; Move argc,argv,envp down so that we can insert more Elf_auxv entries.
|
dd -1
|
||||||
; ld-linux.so.2 depends on AT_PHDR and AT_ENTRY, for instance
|
dw eof
|
||||||
|
|
||||||
%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
|
; vi:ts=8:et:nowrap
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||||
OUTPUT_ARCH(i386)
|
OUTPUT_ARCH(i386)
|
||||||
ENTRY(_start)
|
/*ENTRY(_start)*/
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
/* 0x00401000: l_lx_elf86.asm assumes 1 page up from 64KB boundary */
|
/* 0x00401000: l_lx_elf86.asm assumes 1 page up from 64KB boundary */
|
||||||
|
|||||||
+86
-86
@@ -101,12 +101,19 @@ static uint32_t ascii5(char *p, uint32_t v, unsigned n)
|
|||||||
do {
|
do {
|
||||||
unsigned char d = v % 32;
|
unsigned char d = v % 32;
|
||||||
if (d >= 26) d -= 43; // 43 == 'Z' - '0' + 1
|
if (d >= 26) d -= 43; // 43 == 'Z' - '0' + 1
|
||||||
*--p += d;
|
*--p = (d += 'A');
|
||||||
v /= 32;
|
v /= 32;
|
||||||
} while (--n > 0);
|
} while (--n > 0);
|
||||||
return v;
|
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__)
|
#if defined(__i386__)
|
||||||
# define SET2(p, c0, c1) \
|
# define SET2(p, c0, c1) \
|
||||||
@@ -125,6 +132,51 @@ static uint32_t ascii5(char *p, uint32_t v, unsigned n)
|
|||||||
#endif
|
#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
|
// UPX & NRV stuff
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
@@ -153,59 +205,29 @@ void upx_main(
|
|||||||
f_expand *const f_decompress
|
f_expand *const f_decompress
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// file descriptors
|
// file descriptor
|
||||||
int fdi, fdo;
|
int 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;
|
|
||||||
|
|
||||||
// decompression buffer
|
// decompression buffer
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
static struct MallocArgs {
|
|
||||||
char *ma_addr;
|
char *tmpname;
|
||||||
size_t ma_length;
|
|
||||||
int ma_prot;
|
Elf32_Phdr const *const phdr = (Elf32_Phdr const *)
|
||||||
int ma_flags;
|
(my_ehdr->e_phoff + (char const *)my_ehdr);
|
||||||
int ma_fd;
|
struct Extent xi = { phdr[1].p_memsz, (char *)phdr[1].p_vaddr };
|
||||||
off_t ma_offset;
|
|
||||||
} malloc_args = {
|
char *next_unmap = (char *)(PAGE_MASK & (unsigned)xi.buf);
|
||||||
#if defined(USE_MMAP_FO)
|
struct p_info header;
|
||||||
0, 0, PROT_READ | PROT_WRITE, MAP_SHARED, 0, 0
|
|
||||||
#else
|
// temporary file name
|
||||||
0, 0, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0
|
char tmpname_buf[20];
|
||||||
#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
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// ----- Step 0: set /proc/self using /proc/<pid> -----
|
// ----- Step 0: set /proc/self using /proc/<pid> -----
|
||||||
//
|
//
|
||||||
|
|
||||||
//personality(PER_LINUX);
|
//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
|
// Paranoia. Make sure this is actually our expected executable
|
||||||
// by checking the random program id. (The id is both stored
|
// by checking the random program id. (The id is both stored
|
||||||
// in the header and patched into this stub.)
|
// in the header and patched into this stub.)
|
||||||
if (header.p_progid != UPX2)
|
if (header.p_progid != UPX3)
|
||||||
goto error1;
|
goto error1;
|
||||||
|
|
||||||
|
|
||||||
@@ -234,13 +256,17 @@ void upx_main(
|
|||||||
// ----- Step 2: prepare temporary output file -----
|
// ----- 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[].
|
// Compute name of temporary output file in tmpname[].
|
||||||
// Protect against Denial-of-Service attacks.
|
// Protect against Denial-of-Service attacks.
|
||||||
{
|
{
|
||||||
char *p = tmpname_buf + sizeof(tmpname_buf) - 1;
|
char *p = tmpname_buf + sizeof(tmpname_buf) - 1;
|
||||||
|
|
||||||
// Compute the last 4 characters (20 bits) from getpid().
|
// Compute the last 4 characters (20 bits) from getpid().
|
||||||
uint32_t r = ascii5(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.
|
// Provide 4 random bytes from our program id.
|
||||||
r ^= header.p_progid;
|
r ^= header.p_progid;
|
||||||
@@ -254,7 +280,7 @@ void upx_main(
|
|||||||
r ^= ((uint32_t) tv.tv_usec) << 12; // shift into high-bits
|
r ^= ((uint32_t) tv.tv_usec) << 12; // shift into high-bits
|
||||||
#else
|
#else
|
||||||
// using adjtimex() may cause portability problems
|
// using adjtimex() may cause portability problems
|
||||||
static struct timex tx;
|
struct timex tx;
|
||||||
adjtimex(&tx);
|
adjtimex(&tx);
|
||||||
r ^= (uint32_t) tx.time.tv_sec;
|
r ^= (uint32_t) tx.time.tv_sec;
|
||||||
r ^= ((uint32_t) tx.time.tv_usec) << 12; // shift into high-bits
|
r ^= ((uint32_t) tx.time.tv_usec) << 12; // shift into high-bits
|
||||||
@@ -294,23 +320,23 @@ void upx_main(
|
|||||||
//
|
//
|
||||||
|
|
||||||
#if defined(USE_MMAP_FO)
|
#if defined(USE_MMAP_FO)
|
||||||
// mmap()ed output file.
|
// FIXME: packer could set length
|
||||||
malloc_args.ma_fd = fdo;
|
buf = do_mmap(0, header.p_filesize,
|
||||||
// FIXME: packer could set ma_length
|
PROT_READ | PROT_WRITE, MAP_SHARED, fdo, 0);
|
||||||
malloc_args.ma_length = header.p_filesize;
|
|
||||||
buf = mmap((int *)&malloc_args);
|
|
||||||
if ((unsigned long) buf >= (unsigned long) -4095)
|
if ((unsigned long) buf >= (unsigned long) -4095)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
// Decompressor can overrun the output by 3 bytes.
|
// Decompressor can overrun the output by 3 bytes.
|
||||||
// Defend against SIGSEGV by using a scratch page.
|
// Defend against SIGSEGV by using a scratch page.
|
||||||
scratch_page.ma_addr = buf + (PAGE_MASK & (header.p_filesize + ~PAGE_MASK));
|
// FIXME: packer could set address delta
|
||||||
mmap((int *)&scratch_page);
|
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
|
#else
|
||||||
// Temporary decompression buffer.
|
// Temporary decompression buffer.
|
||||||
// FIXME: packer could set ma_length
|
// FIXME: packer could set length
|
||||||
malloc_args.ma_length = (header.p_blocksize + OVERHEAD + ~PAGE_MASK) & PAGE_MASK;
|
buf = do_mmap(0, (header.p_blocksize + OVERHEAD + ~PAGE_MASK) & PAGE_MASK,
|
||||||
buf = mmap((int *)&malloc_args);
|
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 );
|
||||||
if ((unsigned long) buf >= (unsigned long) -4095)
|
if ((unsigned long) buf >= (unsigned long) -4095)
|
||||||
goto error;
|
goto error;
|
||||||
#endif
|
#endif
|
||||||
@@ -429,34 +455,9 @@ void upx_main(
|
|||||||
// Many thanks to Andi Kleen <ak@muc.de> and
|
// Many thanks to Andi Kleen <ak@muc.de> and
|
||||||
// Jamie Lokier <nospam@cern.ch> for this nice idea.
|
// Jamie Lokier <nospam@cern.ch> for this nice idea.
|
||||||
|
|
||||||
// Open the temp file.
|
if (0 > go_self(tmpname, argv, envp))
|
||||||
fdi = open(tmpname, O_RDONLY, 0);
|
|
||||||
if (fdi < 0)
|
|
||||||
goto error;
|
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 -----
|
// ----- Step 7: start program in /tmp -----
|
||||||
@@ -474,7 +475,7 @@ void upx_main(
|
|||||||
if (fork() == 0)
|
if (fork() == 0)
|
||||||
{
|
{
|
||||||
// Sleep 3 seconds, then remove the temp file.
|
// 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);
|
nanosleep(&ts, 0);
|
||||||
unlink(tmpname);
|
unlink(tmpname);
|
||||||
}
|
}
|
||||||
@@ -500,4 +501,3 @@ void upx_main(
|
|||||||
/*
|
/*
|
||||||
vi:ts=4:et:nowrap
|
vi:ts=4:et:nowrap
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
+64
-83
@@ -33,34 +33,13 @@
|
|||||||
%define jmps jmp short
|
%define jmps jmp short
|
||||||
%define jmpn jmp near
|
%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
|
; // program entry point
|
||||||
; // see glibc/sysdeps/i386/elf/start.S
|
; // see glibc/sysdeps/i386/elf/start.S
|
||||||
; **************************************************************************/
|
; **************************************************************************/
|
||||||
|
|
||||||
GLOBAL _start
|
GLOBAL _start
|
||||||
|
;__LEXEC000__
|
||||||
_start:
|
_start:
|
||||||
;;;; int3
|
;;;; int3
|
||||||
;; How to debug this code: Uncomment the 'int3' breakpoint instruction above.
|
;; How to debug this code: Uncomment the 'int3' breakpoint instruction above.
|
||||||
@@ -85,19 +64,24 @@ _start:
|
|||||||
xor ebx, ebx ; PER_LINUX
|
xor ebx, ebx ; PER_LINUX
|
||||||
int 0x80
|
int 0x80
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
call main ; push address of decompress subroutine
|
call main ; push address of decompress subroutine
|
||||||
|
decompress:
|
||||||
|
|
||||||
; /*************************************************************************
|
; /*************************************************************************
|
||||||
; // C callable decompressor
|
; // C callable decompressor
|
||||||
; **************************************************************************/
|
; **************************************************************************/
|
||||||
|
|
||||||
%define INP dword [esp+8*4+4]
|
%define INP dword [esp+8*4+8]
|
||||||
%define INS dword [esp+8*4+8]
|
%define INS dword [esp+8*4+12]
|
||||||
%define OUTP dword [esp+8*4+12]
|
%define OUTP dword [esp+8*4+16]
|
||||||
%define OUTS dword [esp+8*4+16]
|
%define OUTS dword [esp+8*4+20]
|
||||||
|
|
||||||
decompress:
|
;__LEXEC009__
|
||||||
|
mov eax, 'NMRU' ; free slot in following 'pusha'
|
||||||
|
;__LEXEC010__
|
||||||
pusha
|
pusha
|
||||||
|
push byte '?' ; cto8 (sign extension does not matter)
|
||||||
; cld
|
; cld
|
||||||
|
|
||||||
mov esi, INP
|
mov esi, INP
|
||||||
@@ -105,75 +89,81 @@ decompress:
|
|||||||
|
|
||||||
or ebp, byte -1
|
or ebp, byte -1
|
||||||
;;; align 8
|
;;; 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
|
; eax is 0 from decompressor code
|
||||||
;xor eax, eax ; return code
|
;xor eax, eax ; return code
|
||||||
|
|
||||||
; check compressed size
|
; check compressed size
|
||||||
mov edx, INP
|
mov edx, INP
|
||||||
add edx, INS
|
add edx, INS
|
||||||
cmp esi, edx
|
cmp edx, esi
|
||||||
jz .ok
|
jz .ok
|
||||||
dec eax
|
dec eax
|
||||||
.ok:
|
.ok:
|
||||||
|
xchg [8*4 + esp], eax ; store success/failure, fetch NMRU
|
||||||
|
|
||||||
; write back the uncompressed size
|
; write back the uncompressed size, and prepare for unfilter
|
||||||
sub edi, OUTP
|
mov edx, OUTS
|
||||||
mov edx, OUTS
|
mov ecx, edi
|
||||||
mov [edx], 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
|
popa
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
;__LEXEC020__
|
||||||
|
|
||||||
%define PAGE_MASK (~0<<12)
|
%define PAGE_MASK (~0<<12)
|
||||||
%define PAGE_SIZE ( 1<<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
|
; Decompress the rest of this loader, and jump to it
|
||||||
unfold:
|
unfold:
|
||||||
pop esi ; &fold_begin = src
|
pop esi ; &{ sz_uncompressed, sz_compressed, compressed_data...}
|
||||||
|
mov ecx, PAGE_MASK
|
||||||
push esi ; &dst
|
push esi ; &dst
|
||||||
mov ecx, ebp ; &decompress
|
mov ebx, ebp ; &decompress
|
||||||
and ecx, dword PAGE_MASK ; &my_elfhdr
|
and ebx, ecx ; &my_elfhdr
|
||||||
mov ebx, ecx ; save &my_elfhdr for later
|
neg ecx ; ecx= PAGE_SIZE
|
||||||
|
|
||||||
|
cld
|
||||||
|
lodsd ; sz_uncompressed
|
||||||
|
lodsd ; sz_compressed
|
||||||
|
|
||||||
;; Compressed code now begins at fold_begin.
|
;; Compressed code now begins at fold_begin.
|
||||||
;; We want decompressed code to begin at fold_begin, too.
|
;; We want decompressed code to begin at fold_begin, too.
|
||||||
;; Move the compressed code to the high end of the page.
|
;; Move the compressed code to the high end of the page.
|
||||||
;; Assume non-overlapping so that forward movsb is OK.
|
;; 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)
|
call ebp ; decompress(&src, srclen, &dst, &dstlen)
|
||||||
pop eax ; discard &src
|
pop eax ; discard &src
|
||||||
pop eax ; discard srclen
|
pop eax ; discard srclen
|
||||||
@@ -188,23 +178,14 @@ unfold:
|
|||||||
|
|
||||||
main:
|
main:
|
||||||
pop ebp ; &decompress
|
pop ebp ; &decompress
|
||||||
push eax ; place to store dstlen
|
push eax ; sz_uncompressed (junk, actually)
|
||||||
push esp ; &dstlen
|
push esp ; &sz_uncompressed
|
||||||
call unfold
|
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
|
eof:
|
||||||
mov ecx, esp ; argv starts just at the current stack top
|
; __XTHEENDX__
|
||||||
lea edx, [ecx+eax*4+4] ; envp = &argv[argc + 1]
|
section .data
|
||||||
push eax ; Restore the stack
|
dd -1
|
||||||
push ebp ; argument: &decompress
|
dw eof
|
||||||
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
|
; vi:ts=8:et:nowrap
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||||
OUTPUT_ARCH(i386)
|
OUTPUT_ARCH(i386)
|
||||||
ENTRY(_start)
|
/*ENTRY(_start)*/
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
/* 0x08048000: customary Linux/x86 Elf .text start */
|
/* 0x08048000: customary Linux/x86 Elf .text start */
|
||||||
|
|||||||
+15
-134
@@ -30,37 +30,13 @@
|
|||||||
BITS 32
|
BITS 32
|
||||||
SECTION .text
|
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
|
; // program entry point
|
||||||
; // see glibc/sysdeps/i386/elf/start.S
|
; // see glibc/sysdeps/i386/elf/start.S
|
||||||
; **************************************************************************/
|
; **************************************************************************/
|
||||||
|
|
||||||
GLOBAL _start
|
GLOBAL _start
|
||||||
|
;__LEXEC000__
|
||||||
_start:
|
_start:
|
||||||
;;;; int3
|
;;;; int3
|
||||||
;; How to debug this code: Uncomment the 'int3' breakpoint instruction above.
|
;; How to debug this code: Uncomment the 'int3' breakpoint instruction above.
|
||||||
@@ -79,7 +55,9 @@ _start:
|
|||||||
;; end
|
;; end
|
||||||
;; Step through the code; remember that <Enter> repeats the previous command.
|
;; Step through the code; remember that <Enter> repeats the previous command.
|
||||||
;;
|
;;
|
||||||
|
|
||||||
call main ; push address of decompress subroutine
|
call main ; push address of decompress subroutine
|
||||||
|
decompress:
|
||||||
|
|
||||||
; /*************************************************************************
|
; /*************************************************************************
|
||||||
; // C callable decompressor
|
; // C callable decompressor
|
||||||
@@ -90,7 +68,7 @@ _start:
|
|||||||
%define OUTP dword [esp+8*4+12]
|
%define OUTP dword [esp+8*4+12]
|
||||||
%define OUTS dword [esp+8*4+16]
|
%define OUTS dword [esp+8*4+16]
|
||||||
|
|
||||||
decompress:
|
;__LEXEC010__
|
||||||
pusha
|
pusha
|
||||||
; cld
|
; cld
|
||||||
|
|
||||||
@@ -99,15 +77,13 @@ decompress:
|
|||||||
|
|
||||||
or ebp, byte -1
|
or ebp, byte -1
|
||||||
;;; align 8
|
;;; 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
|
; eax is 0 from decompressor code
|
||||||
;xor eax, eax ; return code
|
;xor eax, eax ; return code
|
||||||
|
|
||||||
@@ -128,15 +104,13 @@ decompress:
|
|||||||
popa
|
popa
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
;__LEXEC020__
|
||||||
|
|
||||||
%define PAGE_MASK (~0<<12)
|
%define PAGE_MASK (~0<<12)
|
||||||
%define PAGE_SIZE ( 1<<12)
|
%define PAGE_SIZE ( 1<<12)
|
||||||
|
|
||||||
%define szElf32_Ehdr 0x34
|
%define szElf32_Ehdr 0x34
|
||||||
%define szElf32_Phdr 8*4
|
|
||||||
%define p_filesz 4*4
|
|
||||||
%define p_memsz 5*4
|
%define p_memsz 5*4
|
||||||
%define a_val 4
|
|
||||||
|
|
||||||
%define MAP_FIXED 0x10
|
%define MAP_FIXED 0x10
|
||||||
%define MAP_PRIVATE 0x02
|
%define MAP_PRIVATE 0x02
|
||||||
@@ -145,7 +119,6 @@ decompress:
|
|||||||
%define PROT_WRITE 2
|
%define PROT_WRITE 2
|
||||||
%define PROT_EXEC 4
|
%define PROT_EXEC 4
|
||||||
%define __NR_mmap 90
|
%define __NR_mmap 90
|
||||||
%define __NR_munmap 91
|
|
||||||
|
|
||||||
; Decompress the rest of this loader, and jump to it
|
; Decompress the rest of this loader, and jump to it
|
||||||
unfold:
|
unfold:
|
||||||
@@ -186,104 +159,12 @@ unfold:
|
|||||||
main:
|
main:
|
||||||
pop ebp ; &decompress
|
pop ebp ; &decompress
|
||||||
call unfold
|
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
|
; vi:ts=8:et:nowrap
|
||||||
|
|
||||||
|
|||||||
+12
-1
@@ -27,18 +27,29 @@
|
|||||||
|
|
||||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||||
OUTPUT_ARCH(i386)
|
OUTPUT_ARCH(i386)
|
||||||
ENTRY(_start)
|
/*ENTRY(_start)*/
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
/* 0x00800000: avoid 0x00400000 for shell itself being compressed */
|
/* 0x00800000: avoid 0x00400000 for shell itself being compressed */
|
||||||
. = 0x00800000 + SIZEOF_HEADERS;
|
. = 0x00800000 + SIZEOF_HEADERS;
|
||||||
. = ALIGN(0x80);
|
. = ALIGN(0x80);
|
||||||
|
/*
|
||||||
.text : {
|
.text : {
|
||||||
*(.text)
|
*(.text)
|
||||||
*(.data)
|
*(.data)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
.data : { /* put everything together in one Phdr */
|
||||||
|
*(.text)
|
||||||
|
*(.rodata)
|
||||||
|
*(.data)
|
||||||
|
*(.bss)
|
||||||
|
*(COMMON)
|
||||||
}
|
}
|
||||||
/* 0x08048000: customary Linux/x86 Elf .text start */
|
/* 0x08048000: customary Linux/x86 Elf .text start */
|
||||||
|
/*
|
||||||
. = 0x08048000 + (0xfff & .);
|
. = 0x08048000 + (0xfff & .);
|
||||||
.data : {
|
.data : {
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,6 +168,53 @@ ctend:
|
|||||||
%endmacro
|
%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
|
;; ============= 32-BIT RELOCATIONS
|
||||||
@@ -213,4 +260,312 @@ reloc_endx:
|
|||||||
%endmacro
|
%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
|
; vi:ts=8:et:nowrap
|
||||||
|
|||||||
Reference in New Issue
Block a user