static char *checkpe(char *dst, uint32_t dsize, char *pehdr, uint32_t *valign, unsigned int *sectcnt) { char *sections; if (!CLI_ISCONTAINED(dst, dsize, pehdr, 0xf8)) return NULL; if (cli_readint32(pehdr) != 0x4550 ) return NULL; if (!(*valign=cli_readint32(pehdr+0x38))) return NULL; sections = pehdr+0xf8; if (!(*sectcnt = (unsigned char)pehdr[6] + (unsigned char)pehdr[7]*256)) return NULL; if (!CLI_ISCONTAINED(dst, dsize, sections, *sectcnt*0x28)) return NULL; return sections; }
END_TEST /* test reading with different alignments, _i is parameter from tcase_add_loop_test */ START_TEST (test_cli_readint32) { size_t j; int32_t value = le_expected[_i&3]; /* read 4 bytes apart, start is not always aligned*/ for(j=_i;j < DATA_REP*sizeof(le_data)-4;j += 4) { fail_unless(cli_readint32(&data[j]) == value, "(1) data read must be little endian"); } value = le_expected[0]; /* read 4 bytes apart, always aligned*/ for(j=0;j < DATA_REP*sizeof(le_data)-4;j += 4) { fail_unless(cli_readint32(&data[j]) == value, "(2) data read must be little endian"); } }
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"); } }
/* test file extract API */ int entrypoint(void) { unsigned char buf[4]; /* fixme:compiler assumes LE here = {1, 2, 3, 4}; */ uint32_t x, i; uint64_t y; *(uint32_t*)buf = le32_to_host(0x04030201); for (i=0;i<3;i++) { extract_new(i); if (write(buf, sizeof(buf)) != sizeof(buf)) return 0xbad1; /* switch input to extracted file */ if (input_switch(1) != 0) return 0xbad2; if (seek(0, SEEK_END) != 4) return 0xbad3; if (seek(0, SEEK_SET) != 0) return 0xbad4; x = 0x5a5a5a5a; if (read(&x, sizeof(x)) != sizeof(x)) return 0xbad5; if (cli_readint32(&x) != 0x04030201) return 0xbad6; /* switch back to normal file */ if (input_switch(0) != 0) return 0xbad7; if (seek(0, SEEK_SET) != 0) return 0xbad8; if (read(&x, sizeof(x)) != sizeof(x)) return 0xbad9; x = le32_to_host(x); if (x != 0x44434241) return 0xbad10; /* write to extracted file again */ if (write(buf, sizeof(buf)) != sizeof(buf)) return 0xbad11; /* switch input to extracted file */ if (input_switch(1) != 0) return 0xbad12; if (seek(0, SEEK_END) != 8) return 0xbad13; if (seek(0, SEEK_SET) != 0) return 0xbad14; if (read(&y, sizeof(y)) != sizeof(y)) return 0xbad15; y = le64_to_host(y); if (y != 0x0403020104030201UL) return 0xbad16; if (input_switch(0) != 0) return 0xbad17; } return 0xf00d; }
int cli_LzmaInit(CLI_LZMA **Lp, uint64_t size_override) { CLI_LZMA *L = *Lp; if(!L) { *Lp = L = cli_calloc(sizeof(*L), 1); if(!L) { return CL_EMEM; } } L->initted = 0; if(size_override) L->usize=size_override; if (!L->next_in || L->avail_in < LZMA_PROPERTIES_SIZE + 8) return LZMA_RESULT_OK; if (LzmaDecodeProperties(&L->state.Properties, L->next_in, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK) return LZMA_RESULT_DATA_ERROR; L->next_in += LZMA_PROPERTIES_SIZE; L->avail_in -= LZMA_PROPERTIES_SIZE; if (!L->usize) { L->usize=(uint64_t)cli_readint32(L->next_in) + ((uint64_t)cli_readint32(L->next_in+4)<<32); L->next_in += 8; L->avail_in -= 8; } if (!(L->state.Probs = (CProb *)cli_malloc(LzmaGetNumProbs(&L->state.Properties) * sizeof(CProb)))) return LZMA_RESULT_DATA_ERROR; if (!(L->state.Dictionary = (unsigned char *)cli_malloc(L->state.Properties.DictionarySize))) { free(L->state.Probs); return LZMA_RESULT_DATA_ERROR; } L->initted = 1; LzmaDecoderInit(&L->state); return LZMA_RESULT_OK; }
static int doubleebx(const char *src, uint32_t *myebx, uint32_t *scur, uint32_t ssize) { uint32_t oldebx = *myebx; *myebx*=2; if ( !(oldebx & 0x7fffffff)) { if (! CLI_ISCONTAINED(src, ssize, src+*scur, 4)) return -1; oldebx = cli_readint32(src+*scur); *myebx = oldebx*2+1; *scur+=4; } return (oldebx>>31); }
int cli_unzip(cli_ctx *ctx) { unsigned int fc=0, fu=0; int ret=CL_CLEAN; uint32_t fsize, lhoff = 0, coff = 0; fmap_t *map = *ctx->fmap; char *tmpd; const char *ptr; int virus_found = 0; #if HAVE_JSON int toval = 0; #endif cli_dbgmsg("in cli_unzip\n"); fsize = (uint32_t)map->len; if(sizeof(off_t)!=sizeof(uint32_t) && (size_t)fsize!=map->len) { cli_dbgmsg("cli_unzip: file too big\n"); return CL_CLEAN; } if (fsize < SIZEOF_CH) { cli_dbgmsg("cli_unzip: file too short\n"); return CL_CLEAN; } if (!(tmpd = cli_gentemp(ctx->engine->tmpdir))) { return CL_ETMPDIR; } if (mkdir(tmpd, 0700)) { cli_dbgmsg("cli_unzip: Can't create temporary directory %s\n", tmpd); free(tmpd); return CL_ETMPDIR; } for(coff=fsize-22 ; coff>0 ; coff--) { /* sizeof(EOC)==22 */ if(!(ptr = fmap_need_off_once(map, coff, 20))) continue; if(cli_readint32(ptr)==0x06054b50) { uint32_t chptr = cli_readint32(&ptr[16]); if(!CLI_ISCONTAINED(0, fsize, chptr, SIZEOF_CH)) continue; coff=chptr; break; } } if(coff) { cli_dbgmsg("cli_unzip: central @%x\n", coff); while(ret==CL_CLEAN && (coff=chdr(map, coff, fsize, &fu, fc+1, &ret, ctx, tmpd, NULL))) { fc++; if (ctx->engine->maxfiles && fu>=ctx->engine->maxfiles) { cli_dbgmsg("cli_unzip: Files limit reached (max: %u)\n", ctx->engine->maxfiles); ret=CL_EMAXFILES; } #if HAVE_JSON if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) { return CL_ETIMEOUT; } #endif } } else cli_dbgmsg("cli_unzip: central not found, using localhdrs\n"); if(fu<=(fc/4)) { /* FIXME: make up a sane ratio or remove the whole logic */ fc = 0; while (ret==CL_CLEAN && lhoff<fsize && (coff=lhdr(map, lhoff, fsize-lhoff, &fu, fc+1, NULL, &ret, ctx, tmpd, 1, zip_scan_cb))) { fc++; lhoff+=coff; if (SCAN_ALL && ret == CL_VIRUS) { ret = CL_CLEAN; virus_found = 1; } if (ctx->engine->maxfiles && fu>=ctx->engine->maxfiles) { cli_dbgmsg("cli_unzip: Files limit reached (max: %u)\n", ctx->engine->maxfiles); ret=CL_EMAXFILES; } #if HAVE_JSON if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) { return CL_ETIMEOUT; } #endif } } if (!ctx->engine->keeptmp) cli_rmdirs(tmpd); free(tmpd); if (ret == CL_CLEAN && virus_found) ret = CL_VIRUS; return ret; }
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 uint8_t nsis_detcomp(const char *b) { if (*b=='1') return COMP_BZIP2; if ((cli_readint32(b)&~0x80000000)==0x5d) return COMP_LZMA; return COMP_ZLIB; }
static int nsis_headers(struct nsis_st *n, cli_ctx *ctx) { char buf[28]; struct stat st; uint32_t pos; int i; uint8_t comps[] = {0, 0, 0, 0}, trunc = 0; if (fstat(n->ifd, &st)==-1 || lseek(n->ifd, n->off, SEEK_SET)==-1 || cli_readn(n->ifd, buf, 28) != 28) return CL_EIO; n->hsz = (uint32_t)cli_readint32(buf+0x14); n->asz = (uint32_t)cli_readint32(buf+0x18); cli_dbgmsg("NSIS: Header info - Flags=%x, Header size=%x, Archive size=%x\n", cli_readint32(buf), n->hsz, n->asz); if (st.st_size - n->off < (off_t) n->asz) { cli_dbgmsg("NSIS: Possibly truncated file\n"); n->asz = st.st_size - n->off; trunc++; } else if (st.st_size - n->off != (off_t) n->asz) { cli_dbgmsg("NSIS: Overlays found\n"); } n->asz -= 0x1c; /* Guess if solid */ for (i=0, pos=0;pos < n->asz-4;i++) { int32_t nextsz; if (cli_readn(n->ifd, buf+4, 4)!=4) return CL_EIO; nextsz=cli_readint32(buf+4); if (!i) n->comp = nsis_detcomp(buf+4); if (nextsz&0x80000000) { nextsz&=~0x80000000; if (cli_readn(n->ifd, buf+4, 4)!=4) return CL_EIO; comps[nsis_detcomp(buf+4)]++; nextsz-=4; pos+=4; } if ((pos+=4+nextsz) > n->asz) { n->solid = 1; break; } if (lseek(n->ifd, nextsz, SEEK_CUR)==-1) return CL_EIO; } if (trunc && i>=2) n->solid=0; cli_dbgmsg("NSIS: solid compression%s detected\n", (n->solid)?"":" not"); /* Guess the compression method */ if (!n->solid) { cli_dbgmsg("NSIS: bzip2 %u - lzma %u - zlib %u\n", comps[1], comps[2], comps[3]); n->comp = (comps[1]<comps[2]) ? (comps[2]<comps[3] ? COMP_ZLIB : COMP_LZMA) : (comps[1]<comps[3] ? COMP_ZLIB : COMP_BZIP2); } if (lseek(n->ifd, n->off+0x1c, SEEK_SET)==-1) return CL_EIO; return nsis_unpack_next(n, ctx); }
static int __zip_find_disk_trailer(int fd, off_t filesize, struct zip_disk_trailer *trailer, off_t *start) { char *buf, *end, *tail; off_t offset = 0, bufsize; struct zip_root_dirent dirent; uint32_t u_rootseek, shift = 0; int i; if(!trailer) { cli_errmsg("Unzip: __zip_find_disk_trailer: trailer == NULL\n"); return CL_ENULLARG; } if(filesize < __sizeof(struct zip_disk_trailer)) { cli_errmsg("Unzip: __zip_find_disk_trailer: File too short\n"); return CL_EFORMAT; } if(!(buf = cli_malloc(ZIPBUFSIZ))) return CL_EMEM; offset = filesize; while(1) { if(offset <= 0) { cli_dbgmsg("Unzip: __zip_find_disk_trailer: Central directory not found\n"); free(buf); return CL_EFORMAT; } if(offset >= ZIPBUFSIZ) { if(offset == filesize) offset -= ZIPBUFSIZ; else offset -= ZIPBUFSIZ - sizeof(struct zip_disk_trailer); bufsize = ZIPBUFSIZ; } else { if(filesize < ZIPBUFSIZ) bufsize = offset; else bufsize = ZIPBUFSIZ; offset = 0; } if(lseek(fd, offset, SEEK_SET) < 0) { cli_errmsg("Unzip: __zip_find_disk_trailer: Can't lseek descriptor %d\n", fd); free(buf); return CL_EIO; } if(cli_readn(fd, buf, (size_t) bufsize) < (ssize_t) bufsize) { cli_errmsg("Unzip: __zip_find_disk_trailer: Can't read %u bytes\n", (unsigned int) bufsize); free(buf); return CL_EIO; } end = buf + bufsize; for(tail = end - 1; tail >= buf; tail--) { if((*tail == 'P') && (end - tail >= __sizeof(struct zip_disk_trailer) - 2) && cli_readint32(tail) == ZIP_DISK_TRAILER_MAGIC) { if(end - tail >= __sizeof(struct zip_disk_trailer)) { memcpy(trailer, tail, sizeof(struct zip_disk_trailer)); } else { memcpy(trailer, tail, sizeof(struct zip_disk_trailer) - 2); trailer->z_comment = 0; } __fixup_rootseek(offset + tail - buf, trailer); u_rootseek = EC32(trailer->z_rootseek); if(u_rootseek > (uint32_t) filesize) { cli_dbgmsg("Unzip: __zip_find_disk_trailer: u_rootseek > filesize, continue search\n"); continue; } for(i = 0; i < 2; i++) { if(u_rootseek + shift + sizeof(dirent) < (uint32_t) filesize) { if(lseek(fd, u_rootseek + shift, SEEK_SET) < 0) { cli_errmsg("Unzip: __zip_find_disk_trailer: Can't lseek descriptor %d\n", fd); free(buf); return CL_EIO; } if(cli_readn(fd, &dirent, sizeof(dirent)) < __sizeof(dirent)) { cli_errmsg("Unzip: __zip_find_disk_trailer: Can't read %u bytes\n", (unsigned int) bufsize); free(buf); return CL_EIO; } if(EC32(dirent.z_magic) == ZIP_ROOT_DIRENT_MAGIC) { cli_dbgmsg("Unzip: __zip_find_disk_trailer: found file header at %u, shift %u\n", u_rootseek + shift, shift); free(buf); *start = shift; return CL_SUCCESS; } shift = *start; } } } } }
static int nsis_unpack_next(struct nsis_st *n, cli_ctx *ctx) { unsigned char *ibuf; uint32_t size, loops; int ret; unsigned char obuf[BUFSIZ]; if (n->eof) { cli_dbgmsg("NSIS: extraction complete\n"); return CL_BREAK; } if (ctx->limits && ctx->limits->maxfiles && n->fno >= ctx->limits->maxfiles) { cli_dbgmsg("NSIS: Files limit reached (max: %u)\n", ctx->limits->maxfiles); return CL_EMAXFILES; } if (n->fno) snprintf(n->ofn, 1023, "%s/content.%.3u", n->dir, n->fno); else snprintf(n->ofn, 1023, "%s/headers", n->dir); n->fno++; if ((n->ofd=open(n->ofn, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600))==-1) { cli_errmsg("NSIS: unable to create output file %s - aborting.", n->ofn); return CL_EIO; } if (!n->solid) { if (cli_readn(n->ifd, &size, 4)!=4) { cli_dbgmsg("NSIS: reached EOF - extraction complete\n"); close(n->ofd); return CL_BREAK; } if (n->asz==4) { cli_dbgmsg("NSIS: reached CRC - extraction complete\n"); close(n->ofd); return CL_BREAK; } loops = EC32(size); if (!(size = (loops&~0x80000000))) { cli_dbgmsg("NSIS: empty file found\n"); return CL_SUCCESS; } if (n->asz <4 || size > n->asz-4) { cli_dbgmsg("NSIS: next file is outside the archive\n"); close(n->ofd); return CL_BREAK; } n->asz -= size+4; if (ctx->limits && ctx->limits->maxfilesize && size > ctx->limits->maxfilesize) { cli_dbgmsg("NSIS: Skipping file due to size limit (%u, max: %lu)\n", size, ctx->limits->maxfilesize); close(n->ofd); if (lseek(n->ifd, size, SEEK_CUR)==-1) return CL_EIO; return CL_EMAXSIZE; } if (!(ibuf= (unsigned char *) cli_malloc(size))) { cli_dbgmsg("NSIS: out of memory"__AT__"\n"); close(n->ofd); return CL_EMEM; } if (cli_readn(n->ifd, ibuf, size) != (ssize_t) size) { cli_dbgmsg("NSIS: cannot read %u bytes"__AT__"\n", size); free(ibuf); close(n->ofd); return CL_EIO; } if (loops==size) { if (cli_writen(n->ofd, ibuf, size) != (ssize_t) size) { cli_dbgmsg("NSIS: cannot write output file"__AT__"\n"); free(ibuf); close(n->ofd); return CL_EIO; } } else { if ((ret=nsis_init(n))!=CL_SUCCESS) { cli_dbgmsg("NSIS: decompressor init failed"__AT__"\n"); free(ibuf); close(n->ofd); return ret; } n->nsis.avail_in = size; n->nsis.next_in = ibuf; n->nsis.next_out = obuf; n->nsis.avail_out = BUFSIZ; loops=0; while ((ret=nsis_decomp(n))==CL_SUCCESS) { if ((size = n->nsis.next_out - obuf)) { if (cli_writen(n->ofd, obuf, size) != (ssize_t) size) { cli_dbgmsg("NSIS: cannot write output file"__AT__"\n"); free(ibuf); close(n->ofd); return CL_EIO; } n->nsis.next_out = obuf; n->nsis.avail_out = BUFSIZ; loops=0; if (ctx->limits && ctx->limits->maxfilesize && size > ctx->limits->maxfilesize) { cli_dbgmsg("NSIS: Skipping file due to size limit (%u, max: %lu)\n", size, ctx->limits->maxfilesize); free(ibuf); close(n->ofd); nsis_shutdown(n); return CL_EMAXSIZE; } } else if (++loops > 10) { cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n"); ret = CL_BREAK; break; } } if (ret != CL_BREAK) { cli_dbgmsg("NSIS: bad stream"__AT__"\n"); free(ibuf); close(n->ofd); return CL_EFORMAT; } if (cli_writen(n->ofd, obuf, n->nsis.next_out - obuf) != n->nsis.next_out - obuf) { cli_dbgmsg("NSIS: cannot write output file"__AT__"\n"); free(ibuf); close(n->ofd); return CL_EIO; } nsis_shutdown(n); } free(ibuf); return CL_SUCCESS; } else { if (!n->freeme) { if ((ret=nsis_init(n))!=CL_SUCCESS) { cli_dbgmsg("NSIS: decompressor init failed\n"); close(n->ofd); return ret; } if (!(n->freeme= (unsigned char *) cli_malloc(n->asz))) { cli_dbgmsg("NSIS: out of memory\n"); close(n->ofd); return CL_EMEM; } if (cli_readn(n->ifd, n->freeme, n->asz) != (ssize_t) n->asz) { cli_dbgmsg("NSIS: cannot read %u bytes"__AT__"\n", n->asz); close(n->ofd); return CL_EIO; } n->nsis.next_in = n->freeme; n->nsis.avail_in = n->asz; } if (n->nsis.avail_in<=4) { cli_dbgmsg("NSIS: extraction complete\n"); close(n->ofd); return CL_BREAK; } n->nsis.next_out = obuf; n->nsis.avail_out = 4; loops = 0; while ((ret=nsis_decomp(n))==CL_SUCCESS) { if (n->nsis.next_out - obuf == 4) break; if (++loops > 20) { cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n"); ret = CL_BREAK; break; } } if (ret != CL_SUCCESS) { cli_dbgmsg("NSIS: bad stream"__AT__"\n"); close(n->ofd); return CL_EFORMAT; } size=cli_readint32(obuf); if (ctx->limits && ctx->limits->maxfilesize && size > ctx->limits->maxfilesize) { cli_dbgmsg("NSIS: Breaking out due to filesize limit (%u, max: %lu) in solid archive\n", size, ctx->limits->maxfilesize); close(n->ofd); return CL_EFORMAT; } n->nsis.next_out = obuf; n->nsis.avail_out = MIN(BUFSIZ,size); loops = 0; while (size && (ret=nsis_decomp(n))==CL_SUCCESS) { unsigned int wsz; if ((wsz = n->nsis.next_out - obuf)) { if (cli_writen(n->ofd, obuf, wsz) != (ssize_t) wsz) { close(n->ofd); return CL_EIO; } size-=wsz; n->nsis.next_out = obuf; n->nsis.avail_out = MIN(size,BUFSIZ); } else if ( ++loops > 20 ) { cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n"); ret = CL_BREAK; break; } } if (ret == CL_BREAK) { if (cli_writen(n->ofd, obuf, n->nsis.next_out - obuf) != n->nsis.next_out - obuf) { close(n->ofd); return CL_EIO; } n->eof=1; } else if (ret != CL_SUCCESS) { cli_dbgmsg("NSIS: bad stream"__AT__"\n"); close(n->ofd); return CL_EFORMAT; } return CL_SUCCESS; } }
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 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; }
int unspin(char *src, int ssize, struct cli_exe_section *sections, int sectcnt, uint32_t nep, int desc, cli_ctx *ctx) { char *curr, *emu, *ep, *spinned; char **sects; int blobsz=0, j; uint32_t key32, bitmap, bitman; uint32_t len; uint8_t key8; cli_dbgmsg("in unspin\n"); if ((spinned = (char *) cli_malloc(sections[sectcnt].rsz)) == NULL ) return 1; memcpy(spinned, src + sections[sectcnt].raw, sections[sectcnt].rsz); ep = spinned + nep - sections[sectcnt].rva; curr = ep+0xdb; if ( *curr != '\xbb' ) { free(spinned); cli_dbgmsg("spin: Not spinned or bad version\n"); return 1; } key8 = (uint8_t)*++curr; curr+=4; if ( *curr != '\xb9' ) { free(spinned); cli_dbgmsg("spin: Not spinned or bad version\n"); return 1; } if ( (len = cli_readint32(curr+1)) != 0x11fe ) { free(spinned); cli_dbgmsg("spin: Not spinned or bad version\n"); return 1; } cli_dbgmsg("spin: Key8 is %x, Len is %x\n", key8, len); if (!CLI_ISCONTAINED(spinned, sections[sectcnt].rsz, ep, len+0x1fe5-1) || !CLI_ISCONTAINED(spinned, sections[sectcnt].rsz, ep+0x3217, 4)) { free(spinned); cli_dbgmsg("spin: len or key out of bounds, giving up\n"); return 1; } if ( ep[0x1e0]!='\xb8' ) cli_dbgmsg("spin: prolly not spinned, expect failure\n"); if ( (cli_readint32(ep+0x1e1) & 0x00200000) ) cli_dbgmsg("spin: password protected, expect failure\n"); curr = ep+0x1fe5+len-1; while ( len-- ) { *curr=(*curr)^(key8--); curr--; } curr = ep+0x26eb; key32 = cli_readint32(curr); if ( (len = cli_readint32(curr+5)) != 0x5a0) { free(spinned); cli_dbgmsg("spin: Not spinned or bad version\n"); return 1; } curr = ep+0x2d5; cli_dbgmsg("spin: Key is %x, Len is %x\n", key32, len); while ( len-- ) { if ( key32 & 1 ) { key32 = key32>>1; key32 ^= 0x8c328834; } else {
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; }
static unsigned int lhdr(fmap_t *map, uint32_t loff,uint32_t zsize, unsigned int *fu, unsigned int fc, const uint8_t *ch, int *ret, cli_ctx *ctx, char *tmpd, int detect_encrypted, zip_cb zcb) { const uint8_t *lh, *zip; char name[256]; uint32_t csize, usize; if(!(lh = fmap_need_off(map, loff, SIZEOF_LH))) { cli_dbgmsg("cli_unzip: lh - out of file\n"); return 0; } if(LH_magic != 0x04034b50) { if (!ch) cli_dbgmsg("cli_unzip: lh - wrkcomplete\n"); else cli_dbgmsg("cli_unzip: lh - bad magic\n"); fmap_unneed_off(map, loff, SIZEOF_LH); return 0; } zip = lh + SIZEOF_LH; zsize-=SIZEOF_LH; if(zsize<=LH_flen) { cli_dbgmsg("cli_unzip: lh - fname out of file\n"); fmap_unneed_off(map, loff, SIZEOF_LH); return 0; } if(ctx->engine->cdb || cli_debug_flag) { uint32_t nsize = (LH_flen>=sizeof(name))?sizeof(name)-1:LH_flen; const char *src; if(nsize && (src = fmap_need_ptr_once(map, zip, nsize))) { memcpy(name, zip, nsize); name[nsize]='\0'; } else name[0] = '\0'; } zip+=LH_flen; zsize-=LH_flen; cli_dbgmsg("cli_unzip: lh - ZMDNAME:%d:%s:%u:%u:%x:%u:%u:%u\n", ((LH_flags & F_ENCR)!=0), name, LH_usize, LH_csize, LH_crc32, LH_method, fc, ctx->recursion); /* ZMDfmt virname:encrypted(0-1):filename(exact|*):usize(exact|*):csize(exact|*):crc32(exact|*):method(exact|*):fileno(exact|*):maxdepth(exact|*) */ if(cli_matchmeta(ctx, name, LH_csize, LH_usize, (LH_flags & F_ENCR)!=0, fc, LH_crc32, NULL) == CL_VIRUS) { *ret = CL_VIRUS; return 0; } if(LH_flags & F_MSKED) { cli_dbgmsg("cli_unzip: lh - header has got unusable masked data\n"); /* FIXME: need to find/craft a sample */ fmap_unneed_off(map, loff, SIZEOF_LH); return 0; } if(detect_encrypted && (LH_flags & F_ENCR) && DETECT_ENCRYPTED) { cli_dbgmsg("cli_unzip: Encrypted files found in archive.\n"); cli_append_virus(ctx, "Heuristics.Encrypted.Zip"); *ret = CL_VIRUS; fmap_unneed_off(map, loff, SIZEOF_LH); return 0; } if(LH_flags & F_USEDD) { cli_dbgmsg("cli_unzip: lh - has data desc\n"); if(!ch) { fmap_unneed_off(map, loff, SIZEOF_LH); return 0; } else { usize = CH_usize; csize = CH_csize; } } else { usize = LH_usize; csize = LH_csize; } if(zsize<=LH_elen) { cli_dbgmsg("cli_unzip: lh - extra out of file\n"); fmap_unneed_off(map, loff, SIZEOF_LH); return 0; } zip+=LH_elen; zsize-=LH_elen; if (!csize) { /* FIXME: what's used for method0 files? csize or usize? Nothing in the specs, needs testing */ cli_dbgmsg("cli_unzip: lh - skipping empty file\n"); } else { if(zsize<csize) { cli_dbgmsg("cli_unzip: lh - stream out of file\n"); fmap_unneed_off(map, loff, SIZEOF_LH); return 0; } if(LH_flags & F_ENCR) { cli_dbgmsg("cli_unzip: lh - skipping encrypted file\n"); } else { if(fmap_need_ptr_once(map, zip, csize)) *ret = unz(zip, csize, usize, LH_method, LH_flags, fu, ctx, tmpd, zcb); } zip+=csize; zsize-=csize; } fmap_unneed_off(map, loff, SIZEOF_LH); /* unneed now. block is guaranteed to exists till the next need */ if(LH_flags & F_USEDD) { if(zsize<12) { cli_dbgmsg("cli_unzip: lh - data desc out of file\n"); return 0; } zsize-=12; if(fmap_need_ptr_once(map, zip, 4)) { if(cli_readint32(zip)==0x08074b50) { if(zsize<4) { cli_dbgmsg("cli_unzip: lh - data desc out of file\n"); return 0; } zip+=4; } } zip+=12; } return zip-lh; }
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 unupack399(char *bs, uint32_t bl, uint32_t init_eax, char *init_ebx, uint32_t init_ecx, char *init_edi, char *end_edi, uint32_t shlsize, char *paddr) { struct lzmastate p; uint32_t loc_eax, ret, loc_al, loc_ecx = init_ecx, loc_ebp, eax_copy = init_eax, temp, i, jakas_kopia; uint32_t state[6], temp_ebp; char *loc_edx, *loc_ebx = init_ebx, *loc_edi = init_edi, *loc_ebp8, *edi_copy; p.p0 = paddr; p.p1 = cli_readint32(init_ebx); p.p2 = cli_readint32(init_ebx + 4); cli_dbgmsg("\n\tp0: %08x\n\tp1: %08x\n\tp2: %08x\n", p.p0, p.p1, p.p2); for (i = 0; i<6; i++) state[i] = cli_readint32(loc_ebx + (i<<2)), cli_dbgmsg("state[%d] = %08x\n", i, state[i]); do { loc_eax = eax_copy; loc_edx = loc_ebx + (loc_eax<<2) + 0x58; if ((ret = lzma_upack_esi_00(&p, loc_edx, bs, bl))) { /* loc_483927 */ loc_al = loc_eax&0xff; loc_al = ((loc_al + 0xf9) > 0xff)?(3+8):8; loc_eax = (loc_eax&0xffffff00)|(loc_al&0xff); loc_ebp = state[2]; loc_ecx = (loc_ecx&0xffffff00)|0x30; loc_edx += loc_ecx; /* *(uint32_t *)(loc_ebx + 14) = loc_ebp; ???? */ if (!(ret = lzma_upack_esi_00(&p, loc_edx, bs, bl))) { /* loc_48397c */ loc_eax--; /* temp_ebp = loc_ebp; loc_ebp = cli_readint32(loc_ebx+0x0c); cli_writeint32(loc_ebx+0x0c, temp_ebp); temp_ebp = loc_ebp; loc_ebp = cli_readint32(loc_ebx+0x10); cli_writeint32(loc_ebx+0x10, temp_ebp); */ temp_ebp = loc_ebp; loc_ebp = state[4]; state[4] = state[3]; state[3] = temp_ebp; eax_copy = loc_eax; loc_edx = loc_ebx + 0xbc0; state[5] = loc_ebp; if (lzma_upack_esi_54(&p, loc_eax, &loc_ecx, &loc_edx, &temp, bs, bl) == 0xffffffff) return -1; loc_ecx = 3; jakas_kopia = temp; loc_eax = temp-1; if (loc_eax >= loc_ecx) loc_eax = loc_ecx; loc_ecx = 0x40; loc_eax <<= 6; /* ecx=0x40, mul cl */ loc_ebp8 = loc_ebx + ((loc_eax<<2) + 0x378); if (lzma_upack_esi_50(&p, 1, loc_ecx, &loc_edx, loc_ebp8, &loc_eax, bs, bl) == 0xffffffff) return -1; loc_ebp = loc_eax; if ((loc_eax&0xff) >= 4) { /* loc_4839af */ loc_ebp = 2 + (loc_eax&1); loc_eax >>= 1; loc_eax--; temp_ebp = loc_eax; loc_eax = loc_ecx; loc_ecx = temp_ebp; loc_ebp <<= (loc_ecx&0xff); loc_edx = loc_ebx + (loc_ebp<<2) + 0x178; if ((loc_ecx&0xff) > 5) { /* loc_4839c6 */ loc_ecx = (loc_ecx&0xffffff00)|(((loc_ecx&0xff)-4)&0xff); loc_eax = 0; do { uint32_t temp_edx; /* compare with lzma_upack_esi_00 */ /* do not put in one statment because of difference in signedness */ if (!CLI_ISCONTAINED(bs, bl, p.p0, 4)) return -1; temp_edx = cli_readint32((char *)p.p0); temp_edx = EC32(CE32(temp_edx)); p.p1 >>= 1; temp_edx -= p.p2; loc_eax <<= 1; if (temp_edx >= p.p1) { temp_edx = p.p1; loc_eax++; p.p2 += temp_edx; } if(((p.p1)&0xff000000) == 0) { p.p2 <<= 8; p.p1 <<= 8; p.p0++; } } while (--loc_ecx); /* loc_4839e8 */ loc_ecx = (loc_ecx&0xffffff00)|4; loc_eax <<= 4; loc_ebp += loc_eax; loc_edx = loc_ebx + 0x18; } /* loc4839f1 */ loc_eax = 1; loc_eax <<= (loc_ecx&0xff); loc_ebp8 = loc_edx; temp_ebp = loc_ecx; loc_ecx = loc_eax; loc_eax = temp_ebp; if (lzma_upack_esi_50(&p, 1, loc_ecx, &loc_edx, loc_ebp8, &loc_eax, bs, bl) == 0xffffffff) return -1; /* cdq, loc_edx = (loc_eax&0x80000000)?0xffffffff:0; */ loc_ecx = temp_ebp; temp_ebp = CLI_SRS((int32_t)loc_eax, 31); /* thx, desp */ /* loc_483a00 */ do { temp_ebp += temp_ebp; temp_ebp += (loc_eax&1); loc_eax >>= 1; } while (--loc_ecx); loc_ebp += temp_ebp; /* loc_483a06 */ }
static int nsis_headers(struct nsis_st *n, cli_ctx *ctx) { const char *buf; uint32_t pos; int i; uint8_t comps[] = {0, 0, 0, 0}, trunc = 0; if (!(buf = fmap_need_off_once(n->map, n->off, 0x1c))) return CL_EREAD; n->hsz = (uint32_t)cli_readint32(buf+0x14); n->asz = (uint32_t)cli_readint32(buf+0x18); n->fullsz = n->map->len; cli_dbgmsg("NSIS: Header info - Flags=%x, Header size=%x, Archive size=%x\n", cli_readint32(buf), n->hsz, n->asz); if (n->fullsz - n->off < (off_t) n->asz) { cli_dbgmsg("NSIS: Possibly truncated file\n"); n->asz = n->fullsz - n->off; trunc++; } else if (n->fullsz - n->off != (off_t) n->asz) { cli_dbgmsg("NSIS: Overlays found\n"); } n->asz -= 0x1c; buf += 0x1c; /* Guess if solid */ for (i=0, pos=0;pos < n->asz-4;i++) { int32_t nextsz; if (!(buf = fmap_need_ptr_once(n->map, (void *)buf, 4))) return CL_EREAD; nextsz=cli_readint32(buf); if (!i) n->comp = nsis_detcomp(buf); buf += 4; if (nextsz&0x80000000) { nextsz&=~0x80000000; if (!(buf = fmap_need_ptr_once(n->map, (void *)buf, 4))) return CL_EREAD; comps[nsis_detcomp(buf)]++; nextsz-=4; pos+=4; buf+=4; } if ((pos+=4+nextsz) > n->asz) { n->solid = 1; break; } buf += nextsz; } if (trunc && i>=2) n->solid=0; cli_dbgmsg("NSIS: solid compression%s detected\n", (n->solid)?"":" not"); /* Guess the compression method */ if (!n->solid) { cli_dbgmsg("NSIS: bzip2 %u - lzma %u - zlib %u\n", comps[1], comps[2], comps[3]); n->comp = (comps[1]<comps[2]) ? (comps[2]<comps[3] ? COMP_ZLIB : COMP_LZMA) : (comps[1]<comps[3] ? COMP_ZLIB : COMP_BZIP2); } n->curpos = n->off+0x1c; return nsis_unpack_next(n, ctx); }
static int nsis_unpack_next(struct nsis_st *n, cli_ctx *ctx) { const unsigned char *ibuf; uint32_t size, loops; int ret, gotsome=0, opened=0; unsigned char obuf[BUFSIZ]; if (n->eof) { cli_dbgmsg("NSIS: extraction complete\n"); return CL_BREAK; } if ((ret=cli_checklimits("NSIS", ctx, 0, 0, 0))!=CL_CLEAN) return ret; if (n->fno) snprintf(n->ofn, 1023, "%s"PATHSEP"content.%.3u", n->dir, n->fno); else snprintf(n->ofn, 1023, "%s"PATHSEP"headers", n->dir); n->fno++; n->opened = 0; if (!n->solid) { if (fmap_readn(n->map, &size, n->curpos, 4)!=4) { cli_dbgmsg("NSIS: reached EOF - extraction complete\n"); return CL_BREAK; } n->curpos += 4; if (n->asz==4) { cli_dbgmsg("NSIS: reached CRC - extraction complete\n"); return CL_BREAK; } loops = EC32(size); if (!(size = (loops&~0x80000000))) { cli_dbgmsg("NSIS: empty file found\n"); return CL_SUCCESS; } if (n->asz <4 || size > n->asz-4) { cli_dbgmsg("NSIS: next file is outside the archive\n"); return CL_BREAK; } n->asz -= size+4; if ((ret=cli_checklimits("NSIS", ctx, size, 0, 0))!=CL_CLEAN) { n->curpos += size; return ret; } if (!(ibuf = fmap_need_off_once(n->map, n->curpos, size))) { cli_dbgmsg("NSIS: cannot read %u bytes"__AT__"\n", size); return CL_EREAD; } if ((n->ofd=open(n->ofn, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600))==-1) { cli_errmsg("NSIS: unable to create output file %s - aborting.", n->ofn); return CL_ECREAT; } n->opened = 1; n->curpos += size; if (loops==size) { if (cli_writen(n->ofd, ibuf, size) != (ssize_t) size) { cli_dbgmsg("NSIS: cannot write output file"__AT__"\n"); close(n->ofd); return CL_EWRITE; } } else { if ((ret=nsis_init(n))!=CL_SUCCESS) { cli_dbgmsg("NSIS: decompressor init failed"__AT__"\n"); close(n->ofd); return ret; } n->nsis.avail_in = size; n->nsis.next_in = (void*)ibuf; n->nsis.next_out = obuf; n->nsis.avail_out = BUFSIZ; loops=0; while ((ret=nsis_decomp(n))==CL_SUCCESS) { if ((size = n->nsis.next_out - obuf)) { gotsome=1; if (cli_writen(n->ofd, obuf, size) != (ssize_t) size) { cli_dbgmsg("NSIS: cannot write output file"__AT__"\n"); close(n->ofd); nsis_shutdown(n); return CL_EWRITE; } n->nsis.next_out = obuf; n->nsis.avail_out = BUFSIZ; loops=0; if ((ret=cli_checklimits("NSIS", ctx, size, 0, 0))!=CL_CLEAN) { close(n->ofd); nsis_shutdown(n); return ret; } } else if (++loops > 20) { cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n"); ret = CL_EFORMAT; break; } } nsis_shutdown(n); if (n->nsis.next_out - obuf) { gotsome=1; if (cli_writen(n->ofd, obuf, n->nsis.next_out - obuf) != n->nsis.next_out - obuf) { cli_dbgmsg("NSIS: cannot write output file"__AT__"\n"); close(n->ofd); return CL_EWRITE; } } if (ret != CL_SUCCESS && ret != CL_BREAK) { cli_dbgmsg("NSIS: bad stream"__AT__"\n"); if (gotsome) { ret = CL_SUCCESS; } else { ret = CL_EMAXSIZE; close(n->ofd); } return ret; } } return CL_SUCCESS; } else { if (!n->freeme) { if ((ret=nsis_init(n))!=CL_SUCCESS) { cli_dbgmsg("NSIS: decompressor init failed\n"); return ret; } if(!(n->freeme = fmap_need_off_once(n->map, n->curpos, n->asz))) { cli_dbgmsg("NSIS: cannot read %u bytes"__AT__"\n", n->asz); return CL_EREAD; } n->nsis.next_in = (void*)n->freeme; n->nsis.avail_in = n->asz; } if (n->nsis.avail_in<=4) { cli_dbgmsg("NSIS: extraction complete\n"); return CL_BREAK; } n->nsis.next_out = obuf; n->nsis.avail_out = 4; loops = 0; while ((ret=nsis_decomp(n))==CL_SUCCESS) { if (n->nsis.next_out - obuf == 4) break; if (++loops > 20) { cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n"); ret = CL_BREAK; break; } } if (ret != CL_SUCCESS) { cli_dbgmsg("NSIS: bad stream"__AT__"\n"); return CL_EFORMAT; } size=cli_readint32(obuf); if ((ret=cli_checklimits("NSIS", ctx, size, 0, 0))!=CL_CLEAN) { return ret; } if (size == 0) { cli_dbgmsg("NSIS: Empty file found.\n"); return CL_SUCCESS; } n->nsis.next_out = obuf; n->nsis.avail_out = MIN(BUFSIZ,size); loops = 0; if ((n->ofd=open(n->ofn, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600))==-1) { cli_errmsg("NSIS: unable to create output file %s - aborting.", n->ofn); return CL_ECREAT; } n->opened = 1; while (size && (ret=nsis_decomp(n))==CL_SUCCESS) { unsigned int wsz; if ((wsz = n->nsis.next_out - obuf)) { gotsome=1; if (cli_writen(n->ofd, obuf, wsz) != (ssize_t) wsz) { cli_dbgmsg("NSIS: cannot write output file"__AT__"\n"); close(n->ofd); return CL_EWRITE; } size-=wsz; loops=0; n->nsis.next_out = obuf; n->nsis.avail_out = MIN(size,BUFSIZ); } else if ( ++loops > 20 ) { cli_dbgmsg("NSIS: xs looping, breaking out"__AT__"\n"); ret = CL_EFORMAT; break; } } if (n->nsis.next_out - obuf) { gotsome=1; if (cli_writen(n->ofd, obuf, n->nsis.next_out - obuf) != n->nsis.next_out - obuf) { cli_dbgmsg("NSIS: cannot write output file"__AT__"\n"); close(n->ofd); return CL_EWRITE; } } if (ret == CL_EFORMAT) { cli_dbgmsg("NSIS: bad stream"__AT__"\n"); if (!gotsome) { close(n->ofd); return CL_EMAXSIZE; } } if (ret == CL_EFORMAT || ret == CL_BREAK) { n->eof=1; } else if (ret != CL_SUCCESS) { cli_dbgmsg("NSIS: bad stream"__AT__"\n"); close(n->ofd); return CL_EFORMAT; } return CL_SUCCESS; } }
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 unzip_search(cli_ctx *ctx, const char *name, size_t nlen, uint32_t *loff) { unsigned int fc = 0; fmap_t *map; size_t fsize; uint32_t coff = 0; const char *ptr; zip_request_t request; int ret = CL_CLEAN; #if HAVE_JSON uint32_t toval = 0; #endif cli_dbgmsg("in unzip_search\n"); if (!ctx) { return CL_ENULLARG; } map = *ctx->fmap; fsize = map->len; if(sizeof(off_t)!=sizeof(uint32_t) && fsize!=map->len) { cli_dbgmsg("unzip_search: file too big\n"); return CL_CLEAN; } if (fsize < SIZEOF_CH) { cli_dbgmsg("unzip_search: file too short\n"); return CL_CLEAN; } for(coff=fsize-22 ; coff>0 ; coff--) { /* sizeof(EOC)==22 */ if(!(ptr = fmap_need_off_once(map, coff, 20))) continue; if(cli_readint32(ptr)==0x06054b50) { uint32_t chptr = cli_readint32(&ptr[16]); if(!CLI_ISCONTAINED(0, fsize, chptr, SIZEOF_CH)) continue; coff=chptr; break; } } request.name = name; request.namelen = nlen; request.found = 0; if(coff) { cli_dbgmsg("unzip_search: central @%x\n", coff); while(ret==CL_CLEAN && (coff=chdr(map, coff, fsize, NULL, fc+1, &ret, ctx, NULL, &request))) { if (request.found) { *loff = request.loff; return CL_VIRUS; } fc++; if (ctx->engine->maxfiles && fc >= ctx->engine->maxfiles) { cli_dbgmsg("cli_unzip: Files limit reached (max: %u)\n", ctx->engine->maxfiles); ret=CL_EMAXFILES; } #if HAVE_JSON if (cli_json_timeout_cycle_check(ctx, (int *)(&toval)) != CL_SUCCESS) { return CL_ETIMEOUT; } #endif } } else { cli_dbgmsg("unzip_search: cannot locate central directory\n"); } return ret; }