PE related fixes for CERT-FI 829767
This commit is contained in:
+36
-4
@@ -1493,10 +1493,13 @@ struct PeFile::Resource::upx_rleaf : public PeFile::Resource::upx_rnode
|
|||||||
PeFile::Resource::Resource() : root(NULL)
|
PeFile::Resource::Resource() : root(NULL)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
PeFile::Resource::Resource(const upx_byte *p)
|
PeFile::Resource::Resource(const upx_byte *p,
|
||||||
|
const upx_byte *ibufstart_,
|
||||||
|
const upx_byte *ibufend_)
|
||||||
{
|
{
|
||||||
|
ibufstart = ibufstart_;
|
||||||
|
ibufend = ibufend_;
|
||||||
init(p);
|
init(p);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PeFile::Resource::~Resource()
|
PeFile::Resource::~Resource()
|
||||||
@@ -1578,15 +1581,25 @@ void PeFile::Resource::init(const upx_byte *res)
|
|||||||
|
|
||||||
void PeFile::Resource::check(const res_dir *node,unsigned level)
|
void PeFile::Resource::check(const res_dir *node,unsigned level)
|
||||||
{
|
{
|
||||||
|
ibufcheck(node, sizeof(*node));
|
||||||
int ic = node->identr + node->namedentr;
|
int ic = node->identr + node->namedentr;
|
||||||
if (ic == 0)
|
if (ic == 0)
|
||||||
return;
|
return;
|
||||||
for (const res_dir_entry *rde = node->entries; --ic >= 0; rde++)
|
for (const res_dir_entry *rde = node->entries; --ic >= 0; rde++)
|
||||||
|
{
|
||||||
|
ibufcheck(rde, sizeof(*rde));
|
||||||
if (((rde->child & 0x80000000) == 0) ^ (level == 2))
|
if (((rde->child & 0x80000000) == 0) ^ (level == 2))
|
||||||
throwCantPack("unsupported resource structure");
|
throwCantPack("unsupported resource structure");
|
||||||
else if (level != 2)
|
else if (level != 2)
|
||||||
check((const res_dir*) (start + (rde->child & 0x7fffffff)),level + 1);
|
check((const res_dir*) (start + (rde->child & 0x7fffffff)),level + 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeFile::Resource::ibufcheck(const void *m, unsigned siz)
|
||||||
|
{
|
||||||
|
if (m < ibufstart || m > ibufend - siz)
|
||||||
|
throwCantUnpack("corrupted resources");
|
||||||
|
}
|
||||||
|
|
||||||
PeFile::Resource::upx_rnode *PeFile::Resource::convert(const void *rnode,
|
PeFile::Resource::upx_rnode *PeFile::Resource::convert(const void *rnode,
|
||||||
upx_rnode *parent,
|
upx_rnode *parent,
|
||||||
@@ -1595,6 +1608,7 @@ PeFile::Resource::upx_rnode *PeFile::Resource::convert(const void *rnode,
|
|||||||
if (level == 3)
|
if (level == 3)
|
||||||
{
|
{
|
||||||
const res_data *node = (const res_data *) rnode;
|
const res_data *node = (const res_data *) rnode;
|
||||||
|
ibufcheck(node, sizeof(*node));
|
||||||
upx_rleaf *leaf = new upx_rleaf;
|
upx_rleaf *leaf = new upx_rleaf;
|
||||||
leaf->name = NULL;
|
leaf->name = NULL;
|
||||||
leaf->parent = parent;
|
leaf->parent = parent;
|
||||||
@@ -1608,6 +1622,7 @@ PeFile::Resource::upx_rnode *PeFile::Resource::convert(const void *rnode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const res_dir *node = (const res_dir *) rnode;
|
const res_dir *node = (const res_dir *) rnode;
|
||||||
|
ibufcheck(node, sizeof(*node));
|
||||||
int ic = node->identr + node->namedentr;
|
int ic = node->identr + node->namedentr;
|
||||||
if (ic == 0)
|
if (ic == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1628,7 +1643,9 @@ PeFile::Resource::upx_rnode *PeFile::Resource::convert(const void *rnode,
|
|||||||
if (child->id & 0x80000000)
|
if (child->id & 0x80000000)
|
||||||
{
|
{
|
||||||
const upx_byte *p = start + (child->id & 0x7fffffff);
|
const upx_byte *p = start + (child->id & 0x7fffffff);
|
||||||
|
ibufcheck(p, 2);
|
||||||
const unsigned len = 2 + 2 * get_le16(p);
|
const unsigned len = 2 + 2 * get_le16(p);
|
||||||
|
ibufcheck(p, len);
|
||||||
child->name = new upx_byte[len];
|
child->name = new upx_byte[len];
|
||||||
memcpy(child->name,p,len); // copy unicode string
|
memcpy(child->name,p,len); // copy unicode string
|
||||||
ssize += len; // size of unicode strings
|
ssize += len; // size of unicode strings
|
||||||
@@ -1643,6 +1660,9 @@ void PeFile::Resource::build(const upx_rnode *node, unsigned &bpos,
|
|||||||
{
|
{
|
||||||
if (level == 3)
|
if (level == 3)
|
||||||
{
|
{
|
||||||
|
if (bpos + sizeof(res_data) >= dirsize())
|
||||||
|
throwCantUnpack("corrupted resources");
|
||||||
|
|
||||||
res_data *l = (res_data*) (newstart + bpos);
|
res_data *l = (res_data*) (newstart + bpos);
|
||||||
const upx_rleaf *leaf = (const upx_rleaf*) node;
|
const upx_rleaf *leaf = (const upx_rleaf*) node;
|
||||||
*l = leaf->data;
|
*l = leaf->data;
|
||||||
@@ -1651,6 +1671,9 @@ void PeFile::Resource::build(const upx_rnode *node, unsigned &bpos,
|
|||||||
bpos += sizeof(*l);
|
bpos += sizeof(*l);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (bpos + sizeof(res_dir) >= dirsize())
|
||||||
|
throwCantUnpack("corrupted resources");
|
||||||
|
|
||||||
res_dir * const b = (res_dir*) (newstart + bpos);
|
res_dir * const b = (res_dir*) (newstart + bpos);
|
||||||
const upx_rbranch *branch = (const upx_rbranch*) node;
|
const upx_rbranch *branch = (const upx_rbranch*) node;
|
||||||
*b = branch->data;
|
*b = branch->data;
|
||||||
@@ -1666,6 +1689,8 @@ void PeFile::Resource::build(const upx_rnode *node, unsigned &bpos,
|
|||||||
if ((p = branch->children[ic]->name) != 0)
|
if ((p = branch->children[ic]->name) != 0)
|
||||||
{
|
{
|
||||||
be->tnl = spos + 0x80000000;
|
be->tnl = spos + 0x80000000;
|
||||||
|
if (spos + get_le16(p) * 2 + 2 >= dirsize())
|
||||||
|
throwCantUnpack("corrupted resources");
|
||||||
memcpy(newstart + spos,p,get_le16(p) * 2 + 2);
|
memcpy(newstart + spos,p,get_le16(p) * 2 + 2);
|
||||||
spos += get_le16(p) * 2 + 2;
|
spos += get_le16(p) * 2 + 2;
|
||||||
}
|
}
|
||||||
@@ -2629,11 +2654,16 @@ void PeFile::rebuildResources(upx_byte *& extrainfo, unsigned lastvaddr)
|
|||||||
extrainfo += 2;
|
extrainfo += 2;
|
||||||
|
|
||||||
const unsigned vaddr = IDADDR(PEDIR_RESOURCE);
|
const unsigned vaddr = IDADDR(PEDIR_RESOURCE);
|
||||||
|
|
||||||
|
if (lastvaddr > vaddr || (vaddr - lastvaddr) > ibuf.getSize())
|
||||||
|
throwCantUnpack("corrupted PE header");
|
||||||
|
|
||||||
const upx_byte *r = ibuf - lastvaddr;
|
const upx_byte *r = ibuf - lastvaddr;
|
||||||
Resource res(r + vaddr);
|
Resource res(r + vaddr, ibuf, ibuf + ibuf.getSize());
|
||||||
while (res.next())
|
while (res.next())
|
||||||
if (res.offs() > vaddr)
|
if (res.offs() > vaddr)
|
||||||
{
|
{
|
||||||
|
ICHECK(r + res.offs() - 4, 4);
|
||||||
unsigned origoffs = get_le32(r + res.offs() - 4);
|
unsigned origoffs = get_le32(r + res.offs() - 4);
|
||||||
res.newoffs() = origoffs;
|
res.newoffs() = origoffs;
|
||||||
omemcpy(obuf + origoffs - rvamin,r + res.offs(),res.size());
|
omemcpy(obuf + origoffs - rvamin,r + res.offs(),res.size());
|
||||||
@@ -2771,6 +2801,8 @@ void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh,
|
|||||||
//infoHeader("[Processing %s, format %s, %d sections]", fn_basename(fi->getName()), getName(), objs);
|
//infoHeader("[Processing %s, format %s, %d sections]", fn_basename(fi->getName()), getName(), objs);
|
||||||
|
|
||||||
handleStub(fi,fo,pe_offset);
|
handleStub(fi,fo,pe_offset);
|
||||||
|
if (ih.filealign == 0)
|
||||||
|
throwCantUnpack("unexpected value in the PE header");
|
||||||
|
|
||||||
const unsigned iobjs = ih.objects;
|
const unsigned iobjs = ih.objects;
|
||||||
const unsigned overlay = file_size - ALIGN_UP(isection[iobjs - 1].rawdataptr
|
const unsigned overlay = file_size - ALIGN_UP(isection[iobjs - 1].rawdataptr
|
||||||
@@ -2792,7 +2824,7 @@ void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh,
|
|||||||
extrainfo += sizeof (oh);
|
extrainfo += sizeof (oh);
|
||||||
unsigned objs = oh.objects;
|
unsigned objs = oh.objects;
|
||||||
|
|
||||||
if ((int) objs <= 0)
|
if ((int) objs <= 0 || isection[2].size == 0)
|
||||||
throwCantUnpack("unexpected value in the PE header");
|
throwCantUnpack("unexpected value in the PE header");
|
||||||
Array(pe_section_t, osection, objs);
|
Array(pe_section_t, osection, objs);
|
||||||
memcpy(osection,extrainfo,sizeof(pe_section_t) * objs);
|
memcpy(osection,extrainfo,sizeof(pe_section_t) * objs);
|
||||||
|
|||||||
+7
-1
@@ -340,6 +340,9 @@ protected:
|
|||||||
unsigned dsize;
|
unsigned dsize;
|
||||||
unsigned ssize;
|
unsigned ssize;
|
||||||
|
|
||||||
|
const upx_byte *ibufstart;
|
||||||
|
const upx_byte *ibufend;
|
||||||
|
|
||||||
void check(const res_dir*,unsigned);
|
void check(const res_dir*,unsigned);
|
||||||
upx_rnode *convert(const void *,upx_rnode *,unsigned);
|
upx_rnode *convert(const void *,upx_rnode *,unsigned);
|
||||||
void build(const upx_rnode *,unsigned &,unsigned &,unsigned);
|
void build(const upx_rnode *,unsigned &,unsigned &,unsigned);
|
||||||
@@ -347,9 +350,12 @@ protected:
|
|||||||
void dump(const upx_rnode *,unsigned) const;
|
void dump(const upx_rnode *,unsigned) const;
|
||||||
void destroy(upx_rnode *urd,unsigned level);
|
void destroy(upx_rnode *urd,unsigned level);
|
||||||
|
|
||||||
|
void ibufcheck(const void *m, unsigned size);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Resource();
|
Resource();
|
||||||
Resource(const upx_byte *p);
|
Resource(const upx_byte *p, const upx_byte *ibufstart,
|
||||||
|
const upx_byte *ibufend);
|
||||||
~Resource();
|
~Resource();
|
||||||
void init(const upx_byte *);
|
void init(const upx_byte *);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user