mirror of
https://github.com/upx/upx
synced 2025-09-28 19:06:07 +08:00
Option --preserve-build-id for Gnu ELF; contributed by Nicholas Twerdochlib
(SourceForge [ upx-Patches-3413335 ])
This commit is contained in:
parent
57e9b27085
commit
640d5b2dec
|
@ -290,6 +290,11 @@ void show_help(int verbose)
|
|||
" --strip-relocs=0 do not strip relocations\n"
|
||||
" --strip-relocs=1 strip relocations [default]\n"
|
||||
"\n");
|
||||
con_fprintf(f,"Options for linux/elf:\n");
|
||||
fg = con_fg(f,fg);
|
||||
con_fprintf(f,
|
||||
" --preserve-build-id copy .gnu.note.build-id to compressed output\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
con_fprintf(f, "file.. executables to (de)compress\n");
|
||||
|
|
|
@ -898,6 +898,9 @@ static int do_option(int optc, const char *arg)
|
|||
case 674:
|
||||
opt->o_unix.unmap_all_pages = true; // val ?
|
||||
break;
|
||||
case 675:
|
||||
opt->o_unix.preserve_build_id = true;
|
||||
break;
|
||||
|
||||
case '\0':
|
||||
return -1;
|
||||
|
@ -1048,6 +1051,7 @@ static const struct mfx_option longopts[] =
|
|||
{"OpenBSD", 0x10, 0, 669},
|
||||
{"openbsd", 0x10, 0, 669},
|
||||
{"unmap-all-pages", 0x10, 0, 674}, // linux /proc/self/exe vanishes
|
||||
{"preserve-build-id", 0, 0, 675},
|
||||
// watcom/le
|
||||
{"le", 0x10, 0, 620}, // produce LE output
|
||||
// win32/pe
|
||||
|
|
|
@ -146,6 +146,7 @@ struct options_t {
|
|||
unsigned char osabi0; // replacement if 0==.e_ident[EI_OSABI]
|
||||
enum { SCRIPT_MAX = 32 };
|
||||
const char *script_name;
|
||||
bool preserve_build_id; // copy the build-id to the compressed binary
|
||||
} o_unix;
|
||||
struct {
|
||||
bool le;
|
||||
|
|
201
src/p_lx_elf.cpp
201
src/p_lx_elf.cpp
|
@ -51,6 +51,12 @@
|
|||
static unsigned const EF_ARM_EABI_VER4 = 0x04000000;
|
||||
static unsigned const EF_ARM_EABI_VER5 = 0x05000000;
|
||||
|
||||
unsigned char PackLinuxElf::o_shstrtab[] = { \
|
||||
/*start*/ '\0',
|
||||
/*offset 1*/ '.','n','o','t','e','.','g','n','u','.','b','u','i','l','d','-','i','d','\0',
|
||||
/*offset 20*/ '.','s','h','s','t','r','t','a','b','\0'
|
||||
};
|
||||
|
||||
static unsigned
|
||||
umin(unsigned a, unsigned b)
|
||||
{
|
||||
|
@ -180,7 +186,8 @@ PackLinuxElf::PackLinuxElf(InputFile *f)
|
|||
: super(f), e_phnum(0), file_image(NULL), dynstr(NULL),
|
||||
sz_phdrs(0), sz_elf_hdrs(0), sz_pack2(0), sz_pack2a(0), sz_pack2b(0),
|
||||
lg2_page(12), page_size(1u<<lg2_page), xct_off(0), xct_va(0),
|
||||
e_machine(0), ei_class(0), ei_data(0), ei_osabi(0), osabi_note(NULL)
|
||||
e_machine(0), ei_class(0), ei_data(0), ei_osabi(0), osabi_note(NULL),
|
||||
o_elf_shnum(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1141,6 +1148,21 @@ Elf32_Shdr const *PackLinuxElf32::elf_find_section_name(
|
|||
return 0;
|
||||
}
|
||||
|
||||
Elf64_Shdr const *PackLinuxElf64::elf_find_section_name(
|
||||
char const *const name
|
||||
) const
|
||||
{
|
||||
Elf64_Shdr const *shdr = shdri;
|
||||
int j = n_elf_shnum;
|
||||
for (; 0 <=--j; ++shdr) {
|
||||
unsigned ndx = get_te64(&shdr->sh_name);
|
||||
if (0==strcmp(name, &shstrtab[ndx])) {
|
||||
return shdr;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Elf32_Shdr const *PackLinuxElf32::elf_find_section_type(
|
||||
unsigned const type
|
||||
) const
|
||||
|
@ -1652,8 +1674,14 @@ PackLinuxElf32::generateElfHdr(
|
|||
assert(get_te16(&h2->ehdr.e_ehsize) == sizeof(Elf32_Ehdr));
|
||||
assert(get_te16(&h2->ehdr.e_phentsize) == sizeof(Elf32_Phdr));
|
||||
set_te16(&h2->ehdr.e_shentsize, sizeof(Elf32_Shdr));
|
||||
h2->ehdr.e_shnum = 0;
|
||||
h2->ehdr.e_shstrndx = 0;
|
||||
if (o_elf_shnum) {
|
||||
h2->ehdr.e_shnum = o_elf_shnum;
|
||||
h2->ehdr.e_shstrndx = o_elf_shnum - 1;
|
||||
}
|
||||
else {
|
||||
h2->ehdr.e_shnum = 0;
|
||||
h2->ehdr.e_shstrndx = 0;
|
||||
}
|
||||
|
||||
sz_elf_hdrs = sizeof(*h2) - sizeof(linfo); // default
|
||||
set_te32(&h2->phdr[0].p_filesz, sizeof(*h2)); // + identsize;
|
||||
|
@ -1878,8 +1906,14 @@ PackLinuxElf64::generateElfHdr(
|
|||
assert(get_te16(&h2->ehdr.e_ehsize) == sizeof(Elf64_Ehdr));
|
||||
assert(get_te16(&h2->ehdr.e_phentsize) == sizeof(Elf64_Phdr));
|
||||
set_te16(&h2->ehdr.e_shentsize, sizeof(Elf64_Shdr));
|
||||
h2->ehdr.e_shnum = 0;
|
||||
h2->ehdr.e_shstrndx = 0;
|
||||
if (o_elf_shnum) {
|
||||
h2->ehdr.e_shnum = o_elf_shnum;
|
||||
h2->ehdr.e_shstrndx = o_elf_shnum - 1;
|
||||
}
|
||||
else {
|
||||
h2->ehdr.e_shnum = 0;
|
||||
h2->ehdr.e_shstrndx = 0;
|
||||
}
|
||||
|
||||
sz_elf_hdrs = sizeof(*h2) - sizeof(linfo); // default
|
||||
set_te64(&h2->phdr[0].p_filesz, sizeof(*h2)); // + identsize;
|
||||
|
@ -1965,6 +1999,65 @@ void PackLinuxElf32::pack1(OutputFile *fo, Filter & /*ft*/)
|
|||
memset(&linfo, 0, sizeof(linfo));
|
||||
fo->write(&linfo, sizeof(linfo));
|
||||
}
|
||||
|
||||
// if the preserve build-id option was specified
|
||||
if (opt->o_unix.preserve_build_id) {
|
||||
n_elf_shnum = ehdri.e_shnum;
|
||||
Elf32_Shdr *shdr = NULL;
|
||||
|
||||
Elf32_Shdr const *tmp = shdri;
|
||||
|
||||
if (! shdri) {
|
||||
shdr = new Elf32_Shdr[n_elf_shnum];
|
||||
|
||||
fi->seek(0,SEEK_SET);
|
||||
fi->seek(ehdri.e_shoff,SEEK_SET);
|
||||
fi->readx((void*)shdr,ehdri.e_shentsize*ehdri.e_shnum);
|
||||
|
||||
// set this so we can use elf_find_section_name
|
||||
shdri = (Elf32_Shdr * const)shdr;
|
||||
}
|
||||
|
||||
//set the shstrtab
|
||||
sec_strndx = &shdr[ehdri.e_shstrndx];
|
||||
|
||||
char *strtab = new char[sec_strndx->sh_size];
|
||||
fi->seek(0,SEEK_SET);
|
||||
fi->seek(sec_strndx->sh_offset,SEEK_SET);
|
||||
fi->readx(strtab,sec_strndx->sh_size);
|
||||
|
||||
shstrtab = (const char*)strtab;
|
||||
|
||||
Elf32_Shdr const *buildid = elf_find_section_name(".note.gnu.build-id");
|
||||
if (buildid) {
|
||||
unsigned char *data = new unsigned char[buildid->sh_size];
|
||||
memset(data,0,buildid->sh_size);
|
||||
fi->seek(0,SEEK_SET);
|
||||
fi->seek(buildid->sh_offset,SEEK_SET);
|
||||
fi->readx(data,buildid->sh_size);
|
||||
|
||||
buildid_data = data;
|
||||
|
||||
o_elf_shnum = 3;
|
||||
memset(&shdrout.shdr,0,sizeof(shdrout));
|
||||
|
||||
//setup the build-id
|
||||
memcpy(&shdrout.shdr[1],buildid, sizeof(shdrout.shdr[1]));
|
||||
shdrout.shdr[1].sh_name = 1;
|
||||
|
||||
//setup the shstrtab
|
||||
memcpy(&shdrout.shdr[2],sec_strndx, sizeof(shdrout.shdr[2]));
|
||||
shdrout.shdr[2].sh_name = 20;
|
||||
shdrout.shdr[2].sh_size = 29; //size of our static shstrtab
|
||||
}
|
||||
|
||||
// repoint shdr in case it is used by code some where else
|
||||
if (shdr) {
|
||||
shdri = tmp;
|
||||
delete [] shdr;
|
||||
shdr = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PackLinuxElf32x86::pack1(OutputFile *fo, Filter &ft)
|
||||
|
@ -2094,6 +2187,68 @@ void PackLinuxElf64::pack1(OutputFile *fo, Filter & /*ft*/)
|
|||
memset(&linfo, 0, sizeof(linfo));
|
||||
fo->write(&linfo, sizeof(linfo));
|
||||
}
|
||||
|
||||
// only execute if option present
|
||||
if (opt->o_unix.preserve_build_id) {
|
||||
// set this so we can use elf_find_section_name
|
||||
n_elf_shnum = ehdri.e_shnum;
|
||||
|
||||
// there is a class member similar to this, but I did not
|
||||
// want to assume it would be available
|
||||
Elf64_Shdr const *tmp = shdri;
|
||||
|
||||
Elf64_Shdr *shdr = NULL;
|
||||
|
||||
if (! shdri) {
|
||||
shdr = new Elf64_Shdr[n_elf_shnum];
|
||||
|
||||
fi->seek(0,SEEK_SET);
|
||||
fi->seek(ehdri.e_shoff,SEEK_SET);
|
||||
fi->readx((void*)shdr,ehdri.e_shentsize*ehdri.e_shnum);
|
||||
|
||||
// set this so we can use elf_find_section_name
|
||||
shdri = (Elf64_Shdr * const)shdr;
|
||||
}
|
||||
|
||||
//set the shstrtab
|
||||
sec_strndx = &shdri[ehdri.e_shstrndx];
|
||||
|
||||
char *strtab = new char[sec_strndx->sh_size];
|
||||
fi->seek(0,SEEK_SET);
|
||||
fi->seek(sec_strndx->sh_offset,SEEK_SET);
|
||||
fi->readx(strtab,sec_strndx->sh_size);
|
||||
|
||||
shstrtab = (const char*)strtab;
|
||||
|
||||
Elf64_Shdr const *buildid = elf_find_section_name(".note.gnu.build-id");
|
||||
if (buildid) {
|
||||
unsigned char *data = new unsigned char[buildid->sh_size];
|
||||
memset(data,0,buildid->sh_size);
|
||||
fi->seek(0,SEEK_SET);
|
||||
fi->seek(buildid->sh_offset,SEEK_SET);
|
||||
fi->readx(data,buildid->sh_size);
|
||||
|
||||
buildid_data = data;
|
||||
|
||||
o_elf_shnum = 3;
|
||||
memset(&shdrout.shdr,0,sizeof(shdrout));
|
||||
|
||||
//setup the build-id
|
||||
memcpy(&shdrout.shdr[1],buildid, sizeof(shdrout.shdr[1]));
|
||||
shdrout.shdr[1].sh_name = 1;
|
||||
|
||||
//setup the shstrtab
|
||||
memcpy(&shdrout.shdr[2],sec_strndx, sizeof(shdrout.shdr[2]));
|
||||
shdrout.shdr[2].sh_name = 20;
|
||||
shdrout.shdr[2].sh_size = 29; //size of our static shstrtab
|
||||
}
|
||||
|
||||
if (shdr) {
|
||||
shdri = tmp;
|
||||
delete [] shdr;
|
||||
shdr = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PackLinuxElf64amd::pack1(OutputFile *fo, Filter &ft)
|
||||
|
@ -2601,6 +2756,24 @@ void PackLinuxElf32::pack4(OutputFile *fo, Filter &ft)
|
|||
{
|
||||
overlay_offset = sz_elf_hdrs + sizeof(linfo);
|
||||
|
||||
if (opt->o_unix.preserve_build_id) {
|
||||
// calc e_shoff here and write shdrout, then o_shstrtab
|
||||
//NOTE: these are pushed last to ensure nothing is stepped on
|
||||
//for the UPX structure.
|
||||
unsigned const len = fpad4(fo);
|
||||
set_te32(&elfout.ehdr.e_shoff,len);
|
||||
|
||||
int const ssize = sizeof(shdrout);
|
||||
|
||||
shdrout.shdr[2].sh_offset = len+ssize;
|
||||
shdrout.shdr[1].sh_offset = shdrout.shdr[2].sh_offset+shdrout.shdr[2].sh_size;
|
||||
|
||||
fo->write(&shdrout, ssize);
|
||||
|
||||
fo->write(o_shstrtab,shdrout.shdr[2].sh_size);
|
||||
fo->write(buildid_data,shdrout.shdr[1].sh_size);
|
||||
}
|
||||
|
||||
// Cannot pre-round .p_memsz. If .p_filesz < .p_memsz, then kernel
|
||||
// tries to make .bss, which requires PF_W.
|
||||
// But strict SELinux (or PaX, grSecurity) disallows PF_W with PF_X.
|
||||
|
@ -2650,6 +2823,24 @@ void PackLinuxElf64::pack4(OutputFile *fo, Filter &ft)
|
|||
{
|
||||
overlay_offset = sz_elf_hdrs + sizeof(linfo);
|
||||
|
||||
if (opt->o_unix.preserve_build_id) {
|
||||
// calc e_shoff here and write shdrout, then o_shstrtab
|
||||
//NOTE: these are pushed last to ensure nothing is stepped on
|
||||
//for the UPX structure.
|
||||
unsigned const len = fpad4(fo);
|
||||
set_te64(&elfout.ehdr.e_shoff,len);
|
||||
|
||||
int const ssize = sizeof(shdrout);
|
||||
|
||||
shdrout.shdr[2].sh_offset = len+ssize;
|
||||
shdrout.shdr[1].sh_offset = shdrout.shdr[2].sh_offset+shdrout.shdr[2].sh_size;
|
||||
|
||||
fo->write(&shdrout, ssize);
|
||||
|
||||
fo->write(o_shstrtab,shdrout.shdr[2].sh_size);
|
||||
fo->write(buildid_data,shdrout.shdr[1].sh_size);
|
||||
}
|
||||
|
||||
// Cannot pre-round .p_memsz. If .p_filesz < .p_memsz, then kernel
|
||||
// tries to make .bss, which requires PF_W.
|
||||
// But strict SELinux (or PaX, grSecurity) disallows PF_W with PF_X.
|
||||
|
|
|
@ -88,6 +88,10 @@ protected:
|
|||
unsigned char ei_data;
|
||||
unsigned char ei_osabi;
|
||||
char const *osabi_note;
|
||||
|
||||
unsigned char const *buildid_data;
|
||||
int o_elf_shnum; // num output Shdrs
|
||||
static unsigned char o_shstrtab[];
|
||||
};
|
||||
|
||||
class PackLinuxElf32 : public PackLinuxElf
|
||||
|
@ -186,6 +190,12 @@ protected:
|
|||
|
||||
cprElfHdrNetBSD elfout;
|
||||
|
||||
__packed_struct(cprElfShdr3)
|
||||
Elf32_Shdr shdr[3];
|
||||
__packed_struct_end();
|
||||
|
||||
cprElfShdr3 shdrout;
|
||||
|
||||
struct Elf32_Nhdr {
|
||||
unsigned namesz;
|
||||
unsigned descsz;
|
||||
|
@ -293,6 +303,12 @@ protected:
|
|||
|
||||
cprElfHdr4 elfout;
|
||||
|
||||
__packed_struct(cprElfShdr3)
|
||||
Elf64_Shdr shdr[3];
|
||||
__packed_struct_end();
|
||||
|
||||
cprElfShdr3 shdrout;
|
||||
|
||||
static void compileTimeAssertions() {
|
||||
COMPILE_TIME_ASSERT(sizeof(cprElfHdr1) == 64 + 1*56 + 12)
|
||||
COMPILE_TIME_ASSERT(sizeof(cprElfHdr2) == 64 + 2*56 + 12)
|
||||
|
|
Loading…
Reference in New Issue
Block a user