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:
+199
-71
@@ -4,6 +4,7 @@
|
||||
|
||||
Copyright (C) 1996-2001 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996-2001 Laszlo Molnar
|
||||
Copyright (C) 2001 John F. Reiser
|
||||
All Rights Reserved.
|
||||
|
||||
UPX and the UCL library are free software; you can redistribute them
|
||||
@@ -21,14 +22,16 @@
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer Laszlo Molnar
|
||||
markus@oberhumer.com ml1050@cdata.tvnet.hu
|
||||
Markus F.X.J. Oberhumer Laszlo Molnar John F. Reiser
|
||||
markus@oberhumer.com ml1050@cdata.tvnet.hu jreiser@BitWagon.com
|
||||
*/
|
||||
|
||||
|
||||
#include "conf.h"
|
||||
|
||||
#include "file.h"
|
||||
#include "filter.h"
|
||||
#include "linker.h"
|
||||
#include "packer.h"
|
||||
#include "p_elf.h"
|
||||
#include "p_unix.h"
|
||||
@@ -42,9 +45,9 @@
|
||||
**************************************************************************/
|
||||
|
||||
static const
|
||||
#include "stub/l_lx_n2b.h"
|
||||
#include "stub/l_lx_exec86.h"
|
||||
static const
|
||||
#include "stub/l_lx_n2d.h"
|
||||
#include "stub/fold_exec86.h"
|
||||
|
||||
|
||||
const int *PackLinuxI386::getCompressionMethods(int method, int level) const
|
||||
@@ -61,29 +64,196 @@ const int *PackLinuxI386::getCompressionMethods(int method, int level) const
|
||||
return m_nrv2d;
|
||||
}
|
||||
|
||||
|
||||
const upx_byte *PackLinuxI386::getLoader() const
|
||||
int const *
|
||||
PackLinuxI386::getFilters() const
|
||||
{
|
||||
if (M_IS_NRV2B(ph.method))
|
||||
return linux_i386exec_nrv2b_loader;
|
||||
if (M_IS_NRV2D(ph.method))
|
||||
return linux_i386exec_nrv2d_loader;
|
||||
return NULL;
|
||||
static const int filters[] = {
|
||||
0x49, 0x46,
|
||||
0x83, 0x86, 0x80, 0x84, 0x87, 0x81, 0x82, 0x85,
|
||||
0x24, 0x16, 0x13, 0x14, 0x11, 0x25, 0x15, 0x12,
|
||||
-1 };
|
||||
return filters;
|
||||
}
|
||||
|
||||
struct cprElfhdr {
|
||||
struct Elf_LE32_Ehdr ehdr;
|
||||
struct Elf_LE32_Phdr phdr[2];
|
||||
struct PackUnix::l_info linfo;
|
||||
};
|
||||
|
||||
int PackLinuxI386::getLoaderSize() const
|
||||
int
|
||||
PackLinuxI386::buildLinuxLoader(
|
||||
upx_byte const *const proto,
|
||||
unsigned const szproto,
|
||||
upx_byte const *const fold,
|
||||
unsigned const szfold,
|
||||
Filter const *ft,
|
||||
unsigned const brka
|
||||
)
|
||||
{
|
||||
if (0!=lsize) {
|
||||
return lsize;
|
||||
initLoader(proto, szproto);
|
||||
|
||||
struct cprElfhdr elfhdr = *(struct cprElfhdr const *)fold;
|
||||
memset(&elfhdr.linfo, 0, sizeof(elfhdr.linfo));
|
||||
|
||||
// Info for OS kernel to set the brk()
|
||||
if (brka) {
|
||||
assert(ph.format==UPX_F_LINUX_ELF_i386
|
||||
|| ph.format==UPX_F_LINUX_SH_i386 );
|
||||
if (ph.format==UPX_F_LINUX_SH_i386) {
|
||||
assert(elfhdr.ehdr.e_phnum==1);
|
||||
elfhdr.ehdr.e_phnum = 2;
|
||||
}
|
||||
elfhdr.phdr[1].p_offset = 0xfff&brka;
|
||||
elfhdr.phdr[1].p_vaddr = brka;
|
||||
elfhdr.phdr[1].p_paddr = brka;
|
||||
elfhdr.phdr[1].p_filesz = 0;
|
||||
elfhdr.phdr[1].p_memsz = 0;
|
||||
}
|
||||
if (M_IS_NRV2B(ph.method))
|
||||
return sizeof(linux_i386exec_nrv2b_loader);
|
||||
if (M_IS_NRV2D(ph.method))
|
||||
return sizeof(linux_i386exec_nrv2d_loader);
|
||||
return 0;
|
||||
|
||||
// The beginning of our loader consists of a elf_hdr (52 bytes) and
|
||||
// two sections elf_phdr (2 * 32 byte), so we have 12 free bytes
|
||||
// from offset 116 to the program start at offset 128.
|
||||
assert(elfhdr.ehdr.e_phoff == sizeof(Elf_LE32_Ehdr));
|
||||
assert(elfhdr.ehdr.e_shoff == 0);
|
||||
assert(elfhdr.ehdr.e_ehsize == sizeof(Elf_LE32_Ehdr));
|
||||
assert(elfhdr.ehdr.e_phentsize == sizeof(Elf_LE32_Phdr));
|
||||
assert(elfhdr.ehdr.e_phnum == (unsigned)(1+ (0!=brka)));
|
||||
assert(elfhdr.ehdr.e_shnum == 0);
|
||||
linker->addSection("ELFHEADX", (unsigned char const *)&elfhdr, sizeof(elfhdr));
|
||||
addLoader("ELFHEADX", 0);
|
||||
|
||||
struct {
|
||||
upx_uint sz_unc; // uncompressed
|
||||
upx_uint sz_cpr; // compressed
|
||||
} h = {
|
||||
szfold - sizeof(elfhdr), 0
|
||||
};
|
||||
unsigned char const *const uncLoader = (unsigned char const *)(1+
|
||||
(struct cprElfhdr const *)fold );
|
||||
unsigned char *const cprLoader = new unsigned char[sizeof(h) + h.sz_unc];
|
||||
|
||||
int r = upx_compress(uncLoader, h.sz_unc, sizeof(h) + cprLoader, &h.sz_cpr,
|
||||
NULL, ph.method, 10, NULL, NULL );
|
||||
if (r != UPX_E_OK || h.sz_cpr >= h.sz_unc)
|
||||
throwInternalError("loader compression failed");
|
||||
memcpy(cprLoader, &h, sizeof(h));
|
||||
linker->addSection("FOLDEXEC", cprLoader, sizeof(h) + h.sz_cpr);
|
||||
delete cprLoader;
|
||||
|
||||
n_mru = ft->n_mru;
|
||||
|
||||
addLoader("IDENTSTR", 0);
|
||||
addLoader("LEXEC000", 0);
|
||||
|
||||
if (ft->id) {
|
||||
if (ph.format==UPX_F_LINUX_ELF_i386) { // decompr, unfilter are separate
|
||||
addLoader("LXUNF000", 0);
|
||||
addLoader("LXUNF002", 0);
|
||||
if (0x80==(ft->id & 0xF0)) {
|
||||
if (256==n_mru) {
|
||||
addLoader("MRUBYTE0", 0);
|
||||
}
|
||||
else if (n_mru) {
|
||||
addLoader("LXMRU005", 0);
|
||||
}
|
||||
if (n_mru) {
|
||||
addLoader("LXMRU006", 0);
|
||||
}
|
||||
else {
|
||||
addLoader("LXMRU007", 0);
|
||||
}
|
||||
}
|
||||
else if (0x40==(ft->id & 0xF0)) {
|
||||
addLoader("LXUNF008", 0);
|
||||
}
|
||||
addLoader("LXUNF010", 0);
|
||||
}
|
||||
if (n_mru) {
|
||||
addLoader("LEXEC009", 0);
|
||||
}
|
||||
}
|
||||
addLoader("LEXEC010", 0);
|
||||
addLoader(getDecompressor(), 0);
|
||||
addLoader("LEXEC015", 0);
|
||||
if (ft->id) {
|
||||
if (ph.format==UPX_F_LINUX_ELF_i386) { // decompr, unfilter are separate
|
||||
if (0x80!=(ft->id & 0xF0)) {
|
||||
addLoader("LXUNF042", 0);
|
||||
}
|
||||
}
|
||||
else { // decompr, unfilter not separate
|
||||
if (0x80==(ft->id & 0xF0)) {
|
||||
addLoader("LEXEC110", 0);
|
||||
if (n_mru) {
|
||||
addLoader("LEXEC100", 0);
|
||||
}
|
||||
// bug in APP: jmp and label must be in same .asx/.asy
|
||||
addLoader("LEXEC016", 0);
|
||||
}
|
||||
}
|
||||
addFilter32(ft->id);
|
||||
if (ph.format==UPX_F_LINUX_ELF_i386) { // decompr, unfilter are separate
|
||||
if (0x80==(ft->id & 0xF0)) {
|
||||
if (0==n_mru) {
|
||||
addLoader("LXMRU058", 0);
|
||||
}
|
||||
}
|
||||
addLoader("LXUNF035", 0);
|
||||
}
|
||||
else { // decompr always unfilters
|
||||
addLoader("LEXEC017", 0);
|
||||
}
|
||||
}
|
||||
|
||||
addLoader("LEXEC020", 0);
|
||||
addLoader("FOLDEXEC", 0);
|
||||
|
||||
struct Elf_LE32_Ehdr *const ldrEhdr =
|
||||
(struct Elf_LE32_Ehdr *)const_cast<unsigned char *>(getLoader());
|
||||
unsigned e_entry = getLoaderSectionStart("LEXEC000");
|
||||
ldrEhdr->e_entry = e_entry + elfhdr.phdr[0].p_vaddr;
|
||||
|
||||
char *ptr_cto = e_entry + (char *)ldrEhdr;
|
||||
int sz_cto = getLoaderSize() - e_entry;
|
||||
if (0x20==(ft->id & 0xF0) || 0x30==(ft->id & 0xF0)) { // push byte '?' ; cto8
|
||||
patch_le16(ptr_cto, sz_cto, "\x6a?", 0x6a + (ft->cto << 8));
|
||||
}
|
||||
|
||||
// FIXME ?? patchVersion((char *)ldrEhdr, e_entry);
|
||||
return getLoaderSize();
|
||||
}
|
||||
|
||||
int
|
||||
PackLinuxI386::buildLoader(Filter const *ft)
|
||||
{
|
||||
unsigned const sz_fold = sizeof(linux_i386exec_fold);
|
||||
MemBuffer buf(sz_fold);
|
||||
memcpy(buf, linux_i386exec_fold, sz_fold);
|
||||
|
||||
// patch loader
|
||||
// note: we only can use /proc/<pid>/fd when exetype > 0.
|
||||
// also, we sleep much longer when compressing a script.
|
||||
checkPatch(0,0,0,0); // reset
|
||||
patch_le32(buf,sz_fold,"UPX4",exetype > 0 ? 3 : 15); // sleep time
|
||||
patch_le32(buf,sz_fold,"UPX3",progid);
|
||||
patch_le32(buf,sz_fold,"UPX2",exetype > 0 ? 0 : 0x7fffffff);
|
||||
|
||||
// get fresh filter
|
||||
Filter fold_ft = *ft;
|
||||
fold_ft.init(ft->id, ft->addvalue);
|
||||
int preferred_ctos[2] = {ft->cto, -1};
|
||||
fold_ft.preferred_ctos = preferred_ctos;
|
||||
|
||||
// filter
|
||||
optimizeFilter(&fold_ft, buf, sz_fold);
|
||||
bool success = fold_ft.filter(buf + sizeof(cprElfhdr), sz_fold - sizeof(cprElfhdr));
|
||||
(void)success;
|
||||
|
||||
return buildLinuxLoader(
|
||||
linux_i386exec_loader, sizeof(linux_i386exec_loader),
|
||||
buf, sz_fold, ft, 0 );
|
||||
}
|
||||
|
||||
int PackLinuxI386::getLoaderPrefixSize() const
|
||||
{
|
||||
@@ -198,58 +368,13 @@ bool PackLinuxI386::canPack()
|
||||
|
||||
void PackLinuxI386::patchLoader()
|
||||
{
|
||||
lsize = getLoaderSize();
|
||||
|
||||
// patch loader
|
||||
// note: we only can use /proc/<pid>/fd when exetype > 0.
|
||||
// also, we sleep much longer when compressing a script.
|
||||
patch_le32(loader,lsize,"UPX4",exetype > 0 ? 3 : 15); // sleep time
|
||||
patch_le32(loader,lsize,"UPX3",exetype > 0 ? 0 : 0x7fffffff);
|
||||
patch_le32(loader,lsize,"UPX2",progid);
|
||||
patchVersion(loader,lsize);
|
||||
|
||||
Elf_LE32_Ehdr *const ehdr = (Elf_LE32_Ehdr *)(void *)loader;
|
||||
Elf_LE32_Phdr *const phdr = (Elf_LE32_Phdr *)(1+ehdr);
|
||||
|
||||
// stub/scripts/setfold.pl puts address of 'fold_begin' in phdr[1].p_offset
|
||||
off_t const fold_begin = phdr[1].p_offset;
|
||||
assert(fold_begin > 0);
|
||||
assert(fold_begin < (off_t)lsize);
|
||||
MemBuffer cprLoader(lsize);
|
||||
|
||||
// compress compiled C-code portion of loader
|
||||
upx_uint const uncLsize = lsize - fold_begin;
|
||||
upx_uint cprLsize;
|
||||
int r = upx_compress(loader + fold_begin, uncLsize, cprLoader, &cprLsize,
|
||||
NULL, ph.method, 10, NULL, NULL);
|
||||
if (r != UPX_E_OK || cprLsize >= uncLsize)
|
||||
throwInternalError("loaded compression failed");
|
||||
|
||||
memcpy(fold_begin+loader, cprLoader, cprLsize);
|
||||
lsize = fold_begin + cprLsize;
|
||||
phdr->p_filesz = lsize;
|
||||
// phdr->p_memsz is the decompressed size
|
||||
|
||||
// The beginning of our loader consists of a elf_hdr (52 bytes) and
|
||||
// one section elf_phdr (32 byte) now,
|
||||
// another section elf_phdr (32 byte) later, so we have 12 free bytes
|
||||
// from offset 116 to the program start at offset 128.
|
||||
// These 12 bytes are used for l_info by ::patchLoaderChecksum().
|
||||
assert(get_le32(loader + 28) == 52); // e_phoff
|
||||
assert(get_le32(loader + 32) == 0); // e_shoff
|
||||
assert(get_le16(loader + 40) == 52); // e_ehsize
|
||||
assert(get_le16(loader + 42) == 32); // e_phentsize
|
||||
assert(get_le16(loader + 44) == 1); // e_phnum
|
||||
assert(get_le16(loader + 48) == 0); // e_shnum
|
||||
assert(lsize > 128 && lsize < 4096);
|
||||
|
||||
patchLoaderChecksum();
|
||||
}
|
||||
|
||||
|
||||
void PackLinuxI386::patchLoaderChecksum()
|
||||
{
|
||||
l_info *const lp = (l_info *)(loader + getLoaderPrefixSize());
|
||||
unsigned char *const ptr = const_cast<unsigned char *>(getLoader());
|
||||
l_info *const lp = (l_info *)(ptr + getLoaderPrefixSize());
|
||||
// checksum for loader + p_info
|
||||
lp->l_checksum = 0;
|
||||
lp->l_magic = UPX_ELF_MAGIC;
|
||||
@@ -258,7 +383,7 @@ void PackLinuxI386::patchLoaderChecksum()
|
||||
lp->l_format = (unsigned char) ph.format;
|
||||
// INFO: lp->l_checksum is currently unused
|
||||
unsigned adler = upx_adler32(0,NULL,0);
|
||||
adler = upx_adler32(adler, loader, lsize + sizeof(p_info));
|
||||
adler = upx_adler32(adler, ptr, lsize + sizeof(p_info));
|
||||
lp->l_checksum = adler;
|
||||
}
|
||||
|
||||
@@ -266,13 +391,18 @@ void PackLinuxI386::patchLoaderChecksum()
|
||||
void PackLinuxI386::updateLoader(OutputFile *fo)
|
||||
{
|
||||
#define PAGE_MASK (~0<<12)
|
||||
Elf_LE32_Ehdr *const ehdr = (Elf_LE32_Ehdr *)(unsigned char *)loader;
|
||||
Elf_LE32_Ehdr *const ehdr = (Elf_LE32_Ehdr *)const_cast<upx_byte *>(getLoader());
|
||||
Elf_LE32_Phdr *const phdr = (Elf_LE32_Phdr *)(1+ehdr);
|
||||
|
||||
ehdr->e_phnum = 2;
|
||||
phdr->p_filesz = lsize;
|
||||
// phdr->p_memsz is the decompressed size
|
||||
assert(lsize > 128 && lsize < 4096);
|
||||
|
||||
// The first Phdr maps the stub (instructions, data, bss) rwx.
|
||||
// The second Phdr maps the overlay r--,
|
||||
// to defend against /usr/bin/strip removing the overlay.
|
||||
Elf_LE32_Phdr *const phdro = 1+(Elf_LE32_Phdr *)(1+ehdr);
|
||||
Elf_LE32_Phdr *const phdro = 1+phdr;
|
||||
|
||||
phdro->p_type = PT_LOAD;
|
||||
phdro->p_offset = lsize;
|
||||
@@ -282,8 +412,6 @@ void PackLinuxI386::updateLoader(OutputFile *fo)
|
||||
phdro->p_align = (unsigned) (-PAGE_MASK);
|
||||
|
||||
patchLoaderChecksum();
|
||||
fo->seek(0, SEEK_SET);
|
||||
fo->rewrite(loader, 0x80);
|
||||
#undef PAGE_MASK
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user