static int cab_read_block(int fd, struct cab_state *state, uint16_t resdata) { struct cab_block_hdr block_hdr; if(cli_readn(fd, &block_hdr, sizeof(block_hdr)) != sizeof(block_hdr)) { cli_dbgmsg("cab_read_block: Can't read block header\n"); return CL_EFORMAT; /* most likely a corrupted file */ } if(resdata && lseek(fd, (off_t) resdata, SEEK_CUR) == -1) { cli_dbgmsg("cab_read_block: lseek failed\n"); return CL_EFORMAT; /* most likely a corrupted file */ } state->blklen = EC16(block_hdr.cbData); state->outlen = EC16(block_hdr.cbUncomp); if(cli_readn(fd, state->block, state->blklen) != state->blklen) { cli_dbgmsg("cab_read_block: Can't read block data\n"); return CL_EFORMAT; /* most likely a corrupted file */ } state->pt = state->end = state->block; state->end += state->blklen; return CL_SUCCESS; }
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; }
int yc_decrypt(char *fbuf, unsigned int filesize, struct cli_exe_section *sections, unsigned int sectcount, uint32_t peoffset, int desc) { uint32_t ycsect = sections[sectcount].raw; unsigned int i; struct pe_image_file_hdr *pe = (struct pe_image_file_hdr*) (fbuf + peoffset); char *sname = (char *)pe + EC16(pe->SizeOfOptionalHeader) + 0x18; /* First layer (decryptor of the section decryptor) in last section Start offset for analyze: Start of yC Section + 0x93 End offset for analyze: Start of yC Section + 0xC3 Lenght to decrypt - ECX = 0xB97 */ cli_dbgmsg("yC: decrypting decryptor on sect %d\n", sectcount); if (yc_poly_emulator(fbuf + ycsect + 0x93, fbuf + ycsect + 0xc6 ,0xB97)) return 1; filesize-=sections[sectcount].ursz; /* Second layer (decryptor of the sections) in last section Start offset for analyze: Start of yC Section + 0x457 End offset for analyze: Start of yC Section + 0x487 Lenght to decrypt - ECX = Raw Size of Section */ /* Loop through all sections and decrypt them... */ for(i=0;i<sectcount;i++) { uint32_t name = (uint32_t) cli_readint32(sname+i*0x28); if ( !sections[i].raw || !sections[i].rsz || name == 0x63727372 || /* rsrc */ name == 0x7273722E || /* .rsr */ name == 0x6F6C6572 || /* relo */ name == 0x6C65722E || /* .rel */ name == 0x6164652E || /* .eda */ name == 0x6164722E || /* .rda */ name == 0x6164692E || /* .ida */ name == 0x736C742E || /* .tls */ (name&0xffff) == 0x4379 /* yC */ ) continue; cli_dbgmsg("yC: decrypting sect%d\n",i); if (yc_poly_emulator(fbuf + ycsect + 0x457, fbuf + sections[i].raw, sections[i].ursz)) return 1; } /* Remove yC section */ pe->NumberOfSections=EC16(sectcount); /* Remove IMPORT_DIRECTORY information */ memset((char *)pe + sizeof(struct pe_image_file_hdr) + 0x68, 0, 8); /* OEP resolving */ /* OEP = DWORD PTR [ Start of yC section+ A0F] */ cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 16, cli_readint32(fbuf + ycsect + 0xa0f)); /* Fix SizeOfImage */ cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38, cli_readint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38) - sections[sectcount].vsz); if (cli_writen(desc, fbuf, filesize)==-1) { cli_dbgmsg("yC: Cannot write unpacked file\n"); return 1; } return 0; }
/* 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; }
int cli_rebuildpe(char *buffer, struct cli_exe_section *sections, int sects, uint32_t base, uint32_t ep, uint32_t ResRva, uint32_t ResSize, int file) { uint32_t datasize=0, rawbase=PESALIGN(0x148+0x80+0x28*sects, 0x200); char *pefile=NULL, *curpe; struct IMAGE_PE_HEADER *fakepe; int i, gotghost=(sections[0].rva > PESALIGN(rawbase, 0x1000)); if (gotghost) rawbase=PESALIGN(0x148+0x80+0x28*(sects+1), 0x200); if(sects+gotghost > 96) return 0; for (i=0; i < sects; i++) datasize+=PESALIGN(sections[i].rsz, 0x200); if(datasize > CLI_MAX_ALLOCATION) return 0; if((pefile = (char *) cli_calloc(rawbase+datasize, 1))) { memcpy(pefile, HEADERS, 0x148); datasize = PESALIGN(rawbase, 0x1000); fakepe = (struct IMAGE_PE_HEADER *)(pefile+0xd0); fakepe->NumberOfSections = EC16(sects+gotghost); fakepe->AddressOfEntryPoint = EC32(ep); fakepe->ImageBase = EC32(base); fakepe->SizeOfHeaders = EC32(rawbase); memset(pefile+0x148, 0, 0x80); cli_writeint32(pefile+0x148+0x10, ResRva); cli_writeint32(pefile+0x148+0x14, ResSize); curpe = pefile+0x148+0x80; if (gotghost) { snprintf(curpe, 8, "empty"); cli_writeint32(curpe+8, sections[0].rva-datasize); /* vsize */ cli_writeint32(curpe+12, datasize); /* rva */ cli_writeint32(curpe+0x24, 0xffffffff); curpe+=40; datasize+=PESALIGN(sections[0].rva-datasize, 0x1000); } for (i=0; i < sects; i++) { snprintf(curpe, 8, ".clam%.2d", i+1); cli_writeint32(curpe+8, sections[i].vsz); cli_writeint32(curpe+12, sections[i].rva); cli_writeint32(curpe+16, sections[i].rsz); cli_writeint32(curpe+20, rawbase); /* already zeroed cli_writeint32(curpe+24, 0); cli_writeint32(curpe+28, 0); cli_writeint32(curpe+32, 0); */ cli_writeint32(curpe+0x24, 0xffffffff); memcpy(pefile+rawbase, buffer+sections[i].raw, sections[i].rsz); rawbase+=PESALIGN(sections[i].rsz, 0x200); curpe+=40; datasize+=PESALIGN(sections[i].vsz, 0x1000); } fakepe->SizeOfImage = EC32(datasize); } else { return 0; } i = (cli_writen(file, pefile, rawbase)!=-1); free(pefile); return i; }
int cli_scancpio_old(int fd, cli_ctx *ctx) { struct cpio_hdr_old hdr_old; char name[513]; unsigned int file = 0, trailer = 0; uint32_t filesize, namesize, hdr_namesize; int ret, conv; off_t pos; while(read(fd, &hdr_old, sizeof(hdr_old)) == sizeof(hdr_old)) { if(!hdr_old.magic && trailer) return CL_SUCCESS; if(hdr_old.magic == 070707) { conv = 0; } else if(hdr_old.magic == 0143561) { conv = 1; } else { cli_dbgmsg("cli_scancpio_old: Invalid magic number\n"); return CL_EFORMAT; } cli_dbgmsg("CPIO: -- File %u --\n", ++file); if(hdr_old.namesize) { hdr_namesize = EC16(hdr_old.namesize, conv); namesize = MIN(sizeof(name), hdr_namesize); if(read(fd, name, namesize) != namesize) { cli_dbgmsg("cli_scancpio_old: Can't read file name\n"); return CL_EFORMAT; } name[namesize - 1] = 0; sanitname(name); cli_dbgmsg("CPIO: Name: %s\n", name); if(!strcmp(name, "TRAILER!!!")) trailer = 1; if(namesize < hdr_namesize) { if(hdr_namesize % 2) hdr_namesize++; lseek(fd, hdr_namesize - namesize, SEEK_CUR); } else if(hdr_namesize % 2) lseek(fd, 1, SEEK_CUR); } filesize = (uint32_t) (EC16(hdr_old.filesize[0], conv) << 16 | EC16(hdr_old.filesize[1], conv)); cli_dbgmsg("CPIO: Filesize: %u\n", filesize); if(!filesize) continue; if(cli_matchmeta(ctx, name, filesize, filesize, 0, file, 0, NULL) == CL_VIRUS) return CL_VIRUS; pos = lseek(fd, 0, SEEK_CUR); if((EC16(hdr_old.mode, conv) & 0170000) != 0100000) { cli_dbgmsg("CPIO: Not a regular file, skipping\n"); } else { ret = cli_checklimits("cli_scancpio_old", ctx, filesize, 0, 0); if(ret == CL_EMAXFILES) { return ret; } else if(ret == CL_SUCCESS) { ret = cli_dumpscan(fd, 0, filesize, ctx); if(ret == CL_VIRUS) return ret; } } if(filesize % 2) filesize++; lseek(fd, pos + filesize, SEEK_SET); } return CL_CLEAN; }
int yc_decrypt(cli_ctx *ctx, char *fbuf, unsigned int filesize, struct cli_exe_section *sections, unsigned int sectcount, uint32_t peoffset, int desc, uint32_t ecx,int16_t offset) { uint32_t ycsect = sections[sectcount].raw+offset; unsigned int i; struct pe_image_file_hdr *pe = (struct pe_image_file_hdr*) (fbuf + peoffset); char *sname = (char *)pe + EC16(pe->SizeOfOptionalHeader) + 0x18; uint32_t max_emu; unsigned int ofilesize = filesize; /* First layer (decryptor of the section decryptor) in last section Start offset for analyze: Start of yC Section + 0x93 End offset for analyze: Start of yC Section + 0xC3 Length to decrypt - ECX = 0xB97 */ cli_dbgmsg("yC: offset: %x, length: %x\n", offset, ecx); cli_dbgmsg("yC: decrypting decryptor on sect %d\n", sectcount); switch (yc_poly_emulator(ctx, fbuf, filesize, fbuf + ycsect + 0x93, fbuf + ycsect + 0xc6, ecx, ecx)) { case 2: return CL_VIRUS; case 1: return CL_EUNPACK; } filesize-=sections[sectcount].ursz; /* Second layer (decryptor of the sections) in last section Start offset for analyze: Start of yC Section + 0x457 End offset for analyze: Start of yC Section + 0x487 Length to decrypt - ECX = Raw Size of Section */ /* Loop through all sections and decrypt them... */ for(i=0;i<sectcount;i++) { uint32_t name = (uint32_t) cli_readint32(sname+i*0x28); if (!sections[i].raw || !sections[i].rsz || name == 0x63727372 || /* rsrc */ name == 0x7273722E || /* .rsr */ name == 0x6F6C6572 || /* relo */ name == 0x6C65722E || /* .rel */ name == 0x6164652E || /* .eda */ name == 0x6164722E || /* .rda */ name == 0x6164692E || /* .ida */ name == 0x736C742E || /* .tls */ (name&0xffff) == 0x4379 /* yC */ ) continue; cli_dbgmsg("yC: decrypting sect%d\n",i); max_emu = filesize - sections[i].raw; if (max_emu > filesize) { cli_dbgmsg("yC: bad emulation length limit %u\n", max_emu); return 1; } switch (yc_poly_emulator(ctx, fbuf, ofilesize, fbuf + ycsect + (offset == -0x18 ? 0x3ea : 0x457), fbuf + sections[i].raw, sections[i].ursz, max_emu)) { case 2: return CL_VIRUS; case 1: return CL_EUNPACK; } } /* Remove yC section */ pe->NumberOfSections=EC16(sectcount); /* Remove IMPORT_DIRECTORY information */ memset((char *)pe + sizeof(struct pe_image_file_hdr) + 0x68, 0, 8); /* OEP resolving */ /* OEP = DWORD PTR [ Start of yC section+ A0F] */ cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 16, cli_readint32(fbuf + ycsect + 0xa0f)); /* Fix SizeOfImage */ cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38, cli_readint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38) - sections[sectcount].vsz); if (cli_writen(desc, fbuf, filesize)==-1) { cli_dbgmsg("yC: Cannot write unpacked file\n"); return CL_EUNPACK; } return CL_SUCCESS; }
int cli_scancpio_old(cli_ctx *ctx) { struct cpio_hdr_old hdr_old; char name[513]; unsigned int file = 0, trailer = 0; uint32_t filesize, namesize, hdr_namesize; int ret = CL_CLEAN, conv; off_t pos = 0; int virus_found = 0; while(fmap_readn(*ctx->fmap, &hdr_old, pos, sizeof(hdr_old)) == sizeof(hdr_old)) { pos += sizeof(hdr_old); if(!hdr_old.magic && trailer) { ret = CL_SUCCESS; goto leave; } if(hdr_old.magic == 070707) { conv = 0; } else if(hdr_old.magic == 0143561) { conv = 1; } else { cli_dbgmsg("cli_scancpio_old: Invalid magic number\n"); ret = CL_EFORMAT; goto leave; } cli_dbgmsg("CPIO: -- File %u --\n", ++file); if(hdr_old.namesize) { hdr_namesize = EC16(hdr_old.namesize, conv); namesize = MIN(sizeof(name), hdr_namesize); if ((uint32_t)fmap_readn(*ctx->fmap, &name, pos, namesize) != namesize) { cli_dbgmsg("cli_scancpio_old: Can't read file name\n"); return CL_EFORMAT; } pos += namesize; name[namesize - 1] = 0; sanitname(name); cli_dbgmsg("CPIO: Name: %s\n", name); if(!strcmp(name, "TRAILER!!!")) trailer = 1; if(namesize < hdr_namesize) { if(hdr_namesize % 2) hdr_namesize++; pos += hdr_namesize - namesize; } else if(hdr_namesize % 2) pos++; } filesize = (uint32_t) (EC16(hdr_old.filesize[0], conv) << 16 | EC16(hdr_old.filesize[1], conv)); cli_dbgmsg("CPIO: Filesize: %u\n", filesize); if(!filesize) continue; if(cli_matchmeta(ctx, name, filesize, filesize, 0, file, 0, NULL) == CL_VIRUS) { if (!SCAN_ALL) return CL_VIRUS; virus_found = 1; } if((EC16(hdr_old.mode, conv) & 0170000) != 0100000) { cli_dbgmsg("CPIO: Not a regular file, skipping\n"); } else { ret = cli_checklimits("cli_scancpio_old", ctx, filesize, 0, 0); if(ret == CL_EMAXFILES) { goto leave; } else if(ret == CL_SUCCESS) { ret = cli_map_scan(*ctx->fmap, pos, filesize, ctx, CL_TYPE_ANY); if(ret == CL_VIRUS) { if (!SCAN_ALL) return ret; virus_found = 1; } } } if(filesize % 2) filesize++; pos += filesize; } leave: if (virus_found != 0) return CL_VIRUS; return ret; }
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_parsegif(cli_ctx *ctx) { fmap_t *map = *ctx->fmap; unsigned char magic[6], v; unsigned int offset = 0, have_gce = 0; struct gif_screen_desc screen_desc; struct gif_graphic_control_ext graphic_control_ext; struct gif_image_desc image_desc; cli_dbgmsg("in cli_parsegif()\n"); if(fmap_readn(map, magic, offset, 6) != 6) return CL_SUCCESS; /* Ignore */ if(!memcmp(magic, "GIF87a", 6) || !memcmp(magic, "GIF89a", 6)) offset = 6; else return CL_SUCCESS; /* Not a GIF file */ if(fmap_readn(map, &screen_desc, offset, sizeof(screen_desc)) != sizeof(screen_desc)) { cli_warnmsg("cli_parsegif: Can't read Logical Screen Descriptor block\n"); return CL_EPARSE; } offset += 7; cli_dbgmsg("GIF: Screen size %ux%u, gctsize: %u\n", EC16(screen_desc.width), EC16(screen_desc.height), screen_desc.flags & 0x7); if(screen_desc.flags & 0x80) offset += 3 * (1 << ((screen_desc.flags & 0x7) + 1)); while(1) { GETBYTE(v); if(v == 0x21) { GETBYTE(v); if(v == 0xf9) { if(fmap_readn(map, &graphic_control_ext, offset, sizeof(graphic_control_ext)) != sizeof(graphic_control_ext)) { cli_warnmsg("cli_parsegif: Can't read Graphic Control Extension block\n"); return CL_EPARSE; } if(have_gce) { cli_warnmsg("cli_parsegif: Multiple Graphic Control Extension blocks not allowed\n"); return CL_EPARSE; } have_gce = 1; offset += sizeof(graphic_control_ext); if(graphic_control_ext.blksize != 4 || graphic_control_ext.blkterm) { cli_warnmsg("cli_parsegif: Invalid Graphic Control Extension block\n"); return CL_EPARSE; } } else { while(1) { GETBYTE(v); if(!v) break; offset += v; } } } else if(v == 0x2c) { if(fmap_readn(map, &image_desc, offset, sizeof(image_desc)) != sizeof(image_desc)) { cli_warnmsg("cli_parsegif: Can't read Image Descriptor block\n"); return CL_EPARSE; } offset += 9; cli_dbgmsg("GIF: Image size %ux%u, left pos: %u, top pos: %u\n", EC16(image_desc.width), EC16(image_desc.height), EC16(image_desc.leftpos), EC16(image_desc.toppos)); break; } } return CL_SUCCESS; }