int cli_rebuildpe(char *buffer, struct cli_exe_section *sections, int sects, uint32_t base, uint32_t ep, uint32_t ResRva, uint32_t ResSize, int file) { uint32_t datasize=0, rawbase=PESALIGN(0x148+0x80+0x28*sects, 0x200); char *pefile=NULL, *curpe; struct IMAGE_PE_HEADER *fakepe; int i, gotghost=(sections[0].rva > PESALIGN(rawbase, 0x1000)); if (gotghost) rawbase=PESALIGN(0x148+0x80+0x28*(sects+1), 0x200); if(sects+gotghost > 96) return 0; for (i=0; i < sects; i++) datasize+=PESALIGN(sections[i].rsz, 0x200); if(datasize > CLI_MAX_ALLOCATION) return 0; if((pefile = (char *) cli_calloc(rawbase+datasize, 1))) { memcpy(pefile, HEADERS, 0x148); datasize = PESALIGN(rawbase, 0x1000); fakepe = (struct IMAGE_PE_HEADER *)(pefile+0xd0); fakepe->NumberOfSections = EC16(sects+gotghost); fakepe->AddressOfEntryPoint = EC32(ep); fakepe->ImageBase = EC32(base); fakepe->SizeOfHeaders = EC32(rawbase); memset(pefile+0x148, 0, 0x80); cli_writeint32(pefile+0x148+0x10, ResRva); cli_writeint32(pefile+0x148+0x14, ResSize); curpe = pefile+0x148+0x80; if (gotghost) { snprintf(curpe, 8, "empty"); cli_writeint32(curpe+8, sections[0].rva-datasize); /* vsize */ cli_writeint32(curpe+12, datasize); /* rva */ cli_writeint32(curpe+0x24, 0xffffffff); curpe+=40; datasize+=PESALIGN(sections[0].rva-datasize, 0x1000); } for (i=0; i < sects; i++) { snprintf(curpe, 8, ".clam%.2d", i+1); cli_writeint32(curpe+8, sections[i].vsz); cli_writeint32(curpe+12, sections[i].rva); cli_writeint32(curpe+16, sections[i].rsz); cli_writeint32(curpe+20, rawbase); /* already zeroed cli_writeint32(curpe+24, 0); cli_writeint32(curpe+28, 0); cli_writeint32(curpe+32, 0); */ cli_writeint32(curpe+0x24, 0xffffffff); memcpy(pefile+rawbase, buffer+sections[i].raw, sections[i].rsz); rawbase+=PESALIGN(sections[i].rsz, 0x200); curpe+=40; datasize+=PESALIGN(sections[i].vsz, 0x1000); } fakepe->SizeOfImage = EC32(datasize); } else { return 0; } i = (cli_writen(file, pefile, rawbase)!=-1); free(pefile); return i; }
static int pefromupx (const char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t ep, uint32_t upx0, uint32_t upx1, uint32_t *magic, uint32_t dend) { char *imports, *sections=NULL, *pehdr=NULL, *newbuf; unsigned int sectcnt=0, upd=1; uint32_t realstuffsz=0, valign=0; uint32_t foffset=0xd0+0xf8; if((dst == NULL) || (src == NULL)) return 0; while ((valign=magic[sectcnt++])) { if ( ep - upx1 + valign <= ssize-5 && /* Wondering how we got so far?! */ src[ep - upx1 + valign - 2] == '\x8d' && /* lea edi, ... */ src[ep - upx1 + valign - 1] == '\xbe' ) /* ... [esi + offset] */ break; } if (!valign && ep - upx1 + 0x80 < ssize-8) { const char *pt = &src[ep - upx1 + 0x80]; cli_dbgmsg("UPX: bad magic - scanning for imports\n"); while ((pt=cli_memstr(pt, ssize - (pt-src) - 8, "\x8d\xbe", 2))) { if (pt[6] == '\x8b' && pt[7] == '\x07') { /* lea edi, [esi+imports] / mov eax, [edi] */ valign=pt-src+2-ep+upx1; break; } pt++; } } if (valign && CLI_ISCONTAINED(src, ssize, src + ep - upx1 + valign, 4)) { imports = dst + cli_readint32(src + ep - upx1 + valign); realstuffsz = imports-dst; if (realstuffsz >= *dsize ) { cli_dbgmsg("UPX: wrong realstuff size\n"); /* fallback and eventually craft */ } else { pehdr = imports; while (CLI_ISCONTAINED(dst, *dsize, pehdr, 8) && cli_readint32(pehdr)) { pehdr+=8; while(CLI_ISCONTAINED(dst, *dsize, pehdr, 2) && *pehdr) { pehdr++; while (CLI_ISCONTAINED(dst, *dsize, pehdr, 2) && *pehdr) pehdr++; pehdr++; } pehdr++; } pehdr+=4; if (!(sections=checkpe(dst, *dsize, pehdr, &valign, §cnt))) pehdr=NULL; } } if (!pehdr && dend>0xf8+0x28) { cli_dbgmsg("UPX: no luck - scanning for PE\n"); pehdr = &dst[dend-0xf8-0x28]; while (pehdr>dst) { if ((sections=checkpe(dst, *dsize, pehdr, &valign, §cnt))) break; pehdr--; } if (!(realstuffsz = pehdr-dst)) pehdr=NULL; } if (!pehdr) { uint32_t rebsz = PESALIGN(dend, 0x1000); cli_dbgmsg("UPX: no luck - brutally crafing a reasonable PE\n"); if (!(newbuf = (char *)cli_calloc(rebsz+0x200, sizeof(char)))) { cli_dbgmsg("UPX: malloc failed - giving up rebuild\n"); return 0; } memcpy(newbuf, HEADERS, 0xd0); memcpy(newbuf+0xd0, FAKEPE, 0x120); memcpy(newbuf+0x200, dst, dend); memcpy(dst, newbuf, dend+0x200); free(newbuf); cli_writeint32(dst+0xd0+0x50, rebsz+0x1000); cli_writeint32(dst+0xd0+0x100, rebsz); cli_writeint32(dst+0xd0+0x108, rebsz); *dsize=rebsz+0x200; cli_dbgmsg("UPX: PE structure added to uncompressed data\n"); return 1; } if (!sections) sectcnt = 0; foffset = PESALIGN(foffset+0x28*sectcnt, valign); for (upd = 0; upd <sectcnt ; upd++) { uint32_t vsize=PESALIGN((uint32_t)cli_readint32(sections+8), valign); uint32_t urva=PEALIGN((uint32_t)cli_readint32(sections+12), valign); /* Within bounds ? */ if (!CLI_ISCONTAINED(upx0, realstuffsz, urva, vsize)) { cli_dbgmsg("UPX: Sect %d out of bounds - giving up rebuild\n", upd); return 0; } cli_writeint32(sections+8, vsize); cli_writeint32(sections+12, urva); cli_writeint32(sections+16, vsize); cli_writeint32(sections+20, foffset); if (foffset + vsize < foffset) { /* Integer overflow */ return 0; } foffset+=vsize; sections+=0x28; } cli_writeint32(pehdr+8, 0x4d414c43); cli_writeint32(pehdr+0x3c, valign); if (!(newbuf = (char *) cli_calloc(foffset, sizeof(char)))) { cli_dbgmsg("UPX: malloc failed - giving up rebuild\n"); return 0; } memcpy(newbuf, HEADERS, 0xd0); memcpy(newbuf+0xd0, pehdr,0xf8+0x28*sectcnt); sections = pehdr+0xf8; for (upd = 0; upd <sectcnt ; upd++) { uint32_t offset1, offset2, offset3; offset1 = (uint32_t)cli_readint32(sections+20); offset2 = (uint32_t)cli_readint32(sections+16); if (offset1 > foffset || offset2 > foffset || offset1 + offset2 > foffset) { free(newbuf); return 1; } offset3 = (uint32_t)cli_readint32(sections+12); if (offset3-upx0 > *dsize) { free(newbuf); return 1; } memcpy(newbuf+offset1, dst+offset3-upx0, offset2); sections+=0x28; } /* CBA restoring the imports they'll look different from the originals anyway... */ /* ...and yeap i miss the icon too :P */ if (foffset > *dsize + 8192) { cli_dbgmsg("UPX: wrong raw size - giving up rebuild\n"); free(newbuf); return 0; } memcpy(dst, newbuf, foffset); *dsize = foffset; free(newbuf); cli_dbgmsg("UPX: PE structure rebuilt from compressed file\n"); return 1; }