filtering support added. better method for finding the compressed kernel.
committer: ml1050 <ml1050> 976877214 +0000
This commit is contained in:
+109
-59
@@ -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_vmlinz.h"
|
#include "p_vmlinz.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
@@ -67,7 +68,9 @@ int PackVmlinuzI386::getCompressionMethod() const
|
|||||||
|
|
||||||
const int *PackVmlinuzI386::getFilters() const
|
const int *PackVmlinuzI386::getFilters() const
|
||||||
{
|
{
|
||||||
return NULL;
|
static const int filters[] = { 0x26, 0x24, 0x11, 0x14, 0x13, 0x16,
|
||||||
|
0x25, 0x15, 0x12, -1 };
|
||||||
|
return filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -88,11 +91,12 @@ int PackVmlinuzI386::readFileHeader()
|
|||||||
fi->readx(&h, sizeof(h));
|
fi->readx(&h, sizeof(h));
|
||||||
if (h.boot_flag != 0xAA55)
|
if (h.boot_flag != 0xAA55)
|
||||||
return -1;
|
return -1;
|
||||||
// FIXME: add more checks for a valid kernel
|
|
||||||
|
|
||||||
setup_size = (1 + (h.setup_sects ? h.setup_sects : 4)) * 0x200;
|
setup_size = (1 + (h.setup_sects ? h.setup_sects : 4)) * 0x200;
|
||||||
if (setup_size > file_size)
|
if (setup_size > file_size)
|
||||||
return -1;
|
return -1;
|
||||||
|
if (h.sys_size * 16 + setup_size - ALIGN_UP(file_size, 16))
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (memcmp(h.hdrs, "HdrS", 4) == 0 && (h.load_flags & 1) != 0)
|
if (memcmp(h.hdrs, "HdrS", 4) == 0 && (h.load_flags & 1) != 0)
|
||||||
return UPX_F_BVMLINUZ_i386;
|
return UPX_F_BVMLINUZ_i386;
|
||||||
@@ -110,39 +114,34 @@ int PackVmlinuzI386::uncompressKernel()
|
|||||||
fi->seek(0, SEEK_SET);
|
fi->seek(0, SEEK_SET);
|
||||||
fi->readx(obuf, file_size);
|
fi->readx(obuf, file_size);
|
||||||
|
|
||||||
|
// estimate gzip-uncompressed kernel size &
|
||||||
|
// alloc buffer to hold the gzip-uncompressed kernel
|
||||||
|
ibuf.alloc((file_size - setup_size) * 3);
|
||||||
|
|
||||||
// find gzip/zlib header
|
// find gzip/zlib header
|
||||||
// FIXME - improve this
|
int klen = 0;
|
||||||
int gzoff = setup_size;
|
gzFile zf= 0;
|
||||||
while (gzoff < file_size)
|
|
||||||
|
for (int gzoff = setup_size; gzoff < file_size; gzoff++)
|
||||||
{
|
{
|
||||||
int off = find(obuf + gzoff, file_size - gzoff, "\x1F\x8B", 2);
|
int off = find(obuf + gzoff, file_size - gzoff, "\x1F\x8B", 2);
|
||||||
if (off < 0)
|
if (off < 0)
|
||||||
return 0;
|
break;
|
||||||
gzoff += off;
|
|
||||||
break;
|
fi->seek(gzoff += off, SEEK_SET);
|
||||||
|
zf = gzdopen(dup(fi->getFd()), "r");
|
||||||
|
if (zf == 0)
|
||||||
|
break;
|
||||||
|
klen = gzread(zf, ibuf, ibuf.getSize());
|
||||||
|
if (klen >= file_size)
|
||||||
|
break;
|
||||||
|
gzclose(zf);
|
||||||
|
zf = 0;
|
||||||
|
klen = 0;
|
||||||
}
|
}
|
||||||
if (gzoff >= file_size)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// estimate gzip-uncompressed kernel size
|
if (zf)
|
||||||
int isize = file_size - gzoff;
|
gzclose(zf);
|
||||||
isize = UPX_MAX(3 * isize, 4*1024*1024);
|
|
||||||
|
|
||||||
// alloc buffer to hold the gzip-uncompressed kernel
|
|
||||||
ibuf.alloc(isize);
|
|
||||||
|
|
||||||
// gzip-uncompress
|
|
||||||
fi->seek(gzoff, SEEK_SET);
|
|
||||||
gzFile zf = gzdopen(fi->getFd(), "r");
|
|
||||||
if (zf == 0)
|
|
||||||
return 0;
|
|
||||||
int klen = gzread(zf, ibuf, isize);
|
|
||||||
if (klen <= 0 || klen <= file_size)
|
|
||||||
return 0;
|
|
||||||
if (klen >= isize)
|
|
||||||
throwCantPack("kernel is too big - send a bug report");
|
|
||||||
|
|
||||||
// success
|
|
||||||
return klen;
|
return klen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,9 +159,10 @@ void PackVmlinuzI386::readKernel()
|
|||||||
memcpy(setup_buf, obuf, setup_size);
|
memcpy(setup_buf, obuf, setup_size);
|
||||||
|
|
||||||
obuf.free();
|
obuf.free();
|
||||||
obuf.allocForCompression(ibuf.getSize());
|
obuf.allocForCompression(klen);
|
||||||
|
|
||||||
ph.u_len = klen;
|
ph.u_len = klen;
|
||||||
|
ph.filter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -170,40 +170,64 @@ void PackVmlinuzI386::readKernel()
|
|||||||
// vmlinuz specific
|
// vmlinuz specific
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
int PackVmlinuzI386::buildLoader(const Filter *ft)
|
||||||
|
{
|
||||||
|
// prepare loader
|
||||||
|
initLoader(nrv_loader, sizeof(nrv_loader));
|
||||||
|
addLoader("LINUZ000",
|
||||||
|
ft->id ? "LZCALLT1" : "",
|
||||||
|
"LZIMAGE0",
|
||||||
|
getDecompressor(),
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
if (ft->id)
|
||||||
|
{
|
||||||
|
assert(ft->calls > 0);
|
||||||
|
addLoader("LZCALLT9", NULL);
|
||||||
|
addFilter32(ft->id);
|
||||||
|
}
|
||||||
|
addLoader("LINUZ990""IDENTSTR""UPX1HEAD", NULL);
|
||||||
|
return getLoaderSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PackVmlinuzI386::pack(OutputFile *fo)
|
void PackVmlinuzI386::pack(OutputFile *fo)
|
||||||
{
|
{
|
||||||
readKernel();
|
readKernel();
|
||||||
|
|
||||||
if (!compress(ibuf, obuf))
|
// prepare filter
|
||||||
throwNotCompressible();
|
Filter ft(opt->level);
|
||||||
|
ft.buf_len = ph.u_len;
|
||||||
|
ft.addvalue = kernel_entry;
|
||||||
|
// prepare other settings
|
||||||
|
unsigned overlapoh;
|
||||||
|
|
||||||
const unsigned clen = ph.c_len;
|
int strategy = -1; // try the first working filter
|
||||||
|
if (opt->filter >= 0 && isValidFilter(opt->filter))
|
||||||
initLoader(nrv_loader, sizeof(nrv_loader));
|
// try opt->filter or 0 if that fails
|
||||||
|
strategy = -2;
|
||||||
addLoader("LINUZ000""LZIMAGE0",
|
else if (opt->all_filters)
|
||||||
getDecompressor(),
|
// choose best from all available filters
|
||||||
"LINUZ990""IDENTSTR""UPX1HEAD",
|
strategy = 0;
|
||||||
NULL
|
compressWithFilters(&ft, &overlapoh, 1 << 20, strategy);
|
||||||
);
|
|
||||||
|
|
||||||
const unsigned lsize = getLoaderSize();
|
const unsigned lsize = getLoaderSize();
|
||||||
MemBuffer loader(lsize);
|
MemBuffer loader(lsize);
|
||||||
memcpy(loader, getLoader(), lsize);
|
memcpy(loader, getLoader(), lsize);
|
||||||
|
|
||||||
patchPackHeader(loader, lsize);
|
patchPackHeader(loader, lsize);
|
||||||
|
patchFilter32(ft, loader, lsize);
|
||||||
patch_le32(loader, lsize, "ESI1", zimage_offset + lsize);
|
patch_le32(loader, lsize, "ESI1", zimage_offset + lsize);
|
||||||
|
|
||||||
patch_le32(loader, lsize, "KEIP", kernel_entry);
|
patch_le32(loader, lsize, "KEIP", kernel_entry);
|
||||||
patch_le32(loader, lsize, "STAK", stack_during_uncompression);
|
patch_le32(loader, lsize, "STAK", stack_during_uncompression);
|
||||||
|
|
||||||
boot_sect_t *bs = (boot_sect_t *) ((unsigned char *) setup_buf);
|
boot_sect_t *bs = (boot_sect_t *) ((unsigned char *) setup_buf);
|
||||||
bs->sys_size = ALIGN_UP(lsize + clen, 16) / 16;
|
bs->sys_size = ALIGN_UP(lsize + ph.c_len, 16) / 16;
|
||||||
|
|
||||||
fo->write(setup_buf, setup_buf.getSize());
|
fo->write(setup_buf, setup_buf.getSize());
|
||||||
fo->write(loader, lsize);
|
fo->write(loader, lsize);
|
||||||
fo->write(obuf, clen);
|
fo->write(obuf, ph.c_len);
|
||||||
#if 0
|
#if 0
|
||||||
printf("%-13s: setup : %8ld bytes\n", getName(), (long) setup_buf.getSize());
|
printf("%-13s: setup : %8ld bytes\n", getName(), (long) setup_buf.getSize());
|
||||||
printf("%-13s: loader : %8ld bytes\n", getName(), (long) lsize);
|
printf("%-13s: loader : %8ld bytes\n", getName(), (long) lsize);
|
||||||
@@ -220,35 +244,61 @@ void PackVmlinuzI386::pack(OutputFile *fo)
|
|||||||
// bvmlinuz specific
|
// bvmlinuz specific
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
int PackBvmlinuzI386::buildLoader(const Filter *ft)
|
||||||
|
{
|
||||||
|
// prepare loader
|
||||||
|
initLoader(nrv_loader, sizeof(nrv_loader));
|
||||||
|
addLoader("LINUZ000",
|
||||||
|
ft->id ? "LZCALLT1" : "",
|
||||||
|
"LBZIMAGE""IDENTSTR",
|
||||||
|
"+40D++++", // align the stuff to 4 byte boundary
|
||||||
|
"UPX1HEAD", // 32 byte
|
||||||
|
"LZCUTPOI""+0000000",
|
||||||
|
getDecompressor(),
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
if (ft->id)
|
||||||
|
{
|
||||||
|
assert(ft->calls > 0);
|
||||||
|
addLoader("LZCALLT9", NULL);
|
||||||
|
addFilter32(ft->id);
|
||||||
|
}
|
||||||
|
addLoader("LINUZ990", NULL);
|
||||||
|
return getLoaderSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PackBvmlinuzI386::pack(OutputFile *fo)
|
void PackBvmlinuzI386::pack(OutputFile *fo)
|
||||||
{
|
{
|
||||||
readKernel();
|
readKernel();
|
||||||
|
|
||||||
if (!compress(ibuf, obuf))
|
// prepare filter
|
||||||
throwNotCompressible();
|
Filter ft(opt->level);
|
||||||
|
ft.buf_len = ph.u_len;
|
||||||
|
ft.addvalue = kernel_entry;
|
||||||
|
// prepare other settings
|
||||||
|
const unsigned overlap_range = 512;
|
||||||
|
unsigned overlapoh;
|
||||||
|
|
||||||
const unsigned overlapoh = findOverlapOverhead(obuf, 512);
|
int strategy = -1; // try the first working filter
|
||||||
|
if (opt->filter >= 0 && isValidFilter(opt->filter))
|
||||||
|
// try opt->filter or 0 if that fails
|
||||||
|
strategy = -2;
|
||||||
|
else if (opt->all_filters)
|
||||||
|
// choose best from all available filters
|
||||||
|
strategy = 0;
|
||||||
|
compressWithFilters(&ft, &overlapoh, overlap_range, strategy);
|
||||||
|
|
||||||
// align everything to dword boundary - it is easier to handle
|
// align everything to dword boundary - it is easier to handle
|
||||||
unsigned clen = ph.c_len;
|
unsigned clen = ph.c_len;
|
||||||
memset(obuf + clen, 0, 4);
|
memset(obuf + clen, 0, 4);
|
||||||
clen = ALIGN_UP(clen, 4);
|
clen = ALIGN_UP(clen, 4);
|
||||||
|
|
||||||
initLoader(nrv_loader, sizeof(nrv_loader));
|
|
||||||
|
|
||||||
addLoader("LINUZ000""LBZIMAGE""IDENTSTR",
|
|
||||||
"+40D++++", // align the stuff to 4 byte boundary
|
|
||||||
"UPX1HEAD", // 32 byte
|
|
||||||
"LZCUTPOI""+0000000",
|
|
||||||
getDecompressor(),
|
|
||||||
"LINUZ990",
|
|
||||||
NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
const unsigned lsize = getLoaderSize();
|
const unsigned lsize = getLoaderSize();
|
||||||
MemBuffer loader(lsize);
|
MemBuffer loader(lsize);
|
||||||
memcpy(loader, getLoader(), lsize);
|
memcpy(loader, getLoader(), lsize);
|
||||||
|
|
||||||
|
patchFilter32(ft, loader, lsize);
|
||||||
patchPackHeader(loader, lsize);
|
patchPackHeader(loader, lsize);
|
||||||
|
|
||||||
const int e_len = getLoaderSectionStart("LZCUTPOI");
|
const int e_len = getLoaderSectionStart("LZCUTPOI");
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ protected:
|
|||||||
virtual int uncompressKernel();
|
virtual int uncompressKernel();
|
||||||
virtual void readKernel();
|
virtual void readKernel();
|
||||||
|
|
||||||
|
virtual int buildLoader(const Filter *ft);
|
||||||
// virtual const upx_byte *getLoader() const;
|
// virtual const upx_byte *getLoader() const;
|
||||||
// virtual int getLoaderSize() const;
|
// virtual int getLoaderSize() const;
|
||||||
|
|
||||||
@@ -98,6 +99,7 @@ public:
|
|||||||
virtual const char *getName() const { return "bvmlinuz/386"; }
|
virtual const char *getName() const { return "bvmlinuz/386"; }
|
||||||
|
|
||||||
virtual void pack(OutputFile *fo);
|
virtual void pack(OutputFile *fo);
|
||||||
|
virtual int buildLoader(const Filter *ft);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user