mirror of
https://github.com/upx/upx
synced 2025-09-28 19:06:07 +08:00
i386-darwin.dylib requires existing LC_ROUINTES command;
decompressor must not overwrite Mach_headers.
This commit is contained in:
parent
84ac771893
commit
3e8d072d24
123
src/p_mach.cpp
123
src/p_mach.cpp
|
@ -68,7 +68,7 @@ PackMachBase<T>::PackMachBase(InputFile *f, unsigned cputype, unsigned filetype,
|
||||||
unsigned flavor, unsigned count, unsigned size) :
|
unsigned flavor, unsigned count, unsigned size) :
|
||||||
super(f), my_cputype(cputype), my_filetype(filetype), my_thread_flavor(flavor),
|
super(f), my_cputype(cputype), my_filetype(filetype), my_thread_flavor(flavor),
|
||||||
my_thread_state_word_count(count), my_thread_command_size(size),
|
my_thread_state_word_count(count), my_thread_command_size(size),
|
||||||
n_segment(0), rawmseg(NULL), msegcmd(NULL)
|
n_segment(0), rawmseg(NULL), msegcmd(NULL), o_routines_cmd(0)
|
||||||
{
|
{
|
||||||
MachClass::compileTimeAssertions();
|
MachClass::compileTimeAssertions();
|
||||||
bele = N_BELE_CTP::getRTP((const BeLePolicy*) NULL);
|
bele = N_BELE_CTP::getRTP((const BeLePolicy*) NULL);
|
||||||
|
@ -81,6 +81,11 @@ PackMachBase<T>::~PackMachBase()
|
||||||
delete [] msegcmd;
|
delete [] msegcmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PackDylibI386::PackDylibI386(InputFile *f) : super(f)
|
||||||
|
{
|
||||||
|
my_filetype = Mach_header::MH_DYLIB;
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
const int *PackMachBase<T>::getCompressionMethods(int method, int level) const
|
const int *PackMachBase<T>::getCompressionMethods(int method, int level) const
|
||||||
{
|
{
|
||||||
|
@ -397,19 +402,14 @@ void PackMachARMEL::pack4(OutputFile *fo, Filter &ft) // append PackHeader
|
||||||
|
|
||||||
void PackDylibI386::pack4(OutputFile *fo, Filter &ft) // append PackHeader
|
void PackDylibI386::pack4(OutputFile *fo, Filter &ft) // append PackHeader
|
||||||
{
|
{
|
||||||
unsigned opos = fo->getBytesWritten();
|
|
||||||
segcmdo.filesize = opos;
|
|
||||||
segcmdo.vmsize = msegcmd->vmsize;
|
|
||||||
rcmd.init_address = threado.state.eip;
|
rcmd.init_address = threado.state.eip;
|
||||||
fo->seek(sizeof(mhdro), SEEK_SET);
|
unsigned opos = sizeof(mhdro);
|
||||||
fo->rewrite(&segcmdo, sizeof(segcmdo));
|
fo->seek(opos, SEEK_SET);
|
||||||
fo->seek(sizeof(mhdro) + mhdro.sizeofcmds - sizeof(rcmd), SEEK_SET);
|
|
||||||
fo->rewrite(&rcmd, sizeof(rcmd));
|
|
||||||
fo->rewrite(&linfo, sizeof(linfo));
|
|
||||||
|
|
||||||
// Append each non-__TEXT segment, page aligned.
|
// Append each non-__TEXT segment, page aligned.
|
||||||
int slide = 0;
|
int slide = 0;
|
||||||
unsigned hdrpos = sizeof(mhdro) + sizeof(segcmdo);
|
unsigned o_end_txt = 0;
|
||||||
|
unsigned hdrpos = sizeof(mhdro);
|
||||||
Mach_segment_command const *seg = rawmseg;
|
Mach_segment_command const *seg = rawmseg;
|
||||||
Mach_segment_command const *const endseg =
|
Mach_segment_command const *const endseg =
|
||||||
(Mach_segment_command const *)(mhdri.sizeofcmds + (char const *)seg);
|
(Mach_segment_command const *)(mhdri.sizeofcmds + (char const *)seg);
|
||||||
|
@ -424,7 +424,6 @@ void PackDylibI386::pack4(OutputFile *fo, Filter &ft) // append PackHeader
|
||||||
case Mach_segment_command::LC_LOAD_DYLIB:
|
case Mach_segment_command::LC_LOAD_DYLIB:
|
||||||
case Mach_segment_command::LC_ID_DYLIB:
|
case Mach_segment_command::LC_ID_DYLIB:
|
||||||
case Mach_segment_command::LC_LOAD_DYLINKER:
|
case Mach_segment_command::LC_LOAD_DYLINKER:
|
||||||
case Mach_segment_command::LC_ROUTINES:
|
|
||||||
case Mach_segment_command::LC_SEGMENT_64:
|
case Mach_segment_command::LC_SEGMENT_64:
|
||||||
case Mach_segment_command::LC_ROUTINES_64:
|
case Mach_segment_command::LC_ROUTINES_64:
|
||||||
case Mach_segment_command::LC_UUID:
|
case Mach_segment_command::LC_UUID:
|
||||||
|
@ -433,13 +432,31 @@ void PackDylibI386::pack4(OutputFile *fo, Filter &ft) // append PackHeader
|
||||||
case Mach_segment_command::LC_REEXPORT_DYLIB:
|
case Mach_segment_command::LC_REEXPORT_DYLIB:
|
||||||
hdrpos += seg->cmdsize;
|
hdrpos += seg->cmdsize;
|
||||||
break; // contain no file offset fields
|
break; // contain no file offset fields
|
||||||
|
case Mach_segment_command::LC_ROUTINES: {
|
||||||
|
Mach_routines_command cmd = *(Mach_routines_command const *)seg;
|
||||||
|
cmd.reserved1 = cmd.init_address;
|
||||||
|
cmd.init_address = threado.state.eip;
|
||||||
|
fo->seek(hdrpos, SEEK_SET);
|
||||||
|
fo->rewrite(&cmd, sizeof(cmd));
|
||||||
|
hdrpos += sizeof(cmd);
|
||||||
|
} break;
|
||||||
case Mach_segment_command::LC_SEGMENT: {
|
case Mach_segment_command::LC_SEGMENT: {
|
||||||
// non-__TEXT might be observed and relocated by dyld before us.
|
// non-__TEXT might be observed and relocated by dyld before us.
|
||||||
if (0!=strncmp(&seg->segname[0], "__TEXT", 1+ 6)) {
|
Mach_segment_command segcmdtmp = *seg;
|
||||||
Mach_segment_command segcmdtmp = *seg;
|
bool const is_text = 0==strncmp(&seg->segname[0], "__TEXT", 1+ 6);
|
||||||
opos += ~PAGE_MASK & (0u - opos); // advance to PAGE_SIZE boundary
|
{
|
||||||
slide = opos - segcmdtmp.fileoff;
|
if (is_text) {
|
||||||
segcmdtmp.fileoff = opos;
|
slide = 0;
|
||||||
|
segcmdtmp.filesize = fo->getBytesWritten();
|
||||||
|
segcmdtmp.maxprot |= Mach_segment_command::VM_PROT_WRITE;
|
||||||
|
segcmdtmp.initprot |= Mach_segment_command::VM_PROT_WRITE;
|
||||||
|
o_end_txt = segcmdtmp.filesize + segcmdtmp.fileoff;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
opos += ~PAGE_MASK & (0u - opos); // advance to PAGE_SIZE boundary
|
||||||
|
slide = opos - segcmdtmp.fileoff;
|
||||||
|
segcmdtmp.fileoff = opos;
|
||||||
|
}
|
||||||
|
|
||||||
fo->seek(hdrpos, SEEK_SET);
|
fo->seek(hdrpos, SEEK_SET);
|
||||||
fo->rewrite(&segcmdtmp, sizeof(segcmdtmp));
|
fo->rewrite(&segcmdtmp, sizeof(segcmdtmp));
|
||||||
|
@ -459,38 +476,40 @@ void PackDylibI386::pack4(OutputFile *fo, Filter &ft) // append PackHeader
|
||||||
hdrpos += sizeof(seccmdtmp);
|
hdrpos += sizeof(seccmdtmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
fo->seek(opos, SEEK_SET);
|
if (!is_text) {
|
||||||
fi->seek(seg->fileoff, SEEK_SET);
|
fo->seek(opos, SEEK_SET);
|
||||||
unsigned const len = seg->filesize;
|
fi->seek(seg->fileoff, SEEK_SET);
|
||||||
char data[len];
|
unsigned const len = seg->filesize;
|
||||||
fi->readx(data, len);
|
char data[len];
|
||||||
fo->write(data, len);
|
fi->readx(data, len);
|
||||||
opos += len;
|
fo->write(data, len);
|
||||||
|
opos += len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case Mach_segment_command::LC_SYMTAB: {
|
case Mach_segment_command::LC_SYMTAB: {
|
||||||
Mach_symtab_command cmd = *(Mach_symtab_command const *)seg;
|
Mach_symtab_command cmd = *(Mach_symtab_command const *)seg;
|
||||||
if (opos < cmd.symoff) { cmd.symoff += slide; }
|
if (o_end_txt <= cmd.symoff) { cmd.symoff += slide; }
|
||||||
if (opos < cmd.stroff) { cmd.stroff += slide; }
|
if (o_end_txt <= cmd.stroff) { cmd.stroff += slide; }
|
||||||
fo->seek(hdrpos, SEEK_SET);
|
fo->seek(hdrpos, SEEK_SET);
|
||||||
fo->rewrite(&cmd, sizeof(cmd));
|
fo->rewrite(&cmd, sizeof(cmd));
|
||||||
hdrpos += sizeof(cmd);
|
hdrpos += sizeof(cmd);
|
||||||
} break;
|
} break;
|
||||||
case Mach_segment_command::LC_DYSYMTAB: {
|
case Mach_segment_command::LC_DYSYMTAB: {
|
||||||
Mach_dysymtab_command cmd = *(Mach_dysymtab_command const *)seg;
|
Mach_dysymtab_command cmd = *(Mach_dysymtab_command const *)seg;
|
||||||
if (opos < cmd.tocoff) { cmd.tocoff += slide; }
|
if (o_end_txt <= cmd.tocoff) { cmd.tocoff += slide; }
|
||||||
if (opos < cmd.modtaboff) { cmd.modtaboff += slide; }
|
if (o_end_txt <= cmd.modtaboff) { cmd.modtaboff += slide; }
|
||||||
if (opos < cmd.nextrefsymoff) { cmd.extrefsymoff += slide; }
|
if (o_end_txt <= cmd.extrefsymoff) { cmd.extrefsymoff += slide; }
|
||||||
if (opos < cmd.indirectsymoff) { cmd.indirectsymoff += slide; }
|
if (o_end_txt <= cmd.indirectsymoff) { cmd.indirectsymoff += slide; }
|
||||||
if (opos < cmd.extreloff) { cmd.extreloff += slide; }
|
if (o_end_txt <= cmd.extreloff) { cmd.extreloff += slide; }
|
||||||
if (opos < cmd.locreloff) { cmd.locreloff += slide; }
|
if (o_end_txt <= cmd.locreloff) { cmd.locreloff += slide; }
|
||||||
fo->seek(hdrpos, SEEK_SET);
|
fo->seek(hdrpos, SEEK_SET);
|
||||||
fo->rewrite(&cmd, sizeof(cmd));
|
fo->rewrite(&cmd, sizeof(cmd));
|
||||||
hdrpos += sizeof(cmd);
|
hdrpos += sizeof(cmd);
|
||||||
} break;
|
} break;
|
||||||
case Mach_segment_command::LC_SEGMENT_SPLIT_INFO: {
|
case Mach_segment_command::LC_SEGMENT_SPLIT_INFO: {
|
||||||
Mach_segsplit_info_command cmd = *(Mach_segsplit_info_command const *)seg;
|
Mach_segsplit_info_command cmd = *(Mach_segsplit_info_command const *)seg;
|
||||||
if (opos < cmd.dataoff) { cmd.dataoff += slide; }
|
if (o_end_txt <= cmd.dataoff) { cmd.dataoff += slide; }
|
||||||
fo->seek(hdrpos, SEEK_SET);
|
fo->seek(hdrpos, SEEK_SET);
|
||||||
fo->rewrite(&cmd, sizeof(cmd));
|
fo->rewrite(&cmd, sizeof(cmd));
|
||||||
hdrpos += sizeof(cmd);
|
hdrpos += sizeof(cmd);
|
||||||
|
@ -734,24 +753,6 @@ void PackMachBase<T>::pack1(OutputFile *const fo, Filter &/*ft*/) // generate e
|
||||||
mhdro.sizeofcmds = sizeof(segcmdo) + my_thread_command_size;
|
mhdro.sizeofcmds = sizeof(segcmdo) + my_thread_command_size;
|
||||||
mhdro.flags = Mach_header::MH_NOUNDEFS;
|
mhdro.flags = Mach_header::MH_NOUNDEFS;
|
||||||
}
|
}
|
||||||
if (my_filetype==Mach_header::MH_DYLIB) {
|
|
||||||
mhdro.ncmds += 2; /* new __TEXT, added LC_ROUTINES */
|
|
||||||
mhdro.sizeofcmds += sizeof(segcmdo) + sizeof(rcmd);
|
|
||||||
Mach_segment_command const *seg = rawmseg;
|
|
||||||
Mach_segment_command const *const endseg =
|
|
||||||
(Mach_segment_command const *)(mhdri.sizeofcmds + (char const *)seg);
|
|
||||||
for (; seg < endseg; seg = (Mach_segment_command const *)(
|
|
||||||
seg->cmdsize + (char const *)seg))
|
|
||||||
switch (~Mach_segment_command::LC_REQ_DYLD & seg->cmd) {
|
|
||||||
case Mach_segment_command::LC_SEGMENT: {
|
|
||||||
// Old __TEXT will be replaced by new __TEXT.
|
|
||||||
if (0==strncmp(&seg->segname[0], "__TEXT", 1+ 6)) {
|
|
||||||
mhdro.ncmds -= 1;
|
|
||||||
mhdro.sizeofcmds -= seg->cmdsize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // end 'switch'
|
|
||||||
}
|
|
||||||
fo->write(&mhdro, sizeof(mhdro));
|
fo->write(&mhdro, sizeof(mhdro));
|
||||||
|
|
||||||
segcmdo.cmd = Mach_segment_command::LC_SEGMENT;
|
segcmdo.cmd = Mach_segment_command::LC_SEGMENT;
|
||||||
|
@ -773,7 +774,9 @@ void PackMachBase<T>::pack1(OutputFile *const fo, Filter &/*ft*/) // generate e
|
||||||
Mach_segment_command::VM_PROT_EXECUTE;
|
Mach_segment_command::VM_PROT_EXECUTE;
|
||||||
segcmdo.nsects = 0;
|
segcmdo.nsects = 0;
|
||||||
segcmdo.flags = 0;
|
segcmdo.flags = 0;
|
||||||
fo->write(&segcmdo, sizeof(segcmdo));
|
if (my_filetype==Mach_header::MH_EXECUTE) {
|
||||||
|
fo->write(&segcmdo, sizeof(segcmdo));
|
||||||
|
}
|
||||||
|
|
||||||
if (my_filetype==Mach_header::MH_EXECUTE) {
|
if (my_filetype==Mach_header::MH_EXECUTE) {
|
||||||
pack1_setup_threado(fo);
|
pack1_setup_threado(fo);
|
||||||
|
@ -789,15 +792,15 @@ void PackMachBase<T>::pack1(OutputFile *const fo, Filter &/*ft*/) // generate e
|
||||||
fo->write(seg, seg->cmdsize);
|
fo->write(seg, seg->cmdsize);
|
||||||
} break;
|
} break;
|
||||||
case Mach_segment_command::LC_SEGMENT: {
|
case Mach_segment_command::LC_SEGMENT: {
|
||||||
if (0!=strncmp(&seg->segname[0], "__TEXT", 1+ 6)) {
|
//if (0!=strncmp(&seg->segname[0], "__TEXT", 1+ 6)) {
|
||||||
fo->write(seg, seg->cmdsize);
|
fo->write(seg, seg->cmdsize);
|
||||||
}
|
//}
|
||||||
} break;
|
} break;
|
||||||
} // end 'switch'
|
} // end 'switch'
|
||||||
memset(&rcmd, 0, sizeof(rcmd));
|
memset(&rcmd, 0, sizeof(rcmd));
|
||||||
rcmd.cmd= Mach_segment_command::LC_ROUTINES;
|
rcmd.cmd= Mach_segment_command::LC_ROUTINES;
|
||||||
rcmd.cmdsize = sizeof(rcmd);
|
rcmd.cmdsize = sizeof(rcmd);
|
||||||
fo->write(&rcmd, sizeof(rcmd));
|
//fo->write(&rcmd, sizeof(rcmd));
|
||||||
}
|
}
|
||||||
sz_mach_headers = fo->getBytesWritten();
|
sz_mach_headers = fo->getBytesWritten();
|
||||||
|
|
||||||
|
@ -897,12 +900,18 @@ bool PackMachBase<T>::canPack()
|
||||||
fi->readx(rawmseg, mhdri.sizeofcmds);
|
fi->readx(rawmseg, mhdri.sizeofcmds);
|
||||||
|
|
||||||
msegcmd = new Mach_segment_command[(unsigned) mhdri.ncmds];
|
msegcmd = new Mach_segment_command[(unsigned) mhdri.ncmds];
|
||||||
unsigned char *ptr = (unsigned char *)rawmseg;
|
unsigned char const *ptr = (unsigned char const *)rawmseg;
|
||||||
for (unsigned j= 0; j < mhdri.ncmds; ++j) {
|
for (unsigned j= 0; j < mhdri.ncmds; ++j) {
|
||||||
msegcmd[j] = *(Mach_segment_command *)ptr;
|
msegcmd[j] = *(Mach_segment_command const *)ptr;
|
||||||
|
if (((Mach_segment_command const *)ptr)->cmd ==
|
||||||
|
Mach_segment_command::LC_ROUTINES) {
|
||||||
|
o_routines_cmd = (char *)ptr - (char *)rawmseg;
|
||||||
|
}
|
||||||
ptr += (unsigned) ((Mach_segment_command *)ptr)->cmdsize;
|
ptr += (unsigned) ((Mach_segment_command *)ptr)->cmdsize;
|
||||||
}
|
}
|
||||||
|
if (Mach_header::MH_DYLIB==my_filetype && 0==o_routines_cmd) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Put LC_SEGMENT together at the beginning, ascending by .vmaddr.
|
// Put LC_SEGMENT together at the beginning, ascending by .vmaddr.
|
||||||
qsort(msegcmd, mhdri.ncmds, sizeof(*msegcmd), compare_segment_command);
|
qsort(msegcmd, mhdri.ncmds, sizeof(*msegcmd), compare_segment_command);
|
||||||
|
|
|
@ -500,6 +500,7 @@ protected:
|
||||||
unsigned sz_mach_headers;
|
unsigned sz_mach_headers;
|
||||||
Mach_segment_command *rawmseg; // as input, with sections
|
Mach_segment_command *rawmseg; // as input, with sections
|
||||||
Mach_segment_command *msegcmd; // LC_SEGMENT first, without sections
|
Mach_segment_command *msegcmd; // LC_SEGMENT first, without sections
|
||||||
|
unsigned o_routines_cmd; // file offset to LC_ROUINTES
|
||||||
Mach_header mhdri;
|
Mach_header mhdri;
|
||||||
|
|
||||||
Mach_header mhdro;
|
Mach_header mhdro;
|
||||||
|
@ -618,7 +619,7 @@ class PackDylibI386 : public PackMachI386 //PackMachBase<MachClass_LE32>
|
||||||
typedef PackMachI386 /*PackMachBase<MachClass_LE32>*/ super;
|
typedef PackMachI386 /*PackMachBase<MachClass_LE32>*/ super;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PackDylibI386(InputFile *f) : super(f) { my_filetype = Mach_header::MH_DYLIB; }
|
PackDylibI386(InputFile *f);
|
||||||
|
|
||||||
virtual int getFormat() const { return UPX_F_DYLIB_i386; }
|
virtual int getFormat() const { return UPX_F_DYLIB_i386; }
|
||||||
virtual const char *getName() const { return "Dylib/i386"; }
|
virtual const char *getName() const { return "Dylib/i386"; }
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -164,7 +164,7 @@ main:
|
||||||
sub ecx,offset(decompress)
|
sub ecx,offset(decompress)
|
||||||
cld; rep movsb
|
cld; rep movsb
|
||||||
|
|
||||||
// Goto copied dy_reloc.
|
// Goto the copied dy_reloc.
|
||||||
lea eax,[-offset(dy_top - dy_reloc) + edi]
|
lea eax,[-offset(dy_top - dy_reloc) + edi]
|
||||||
jmp %eax
|
jmp %eax
|
||||||
dy_reloc:
|
dy_reloc:
|
||||||
|
@ -179,7 +179,12 @@ dy_reloc:
|
||||||
pop esi # &b_info for Mach_header
|
pop esi # &b_info for Mach_header
|
||||||
mov edi,edx # runtime base address
|
mov edi,edx # runtime base address
|
||||||
|
|
||||||
// Decompress __TEXT.
|
// Decompress __TEXT, but do not overwrite Mach_headers
|
||||||
|
// in order to maintain consistency with dyld partial caching of them.
|
||||||
|
// So, skip the first compressed block.
|
||||||
|
lodsd; add edi,eax # sz_unc
|
||||||
|
lodsd; add esi,eax # sz_cpr
|
||||||
|
lodsd # b_method
|
||||||
dy_uncpr:
|
dy_uncpr:
|
||||||
push esi; push edi # save in case unfilter
|
push esi; push edi # save in case unfilter
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user