vmlinux/386 check for __ksymtab; fix unpack

This commit is contained in:
John Reiser
2006-10-15 14:51:02 -07:00
parent 2b122562ad
commit 452a953234
2 changed files with 67 additions and 40 deletions
+55 -30
View File
@@ -46,12 +46,13 @@ static const
**************************************************************************/ **************************************************************************/
PackVmlinuxI386::PackVmlinuxI386(InputFile *f) : PackVmlinuxI386::PackVmlinuxI386(InputFile *f) :
super(f), n_ptload(0), phdri(NULL), shdri(NULL) super(f), n_ptload(0), phdri(NULL), shdri(NULL), shstrtab(NULL)
{ {
} }
PackVmlinuxI386::~PackVmlinuxI386() PackVmlinuxI386::~PackVmlinuxI386()
{ {
delete [] shstrtab;
delete [] phdri; delete [] phdri;
delete [] shdri; delete [] shdri;
} }
@@ -81,6 +82,34 @@ int PackVmlinuxI386::getStrategy(Filter &/*ft*/)
return (opt->no_filter ? -3 : ((opt->filter > 0) ? -2 : 2)); return (opt->no_filter ? -3 : ((opt->filter > 0) ? -2 : 2));
} }
Elf_LE32_Shdr const *
PackVmlinuxI386::getElfSections()
{
Elf_LE32_Shdr const *p, *shstrsec=0;
shdri = new Elf_LE32_Shdr[(unsigned) ehdri.e_shnum];
fi->seek(ehdri.e_shoff, SEEK_SET);
fi->readx(shdri, ehdri.e_shnum * sizeof(*shdri));
int j;
for (p = shdri, j= ehdri.e_shnum; --j>=0; ++p) {
if (Elf32_Shdr::SHT_STRTAB==p->sh_type
&& (p->sh_size + p->sh_offset) <= (unsigned) file_size
&& (10+ p->sh_name) <= p->sh_size // 1+ strlen(".shstrtab")
) {
delete [] shstrtab;
shstrtab = new char[1+ p->sh_size];
fi->seek(p->sh_offset, SEEK_SET);
fi->readx(shstrtab, p->sh_size);
shstrtab[p->sh_size] = '\0';
if (0==strcmp(".shstrtab", shstrtab + p->sh_name)) {
shstrsec = p;
break;
}
}
}
return shstrsec;
}
static int __acc_cdecl_qsort static int __acc_cdecl_qsort
compare_Phdr(void const *aa, void const *bb) compare_Phdr(void const *aa, void const *bb)
{ {
@@ -143,6 +172,22 @@ bool PackVmlinuxI386::canPack()
return false; return false;
} }
// A Linux kernel must have a __ksymtab section. [??]
Elf_LE32_Shdr const *p, *const shstrsec = getElfSections();
if (0==shstrsec) {
return false;
}
int j;
for (p = shdri, j= ehdri.e_shnum; --j>=0; ++p) {
if (Elf32_Shdr::SHT_PROGBITS==p->sh_type
&& 0==strcmp("__ksymtab", p->sh_name + shstrtab)) {
break;
}
}
if (j < 0) {
return false;
}
phdri = new Elf_LE32_Phdr[(unsigned) ehdri.e_phnum]; phdri = new Elf_LE32_Phdr[(unsigned) ehdri.e_phnum];
fi->seek(ehdri.e_phoff, SEEK_SET); fi->seek(ehdri.e_phoff, SEEK_SET);
fi->readx(phdri, ehdri.e_phnum * sizeof(*phdri)); fi->readx(phdri, ehdri.e_phnum * sizeof(*phdri));
@@ -220,6 +265,8 @@ static bool defineFilterSymbols(Linker *linker, const Filter *ft)
return true; return true;
} }
static const
#include "stub/i386-linux.kernel.head-vmlinux.h"
void PackVmlinuxI386::pack(OutputFile *fo) void PackVmlinuxI386::pack(OutputFile *fo)
{ {
@@ -284,13 +331,9 @@ void PackVmlinuxI386::pack(OutputFile *fo)
shdro[1].sh_type = Elf32_Shdr::SHT_PROGBITS; shdro[1].sh_type = Elf32_Shdr::SHT_PROGBITS;
shdro[1].sh_flags = Elf32_Shdr::SHF_ALLOC | Elf32_Shdr::SHF_EXECINSTR; shdro[1].sh_flags = Elf32_Shdr::SHF_ALLOC | Elf32_Shdr::SHF_EXECINSTR;
shdro[1].sh_offset = fo_off; shdro[1].sh_offset = fo_off;
shdro[1].sh_size = 1+ 4+ ph.c_len + lsize; shdro[1].sh_size = sizeof(head_stack) + ph.c_len + lsize;
shdro[1].sh_addralign = 1; shdro[1].sh_addralign = 1;
{
static const
#include "stub/i386-linux.kernel.head-vmlinux.h"
// ENTRY_POINT // ENTRY_POINT
fo->write(&head_stack[0], sizeof(head_stack)-2*(1+ 4) +1); fo->write(&head_stack[0], sizeof(head_stack)-2*(1+ 4) +1);
tmp_le32 = ehdri.e_entry; fo->write(&tmp_le32, 4); tmp_le32 = ehdri.e_entry; fo->write(&tmp_le32, 4);
@@ -303,7 +346,6 @@ void PackVmlinuxI386::pack(OutputFile *fo)
fo->write(obuf, ph.c_len); fo_off += ph.c_len; fo->write(obuf, ph.c_len); fo_off += ph.c_len;
fo->write(loader, lsize); fo_off += lsize; fo->write(loader, lsize); fo_off += lsize;
}
#if 0 #if 0
printf("%-13s: compressed : %8u bytes\n", getName(), ph.c_len); printf("%-13s: compressed : %8u bytes\n", getName(), ph.c_len);
@@ -416,35 +458,18 @@ int PackVmlinuxI386::canUnpack()
return false; return false;
// find the .shstrtab section // find the .shstrtab section
char shstrtab[40]; Elf_LE32_Shdr const *const shstrsec = getElfSections();
Elf_LE32_Shdr *p, *p_shstrtab=0; if (0==shstrsec) {
shdri = new Elf_LE32_Shdr[(unsigned) ehdri.e_shnum];
fi->seek(ehdri.e_shoff, SEEK_SET);
fi->readx(shdri, ehdri.e_shnum * sizeof(*shdri));
int j;
for (p = shdri, j= ehdri.e_shnum; --j>=0; ++p) {
if (Elf32_Shdr::SHT_STRTAB==p->sh_type
&& p->sh_size <= sizeof(shstrtab)
&& (p->sh_size + p->sh_offset) <= (unsigned) file_size
&& (10+ p->sh_name) <= p->sh_size // 1+ strlen(".shstrtab")
) {
fi->seek(p->sh_offset, SEEK_SET);
fi->readx(shstrtab, p->sh_size);
if (0==strcmp(".shstrtab", shstrtab + p->sh_name)) {
p_shstrtab = p;
break;
}
}
}
if (0==p_shstrtab) {
return false; return false;
} }
// check for .text .note .note and sane (.sh_size + .sh_offset) // check for .text .note .note and sane (.sh_size + .sh_offset)
p_note0 = p_note1 = p_text = 0; p_note0 = p_note1 = p_text = 0;
int j;
Elf_LE32_Shdr *p;
for (p= shdri, j= ehdri.e_shnum; --j>=0; ++p) { for (p= shdri, j= ehdri.e_shnum; --j>=0; ++p) {
if ((unsigned)file_size < (p->sh_size + p->sh_offset) if ((unsigned)file_size < (p->sh_size + p->sh_offset)
|| p_shstrtab->sh_size < (5+ p->sh_name) ) { || shstrsec->sh_size < (5+ p->sh_name) ) {
continue; continue;
} }
if (0==strcmp(".text", shstrtab + p->sh_name)) { if (0==strcmp(".text", shstrtab + p->sh_name)) {
@@ -491,7 +516,7 @@ void PackVmlinuxI386::unpack(OutputFile *fo)
ibuf.dealloc(); ibuf.dealloc();
ph = ph_tmp; ph = ph_tmp;
fi->seek(p_text->sh_offset, SEEK_SET); fi->seek(p_text->sh_offset + sizeof(head_stack) -5, SEEK_SET);
fi->readx(&buf[0], 5); fi->readx(&buf[0], 5);
if (0xE8!=buf[0] || get_le32(&buf[1]) != ph.c_len) if (0xE8!=buf[0] || get_le32(&buf[1]) != ph.c_len)
{ {
+2
View File
@@ -55,6 +55,7 @@ public:
virtual int canUnpack(); virtual int canUnpack();
protected: protected:
virtual Elf_LE32_Shdr const *getElfSections();
virtual int buildLoader(const Filter *ft); virtual int buildLoader(const Filter *ft);
virtual Linker* newLinker() const; virtual Linker* newLinker() const;
// virtual const upx_byte *getLoader() const; // virtual const upx_byte *getLoader() const;
@@ -64,6 +65,7 @@ protected:
unsigned sz_ptload; unsigned sz_ptload;
Elf_LE32_Phdr *phdri; // from input file Elf_LE32_Phdr *phdri; // from input file
Elf_LE32_Shdr *shdri; // from input file Elf_LE32_Shdr *shdri; // from input file
char *shstrtab; // from input file
Elf_LE32_Shdr *p_text; Elf_LE32_Shdr *p_text;
Elf_LE32_Shdr *p_note0; Elf_LE32_Shdr *p_note0;
Elf_LE32_Shdr *p_note1; Elf_LE32_Shdr *p_note1;