pepfile.* disabled; PeFile64 class introduced

This commit is contained in:
László Molnár 2014-02-20 00:10:18 +01:00
parent e49b65723f
commit 18e55061e1
7 changed files with 263 additions and 924 deletions

View File

@ -118,9 +118,7 @@ PackW32Pe::PackW32Pe(InputFile *f) : super(f)
PackW32Pe::~PackW32Pe()
{
delete [] oloadconf;
}
{}
const int *PackW32Pe::getCompressionMethods(int method, int level) const
@ -858,20 +856,6 @@ void PackW32Pe::pack(OutputFile *fo)
throwNotCompressible();
}
/*
extra info added to help uncompression:
<ih sizeof(pe_head)>
<pe_section_t objs*sizeof(pe_section_t)>
<start of compressed imports 4> - optional \
<start of the names from uncompressed imports> - opt /
<start of compressed relocs 4> - optional \
<relocation type indicator 1> - optional /
<icondir_count 2> - optional
<offset of extra info 4>
*/
/*
vi:ts=4:et
*/

View File

@ -35,7 +35,7 @@
#include "file.h"
#include "filter.h"
#include "packer.h"
#include "pepfile.h"
#include "pefile.h"
#include "p_w64pep.h"
#include "linker.h"
@ -93,6 +93,7 @@ static unsigned my_strlen(const unsigned char *s)
#define OPTR_C(type, var, v) type* const var = (v)
#endif
#if 0
static void xcheck(const void *p, size_t plen, const void *b, size_t blen)
{
const char *pp = (const char *) p;
@ -100,7 +101,6 @@ static void xcheck(const void *p, size_t plen, const void *b, size_t blen)
if (pp < bb || pp > bb + blen || pp + plen > bb + blen)
throwCantUnpack("pointer out of range; take care!");
}
#if 0
static void xcheck(size_t poff, size_t plen, const void *b, size_t blen)
{
ACC_UNUSED(b);
@ -126,7 +126,6 @@ PackW64Pep::PackW64Pep(InputFile *f) : super(f)
isrtm = false;
use_dep_hack = true;
use_clear_dirty_stack = true;
use_tls_callbacks = false;
}
@ -167,671 +166,6 @@ int PackW64Pep::readFileHeader()
return super::readFileHeader();
}
/*************************************************************************
// import handling
**************************************************************************/
__packed_struct(import_desc)
LE32 oft; // orig first thunk
char _[8];
LE32 dllname;
LE32 iat; // import address table
__packed_struct_end()
/*
ImportLinker: 32 and 64 bit import table building.
Import entries (dll name + proc name/ordinal pairs) can be
added in arbitrary order.
Internally it works by creating sections with special names,
and adding relocation entries between those sections. The special
names ensure that when the import table is built in the memory
from those sections, a correct table can be generated simply by
sorting the sections by name, and adding all of them to the output
in the sorted order.
*/
class ImportLinker : public ElfLinkerAMD64
{
struct tstr : private ::noncopyable
{
char *s;
explicit tstr(char *str) : s(str) {}
~tstr() { delete [] s; }
operator char *() const { return s; }
};
// encoding of dll and proc names are required, so that our special
// control characters in the name of sections can work as intended
static char *encode_name(const char *name, char *buf)
{
char *b = buf;
while (*name)
{
*b++ = 'a' + ((*name >> 4) & 0xf);
*b++ = 'a' + (*name & 0xf);
name++;
}
*b = 0;
return buf;
}
static char *name_for_dll(const char *dll, char first_char)
{
assert(dll);
unsigned l = strlen(dll);
assert(l > 0);
char *name = new char[3 * l + 2];
assert(name);
name[0] = first_char;
char *n = name + 1 + 2 * l;
do {
*n++ = tolower(*dll);
} while(*dll++);
return encode_name(name + 1 + 2 * l, name + 1) - 1;
}
static char *name_for_proc(const char *dll, const char *proc,
char first_char, char separator)
{
unsigned len = 1 + 2 * strlen(dll) + 1 + 2 * strlen(proc) + 1 + 1;
tstr dlln(name_for_dll(dll, first_char));
char *procn = new char[len];
snprintf(procn, len - 1, "%s%c", (const char*) dlln, separator);
encode_name(proc, procn + strlen(procn));
return procn;
}
static char zeros[sizeof(import_desc)];
enum {
// the order of identifiers is very important below!!
descriptor_id = 'D',
thunk_id,
dll_name_id,
proc_name_id,
ordinal_id,
thunk_separator_first,
thunk_separator,
thunk_separator_last,
procname_separator,
};
unsigned thunk_size; // 4 or 8 bytes
void add(const char *dll, const char *proc, unsigned ordinal)
{
tstr sdll(name_for_dll(dll, dll_name_id));
tstr desc_name(name_for_dll(dll, descriptor_id));
char tsep = thunk_separator;
if (findSection(sdll, false) == NULL)
{
tsep = thunk_separator_first;
addSection(sdll, dll, strlen(dll) + 1, 0); // name of the dll
addSymbol(sdll, sdll, 0);
addSection(desc_name, zeros, sizeof(zeros), 0); // descriptor
addRelocation(desc_name, offsetof(import_desc, dllname),
"R_X86_64_32", sdll, 0);
}
tstr thunk(name_for_proc(dll, proc, thunk_id, tsep));
addSection(thunk, zeros, thunk_size, 0);
addSymbol(thunk, thunk, 0);
if (tsep == thunk_separator_first)
{
addRelocation(desc_name, offsetof(import_desc, iat),
"R_X86_64_32", thunk, 0);
tstr last_thunk(name_for_proc(dll, "X", thunk_id, thunk_separator_last));
addSection(last_thunk, zeros, thunk_size, 0);
}
const char *reltype = thunk_size == 4 ? "R_X86_64_32" : "R_X86_64_64";
if (ordinal != 0u)
{
addRelocation(thunk, 0, reltype, "*UND*",
ordinal | (1ull << (thunk_size * 8 - 1)));
}
else
{
tstr proc_name(name_for_proc(dll, proc, proc_name_id, procname_separator));
addSection(proc_name, zeros, 2, 1); // 2 bytes of word aligned "hint"
addSymbol(proc_name, proc_name, 0);
addRelocation(thunk, 0, reltype, proc_name, 0);
strcat(proc_name, "X");
addSection(proc_name, proc, strlen(proc), 0); // the name of the symbol
}
}
static int __acc_cdecl_qsort compare(const void *p1, const void *p2)
{
const Section *s1 = * (const Section * const *) p1;
const Section *s2 = * (const Section * const *) p2;
return strcmp(s1->name, s2->name);
}
virtual void alignCode(unsigned len) { alignWithByte(len, 0); }
const Section *getThunk(const char *dll, const char *proc, char tsep) const
{
assert(dll);
assert(proc);
tstr thunk(name_for_proc(dll, proc, thunk_id, tsep));
return findSection(thunk, false);
}
public:
explicit ImportLinker(unsigned thunk_size_) : thunk_size(thunk_size_)
{
assert(thunk_size == 4 || thunk_size == 8);
addSection("*UND*", NULL, 0, 0);
addSymbol("*UND*", "*UND*", 0);
addSection("*ZSTART", NULL, 0, 0);
addSymbol("*ZSTART", "*ZSTART", 0);
Section *s = addSection("Dzero", zeros, sizeof(import_desc), 0);
assert(s->name[0] == descriptor_id);
// one trailing 00 byte after the last proc name
addSection("Zzero", zeros, 1, 0);
}
template <typename C>
void add(const C *dll, unsigned ordinal)
{
assert(ordinal > 0 && ordinal < 0x10000);
char ord[20];
snprintf(ord, sizeof(ord), "%c%05u", ordinal_id, ordinal);
add((const char*) dll, ord, ordinal);
}
template <typename C1, typename C2>
void add(const C1 *dll, const C2 *proc)
{
assert(proc);
add((const char*) dll, (const char*) proc, 0);
}
unsigned build()
{
assert(output == NULL);
int osize = 4 + 2 * nsections; // upper limit for alignments
for (unsigned ic = 0; ic < nsections; ic++)
osize += sections[ic]->size;
output = new upx_byte[osize];
// sort the sections by name before adding them all
qsort(sections, nsections, sizeof (Section*), ImportLinker::compare);
for (unsigned ic = 0; ic < nsections; ic++)
addLoader(sections[ic]->name);
addLoader("+40D");
assert(outputlen <= osize);
//OutputFile::dump("il0.imp", output, outputlen);
return outputlen;
}
void relocate(unsigned myimport)
{
assert(nsections > 0);
assert(output);
defineSymbol("*ZSTART", /*0xffffffffff1000ull + 0 * */ myimport);
ElfLinkerAMD64::relocate();
//OutputFile::dump("il1.imp", output, outputlen);
}
template <typename C1, typename C2>
upx_uint64_t getAddress(const C1 *dll, const C2 *proc) const
{
const Section *s = getThunk((const char*) dll, (const char*) proc,
thunk_separator_first);
if (s == NULL && (s = getThunk((const char*) dll,(const char*) proc,
thunk_separator)) == NULL)
throwInternalError("entry not found");
return s->offset;
}
template <typename C1>
upx_uint64_t getAddress(const C1 *dll, unsigned ordinal) const
{
assert(ordinal > 0 && ordinal < 0x10000);
char ord[20];
snprintf(ord, sizeof(ord), "%c%05u", ordinal_id, ordinal);
const Section *s = getThunk((const char*) dll, ord, thunk_separator_first);
if (s == NULL
&& (s = getThunk((const char*) dll, ord, thunk_separator)) == NULL)
throwInternalError("entry not found");
return s->offset;
}
template <typename C1>
upx_uint64_t getAddress(const C1 *dll) const
{
tstr sdll(name_for_dll((const char*) dll, dll_name_id));
return findSection(sdll, true)->offset;
}
};
char ImportLinker::zeros[sizeof(import_desc)];
ImportLinker ilinker(8);
void PackW64Pep::processImports(unsigned myimport, unsigned) // pass 2
{
COMPILE_TIME_ASSERT(sizeof(import_desc) == 20);
ilinker.relocate(myimport);
int len;
oimpdlls = ilinker.getLoader(&len);
assert(len == (int) soimpdlls);
//OutputFile::dump("x1.imp", oimpdlls, soimpdlls);
}
unsigned PackW64Pep::processImports() // pass 1
{
static const unsigned char kernel32dll[] = "KERNEL32.DLL";
unsigned dllnum = 0;
import_desc *im = (import_desc*) (ibuf + IDADDR(PEDIR_IMPORT));
import_desc * const im_save = im;
if (IDADDR(PEDIR_IMPORT))
{
while (im->dllname)
dllnum++, im++;
im = im_save;
}
struct udll
{
const upx_byte *name;
const upx_byte *shname;
unsigned ordinal;
unsigned iat;
LE64 *lookupt;
unsigned original_position;
bool isk32;
static int __acc_cdecl_qsort compare(const void *p1, const void *p2)
{
const udll *u1 = * (const udll * const *) p1;
const udll *u2 = * (const udll * const *) p2;
if (u1->isk32) return -1;
if (u2->isk32) return 1;
if (!*u1->lookupt) return 1;
if (!*u2->lookupt) return -1;
int rc = strcasecmp(u1->name,u2->name);
if (rc) return rc;
if (u1->ordinal) return -1;
if (u2->ordinal) return 1;
if (!u1->shname) return 1;
if (!u2->shname) return -1;
return strlen(u1->shname) - strlen(u2->shname);
}
};
// +1 for dllnum=0
Array(struct udll, dlls, dllnum+1);
Array(struct udll *, idlls, dllnum+1);
soimport = 1024; // safety
unsigned ic;
for (ic = 0; dllnum && im->dllname; ic++, im++)
{
idlls[ic] = dlls + ic;
dlls[ic].name = ibuf + im->dllname;
dlls[ic].shname = NULL;
dlls[ic].ordinal = 0;
dlls[ic].iat = im->iat;
dlls[ic].lookupt = (LE64*) (ibuf + (im->oft ? im->oft : im->iat));
dlls[ic].original_position = ic;
dlls[ic].isk32 = strcasecmp(kernel32dll,dlls[ic].name) == 0;
soimport += strlen(dlls[ic].name) + 1 + 4;
// FIXME use IPTR_I as in p32pe.cpp
for (LE64 *tarr = dlls[ic].lookupt; *tarr; tarr++)
{
if (*tarr & (1ULL << 63))
{
importbyordinal = true;
soimport += 2; // ordinal num: 2 bytes
dlls[ic].ordinal = *tarr & 0xffff;
}
else //it's an import by name
{
unsigned len = strlen(ibuf + *tarr + 2);
soimport += len + 1;
if (dlls[ic].shname == NULL || len < strlen (dlls[ic].shname))
dlls[ic].shname = ibuf + *tarr + 2;
}
soimport++; // separator
}
}
oimport = new upx_byte[soimport];
memset(oimport,0,soimport);
qsort(idlls,dllnum,sizeof (udll*),udll::compare);
info("Processing imports: %d DLLs", dllnum);
// create the new import table
ilinker.add(kernel32dll, "LoadLibraryA");
ilinker.add(kernel32dll, "GetProcAddress");
if (!isdll)
ilinker.add(kernel32dll, "ExitProcess");
ilinker.add(kernel32dll, "VirtualProtect");
for (ic = 0; ic < dllnum; ic++)
{
if (idlls[ic]->isk32)
{
// for kernel32.dll we need to put all the imported
// ordinals into the output import table, as on
// some versions of windows GetProcAddress does not resolve them
if (idlls[ic]->ordinal)
for (LE64 *tarr = idlls[ic]->lookupt; *tarr; tarr++)
if (*tarr & (1ULL << 63))
{
ilinker.add(kernel32dll, *tarr & 0xffff);
kernel32ordinal = true;
}
}
else
{
if (idlls[ic]->ordinal)
ilinker.add(idlls[ic]->name, idlls[ic]->ordinal);
else if (idlls[ic]->shname)
ilinker.add(idlls[ic]->name, idlls[ic]->shname);
else
throwInternalError("should not happen");
}
}
soimpdlls = ilinker.build();
Interval names(ibuf),iats(ibuf),lookups(ibuf);
// create the preprocessed data
upx_byte *ppi = oimport; // preprocessed imports
for (ic = 0; ic < dllnum; ic++)
{
LE64 *tarr = idlls[ic]->lookupt;
#if 0 && ENABLE_THIS_AND_UNCOMPRESSION_WILL_BREAK // FIXME
if (!*tarr) // no imports from this dll
continue;
#endif
set_le32(ppi, ilinker.getAddress(idlls[ic]->name));
set_le32(ppi+4,idlls[ic]->iat - rvamin);
ppi += 8;
for (; *tarr; tarr++)
if (*tarr & (1ULL << 63))
{
unsigned ord = *tarr & 0xffff;
if (idlls[ic]->isk32)
{
*ppi++ = 0xfe; // signed + odd parity
set_le32(ppi, ilinker.getAddress(idlls[ic]->name, ord));
ppi += 4;
}
else
{
*ppi++ = 0xff;
set_le16(ppi, ord);
ppi += 2;
}
}
else
{
*ppi++ = 1;
unsigned len = strlen(ibuf + *tarr + 2) + 1;
memcpy(ppi,ibuf + *tarr + 2,len);
ppi += len;
names.add(*tarr,len + 2 + 1);
}
ppi++;
unsigned esize = ptr_diff((char *)tarr, (char *)idlls[ic]->lookupt);
lookups.add(idlls[ic]->lookupt,esize);
if (ptr_diff(ibuf + idlls[ic]->iat, (char *)idlls[ic]->lookupt))
{
memcpy(ibuf + idlls[ic]->iat, idlls[ic]->lookupt, esize);
iats.add(idlls[ic]->iat,esize);
}
names.add(idlls[ic]->name,strlen(idlls[ic]->name) + 1 + 1);
}
ppi += 4;
assert(ppi < oimport+soimport);
soimport = ptr_diff(ppi,oimport);
if (soimport == 4)
soimport = 0;
OutputFile::dump("x0.imp", oimport, soimport);
unsigned ilen = 0;
names.flatten();
if (names.ivnum > 1)
{
// The area occupied by the dll and imported names is not continuous
// so to still support uncompression, I can't zero the iat area.
// This decreases compression ratio, so FIXME somehow.
infoWarning("can't remove unneeded imports");
ilen += sizeof(import_desc) * dllnum;
#if defined(DEBUG)
if (opt->verbose > 3)
names.dump();
#endif
// do some work for the unpacker
im = im_save;
for (ic = 0; ic < dllnum; ic++, im++)
{
memset(im,FILLVAL,sizeof(*im));
im->dllname = ptr_diff(dlls[idlls[ic]->original_position].name,ibuf);
}
}
else
{
iats.add(im_save,sizeof(import_desc) * dllnum);
// zero unneeded data
iats.clear();
lookups.clear();
}
names.clear();
iats.add(&names);
iats.add(&lookups);
iats.flatten();
for (ic = 0; ic < iats.ivnum; ic++)
ilen += iats.ivarr[ic].len;
info("Imports: original size: %u bytes, preprocessed size: %u bytes",ilen,soimport);
return names.ivnum == 1 ? names.ivarr[0].start : 0;
}
/*************************************************************************
// TLS handling
**************************************************************************/
// thanks for theowl for providing me some docs, so that now I understand
// what I'm doing here :)
// 1999-10-17: this was tricky to find:
// when the fixup records and the tls area are on the same page, then
// the tls area is not relocated, because the relocation is done by
// the virtual memory manager only for pages which are not yet loaded.
// of course it was impossible to debug this ;-)
#define TLS_CB_ALIGNMENT 8u // alignment of tls callbacks
__packed_struct(tls)
LE64 datastart; // VA tls init data start
LE64 dataend; // VA tls init data end
LE64 tlsindex; // VA tls index
LE64 callbacks; // VA tls callbacks
char _[8]; // zero init, characteristics
__packed_struct_end()
void PackW64Pep::processTls(Interval *iv) // pass 1
{
COMPILE_TIME_ASSERT(sizeof(tls) == 40) //size of TLS structure is 40 byte now
COMPILE_TIME_ASSERT_ALIGNED1(tls)
if ((sotls = ALIGN_UP(IDSIZE(PEDIR_TLS),4)) == 0)
return;
const tls * const tlsp = (const tls*) (ibuf + IDADDR(PEDIR_TLS));
// note: TLS callbacks are not implemented in Windows 95/98/ME
if (tlsp->callbacks)
{
if (tlsp->callbacks < ih.imagebase)
throwCantPack("invalid TLS callback");
else if (tlsp->callbacks - ih.imagebase + 4 >= ih.imagesize)
throwCantPack("invalid TLS callback");
upx_uint64_t v = get_le64(ibuf + (tlsp->callbacks - ih.imagebase));
if (v != 0)
{
//count number of callbacks, just for information string - Stefan Widmann
unsigned num_callbacks = 0;
unsigned callback_offset = 0;
while(get_le64(ibuf + (tlsp->callbacks - ih.imagebase) + callback_offset))
{
//increment number of callbacks
num_callbacks++;
//increment pointer by 8
callback_offset += 8;
}
info("TLS: %u callback(s) found, adding TLS callback handler", num_callbacks);
//set flag to include necessary sections in loader
use_tls_callbacks = true;
//define linker symbols
tlscb_ptr = tlsp->callbacks;
}
}
const unsigned tlsdatastart = tlsp->datastart - ih.imagebase;
const unsigned tlsdataend = tlsp->dataend - ih.imagebase;
// now some ugly stuff: find the relocation entries in the tls data area
unsigned pos,type;
Reloc rel(ibuf + IDADDR(PEDIR_RELOC),IDSIZE(PEDIR_RELOC));
while (rel.next(pos,type))
if (pos >= tlsdatastart && pos < tlsdataend)
iv->add(pos,type);
sotls = sizeof(tls) + tlsdataend - tlsdatastart;
// if TLS callbacks are used, we need two more QWORDS at the end of the TLS
// ... and those qwords should be correctly aligned
if (use_tls_callbacks)
sotls = ALIGN_UP(sotls, TLS_CB_ALIGNMENT) + 16;
// the PE loader wants this stuff uncompressed
otls = new upx_byte[sotls];
memset(otls,0,sotls);
memcpy(otls,ibuf + IDADDR(PEDIR_TLS), sizeof(tls));
// WARNING: this can acces data in BSS
memcpy(otls + sizeof(tls),ibuf + tlsdatastart,sotls - sizeof(tls));
tlsindex = tlsp->tlsindex - ih.imagebase;
info("TLS: %u bytes tls data and %u relocations added",sotls - (unsigned) sizeof(tls) - (use_tls_callbacks ? 16 : 0),iv->ivnum);
// makes sure tls index is zero after decompression
if (tlsindex && tlsindex < ih.imagesize)
set_le32(ibuf + tlsindex, 0);
}
void PackW64Pep::processTls(Reloc *rel,const Interval *iv,unsigned newaddr) // pass 2
{
if (sotls == 0)
return;
// add new relocation entries
unsigned ic;
for (ic = 0; ic < (use_tls_callbacks ? 32u : 24u); ic += 8)
rel->add(newaddr + ic,10);
tls * const tlsp = (tls*) otls;
// now the relocation entries in the tls data area
// FIXME check this code below!!!
for (ic = 0; ic < iv->ivnum; ic += 4)
{
void *p = otls + iv->ivarr[ic].start - (tlsp->datastart - ih.imagebase) + sizeof(tls);
upx_uint64_t kc = get_le64(p); //changed to LE64 - Stefan Widmann
if (kc < tlsp->dataend && kc >= tlsp->datastart)
{
kc += newaddr + sizeof(tls) - tlsp->datastart;
set_le64(p,kc + ih.imagebase); //changed to LE64 - Stefan Widmann
rel->add(kc,iv->ivarr[ic].len);
}
else
rel->add(kc - ih.imagebase,iv->ivarr[ic].len);
}
const unsigned tls_data_size = tlsp->dataend - tlsp->datastart;
tlsp->datastart = newaddr + sizeof(tls) + ih.imagebase;
tlsp->dataend = tlsp->datastart + tls_data_size;
tlsp->callbacks = (use_tls_callbacks ? newaddr + sotls + ih.imagebase - 16 : 0);
if (use_tls_callbacks)
{
//set handler offset
set_le64(otls + sotls - 16, tls_handler_offset + ih.imagebase);
//add relocation for TLS handler offset
rel->add(newaddr + sotls - 16, 10);
}
}
/*************************************************************************
// Load Configuration handling
**************************************************************************/
void PackW64Pep::processLoadConf(Interval *iv) // pass 1
{
if (IDSIZE(PEDIR_LOADCONF) == 0)
return;
const unsigned lcaddr = IDADDR(PEDIR_LOADCONF);
const upx_byte * const loadconf = ibuf + lcaddr;
soloadconf = get_le32(loadconf);
if (soloadconf == 0)
return;
if (soloadconf > 256)
throwCantPack("size of Load Configuration directory unexpected");
// if there were relocation entries referring to the load config table
// then we need them for the copy of the table too
unsigned pos,type;
Reloc rel(ibuf + IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC));
while (rel.next(pos, type))
if (pos >= lcaddr && pos < lcaddr + soloadconf)
{
iv->add(pos - lcaddr, type);
// printf("loadconf reloc detected: %x\n", pos);
}
oloadconf = new upx_byte[soloadconf];
memcpy(oloadconf, loadconf, soloadconf);
}
void PackW64Pep::processLoadConf(Reloc *rel, const Interval *iv,
unsigned newaddr) // pass2
{
// now we have the address of the new load config table
// so we can create the new relocation entries
for (unsigned ic = 0; ic < iv->ivnum; ic++)
{
rel->add(iv->ivarr[ic].start + newaddr, iv->ivarr[ic].len);
//printf("loadconf reloc added: %x %d\n",
// iv->ivarr[ic].start + newaddr, iv->ivarr[ic].len);
}
}
/*************************************************************************
// pack
@ -1288,17 +622,17 @@ void PackW64Pep::pack(OutputFile *fo)
0x2000 : 0x1000); // 2 pages or 1 page
linker->defineSymbol("vp_base", addr &~ 0xfff); // page mask
linker->defineSymbol("VirtualProtect", myimport +
ilinker.getAddress("kernel32.dll", "VirtualProtect"));
ilinkerGetAddress("kernel32.dll", "VirtualProtect"));
}
linker->defineSymbol("start_of_relocs", crelocs);
if (!isdll)
linker->defineSymbol("ExitProcess", myimport +
ilinker.getAddress("kernel32.dll", "ExitProcess"));
ilinkerGetAddress("kernel32.dll", "ExitProcess"));
linker->defineSymbol("GetProcAddress", myimport +
ilinker.getAddress("kernel32.dll", "GetProcAddress"));
ilinkerGetAddress("kernel32.dll", "GetProcAddress"));
linker->defineSymbol("kernel32_ordinals", myimport);
linker->defineSymbol("LoadLibraryA", myimport +
ilinker.getAddress("kernel32.dll", "LoadLibraryA"));
ilinkerGetAddress("kernel32.dll", "LoadLibraryA"));
linker->defineSymbol("start_of_imports", myimport);
linker->defineSymbol("compressed_imports", cimports);
@ -1384,7 +718,7 @@ void PackW64Pep::pack(OutputFile *fo)
ODSIZE(PEDIR_RESOURCE) = soresources;
ic += soresources;
processImports(ic, 0);
PeFile::processImports(ic, 0);
ODADDR(PEDIR_IMPORT) = ic;
ODSIZE(PEDIR_IMPORT) = soimpdlls;
ic += soimpdlls;
@ -1399,7 +733,7 @@ void PackW64Pep::pack(OutputFile *fo)
}
ic += soexport;
processRelocs(&rel);
PeFile::processRelocs(&rel);
ODADDR(PEDIR_RELOC) = soxrelocs ? ic : 0;
ODSIZE(PEDIR_RELOC) = soxrelocs;
ic += soxrelocs;
@ -1524,195 +858,6 @@ void PackW64Pep::pack(OutputFile *fo)
throwNotCompressible();
}
/*************************************************************************
// unpack
**************************************************************************/
int PackW64Pep::canUnpack()
{
if (!readFileHeader() || ih.cpu != 0x8664)
return false;
unsigned objs = ih.objects;
isection = new pe_section_t[objs];
fi->seek(pe_offset+sizeof(ih),SEEK_SET);
fi->readx(isection,sizeof(pe_section_t)*objs);
if (ih.objects < 3)
return -1;
bool is_packed = (ih.objects == 3 &&
(IDSIZE(15) || ih.entry > isection[1].vaddr));
bool found_ph = false;
if (memcmp(isection[0].name,"UPX",3) == 0)
{
// current version
fi->seek(isection[1].rawdataptr - 64, SEEK_SET);
found_ph = readPackHeader(1024);
if (!found_ph)
{
// old versions
fi->seek(isection[2].rawdataptr, SEEK_SET);
found_ph = readPackHeader(1024);
}
}
if (is_packed && found_ph)
return true;
if (!is_packed && !found_ph)
return -1;
if (is_packed && ih.entry < isection[2].vaddr)
{
unsigned char buf[256];
bool x = false;
memset(buf, 0, sizeof(buf));
try {
fi->seek(ih.entry - isection[1].vaddr + isection[1].rawdataptr, SEEK_SET);
fi->read(buf, sizeof(buf));
static const unsigned char magic[] = "\x8b\x1e\x83\xee\xfc\x11\xdb";
// mov ebx, [esi]; sub esi, -4; adc ebx,ebx
int offset = find(buf, sizeof(buf), magic, 7);
if (offset >= 0 && find(buf + offset + 1, sizeof(buf) - offset - 1, magic, 7) >= 0)
x = true;
} catch (...) {
//x = true;
}
if (x)
throwCantUnpack("file is modified/hacked/protected; take care!!!");
else
throwCantUnpack("file is possibly modified/hacked/protected; take care!");
return false; // not reached
}
// FIXME: what should we say here ?
//throwCantUnpack("file is possibly modified/hacked/protected; take care!");
return false;
}
void PackW64Pep::rebuildImports(upx_byte *& extrainfo)
{
if (ODADDR(PEDIR_IMPORT) == 0
|| ODSIZE(PEDIR_IMPORT) <= sizeof(import_desc))
return;
// const upx_byte * const idata = obuf + get_le32(extrainfo);
OPTR_C(const upx_byte, idata, obuf + get_le32(extrainfo));
const unsigned inamespos = get_le32(extrainfo + 4);
extrainfo += 8;
unsigned sdllnames = 0;
// const upx_byte *import = ibuf + IDADDR(PEDIR_IMPORT) - isection[2].vaddr;
// const upx_byte *p;
IPTR_I(const upx_byte, import, ibuf + IDADDR(PEDIR_IMPORT) - isection[2].vaddr);
OPTR(const upx_byte, p);
for (p = idata; get_le32(p) != 0; ++p)
{
const upx_byte *dname = get_le32(p) + import;
ICHECK(dname, 1);
const unsigned dlen = strlen(dname);
ICHECK(dname, dlen + 1);
sdllnames += dlen + 1;
for (p += 8; *p;)
if (*p == 1)
p += strlen(++p) + 1;
else if (*p == 0xff)
p += 3; // ordinal
else
p += 5;
}
sdllnames = ALIGN_UP(sdllnames, 2u);
upx_byte * const Obuf = obuf - rvamin;
import_desc * const im0 = (import_desc*) (Obuf + ODADDR(PEDIR_IMPORT));
import_desc *im = im0;
upx_byte *dllnames = Obuf + inamespos;
upx_byte *importednames = dllnames + sdllnames;
upx_byte * const importednames_start = importednames;
for (p = idata; get_le32(p) != 0; ++p)
{
// restore the name of the dll
const upx_byte *dname = get_le32(p) + import;
ICHECK(dname, 1);
const unsigned dlen = strlen(dname);
ICHECK(dname, dlen + 1);
const unsigned iatoffs = get_le32(p + 4) + rvamin;
if (inamespos)
{
// now I rebuild the dll names
OCHECK(dllnames, dlen + 1);
strcpy(dllnames, dname);
im->dllname = ptr_diff(dllnames,Obuf);
//;;;printf("\ndll: %s:",dllnames);
dllnames += dlen + 1;
}
else
{
OCHECK(Obuf + im->dllname, dlen + 1);
strcpy(Obuf + im->dllname, dname);
}
im->iat = iatoffs;
OPTR_I(LE64, newiat, (LE64 *) (Obuf + iatoffs));
// restore the imported names+ordinals
for (p += 8; *p; ++newiat)
if (*p == 1)
{
const unsigned ilen = strlen(++p) + 1;
if (inamespos)
{
if (ptr_diff(importednames, importednames_start) & 1)
importednames -= 1;
omemcpy(importednames + 2, p, ilen);
//;;;printf(" %s",importednames+2);
*newiat = ptr_diff(importednames, Obuf);
importednames += 2 + ilen;
}
else
{
OCHECK(Obuf + (*newiat + 2), ilen + 1);
strcpy(Obuf + (*newiat + 2), p);
}
p += ilen;
}
else if (*p == 0xff)
{
*newiat = get_le16(p + 1) + (1ULL << 63);
//;;;printf(" %llx",(unsigned long long)*newiat);
p += 3;
}
else
{
*newiat = get_le64(get_le32(p + 1) + import);
assert(*newiat & (1ULL << 63));
p += 5;
}
*newiat = 0;
im++;
}
//memset(idata,0,p - idata);
}
/*
extra info added to help uncompression:
<ih sizeof(pe_head)>
<pe_section_t objs*sizeof(pe_section_t)>
<start of compressed imports 4> - optional \
<start of the names from uncompressed imports> - opt /
<start of compressed relocs 4> - optional \
<relocation type indicator 1> - optional /
<icondir_count 2> - optional
<offset of extra info 4>
*/
/*
vi:ts=4:et
*/

View File

@ -33,9 +33,9 @@
// w64/pep
**************************************************************************/
class PackW64Pep : public PepFile
class PackW64Pep : public PeFile64
{
typedef PepFile super;
typedef PeFile64 super;
public:
PackW64Pep(InputFile *f);
@ -49,7 +49,6 @@ public:
virtual void pack(OutputFile *fo);
virtual bool canPack();
virtual int canUnpack();
protected:
virtual int readFileHeader();
@ -57,25 +56,9 @@ protected:
virtual void buildLoader(const Filter *ft);
virtual Linker* newLinker() const;
virtual unsigned processImports();
virtual void processImports(unsigned, unsigned);
virtual void rebuildImports(upx_byte *&);
virtual void processTls(Interval *); //NEW: TLS callback handling - Stefan Widmann
void processTls(Reloc *, const Interval *, unsigned); //NEW: TLS callback handling - Stefan Widmann
void processLoadConf(Reloc *, const Interval *, unsigned);
void processLoadConf(Interval *);
upx_byte *oloadconf;
unsigned soloadconf;
unsigned tlscb_ptr; //NEW: TLS callback handling - Stefan Widmann
unsigned tls_handler_offset;
bool isrtm;
bool use_dep_hack;
bool use_clear_dirty_stack;
bool use_tls_callbacks; //NEW: TLS callback handling - Stefan Widmann
};

View File

@ -142,21 +142,6 @@ PeFile::PeFile(InputFile *f) : super(f)
}
PeFile::~PeFile()
{
delete [] isection;
delete [] orelocs;
delete [] oimport;
oimpdlls = NULL;
delete [] oexport;
delete [] otls;
delete [] oresources;
delete [] oxrelocs;
delete [] oloadconf;
//delete res;
}
bool PeFile::testUnpackVersion(int version) const
{
if (version != ph_version && ph_version != -1)
@ -478,6 +463,107 @@ void PeFile32::processRelocs() // pass1
info("Relocations: original size: %u bytes, preprocessed size: %u bytes",(unsigned) IDSIZE(PEDIR_RELOC),sorelocs);
}
void PeFile64::processRelocs() // pass1
{
big_relocs = 0;
Reloc rel(ibuf + IDADDR(PEDIR_RELOC),IDSIZE(PEDIR_RELOC));
const unsigned *counts = rel.getcounts();
unsigned rnum = 0;
unsigned ic;
for (ic = 1; ic < 16; ic++)
rnum += counts[ic];
if ((opt->win32_pe.strip_relocs && !isdll) || rnum == 0)
{
if (IDSIZE(PEDIR_RELOC))
ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL);
orelocs = new upx_byte [1];
sorelocs = 0;
return;
}
for (ic = 15; ic; ic--)
if (ic != 10 && counts[ic])
infoWarning("skipping unsupported relocation type %d (%d)",ic,counts[ic]);
LE32 *fix[16];
for (ic = 15; ic; ic--)
fix[ic] = new LE32 [counts[ic]];
unsigned xcounts[16];
memset(xcounts, 0, sizeof(xcounts));
// prepare sorting
unsigned pos,type;
while (rel.next(pos,type))
{
// FIXME add check for relocations which try to modify the
// PE header or other relocation records
if (pos >= ih.imagesize)
continue; // skip out-of-bounds record
if (type < 16)
fix[type][xcounts[type]++] = pos - rvamin;
}
// remove duplicated records
for (ic = 1; ic <= 15; ic++)
{
qsort(fix[ic], xcounts[ic], 4, le32_compare);
unsigned prev = ~0;
unsigned jc = 0;
for (unsigned kc = 0; kc < xcounts[ic]; kc++)
if (fix[ic][kc] != prev)
prev = fix[ic][jc++] = fix[ic][kc];
//printf("xcounts[%u] %u->%u\n", ic, xcounts[ic], jc);
xcounts[ic] = jc;
}
// preprocess "type 10" relocation records
for (ic = 0; ic < xcounts[10]; ic++)
{
pos = fix[10][ic] + rvamin;
set_le64(ibuf + pos, get_le64(ibuf + pos) - ih.imagebase - rvamin);
}
ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL);
orelocs = new upx_byte [rnum * 4 + 1024]; // 1024 - safety
sorelocs = ptr_diff(optimizeReloc64((upx_byte*) fix[10], xcounts[10],
orelocs, ibuf + rvamin,1, &big_relocs),
orelocs);
for (ic = 15; ic; ic--)
delete [] fix[ic];
#if 0
// Malware that hides behind UPX often has PE header info that is
// deliberately corrupt. Sometimes it is even tuned to cause us trouble!
// Use an extra check to avoid AccessViolation (SIGSEGV) when appending
// the relocs into one array.
if ((rnum * 4 + 1024) < (sorelocs + 4*(2 + xcounts[2] + xcounts[1])))
throwCantUnpack("Invalid relocs");
// append relocs type "LOW" then "HIGH"
for (ic = 2; ic ; ic--)
{
memcpy(orelocs + sorelocs,fix[ic],4 * xcounts[ic]);
sorelocs += 4 * xcounts[ic];
delete [] fix[ic];
set_le32(orelocs + sorelocs,0);
if (xcounts[ic])
{
sorelocs += 4;
big_relocs |= 2 * ic;
}
}
#endif
info("Relocations: original size: %u bytes, preprocessed size: %u bytes",(unsigned) IDSIZE(PEDIR_RELOC),sorelocs);
}
/*************************************************************************
// import handling
**************************************************************************/
@ -850,6 +936,7 @@ unsigned PeFile::processImports(ord_mask_t ord_mask) // pass 1
info("Processing imports: %d DLLs", dllnum);
ilinker = new ImportLinker(sizeof(LEXX));
// create the new import table
addKernelImports();
@ -1152,6 +1239,23 @@ struct PeFile::tls_traits<LE32>
static const unsigned reloc_type = 3;
};
template <>
struct PeFile::tls_traits<LE64>
{
__packed_struct(tls)
LE64 datastart; // VA tls init data start
LE64 dataend; // VA tls init data end
LE64 tlsindex; // VA tls index
LE64 callbacks; // VA tls callbacks
char _[8]; // zero init, characteristics
__packed_struct_end()
static const unsigned sotls = 40;
static const unsigned cb_size = 8;
typedef upx_uint64_t cb_value_t;
static const unsigned reloc_type = 10;
};
template <typename LEXX>
void PeFile::processTls1(Interval *iv,
typename tls_traits<LEXX>::cb_value_t imagebase,
@ -2101,8 +2205,8 @@ void PeFile::rebuildImports(upx_byte *& extrainfo,
}
else
{
OCHECK(Obuf + *newiat + 2, ilen + 1);
strcpy(Obuf + *newiat + 2, p);
OCHECK(Obuf + (*newiat + 2), ilen + 1);
strcpy(Obuf + (*newiat + 2), p);
}
p += ilen;
}
@ -2307,6 +2411,26 @@ int PeFile::canUnpack0(unsigned max_sections, LE16 &ih_objects,
return false;
}
upx_uint64_t PeFile::ilinkerGetAddress(const char *d, const char *n) const
{
return ilinker->getAddress(d, n);
}
PeFile::~PeFile()
{
delete [] isection;
delete [] orelocs;
delete [] oimport;
oimpdlls = NULL;
delete [] oexport;
delete [] otls;
delete [] oresources;
delete [] oxrelocs;
delete [] oloadconf;
delete ilinker;
//delete res;
}
/*************************************************************************
// PeFile32
@ -2319,14 +2443,10 @@ PeFile32::PeFile32(InputFile *f) : super(f)
iddirs = ih.ddirs;
oddirs = oh.ddirs;
ilinker = new ImportLinker(4);
}
PeFile32::~PeFile32()
{
delete ilinker;
}
{}
void PeFile32::readPeHeader()
{
@ -2361,6 +2481,53 @@ void PeFile32::processTls(Reloc *r, const Interval *iv, unsigned a)
super::processTls2<LE32>(r, iv, a, ih.imagebase);
}
/*************************************************************************
// PeFile64
**************************************************************************/
PeFile64::PeFile64(InputFile *f) : super(f)
{
COMPILE_TIME_ASSERT(sizeof(pe_header_t) == 264)
COMPILE_TIME_ASSERT_ALIGNED1(pe_header_t)
iddirs = ih.ddirs;
oddirs = oh.ddirs;
}
PeFile64::~PeFile64()
{}
void PeFile64::readPeHeader()
{
fi->readx(&ih,sizeof(ih));
isdll = ((ih.flags & DLL_FLAG) != 0);
}
void PeFile64::unpack(OutputFile *fo)
{
super::unpack<pe_header_t, LE64>(fo, ih, oh, 1ULL << 63, false);
}
int PeFile64::canUnpack()
{
return canUnpack0(3, ih.objects, ih.entry, sizeof(ih));
}
unsigned PeFile64::processImports() // pass 1
{
return super::processImports<LE64>(1ULL << 63);
}
void PeFile64::processTls(Interval *iv)
{
super::processTls1<LE64>(iv, ih.imagebase, ih.imagesize);
}
void PeFile64::processTls(Reloc *r, const Interval *iv, unsigned a)
{
super::processTls2<LE64>(r, iv, a, ih.imagebase);
}
/*
extra info added to help uncompression:

View File

@ -80,6 +80,7 @@ protected:
ImportLinker *ilinker;
void addKernelImport(const char *, const char *);
virtual void addKernelImports();
upx_uint64_t ilinkerGetAddress(const char *, const char *) const;
virtual void processRelocs() = 0;
void processRelocs(Reloc *);
@ -428,6 +429,64 @@ protected:
pe_header_t ih, oh;
};
class PeFile64 : public PeFile
{
typedef PeFile super;
protected:
PeFile64(InputFile *f);
virtual ~PeFile64();
virtual void unpack(OutputFile *fo);
virtual int canUnpack();
virtual void readPeHeader();
virtual unsigned processImports();
virtual void processRelocs();
virtual void processTls(Interval *);
void processTls(Reloc *, const Interval *, unsigned);
__packed_struct(pe_header_t)
// 0x0
char _[4]; // pemagic
LE16 cpu;
LE16 objects; // number of sections
char __[12]; // timestamp + reserved
LE16 opthdrsize;
LE16 flags; // characteristics
// optional header
LE16 coffmagic; // NEW: Stefan Widmann
char ___[2]; // linkerversion
LE32 codesize;
// 0x20
LE32 datasize;
LE32 bsssize;
LE32 entry; // still a 32 bit RVA
LE32 codebase;
// 0x30
//LE32 database; // field does not exist in PE+!
// nt specific fields
LE64 imagebase; // LE32 -> LE64 - Stefan Widmann standard is 0x0000000140000000
LE32 objectalign;
LE32 filealign; // should set to 0x200 ?
// 0x40
char ____[16]; // versions
// 0x50
LE32 imagesize;
LE32 headersize;
LE32 chksum; // should set to 0
LE16 subsystem;
LE16 dllflags;
// 0x60
char _____[36]; // stack + heap sizes + loader flag
// 0x84
LE32 ddirsentries; // usually 16
ddirs_t ddirs[16];
__packed_struct_end()
pe_header_t ih, oh;
};
#endif /* already included */

View File

@ -30,7 +30,7 @@
changes in:
*/
#if 0
#include "conf.h"
#include "file.h"
#include "filter.h"
@ -1731,7 +1731,7 @@ void PepFile::unpack(OutputFile *fo)
<offset of extra info 4>
*/
#endif
/*
vi:ts=4:et
*/

View File

@ -35,7 +35,7 @@
#ifndef __UPX_PEPFILE_H
#define __UPX_PEPFILE_H 1
#if 0
/*************************************************************************
// general/pe handling
**************************************************************************/
@ -378,6 +378,7 @@ protected:
};
#endif
#endif /* already included */