int unfsg_133(const char *source, char *dest, int ssize, int dsize, struct cli_exe_section *sections, int sectcount, uint32_t base, uint32_t ep, int file) { const char *tsrc=source; char *tdst=dest; int i, upd=1, offs=0, lastsz=dsize; for (i = 0 ; i <= sectcount ; i++) { char *startd=tdst; if ( cli_unfsg(tsrc, tdst, ssize - (tsrc - source), dsize - (tdst - dest), &tsrc, &tdst) == -1 ) return -1; /* RVA has been filled already in pe.c */ sections[i].raw=offs; sections[i].rsz=tdst-startd; /* cli_dbgmsg("Unpacked section %d @%x size %x Vsize =%x \n", i, offs, tdst-startd, dsize - (startd - dest)); */ offs+=tdst-startd; } /* Sort out the sections */ while ( upd ) { upd = 0; for (i = 0; i < sectcount ; i++) { uint32_t trva,trsz,traw; if ( sections[i].rva <= sections[i+1].rva ) continue; trva = sections[i].rva; traw = sections[i].raw; trsz = sections[i].rsz; sections[i].rva = sections[i+1].rva; sections[i].rsz = sections[i+1].rsz; sections[i].raw = sections[i+1].raw; sections[i+1].rva = trva; sections[i+1].raw = traw; sections[i+1].rsz = trsz; upd = 1; } } /* Cure Vsizes and debugspam */ for (i = 0; i <= sectcount ; i++) { if ( i != sectcount ) { sections[i].vsz = sections[i+1].rva - sections[i].rva; lastsz-= sections[i+1].rva - sections[i].rva; } else sections[i].vsz = lastsz; cli_dbgmsg("FSG: .SECT%d RVA:%x VSize:%x ROffset: %x, RSize:%x\n", i, sections[i].rva, sections[i].vsz, sections[i].raw, sections[i].rsz); } if (!cli_rebuildpe(dest, sections, sectcount+1, base, ep, 0, 0, file)) { cli_dbgmsg("FSG: Rebuilding failed\n"); return 0; } return 1; }
int unfsg_200(const char *source, char *dest, int ssize, int dsize, uint32_t rva, uint32_t base, uint32_t ep, int file) { struct cli_exe_section section; /* Yup, just one ;) */ if ( cli_unfsg(source, dest, ssize, dsize, NULL, NULL) ) return -1; section.raw=0; section.rsz = dsize; section.vsz = dsize; section.rva = rva; if (!cli_rebuildpe(dest, §ion, 1, base, ep, 0, 0, file)) { cli_dbgmsg("FSG: Rebuilding failed\n"); return 0; } return 1; }
int petite_inflate2x_1to9(char *buf, uint32_t minrva, uint32_t bufsz, struct cli_exe_section *sections, unsigned int sectcount, uint32_t Imagebase, uint32_t pep, int desc, int version, uint32_t ResRva, uint32_t ResSize) { char *adjbuf = buf - minrva; char *packed = NULL; uint32_t thisrva=0, bottom = 0, enc_ep=0, irva=0, workdone=0, grown=0x355, skew=0x35; int j = 0, oob, mangled = 0, check4resources=0; struct cli_exe_section *usects = NULL; void *tmpsct = NULL; /* -] The real thing [- */ /* NOTE: (435063->4350a5) Petite kernel32!imports and error strings */ /* Here we adjust the start of packed blob, the size of petite code, * the difference in size if relocs were stripped * See below... */ if ( version == 2 ) packed = adjbuf + sections[sectcount-1].rva + 0x1b8; if ( version == 1 ) { packed = adjbuf + sections[sectcount-1].rva + 0x178; grown=0x323; /* My name is Harry potter */ skew=0x34; } while (1) { char *ssrc, *ddst; uint32_t size, srva; int backbytes, oldback, backsize, addsize; if ( ! CLI_ISCONTAINED(buf, bufsz, packed, 4)) { if (usects) free(usects); return 1; } srva = cli_readint32(packed); if (! srva) { /* WERE DONE !!! :D */ int t, upd = 1; if ( j <= 0 ) /* Some non petite compressed files will get here */ return 1; /* Select * from sections order by rva asc; */ while ( upd ) { upd = 0; for (t = 0; t < j-1 ; t++) { uint32_t trva, trsz, tvsz; if ( usects[t].rva <= usects[t+1].rva ) continue; trva = usects[t].rva; trsz = usects[t].rsz; tvsz = usects[t].vsz; usects[t].rva = usects[t+1].rva; usects[t].rsz = usects[t+1].rsz; usects[t].vsz = usects[t+1].vsz; usects[t+1].rva = trva; usects[t+1].rsz = trsz; usects[t+1].vsz = tvsz; upd = 1; } } /* Computes virtualsize... we try to guess, actually :O */ for (t = 0; t < j-1 ; t++) { if ( usects[t].vsz != usects[t+1].rva - usects[t].rva ) usects[t].vsz = usects[t+1].rva - usects[t].rva; } /* * Our encryption is pathetic and out software is lame but * we need to claim it's unbreakable. * So why dont we just mangle the imports and encrypt the EP?! */ /* Decrypts old entrypoint if we got enough clues */ if (enc_ep) { uint32_t virtaddr = pep + 5 + Imagebase, tmpep; int rndm = 0, dummy = 1; char *thunk = adjbuf+irva; char *imports; if ( version == 2 ) { /* 2.2 onley */ while ( dummy && CLI_ISCONTAINED(buf, bufsz, thunk, 4) ) { uint32_t api; if (! cli_readint32(thunk)) { workdone = 1; break; } imports = adjbuf + cli_readint32(thunk); thunk+=4; dummy = 0; while ( CLI_ISCONTAINED(buf, bufsz, imports, 4)) { dummy = 0; imports+=4; if ( ! (api = cli_readint32(imports-4)) ) { dummy = 1; break; } if ( (api != (api | 0x80000000)) && mangled && --rndm < 0) { api = virtaddr; virtaddr +=5; /* EB + 1 double */ rndm = virtaddr & 7; } else { api = 0xbff01337; /* KERNEL32!leet */ } if (sections[sectcount-1].rva+Imagebase < api ) enc_ep--; if ( api < virtaddr ) enc_ep--; tmpep = (enc_ep & 0xfffffff8)>>3 & 0x1fffffff; enc_ep = (enc_ep & 7)<<29 | tmpep; } } } else workdone = 1; enc_ep = pep+5+enc_ep; if ( workdone == 1 ) { cli_dbgmsg("Petite: Old EP: %x\n", enc_ep); } else { enc_ep = usects[0].rva; cli_dbgmsg("Petite: In troubles while attempting to decrypt old EP, using bogus %x\n", enc_ep); } } /* Let's compact data */ for (t = 0; t < j ; t++) { usects[t].raw = (t>0)?(usects[t-1].raw + usects[t-1].rsz):0; if (usects[t].rsz != 0) { if(CLI_ISCONTAINED(buf, bufsz, buf + usects[t].raw, usects[t].rsz)) { memmove(buf + usects[t].raw, adjbuf + usects[t].rva, usects[t].rsz); } else { cli_dbgmsg("Petite: Skipping section %d, Raw: %x, RSize:%x\n", t, usects[t].raw, usects[t].rsz); usects[t].raw = t>0 ? usects[t-1].raw : 0; usects[t].rsz = 0; } } } /* Showtime!!! */ cli_dbgmsg("Petite: Sections dump:\n"); for (t = 0; t < j ; t++) cli_dbgmsg("Petite: .SECT%d RVA:%x VSize:%x ROffset: %x, RSize:%x\n", t, usects[t].rva, usects[t].vsz, usects[t].raw, usects[t].rsz); if (! cli_rebuildpe(buf, usects, j, Imagebase, enc_ep, ResRva, ResSize, desc)) { cli_dbgmsg("Petite: Rebuilding failed\n"); free(usects); return 1; } free(usects); return 0; }
int unupack(int upack, char *dest, uint32_t dsize, char *buff, uint32_t vma, uint32_t ep, uint32_t base, uint32_t va, int file) { int j, searchval; char *loc_esi, *loc_edi, *loc_ebx, *end_edi, *save_edi, *rpeb, *alvalue; char *paddr, *pushed_esi, *save2; uint32_t save1, save3, loc_ecx, count, shlsize, original_ep, ret, loc_ebx_u; struct cli_exe_section section; int upack_version = UPACK_399; /* buff [168 bytes] doesn't have to be checked, since it was checked in pe.c */ if (upack) { uint32_t aljump, shroff, lngjmpoff; /* dummy characteristics ;/ */ if (buff[5] == '\xff' && buff[6] == '\x36') upack_version = UPACK_0297729; loc_esi = dest + (cli_readint32(buff + 1) - vma); if (!CLI_ISCONTAINED(dest, dsize, loc_esi, 12)) return -1; original_ep = cli_readint32(loc_esi); loc_esi += 4; /*cli_readint32(loc_esi);*/ loc_esi += 4; original_ep -= vma; cli_dbgmsg("Upack: EP: %08x original: %08X || %08x\n", ep, original_ep, cli_readint32(loc_esi-8)); if (upack_version == UPACK_399) { /* jmp 1 */ loc_edi = dest + (cli_readint32(loc_esi) - vma); if (!CLI_ISCONTAINED(dest, dsize, dest+ep+0xa, 2) || dest[ep+0xa] != '\xeb') return -1; loc_esi = dest + *(dest + ep + 0xb) + ep + 0xc; /* use this as a temp var */ /* jmp 2 + 0xa */ alvalue = loc_esi+0x1a; if (!CLI_ISCONTAINED(dest, dsize, alvalue, 2) || *alvalue != '\xeb') return -1; alvalue++; alvalue += (*alvalue&0xff) + 1 + 0xa; lngjmpoff = 8; } else { if (!CLI_ISCONTAINED(dest, dsize, dest+ep+7, 5) || dest[ep+7] != '\xe9') return -1; loc_esi = dest + cli_readint32(dest + ep + 8) + ep + 0xc; alvalue = loc_esi + 0x25; lngjmpoff = 10; } if (!CLI_ISCONTAINED(dest, dsize, alvalue, 2) || *alvalue != '\xb5') return -1; alvalue++; count = *alvalue&0xff; if (!CLI_ISCONTAINED(dest, dsize, alvalue, lngjmpoff+5) || *(alvalue+lngjmpoff) != '\xe9') return -1; /* use this as a temp to make a long jmp to head of unpacking proc */ shlsize = cli_readint32(alvalue + lngjmpoff+1); /* upack_399 + upack_0151477 */ if (upack_version == UPACK_399) shlsize = shlsize + (loc_esi - dest) + *(loc_esi+0x1b) + 0x1c + 0x018; /* read checked above */ else /* there is no additional jump in upack_0297729 */ shlsize = shlsize + (loc_esi - dest) + 0x035; /* do the jump, 43 - point to jecxz */ alvalue = dest+shlsize+43; /* 0.39 */ aljump = 8; shroff = 24; if (!CLI_ISCONTAINED(dest, dsize, alvalue-1, 2) || *(alvalue-1) != '\xe3') { /* in upack_0297729 and upack_0151477 jecxz is at offset: 46 */ alvalue = dest+shlsize+46; if (!CLI_ISCONTAINED(dest, dsize, alvalue-1, 2) || *(alvalue-1) != '\xe3') return -1; else { if (upack_version != UPACK_0297729) upack_version = UPACK_0151477; aljump = 7; shroff = 26; } } /* do jecxz */ alvalue += (*alvalue&0xff) + 1; /* is there a long jump ? */ if (!CLI_ISCONTAINED(dest, dsize, alvalue, aljump+5) || *(alvalue+aljump) != '\xe9') return -1; /* do jmp, 1+4 - size of jmp instruction, aljump - instruction offset, 27 offset to cmp al,xx*/ ret = cli_readint32(alvalue+aljump+1); alvalue += ret + aljump+1+4 + 27; if (upack_version == UPACK_0297729) alvalue += 2; /* shr ebp */ if (!CLI_ISCONTAINED(dest, dsize, dest+shlsize+shroff, 3) || *(dest+shlsize+shroff) != '\xc1' || *(dest+shlsize+shroff+1) != '\xed') return -1; shlsize = (*(dest + shlsize + shroff+2))&0xff; count *= 0x100; if (shlsize < 2 || shlsize > 8) { cli_dbgmsg ("Upack: context bits out of bounds\n"); return -1; } cli_dbgmsg("Upack: Context Bits parameter used with lzma: %02x, %02x\n", shlsize, count); /* check if loc_esi + .. == 0xbe -> mov esi */ /* upack_0297729 has mov esi, .. + mov edi, .., in upack_0151477 and upack_399 EDI has been already set before */ if (upack_version == UPACK_0297729) { if (!CLI_ISCONTAINED(dest, dsize, loc_esi+6, 10) || *(loc_esi+6) != '\xbe' || *(loc_esi+11) != '\xbf') return -1; if ((uint32_t)cli_readint32(loc_esi + 7) < base || (uint32_t)cli_readint32(loc_esi+7) > vma) return -1; loc_edi = dest + (cli_readint32(loc_esi + 12) - vma); loc_esi = dest + (cli_readint32(loc_esi + 7) - base); } else { if (!CLI_ISCONTAINED(dest, dsize, loc_esi+7, 5) || *(loc_esi+7) != '\xbe') return -1; loc_esi = dest + (cli_readint32(loc_esi + 8) - vma); } if (upack_version == UPACK_0297729) { /* 0x16*4=0x58, 6longs*4 = 24, 0x64-last loc_esi read location */ if (!CLI_ISCONTAINED(dest, dsize, loc_edi, (0x58 + 24 + 4*count)) || !CLI_ISCONTAINED(dest, dsize, loc_esi, (0x58 + 0x64 + 4))) return -1; /* XXX I don't know if this [0x16] is constant number, not enough samples provided */ for (j=0; j<0x16; j++, loc_esi+=4, loc_edi+=4) cli_writeint32(loc_edi, cli_readint32(loc_esi)); } else { /* 0x27*4=0x9c, 6longs*4 = 24, 0x34-last loc_esi read location */ if (!CLI_ISCONTAINED(dest, dsize, loc_edi, (0x9c + 24 + 4*count)) || !CLI_ISCONTAINED(dest, dsize, loc_esi, (0x9c + 0x34 + 4))) return -1; for (j=0; j<0x27; j++, loc_esi+=4, loc_edi+=4) cli_writeint32(loc_edi, cli_readint32(loc_esi)); } save3 = cli_readint32(loc_esi + 4); paddr = dest + ((uint32_t)cli_readint32(loc_edi - 4)) - vma; loc_ebx = loc_edi; cli_writeint32(loc_edi, 0xffffffff); loc_edi+=4; cli_writeint32(loc_edi, 0); loc_edi+=4; for (j=0; j<4; j++, loc_edi+=4) cli_writeint32(loc_edi, (1)); for (j=0; (unsigned int)j<count; j++, loc_edi+=4) cli_writeint32(loc_edi, 0x400); loc_edi = dest + cli_readint32(loc_esi + 0xc) - vma; if (upack_version == UPACK_0297729) loc_edi = dest+vma-base; /* XXX not enough samples provided to be sure of it! */ pushed_esi = loc_edi; end_edi = dest + cli_readint32(loc_esi + 0x34) - vma; if (upack_version == UPACK_0297729) { end_edi = dest + cli_readint32(loc_esi + 0x64) - vma; save3 = cli_readint32(loc_esi + 0x40); } /* begin end */ cli_dbgmsg("Upack: data initialized, before upack lzma call!\n"); if ((ret = (uint32_t)unupack399(dest, dsize, 0, loc_ebx, 0, loc_edi, end_edi, shlsize, paddr)) == 0xffffffff) return -1; /* alternative begin */ } else { int ep_jmp_offs, rep_stosd_count_offs, context_bits_offs; loc_esi = dest + vma + ep; /* yet another dummy characteristics ;/ */ if (buff[0] == '\xbe' && buff[5] == '\xad' && buff[6] == '\x8b' && buff[7] == '\xf8') upack_version = UPACK_11_12; if (upack_version == UPACK_11_12) { ep_jmp_offs = 0x1a4; rep_stosd_count_offs = 0x1b; context_bits_offs = 0x41; alvalue = loc_esi + 0x184; } else { ep_jmp_offs = 0x217; rep_stosd_count_offs = 0x3a; context_bits_offs = 0x5f; alvalue = loc_esi + 0x1c1; } if (!CLI_ISCONTAINED(dest, dsize, loc_esi, ep_jmp_offs+4)) return -1; save1 = cli_readint32(loc_esi + ep_jmp_offs); original_ep = (loc_esi - dest) + ep_jmp_offs + 4; original_ep += (int32_t)save1; cli_dbgmsg("Upack: EP: %08x original %08x\n", ep, original_ep); /* this are really ugly hacks, * rep_stosd_count_offs & context_bits_offs are < ep_jmp_offs, * so checked in CLI_ISCONTAINED above */ count = (*(loc_esi + rep_stosd_count_offs))&0xff; shlsize = (*(loc_esi + context_bits_offs))&0xff; shlsize = 8 - shlsize; if (shlsize < 2 || shlsize > 8) { cli_dbgmsg ("Upack: context bits out of bounds\n"); return -1; } count *= 0x100; cli_dbgmsg("Upack: Context Bits parameter used with lzma: %02x, %02x\n", shlsize, count); if (upack_version == UPACK_399) { loc_esi += 4; loc_ecx = cli_readint32(loc_esi+2); cli_writeint32(loc_esi+2,0); if (!loc_ecx) { cli_dbgmsg("Upack: something's wrong, report back\n"); return -1;/* XXX XXX XXX XXX */ } loc_esi -= (loc_ecx - 2); if (!CLI_ISCONTAINED(dest, dsize, loc_esi, 12)) return -1; cli_dbgmsg("Upack: %08x %08x %08x %08x\n", loc_esi, dest, cli_readint32(loc_esi), base); loc_ebx_u = loc_esi - (dest + cli_readint32(loc_esi) - base); cli_dbgmsg("Upack: EBX: %08x\n", loc_ebx_u); loc_esi += 4; save2 = loc_edi = dest + cli_readint32(loc_esi) - base; cli_dbgmsg("Upack: DEST: %08x, %08x\n", cli_readint32(loc_esi), cli_readint32(loc_esi) - base); loc_esi += 4; /* 2vGiM: j is signed. Is that really what you want? Will it cause problems with the following checks? * yes! this is wrong! how did you notice that?! */ j = cli_readint32(loc_esi); if (j<0) { cli_dbgmsg("Upack: probably hand-crafted data, report back\n"); return -1; } loc_esi += 4; cli_dbgmsg("Upack: ecx counter: %08x\n", j); if (!CLI_ISCONTAINED(dest, dsize, loc_esi, (j*4)) || !CLI_ISCONTAINED(dest, dsize, loc_edi, ((j+count)*4))) return -1; for (;j--; loc_edi+=4, loc_esi+=4) cli_writeint32(loc_edi, cli_readint32(loc_esi)); if (!CLI_ISCONTAINED(dest, dsize, save2, 8)) return -1; loc_ecx = cli_readint32(save2); save2 += 4; loc_esi = save2; /* I could probably do simple loc_esi+= (0xe<<2), * but I'm not sure if there is always 0xe and is always ebx =0 */ do { loc_esi += loc_ebx_u; loc_esi += 4; } while (--loc_ecx); if (!CLI_ISCONTAINED(dest, dsize, loc_esi, 4)) return -1; save1 = cli_readint32(loc_esi); /* loc_eax = 0x400 */ loc_esi += 4; for (j=0; j<count; j++, loc_edi+=4) /* checked above */ cli_writeint32(loc_edi, (save1)); if (!CLI_ISCONTAINED(dest, dsize, (loc_esi+0x10), 4)) return -1; cli_writeint32(loc_esi+0x10, (uint32_t)cli_readint32(loc_esi+0x10)+loc_ebx_u); loc_ebx = loc_esi+0x14; loc_esi = save2; /* loc_ebx_u gets saved */ /* checked above, (...save2, 8) */ save_edi = loc_edi = dest + ((uint32_t)cli_readint32(loc_esi) - base); loc_esi +=4; cli_dbgmsg("Upack: before_fixing\n"); /* fix values */ if (!CLI_ISCONTAINED(dest, dsize, loc_ebx-4, (12 + 4*4)) || !CLI_ISCONTAINED(dest, dsize, loc_esi+0x24, 4) || !CLI_ISCONTAINED(dest, dsize, loc_esi+0x40, 4)) return -1; for (j=2; j<6; j++) cli_writeint32(loc_ebx+(j<<2), cli_readint32(loc_ebx+(j<<2))); paddr = dest + cli_readint32(loc_ebx - 4) - base; save1 = loc_ecx; pushed_esi = loc_edi; end_edi = dest + cli_readint32(loc_esi+0x24) - base; vma = cli_readint32(loc_ebx); cli_writeint32(loc_ebx, cli_readint32(loc_ebx + 4)); cli_writeint32((loc_ebx + 4), vma); /* Upack 1.1/1.2 is something between 0.39 2-section and 0.39 3-section */ } else if (upack_version == UPACK_11_12) { cli_dbgmsg("Upack v 1.1/1.2\n"); loc_esi = dest + 0x148; /* always constant? */ loc_edi = dest + cli_readint32(loc_esi) - base; /* read checked above */ loc_esi += 4; save_edi = loc_edi; /* movsd */ paddr = dest + ((uint32_t)cli_readint32(loc_esi)) - base; loc_esi += 4; loc_edi += 4; loc_ebx = loc_edi; if (!CLI_ISCONTAINED(dest, dsize, loc_edi, ((6+count)*4))) return -1; cli_writeint32(loc_edi, 0xffffffff); loc_edi += 4; cli_writeint32(loc_edi, 0); loc_edi += 4; for (j=0; j<4; j++, loc_edi+=4) cli_writeint32(loc_edi, (1)); for (j=0; j<count; j++, loc_edi+=4) cli_writeint32(loc_edi, 0x400); loc_edi = dest + cli_readint32(loc_esi) - base; /* read checked above */ pushed_esi = loc_edi; loc_esi += 4; loc_ecx = 0; loc_esi += 4; end_edi = dest + cli_readint32(loc_esi-0x28) - base; /* read checked above */ loc_esi = save_edi; } cli_dbgmsg("Upack: data initialized, before upack lzma call!\n"); if ((ret = (uint32_t)unupack399(dest, dsize, loc_ecx, loc_ebx, loc_ecx, loc_edi, end_edi, shlsize, paddr)) == 0xffffffff) return -1; if (upack_version == UPACK_399) save3 = cli_readint32(loc_esi + 0x40); else if (upack_version == UPACK_11_12) save3 = cli_readint32(dest + vma + ep + 0x174); } /* let's fix calls */ loc_ecx = 0; if (!CLI_ISCONTAINED(dest, dsize, alvalue, 1)) { cli_dbgmsg("Upack: alvalue out of bounds\n"); return -1; } searchval = *alvalue&0xff; cli_dbgmsg("Upack: loops: %08x search value: %02x\n", save3, searchval); while(save3) { if (!CLI_ISCONTAINED(dest, dsize, pushed_esi + loc_ecx, 1)) { cli_dbgmsg("Upack: callfixerr %08x %08x = %08x, %08x\n", dest, dsize, dest+dsize, pushed_esi+loc_ecx); return -1; } if (pushed_esi[loc_ecx] == '\xe8' || pushed_esi[loc_ecx] == '\xe9') { char *adr = (pushed_esi + loc_ecx + 1); loc_ecx++; if (!CLI_ISCONTAINED(dest, dsize, adr, 4)) { cli_dbgmsg("Upack: callfixerr\n"); return -1; } if ((cli_readint32(adr)&0xff) != searchval) continue; cli_writeint32(adr, EC32(CE32((uint32_t)(cli_readint32(adr)&0xffffff00)))-loc_ecx-4); loc_ecx += 4; save3--; } else loc_ecx++; } section.raw = 0; section.rva = va; section.rsz = end_edi-loc_edi; section.vsz = end_edi-loc_edi; if (!cli_rebuildpe(dest + (upack?0:va), §ion, 1, base, original_ep, 0, 0, file)) { cli_dbgmsg("Upack: Rebuilding failed\n"); return 0; } return 1; }