📄 pefile.cpp
字号:
struct tls{ LE32 datastart; // VA tls init data start LE32 dataend; // VA tls init data end LE32 tlsindex; // VA tls index LE32 callbacks; // VA tls callbacks char _[8]; // zero init, characteristics}__attribute_packed;void PeFile::processTls(Interval *iv) // pass 1{ COMPILE_TIME_ASSERT(sizeof(tls) == 24); 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"); unsigned v = get_le32(ibuf + tlsp->callbacks - ih.imagebase); if (v != 0) { //fprintf(stderr, "TLS callbacks: 0x%0x -> 0x%0x\n", (int)tlsp->callbacks, v); throwCantPack("TLS callbacks are not supported"); } } 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; // the PE loader wants this stuff uncompressed otls = new upx_byte[sotls]; memset(otls,0,sotls); memcpy(otls,ibuf + IDADDR(PEDIR_TLS),0x18); // 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),iv->ivnum); // makes sure tls index is zero after decompression if (tlsindex && tlsindex < ih.imagesize) set_le32(ibuf + tlsindex, 0);}void PeFile::processTls(Reloc *rel,const Interval *iv,unsigned newaddr) // pass 2{ if (sotls == 0) return; // add new relocation entries unsigned ic; for (ic = 0; ic < 12; ic += 4) rel->add(newaddr + ic,3); tls * const tlsp = (tls*) otls; // now the relocation entries in the tls data area for (ic = 0; ic < iv->ivnum; ic += 4) { void *p = otls + iv->ivarr[ic].start - (tlsp->datastart - ih.imagebase) + sizeof(tls); unsigned kc = get_le32(p); if (kc < tlsp->dataend && kc >= tlsp->datastart) { kc += newaddr + sizeof(tls) - tlsp->datastart; set_le32(p,kc + ih.imagebase); rel->add(kc,iv->ivarr[ic].len); } else rel->add(kc - ih.imagebase,iv->ivarr[ic].len); } tlsp->datastart = newaddr + sizeof(tls) + ih.imagebase; tlsp->dataend = newaddr + sotls + ih.imagebase; tlsp->callbacks = 0; // note: TLS callbacks are not implemented in Windows 95/98/ME}/*************************************************************************// resource handling**************************************************************************/struct PeFile::Resource::res_dir_entry{ LE32 tnl; // Type | Name | Language id - depending on level LE32 child;}__attribute_packed;struct PeFile::Resource::res_dir{ char _[12]; // flags, timedate, version LE16 namedentr; LE16 identr; unsigned Sizeof() const { return 16 + sizeof(res_dir_entry)*(namedentr + identr); } res_dir_entry entries[1]; // it's usually safe to assume that every res_dir contains // at least one res_dir_entry - check() complains otherwise}__attribute_packed;struct PeFile::Resource::res_data{ LE32 offset; LE32 size; char _[8]; // codepage, reserved}__attribute_packed;struct PeFile::Resource::upx_rnode{ unsigned id; upx_byte *name; upx_rnode *parent;};struct PeFile::Resource::upx_rbranch : public upx_rnode{ unsigned nc; upx_rnode **children; res_dir data;};struct PeFile::Resource::upx_rleaf : public upx_rnode{ upx_rleaf *next; unsigned newoffset; res_data data;};PeFile::Resource::Resource() : root(NULL){}PeFile::Resource::Resource(const upx_byte *p){ init(p);}PeFile::Resource::~Resource(){ if (root) destroy (root,0);}unsigned PeFile::Resource::dirsize() const{ return ALIGN_UP(dsize + ssize, 4u);}bool PeFile::Resource::next(){ // wow, builtin autorewind... :-) return (current = current ? current->next : head) != NULL;}unsigned PeFile::Resource::itype() const{ return current->parent->parent->id;}const upx_byte *PeFile::Resource::ntype() const{ return current->parent->parent->name;}unsigned PeFile::Resource::size() const{ return ALIGN_UP(current->data.size,4);}unsigned PeFile::Resource::offs() const{ return current->data.offset;}unsigned &PeFile::Resource::newoffs(){ return current->newoffset;}void PeFile::Resource::dump() const{ dump(root,0);}unsigned PeFile::Resource::iname() const{ return current->parent->id;}const upx_byte *PeFile::Resource::nname() const{ return current->parent->name;}/* unsigned ilang() const {return current->id;} const upx_byte *nlang() const {return current->name;}*/void PeFile::Resource::init(const upx_byte *res){ COMPILE_TIME_ASSERT(sizeof(res_dir_entry) == 8) COMPILE_TIME_ASSERT(sizeof(res_dir) == 16 + 8) COMPILE_TIME_ASSERT(sizeof(res_data) == 16) COMPILE_TIME_ASSERT_ALIGNED1(res_dir_entry) COMPILE_TIME_ASSERT_ALIGNED1(res_dir) COMPILE_TIME_ASSERT_ALIGNED1(res_data) start = res; root = head = current = NULL; dsize = ssize = 0; check((const res_dir*) start,0); root = convert(start,NULL,0);}void PeFile::Resource::check(const res_dir *node,unsigned level){ int ic = node->identr + node->namedentr; if (ic == 0) return; for (const res_dir_entry *rde = node->entries; --ic >= 0; rde++) if (((rde->child & 0x80000000) == 0) ^ (level == 2)) throwCantPack("unsupported resource structure"); else if (level != 2) check((const res_dir*) (start + (rde->child & 0x7fffffff)),level + 1);}PeFile::Resource::upx_rnode *PeFile::Resource::convert(const void *rnode, upx_rnode *parent, unsigned level){ if (level == 3) { const res_data *node = (const res_data *) rnode; upx_rleaf *leaf = new upx_rleaf; leaf->name = NULL; leaf->parent = parent; leaf->next = head; leaf->newoffset = 0; leaf->data = *node; head = leaf; // append node to a linked list for traversal dsize += sizeof(res_data); return leaf; } const res_dir *node = (const res_dir *) rnode; int ic = node->identr + node->namedentr; if (ic == 0) return NULL; upx_rbranch *branch = new upx_rbranch; branch->name = NULL; branch->parent = parent; branch->nc = ic; branch->children = new upx_rnode*[ic]; branch->data = *node; for (const res_dir_entry *rde = node->entries + ic - 1; --ic >= 0; rde--) { upx_rnode *child = convert(start + (rde->child & 0x7fffffff),branch,level + 1); branch->children[ic] = child; child->id = rde->tnl; if (child->id & 0x80000000) { const upx_byte *p = start + (child->id & 0x7fffffff); const unsigned len = 2 + 2 * get_le16(p); child->name = new upx_byte[len]; memcpy(child->name,p,len); // copy unicode string ssize += len; // size of unicode strings } } dsize += node->Sizeof(); return branch;}void PeFile::Resource::build(const upx_rnode *node, unsigned &bpos, unsigned &spos, unsigned level){ if (level == 3) { res_data *l = (res_data*) (newstart + bpos); const upx_rleaf *leaf = (const upx_rleaf*) node; *l = leaf->data; if (leaf->newoffset) l->offset = leaf->newoffset; bpos += sizeof(*l); return; } res_dir * const b = (res_dir*) (newstart + bpos); const upx_rbranch *branch = (const upx_rbranch*) node; *b = branch->data; bpos += b->Sizeof(); res_dir_entry *be = b->entries; for (unsigned ic = 0; ic < branch->nc; ic++, be++) { be->tnl = branch->children[ic]->id; be->child = bpos + ((level < 2) ? 0x80000000 : 0); const upx_byte *p; if ((p = branch->children[ic]->name) != 0) { be->tnl = spos + 0x80000000; memcpy(newstart + spos,p,get_le16(p) * 2 + 2); spos += get_le16(p) * 2 + 2; } build(branch->children[ic],bpos,spos,level + 1); }}upx_byte *PeFile::Resource::build(){ newstart = new upx_byte [dirsize()]; unsigned bpos = 0,spos = dsize; build(root,bpos,spos,0); // dirsize() is 4 bytes aligned, so we may need to zero // up to 2 bytes to make valgrind happy while (spos < dirsize()) newstart[spos++] = 0; return newstart;}void PeFile::Resource::destroy(upx_rnode *node,unsigned level){ delete [] node->name; node->name = NULL; if (level != 3) { upx_rbranch * const branch = (upx_rbranch *) node; for (int ic = branch->nc; --ic >= 0; ) destroy(branch->children[ic],level + 1); delete [] branch->children; branch->children = NULL; } delete node;}static void lame_print_unicode(const upx_byte *p){ for (unsigned ic = 0; ic < get_le16(p); ic++) printf("%c",(char)p[ic * 2 + 2]);}void PeFile::Resource::dump(const upx_rnode *node,unsigned level) const{ if (level) { for (unsigned ic = 1; ic < level; ic++) printf("\t\t"); if (node->name) lame_print_unicode(node->name); else printf("0x%x",node->id); printf("\n"); } if (level == 3) return; const upx_rbranch * const branch = (const upx_rbranch *) node; for (unsigned ic = 0; ic < branch->nc; ic++) dump(branch->children[ic],level + 1);}void PeFile::Resource::clear(upx_byte *node,unsigned level,Interval *iv){ if (level == 3) iv->add(node,sizeof (res_data)); else { const res_dir * const rd = (res_dir*) node; const unsigned n = rd->identr + rd->namedentr; const res_dir_entry *rde = rd->entries; for (unsigned ic = 0; ic < n; ic++, rde++) clear(newstart + (rde->child & 0x7fffffff),level + 1,iv); iv->add(rd,rd->Sizeof()); }}bool PeFile::Resource::clear(){ newstart = const_cast<upx_byte*> (start); Interval iv(newstart); clear(newstart,0,&iv); iv.flatten(); if (iv.ivnum == 1) iv.clear();#if defined(DEBUG) if (opt->verbose > 3) iv.dump();#endif return iv.ivnum == 1;}void PeFile::processResources(Resource *res,unsigned newaddr){ if (IDSIZE(PEDIR_RESOURCE) == 0) return; while (res->next()) if (res->newoffs()) res->newoffs() += newaddr; upx_byte *p = res->build(); memcpy(oresources,p,res->dirsize()); delete [] p;}static bool match(unsigned itype, const unsigned char *ntype, unsigned iname, const unsigned char *nname, const char *keep){ // format of string keep: type1[/name1],type2[/name2], .... // typex and namex can be string or number // hopefully resource names do not have '/' or ',' characters inside struct helper { static bool match(unsigned num, const unsigned char *unistr, const char *mkeep) { if (!unistr) return (unsigned) atoi(mkeep) == num; unsigned ic; for (ic = 0; ic < get_le16(unistr); ic++) if (unistr[2 + ic * 2] != (unsigned char) mkeep[ic]) return false; return mkeep[ic] == 0 || mkeep[ic] == ',' || mkeep[ic] == '/'; } }; // FIXME this comparison is not too exact while (1) { char *delim1 = strchr(keep, '/'); char *delim2 = strchr(keep, ','); if (helper::match(itype, ntype, keep)) { if (!delim1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -