int upx_inflatelzma(const char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep) { struct CLI_LZMA l; uint32_t magic[]={0xb16,0xb1e,0}; unsigned char fake_lzmahdr[5]; memset(&l, 0, sizeof(l)); cli_writeint32(fake_lzmahdr + 1, *dsize); *fake_lzmahdr = 3 /* lc */ + 9* ( 5* 2 /* pb */ + 0 /* lp */); l.next_in = fake_lzmahdr; l.avail_in = 5; if(cli_LzmaInit(&l, *dsize) != LZMA_RESULT_OK) return 0; l.avail_in = ssize; l.avail_out = *dsize; l.next_in = (unsigned char*)src+2; l.next_out = (unsigned char*)dst; if(cli_LzmaDecode(&l)==LZMA_RESULT_DATA_ERROR) { /* __asm__ __volatile__("int3"); */ cli_LzmaShutdown(&l); return -1; } cli_LzmaShutdown(&l); return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, *dsize); }
END_TEST /* test writing with different alignments, _i is parameter from tcase_add_loop_test */ START_TEST (test_cli_writeint32) { size_t j; /* write 4 bytes apart, start is not always aligned*/ for(j=_i;j < DATA_REP*sizeof(le_data) - 4;j += 4) { cli_writeint32(&data2[j], 0x12345678); } for(j=_i;j < DATA_REP*sizeof(le_data) - 4;j += 4) { fail_unless(cli_readint32(&data2[j]) == 0x12345678, "write/read mismatch"); } /* write 4 bytes apart, always aligned*/ for(j=0;j < DATA_REP*sizeof(le_data) - 4;j += 4) { cli_writeint32(&data2[j], 0x12345678); } for(j=0;j < DATA_REP*sizeof(le_data) - 4;j += 4) { fail_unless(cli_readint32(&data2[j]) == 0x12345678, "write/read mismatch"); } }
int yc_decrypt(char *fbuf, unsigned int filesize, struct cli_exe_section *sections, unsigned int sectcount, uint32_t peoffset, int desc) { uint32_t ycsect = sections[sectcount].raw; unsigned int i; struct pe_image_file_hdr *pe = (struct pe_image_file_hdr*) (fbuf + peoffset); char *sname = (char *)pe + EC16(pe->SizeOfOptionalHeader) + 0x18; /* First layer (decryptor of the section decryptor) in last section Start offset for analyze: Start of yC Section + 0x93 End offset for analyze: Start of yC Section + 0xC3 Lenght to decrypt - ECX = 0xB97 */ cli_dbgmsg("yC: decrypting decryptor on sect %d\n", sectcount); if (yc_poly_emulator(fbuf + ycsect + 0x93, fbuf + ycsect + 0xc6 ,0xB97)) return 1; filesize-=sections[sectcount].ursz; /* Second layer (decryptor of the sections) in last section Start offset for analyze: Start of yC Section + 0x457 End offset for analyze: Start of yC Section + 0x487 Lenght to decrypt - ECX = Raw Size of Section */ /* Loop through all sections and decrypt them... */ for(i=0;i<sectcount;i++) { uint32_t name = (uint32_t) cli_readint32(sname+i*0x28); if ( !sections[i].raw || !sections[i].rsz || name == 0x63727372 || /* rsrc */ name == 0x7273722E || /* .rsr */ name == 0x6F6C6572 || /* relo */ name == 0x6C65722E || /* .rel */ name == 0x6164652E || /* .eda */ name == 0x6164722E || /* .rda */ name == 0x6164692E || /* .ida */ name == 0x736C742E || /* .tls */ (name&0xffff) == 0x4379 /* yC */ ) continue; cli_dbgmsg("yC: decrypting sect%d\n",i); if (yc_poly_emulator(fbuf + ycsect + 0x457, fbuf + sections[i].raw, sections[i].ursz)) return 1; } /* Remove yC section */ pe->NumberOfSections=EC16(sectcount); /* Remove IMPORT_DIRECTORY information */ memset((char *)pe + sizeof(struct pe_image_file_hdr) + 0x68, 0, 8); /* OEP resolving */ /* OEP = DWORD PTR [ Start of yC section+ A0F] */ cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 16, cli_readint32(fbuf + ycsect + 0xa0f)); /* Fix SizeOfImage */ cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38, cli_readint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38) - sections[sectcount].vsz); if (cli_writen(desc, fbuf, filesize)==-1) { cli_dbgmsg("yC: Cannot write unpacked file\n"); return 1; } return 0; }
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; }
int yc_decrypt(cli_ctx *ctx, char *fbuf, unsigned int filesize, struct cli_exe_section *sections, unsigned int sectcount, uint32_t peoffset, int desc, uint32_t ecx,int16_t offset) { uint32_t ycsect = sections[sectcount].raw+offset; unsigned int i; struct pe_image_file_hdr *pe = (struct pe_image_file_hdr*) (fbuf + peoffset); char *sname = (char *)pe + EC16(pe->SizeOfOptionalHeader) + 0x18; uint32_t max_emu; unsigned int ofilesize = filesize; /* First layer (decryptor of the section decryptor) in last section Start offset for analyze: Start of yC Section + 0x93 End offset for analyze: Start of yC Section + 0xC3 Length to decrypt - ECX = 0xB97 */ cli_dbgmsg("yC: offset: %x, length: %x\n", offset, ecx); cli_dbgmsg("yC: decrypting decryptor on sect %d\n", sectcount); switch (yc_poly_emulator(ctx, fbuf, filesize, fbuf + ycsect + 0x93, fbuf + ycsect + 0xc6, ecx, ecx)) { case 2: return CL_VIRUS; case 1: return CL_EUNPACK; } filesize-=sections[sectcount].ursz; /* Second layer (decryptor of the sections) in last section Start offset for analyze: Start of yC Section + 0x457 End offset for analyze: Start of yC Section + 0x487 Length to decrypt - ECX = Raw Size of Section */ /* Loop through all sections and decrypt them... */ for(i=0;i<sectcount;i++) { uint32_t name = (uint32_t) cli_readint32(sname+i*0x28); if (!sections[i].raw || !sections[i].rsz || name == 0x63727372 || /* rsrc */ name == 0x7273722E || /* .rsr */ name == 0x6F6C6572 || /* relo */ name == 0x6C65722E || /* .rel */ name == 0x6164652E || /* .eda */ name == 0x6164722E || /* .rda */ name == 0x6164692E || /* .ida */ name == 0x736C742E || /* .tls */ (name&0xffff) == 0x4379 /* yC */ ) continue; cli_dbgmsg("yC: decrypting sect%d\n",i); max_emu = filesize - sections[i].raw; if (max_emu > filesize) { cli_dbgmsg("yC: bad emulation length limit %u\n", max_emu); return 1; } switch (yc_poly_emulator(ctx, fbuf, ofilesize, fbuf + ycsect + (offset == -0x18 ? 0x3ea : 0x457), fbuf + sections[i].raw, sections[i].ursz, max_emu)) { case 2: return CL_VIRUS; case 1: return CL_EUNPACK; } } /* Remove yC section */ pe->NumberOfSections=EC16(sectcount); /* Remove IMPORT_DIRECTORY information */ memset((char *)pe + sizeof(struct pe_image_file_hdr) + 0x68, 0, 8); /* OEP resolving */ /* OEP = DWORD PTR [ Start of yC section+ A0F] */ cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 16, cli_readint32(fbuf + ycsect + 0xa0f)); /* Fix SizeOfImage */ cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38, cli_readint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38) - sections[sectcount].vsz); if (cli_writen(desc, fbuf, filesize)==-1) { cli_dbgmsg("yC: Cannot write unpacked file\n"); return CL_EUNPACK; } return CL_SUCCESS; }
static int rtf_object_process(struct rtf_state* state, const unsigned char* input,const size_t len) { struct rtf_object_data* data = state->cb_data; unsigned char outdata[BUFF_SIZE]; const unsigned char* out_data; size_t out_cnt = 0; size_t i; int ret; if(!data || !len) return 0; if(data->has_partial) { for(i=0;i<len && !isxdigit(input[i]);i++) ; if(i<len) { outdata[out_cnt++] = data->partial | hextable[input[i++]]; data->has_partial = 0; } else return 0; } else i = 0; for(;i<len;i++) { if(isxdigit(input[i])) { const unsigned char byte = hextable[ input[i++] ] << 4; while(i<len && !isxdigit(input[i])) i++; if(i == len) { data->partial = byte; data->has_partial = 1; break; } outdata[out_cnt++] = byte | hextable[ input[i] ]; } } out_data = outdata; while(out_data && out_cnt) { switch(data->internal_state) { case WAIT_MAGIC: { cli_dbgmsg("RTF: waiting for magic\n"); for(i=0; i<out_cnt && data->bread < rtf_data_magic_len; i++, data->bread++) if(rtf_data_magic[data->bread] != out_data[i]) { cli_dbgmsg("Warning: rtf objdata magic number not matched, expected:%d, got: %d, at pos:%lu\n",rtf_data_magic[i],out_data[i], (unsigned long int) data->bread); } out_cnt -= i; if(data->bread == rtf_data_magic_len) { out_data += i; data->bread = 0; data->internal_state = WAIT_DESC_LEN; } break; } case WAIT_DESC_LEN: { if(data->bread == 0) data->desc_len = 0; for(i=0; i<out_cnt && data->bread < 4; i++,data->bread++) data->desc_len |= ((size_t)out_data[i]) << (data->bread*8); out_cnt -= i; if(data->bread == 4) { out_data += i; data->bread=0; if(data->desc_len > 64) { cli_dbgmsg("Description length too big (%lu), showing only 64 bytes of it\n", (unsigned long int) data->desc_len); data->desc_name = cli_malloc(65); } else data->desc_name = cli_malloc(data->desc_len+1); if(!data->desc_name) { cli_errmsg("rtf_object_process: Unable to allocate memory for data->desc_name\n"); return CL_EMEM; } data->internal_state = WAIT_DESC; cli_dbgmsg("RTF: description length:%lu\n", (unsigned long int) data->desc_len); } break; } case WAIT_DESC:{ cli_dbgmsg("RTF: in WAIT_DESC\n"); for(i=0;i<out_cnt && data->bread < data->desc_len && data->bread < 64;i++, data->bread++) data->desc_name[data->bread] = out_data[i]; out_cnt -= i; out_data += i; if(data->bread < data->desc_len && data->bread < 64) { cli_dbgmsg("RTF: waiting for more data(1)\n"); return 0;/* wait for more data */ } data->desc_name[data->bread] = '\0'; if(data->desc_len - data->bread > out_cnt) { data->desc_len -= out_cnt; cli_dbgmsg("RTF: waiting for more data(2)\n"); return 0;/* wait for more data */ } out_cnt -= data->desc_len - data->bread; if(data->bread >= data->desc_len) { out_data += data->desc_len - data->bread; data->bread = 0; cli_dbgmsg("Preparing to dump rtf embedded object, description:%s\n",data->desc_name); free(data->desc_name); data->desc_name = NULL; data->internal_state = WAIT_ZERO; } break; } case WAIT_ZERO:{ if(out_cnt < 8-data->bread) { out_cnt = 0; data->bread += out_cnt; } else { out_cnt -= 8-data->bread; data->bread = 8; } if(data->bread == 8) { out_data += 8; data->bread = 0; cli_dbgmsg("RTF: next state: wait_data_size\n"); data->internal_state = WAIT_DATA_SIZE; } break; } case WAIT_DATA_SIZE: { cli_dbgmsg("RTF: in WAIT_DATA_SIZE\n"); if(data->bread == 0) data->desc_len = 0; for(i=0; i<out_cnt && data->bread < 4; i++,data->bread++) data->desc_len |= ((size_t)out_data[i]) << (8*data->bread); out_cnt -= i; if(data->bread == 4) { out_data += i; data->bread=0; cli_dbgmsg("Dumping rtf embedded object of size:%lu\n", (unsigned long int) data->desc_len); if((ret = cli_gentempfd(data->tmpdir, &data->name, &data->fd))) return ret; data->internal_state = DUMP_DATA; cli_dbgmsg("RTF: next state: DUMP_DATA\n"); } break; } case DUMP_DATA: { ssize_t out_want = out_cnt < data->desc_len ? out_cnt : data->desc_len; if(!data->bread) { if(out_data[0] != 0xd0 || out_data[1]!=0xcf) { /* this is not an ole2 doc, but some ole (stream?) to be * decoded by cli_decode_ole_object*/ char out[4]; data->bread = 1;/* flag to indicate this needs to be scanned with cli_decode_ole_object*/ cli_writeint32(out,data->desc_len); if(cli_writen(data->fd,out,4)!=4) return CL_EWRITE; } else data->bread = 2; } data->desc_len -= out_want; if(cli_writen(data->fd,out_data,out_want) != out_want) { return CL_EWRITE; } out_data += out_want; out_cnt -= out_want; if(!data->desc_len) { int rc; if(( rc = decode_and_scan(data, data->ctx) )) return rc; data->bread=0; data->internal_state = WAIT_MAGIC; } break; } case DUMP_DISCARD: default: out_cnt = 0; ; } } 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; }
int wwunpack(uint8_t *exe, uint32_t exesz, uint8_t *wwsect, struct cli_exe_section *sects, uint16_t scount, uint32_t pe, int desc) { uint8_t *structs = wwsect + 0x2a1, *compd, *ccur, *unpd, *ucur, bc; uint32_t src, srcend, szd, bt, bits; int error=0, i; cli_dbgmsg("in wwunpack\n"); while (1) { if (!CLI_ISCONTAINED(wwsect, sects[scount].rsz, structs, 17)) { cli_dbgmsg("WWPack: Array of structs out of section\n"); break; } src = sects[scount].rva - cli_readint32(structs); /* src delta / dst delta - not used / dwords / end of src */ structs+=8; szd = cli_readint32(structs) * 4; structs+=4; srcend = cli_readint32(structs); structs+=4; unpd = ucur = exe+src+srcend+4-szd; if (!szd || !CLI_ISCONTAINED(exe, exesz, unpd, szd)) { cli_dbgmsg("WWPack: Compressed data out of file\n"); break; } cli_dbgmsg("WWP: src: %x, szd: %x, srcend: %x - %x\n", src, szd, srcend, srcend+4-szd); if (!(compd = cli_malloc(szd))) { cli_dbgmsg("WWPack: Unable to allocate memory for compd\n"); break; } memcpy(compd, unpd, szd); memset(unpd, -1, szd); /*FIXME*/ ccur=compd; RESEED; while(!error) { uint32_t backbytes, backsize; uint8_t saved; BIT; if (!bits) { /* BYTE copy */ if(ccur-compd>=szd || !CLI_ISCONTAINED(exe, exesz, ucur, 1)) error=1; else *ucur++=*ccur++; continue; } BITS(2); if(bits==3) { /* WORD backcopy */ uint8_t shifted, subbed = 31; BITS(2); shifted = bits + 5; if(bits>=2) { shifted++; subbed += 0x80; } backbytes = (1<<shifted)-subbed; /* 1h, 21h, 61h, 161h */ BITS(shifted); /* 5, 6, 8, 9 */ if(error || bits == 0x1ff) break; backbytes+=bits; if(!CLI_ISCONTAINED(exe, exesz, ucur, 2) || !CLI_ISCONTAINED(exe, exesz, ucur-backbytes, 2)) { error=1; } else { ucur[0]=*(ucur-backbytes); ucur[1]=*(ucur-backbytes+1); ucur+=2; } continue; } /* BLOCK backcopy */ saved = bits; /* cmp al, 1 / pushf */ BITS(3); if (bits<6) { backbytes = bits; switch(bits) { case 4: /* 10,11 */ backbytes++; case 3: /* 8,9 */ BIT; backbytes+=bits; case 0: case 1: case 2: /* 5,6,7 */ backbytes+=5; break; case 5: /* 12 */ backbytes=12; break; } BITS(backbytes); bits+=(1<<backbytes)-31; } else if(bits==6) { BITS(0x0e); bits+=0x1fe1; } else { BITS(0x0f); bits+=0x5fe1; } backbytes = bits; /* popf / jb */ if (!saved) { BIT; if(!bits) { BIT; bits+=5; } else { BITS(3); if(bits) { bits+=6; } else { BITS(4); if(bits) { bits+=13; } else { uint8_t cnt = 4; uint16_t shifted = 0x0d; do { if(cnt==7) { cnt = 0x0e; shifted = 0; break; } shifted=((shifted+2)<<1)-1; BIT; cnt++; } while(!bits); BITS(cnt); bits+=shifted; } } } backsize = bits; } else { backsize = saved+2; } if(!CLI_ISCONTAINED(exe, exesz, ucur, backsize) || !CLI_ISCONTAINED(exe, exesz, ucur-backbytes, backsize)) error=1; else while(backsize--) { *ucur=*(ucur-backbytes); ucur++; } } free(compd); if(error) { cli_dbgmsg("WWPack: decompression error\n"); break; } if (error || !*structs++) break; } if(!error) { exe[pe+6]=(uint8_t)scount; exe[pe+7]=(uint8_t)(scount>>8); cli_writeint32(&exe[pe+0x28], cli_readint32(wwsect+0x295)+sects[scount].rva+0x299); cli_writeint32(&exe[pe+0x50], cli_readint32(&exe[pe+0x50])-sects[scount].vsz); structs = &exe[(0xffff&cli_readint32(&exe[pe+0x14]))+pe+0x18]; for(i=0 ; i<scount ; i++) { if (!CLI_ISCONTAINED(exe, exesz, structs, 0x28)) { cli_dbgmsg("WWPack: structs pointer out of bounds\n"); return CL_EFORMAT; } cli_writeint32(structs+8, sects[i].vsz); cli_writeint32(structs+12, sects[i].rva); cli_writeint32(structs+16, sects[i].vsz); cli_writeint32(structs+20, sects[i].rva); structs+=0x28; } if (!CLI_ISCONTAINED(exe, exesz, structs, 0x28)) { cli_dbgmsg("WWPack: structs pointer out of bounds\n"); return CL_EFORMAT; } memset(structs, 0, 0x28); error = (uint32_t)cli_writen(desc, exe, exesz)!=exesz; }
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; }