Пример #1
0
Файл: cab.c Проект: OPSF/uClinux
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;
}
Пример #2
0
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;
}
Пример #3
0
Файл: yc.c Проект: OPSF/uClinux
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;
}
Пример #4
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;
}
Пример #5
0
int cli_rebuildpe(char *buffer, struct cli_exe_section *sections, int sects, uint32_t base, uint32_t ep, uint32_t ResRva, uint32_t ResSize, int file)
{
  uint32_t datasize=0, rawbase=PESALIGN(0x148+0x80+0x28*sects, 0x200);
  char *pefile=NULL, *curpe;
  struct IMAGE_PE_HEADER *fakepe;
  int i, gotghost=(sections[0].rva > PESALIGN(rawbase, 0x1000));

  if (gotghost) rawbase=PESALIGN(0x148+0x80+0x28*(sects+1), 0x200);

  if(sects+gotghost > 96)
    return 0;

  for (i=0; i < sects; i++)
    datasize+=PESALIGN(sections[i].rsz, 0x200);

  if(datasize > CLI_MAX_ALLOCATION)
    return 0;

  if((pefile = (char *) cli_calloc(rawbase+datasize, 1))) {
    memcpy(pefile, HEADERS, 0x148);

    datasize = PESALIGN(rawbase, 0x1000);

    fakepe = (struct IMAGE_PE_HEADER *)(pefile+0xd0);
    fakepe->NumberOfSections = EC16(sects+gotghost);
    fakepe->AddressOfEntryPoint = EC32(ep);
    fakepe->ImageBase = EC32(base);
    fakepe->SizeOfHeaders = EC32(rawbase);
    memset(pefile+0x148, 0, 0x80);
    cli_writeint32(pefile+0x148+0x10, ResRva);
    cli_writeint32(pefile+0x148+0x14, ResSize);
    curpe = pefile+0x148+0x80;

    if (gotghost) {
      snprintf(curpe, 8, "empty");
      cli_writeint32(curpe+8, sections[0].rva-datasize); /* vsize */
      cli_writeint32(curpe+12, datasize); /* rva */
      cli_writeint32(curpe+0x24, 0xffffffff);
      curpe+=40;
      datasize+=PESALIGN(sections[0].rva-datasize, 0x1000);
    }

    for (i=0; i < sects; i++) {
      snprintf(curpe, 8, ".clam%.2d", i+1);
      cli_writeint32(curpe+8, sections[i].vsz);
      cli_writeint32(curpe+12, sections[i].rva);
      cli_writeint32(curpe+16, sections[i].rsz);
      cli_writeint32(curpe+20, rawbase);
      /* already zeroed
      cli_writeint32(curpe+24, 0);
      cli_writeint32(curpe+28, 0);
      cli_writeint32(curpe+32, 0);
      */
      cli_writeint32(curpe+0x24, 0xffffffff);
      memcpy(pefile+rawbase, buffer+sections[i].raw, sections[i].rsz);
      rawbase+=PESALIGN(sections[i].rsz, 0x200);
      curpe+=40;
      datasize+=PESALIGN(sections[i].vsz, 0x1000);
    }
    fakepe->SizeOfImage = EC32(datasize);
  } else {
    return 0;
  }

  i = (cli_writen(file, pefile, rawbase)!=-1);
  free(pefile);
  return i;
}
Пример #6
0
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;
}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
0
Файл: cab.c Проект: OPSF/uClinux
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;
}
Пример #10
0
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;
}