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
+8 -863
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
*/