mirror of https://github.com/upx/upx.git
pepfile.* disabled; PeFile64 class introduced
This commit is contained in:
parent
e49b65723f
commit
18e55061e1
|
@ -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
|
||||
*/
|
||||
|
|
871
src/p_w64pep.cpp
871
src/p_w64pep.cpp
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
|
211
src/pefile.cpp
211
src/pefile.cpp
|
@ -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:
|
||||
|
||||
|
|
59
src/pefile.h
59
src/pefile.h
|
@ -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 */
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue