fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty) { /* WIN32 */ unsigned int pages, mapsz, hdrsz; int pgsz = cli_getpagesize(); STATBUF st; fmap_t *m; const void *data; HANDLE fh; HANDLE mh; *empty = 0; if(FSTAT(fd, &st)) { cli_warnmsg("fmap: fstat failed\n"); return NULL; } if(offset < 0 || offset != fmap_align_to(offset, pgsz)) { cli_warnmsg("fmap: attempted mapping with unaligned offset\n"); return NULL; } if(!len) len = st.st_size - offset; /* bound checked later */ if(!len) { cli_dbgmsg("fmap: attempted void mapping\n"); *empty = 1; return NULL; } if(!CLI_ISCONTAINED(0, st.st_size, offset, len)) { cli_warnmsg("fmap: attempted oof mapping\n"); return NULL; } pages = fmap_align_items(len, pgsz); hdrsz = fmap_align_to(sizeof(fmap_t), pgsz); if((fh = (HANDLE)_get_osfhandle(fd)) == INVALID_HANDLE_VALUE) { cli_errmsg("fmap: cannot get a valid handle for descriptor %d\n", fd); return NULL; } if(!(mh = CreateFileMapping(fh, NULL, PAGE_READONLY, (DWORD)((len>>31)>>1), (DWORD)len, NULL))) { cli_errmsg("fmap: cannot create a map of descriptor %d\n", fd); CloseHandle(fh); return NULL; } if(!(data = MapViewOfFile(mh, FILE_MAP_READ, (DWORD)((offset>>31)>>1), (DWORD)(offset), len))) { cli_errmsg("fmap: cannot map file descriptor %d\n", fd); CloseHandle(mh); CloseHandle(fh); return NULL; } if(!(m = cl_fmap_open_memory(data, len))) { cli_errmsg("fmap: canot allocate fmap_t\n", fd); CloseHandle(mh); CloseHandle(fh); return NULL; } m->handle = (void*)(ssize_t)fd; m->handle_is_fd = 1; m->fh = fh; m->mh = mh; m->unmap = unmap_win32; return m; }
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; }
static const void *handle_need(fmap_t *m, size_t at, size_t len, int lock) { unsigned int first_page, last_page, lock_count; char *ret; if(!len) return NULL; at += m->nested_offset; if(!CLI_ISCONTAINED(0, m->real_len, at, len)) return NULL; fmap_aging(m); first_page = fmap_which_page(m, at); last_page = fmap_which_page(m, at + len - 1); lock_count = (lock!=0) * (last_page-first_page+1); #ifdef READAHED_PAGES last_page += READAHED_PAGES; if(last_page >= m->pages) last_page = m->pages - 1; #endif if(fmap_readpage(m, first_page, last_page-first_page+1, lock_count)) return NULL; ret = (char *)m; ret += at + m->hdrsz; return (void *)ret; }
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty) { STATBUF st; fmap_t *m; *empty = 0; if(FSTAT(fd, &st)) { cli_warnmsg("fmap: fstat failed\n"); return NULL; } if(!len) len = st.st_size - offset; /* bound checked later */ if(!len) { cli_dbgmsg("fmap: attempted void mapping\n"); *empty = 1; return NULL; } if(!CLI_ISCONTAINED(0, st.st_size, offset, len)) { cli_warnmsg("fmap: attempted oof mapping\n"); return NULL; } m = cl_fmap_open_handle((void*)(ssize_t)fd, offset, len, pread_cb, 1); if (!m) return NULL; m->mtime = st.st_mtime; m->handle_is_fd = 1; return m; }
static void *fmap_need(fmap_t *m, size_t at, size_t len) { /* WIN32 */ if(!CLI_ISCONTAINED(0, m->len, at, len)) return NULL; if(!len) return NULL; return (void *)((char *)m->data + at); }
static const void *mem_need(fmap_t *m, size_t at, size_t len, int lock) { /* WIN32 */ UNUSEDPARAM(lock); if(!len) { return NULL; } at += m->nested_offset; if(!CLI_ISCONTAINED(0, m->real_len, at, len)) { return NULL; } return (void *)((char *)m->data + at); }
void *fmap_need_offstr(fmap_t *m, size_t at, size_t len_hint) { /* WIN32 */ char *ptr = (char *)m->data + at; if(!len_hint || len_hint > m->len - at) len_hint = m->len - at; if(!CLI_ISCONTAINED(0, m->len, at, len_hint)) return NULL; if(memchr(ptr, 0, len_hint)) return (void *)ptr; return NULL; }
static const void *mem_need_offstr(fmap_t *m, size_t at, size_t len_hint) { char *ptr = (char *)m->data + at; if(!len_hint || len_hint > m->real_len - at) len_hint = m->real_len - at; if(!CLI_ISCONTAINED(0, m->real_len, at, len_hint)) return NULL; if(memchr(ptr, 0, len_hint)) return (void *)ptr; return NULL; }
int32_t cli_bcapi_fill_buffer(struct cli_bc_ctx *ctx, uint8_t* buf, uint32_t buflen, uint32_t filled, uint32_t pos, uint32_t fill) { int32_t res, remaining, tofill; if (!buf || !buflen || buflen > CLI_MAX_ALLOCATION || filled > buflen) { cli_dbgmsg("fill_buffer1\n"); API_MISUSE(); return -1; } if (ctx->off >= ctx->file_size) { cli_dbgmsg("fill_buffer2\n"); API_MISUSE(); return 0; } remaining = filled - pos; if (remaining) { if (!CLI_ISCONTAINED(buf, buflen, buf+pos, remaining)) { cli_dbgmsg("fill_buffer3\n"); API_MISUSE(); return -1; } memmove(buf, buf+pos, remaining); } tofill = buflen - remaining; if (!CLI_ISCONTAINED(buf, buflen, buf+remaining, tofill)) { cli_dbgmsg("fill_buffer4\n"); API_MISUSE(); return -1; } res = cli_bcapi_read(ctx, buf+remaining, tofill); if (res <= 0) { cli_dbgmsg("fill_buffer5\n"); API_MISUSE(); return res; } return remaining + res; }
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); }
static const void *handle_gets(fmap_t *m, char *dst, size_t *at, size_t max_len) { unsigned int i, first_page, last_page; char *src = (void *)((char *)m + m->hdrsz + *at), *endptr = NULL; size_t len = MIN(max_len-1, m->real_len - *at), fullen = len; if(!len || !CLI_ISCONTAINED(0, m->real_len, *at, len)) return NULL; fmap_aging(m); first_page = fmap_which_page(m, *at); last_page = fmap_which_page(m, *at + len - 1); for(i=first_page; i<=last_page; i++) { char *thispage = (char *)m + m->hdrsz + i * m->pgsz; unsigned int scanat, scansz; if(fmap_readpage(m, i, 1, 0)) return NULL; if(i == first_page) { scanat = *at % m->pgsz; scansz = MIN(len, m->pgsz - scanat); } else { scanat = 0; scansz = MIN(len, m->pgsz); } len -= scansz; if((endptr = memchr(&thispage[scanat], '\n', scansz))) { endptr++; break; } } if(endptr) { memcpy(dst, src, endptr - src); dst[endptr - src] = '\0'; *at += endptr - src; } else { memcpy(dst, src, fullen); dst[fullen] = '\0'; *at += fullen; } return dst; }
static const void *mem_gets(fmap_t *m, char *dst, size_t *at, size_t max_len) { char *src = (char *)m->data + *at, *endptr = NULL; size_t len = MIN(max_len-1, m->real_len - *at); if(!len || !CLI_ISCONTAINED(0, m->real_len, *at, len)) return NULL; if((endptr = memchr(src, '\n', len))) { endptr++; memcpy(dst, src, endptr - src); dst[endptr - src] = '\0'; *at += endptr - src; } else { memcpy(dst, src, len); dst[len] = '\0'; *at += len; } return dst; }
void fmap_unneed_off(fmap_t *m, size_t at, size_t len) { unsigned int i, first_page, last_page; if(m->dumb) return; if(!len) { cli_warnmsg("fmap_unneed: attempted void unneed\n"); return; } if(!CLI_ISCONTAINED(0, m->len, at, len)) { cli_warnmsg("fmap: attempted oof unneed\n"); return; } first_page = fmap_which_page(m, at); last_page = fmap_which_page(m, at + len - 1); for(i=first_page; i<=last_page; i++) { fmap_unneed_page(m, i); } }
static void handle_unneed_off(fmap_t *m, size_t at, size_t len) { unsigned int i, first_page, last_page; if(!m->aging) return; if(!len) { cli_warnmsg("fmap_unneed: attempted void unneed\n"); return; } at += m->nested_offset; if(!CLI_ISCONTAINED(0, m->real_len, at, len)) { cli_warnmsg("fmap: attempted oof unneed\n"); return; } first_page = fmap_which_page(m, at); last_page = fmap_which_page(m, at + len - 1); for(i=first_page; i<=last_page; i++) { fmap_unneed_page(m, i); } }
static const void *handle_need_offstr(fmap_t *m, size_t at, size_t len_hint) { unsigned int i, first_page, last_page; void *ptr = (void *)((char *)m + m->hdrsz + at); if(!len_hint || len_hint > m->real_len - at) len_hint = m->real_len - at; if(!CLI_ISCONTAINED(0, m->real_len, at, len_hint)) return NULL; fmap_aging(m); first_page = fmap_which_page(m, at); last_page = fmap_which_page(m, at + len_hint - 1); for(i=first_page; i<=last_page; i++) { char *thispage = (char *)m + m->hdrsz + i * m->pgsz; unsigned int scanat, scansz; if(fmap_readpage(m, i, 1, 1)) { last_page = i-1; break; } if(i == first_page) { scanat = at % m->pgsz; scansz = MIN(len_hint, m->pgsz - scanat); } else { scanat = 0; scansz = MIN(len_hint, m->pgsz); } len_hint -= scansz; if(memchr(&thispage[scanat], 0, scansz)) return ptr; } for(i=first_page; i<=last_page; i++) fmap_unneed_page(m, i); return NULL; }
int upx_inflate2e(const char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep) { int32_t backbytes, unp_offset = -1; uint32_t backsize, myebx = 0, scur=0, dcur=0, i, magic[]={0x128,0x130,0}; int oob; for(;;) { while ( (oob = doubleebx(src, &myebx, &scur, ssize)) ) { if (oob == -1) return -1; if (scur>=ssize || dcur>=*dsize) return -1; dst[dcur++] = src[scur++]; } backbytes = 1; for(;;) { if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 ) return -1; backbytes = backbytes*2+oob; if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 ) return -1; if ( oob ) break; backbytes--; if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 ) return -1; backbytes=backbytes*2+oob; } backbytes-=3; if ( backbytes >= 0 ) { if (scur>=ssize) return -1; backbytes<<=8; backbytes+=(unsigned char)(src[scur++]); backbytes^=0xffffffff; if (!backbytes) break; backsize = backbytes & 1; /* Using backsize to carry on the shifted out bit (UPX uses CF) */ CLI_SAR(backbytes,1); unp_offset = backbytes; } else { if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff ) return -1; } /* Using backsize to carry on the doubleebx result (UPX uses CF) */ if (backsize) { /* i.e. IF ( last sar shifted out 1 bit || last doubleebx()==1 ) */ if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff ) return -1; } else { backsize = 1; if ((oob = doubleebx(src, &myebx, &scur, ssize)) == -1) return -1; if (oob) { if ((oob = doubleebx(src, &myebx, &scur, ssize)) == -1) return -1; backsize = 2 + oob; } else { do { if ((oob = doubleebx(src, &myebx, &scur, ssize)) == -1) return -1; backsize = backsize * 2 + oob; } while ((oob = doubleebx(src, &myebx, &scur, ssize)) == 0); if (oob == -1) return -1; backsize+=2; } } if ( (uint32_t)unp_offset < 0xfffffb00 ) backsize++; backsize+=2; if (!CLI_ISCONTAINED(dst, *dsize, dst+dcur+unp_offset, backsize) || !CLI_ISCONTAINED(dst, *dsize, dst+dcur, backsize) || unp_offset >=0 ) return -1; for (i = 0; i < backsize; i++) dst[dcur + i] = dst[dcur + unp_offset + i]; dcur+=backsize; } return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur); }
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 {
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 upx_inflate2d(const char *src, uint32_t ssize, char *dst, uint32_t *dsize, uint32_t upx0, uint32_t upx1, uint32_t ep) { int32_t backbytes, unp_offset = -1; uint32_t backsize, myebx = 0, scur=0, dcur=0, i, magic[]={0x11c,0x124,0}; int oob; while (1) { while ( (oob = doubleebx(src, &myebx, &scur, ssize)) == 1) { if (scur>=ssize || dcur>=*dsize) return -1; dst[dcur++] = src[scur++]; } if ( oob == -1 ) return -1; backbytes = 1; while (1) { if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 ) return -1; backbytes = backbytes*2+oob; if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 ) return -1; if (oob) break; backbytes--; if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 ) return -1; backbytes=backbytes*2+oob; } backsize = 0; backbytes-=3; if ( backbytes >= 0 ) { if (scur>=ssize) return -1; backbytes<<=8; backbytes+=(unsigned char)(src[scur++]); backbytes^=0xffffffff; if (!backbytes) break; backsize = backbytes & 1; CLI_SAR(backbytes,1); unp_offset = backbytes; } else { if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff ) return -1; } if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 ) return -1; backsize = backsize*2 + oob; if (!backsize) { backsize++; do { if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 ) return -1; backsize = backsize*2 + oob; } while ( (oob = doubleebx(src, &myebx, &scur, ssize)) == 0); if ( oob == -1 ) return -1; backsize+=2; } if ( (uint32_t)unp_offset < 0xfffffb00 ) backsize++; backsize++; if (!CLI_ISCONTAINED(dst, *dsize, dst+dcur+unp_offset, backsize) || !CLI_ISCONTAINED(dst, *dsize, dst+dcur, backsize) || unp_offset >=0 ) return -1; for (i = 0; i < backsize; i++) dst[dcur + i] = dst[dcur + unp_offset + i]; dcur+=backsize; } return pefromupx (src, ssize, dst, dsize, ep, upx0, upx1, magic, dcur); }
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 */ }
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty) { unsigned int pages, mapsz, hdrsz; unsigned short dumb = 1; int pgsz = cli_getpagesize(); struct stat st; fmap_t *m; *empty = 0; if(fstat(fd, &st)) { cli_warnmsg("fmap: fstat failed\n"); return NULL; } if(offset < 0 || offset != fmap_align_to(offset, pgsz)) { cli_warnmsg("fmap: attempted mapping with unaligned offset\n"); return NULL; } if(!len) len = st.st_size - offset; /* bound checked later */ if(!len) { cli_dbgmsg("fmap: attempted void mapping\n"); *empty = 1; return NULL; } if(!CLI_ISCONTAINED(0, st.st_size, offset, len)) { cli_warnmsg("fmap: attempted oof mapping\n"); return NULL; } pages = fmap_align_items(len, pgsz); hdrsz = fmap_align_to(sizeof(fmap_t) + (pages-1) * sizeof(uint32_t), pgsz); /* fmap_t includes 1 bitmap slot, hence (pages-1) */ mapsz = pages * pgsz + hdrsz; fmap_lock; #ifdef ANONYMOUS_MAP if ((m = (fmap_t *)mmap(NULL, mapsz, PROT_READ | PROT_WRITE, MAP_PRIVATE|/*FIXME: MAP_POPULATE is ~8% faster but more memory intensive */ANONYMOUS_MAP, -1, 0)) == MAP_FAILED) { m = NULL; } else { dumb = 0; #if HAVE_MADVISE madvise((void *)m, mapsz, MADV_RANDOM|MADV_DONTFORK); #endif /* madvise */ } #else /* ! ANONYMOUS_MAP */ m = (fmap_t *)cli_malloc(mapsz); #endif /* ANONYMOUS_MAP */ if(!m) { cli_warnmsg("fmap: map allocation failed\n"); fmap_unlock; return NULL; } /* fault the header while we still have the lock - we DO context switch here a lot here :@ */ memset(fmap_bitmap, 0, sizeof(uint32_t) * pages); fmap_unlock; m->fd = fd; m->dumb = dumb; m->mtime = st.st_mtime; m->offset = offset; m->len = len; m->pages = pages; m->hdrsz = hdrsz; m->pgsz = pgsz; m->paged = 0; m->dont_cache_flag = 0; return m; }
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty) { /* WIN32 */ unsigned int pages, mapsz, hdrsz; unsigned short dumb = 1; int pgsz = cli_getpagesize(); struct stat st; fmap_t *m; *empty = 0; if(fstat(fd, &st)) { cli_warnmsg("fmap: fstat failed\n"); return NULL; } if(offset < 0 || offset != fmap_align_to(offset, pgsz)) { cli_warnmsg("fmap: attempted mapping with unaligned offset\n"); return NULL; } if(!len) len = st.st_size - offset; /* bound checked later */ if(!len) { cli_dbgmsg("fmap: attempted void mapping\n"); *empty = 1; return NULL; } if(!CLI_ISCONTAINED(0, st.st_size, offset, len)) { cli_warnmsg("fmap: attempted oof mapping\n"); return NULL; } pages = fmap_align_items(len, pgsz); hdrsz = fmap_align_to(sizeof(fmap_t), pgsz); if(!(m = (fmap_t *)cli_malloc(sizeof(fmap_t)))) { cli_errmsg("fmap: canot allocate fmap_t\n", fd); return NULL; } if((m->fh = (HANDLE)_get_osfhandle(fd)) == INVALID_HANDLE_VALUE) { cli_errmsg("fmap: cannot get a valid handle for descriptor %d\n", fd); free(m); return NULL; } if(!(m->mh = CreateFileMapping(m->fh, NULL, PAGE_READONLY, (DWORD)((len>>31)>>1), (DWORD)len, NULL))) { cli_errmsg("fmap: cannot create a map of descriptor %d\n", fd); free(m); return NULL; } if(!(m->data = MapViewOfFile(m->mh, FILE_MAP_READ, (DWORD)((offset>>31)>>1), (DWORD)(offset), len))) { cli_errmsg("fmap: cannot map file descriptor %d\n", fd); CloseHandle(m->mh); free(m); return NULL; } m->fd = fd; m->dumb = dumb; m->mtime = st.st_mtime; m->offset = offset; m->len = len; m->pages = pages; m->hdrsz = hdrsz; m->pgsz = pgsz; m->paged = 0; m->dont_cache_flag = 0; return m; }
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; }
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; }
int cli_unfsg(char *source, char *dest, int ssize, int dsize, char **endsrc, char **enddst) { uint8 mydl=0x80; uint32 backbytes, backsize, oldback = 0; char *csrc = source, *cdst = dest; int oob, lostbit = 1; if (ssize<=0 || dsize<=0) return -1; *cdst++=*csrc++; while ( 1 ) { if ((oob=doubledl(&csrc, &mydl, source, ssize))) { if (oob == -1) return -1; /* 164 */ backsize = 0; if ((oob=doubledl(&csrc, &mydl, source, ssize))) { if (oob == -1) return -1; /* 16a */ backbytes = 0; if ((oob=doubledl(&csrc, &mydl, source, ssize))) { if (oob == -1) return -1; /* 170 */ lostbit = 1; backsize++; backbytes = 0x10; while ( backbytes < 0x100 ) { if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1) return -1; backbytes = backbytes*2+oob; } backbytes &= 0xff; if ( ! backbytes ) { if (cdst >= dest+dsize) return -1; *cdst++=0x00; continue; } } else { /* 18f */ if (csrc >= source+ssize) return -1; backbytes = *(unsigned char*)csrc; backsize = backsize * 2 + (backbytes & 1); backbytes = (backbytes & 0xff)>>1; csrc++; if (! backbytes) break; backsize+=2; oldback = backbytes; lostbit = 0; } } else { /* 180 */ backsize = 1; do { if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1) return -1; backsize = backsize*2+oob; if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1) return -1; } while (oob); backsize = backsize - 1 - lostbit; if (! backsize) { /* 18a */ backsize = 1; do { if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1) return -1; backsize = backsize*2+oob; if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1) return -1; } while (oob); backbytes = oldback; } else { /* 198 */ if (csrc >= source+ssize) return -1; backbytes = *(unsigned char*)csrc; backbytes += (backsize-1)<<8; backsize = 1; csrc++; do { if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1) return -1; backsize = backsize*2+oob; if ((oob=doubledl(&csrc, &mydl, source, ssize)) == -1) return -1; } while (oob); if (backbytes >= 0x7d00) backsize++; if (backbytes >= 0x500) backsize++; if (backbytes <= 0x7f) backsize += 2; oldback = backbytes; } lostbit = 0; } if (!CLI_ISCONTAINED(dest, dsize, cdst, backsize) || !CLI_ISCONTAINED(dest, dsize, cdst-backbytes, backsize)) return -1; while(backsize--) { *cdst=*(cdst-backbytes); cdst++; } } else { /* 15d */ if (cdst < dest || cdst >= dest+dsize || csrc < source || csrc >= source+ssize)
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; }