inline static void __fixup_rootseek(off_t offset_of_trailer, struct zip_disk_trailer *trailer) { if((off_t) EC32(trailer->z_rootseek) > offset_of_trailer - (off_t) EC32(trailer->z_rootsize) && offset_of_trailer > (off_t) EC32(trailer->z_rootsize)) trailer->z_rootseek = (uint32_t) (offset_of_trailer - EC32(trailer->z_rootsize)); }
int cli_scanmacho_unibin(cli_ctx *ctx) { struct macho_fat_header fat_header; struct macho_fat_arch fat_arch; unsigned int conv, i, matcher = 0; int ret = CL_CLEAN; fmap_t *map = *ctx->fmap; ssize_t at; if(fmap_readn(map, &fat_header, 0, sizeof(fat_header)) != sizeof(fat_header)) { cli_dbgmsg("cli_scanmacho_unibin: Can't read fat_header\n"); return CL_EFORMAT; } at = sizeof(fat_header); if(fat_header.magic == 0xcafebabe) { conv = 0; } else if(fat_header.magic == 0xbebafeca) { conv = 1; } else { cli_dbgmsg("cli_scanmacho_unibin: Incorrect magic\n"); return CL_EFORMAT; } fat_header.nfats = EC32(fat_header.nfats, conv); if((fat_header.nfats & 0xffff) >= 39) /* Java Bytecode */ return CL_CLEAN; if(fat_header.nfats > 32) { cli_dbgmsg("cli_scanmacho_unibin: Invalid number of architectures\n"); return CL_EFORMAT; } cli_dbgmsg("UNIBIN: Number of architectures: %u\n", (unsigned int) fat_header.nfats); for(i = 0; i < fat_header.nfats; i++) { if(fmap_readn(map, &fat_arch, at, sizeof(fat_arch)) != sizeof(fat_arch)) { cli_dbgmsg("cli_scanmacho_unibin: Can't read fat_arch\n"); RETURN_BROKEN; } at += sizeof(fat_arch); fat_arch.offset = EC32(fat_arch.offset, conv); fat_arch.size = EC32(fat_arch.size, conv); cli_dbgmsg("UNIBIN: Binary %u of %u\n", i + 1, fat_header.nfats); cli_dbgmsg("UNIBIN: File offset: %u\n", fat_arch.offset); cli_dbgmsg("UNIBIN: File size: %u\n", fat_arch.size); ret = cli_map_scan(map, fat_arch.offset, fat_arch.size, ctx); if(ret == CL_VIRUS) break; } return ret; /* result from the last binary */ }
static uint32_t cli_rawaddr32(uint32_t vaddr, struct elf_program_hdr32 *ph, uint16_t phnum, uint8_t conv, uint8_t *err) { uint16_t i, found = 0; for(i = 0; i < phnum; i++) { if(EC32(ph[i].p_vaddr, conv) <= vaddr && EC32(ph[i].p_vaddr, conv) + EC32(ph[i].p_memsz, conv) > vaddr) { found = 1; break; } } if(!found) { *err = 1; return 0; } *err = 0; return vaddr - EC32(ph[i].p_vaddr, conv) + EC32(ph[i].p_offset, conv); }
int cli_msexpand(cli_ctx *ctx, int ofd) { const struct msexp_hdr *hdr; uint8_t i, mask, bits; unsigned char buff[B_SIZE], wbuff[RW_SIZE]; const unsigned char *rbuff; unsigned int j = B_SIZE - 16, k, l, r = 0, w = 0, rbytes = 0, wbytes = 0; fmap_t *map = *ctx->fmap; off_t cur_off = sizeof(*hdr); unsigned int fsize; int ret; if(!(hdr = fmap_need_off_once(map, 0, sizeof(*hdr)))) return CL_EREAD; if(EC32(hdr->magic1) != MAGIC1 || EC32(hdr->magic2) != MAGIC2 || EC16(hdr->magic3) != MAGIC3) { cli_dbgmsg("MSEXPAND: Not supported file format\n"); return CL_EFORMAT; } fsize = EC32(hdr->fsize); cli_dbgmsg("MSEXPAND: File size from header: %u\n", fsize); if(cli_checklimits("MSEXPAND", ctx, fsize, 0, 0)!=CL_CLEAN) return CL_SUCCESS; memset(buff, 0, B_SIZE); while(1) { if(!rbytes || (r == rbytes)) { READBYTES; } bits = rbuff[r]; r++; mask = 1; for(i = 0; i < 8; i++) { if(bits & mask) { if(r == rbytes) { READBYTES; } if(w == RW_SIZE) { WRITEBYTES; } wbuff[w] = buff[j] = rbuff[r]; r++; w++; j++; j %= B_SIZE; } else { if(r == rbytes) { READBYTES; } k = rbuff[r]; r++; if(r == rbytes) { READBYTES; } l = rbuff[r]; r++; k += (l & 0xf0) << 4; l = (l & 0x0f) + 3; while(l--) { if(w == RW_SIZE) { WRITEBYTES; } wbuff[w] = buff[j] = buff[k]; w++; k++; k %= B_SIZE; j++; j %= B_SIZE; } } mask *= 2; } } if(w) { WRITEBYTES; } return CL_SUCCESS; }
/* Return converted endian-fixed header, or error code */ static int cli_elf_fileheader(cli_ctx *ctx, fmap_t *map, union elf_file_hdr *file_hdr, uint8_t *do_convert, uint8_t *is64) { uint8_t format64, conv; /* Load enough for smaller header first */ if(fmap_readn(map, file_hdr, 0, sizeof(struct elf_file_hdr32)) != sizeof(struct elf_file_hdr32)) { /* Not an ELF file? */ cli_dbgmsg("ELF: Can't read file header\n"); return CL_BREAK; } if(memcmp(file_hdr->hdr64.e_ident, "\x7f\x45\x4c\x46", 4)) { cli_dbgmsg("ELF: Not an ELF file\n"); return CL_BREAK; } switch(file_hdr->hdr64.e_ident[4]) { case 1: cli_dbgmsg("ELF: ELF class 1 (32-bit)\n"); format64 = 0; break; case 2: cli_dbgmsg("ELF: ELF class 2 (64-bit)\n"); format64 = 1; break; default: cli_dbgmsg("ELF: Unknown ELF class (%u)\n", file_hdr->hdr64.e_ident[4]); return CL_EFORMAT; } /* Need to know to endian convert */ if(file_hdr->hdr64.e_ident[5] == 1) { #if WORDS_BIGENDIAN == 0 if(ctx) cli_dbgmsg("ELF: File is little-endian - conversion not required\n"); conv = 0; #else if(ctx) cli_dbgmsg("ELF: File is little-endian - data conversion enabled\n"); conv = 1; #endif } else { #if WORDS_BIGENDIAN == 0 if(ctx) cli_dbgmsg("ELF: File is big-endian - data conversion enabled\n"); conv = 1; #else if(ctx) cli_dbgmsg("ELF: File is big-endian - conversion not required\n"); conv = 0; #endif } *do_convert = conv; *is64 = format64; /* Solve bit-size and conversion pronto */ file_hdr->hdr64.e_type = EC16(file_hdr->hdr64.e_type, conv); file_hdr->hdr64.e_machine = EC16(file_hdr->hdr64.e_machine, conv); file_hdr->hdr64.e_version = EC32(file_hdr->hdr64.e_version, conv); if(format64) { /* Read rest of 64-bit header */ if(fmap_readn(map, file_hdr->hdr32.pad, sizeof(struct elf_file_hdr32), ELF_HDR_SIZEDIFF) != ELF_HDR_SIZEDIFF) { /* Not an ELF file? */ cli_dbgmsg("ELF: Can't read file header\n"); return CL_BREAK; } /* Now endian convert, if needed */ if(conv) { file_hdr->hdr64.e_entry = EC64(file_hdr->hdr64.e_entry, conv); file_hdr->hdr64.e_phoff = EC64(file_hdr->hdr64.e_phoff, conv); file_hdr->hdr64.e_shoff = EC64(file_hdr->hdr64.e_shoff, conv); file_hdr->hdr64.e_flags = EC32(file_hdr->hdr64.e_flags, conv); file_hdr->hdr64.e_ehsize = EC16(file_hdr->hdr64.e_ehsize, conv); file_hdr->hdr64.e_phentsize = EC16(file_hdr->hdr64.e_phentsize, conv); file_hdr->hdr64.e_phnum = EC16(file_hdr->hdr64.e_phnum, conv); file_hdr->hdr64.e_shentsize = EC16(file_hdr->hdr64.e_shentsize, conv); file_hdr->hdr64.e_shnum = EC16(file_hdr->hdr64.e_shnum, conv); file_hdr->hdr64.e_shstrndx = EC16(file_hdr->hdr64.e_shstrndx, conv); } } else { /* Convert 32-bit structure, if needed */ if(conv) { file_hdr->hdr32.hdr.e_entry = EC32(file_hdr->hdr32.hdr.e_entry, conv); file_hdr->hdr32.hdr.e_phoff = EC32(file_hdr->hdr32.hdr.e_phoff, conv); file_hdr->hdr32.hdr.e_shoff = EC32(file_hdr->hdr32.hdr.e_shoff, conv); file_hdr->hdr32.hdr.e_flags = EC32(file_hdr->hdr32.hdr.e_flags, conv); file_hdr->hdr32.hdr.e_ehsize = EC16(file_hdr->hdr32.hdr.e_ehsize, conv); file_hdr->hdr32.hdr.e_phentsize = EC16(file_hdr->hdr32.hdr.e_phentsize, conv); file_hdr->hdr32.hdr.e_phnum = EC16(file_hdr->hdr32.hdr.e_phnum, conv); file_hdr->hdr32.hdr.e_shentsize = EC16(file_hdr->hdr32.hdr.e_shentsize, conv); file_hdr->hdr32.hdr.e_shnum = EC16(file_hdr->hdr32.hdr.e_shnum, conv); file_hdr->hdr32.hdr.e_shstrndx = EC16(file_hdr->hdr32.hdr.e_shstrndx, conv); } /* Wipe pad for safety */ memset(file_hdr->hdr32.pad, 0, ELF_HDR_SIZEDIFF); } return CL_CLEAN; }
/* 64-bit version of section header parsing */ static int cli_elf_sh64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo, struct elf_file_hdr64 *file_hdr, uint8_t conv) { struct elf_section_hdr64 *section_hdr = NULL; uint16_t shnum, shentsize; uint32_t i; uint64_t shoff; shnum = file_hdr->e_shnum; cli_dbgmsg("ELF: Number of sections: %d\n", shnum); if(ctx && (shnum > 2048)) { cli_dbgmsg("ELF: Number of sections > 2048, skipping\n"); return CL_BREAK; } else if(elfinfo && (shnum > 256)) { cli_dbgmsg("ELF: Suspicious number of sections\n"); return CL_BREAK; } if(elfinfo) { elfinfo->nsections = shnum; } shentsize = file_hdr->e_shentsize; /* Sanity check */ if(shentsize != sizeof(struct elf_section_hdr64)) { cli_dbgmsg("ELF: shentsize != sizeof(struct elf_section_hdr64)\n"); if(ctx && DETECT_BROKEN) { cli_append_virus(ctx, "Heuristics.Broken.Executable"); return CL_VIRUS; } return CL_EFORMAT; } if(elfinfo && !shnum) { return CL_CLEAN; } shoff = file_hdr->e_shoff; if(ctx) cli_dbgmsg("ELF: Section header table offset: " STDu64 "\n", shoff); if(elfinfo) { elfinfo->section = (struct cli_exe_section *)cli_calloc(shnum, sizeof(struct cli_exe_section)); if(!elfinfo->section) { cli_dbgmsg("ELF: Can't allocate memory for section headers\n"); return CL_EMEM; } } if(shnum) { section_hdr = (struct elf_section_hdr64 *) cli_calloc(shnum, shentsize); if(!section_hdr) { cli_errmsg("ELF: Can't allocate memory for section headers\n"); if(elfinfo) { free(elfinfo->section); elfinfo->section = NULL; } return CL_EMEM; } if(ctx) { cli_dbgmsg("------------------------------------\n"); } } /* Loop over section headers */ for(i = 0; i < shnum; i++) { uint32_t sh_type, sh_flags; if(fmap_readn(map, §ion_hdr[i], shoff, sizeof(struct elf_section_hdr64)) != sizeof(struct elf_section_hdr64)) { cli_dbgmsg("ELF: Can't read section header\n"); if(ctx) { cli_dbgmsg("ELF: Possibly broken ELF file\n"); } free(section_hdr); if(elfinfo) { free(elfinfo->section); elfinfo->section = NULL; } if(ctx && DETECT_BROKEN) { cli_append_virus(ctx, "Heuristics.Broken.Executable"); return CL_VIRUS; } return CL_BREAK; } shoff += sizeof(struct elf_section_hdr64); if(elfinfo) { elfinfo->section[i].rva = EC64(section_hdr[i].sh_addr, conv); elfinfo->section[i].raw = EC64(section_hdr[i].sh_offset, conv); elfinfo->section[i].rsz = EC64(section_hdr[i].sh_size, conv); } if(ctx) { cli_dbgmsg("ELF: Section %u\n", i); cli_dbgmsg("ELF: Section offset: " STDu64 "\n", EC64(section_hdr[i].sh_offset, conv)); cli_dbgmsg("ELF: Section size: " STDu64 "\n", EC64(section_hdr[i].sh_size, conv)); sh_type = EC32(section_hdr[i].sh_type, conv); sh_flags = (uint32_t)(EC64(section_hdr[i].sh_flags, conv) & ELF_SHF_MASK); cli_elf_sectionlog(sh_type, sh_flags); cli_dbgmsg("------------------------------------\n"); } } free(section_hdr); return CL_CLEAN; }
/* Read 64-bit program headers */ static int cli_elf_ph64(cli_ctx *ctx, fmap_t *map, struct cli_exe_info *elfinfo, struct elf_file_hdr64 *file_hdr, uint8_t conv) { struct elf_program_hdr64 *program_hdr = NULL; uint16_t phnum, phentsize; uint64_t entry, fentry = 0, phoff; uint32_t i; uint8_t err; /* Program headers and Entry */ phnum = file_hdr->e_phnum; cli_dbgmsg("ELF: Number of program headers: %d\n", phnum); if(phnum > 128) { cli_dbgmsg("ELF: Suspicious number of program headers\n"); if(ctx && DETECT_BROKEN) { cli_append_virus(ctx, "Heuristics.Broken.Executable"); return CL_VIRUS; } return CL_EFORMAT; } entry = file_hdr->e_entry; if(phnum && entry) { phentsize = file_hdr->e_phentsize; /* Sanity check */ if (phentsize != sizeof(struct elf_program_hdr64)) { cli_dbgmsg("ELF: phentsize != sizeof(struct elf_program_hdr64)\n"); if(ctx && DETECT_BROKEN) { cli_append_virus(ctx, "Heuristics.Broken.Executable"); return CL_VIRUS; } return CL_EFORMAT; } phoff = file_hdr->e_phoff; if(ctx) { cli_dbgmsg("ELF: Program header table offset: " STDu64 "\n", phoff); } if(phnum) { program_hdr = (struct elf_program_hdr64 *) cli_calloc(phnum, sizeof(struct elf_program_hdr64)); if(!program_hdr) { cli_errmsg("ELF: Can't allocate memory for program headers\n"); return CL_EMEM; } if(ctx) { cli_dbgmsg("------------------------------------\n"); } } for(i = 0; i < phnum; i++) { err = 0; if(fmap_readn(map, &program_hdr[i], phoff, sizeof(struct elf_program_hdr64)) != sizeof(struct elf_program_hdr64)) err = 1; phoff += sizeof(struct elf_program_hdr64); if(err) { cli_dbgmsg("ELF: Can't read segment #%d\n", i); if(ctx) { cli_dbgmsg("ELF: Possibly broken ELF file\n"); } free(program_hdr); if(ctx && DETECT_BROKEN) { cli_append_virus(ctx, "Heuristics.Broken.Executable"); return CL_VIRUS; } return CL_BREAK; } if(ctx) { cli_dbgmsg("ELF: Segment #%d\n", i); cli_dbgmsg("ELF: Segment type: 0x%x\n", EC32(program_hdr[i].p_type, conv)); cli_dbgmsg("ELF: Segment offset: 0x" STDx64 "\n", EC64(program_hdr[i].p_offset, conv)); cli_dbgmsg("ELF: Segment virtual address: 0x" STDx64 "\n", EC64(program_hdr[i].p_vaddr, conv)); cli_dbgmsg("ELF: Segment real size: 0x" STDx64 "\n", EC64(program_hdr[i].p_filesz, conv)); cli_dbgmsg("ELF: Segment virtual size: 0x" STDx64 "\n", EC64(program_hdr[i].p_memsz, conv)); cli_dbgmsg("------------------------------------\n"); } } fentry = cli_rawaddr64(entry, program_hdr, phnum, conv, &err); free(program_hdr); if(err) { cli_dbgmsg("ELF: Can't calculate file offset of entry point\n"); if(ctx && DETECT_BROKEN) { cli_append_virus(ctx, "Heuristics.Broken.Executable"); return CL_VIRUS; } return CL_EFORMAT; } if(ctx) { cli_dbgmsg("ELF: Entry point address: 0x%.16" PRIx64 "\n", entry); cli_dbgmsg("ELF: Entry point offset: 0x%.16" PRIx64 " (" STDi64 ")\n", fentry, fentry); } } if(elfinfo) { elfinfo->ep = fentry; } return CL_CLEAN; }
int cli_rebuildpe(char *buffer, struct cli_exe_section *sections, int sects, uint32_t base, uint32_t ep, uint32_t ResRva, uint32_t ResSize, int file) { uint32_t datasize=0, rawbase=PESALIGN(0x148+0x80+0x28*sects, 0x200); char *pefile=NULL, *curpe; struct IMAGE_PE_HEADER *fakepe; int i, gotghost=(sections[0].rva > PESALIGN(rawbase, 0x1000)); if (gotghost) rawbase=PESALIGN(0x148+0x80+0x28*(sects+1), 0x200); if(sects+gotghost > 96) return 0; for (i=0; i < sects; i++) datasize+=PESALIGN(sections[i].rsz, 0x200); if(datasize > CLI_MAX_ALLOCATION) return 0; if((pefile = (char *) cli_calloc(rawbase+datasize, 1))) { memcpy(pefile, HEADERS, 0x148); datasize = PESALIGN(rawbase, 0x1000); fakepe = (struct IMAGE_PE_HEADER *)(pefile+0xd0); fakepe->NumberOfSections = EC16(sects+gotghost); fakepe->AddressOfEntryPoint = EC32(ep); fakepe->ImageBase = EC32(base); fakepe->SizeOfHeaders = EC32(rawbase); memset(pefile+0x148, 0, 0x80); cli_writeint32(pefile+0x148+0x10, ResRva); cli_writeint32(pefile+0x148+0x14, ResSize); curpe = pefile+0x148+0x80; if (gotghost) { snprintf(curpe, 8, "empty"); cli_writeint32(curpe+8, sections[0].rva-datasize); /* vsize */ cli_writeint32(curpe+12, datasize); /* rva */ cli_writeint32(curpe+0x24, 0xffffffff); curpe+=40; datasize+=PESALIGN(sections[0].rva-datasize, 0x1000); } for (i=0; i < sects; i++) { snprintf(curpe, 8, ".clam%.2d", i+1); cli_writeint32(curpe+8, sections[i].vsz); cli_writeint32(curpe+12, sections[i].rva); cli_writeint32(curpe+16, sections[i].rsz); cli_writeint32(curpe+20, rawbase); /* already zeroed cli_writeint32(curpe+24, 0); cli_writeint32(curpe+28, 0); cli_writeint32(curpe+32, 0); */ cli_writeint32(curpe+0x24, 0xffffffff); memcpy(pefile+rawbase, buffer+sections[i].raw, sections[i].rsz); rawbase+=PESALIGN(sections[i].rsz, 0x200); curpe+=40; datasize+=PESALIGN(sections[i].vsz, 0x1000); } fakepe->SizeOfImage = EC32(datasize); } else { return 0; } i = (cli_writen(file, pefile, rawbase)!=-1); free(pefile); return i; }
static int 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 cab_open(int fd, off_t offset, struct cab_archive *cab) { unsigned int i, folders = 0; struct cab_file *file, *lfile = NULL; struct cab_folder *folder, *lfolder = NULL; struct cab_hdr hdr; struct cab_hdr_opt hdr_opt; struct cab_folder_hdr folder_hdr; struct cab_file_hdr file_hdr; struct stat sb; uint16_t fidx; char *pt; int ret; off_t resfold = 0, rsize; if(lseek(fd, offset, SEEK_SET) == -1) { cli_errmsg("cab_open: Can't lseek to %u (offset)\n", (unsigned int) offset); return CL_ESEEK; } if(cli_readn(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { cli_dbgmsg("cab_open: Can't read cabinet header\n"); return CL_EFORMAT; /* most likely a corrupted file */ } if(EC32(hdr.signature) != 0x4643534d) { cli_dbgmsg("cab_open: Incorrect CAB signature\n"); return CL_EFORMAT; } else { cli_dbgmsg("CAB: -------------- Cabinet file ----------------\n"); } if(fstat(fd, &sb) == -1) { cli_errmsg("cab_open: Can't fstat descriptor %d\n", fd); return CL_ESTAT; } rsize = sb.st_size; memset(cab, 0, sizeof(struct cab_archive)); cab->length = EC32(hdr.cbCabinet); cli_dbgmsg("CAB: Cabinet length: %u\n", cab->length); if((off_t) cab->length > rsize) { cli_dbgmsg("CAB: Truncating file size from %lu to %lu\n", (unsigned long int) cab->length, (unsigned long int) rsize); cab->length = (uint32_t) rsize; } cab->nfolders = EC16(hdr.cFolders); if(!cab->nfolders) { cli_dbgmsg("cab_open: No folders in cabinet (fake cab?)\n"); return CL_EFORMAT; } else { cli_dbgmsg("CAB: Folders: %u\n", cab->nfolders); if(cab->nfolders > CAB_FOLDER_LIMIT) { cab->nfolders = CAB_FOLDER_LIMIT; cli_dbgmsg("CAB: *** Number of folders limited to %u ***\n", cab->nfolders); } } cab->nfiles = EC16(hdr.cFiles); if(!cab->nfiles) { cli_dbgmsg("cab_open: No files in cabinet (fake cab?)\n"); return CL_EFORMAT; } else { cli_dbgmsg("CAB: Files: %u\n", cab->nfiles); if(cab->nfiles > CAB_FILE_LIMIT) { cab->nfiles = CAB_FILE_LIMIT; cli_dbgmsg("CAB: *** Number of files limited to %u ***\n", cab->nfiles); } } cli_dbgmsg("CAB: File format version: %u.%u\n", hdr.versionMajor, hdr.versionMinor); cab->flags = EC16(hdr.flags); if(cab->flags & 0x0004) { if(cli_readn(fd, &hdr_opt, sizeof(hdr_opt)) != sizeof(hdr_opt)) { cli_dbgmsg("cab_open: Can't read file header (fake cab?)\n"); return CL_EFORMAT; /* most likely a corrupted file */ } cab->reshdr = EC16(hdr_opt.cbCFHeader); resfold = hdr_opt.cbCFFolder; cab->resdata = hdr_opt.cbCFData; if(cab->reshdr) { if(lseek(fd, cab->reshdr, SEEK_CUR) == -1) { cli_dbgmsg("cab_open: Can't lseek to %u (fake cab?)\n", cab->reshdr); return CL_EFORMAT; /* most likely a corrupted file */ } } } if(cab->flags & 0x0001) { /* preceeding cabinet */ /* name */ pt = cab_readstr(fd, &ret); if(ret) return ret; if(cab_chkname(pt, 0)) cli_dbgmsg("CAB: Invalid name of preceeding cabinet\n"); else cli_dbgmsg("CAB: Preceeding cabinet name: %s\n", pt); free(pt); /* info */ pt = cab_readstr(fd, &ret); if(ret) return ret; if(cab_chkname(pt, 0)) cli_dbgmsg("CAB: Invalid info for preceeding cabinet\n"); else cli_dbgmsg("CAB: Preceeding cabinet info: %s\n", pt); free(pt); } if(cab->flags & 0x0002) { /* next cabinet */ /* name */ pt = cab_readstr(fd, &ret); if(ret) return ret; if(cab_chkname(pt, 0)) cli_dbgmsg("CAB: Invalid name of next cabinet\n"); else cli_dbgmsg("CAB: Next cabinet name: %s\n", pt); free(pt); /* info */ pt = cab_readstr(fd, &ret); if(ret) return ret; if(cab_chkname(pt, 0)) cli_dbgmsg("CAB: Invalid info for next cabinet\n"); else cli_dbgmsg("CAB: Next cabinet info: %s\n", pt); free(pt); } /* folders */ for(i = 0; i < cab->nfolders; i++) { if(cli_readn(fd, &folder_hdr, sizeof(folder_hdr)) != sizeof(folder_hdr)) { cli_dbgmsg("cab_open: Can't read header for folder %u\n", i); break; } if(resfold) { if(lseek(fd, resfold, SEEK_CUR) == -1) { cli_dbgmsg("cab_open: Can't lseek to %u (resfold)\n", (unsigned int) resfold); break; } } if(EC32(folder_hdr.coffCabStart) + offset > rsize) { cli_dbgmsg("CAB: Folder out of file\n"); continue; } if((EC16(folder_hdr.typeCompress) & 0x000f) > 3) { cli_dbgmsg("CAB: Unknown compression method\n"); continue; } folder = (struct cab_folder *) cli_calloc(1, sizeof(struct cab_folder)); if(!folder) { cli_errmsg("cab_open: Can't allocate memory for folder\n"); cab_free(cab); return CL_EMEM; } folder->cab = (struct cab_archive *) cab; folder->offset = (off_t) EC32(folder_hdr.coffCabStart) + offset; folder->nblocks = EC16(folder_hdr.cCFData); folder->cmethod = EC16(folder_hdr.typeCompress); cli_dbgmsg("CAB: Folder record %u\n", i); cli_dbgmsg("CAB: Folder offset: %u\n", (unsigned int) folder->offset); cli_dbgmsg("CAB: Folder compression method: %d\n", folder->cmethod); if(!lfolder) cab->folders = folder; else lfolder->next = folder; lfolder = folder; folders++; } cli_dbgmsg("CAB: Recorded folders: %u\n", folders); /* files */ if(cab->nfolders != folders && lseek(fd, EC16(hdr.coffFiles), SEEK_SET) == -1) { cli_dbgmsg("cab_open: Can't lseek to hdr.coffFiles\n"); cab_free(cab); return CL_EFORMAT; } for(i = 0; i < cab->nfiles; i++) { if(cli_readn(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) { cli_dbgmsg("cab_open: Can't read file %u header\n", i); break; } file = (struct cab_file *) cli_calloc(1, sizeof(struct cab_file)); if(!file) { cli_errmsg("cab_open: Can't allocate memory for file\n"); cab_free(cab); return CL_EMEM; } file->cab = cab; file->fd = fd; file->offset = EC32(file_hdr.uoffFolderStart); file->length = EC32(file_hdr.cbFile); file->attribs = EC32(file_hdr.attribs); fidx = EC32(file_hdr.iFolder); file->error = CL_SUCCESS; file->name = cab_readstr(fd, &ret); if(ret) { free(file); continue; } cab_chkname(file->name, 1); cli_dbgmsg("CAB: File record %u\n", i); cli_dbgmsg("CAB: File name: %s\n", file->name); cli_dbgmsg("CAB: File offset: %u\n", (unsigned int) file->offset); cli_dbgmsg("CAB: File folder index: %u\n", fidx); cli_dbgmsg("CAB: File attribs: 0x%x\n", file->attribs); if(file->attribs & 0x01) cli_dbgmsg("CAB: * file is read-only\n"); if(file->attribs & 0x02) cli_dbgmsg("CAB: * file is hidden\n"); if(file->attribs & 0x04) cli_dbgmsg("CAB: * file is a system file\n"); if(file->attribs & 0x20) cli_dbgmsg("CAB: * file modified since last backup\n"); if(file->attribs & 0x40) cli_dbgmsg("CAB: * file to be run after extraction\n"); if(file->attribs & 0x80) cli_dbgmsg("CAB: * file name contains UTF\n"); /* folder index */ if(fidx < 0xfffd) { if(fidx > cab->nfolders) { cli_dbgmsg("cab_open: File %s is not associated with any folder\n", file->name); free(file->name); free(file); continue; } file->folder = cab->folders; while(file->folder && fidx--) file->folder = file->folder->next; if(!file->folder) { cli_dbgmsg("cab_open: Folder not found for file %s\n", file->name); free(file->name); free(file); continue; } } else { cli_dbgmsg("CAB: File is split *skipping*\n"); free(file->name); free(file); continue; } if(!lfile) cab->files = file; else lfile->next = file; lfile = file; } return CL_SUCCESS; }
int cli_scanswf(cli_ctx *ctx) { struct swf_file_hdr file_hdr; fmap_t *map = *ctx->fmap; unsigned int bitpos, bitbuf, getbits_n, nbits, getword_1, getword_2, getdword_1, getdword_2; const char *pt; unsigned char get_c; size_t offset = 0; unsigned int val, foo, tag_hdr, tag_type, tag_len; unsigned long int bits; cli_dbgmsg("in cli_scanswf()\n"); if(fmap_readn(map, &file_hdr, offset, sizeof(file_hdr)) != sizeof(file_hdr)) { cli_dbgmsg("SWF: Can't read file header\n"); return CL_CLEAN; } offset += sizeof(file_hdr); if(!strncmp(file_hdr.signature, "CWS", 3)) { cli_dbgmsg("SWF: zlib compressed file\n"); return scancws(ctx, &file_hdr); } else if(!strncmp(file_hdr.signature, "ZWS", 3)) { cli_dbgmsg("SWF: LZMA compressed file\n"); return scanzws(ctx, &file_hdr); } else if(!strncmp(file_hdr.signature, "FWS", 3)) { cli_dbgmsg("SWF: Uncompressed file\n"); } else { cli_dbgmsg("SWF: Not a SWF file\n"); return CL_CLEAN; } cli_dbgmsg("SWF: Version: %u\n", file_hdr.version); cli_dbgmsg("SWF: File size: %u\n", EC32(file_hdr.filesize)); INITBITS; GETBITS(nbits, 5); cli_dbgmsg("SWF: FrameSize RECT size bits: %u\n", nbits); { uint32_t xMin = 0, xMax = 0, yMin = 0, yMax = 0; GETBITS(xMin, nbits); /* Should be zero */ GETBITS(xMax, nbits); GETBITS(yMin, nbits); /* Should be zero */ GETBITS(yMax, nbits); cli_dbgmsg("SWF: FrameSize xMin %u xMax %u yMin %u yMax %u\n", xMin, xMax, yMin, yMax); } GETWORD(foo); GETWORD(val); cli_dbgmsg("SWF: Frames total: %d\n", val); /* Skip Flash tag walk unless debug mode */ if(!cli_debug_flag) { return CL_CLEAN; } while(offset < map->len) { GETWORD(tag_hdr); tag_type = tag_hdr >> 6; if(tag_type == 0) break; tag_len = tag_hdr & 0x3f; if(tag_len == 0x3f) GETDWORD(tag_len); pt = tagname(tag_type); cli_dbgmsg("SWF: %s\n", pt ? pt : "UNKNOWN TAG"); cli_dbgmsg("SWF: Tag length: %u\n", tag_len); if (tag_len > map->len) { cli_dbgmsg("SWF: Invalid tag length.\n"); return CL_EFORMAT; } if ((offset + tag_len) < offset) { cli_warnmsg("SWF: Tag length too large.\n"); break; } if(!pt) { offset += tag_len; continue; } switch(tag_type) { case TAG_SCRIPTLIMITS: { unsigned int recursion, timeout; GETWORD(recursion); GETWORD(timeout); cli_dbgmsg("SWF: scriptLimits recursion %u timeout %u\n", recursion, timeout); break; } case TAG_FILEATTRIBUTES: GETDWORD(val); cli_dbgmsg("SWF: File attributes:\n"); if(val & SWF_ATTR_USENETWORK) cli_dbgmsg(" * Use network\n"); if(val & SWF_ATTR_RELATIVEURLS) cli_dbgmsg(" * Relative URLs\n"); if(val & SWF_ATTR_SUPPRESSCROSSDOMAINCACHE) cli_dbgmsg(" * Suppress cross domain cache\n"); if(val & SWF_ATTR_ACTIONSCRIPT3) cli_dbgmsg(" * ActionScript 3.0\n"); if(val & SWF_ATTR_HASMETADATA) cli_dbgmsg(" * Has metadata\n"); if(val & SWF_ATTR_USEDIRECTBLIT) cli_dbgmsg(" * Use hardware acceleration\n"); if(val & SWF_ATTR_USEGPU) cli_dbgmsg(" * Use GPU\n"); break; default: offset += tag_len; continue; } } return CL_CLEAN; }
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 */ }
int cli_scanmacho(cli_ctx *ctx, struct cli_exe_info *fileinfo) { struct macho_hdr hdr; struct macho_load_cmd load_cmd; struct macho_segment_cmd segment_cmd; struct macho_segment_cmd64 segment_cmd64; struct macho_section section; struct macho_section64 section64; unsigned int i, j, sect = 0, conv, m64, nsects, matcher = 0; unsigned int arch = 0, ep = 0, err; struct cli_exe_section *sections = NULL; char name[16]; fmap_t *map = *ctx->fmap; ssize_t at; if(fileinfo) matcher = 1; if(fmap_readn(map, &hdr, 0, sizeof(hdr)) != sizeof(hdr)) { cli_dbgmsg("cli_scanmacho: Can't read header\n"); return matcher ? -1 : CL_EFORMAT; } at = sizeof(hdr); if(hdr.magic == 0xfeedface) { conv = 0; m64 = 0; } else if(hdr.magic == 0xcefaedfe) { conv = 1; m64 = 0; } else if(hdr.magic == 0xfeedfacf) { conv = 0; m64 = 1; } else if(hdr.magic == 0xcffaedfe) { conv = 1; m64 = 1; } else { cli_dbgmsg("cli_scanmacho: Incorrect magic\n"); return matcher ? -1 : CL_EFORMAT; } switch(EC32(hdr.cpu_type, conv)) { case 7: if(!matcher) cli_dbgmsg("MACHO: CPU Type: Intel 32-bit\n"); arch = 1; break; case 7 | 0x1000000: if(!matcher) cli_dbgmsg("MACHO: CPU Type: Intel 64-bit\n"); break; case 12: if(!matcher) cli_dbgmsg("MACHO: CPU Type: ARM\n"); break; case 14: if(!matcher) cli_dbgmsg("MACHO: CPU Type: SPARC\n"); break; case 18: if(!matcher) cli_dbgmsg("MACHO: CPU Type: POWERPC 32-bit\n"); arch = 2; break; case 18 | 0x1000000: if(!matcher) cli_dbgmsg("MACHO: CPU Type: POWERPC 64-bit\n"); arch = 3; break; default: if(!matcher) cli_dbgmsg("MACHO: CPU Type: ** UNKNOWN ** (%u)\n", EC32(hdr.cpu_type, conv)); break; } if(!matcher) switch(EC32(hdr.filetype, conv)) { case 0x1: /* MH_OBJECT */ cli_dbgmsg("MACHO: Filetype: Relocatable object file\n"); break; case 0x2: /* MH_EXECUTE */ cli_dbgmsg("MACHO: Filetype: Executable\n"); break; case 0x3: /* MH_FVMLIB */ cli_dbgmsg("MACHO: Filetype: Fixed VM shared library file\n"); break; case 0x4: /* MH_CORE */ cli_dbgmsg("MACHO: Filetype: Core file\n"); break; case 0x5: /* MH_PRELOAD */ cli_dbgmsg("MACHO: Filetype: Preloaded executable file\n"); break; case 0x6: /* MH_DYLIB */ cli_dbgmsg("MACHO: Filetype: Dynamically bound shared library\n"); break; case 0x7: /* MH_DYLINKER */ cli_dbgmsg("MACHO: Filetype: Dynamic link editor\n"); break; case 0x8: /* MH_BUNDLE */ cli_dbgmsg("MACHO: Filetype: Dynamically bound bundle file\n"); break; case 0x9: /* MH_DYLIB_STUB */ cli_dbgmsg("MACHO: Filetype: Shared library stub for static\n"); break; default: cli_dbgmsg("MACHO: Filetype: ** UNKNOWN ** (0x%x)\n", EC32(hdr.filetype, conv)); } if(!matcher) { cli_dbgmsg("MACHO: Number of load commands: %u\n", EC32(hdr.ncmds, conv)); cli_dbgmsg("MACHO: Size of load commands: %u\n", EC32(hdr.sizeofcmds, conv)); } if(m64) at += 4; hdr.ncmds = EC32(hdr.ncmds, conv); if(!hdr.ncmds || hdr.ncmds > 1024) { cli_dbgmsg("cli_scanmacho: Invalid number of load commands (%u)\n", hdr.ncmds); RETURN_BROKEN; } for(i = 0; i < hdr.ncmds; i++) { if(fmap_readn(map, &load_cmd, at, sizeof(load_cmd)) != sizeof(load_cmd)) { cli_dbgmsg("cli_scanmacho: Can't read load command\n"); free(sections); RETURN_BROKEN; } at += sizeof(load_cmd); /* if((m64 && EC32(load_cmd.cmdsize, conv) % 8) || (!m64 && EC32(load_cmd.cmdsize, conv) % 4)) { cli_dbgmsg("cli_scanmacho: Invalid command size (%u)\n", EC32(load_cmd.cmdsize, conv)); free(sections); RETURN_BROKEN; } */ load_cmd.cmd = EC32(load_cmd.cmd, conv); if((m64 && load_cmd.cmd == 0x19) || (!m64 && load_cmd.cmd == 0x01)) { /* LC_SEGMENT */ if(m64) { if(fmap_readn(map, &segment_cmd64, at, sizeof(segment_cmd64)) != sizeof(segment_cmd64)) { cli_dbgmsg("cli_scanmacho: Can't read segment command\n"); free(sections); RETURN_BROKEN; } at += sizeof(segment_cmd64); nsects = EC32(segment_cmd64.nsects, conv); strncpy(name, segment_cmd64.segname, sizeof(name)); name[sizeof(name)-1] = '\0'; } else { if(fmap_readn(map, &segment_cmd, at, sizeof(segment_cmd)) != sizeof(segment_cmd)) { cli_dbgmsg("cli_scanmacho: Can't read segment command\n"); free(sections); RETURN_BROKEN; } at += sizeof(segment_cmd); nsects = EC32(segment_cmd.nsects, conv); strncpy(name, segment_cmd.segname, sizeof(name)); } if(!matcher) { name[sizeof(name)-1] = '\0'; cli_dbgmsg("MACHO: Segment name: %s\n", name); cli_dbgmsg("MACHO: Number of sections: %u\n", nsects); } if(nsects > 255) { cli_dbgmsg("cli_scanmacho: Invalid number of sections\n"); free(sections); RETURN_BROKEN; } if(!nsects) { if(!matcher) cli_dbgmsg("MACHO: ------------------\n"); continue; } sections = (struct cli_exe_section *) cli_realloc2(sections, (sect + nsects) * sizeof(struct cli_exe_section)); if(!sections) { cli_errmsg("cli_scanmacho: Can't allocate memory for 'sections'\n"); return matcher ? -1 : CL_EMEM; } for(j = 0; j < nsects; j++) { if(m64) { if(fmap_readn(map, §ion64, at, sizeof(section64)) != sizeof(section64)) { cli_dbgmsg("cli_scanmacho: Can't read section\n"); free(sections); RETURN_BROKEN; } at += sizeof(section64); sections[sect].rva = EC64(section64.addr, conv); sections[sect].vsz = EC64(section64.size, conv); sections[sect].raw = EC32(section64.offset, conv); section64.align = 1 << EC32(section64.align, conv); sections[sect].rsz = sections[sect].vsz + (section64.align - (sections[sect].vsz % section64.align)) % section64.align; /* most likely we can assume it's the same as .vsz */ strncpy(name, section64.sectname, sizeof(name)); } else { if(fmap_readn(map, §ion, at, sizeof(section)) != sizeof(section)) { cli_dbgmsg("cli_scanmacho: Can't read section\n"); free(sections); RETURN_BROKEN; } at += sizeof(section); sections[sect].rva = EC32(section.addr, conv); sections[sect].vsz = EC32(section.size, conv); sections[sect].raw = EC32(section.offset, conv); section.align = 1 << EC32(section.align, conv); sections[sect].rsz = sections[sect].vsz + (section.align - (sections[sect].vsz % section.align)) % section.align; strncpy(name, section.sectname, sizeof(name)); } if(!matcher) { name[sizeof(name)-1] = '\0'; cli_dbgmsg("MACHO: --- Section %u ---\n", sect); cli_dbgmsg("MACHO: Name: %s\n", name); cli_dbgmsg("MACHO: Virtual address: 0x%x\n", (unsigned int) sections[sect].rva); cli_dbgmsg("MACHO: Virtual size: %u\n", (unsigned int) sections[sect].vsz); cli_dbgmsg("MACHO: Raw size: %u\n", (unsigned int) sections[sect].rsz); if(sections[sect].raw) cli_dbgmsg("MACHO: File offset: %u\n", (unsigned int) sections[sect].raw); } sect++; } if(!matcher) cli_dbgmsg("MACHO: ------------------\n"); } else if(arch && (load_cmd.cmd == 0x4 || load_cmd.cmd == 0x5)) { /* LC_(UNIX)THREAD */ at += 8; switch(arch) { case 1: /* x86 */ { struct macho_thread_state_x86 thread_state_x86; if(fmap_readn(map, &thread_state_x86, at, sizeof(thread_state_x86)) != sizeof(thread_state_x86)) { cli_dbgmsg("cli_scanmacho: Can't read thread_state_x86\n"); free(sections); RETURN_BROKEN; } at += sizeof(thread_state_x86); break; } case 2: /* PPC */ { struct macho_thread_state_ppc thread_state_ppc; if(fmap_readn(map, &thread_state_ppc, at, sizeof(thread_state_ppc)) != sizeof(thread_state_ppc)) { cli_dbgmsg("cli_scanmacho: Can't read thread_state_ppc\n"); free(sections); RETURN_BROKEN; } at += sizeof(thread_state_ppc); ep = EC32(thread_state_ppc.srr0, conv); break; } case 3: /* PPC64 */ { struct macho_thread_state_ppc64 thread_state_ppc64; if(fmap_readn(map, &thread_state_ppc64, at, sizeof(thread_state_ppc64)) != sizeof(thread_state_ppc64)) { cli_dbgmsg("cli_scanmacho: Can't read thread_state_ppc64\n"); free(sections); RETURN_BROKEN; } at += sizeof(thread_state_ppc64); ep = EC64(thread_state_ppc64.srr0, conv); break; } default: cli_errmsg("cli_scanmacho: Invalid arch setting!\n"); free(sections); return matcher ? -1 : CL_EARG; } } else { if(EC32(load_cmd.cmdsize, conv) > sizeof(load_cmd)) at += EC32(load_cmd.cmdsize, conv) - sizeof(load_cmd); } } if(ep) { if(!matcher) cli_dbgmsg("Entry Point: 0x%x\n", ep); if(sections) { ep = cli_rawaddr(ep, sections, sect, &err); if(err) { cli_dbgmsg("cli_scanmacho: Can't calculate EP offset\n"); free(sections); return matcher ? -1 : CL_EFORMAT; } if(!matcher) cli_dbgmsg("Entry Point file offset: %u\n", ep); } } if(matcher) { fileinfo->ep = ep; fileinfo->nsections = sect; fileinfo->section = sections; return 0; } else { free(sections); return CL_SUCCESS; } }
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; } }
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; } } } } }