mirror of
https://github.com/Cisco-Talos/clamav.git
synced 2025-10-19 10:23:17 +00:00
improve handling of PDF, CAB, RTF, OLE2 and HTML files (sync with branch/0.93)
git-svn: trunk@3862
This commit is contained in:
parent
cb4e478c1a
commit
72ce4b70eb
34 changed files with 917 additions and 672 deletions
|
@ -1,3 +1,8 @@
|
|||
Tue May 27 17:39:06 CEST 2008
|
||||
-----------------------------
|
||||
* improve handling of PDF, CAB, RTF, OLE2 and HTML files (sync with
|
||||
branch/0.93)
|
||||
|
||||
Sat May 24 21:38:47 EEST 2008 (edwin)
|
||||
-------------------------------------
|
||||
* clamd/others.c, session.c, m4/fdpassing.m4:
|
||||
|
|
|
@ -1167,6 +1167,7 @@ main(int argc, char **argv)
|
|||
|
||||
memset(&ifr, '\0', sizeof(struct ifreq));
|
||||
strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1);
|
||||
ifr.ifr_name[sizeof(ifr.ifr_name)-1]='\0';
|
||||
if(setsockopt(broadcastSock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) {
|
||||
perror(iface);
|
||||
return EX_CONFIG;
|
||||
|
@ -1515,6 +1516,7 @@ main(int argc, char **argv)
|
|||
memset((char *)&sockun, 0, sizeof(struct sockaddr_un));
|
||||
sockun.sun_family = AF_UNIX;
|
||||
strncpy(sockun.sun_path, localSocket, sizeof(sockun.sun_path));
|
||||
sockun.sun_path[sizeof(sockun.sun_path)-1]='\0';
|
||||
|
||||
sessions = (struct session *)cli_malloc(sizeof(struct session));
|
||||
if((sessions[0].sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
|
@ -2197,6 +2199,7 @@ pingServer(int serverNumber)
|
|||
memset((char *)&server, 0, sizeof(struct sockaddr_un));
|
||||
server.sun_family = AF_UNIX;
|
||||
strncpy(server.sun_path, localSocket, sizeof(server.sun_path));
|
||||
server.sun_path[sizeof(server.sun_path)-1]='\0';
|
||||
|
||||
if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
perror(localSocket);
|
||||
|
@ -2749,6 +2752,7 @@ clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
|
|||
}
|
||||
#else
|
||||
strncpy(ip, (char *)inet_ntoa(*(struct in_addr *)hostent.h_addr), sizeof(ip));
|
||||
ip[sizeof(ip)-1]='\0';
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -3409,6 +3413,7 @@ clamfi_eom(SMFICTX *ctx)
|
|||
memset((char *)&server, 0, sizeof(struct sockaddr_un));
|
||||
server.sun_family = AF_UNIX;
|
||||
strncpy(server.sun_path, localSocket, sizeof(server.sun_path));
|
||||
server.sun_path[sizeof(server.sun_path)-1]='\0';
|
||||
|
||||
if(connect(privdata->cmdSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) < 0) {
|
||||
perror(localSocket);
|
||||
|
@ -3530,19 +3535,20 @@ clamfi_eom(SMFICTX *ctx)
|
|||
const char *j = smfi_getsymval(ctx, "{j}");
|
||||
|
||||
if(j)
|
||||
strncpy(hostname, j,
|
||||
sizeof(hostname) - 1);
|
||||
strncpy(hostname, j, sizeof(hostname) - 1);
|
||||
else
|
||||
strcpy(hostname, _("Error determining host"));
|
||||
hostname[sizeof(hostname)-1]='\0';
|
||||
} else if(strchr(hostname, '.') == NULL) {
|
||||
/*
|
||||
* Determine fully qualified name
|
||||
*/
|
||||
struct hostent hostent;
|
||||
|
||||
if((r_gethostbyname(hostname, &hostent, buf, sizeof(buf)) == 0) &&
|
||||
hostent.h_name)
|
||||
if((r_gethostbyname(hostname, &hostent, buf, sizeof(buf)) == 0) && hostent.h_name) {
|
||||
strncpy(hostname, hostent.h_name, sizeof(hostname));
|
||||
hostname[sizeof(hostname)-1]='\0';
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SESSION
|
||||
|
@ -4557,6 +4563,7 @@ connect2clamd(struct privdata *privdata)
|
|||
memset((char *)&server, 0, sizeof(struct sockaddr_un));
|
||||
server.sun_family = AF_UNIX;
|
||||
strncpy(server.sun_path, localSocket, sizeof(server.sun_path));
|
||||
server.sun_path[sizeof(server.sun_path)-1]='\0';
|
||||
|
||||
if((privdata->cmdSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
perror("socket");
|
||||
|
@ -6405,6 +6412,7 @@ spf(struct privdata *privdata, table_t *prevhosts)
|
|||
continue;
|
||||
}
|
||||
strncpy(txt, (const char *)&p[1], sizeof(txt) - 1);
|
||||
txt[sizeof(txt)-1]='\0';
|
||||
txt[len - 1] = '\0';
|
||||
if((strncmp(txt, "v=spf1 ", 7) == 0) || (strncmp(txt, "spf2.0/pra ", 11) == 0)) {
|
||||
int j;
|
||||
|
|
|
@ -173,11 +173,13 @@ int dazukoRegister_TS(dazuko_id_t **dazuko_id, const char *groupName, const char
|
|||
if (strcasecmp(mode, "r") == 0)
|
||||
{
|
||||
strncpy(regMode, "R", sizeof(regMode));
|
||||
regMode[sizeof(regMode)-1]='\0';
|
||||
write_mode = 0;
|
||||
}
|
||||
else if (strcasecmp(mode, "r+") == 0 || strcasecmp(mode, "rw") == 0)
|
||||
{
|
||||
strncpy(regMode, "RW", sizeof(regMode));
|
||||
regMode[sizeof(regMode)-1]='\0';
|
||||
write_mode = 1;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -116,6 +116,7 @@ int dazukoRegister_TS_compat12(struct dazuko_id *dazuko, const char *groupName)
|
|||
|
||||
opt->command = REGISTER;
|
||||
strncpy(opt->buffer, groupName, sizeof(opt->buffer) - 1);
|
||||
opt->buffer[sizeof(opt->buffer)-1]='\0';
|
||||
opt->buffer_length = strlen(opt->buffer) + 1;
|
||||
|
||||
if (ioctl(dazuko->device, _IOW(dazuko->dev_major, IOCTL_SET_OPTION, void *), opt) != 0)
|
||||
|
@ -186,6 +187,7 @@ int dazuko_set_path_compat12(struct dazuko_id *dazuko, const char *path, int com
|
|||
|
||||
opt->command = command;
|
||||
strncpy(opt->buffer, path, sizeof(opt->buffer) - 1);
|
||||
opt->buffer[sizeof(opt->buffer)-1]='\0';
|
||||
opt->buffer_length = strlen(opt->buffer) + 1;
|
||||
|
||||
if (ioctl(dazuko->device, _IOW(dazuko->dev_major, IOCTL_SET_OPTION, void *), opt) != 0)
|
||||
|
|
|
@ -64,6 +64,7 @@ int localserver(const struct cfgstruct *copt)
|
|||
memset((char *) &server, 0, sizeof(server));
|
||||
server.sun_family = AF_UNIX;
|
||||
strncpy(server.sun_path, cfgopt(copt, "LocalSocket")->strarg, sizeof(server.sun_path));
|
||||
server.sun_path[sizeof(server.sun_path)-1]='\0';
|
||||
|
||||
if((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
||||
estr = strerror(errno);
|
||||
|
|
|
@ -376,6 +376,8 @@ int readsock(int sockfd, char *buf, size_t size, unsigned char delim, int timeou
|
|||
break;
|
||||
} else {
|
||||
n = recv(sockfd, buf+boff, n, 0);
|
||||
if(n < 0)
|
||||
return -1;
|
||||
if((boff+n) == size)
|
||||
break;
|
||||
boff += n;
|
||||
|
|
|
@ -284,6 +284,7 @@ static int dconnect(const struct optstruct *opt)
|
|||
|
||||
server.sun_family = AF_UNIX;
|
||||
strncpy(server.sun_path, cpt->strarg, sizeof(server.sun_path));
|
||||
server.sun_path[sizeof(server.sun_path)-1]='\0';
|
||||
|
||||
if((sockd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
perror("socket()");
|
||||
|
|
|
@ -226,6 +226,7 @@ int scanmanager(const struct optstruct *opt)
|
|||
if(tolower(ptr[strlen(ptr) - 1]) == 'm') {
|
||||
cpy = calloc(strlen(ptr), 1);
|
||||
strncpy(cpy, ptr, strlen(ptr) - 1);
|
||||
cpy[strlen(ptr)-1]='\0';
|
||||
limits.maxscansize = atoi(cpy) * 1024 * 1024;
|
||||
free(cpy);
|
||||
} else
|
||||
|
@ -239,6 +240,7 @@ int scanmanager(const struct optstruct *opt)
|
|||
if(tolower(ptr[strlen(ptr) - 1]) == 'm') {
|
||||
cpy = calloc(strlen(ptr), 1);
|
||||
strncpy(cpy, ptr, strlen(ptr) - 1);
|
||||
cpy[strlen(ptr)-1]='\0';
|
||||
limits.maxfilesize = atoi(cpy) * 1024 * 1024;
|
||||
free(cpy);
|
||||
} else
|
||||
|
@ -467,6 +469,7 @@ static int clamav_unpack(const char *prog, const char **args, const char *tmpdir
|
|||
if(tolower(ptr[strlen(ptr) - 1]) == 'm') { /* megabytes */
|
||||
cpy = calloc(strlen(ptr), 1);
|
||||
strncpy(cpy, ptr, strlen(ptr) - 1);
|
||||
cpy[strlen(ptr)-1]='\0';
|
||||
maxscansize = atoi(cpy) * 1024;
|
||||
free(cpy);
|
||||
} else /* default - kilobytes */
|
||||
|
|
|
@ -150,14 +150,17 @@ int match_regex(const char *filename, const char *pattern)
|
|||
#else
|
||||
if(pattern[strlen(pattern) - 1] == '\\') {
|
||||
strncpy(fname, filename, 510);
|
||||
fname[509]='\0';
|
||||
len = strlen(fname);
|
||||
if(fname[len - 1] != '\\') {
|
||||
fname[len] = '\\';
|
||||
fname[len + 1] = 0;
|
||||
}
|
||||
#endif
|
||||
} else
|
||||
} else {
|
||||
strncpy(fname, filename, 513);
|
||||
fname[512]='\0';
|
||||
}
|
||||
|
||||
match = (cli_regexec(®, fname, 0, NULL, 0) == REG_NOMATCH) ? 0 : 1;
|
||||
cli_regfree(®);
|
||||
|
|
|
@ -73,6 +73,7 @@ int notify(const char *cfgfile)
|
|||
socktype = "UNIX";
|
||||
server.sun_family = AF_UNIX;
|
||||
strncpy(server.sun_path, cpt->strarg, sizeof(server.sun_path));
|
||||
server.sun_path[sizeof(server.sun_path)-1]='\0';
|
||||
|
||||
if((sockd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
logg("^Clamd was NOT notified: Can't create socket endpoint for %s\n", cpt->strarg);
|
||||
|
|
126
libclamav/cab.c
126
libclamav/cab.c
|
@ -122,7 +122,6 @@ static char *cab_readstr(int fd, int *ret)
|
|||
}
|
||||
|
||||
if(lseek(fd, (off_t) (pos + i + 1), SEEK_SET) == -1) {
|
||||
/* *ret = CL_EIO; */
|
||||
*ret = CL_EFORMAT; /* most likely a corrupted file */
|
||||
return NULL;
|
||||
}
|
||||
|
@ -136,15 +135,17 @@ static char *cab_readstr(int fd, int *ret)
|
|||
return str;
|
||||
}
|
||||
|
||||
static int cab_chkname(const char *name)
|
||||
static int cab_chkname(char *name, int san)
|
||||
{
|
||||
size_t i, len = strlen(name);
|
||||
|
||||
|
||||
for(i = 0; i < len; i++) {
|
||||
if(strchr("%/*?|\\\"+=<>;:\t ", name[i]) || !isascii(name[i])) {
|
||||
if(!san && (strchr("%/*?|\\\"+=<>;:\t ", name[i]) || !isascii(name[i]))) {
|
||||
cli_dbgmsg("cab_chkname: File name contains disallowed characters\n");
|
||||
return 1;
|
||||
} else if(san && !isalnum(name[i])) {
|
||||
name[i] = '*';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,7 +190,7 @@ void cab_free(struct cab_archive *cab)
|
|||
|
||||
int cab_open(int fd, off_t offset, struct cab_archive *cab)
|
||||
{
|
||||
unsigned int i, bscore = 0, badname = 0;
|
||||
unsigned int i, folders = 0;
|
||||
struct cab_file *file, *lfile = NULL;
|
||||
struct cab_folder *folder, *lfolder = NULL;
|
||||
struct cab_hdr hdr;
|
||||
|
@ -210,7 +211,6 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
|
|||
|
||||
if(cli_readn(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
|
||||
cli_dbgmsg("cab_open: Can't read cabinet header\n");
|
||||
/* return CL_EIO; */
|
||||
return CL_EFORMAT; /* most likely a corrupted file */
|
||||
}
|
||||
|
||||
|
@ -232,8 +232,8 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
|
|||
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;
|
||||
bscore++;
|
||||
}
|
||||
|
||||
cab->nfolders = EC16(hdr.cFolders);
|
||||
|
@ -245,7 +245,6 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
|
|||
if(cab->nfolders > CAB_FOLDER_LIMIT) {
|
||||
cab->nfolders = CAB_FOLDER_LIMIT;
|
||||
cli_dbgmsg("CAB: *** Number of folders limited to %u ***\n", cab->nfolders);
|
||||
bscore++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,19 +257,15 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
|
|||
if(cab->nfiles > CAB_FILE_LIMIT) {
|
||||
cab->nfiles = CAB_FILE_LIMIT;
|
||||
cli_dbgmsg("CAB: *** Number of files limited to %u ***\n", cab->nfiles);
|
||||
bscore++;
|
||||
}
|
||||
}
|
||||
|
||||
cli_dbgmsg("CAB: File format version: %u.%u\n", hdr.versionMajor, hdr.versionMinor);
|
||||
if(hdr.versionMajor != 1 || hdr.versionMinor != 3)
|
||||
bscore++;
|
||||
|
||||
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_EIO; */
|
||||
return CL_EFORMAT; /* most likely a corrupted file */
|
||||
}
|
||||
|
||||
|
@ -281,7 +276,6 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
|
|||
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_EIO; */
|
||||
return CL_EFORMAT; /* most likely a corrupted file */
|
||||
}
|
||||
}
|
||||
|
@ -292,8 +286,8 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
|
|||
pt = cab_readstr(fd, &ret);
|
||||
if(ret)
|
||||
return ret;
|
||||
if(cab_chkname(pt))
|
||||
badname = 1;
|
||||
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);
|
||||
|
@ -301,8 +295,8 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
|
|||
pt = cab_readstr(fd, &ret);
|
||||
if(ret)
|
||||
return ret;
|
||||
if(cab_chkname(pt))
|
||||
badname = 1;
|
||||
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);
|
||||
|
@ -313,8 +307,8 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
|
|||
pt = cab_readstr(fd, &ret);
|
||||
if(ret)
|
||||
return ret;
|
||||
if(cab_chkname(pt))
|
||||
badname = 1;
|
||||
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);
|
||||
|
@ -322,37 +316,37 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
|
|||
pt = cab_readstr(fd, &ret);
|
||||
if(ret)
|
||||
return ret;
|
||||
if(cab_chkname(pt))
|
||||
badname = 1;
|
||||
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);
|
||||
}
|
||||
bscore += badname;
|
||||
|
||||
if(bscore >= 4) {
|
||||
cli_dbgmsg("CAB: bscore == %u, most likely a fake cabinet\n", bscore);
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
||||
/* folders */
|
||||
for(i = 0; i < cab->nfolders; i++) {
|
||||
if(cli_readn(fd, &folder_hdr, sizeof(folder_hdr)) != sizeof(folder_hdr)) {
|
||||
cli_errmsg("cab_open: Can't read header for folder %u\n", i);
|
||||
cab_free(cab);
|
||||
/* return CL_EIO; */
|
||||
return CL_EFORMAT; /* most likely a corrupted file */
|
||||
cli_dbgmsg("cab_open: Can't read header for folder %u\n", i);
|
||||
break;
|
||||
}
|
||||
|
||||
if(resfold) {
|
||||
if(lseek(fd, resfold, SEEK_CUR) == -1) {
|
||||
cli_errmsg("cab_open: Can't lseek to %u (resfold)\n", (unsigned int) resfold);
|
||||
cab_free(cab);
|
||||
/* return CL_EIO; */
|
||||
return CL_EFORMAT; /* most likely a corrupted file */
|
||||
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");
|
||||
|
@ -362,16 +356,12 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
|
|||
|
||||
folder->cab = (struct cab_archive *) cab;
|
||||
folder->offset = (off_t) EC32(folder_hdr.coffCabStart) + offset;
|
||||
if(folder->offset > rsize)
|
||||
bscore++;
|
||||
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((folder->cmethod & 0x000f) > 3)
|
||||
bscore++;
|
||||
|
||||
if(!lfolder)
|
||||
cab->folders = folder;
|
||||
|
@ -379,27 +369,20 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
|
|||
lfolder->next = folder;
|
||||
|
||||
lfolder = folder;
|
||||
|
||||
if(bscore > 10) {
|
||||
cab_free(cab);
|
||||
cli_dbgmsg("CAB: bscore == %u, most likely a fake cabinet\n", bscore);
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
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(bscore > 10) {
|
||||
cab_free(cab);
|
||||
cli_dbgmsg("CAB: bscore == %u, most likely a fake cabinet\n", bscore);
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
|
||||
if(cli_readn(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) {
|
||||
cli_errmsg("cab_open: Can't read file %u header\n", i);
|
||||
cab_free(cab);
|
||||
/* return CL_EIO; */
|
||||
return CL_EFORMAT; /* most likely a corrupted file */
|
||||
cli_dbgmsg("cab_open: Can't read file %u header\n", i);
|
||||
break;
|
||||
}
|
||||
|
||||
file = (struct cab_file *) cli_calloc(1, sizeof(struct cab_file));
|
||||
|
@ -411,17 +394,18 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
|
|||
|
||||
file->cab = cab;
|
||||
file->fd = fd;
|
||||
file->length = EC32(file_hdr.cbFile);
|
||||
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);
|
||||
cab_free(cab);
|
||||
return ret;
|
||||
continue;
|
||||
}
|
||||
cab_chkname(file->name, 1);
|
||||
|
||||
cli_dbgmsg("CAB: File record %u\n", i);
|
||||
cli_dbgmsg("CAB: File name: %s\n", file->name);
|
||||
|
@ -444,9 +428,7 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
|
|||
/* folder index */
|
||||
if(fidx < 0xfffd) {
|
||||
if(fidx > cab->nfolders) {
|
||||
if(bscore < 3)
|
||||
cli_dbgmsg("cab_open: File %s is not associated with any folder\n", file->name);
|
||||
bscore++;
|
||||
cli_dbgmsg("cab_open: File %s is not associated with any folder\n", file->name);
|
||||
free(file->name);
|
||||
free(file);
|
||||
continue;
|
||||
|
@ -457,11 +439,10 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
|
|||
file->folder = file->folder->next;
|
||||
|
||||
if(!file->folder) {
|
||||
cli_errmsg("cab_open: Folder not found for file %s\n", file->name);
|
||||
cli_dbgmsg("cab_open: Folder not found for file %s\n", file->name);
|
||||
free(file->name);
|
||||
free(file);
|
||||
cab_free(cab);
|
||||
return CL_EFORMAT;
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -490,13 +471,11 @@ static int cab_read_block(int fd, struct cab_state *state, uint16_t resdata)
|
|||
|
||||
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_EIO; */
|
||||
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_EIO; */
|
||||
return CL_EFORMAT; /* most likely a corrupted file */
|
||||
}
|
||||
|
||||
|
@ -515,7 +494,6 @@ static int cab_read_block(int fd, struct cab_state *state, uint16_t resdata)
|
|||
|
||||
if(cli_readn(fd, state->block, state->blklen) != state->blklen) {
|
||||
cli_dbgmsg("cab_read_block: Can't read block data\n");
|
||||
/* return CL_EIO; */
|
||||
return CL_EFORMAT; /* most likely a corrupted file */
|
||||
}
|
||||
|
||||
|
@ -530,6 +508,11 @@ static int cab_read(struct cab_file *file, unsigned char *buffer, int bytes)
|
|||
uint16_t todo, left;
|
||||
|
||||
|
||||
if((file->cab->state->blknum > file->folder->nblocks) && !file->lread) {
|
||||
file->error = CL_BREAK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
todo = bytes;
|
||||
while(todo > 0) {
|
||||
left = file->cab->state->end - file->cab->state->pt;
|
||||
|
@ -544,10 +527,8 @@ static int cab_read(struct cab_file *file, unsigned char *buffer, int bytes)
|
|||
todo -= left;
|
||||
|
||||
} else {
|
||||
if(file->cab->state->blknum++ >= file->folder->nblocks) {
|
||||
file->error = CL_EFORMAT;
|
||||
if(file->cab->state->blknum++ >= file->folder->nblocks)
|
||||
break;
|
||||
}
|
||||
|
||||
file->error = cab_read_block(file->fd, file->cab->state, file->cab->resdata);
|
||||
if(file->error)
|
||||
|
@ -568,7 +549,7 @@ static int cab_read(struct cab_file *file, unsigned char *buffer, int bytes)
|
|||
}
|
||||
}
|
||||
|
||||
return bytes - todo;
|
||||
return file->lread = bytes - todo;
|
||||
}
|
||||
|
||||
static int cab_unstore(struct cab_file *file, int bytes)
|
||||
|
@ -721,11 +702,14 @@ int cab_extract(struct cab_file *file, const char *name)
|
|||
break;
|
||||
|
||||
default:
|
||||
cli_warnmsg("CAB: Not supported compression method: 0x%x\n", file->folder->cmethod & 0x000f);
|
||||
cli_dbgmsg("CAB: Not supported compression method: 0x%x\n", file->folder->cmethod & 0x000f);
|
||||
ret = CL_EFORMAT;
|
||||
}
|
||||
|
||||
close(file->ofd);
|
||||
|
||||
if(ret == CL_BREAK)
|
||||
ret = CL_SUCCESS;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ struct cab_file {
|
|||
char *name;
|
||||
uint32_t length;
|
||||
int error;
|
||||
int lread;
|
||||
int fd;
|
||||
int ofd;
|
||||
struct cab_folder *folder;
|
||||
|
|
|
@ -135,7 +135,7 @@ int is_tar(unsigned char *buf, unsigned int nbytes);
|
|||
|
||||
cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
|
||||
{
|
||||
unsigned char smallbuff[MAGIC_BUFFER_SIZE + 1], *decoded, *bigbuff;
|
||||
unsigned char buff[MAGIC_BUFFER_SIZE + 1], *decoded;
|
||||
int bread, sret;
|
||||
cli_file_t ret = CL_TYPE_BINARY_DATA;
|
||||
struct cli_matcher *root;
|
||||
|
@ -147,12 +147,13 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
|
|||
return CL_TYPE_ERROR;
|
||||
}
|
||||
|
||||
memset(smallbuff, 0, sizeof(smallbuff));
|
||||
bread = cli_readn(desc, smallbuff, MAGIC_BUFFER_SIZE);
|
||||
memset(buff, 0, sizeof(buff));
|
||||
bread = cli_readn(desc, buff, MAGIC_BUFFER_SIZE);
|
||||
if(bread == -1)
|
||||
return CL_TYPE_ERROR;
|
||||
buff[bread] = 0;
|
||||
|
||||
ret = cli_filetype(smallbuff, bread, engine);
|
||||
ret = cli_filetype(buff, bread, engine);
|
||||
|
||||
if(ret >= CL_TYPE_TEXT_ASCII && ret <= CL_TYPE_BINARY_DATA) {
|
||||
/* HTML files may contain special characters and could be
|
||||
|
@ -165,7 +166,7 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
|
|||
if(cli_ac_initdata(&mdata, root->ac_partsigs, AC_DEFAULT_TRACKLEN))
|
||||
return ret;
|
||||
|
||||
sret = cli_ac_scanbuff(smallbuff, bread, NULL, engine->root[0], &mdata, 0, ret, desc, NULL, AC_SCAN_FT, NULL);
|
||||
sret = cli_ac_scanbuff(buff, bread, NULL, engine->root[0], &mdata, 0, ret, desc, NULL, AC_SCAN_FT, NULL);
|
||||
|
||||
cli_ac_freedata(&mdata);
|
||||
|
||||
|
@ -175,7 +176,7 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
|
|||
if(cli_ac_initdata(&mdata, root->ac_partsigs, AC_DEFAULT_TRACKLEN))
|
||||
return ret;
|
||||
|
||||
decoded = (unsigned char *) cli_utf16toascii((char *) smallbuff, bread);
|
||||
decoded = (unsigned char *) cli_utf16toascii((char *) buff, bread);
|
||||
if(decoded) {
|
||||
sret = cli_ac_scanbuff(decoded, strlen((char *) decoded), NULL, engine->root[0], &mdata, 0, CL_TYPE_TEXT_ASCII, desc, NULL, AC_SCAN_FT, NULL);
|
||||
free(decoded);
|
||||
|
@ -190,11 +191,11 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
|
|||
/* check if we can autodetect this encoding.
|
||||
* If we can't don't try to detect HTML sig, since
|
||||
* we just tried that above, and failed */
|
||||
if((encoding = encoding_detect_bom(smallbuff, bread))) {
|
||||
unsigned char decodedbuff[sizeof(smallbuff)*2];
|
||||
if((encoding = encoding_detect_bom(buff, bread))) {
|
||||
unsigned char decodedbuff[sizeof(buff)*2];
|
||||
m_area_t in_area, out_area;
|
||||
|
||||
in_area.buffer = (unsigned char *) smallbuff;
|
||||
in_area.buffer = (unsigned char *) buff;
|
||||
in_area.length = bread;
|
||||
in_area.offset = 0;
|
||||
out_area.buffer = decodedbuff;
|
||||
|
@ -227,38 +228,16 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
|
|||
}
|
||||
|
||||
if(ret == CL_TYPE_BINARY_DATA) {
|
||||
|
||||
if(!(bigbuff = (unsigned char *) cli_calloc(37638 + 1, sizeof(unsigned char))))
|
||||
return ret;
|
||||
|
||||
lseek(desc, 0, SEEK_SET);
|
||||
if((bread = cli_readn(desc, bigbuff, 37638)) > 0) {
|
||||
|
||||
bigbuff[bread] = 0;
|
||||
|
||||
switch(is_tar(bigbuff, bread)) {
|
||||
case 1:
|
||||
ret = CL_TYPE_OLD_TAR;
|
||||
cli_dbgmsg("Recognized old fashioned tar file\n");
|
||||
break;
|
||||
case 2:
|
||||
ret = CL_TYPE_POSIX_TAR;
|
||||
cli_dbgmsg("Recognized POSIX tar file\n");
|
||||
break;
|
||||
}
|
||||
switch(is_tar(buff, bread)) {
|
||||
case 1:
|
||||
ret = CL_TYPE_OLD_TAR;
|
||||
cli_dbgmsg("Recognized old fashioned tar file\n");
|
||||
break;
|
||||
case 2:
|
||||
ret = CL_TYPE_POSIX_TAR;
|
||||
cli_dbgmsg("Recognized POSIX tar file\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if(ret == CL_TYPE_BINARY_DATA) {
|
||||
if(!memcmp(bigbuff + 32769, "CD001" , 5) || !memcmp(bigbuff + 37633, "CD001" , 5)) {
|
||||
cli_dbgmsg("Recognized ISO 9660 CD-ROM data\n");
|
||||
ret = CL_TYPE_IGNORED;
|
||||
} else if(!memcmp(bigbuff + 32776, "CDROM" , 5)) {
|
||||
cli_dbgmsg("Recognized High Sierra CD-ROM data\n");
|
||||
ret = CL_TYPE_IGNORED;
|
||||
}
|
||||
}
|
||||
|
||||
free(bigbuff);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -315,6 +315,7 @@ int hashtab_insert(struct hashtable *s, const char* key, const size_t len, const
|
|||
if(!thekey)
|
||||
return CL_EMEM;
|
||||
strncpy(thekey, key, len+1);
|
||||
thekey[len]='\0';
|
||||
element->key = thekey;
|
||||
element->data = data;
|
||||
element->len = len;
|
||||
|
@ -557,3 +558,26 @@ ssize_t hashset_toarray(const struct hashset* hs, uint32_t** array)
|
|||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
struct uniq *uniq_init(uint32_t count) {
|
||||
struct uniq *U;
|
||||
if(!count) return NULL;
|
||||
count = count <= 256 ? 256 : count + (count*20/100);
|
||||
U = (struct uniqueid *)cli_calloc(1, sizeof(U)+sizeof(uint32_t)*count);
|
||||
if(!U) return NULL;
|
||||
U->count = count;
|
||||
return U;
|
||||
}
|
||||
|
||||
uint32_t uniq_add(struct uniq *U, const char *key, uint32_t key_len, uint32_t *rhash) {
|
||||
uint32_t h = hash((const unsigned char *)key, key_len, U->count);
|
||||
if(rhash) *rhash = h;
|
||||
return U->uniques[h]++;
|
||||
}
|
||||
|
||||
uint32_t uniq_get(struct uniq *U, const char *key, uint32_t key_len, uint32_t *rhash) {
|
||||
uint32_t h = hash((const unsigned char *)key, key_len, U->count);
|
||||
if(rhash) *rhash = h;
|
||||
return U->uniques[h];
|
||||
}
|
||||
|
||||
|
|
|
@ -20,11 +20,11 @@
|
|||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#ifndef _HASHTAB_H
|
||||
#define _HASHTAB_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include "cltypes.h"
|
||||
typedef long element_data;
|
||||
|
||||
/* define this for debugging/profiling purposes only, NOT in production/release code */
|
||||
|
@ -105,5 +105,17 @@ int hashset_clear(struct hashset* hs);
|
|||
void hashset_destroy(struct hashset* hs);
|
||||
ssize_t hashset_toarray(const struct hashset* hs, uint32_t** array);
|
||||
|
||||
|
||||
/* A basic storage for unique IDs */
|
||||
struct uniq {
|
||||
uint32_t count;
|
||||
uint32_t uniques[];
|
||||
};
|
||||
|
||||
struct uniq *uniq_init(uint32_t);
|
||||
#define uniq_free(X) free(X);
|
||||
uint32_t uniq_add(struct uniq *, const char *, uint32_t, uint32_t *);
|
||||
uint32_t uniq_get(struct uniq *, const char *, uint32_t, uint32_t *);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -555,7 +555,7 @@ static int cli_html_normalise(int fd, m_area_t *m_area, const char *dirname, tag
|
|||
/* this will still contains scripts that are inside comments */
|
||||
snprintf(filename, 1024, "%s/nocomment.html", dirname);
|
||||
file_buff_o2->fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR);
|
||||
if (!file_buff_o2->fd) {
|
||||
if (file_buff_o2->fd == -1) {
|
||||
cli_dbgmsg("open failed: %s\n", filename);
|
||||
free(file_buff_o2);
|
||||
file_buff_o2 = file_buff_text = NULL;
|
||||
|
@ -564,6 +564,7 @@ static int cli_html_normalise(int fd, m_area_t *m_area, const char *dirname, tag
|
|||
|
||||
file_buff_text = (file_buff_t *) cli_malloc(sizeof(file_buff_t));
|
||||
if(!file_buff_text) {
|
||||
close(file_buff_o2->fd);
|
||||
free(file_buff_o2);
|
||||
file_buff_o2 = file_buff_text = NULL;
|
||||
goto abort;
|
||||
|
@ -571,12 +572,13 @@ static int cli_html_normalise(int fd, m_area_t *m_area, const char *dirname, tag
|
|||
|
||||
snprintf(filename, 1024, "%s/notags.html", dirname);
|
||||
file_buff_text->fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR);
|
||||
if(!file_buff_text->fd) {
|
||||
if(file_buff_text->fd == -1) {
|
||||
cli_dbgmsg("open failed: %s\n", filename);
|
||||
close(file_buff_o2->fd);
|
||||
free(file_buff_o2);
|
||||
free(file_buff_text);
|
||||
file_buff_o2 = file_buff_text = NULL;
|
||||
goto abort;
|
||||
}
|
||||
file_buff_o2->length = 0;
|
||||
file_buff_text->length = 0;
|
||||
|
|
|
@ -74,6 +74,7 @@ CLAMAV_PRIVATE {
|
|||
cli_warnmsg;
|
||||
cli_strtokbuf;
|
||||
cli_leavetemps_flag;
|
||||
uniq_get;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
|
|
@ -1079,6 +1079,7 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
|
|||
return CL_EMEM;
|
||||
}
|
||||
strncpy(new->virname, virname, namelen);
|
||||
new->virname[namelen]='\0';
|
||||
|
||||
if(offset) {
|
||||
new->offset = cli_strdup(offset);
|
||||
|
|
|
@ -104,7 +104,7 @@ static const unsigned short mszip_bit_mask_tab[17] = {
|
|||
if (mszip_read_input(zip)) return zip->error; \
|
||||
i_ptr = zip->i_ptr; \
|
||||
i_end = zip->i_end; \
|
||||
if(i_ptr == i_end) return CL_EFORMAT; \
|
||||
if(i_ptr == i_end) break; \
|
||||
} \
|
||||
bit_buffer |= *i_ptr++ << bits_left; bits_left += 8; \
|
||||
} \
|
||||
|
@ -125,7 +125,12 @@ static const unsigned short mszip_bit_mask_tab[17] = {
|
|||
|
||||
static int mszip_read_input(struct mszip_stream *zip) {
|
||||
int nread = zip->read_cb ? zip->read_cb(zip->file, zip->inbuf, (int)zip->inbuf_size) : cli_readn(zip->fd, zip->inbuf, (int)zip->inbuf_size);
|
||||
if (nread < 0) return zip->error = CL_EFORMAT;
|
||||
if (nread < 0) {
|
||||
if (zip->file->error == CL_BREAK)
|
||||
return zip->error = CL_BREAK;
|
||||
else
|
||||
return zip->error = CL_EFORMAT;
|
||||
}
|
||||
|
||||
zip->i_ptr = &zip->inbuf[0];
|
||||
zip->i_end = &zip->inbuf[nread];
|
||||
|
@ -749,7 +754,12 @@ void mszip_free(struct mszip_stream *zip) {
|
|||
|
||||
static int lzx_read_input(struct lzx_stream *lzx) {
|
||||
int bread = lzx->read_cb ? lzx->read_cb(lzx->file, &lzx->inbuf[0], (int)lzx->inbuf_size) : cli_readn(lzx->fd, &lzx->inbuf[0], (int)lzx->inbuf_size);
|
||||
if (bread < 0) return lzx->error = CL_EFORMAT;
|
||||
if (bread < 0) {
|
||||
if (lzx->file->error == CL_BREAK)
|
||||
return lzx->error = CL_BREAK;
|
||||
else
|
||||
return lzx->error = CL_EFORMAT;
|
||||
}
|
||||
|
||||
/* huff decode's ENSURE_BYTES(16) might overrun the input stream, even
|
||||
* if those bits aren't used, so fake 2 more bytes */
|
||||
|
@ -1577,7 +1587,12 @@ void lzx_free(struct lzx_stream *lzx) {
|
|||
|
||||
static int qtm_read_input(struct qtm_stream *qtm) {
|
||||
int nread = qtm->read_cb ? qtm->read_cb(qtm->file, &qtm->inbuf[0], (int)qtm->inbuf_size) : cli_readn(qtm->fd, &qtm->inbuf[0], (int)qtm->inbuf_size);
|
||||
if (nread < 0) return qtm->error = CL_EFORMAT;
|
||||
if (nread < 0) {
|
||||
if (qtm->file->error == CL_BREAK)
|
||||
return qtm->error = CL_BREAK;
|
||||
else
|
||||
return qtm->error = CL_EFORMAT;
|
||||
}
|
||||
|
||||
qtm->i_ptr = &qtm->inbuf[0];
|
||||
qtm->i_end = &qtm->inbuf[nread];
|
||||
|
|
|
@ -47,9 +47,10 @@
|
|||
#include "cltypes.h"
|
||||
#include "others.h"
|
||||
#include "ole2_extract.h"
|
||||
#include "scanners.h"
|
||||
#include "hashtab.h"
|
||||
|
||||
#include "mbox.h"
|
||||
#include "blob.h" /* sanitiseName() */
|
||||
|
||||
#define ole2_endian_convert_16(v) le16_to_host((uint16_t)(v))
|
||||
#define ole2_endian_convert_32(v) le32_to_host((uint32_t)(v))
|
||||
|
@ -70,6 +71,7 @@
|
|||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct ole2_header_tag
|
||||
{
|
||||
unsigned char magic[8]; /* should be: 0xd0cf11e0a1b11ae1 */
|
||||
|
@ -102,8 +104,11 @@ typedef struct ole2_header_tag
|
|||
unsigned char *m_area;
|
||||
off_t m_length;
|
||||
bitset_t *bitset;
|
||||
struct uniq *U;
|
||||
int has_vba;
|
||||
} ole2_header_t;
|
||||
|
||||
|
||||
typedef struct property_tag
|
||||
{
|
||||
char name[64]; /* in unicode */
|
||||
|
@ -136,7 +141,8 @@ typedef struct property_tag
|
|||
|
||||
static unsigned char magic_id[] = { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1};
|
||||
|
||||
static char *get_property_name(char *name, int size)
|
||||
|
||||
static char *get_property_name2(char *name, int size)
|
||||
{
|
||||
int i, j;
|
||||
char *newname;
|
||||
|
@ -153,7 +159,7 @@ static char *get_property_name(char *name, int size)
|
|||
/* size-2 to ignore trailing NULL */
|
||||
for (i=0 ; i < size-2; i+=2) {
|
||||
if((!(name[i]&0x80)) && isprint(name[i])) {
|
||||
newname[j++] = name[i];
|
||||
newname[j++] = tolower(name[i]);
|
||||
} else {
|
||||
if (name[i] < 10 && name[i] >= 0) {
|
||||
newname[j++] = '_';
|
||||
|
@ -179,50 +185,72 @@ static char *get_property_name(char *name, int size)
|
|||
return newname;
|
||||
}
|
||||
|
||||
static void print_property_name(char *pname, int size)
|
||||
{
|
||||
char *name;
|
||||
|
||||
name = get_property_name(pname, size);
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
cli_dbgmsg("%34s ", name);
|
||||
free(name);
|
||||
return;
|
||||
static char *get_property_name(char *name, int size) {
|
||||
const char *carray = "0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz._";
|
||||
int csize = size>>1;
|
||||
char *newname, *cname;
|
||||
char *oname = name;
|
||||
|
||||
if (csize<=0) return NULL;
|
||||
|
||||
newname = cname = (char *)cli_malloc(size);
|
||||
if (!newname) return NULL;
|
||||
|
||||
while(--csize) {
|
||||
uint16_t lo, hi, u=cli_readint16(oname)-0x3800;
|
||||
oname+=2;
|
||||
if (u > 0x1040) {
|
||||
free(newname);
|
||||
return get_property_name2(name, size);
|
||||
}
|
||||
lo = u % 64;
|
||||
u >>= 6;
|
||||
hi = u % 64;
|
||||
*cname++=carray[lo];
|
||||
if(csize!=1 || u!= 64) *cname++=carray[hi];
|
||||
}
|
||||
*cname='\0';
|
||||
return newname;
|
||||
}
|
||||
|
||||
|
||||
static void print_ole2_property(property_t *property)
|
||||
{
|
||||
char spam[128], *buf;
|
||||
if (property->name_size > 64) {
|
||||
cli_dbgmsg("[err name len: %d]\n", property->name_size);
|
||||
return;
|
||||
}
|
||||
print_property_name(property->name, property->name_size);
|
||||
buf = get_property_name(property->name, property->name_size);
|
||||
snprintf(spam, sizeof(spam), "OLE2: %s ", buf ? buf : "<noname>");
|
||||
spam[sizeof(spam)-1]='\0';
|
||||
if (buf) free(buf);
|
||||
switch (property->type) {
|
||||
case 2:
|
||||
cli_dbgmsg(" [file] ");
|
||||
strncat(spam, " [file] ", sizeof(spam) - 1 - strlen(spam));
|
||||
break;
|
||||
case 1:
|
||||
cli_dbgmsg(" [dir ] ");
|
||||
strncat(spam, " [dir ] ", sizeof(spam) - 1 - strlen(spam));
|
||||
break;
|
||||
case 5:
|
||||
cli_dbgmsg(" [root] ");
|
||||
strncat(spam, " [root] ", sizeof(spam) - 1 - strlen(spam));
|
||||
break;
|
||||
default:
|
||||
cli_dbgmsg(" [%d]", property->type);
|
||||
strncat(spam, " [unkn] ", sizeof(spam) - 1 - strlen(spam));
|
||||
}
|
||||
spam[sizeof(spam)-1]='\0';
|
||||
switch (property->color) {
|
||||
case 0:
|
||||
cli_dbgmsg(" r ");
|
||||
strncat(spam, " r ", sizeof(spam) - 1 - strlen(spam));
|
||||
break;
|
||||
case 1:
|
||||
cli_dbgmsg(" b ");
|
||||
strncat(spam, " b ", sizeof(spam) - 1 - strlen(spam));
|
||||
break;
|
||||
default:
|
||||
cli_dbgmsg(" u ");
|
||||
strncat(spam, " u ", sizeof(spam) - 1 - strlen(spam));
|
||||
}
|
||||
cli_dbgmsg(" 0x%.8x 0x%.8x\n", property->size, property->user_flags);
|
||||
spam[sizeof(spam)-1]='\0';
|
||||
cli_dbgmsg("%s size:0x%.8x flags:0x%.8x\n", spam, property->size, property->user_flags);
|
||||
}
|
||||
|
||||
static void print_ole2_header(ole2_header_t *hdr)
|
||||
|
@ -461,44 +489,45 @@ static void ole2_read_property_tree(int fd, ole2_header_t *hdr, const char *dir,
|
|||
}
|
||||
*/
|
||||
|
||||
static void ole2_walk_property_tree(int fd, ole2_header_t *hdr, const char *dir, int32_t prop_index,
|
||||
int (*handler)(int fd, ole2_header_t *hdr, property_t *prop, const char *dir),
|
||||
unsigned int rec_level, unsigned int *file_count, cli_ctx *ctx, unsigned long *scansize)
|
||||
static int ole2_walk_property_tree(int fd, ole2_header_t *hdr, const char *dir, int32_t prop_index,
|
||||
int (*handler)(int fd, ole2_header_t *hdr, property_t *prop, const char *dir, cli_ctx *ctx),
|
||||
unsigned int rec_level, unsigned int *file_count, cli_ctx *ctx, unsigned long *scansize)
|
||||
{
|
||||
property_t prop_block[4];
|
||||
int32_t idx, current_block, i;
|
||||
char *dirname;
|
||||
int ret;
|
||||
const struct cl_limits *limits = ctx ? ctx->limits : NULL;
|
||||
|
||||
current_block = hdr->prop_start;
|
||||
|
||||
if ((prop_index < 0) || (prop_index > (int32_t) hdr->max_block_no) || (rec_level > 100) || (*file_count > 100000)) {
|
||||
return;
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
if (limits && limits->maxfiles && (*file_count > limits->maxfiles)) {
|
||||
cli_dbgmsg("OLE2: File limit reached (max: %d)\n", limits->maxfiles);
|
||||
return;
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
if (limits && limits->maxreclevel && (rec_level > limits->maxreclevel)) {
|
||||
cli_dbgmsg("OLE2: Recursion limit reached (max: %d)\n", limits->maxreclevel);
|
||||
return;
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
idx = prop_index / 4;
|
||||
for (i=0 ; i < idx ; i++) {
|
||||
current_block = ole2_get_next_block_number(fd, hdr, current_block);
|
||||
if (current_block < 0) {
|
||||
return;
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
}
|
||||
idx = prop_index % 4;
|
||||
if (!ole2_read_block(fd, hdr, prop_block,
|
||||
current_block)) {
|
||||
return;
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
if (prop_block[idx].type <= 0) {
|
||||
return;
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
prop_block[idx].name_size = ole2_endian_convert_16(prop_block[idx].name_size);
|
||||
prop_block[idx].prev = ole2_endian_convert_32(prop_block[idx].prev);
|
||||
|
@ -512,16 +541,16 @@ static void ole2_walk_property_tree(int fd, ole2_header_t *hdr, const char *dir,
|
|||
prop_block[idx].start_block = ole2_endian_convert_32(prop_block[idx].start_block);
|
||||
prop_block[idx].size = ole2_endian_convert_32(prop_block[idx].size);
|
||||
|
||||
print_ole2_property(&prop_block[idx]);
|
||||
if (dir) print_ole2_property(&prop_block[idx]);
|
||||
|
||||
/* Check we aren't in a loop */
|
||||
if (cli_bitset_test(hdr->bitset, (unsigned long) prop_index)) {
|
||||
/* Loop in property tree detected */
|
||||
cli_dbgmsg("OLE2: Property tree loop detected at index %d\n", prop_index);
|
||||
return;
|
||||
return CL_BREAK;
|
||||
}
|
||||
if (!cli_bitset_set(hdr->bitset, (unsigned long) prop_index)) {
|
||||
return;
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
switch (prop_block[idx].type) {
|
||||
|
@ -530,162 +559,143 @@ static void ole2_walk_property_tree(int fd, ole2_header_t *hdr, const char *dir,
|
|||
(*file_count != 0)) {
|
||||
/* Can only have RootEntry as the top */
|
||||
cli_dbgmsg("ERROR: illegal Root Entry\n");
|
||||
return;
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
hdr->sbat_root_start = prop_block[idx].start_block;
|
||||
ole2_walk_property_tree(fd, hdr, dir,
|
||||
prop_block[idx].prev, handler, rec_level+1, file_count, ctx, scansize);
|
||||
ole2_walk_property_tree(fd, hdr, dir,
|
||||
prop_block[idx].next, handler, rec_level+1, file_count, ctx, scansize);
|
||||
ole2_walk_property_tree(fd, hdr, dir,
|
||||
prop_block[idx].child, handler, rec_level+1, file_count, ctx, scansize);
|
||||
if (
|
||||
(ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].prev, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
|
||||
||
|
||||
(ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].next, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
|
||||
||
|
||||
(ret=ole2_walk_property_tree(fd, hdr, dir,prop_block[idx].child, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
|
||||
) return ret;
|
||||
break;
|
||||
case 2: /* File */
|
||||
if (limits && limits->maxfiles && ctx->scannedfiles + *file_count > limits->maxfiles) {
|
||||
cli_dbgmsg("ole2: files limit reached (max: %u)\n", ctx->limits->maxfiles);
|
||||
break;
|
||||
cli_dbgmsg("OLE2: files limit reached (max: %u)\n", ctx->limits->maxfiles);
|
||||
return CL_BREAK;
|
||||
}
|
||||
if (!limits || !limits->maxfilesize || prop_block[idx].size <= limits->maxfilesize || *scansize == -1 || prop_block[idx].size <= *scansize) {
|
||||
(*file_count)++;
|
||||
*scansize-=prop_block[idx].size;
|
||||
if (!handler(fd, hdr, &prop_block[idx], dir)) {
|
||||
cli_dbgmsg("ERROR: handler failed\n");
|
||||
/* If we don't return on this error then
|
||||
we can sometimes pull VBA code
|
||||
from corrupted files.
|
||||
*/
|
||||
|
||||
}
|
||||
if ((ret=handler(fd, hdr, &prop_block[idx], dir, ctx)) != CL_SUCCESS)
|
||||
return ret;
|
||||
} else {
|
||||
cli_dbgmsg("ole2: filesize exceeded\n");
|
||||
cli_dbgmsg("OLE2: filesize exceeded\n");
|
||||
}
|
||||
ole2_walk_property_tree(fd, hdr, dir,
|
||||
prop_block[idx].prev, handler, rec_level, file_count, ctx, scansize);
|
||||
ole2_walk_property_tree(fd, hdr, dir,
|
||||
prop_block[idx].next, handler, rec_level, file_count, ctx, scansize);
|
||||
ole2_walk_property_tree(fd, hdr, dir,
|
||||
prop_block[idx].child, handler, rec_level, file_count, ctx, scansize);
|
||||
if (
|
||||
(ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].prev, handler, rec_level, file_count, ctx, scansize))!=CL_SUCCESS
|
||||
||
|
||||
(ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].next, handler, rec_level, file_count, ctx, scansize))!=CL_SUCCESS
|
||||
||
|
||||
(ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].child, handler, rec_level, file_count, ctx, scansize))!=CL_SUCCESS
|
||||
) return ret;
|
||||
break;
|
||||
case 1: /* Directory */
|
||||
dirname = (char *) cli_malloc(strlen(dir)+8);
|
||||
if (!dirname) {
|
||||
return;
|
||||
}
|
||||
snprintf(dirname, strlen(dir)+8, "%s/%.6d", dir, prop_index);
|
||||
if (mkdir(dirname, 0700) != 0) {
|
||||
free(dirname);
|
||||
return;
|
||||
}
|
||||
cli_dbgmsg("OLE2 dir entry: %s\n",dirname);
|
||||
ole2_walk_property_tree(fd, hdr, dir,
|
||||
prop_block[idx].prev, handler, rec_level+1, file_count, ctx, scansize);
|
||||
ole2_walk_property_tree(fd, hdr, dir,
|
||||
prop_block[idx].next, handler, rec_level+1, file_count, ctx, scansize);
|
||||
ole2_walk_property_tree(fd, hdr, dirname,
|
||||
prop_block[idx].child, handler, rec_level+1, file_count, ctx, scansize);
|
||||
free(dirname);
|
||||
if (dir) {
|
||||
dirname = (char *) cli_malloc(strlen(dir)+8);
|
||||
if (!dirname) return CL_BREAK;
|
||||
snprintf(dirname, strlen(dir)+8, "%s/%.6d", dir, prop_index);
|
||||
if (mkdir(dirname, 0700) != 0) {
|
||||
free(dirname);
|
||||
return CL_BREAK;
|
||||
}
|
||||
cli_dbgmsg("OLE2 dir entry: %s\n",dirname);
|
||||
} else dirname = NULL;
|
||||
if (
|
||||
(ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].prev, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
|
||||
||
|
||||
(ret=ole2_walk_property_tree(fd, hdr, dir,prop_block[idx].next, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
|
||||
||
|
||||
(ret=ole2_walk_property_tree(fd, hdr, dirname, prop_block[idx].child, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
|
||||
) {}
|
||||
if (dirname) free(dirname);
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
cli_dbgmsg("ERROR: unknown OLE2 entry type: %d\n", prop_block[idx].type);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
/* Write file Handler - write the contents of the entry to a file */
|
||||
static int handler_writefile(int fd, ole2_header_t *hdr, property_t *prop, const char *dir)
|
||||
static int handler_writefile(int fd, ole2_header_t *hdr, property_t *prop, const char *dir, cli_ctx *ctx)
|
||||
{
|
||||
unsigned char *buff;
|
||||
int32_t current_block, ofd, len, offset;
|
||||
char *name, *newname;
|
||||
char *name, newname[1024];
|
||||
bitset_t *blk_bitset;
|
||||
uint32_t hash, cnt;
|
||||
|
||||
if (prop->type != 2) {
|
||||
/* Not a file */
|
||||
return TRUE;
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
if (prop->name_size > 64) {
|
||||
cli_dbgmsg("\nERROR: property name too long: %d\n", prop->name_size);
|
||||
return FALSE;
|
||||
cli_dbgmsg("OLE2 [handler_writefile]: property name too long: %d\n", prop->name_size);
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
if (! (name = get_property_name(prop->name, prop->name_size))) {
|
||||
/* File without a name - create a name for it */
|
||||
off_t i;
|
||||
|
||||
i = lseek(fd, 0, SEEK_CUR);
|
||||
name = (char *) cli_malloc(11);
|
||||
if (!name) {
|
||||
return FALSE;
|
||||
}
|
||||
snprintf(name, 11, "%.10ld", (long int) (i + (long int) prop));
|
||||
} else {
|
||||
/* Sanitize the file name */
|
||||
sanitiseName(name);
|
||||
}
|
||||
|
||||
newname = (char *) cli_malloc(strlen(name) + strlen(dir) + 2);
|
||||
if (!newname) {
|
||||
free(name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sprintf(newname, "%s/%s", dir, name);
|
||||
free(name);
|
||||
name = get_property_name2(prop->name, prop->name_size);
|
||||
if (name) cnt = uniq_add(hdr->U, name, strlen(name), &hash);
|
||||
else cnt = uniq_add(hdr->U, NULL, 0, &hash);
|
||||
snprintf(newname, sizeof(newname), "%s/%u_%u", dir, hash, cnt);
|
||||
newname[sizeof(newname)-1]='\0';
|
||||
cli_dbgmsg("OLE2 [handler_writefile]: Dumping '%s' to '%s'\n", name ? name : "<empty>", newname);
|
||||
if (name) free(name);
|
||||
|
||||
ofd = open(newname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU);
|
||||
if (ofd < 0) {
|
||||
cli_errmsg("ERROR: failed to create file: %s\n", newname);
|
||||
free(newname);
|
||||
return FALSE;
|
||||
cli_errmsg("OLE2 [handler_writefile]: failed to create file: %s\n", newname);
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
free(newname);
|
||||
current_block = prop->start_block;
|
||||
len = prop->size;
|
||||
|
||||
buff = (unsigned char *) cli_malloc(1 << hdr->log2_big_block_size);
|
||||
if (!buff) {
|
||||
close(ofd);
|
||||
return FALSE;
|
||||
return CL_BREAK;
|
||||
}
|
||||
|
||||
blk_bitset = cli_bitset_init();
|
||||
if (!blk_bitset) {
|
||||
cli_errmsg("ERROR [handler_writefile]: init bitset failed\n");
|
||||
cli_errmsg("OLE2 [handler_writefile]: init bitset failed\n");
|
||||
close(ofd);
|
||||
return FALSE;
|
||||
return CL_BREAK;
|
||||
}
|
||||
while((current_block >= 0) && (len > 0)) {
|
||||
if (current_block > (int32_t) hdr->max_block_no) {
|
||||
cli_dbgmsg("OLE2: Max block number for file size exceeded: %d\n", current_block);
|
||||
cli_dbgmsg("OLE2 [handler_writefile]: Max block number for file size exceeded: %d\n", current_block);
|
||||
close(ofd);
|
||||
free(buff);
|
||||
cli_bitset_free(blk_bitset);
|
||||
return FALSE;
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
/* Check we aren't in a loop */
|
||||
if (cli_bitset_test(blk_bitset, (unsigned long) current_block)) {
|
||||
/* Loop in block list */
|
||||
cli_dbgmsg("OLE2: Block list loop detected\n");
|
||||
cli_dbgmsg("OLE2 [handler_writefile]: Block list loop detected\n");
|
||||
close(ofd);
|
||||
free(buff);
|
||||
cli_bitset_free(blk_bitset);
|
||||
return FALSE;
|
||||
return CL_BREAK;
|
||||
}
|
||||
if (!cli_bitset_set(blk_bitset, (unsigned long) current_block)) {
|
||||
close(ofd);
|
||||
free(buff);
|
||||
cli_bitset_free(blk_bitset);
|
||||
return FALSE;
|
||||
return CL_BREAK;
|
||||
}
|
||||
if (prop->size < (int64_t)hdr->sbat_cutoff) {
|
||||
/* Small block file */
|
||||
if (!ole2_get_sbat_data_block(fd, hdr, buff, current_block)) {
|
||||
cli_dbgmsg("ole2_get_sbat_data_block failed\n");
|
||||
cli_dbgmsg("OLE2 [handler_writefile]: ole2_get_sbat_data_block failed\n");
|
||||
close(ofd);
|
||||
free(buff);
|
||||
cli_bitset_free(blk_bitset);
|
||||
return FALSE;
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
/* buff now contains the block with 8 small blocks in it */
|
||||
offset = 64 * (current_block % 8);
|
||||
|
@ -693,7 +703,7 @@ static int handler_writefile(int fd, ole2_header_t *hdr, property_t *prop, const
|
|||
close(ofd);
|
||||
free(buff);
|
||||
cli_bitset_free(blk_bitset);
|
||||
return FALSE;
|
||||
return CL_BREAK;
|
||||
}
|
||||
|
||||
len -= MIN(len,64);
|
||||
|
@ -704,14 +714,14 @@ static int handler_writefile(int fd, ole2_header_t *hdr, property_t *prop, const
|
|||
close(ofd);
|
||||
free(buff);
|
||||
cli_bitset_free(blk_bitset);
|
||||
return FALSE;
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
if (cli_writen(ofd, buff, MIN(len,(1 << hdr->log2_big_block_size))) !=
|
||||
MIN(len,(1 << hdr->log2_big_block_size))) {
|
||||
close(ofd);
|
||||
free(buff);
|
||||
cli_bitset_free(blk_bitset);
|
||||
return FALSE;
|
||||
return CL_BREAK;
|
||||
}
|
||||
|
||||
current_block = ole2_get_next_block_number(fd, hdr, current_block);
|
||||
|
@ -721,7 +731,188 @@ static int handler_writefile(int fd, ole2_header_t *hdr, property_t *prop, const
|
|||
close(ofd);
|
||||
free(buff);
|
||||
cli_bitset_free(blk_bitset);
|
||||
return TRUE;
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
/* enum file Handler - checks for VBA presence */
|
||||
static int handler_enum(int fd, ole2_header_t *hdr, property_t *prop, const char *dir, cli_ctx *ctx)
|
||||
{
|
||||
char *name;
|
||||
|
||||
if (!hdr->has_vba) {
|
||||
name = get_property_name2(prop->name, prop->name_size);
|
||||
if (name) {
|
||||
if (!strcmp(name, "_vba_project") || !strcmp(name, "powerpoint document") || !strcmp(name, "worddocument") || !strcmp(name, "_1_ole10native"))
|
||||
hdr->has_vba = 1;
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int handler_otf(int fd, ole2_header_t *hdr, property_t *prop, const char *dir, cli_ctx *ctx)
|
||||
{
|
||||
char *tempfile;
|
||||
unsigned char *buff;
|
||||
int32_t current_block, len, offset;
|
||||
int ofd, ret;
|
||||
bitset_t *blk_bitset;
|
||||
|
||||
if (prop->type != 2) {
|
||||
/* Not a file */
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
print_ole2_property(prop);
|
||||
|
||||
if(!(tempfile = cli_gentemp(NULL)))
|
||||
return CL_EMEM;
|
||||
|
||||
if((ofd = open(tempfile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU)) < 0) {
|
||||
cli_dbgmsg("OLE2: Can't create file %s\n", tempfile);
|
||||
free(tempfile);
|
||||
return CL_EIO;
|
||||
}
|
||||
|
||||
current_block = prop->start_block;
|
||||
len = prop->size;
|
||||
|
||||
buff = (unsigned char *) cli_malloc(1 << hdr->log2_big_block_size);
|
||||
if (!buff) {
|
||||
close(ofd);
|
||||
cli_unlink(tempfile);
|
||||
free(tempfile);
|
||||
return CL_EMEM;
|
||||
}
|
||||
|
||||
blk_bitset = cli_bitset_init();
|
||||
|
||||
if (!blk_bitset) {
|
||||
cli_errmsg("OLE2: OTF handler init bitset failed\n");
|
||||
free(buff);
|
||||
close(ofd);
|
||||
if (cli_unlink(tempfile)) {
|
||||
free(tempfile);
|
||||
return CL_EIO;
|
||||
}
|
||||
free(tempfile);
|
||||
return CL_BREAK;
|
||||
}
|
||||
|
||||
while((current_block >= 0) && (len > 0)) {
|
||||
if (current_block > (int32_t) hdr->max_block_no) {
|
||||
cli_dbgmsg("OLE2: Max block number for file size exceeded: %d\n", current_block);
|
||||
close(ofd);
|
||||
free(buff);
|
||||
cli_bitset_free(blk_bitset);
|
||||
if (cli_unlink(tempfile)) {
|
||||
free(tempfile);
|
||||
return CL_EIO;
|
||||
}
|
||||
free(tempfile);
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
/* Check we aren't in a loop */
|
||||
if (cli_bitset_test(blk_bitset, (unsigned long) current_block)) {
|
||||
/* Loop in block list */
|
||||
cli_dbgmsg("OLE2: Block list loop detected\n");
|
||||
close(ofd);
|
||||
free(buff);
|
||||
cli_bitset_free(blk_bitset);
|
||||
if (cli_unlink(tempfile)) {
|
||||
free(tempfile);
|
||||
return CL_EIO;
|
||||
}
|
||||
free(tempfile);
|
||||
return CL_BREAK;
|
||||
}
|
||||
if (!cli_bitset_set(blk_bitset, (unsigned long) current_block)) {
|
||||
close(ofd);
|
||||
free(buff);
|
||||
cli_bitset_free(blk_bitset);
|
||||
if (cli_unlink(tempfile)) {
|
||||
free(tempfile);
|
||||
return CL_EIO;
|
||||
}
|
||||
free(tempfile);
|
||||
return CL_BREAK;
|
||||
}
|
||||
if (prop->size < (int64_t)hdr->sbat_cutoff) {
|
||||
/* Small block file */
|
||||
if (!ole2_get_sbat_data_block(fd, hdr, buff, current_block)) {
|
||||
cli_dbgmsg("ole2_get_sbat_data_block failed\n");
|
||||
close(ofd);
|
||||
free(buff);
|
||||
cli_bitset_free(blk_bitset);
|
||||
if (cli_unlink(tempfile)) {
|
||||
free(tempfile);
|
||||
return CL_EIO;
|
||||
}
|
||||
free(tempfile);
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
/* buff now contains the block with 8 small blocks in it */
|
||||
offset = 64 * (current_block % 8);
|
||||
if (cli_writen(ofd, &buff[offset], MIN(len,64)) != MIN(len,64)) {
|
||||
close(ofd);
|
||||
free(buff);
|
||||
cli_bitset_free(blk_bitset);
|
||||
if (cli_unlink(tempfile)) {
|
||||
free(tempfile);
|
||||
return CL_EIO;
|
||||
}
|
||||
free(tempfile);
|
||||
return CL_BREAK;
|
||||
}
|
||||
|
||||
len -= MIN(len,64);
|
||||
current_block = ole2_get_next_sbat_block(fd, hdr, current_block);
|
||||
} else {
|
||||
/* Big block file */
|
||||
if (!ole2_read_block(fd, hdr, buff, current_block)) {
|
||||
close(ofd);
|
||||
free(buff);
|
||||
cli_bitset_free(blk_bitset);
|
||||
if (cli_unlink(tempfile)) {
|
||||
free(tempfile);
|
||||
return CL_EIO;
|
||||
}
|
||||
free(tempfile);
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
if (cli_writen(ofd, buff, MIN(len,(1 << hdr->log2_big_block_size))) !=
|
||||
MIN(len,(1 << hdr->log2_big_block_size))) {
|
||||
close(ofd);
|
||||
free(buff);
|
||||
cli_bitset_free(blk_bitset);
|
||||
if (cli_unlink(tempfile)) {
|
||||
free(tempfile);
|
||||
return CL_EIO;
|
||||
}
|
||||
free(tempfile);
|
||||
return CL_BREAK;
|
||||
}
|
||||
|
||||
current_block = ole2_get_next_block_number(fd, hdr, current_block);
|
||||
len -= MIN(len,(1 << hdr->log2_big_block_size));
|
||||
}
|
||||
}
|
||||
|
||||
lseek(ofd, 0, SEEK_SET);
|
||||
ret=cli_magic_scandesc(ofd, ctx);
|
||||
close(ofd);
|
||||
free(buff);
|
||||
cli_bitset_free(blk_bitset);
|
||||
if(!cli_leavetemps_flag) {
|
||||
if (cli_unlink(tempfile)) {
|
||||
free(tempfile);
|
||||
return CL_EIO;
|
||||
}
|
||||
}
|
||||
free(tempfile);
|
||||
return ret==CL_VIRUS ? CL_VIRUS : CL_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
#if !defined(HAVE_ATTRIB_PACKED) && !defined(HAVE_PRAGMA_PACK) && !defined(HAVE_PRAGMA_PACK_HPPA)
|
||||
|
@ -786,13 +977,13 @@ static int ole2_read_header(int fd, ole2_header_t *hdr)
|
|||
}
|
||||
#endif
|
||||
|
||||
int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx)
|
||||
int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx, struct uniq **vba)
|
||||
{
|
||||
ole2_header_t hdr;
|
||||
int hdr_size;
|
||||
int hdr_size, ret=CL_CLEAN;
|
||||
struct stat statbuf;
|
||||
unsigned int file_count=0;
|
||||
unsigned long scansize;
|
||||
unsigned long scansize, scansize2;
|
||||
|
||||
cli_dbgmsg("in cli_ole2_extract()\n");
|
||||
|
||||
|
@ -802,17 +993,19 @@ int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx)
|
|||
else
|
||||
return CL_EMAXSIZE;
|
||||
} else scansize = -1;
|
||||
|
||||
scansize2 = scansize;
|
||||
|
||||
/* size of header - size of other values in struct */
|
||||
hdr_size = sizeof(struct ole2_header_tag) - sizeof(int32_t) -
|
||||
hdr_size = sizeof(struct ole2_header_tag) - sizeof(int32_t) - sizeof(uint32_t) -
|
||||
sizeof(unsigned char *) - sizeof(off_t) - sizeof(bitset_t *) -
|
||||
sizeof(uint32_t);
|
||||
sizeof(struct uniq *) - sizeof(int);
|
||||
|
||||
hdr.m_area = NULL;
|
||||
|
||||
if (fstat(fd, &statbuf) == 0) {
|
||||
if (statbuf.st_size < hdr_size) {
|
||||
return 0;
|
||||
return CL_CLEAN;
|
||||
}
|
||||
#ifdef HAVE_MMAP
|
||||
hdr.m_length = statbuf.st_size;
|
||||
|
@ -827,13 +1020,14 @@ int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx)
|
|||
}
|
||||
|
||||
if (hdr.m_area == NULL) {
|
||||
hdr.bitset = NULL;
|
||||
#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK) || defined(HAVE_PRAGMA_PACK_HPPA)
|
||||
if (cli_readn(fd, &hdr, hdr_size) != hdr_size) {
|
||||
return 0;
|
||||
goto abort;
|
||||
}
|
||||
#else
|
||||
if (!ole2_read_header(fd, &hdr)) {
|
||||
return 0;
|
||||
goto abort;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -854,19 +1048,14 @@ int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx)
|
|||
hdr.sbat_root_start = -1;
|
||||
|
||||
hdr.bitset = cli_bitset_init();
|
||||
if (!hdr.bitset) {
|
||||
if (!hdr.bitset) { /* FIXME: mmap leaks here */
|
||||
return CL_EOLE2;
|
||||
}
|
||||
|
||||
if (memcmp(hdr.magic, magic_id, 8) != 0) {
|
||||
cli_dbgmsg("OLE2 magic failed!\n");
|
||||
#ifdef HAVE_MMAP
|
||||
if (hdr.m_area != NULL) {
|
||||
munmap(hdr.m_area, hdr.m_length);
|
||||
}
|
||||
#endif
|
||||
cli_bitset_free(hdr.bitset);
|
||||
return CL_EOLE2;
|
||||
ret=CL_EOLE2;
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (hdr.log2_big_block_size != 9) {
|
||||
|
@ -894,7 +1083,35 @@ int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx)
|
|||
|
||||
/* OR */
|
||||
|
||||
ole2_walk_property_tree(fd, &hdr, dirname, 0, handler_writefile, 0, &file_count, ctx, &scansize);
|
||||
|
||||
/* PASS 1 : Count files and check for VBA */
|
||||
// __asm__ __volatile__("int3");
|
||||
hdr.has_vba = 0;
|
||||
ret = ole2_walk_property_tree(fd, &hdr, NULL, 0, handler_enum, 0, &file_count, ctx, &scansize);
|
||||
cli_bitset_free(hdr.bitset);
|
||||
hdr.bitset = NULL;
|
||||
if (!file_count || !(hdr.bitset = cli_bitset_init()))
|
||||
goto abort;
|
||||
|
||||
/* If there's no VBA we scan OTF */
|
||||
if (hdr.has_vba) {
|
||||
/* PASS 2/A : VBA scan */
|
||||
cli_dbgmsg("OLE2: VBA project found\n");
|
||||
if (!(hdr.U = uniq_init(file_count))) {
|
||||
cli_dbgmsg("OLE2: uniq_init() failed\n");
|
||||
ret = CL_EMEM;
|
||||
goto abort;
|
||||
}
|
||||
file_count = 0;
|
||||
ole2_walk_property_tree(fd, &hdr, dirname, 0, handler_writefile, 0, &file_count, ctx, &scansize2);
|
||||
ret = CL_CLEAN;
|
||||
*vba = hdr.U;
|
||||
} else {
|
||||
cli_dbgmsg("OLE2: no VBA projects found %d\n", ret);
|
||||
/* PASS 2/B : OTF scan */
|
||||
file_count = 0;
|
||||
ret = ole2_walk_property_tree(fd, &hdr, NULL, 0, handler_otf, 0, &file_count, ctx, &scansize2);
|
||||
}
|
||||
|
||||
abort:
|
||||
#ifdef HAVE_MMAP
|
||||
|
@ -902,6 +1119,8 @@ abort:
|
|||
munmap(hdr.m_area, hdr.m_length);
|
||||
}
|
||||
#endif
|
||||
cli_bitset_free(hdr.bitset);
|
||||
return 0;
|
||||
if(hdr.bitset)
|
||||
cli_bitset_free(hdr.bitset);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
#define __OLE2_EXTRACT_H
|
||||
|
||||
#include "others.h"
|
||||
#include "hashtab.h"
|
||||
|
||||
int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx);
|
||||
int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx, struct uniq **);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -99,6 +99,7 @@ static unsigned char name_salt[16] = { 16, 38, 97, 12, 8, 4, 72, 196, 217, 144,
|
|||
int len = sizeof(x) - 1; \
|
||||
char buff[BUFSIZ]; \
|
||||
strncpy(buff, x, len); \
|
||||
buff[BUFSIZ-1]='\0'; \
|
||||
va_start(args, str); \
|
||||
vsnprintf(buff + len, sizeof(buff) - len, str, args); \
|
||||
buff[sizeof(buff) - 1] = '\0'; \
|
||||
|
|
|
@ -79,7 +79,7 @@ static const char *cli_pmemstr(const char *haystack, size_t hs, const char *need
|
|||
* TODO: handle embedded URLs if (options&CL_SCAN_MAILURL)
|
||||
*/
|
||||
int
|
||||
cli_pdf(const char *dir, int desc, cli_ctx *ctx)
|
||||
cli_pdf(const char *dir, int desc, cli_ctx *ctx, off_t offset)
|
||||
{
|
||||
off_t size; /* total number of bytes in the file */
|
||||
off_t bytesleft, trailerlength;
|
||||
|
@ -99,12 +99,12 @@ cli_pdf(const char *dir, int desc, cli_ctx *ctx)
|
|||
return CL_EOPEN;
|
||||
}
|
||||
|
||||
size = statb.st_size;
|
||||
size = statb.st_size - offset;
|
||||
|
||||
if(size <= 7) /* doesn't even include the file header */
|
||||
return CL_CLEAN;
|
||||
|
||||
p = buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, desc, 0);
|
||||
p = buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, desc, offset);
|
||||
if(buf == MAP_FAILED) {
|
||||
cli_errmsg("cli_pdf: mmap() failed\n");
|
||||
return CL_EMEM;
|
||||
|
@ -115,28 +115,24 @@ cli_pdf(const char *dir, int desc, cli_ctx *ctx)
|
|||
/* Lines are terminated by \r, \n or both */
|
||||
|
||||
/* File Header */
|
||||
if(memcmp(p, "%PDF-1.", 7) != 0) {
|
||||
munmap(buf, size);
|
||||
cli_dbgmsg("cli_pdf: file header not found\n");
|
||||
return CL_CLEAN;
|
||||
bytesleft = size - 5;
|
||||
for(q = p; bytesleft; bytesleft--, q++) {
|
||||
if(!strncasecmp(q, "%PDF-", 5)) {
|
||||
bytesleft = size - (off_t) (q - p);
|
||||
p = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
q = pdf_nextlinestart(&p[6], size - 6);
|
||||
if(q == NULL) {
|
||||
munmap(buf, size);
|
||||
return CL_CLEAN;
|
||||
if(!bytesleft) {
|
||||
munmap(buf, size);
|
||||
cli_dbgmsg("cli_pdf: file header not found\n");
|
||||
return CL_CLEAN;
|
||||
}
|
||||
bytesleft = size - (long)(q - p);
|
||||
p = q;
|
||||
#else
|
||||
p = &p[6];
|
||||
bytesleft = size - 6;
|
||||
#endif
|
||||
|
||||
/* Find the file trailer */
|
||||
for(q = &p[bytesleft - 6]; q > p; --q)
|
||||
if(memcmp(q, "%%EOF", 5) == 0)
|
||||
for(q = &p[bytesleft - 5]; q > p; --q)
|
||||
if(strncasecmp(q, "%%EOF", 5) == 0)
|
||||
break;
|
||||
|
||||
if(q <= p) {
|
||||
|
@ -868,7 +864,7 @@ cli_pmemstr(const char *haystack, size_t hs, const char *needle, size_t ns)
|
|||
#include "pdf.h"
|
||||
|
||||
int
|
||||
cli_pdf(const char *dir, int desc, cli_ctx *ctx)
|
||||
cli_pdf(const char *dir, int desc, cli_ctx *ctx, off_t offset)
|
||||
{
|
||||
cli_dbgmsg("File not decoded - PDF decoding needs mmap() (for now)\n");
|
||||
return CL_CLEAN;
|
||||
|
|
|
@ -22,6 +22,6 @@
|
|||
|
||||
#include "others.h"
|
||||
|
||||
int cli_pdf(const char *dir, int desc, cli_ctx *ctx);
|
||||
int cli_pdf(const char *dir, int desc, cli_ctx *ctx, off_t offset);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -260,6 +260,7 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex
|
|||
}
|
||||
|
||||
strncpy(bm_new->virname, virname, virlen);
|
||||
bm_new->virname[virlen]='\0';
|
||||
|
||||
if(offset) {
|
||||
bm_new->offset = cli_strdup(offset);
|
||||
|
@ -687,6 +688,7 @@ static int cli_loadftm(FILE *fs, struct cl_engine **engine, unsigned int options
|
|||
if(!ftypes_int[line])
|
||||
break;
|
||||
strncpy(buffer, ftypes_int[line], sizeof(buffer));
|
||||
buffer[sizeof(buffer)-1]='\0';
|
||||
} else {
|
||||
if(!cli_dbgets(buffer, FILEBUFF, fs, dbio))
|
||||
break;
|
||||
|
|
|
@ -137,14 +137,12 @@ static void init_rtf_state(struct rtf_state* state)
|
|||
|
||||
static int compare_state(const struct rtf_state* a,const struct rtf_state* b)
|
||||
{
|
||||
return (a->controlword_param == b->controlword_param &&
|
||||
a->parse_state == b->parse_state &&
|
||||
a->encounteredTopLevel == b->encounteredTopLevel &&
|
||||
memcmp(a->controlword,b->controlword,33)==0 &&
|
||||
a->cb_begin == b->cb_begin &&
|
||||
a->cb_process == b->cb_process &&
|
||||
a->cb_end == b->cb_end &&
|
||||
a->cb_data == b->cb_data);
|
||||
return (a->parse_state == b->parse_state &&
|
||||
a->encounteredTopLevel == b->encounteredTopLevel &&
|
||||
a->cb_begin == b->cb_begin &&
|
||||
a->cb_process == b->cb_process &&
|
||||
a->cb_end == b->cb_end &&
|
||||
a->cb_data == b->cb_data);
|
||||
}
|
||||
|
||||
|
||||
|
@ -161,10 +159,12 @@ static int push_state(struct stack* stack,struct rtf_state* state)
|
|||
}
|
||||
if(stack->stack_cnt >= stack->stack_size) {
|
||||
/* grow stack */
|
||||
struct rtf_state *states;
|
||||
stack->stack_size += 128;
|
||||
stack->states = cli_realloc2(stack->states, stack->stack_size*sizeof(*stack->states));
|
||||
if(!stack->states)
|
||||
states = cli_realloc2(stack->states, stack->stack_size*sizeof(*stack->states));
|
||||
if(!states)
|
||||
return CL_EMEM;
|
||||
stack->states = states;
|
||||
}
|
||||
stack->states[stack->stack_cnt++] = *state;
|
||||
toplevel = state->encounteredTopLevel;
|
||||
|
@ -233,17 +233,12 @@ static int rtf_object_begin(struct rtf_state* state,cli_ctx* ctx,const char* tmp
|
|||
|
||||
static int decode_and_scan(struct rtf_object_data* data, cli_ctx* ctx)
|
||||
{
|
||||
int ofd, ret=0;
|
||||
int ret=CL_CLEAN;
|
||||
|
||||
cli_dbgmsg("RTF:Scanning embedded object:%s\n",data->name);
|
||||
if(data->bread == 1 && data->fd > 0) {
|
||||
cli_dbgmsg("Decoding ole object\n");
|
||||
lseek(data->fd,0,SEEK_SET);
|
||||
ofd = cli_decode_ole_object(data->fd,data->tmpdir);
|
||||
if (ofd >= 0) {
|
||||
ret = cli_magic_scandesc(ofd, ctx);
|
||||
close(ofd);
|
||||
}
|
||||
ret = cli_scan_ole10(data->fd, ctx);
|
||||
}
|
||||
else if(data->fd > 0)
|
||||
ret = cli_magic_scandesc(data->fd,ctx);
|
||||
|
@ -483,6 +478,8 @@ static void rtf_action(struct rtf_state* state,long action)
|
|||
|
||||
static void cleanup_stack(struct stack* stack,struct rtf_state* state,cli_ctx* ctx)
|
||||
{
|
||||
if(!stack || !stack->states)
|
||||
return;
|
||||
while(stack && stack->stack_cnt /* && state->default_elements*/) {
|
||||
pop_state(stack,state);
|
||||
if(state->cb_data && state->cb_end)
|
||||
|
|
|
@ -722,9 +722,9 @@ static int cli_scanmscab(int desc, cli_ctx *ctx, off_t sfx_offset)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int cli_vba_scandir(const char *dirname, cli_ctx *ctx)
|
||||
static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
|
||||
{
|
||||
int ret = CL_CLEAN, i, fd, ofd, data_len;
|
||||
int ret = CL_CLEAN, i, j, fd, ofd, data_len;
|
||||
vba_project_t *vba_project;
|
||||
DIR *dd;
|
||||
struct dirent *dent;
|
||||
|
@ -735,84 +735,88 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx)
|
|||
} result;
|
||||
#endif
|
||||
struct stat statbuf;
|
||||
char *fname, *fullname;
|
||||
char *fullname, vbaname[1024];
|
||||
unsigned char *data;
|
||||
uint32_t hash, hashcnt;
|
||||
|
||||
|
||||
cli_dbgmsg("VBADir: %s\n", dirname);
|
||||
if((vba_project = (vba_project_t *)cli_vba_readdir(dirname))) {
|
||||
hashcnt = uniq_get(U, "_vba_project", 12, NULL);
|
||||
while(hashcnt--) {
|
||||
if(!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) continue;
|
||||
|
||||
for(i = 0; i < vba_project->count; i++) {
|
||||
fullname = (char *) cli_malloc(strlen(vba_project->dir) + strlen(vba_project->name[i]) + 2);
|
||||
if(!fullname) {
|
||||
ret = CL_EMEM;
|
||||
break;
|
||||
}
|
||||
sprintf(fullname, "%s/%s", vba_project->dir, vba_project->name[i]);
|
||||
fd = open(fullname, O_RDONLY|O_BINARY);
|
||||
if(fd == -1) {
|
||||
cli_dbgmsg("VBADir: Can't open file %s\n", fullname);
|
||||
free(fullname);
|
||||
ret = CL_EOPEN;
|
||||
break;
|
||||
}
|
||||
free(fullname);
|
||||
cli_dbgmsg("VBADir: Decompress VBA project '%s'\n", vba_project->name[i]);
|
||||
data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
|
||||
close(fd);
|
||||
for(j = 0; j < vba_project->colls[i]; j++) {
|
||||
snprintf(vbaname, 1024, "%s/%u_%u", vba_project->dir, vba_project->name[i], j);
|
||||
vbaname[sizeof(vbaname)-1] = '\0';
|
||||
fd = open(vbaname, O_RDONLY|O_BINARY);
|
||||
if(fd == -1) continue;
|
||||
cli_dbgmsg("VBADir: Decompress VBA project '%u_%u'\n", vba_project->name[i], j);
|
||||
data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
|
||||
close(fd);
|
||||
|
||||
if(!data) {
|
||||
cli_dbgmsg("VBADir: WARNING: VBA project '%s' decompressed to NULL\n", vba_project->name[i]);
|
||||
} else {
|
||||
if(ctx->scanned)
|
||||
*ctx->scanned += data_len / CL_COUNT_PRECISION;
|
||||
|
||||
if(cli_scanbuff(data, data_len, ctx, CL_TYPE_MSOLE2) == CL_VIRUS) {
|
||||
if(!data) {
|
||||
cli_dbgmsg("VBADir: WARNING: VBA project '%u_%u' decompressed to NULL\n", vba_project->name[i], j);
|
||||
} else {
|
||||
/* cli_dbgmsg("Project content:\n%s", data); */
|
||||
if(ctx->scanned)
|
||||
*ctx->scanned += data_len / CL_COUNT_PRECISION;
|
||||
if(cli_scanbuff(data, data_len, ctx, CL_TYPE_MSOLE2) == CL_VIRUS) {
|
||||
free(data);
|
||||
ret = CL_VIRUS;
|
||||
break;
|
||||
}
|
||||
free(data);
|
||||
ret = CL_VIRUS;
|
||||
break;
|
||||
}
|
||||
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < vba_project->count; i++)
|
||||
free(vba_project->name[i]);
|
||||
free(vba_project->name);
|
||||
free(vba_project->colls);
|
||||
free(vba_project->dir);
|
||||
free(vba_project->offset);
|
||||
free(vba_project);
|
||||
} else if ((fullname = cli_ppt_vba_read(dirname))) {
|
||||
if(cli_scandir(fullname, ctx, 0) == CL_VIRUS) {
|
||||
ret = CL_VIRUS;
|
||||
}
|
||||
if(!cli_leavetemps_flag)
|
||||
cli_rmdirs(fullname);
|
||||
free(fullname);
|
||||
} else if ((vba_project = (vba_project_t *)cli_wm_readdir(dirname))) {
|
||||
for (i = 0; i < vba_project->count; i++) {
|
||||
fullname = (char *) cli_malloc(strlen(vba_project->dir) + strlen(vba_project->name[i]) + 2);
|
||||
if(!fullname) {
|
||||
ret = CL_EMEM;
|
||||
break;
|
||||
}
|
||||
sprintf(fullname, "%s/%s", vba_project->dir, vba_project->name[i]);
|
||||
fd = open(fullname, O_RDONLY|O_BINARY);
|
||||
if(fd == -1) {
|
||||
cli_dbgmsg("VBADir: Can't open file %s\n", fullname);
|
||||
free(fullname);
|
||||
ret = CL_EOPEN;
|
||||
break;
|
||||
if (ret == CL_VIRUS) break;
|
||||
}
|
||||
|
||||
if(ret == CL_CLEAN && (hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
|
||||
while(hashcnt--) {
|
||||
snprintf(vbaname, 1024, "%s/%u_%u", dirname, hash, hashcnt);
|
||||
vbaname[sizeof(vbaname)-1] = '\0';
|
||||
fd = open(vbaname, O_RDONLY|O_BINARY);
|
||||
if (fd == -1) continue;
|
||||
if ((fullname = cli_ppt_vba_read(fd))) {
|
||||
if(cli_scandir(fullname, ctx, 0) == CL_VIRUS) {
|
||||
ret = CL_VIRUS;
|
||||
}
|
||||
if(!cli_leavetemps_flag)
|
||||
cli_rmdirs(fullname);
|
||||
free(fullname);
|
||||
cli_dbgmsg("VBADir: Decompress WM project '%s' macro:%d key:%d length:%d\n", vba_project->name[i], i, vba_project->key[i], vba_project->length[i]);
|
||||
data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], vba_project->length[i], vba_project->key[i]);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == CL_CLEAN && (hashcnt = uniq_get(U, "worddocument", 12, &hash))) {
|
||||
while(hashcnt--) {
|
||||
snprintf(vbaname, sizeof(vbaname), "%s/%u_%u", dirname, hash, hashcnt);
|
||||
vbaname[sizeof(vbaname)-1] = '\0';
|
||||
fd = open(vbaname, O_RDONLY|O_BINARY);
|
||||
if (fd == -1) continue;
|
||||
|
||||
if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd))) {
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < vba_project->count; i++) {
|
||||
cli_dbgmsg("VBADir: Decompress WM project macro:%d key:%d length:%d\n", i, vba_project->key[i], vba_project->length[i]);
|
||||
data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], vba_project->length[i], vba_project->key[i]);
|
||||
|
||||
if(!data) {
|
||||
cli_dbgmsg("VBADir: WARNING: WM project '%s' macro %d decrypted to NULL\n", vba_project->name[i], i);
|
||||
} else {
|
||||
cli_dbgmsg("Project content:\n%s", data);
|
||||
if(ctx->scanned)
|
||||
*ctx->scanned += vba_project->length[i] / CL_COUNT_PRECISION;
|
||||
if(cli_scanbuff(data, vba_project->length[i], ctx, CL_TYPE_MSOLE2) == CL_VIRUS) {
|
||||
|
@ -822,39 +826,43 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx)
|
|||
}
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
free(vba_project->name);
|
||||
free(vba_project->colls);
|
||||
free(vba_project->dir);
|
||||
free(vba_project->offset);
|
||||
free(vba_project->key);
|
||||
free(vba_project->length);
|
||||
free(vba_project);
|
||||
if(ret == CL_VIRUS) break;
|
||||
}
|
||||
for(i = 0; i < vba_project->count; i++)
|
||||
free(vba_project->name[i]);
|
||||
free(vba_project->key);
|
||||
free(vba_project->length);
|
||||
free(vba_project->offset);
|
||||
free(vba_project->name);
|
||||
free(vba_project->dir);
|
||||
free(vba_project);
|
||||
}
|
||||
|
||||
if(ret != CL_CLEAN)
|
||||
return ret;
|
||||
|
||||
/* Check directory for embedded OLE objects */
|
||||
fullname = (char *) cli_malloc(strlen(dirname) + 16);
|
||||
if(!fullname)
|
||||
return CL_EMEM;
|
||||
hashcnt = uniq_get(U, "_1_ole10native", 14, &hash);
|
||||
while(hashcnt--) {
|
||||
snprintf(vbaname, sizeof(vbaname), "%s/%u_%u", dirname, hash, hashcnt);
|
||||
vbaname[sizeof(vbaname)-1] = '\0';
|
||||
|
||||
sprintf(fullname, "%s/_1_Ole10Native", dirname);
|
||||
fd = open(fullname, O_RDONLY|O_BINARY);
|
||||
free(fullname);
|
||||
if (fd >= 0) {
|
||||
ofd = cli_decode_ole_object(fd, dirname);
|
||||
if (ofd >= 0) {
|
||||
ret = cli_scandesc(ofd, ctx, 0, 0, NULL, AC_SCAN_VIR);
|
||||
close(ofd);
|
||||
fd = open(vbaname, O_RDONLY|O_BINARY);
|
||||
if (fd >= 0) {
|
||||
ret = cli_scan_ole10(fd, ctx);
|
||||
close(fd);
|
||||
if(ret != CL_CLEAN)
|
||||
return ret;
|
||||
}
|
||||
close(fd);
|
||||
if(ret != CL_CLEAN)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* ACAB: since we now hash filenames and handle collisions we
|
||||
* could avoid recursion by removing the block below and by
|
||||
* flattening the paths in ole2_walk_property_tree (case 1) */
|
||||
|
||||
if((dd = opendir(dirname)) != NULL) {
|
||||
#ifdef HAVE_READDIR_R_3
|
||||
while(!readdir_r(dd, &result.d, &dent) && dent) {
|
||||
|
@ -869,23 +877,23 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx)
|
|||
{
|
||||
if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
|
||||
/* build the full name */
|
||||
fname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
|
||||
if(!fname) {
|
||||
fullname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
|
||||
if(!fullname) {
|
||||
ret = CL_EMEM;
|
||||
break;
|
||||
}
|
||||
sprintf(fname, "%s/%s", dirname, dent->d_name);
|
||||
sprintf(fullname, "%s/%s", dirname, dent->d_name);
|
||||
|
||||
/* stat the file */
|
||||
if(lstat(fname, &statbuf) != -1) {
|
||||
if(lstat(fullname, &statbuf) != -1) {
|
||||
if(S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode))
|
||||
if (cli_vba_scandir(fname, ctx) == CL_VIRUS) {
|
||||
if (cli_vba_scandir(fullname, ctx, U) == CL_VIRUS) {
|
||||
ret = CL_VIRUS;
|
||||
free(fname);
|
||||
free(fullname);
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(fname);
|
||||
free(fullname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1086,7 +1094,7 @@ static int cli_scanole2(int desc, cli_ctx *ctx)
|
|||
{
|
||||
char *dir;
|
||||
int ret = CL_CLEAN;
|
||||
|
||||
struct uniq *vba = NULL;
|
||||
|
||||
cli_dbgmsg("in cli_scanole2()\n");
|
||||
|
||||
|
@ -1103,25 +1111,26 @@ static int cli_scanole2(int desc, cli_ctx *ctx)
|
|||
return CL_ETMPDIR;
|
||||
}
|
||||
|
||||
if((ret = cli_ole2_extract(desc, dir, ctx))) {
|
||||
ret = cli_ole2_extract(desc, dir, ctx, &vba);
|
||||
if(ret!=CL_CLEAN && ret!=CL_VIRUS) {
|
||||
cli_dbgmsg("OLE2: %s\n", cl_strerror(ret));
|
||||
if(!cli_leavetemps_flag)
|
||||
cli_rmdirs(dir);
|
||||
free(dir);
|
||||
ctx->recursion--;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctx->recursion++;
|
||||
if (vba) {
|
||||
ctx->recursion++;
|
||||
|
||||
if((ret = cli_vba_scandir(dir, ctx)) != CL_VIRUS) {
|
||||
if(cli_scandir(dir, ctx, 0) == CL_VIRUS) {
|
||||
ret = CL_VIRUS;
|
||||
}
|
||||
ret = cli_vba_scandir(dir, ctx, vba);
|
||||
free(vba);
|
||||
if(ret != CL_VIRUS)
|
||||
if(cli_scandir(dir, ctx, 0) == CL_VIRUS)
|
||||
ret = CL_VIRUS;
|
||||
ctx->recursion--;
|
||||
}
|
||||
|
||||
ctx->recursion--;
|
||||
|
||||
if(!cli_leavetemps_flag)
|
||||
cli_rmdirs(dir);
|
||||
free(dir);
|
||||
|
@ -1380,7 +1389,7 @@ static int cli_scancryptff(int desc, cli_ctx *ctx)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int cli_scanpdf(int desc, cli_ctx *ctx)
|
||||
static int cli_scanpdf(int desc, cli_ctx *ctx, off_t offset)
|
||||
{
|
||||
int ret;
|
||||
char *dir = cli_gentemp(NULL);
|
||||
|
@ -1394,7 +1403,7 @@ static int cli_scanpdf(int desc, cli_ctx *ctx)
|
|||
return CL_ETMPDIR;
|
||||
}
|
||||
|
||||
ret = cli_pdf(dir, desc, ctx);
|
||||
ret = cli_pdf(dir, desc, ctx, offset);
|
||||
|
||||
if(!cli_leavetemps_flag)
|
||||
cli_rmdirs(dir);
|
||||
|
@ -1717,6 +1726,13 @@ static int cli_scanraw(int desc, cli_ctx *ctx, cli_file_t type, uint8_t typercg,
|
|||
}
|
||||
break;
|
||||
|
||||
case CL_TYPE_PDF:
|
||||
if(SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF)) {
|
||||
cli_dbgmsg("PDF signature found at %u\n", (unsigned int) fpt->offset);
|
||||
nret = cli_scanpdf(desc, ctx, fpt->offset);
|
||||
}
|
||||
break;
|
||||
|
||||
case CL_TYPE_MSEXE:
|
||||
if(SCAN_PE && ctx->dconf->pe && fpt->offset) {
|
||||
cli_dbgmsg("PE signature found at %u\n", (unsigned int) fpt->offset);
|
||||
|
@ -1969,7 +1985,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
|
|||
|
||||
case CL_TYPE_PDF: /* FIXMELIMITS: pdf should be an archive! */
|
||||
if(SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF))
|
||||
ret = cli_scanpdf(desc, ctx);
|
||||
ret = cli_scanpdf(desc, ctx, 0);
|
||||
break;
|
||||
|
||||
case CL_TYPE_CRYPTFF:
|
||||
|
@ -2105,3 +2121,9 @@ int cl_scanfile(const char *filename, const char **virname, unsigned long int *s
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
c-basic-offset: 4
|
||||
End:
|
||||
*/
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "clamav.h"
|
||||
|
||||
#include "others.h"
|
||||
#include "scanners.h"
|
||||
#include "vba_extract.h"
|
||||
#ifdef CL_DEBUG
|
||||
#include "mbox.h"
|
||||
|
@ -71,29 +72,11 @@ typedef struct {
|
|||
int big_endian; /* e.g. MAC Office */
|
||||
} vba_version_t;
|
||||
|
||||
static const vba_version_t vba_versions[] = {
|
||||
{ 0x0100005e, "97", FALSE },
|
||||
{ 0x0100005f, "97 SR1", FALSE },
|
||||
{ 0x01000065, "2000 alpha", FALSE },
|
||||
{ 0x0100006b, "2000 beta", FALSE },
|
||||
{ 0x0100006d, "2000", FALSE },
|
||||
{ 0x0100006f, "2000", FALSE },
|
||||
{ 0x01000070, "XP beta 1/2", FALSE },
|
||||
{ 0x01000073, "XP", FALSE },
|
||||
{ 0x01000073, "2003", FALSE },
|
||||
{ 0x01000079, "2003", FALSE },
|
||||
{ 0x0e000060, "98", TRUE },
|
||||
{ 0x0e000062, "2001", TRUE },
|
||||
{ 0x0e000063, "X", TRUE },
|
||||
{ 0x0e000064, "2004", TRUE },
|
||||
{ 0x00000000, NULL, FALSE },
|
||||
};
|
||||
|
||||
static int skip_past_nul(int fd);
|
||||
static int read_uint16(int fd, uint16_t *u, int big_endian);
|
||||
static int read_uint32(int fd, uint32_t *u, int big_endian);
|
||||
static int seekandread(int fd, off_t offset, int whence, void *data, size_t len);
|
||||
static vba_project_t *create_vba_project(int record_count, const char *dir);
|
||||
static vba_project_t *create_vba_project(int record_count, const char *dir, struct uniq *U);
|
||||
|
||||
static uint16_t
|
||||
vba_endian_convert_16(uint16_t value, int big_endian)
|
||||
|
@ -114,6 +97,7 @@ vba_endian_convert_32(uint32_t value, int big_endian)
|
|||
return le32_to_host(value);
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
get_unicode_name(const char *name, int size, int big_endian)
|
||||
{
|
||||
|
@ -136,9 +120,9 @@ get_unicode_name(const char *name, int size, int big_endian)
|
|||
ret = newname;
|
||||
|
||||
for(i = 0; i < size; i += increment) {
|
||||
if(isprint(name[i]))
|
||||
*ret++ = name[i];
|
||||
else {
|
||||
if((!(name[i]&0x80)) && isprint(name[i])) {
|
||||
*ret++ = tolower(name[i]);
|
||||
} else {
|
||||
if((name[i] < 10) && (name[i] >= 0)) {
|
||||
*ret++ = '_';
|
||||
*ret++ = (char)(name[i] + '0');
|
||||
|
@ -195,17 +179,16 @@ vba_read_project_strings(int fd, int big_endian)
|
|||
{
|
||||
unsigned char *buf = NULL;
|
||||
uint16_t buflen = 0;
|
||||
int ret = 0;
|
||||
|
||||
for(;;) {
|
||||
off_t offset;
|
||||
uint16_t length;
|
||||
char *name;
|
||||
|
||||
if(!read_uint16(fd, &length, big_endian)) {
|
||||
if(buf)
|
||||
free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
if(!read_uint16(fd, &length, big_endian))
|
||||
break;
|
||||
|
||||
if (length < 6) {
|
||||
lseek(fd, -2, SEEK_CUR);
|
||||
break;
|
||||
|
@ -215,7 +198,7 @@ vba_read_project_strings(int fd, int big_endian)
|
|||
if(newbuf == NULL) {
|
||||
if(buf)
|
||||
free(buf);
|
||||
return FALSE;
|
||||
return 0;
|
||||
}
|
||||
buflen = length;
|
||||
buf = newbuf;
|
||||
|
@ -232,7 +215,7 @@ vba_read_project_strings(int fd, int big_endian)
|
|||
cli_dbgmsg("length: %d, name: %s\n", length, (name) ? name : "[null]");
|
||||
|
||||
if((name == NULL) || (memcmp("*\\", name, 2) != 0) ||
|
||||
(strchr("GCHD", name[2]) == NULL)) {
|
||||
(strchr("ghcd", name[2]) == NULL)) {
|
||||
/* Not a string */
|
||||
lseek(fd, -(length+2), SEEK_CUR);
|
||||
if(name)
|
||||
|
@ -244,9 +227,11 @@ vba_read_project_strings(int fd, int big_endian)
|
|||
if(!read_uint16(fd, &length, big_endian)) {
|
||||
if(buf)
|
||||
free(buf);
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
ret++;
|
||||
|
||||
if ((length != 0) && (length != 65535)) {
|
||||
lseek(fd, -2, SEEK_CUR);
|
||||
continue;
|
||||
|
@ -257,21 +242,22 @@ vba_read_project_strings(int fd, int big_endian)
|
|||
}
|
||||
if(buf)
|
||||
free(buf);
|
||||
return TRUE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
vba_project_t *
|
||||
cli_vba_readdir(const char *dir)
|
||||
cli_vba_readdir(const char *dir, struct uniq *U, uint32_t which)
|
||||
{
|
||||
unsigned char *buf;
|
||||
const unsigned char vba56_signature[] = { 0xcc, 0x61 };
|
||||
uint16_t record_count, buflen, ffff, byte_count;
|
||||
uint32_t offset, sig;
|
||||
int i, fd, big_endian;
|
||||
uint32_t offset, sig, hash, colls;
|
||||
int i, j, fd, big_endian = FALSE;
|
||||
vba_project_t *vba_project;
|
||||
const vba_version_t *v;
|
||||
struct vba56_header v56h;
|
||||
char fullname[NAME_MAX + 1];
|
||||
off_t seekback;
|
||||
char fullname[1024];
|
||||
|
||||
cli_dbgmsg("in cli_vba_readdir()\n");
|
||||
|
||||
|
@ -281,13 +267,15 @@ cli_vba_readdir(const char *dir)
|
|||
/*
|
||||
* _VBA_PROJECT files are embedded within office documents (OLE2)
|
||||
*/
|
||||
snprintf(fullname, sizeof(fullname) - 1, "%s/_VBA_PROJECT", dir);
|
||||
|
||||
if (!uniq_get(U, "_vba_project", 12, &hash))
|
||||
return NULL;
|
||||
snprintf(fullname, sizeof(fullname), "%s/%u_%u", dir, hash, which);
|
||||
fullname[sizeof(fullname)-1] = '\0';
|
||||
fd = open(fullname, O_RDONLY|O_BINARY);
|
||||
|
||||
if(fd == -1) {
|
||||
cli_dbgmsg("Can't open %s\n", fullname);
|
||||
if(fd == -1)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(cli_readn(fd, &v56h, sizeof(struct vba56_header)) != sizeof(struct vba56_header)) {
|
||||
close(fd);
|
||||
|
@ -298,37 +286,22 @@ cli_vba_readdir(const char *dir)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
sig = cli_readint32(v56h.version);
|
||||
for(v = vba_versions; v->sig; v++)
|
||||
if(v->sig == sig)
|
||||
break;
|
||||
|
||||
if(!v->sig) {
|
||||
cli_warnmsg("Unknown VBA version signature %x %x %x %x\n",
|
||||
v56h.version[0], v56h.version[1],
|
||||
v56h.version[2], v56h.version[3]);
|
||||
switch(v56h.version[3]) {
|
||||
case 0x01:
|
||||
cli_warnmsg("Guessing little-endian\n");
|
||||
big_endian = FALSE;
|
||||
break;
|
||||
case 0x0E:
|
||||
cli_warnmsg("Guessing big-endian\n");
|
||||
big_endian = TRUE;
|
||||
break;
|
||||
default:
|
||||
cli_warnmsg("Unable to guess VBA type\n");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
cli_dbgmsg("VBA Project: %s %s\n", v->big_endian ? "MacOffice" : "Office", v->ver);
|
||||
big_endian = v->big_endian;
|
||||
}
|
||||
|
||||
if (!vba_read_project_strings(fd, big_endian)) {
|
||||
close(fd);
|
||||
i = vba_read_project_strings(fd, TRUE);
|
||||
seekback = lseek(fd, 0, SEEK_CUR);
|
||||
if (lseek(fd, sizeof(struct vba56_header), SEEK_SET) == -1)
|
||||
return NULL;
|
||||
j = vba_read_project_strings(fd, FALSE);
|
||||
if(!i && !j) {
|
||||
close(fd);
|
||||
cli_warnmsg("vba_readdir: Unable to guess VBA type\n");
|
||||
return NULL;
|
||||
}
|
||||
if (i > j) {
|
||||
big_endian = TRUE;
|
||||
lseek(fd, seekback, SEEK_SET);
|
||||
cli_dbgmsg("vba_readdir: Guessing big-endian\n");
|
||||
} else {
|
||||
cli_dbgmsg("vba_readdir: Guessing little-endian\n");
|
||||
}
|
||||
|
||||
/* junk some more stuff */
|
||||
|
@ -369,7 +342,7 @@ cli_vba_readdir(const char *dir)
|
|||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
cli_dbgmsg("VBA Record count: %d\n", record_count);
|
||||
cli_dbgmsg("vba_readdir: VBA Record count %d\n", record_count);
|
||||
if (record_count == 0) {
|
||||
/* No macros, assume clean */
|
||||
close(fd);
|
||||
|
@ -377,12 +350,12 @@ cli_vba_readdir(const char *dir)
|
|||
}
|
||||
if (record_count > MAX_VBA_COUNT) {
|
||||
/* Almost certainly an error */
|
||||
cli_dbgmsg("VBA Record count too big\n");
|
||||
cli_dbgmsg("vba_readdir: VBA Record count too big\n");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vba_project = create_vba_project(record_count, dir);
|
||||
vba_project = create_vba_project(record_count, dir, U);
|
||||
if(vba_project == NULL) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
|
@ -393,11 +366,12 @@ cli_vba_readdir(const char *dir)
|
|||
uint16_t length;
|
||||
char *ptr;
|
||||
|
||||
vba_project->colls[i] = 0;
|
||||
if(!read_uint16(fd, &length, big_endian))
|
||||
break;
|
||||
|
||||
if (length == 0) {
|
||||
cli_dbgmsg("zero name length\n");
|
||||
cli_dbgmsg("vba_readdir: zero name length\n");
|
||||
break;
|
||||
}
|
||||
if(length > buflen) {
|
||||
|
@ -408,51 +382,39 @@ cli_vba_readdir(const char *dir)
|
|||
buf = newbuf;
|
||||
}
|
||||
if (cli_readn(fd, buf, length) != length) {
|
||||
cli_dbgmsg("read name failed\n");
|
||||
cli_dbgmsg("vba_readdir: read name failed\n");
|
||||
break;
|
||||
}
|
||||
ptr = get_unicode_name((const char *)buf, length, big_endian);
|
||||
if(ptr == NULL) {
|
||||
offset = lseek(fd, 0, SEEK_CUR);
|
||||
ptr = (char *)cli_malloc(18);
|
||||
if(ptr == NULL)
|
||||
break;
|
||||
sprintf(ptr, "clamav-%.10d", (int)offset);
|
||||
}
|
||||
cli_dbgmsg("project name: %s\n", ptr);
|
||||
|
||||
if(!read_uint16(fd, &length, big_endian)) {
|
||||
free(ptr);
|
||||
if(ptr == NULL) break;
|
||||
if (!(vba_project->colls[i]=uniq_get(U, ptr, strlen(ptr), &hash))) {
|
||||
cli_dbgmsg("vba_readdir: cannot find project %s (%u)\n", ptr, hash);
|
||||
break;
|
||||
}
|
||||
cli_dbgmsg("vba_readdir: project name: %s (%u)\n", ptr, hash);
|
||||
free(ptr);
|
||||
vba_project->name[i] = hash;
|
||||
if(!read_uint16(fd, &length, big_endian))
|
||||
break;
|
||||
lseek(fd, length, SEEK_CUR);
|
||||
|
||||
if(!read_uint16(fd, &ffff, big_endian)) {
|
||||
free(ptr);
|
||||
if(!read_uint16(fd, &ffff, big_endian))
|
||||
break;
|
||||
}
|
||||
if (ffff == 0xFFFF) {
|
||||
lseek(fd, 2, SEEK_CUR);
|
||||
if(!read_uint16(fd, &ffff, big_endian)) {
|
||||
free(ptr);
|
||||
if(!read_uint16(fd, &ffff, big_endian))
|
||||
break;
|
||||
}
|
||||
lseek(fd, ffff + 8, SEEK_CUR);
|
||||
} else
|
||||
lseek(fd, ffff + 10, SEEK_CUR);
|
||||
|
||||
if(!read_uint16(fd, &byte_count, big_endian)) {
|
||||
free(ptr);
|
||||
if(!read_uint16(fd, &byte_count, big_endian))
|
||||
break;
|
||||
}
|
||||
lseek(fd, (8 * byte_count) + 5, SEEK_CUR);
|
||||
if(!read_uint32(fd, &offset, big_endian)) {
|
||||
free(ptr);
|
||||
if(!read_uint32(fd, &offset, big_endian))
|
||||
break;
|
||||
}
|
||||
cli_dbgmsg("offset: %u\n", (unsigned int)offset);
|
||||
cli_dbgmsg("vba_readdir: offset: %u\n", (unsigned int)offset);
|
||||
vba_project->offset[i] = offset;
|
||||
vba_project->name[i] = ptr;
|
||||
lseek(fd, 2, SEEK_CUR);
|
||||
}
|
||||
|
||||
|
@ -462,10 +424,8 @@ cli_vba_readdir(const char *dir)
|
|||
close(fd);
|
||||
|
||||
if(i < record_count) {
|
||||
while(--i >= 0)
|
||||
free(vba_project->name[i]);
|
||||
|
||||
free(vba_project->name);
|
||||
free(vba_project->colls);
|
||||
free(vba_project->dir);
|
||||
free(vba_project->offset);
|
||||
free(vba_project);
|
||||
|
@ -585,66 +545,68 @@ ole_copy_file_data(int s, int d, uint32_t len)
|
|||
}
|
||||
|
||||
int
|
||||
cli_decode_ole_object(int fd, const char *dir)
|
||||
cli_scan_ole10(int fd, cli_ctx *ctx)
|
||||
{
|
||||
int ofd;
|
||||
int ofd, ret;
|
||||
uint32_t object_size;
|
||||
struct stat statbuf;
|
||||
char *fullname;
|
||||
|
||||
if(dir == NULL)
|
||||
return -1;
|
||||
|
||||
if(fd < 0)
|
||||
return -1;
|
||||
return CL_CLEAN;
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
if(!read_uint32(fd, &object_size, FALSE))
|
||||
return -1;
|
||||
return CL_CLEAN;
|
||||
|
||||
if(fstat(fd, &statbuf) == -1)
|
||||
return -1;
|
||||
return CL_EIO;
|
||||
|
||||
if ((statbuf.st_size - object_size) >= 4) {
|
||||
/* Probably the OLE type id */
|
||||
if (lseek(fd, 2, SEEK_CUR) == -1) {
|
||||
return -1;
|
||||
return CL_CLEAN;
|
||||
}
|
||||
|
||||
/* Attachment name */
|
||||
if(!skip_past_nul(fd))
|
||||
return -1;
|
||||
return CL_CLEAN;
|
||||
|
||||
/* Attachment full path */
|
||||
if(!skip_past_nul(fd))
|
||||
return -1;
|
||||
return CL_CLEAN;
|
||||
|
||||
/* ??? */
|
||||
if(lseek(fd, 8, SEEK_CUR) == -1)
|
||||
return -1;
|
||||
return CL_CLEAN;
|
||||
|
||||
/* Attachment full path */
|
||||
if(!skip_past_nul(fd))
|
||||
return -1;
|
||||
return CL_CLEAN;
|
||||
|
||||
if(!read_uint32(fd, &object_size, FALSE))
|
||||
return -1;
|
||||
return CL_CLEAN;
|
||||
}
|
||||
if(!(fullname = cli_gentemp(dir))) {
|
||||
return -1;
|
||||
if(!(fullname = cli_gentemp(NULL))) {
|
||||
return CL_EMEM;
|
||||
}
|
||||
ofd = open(fullname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY|O_EXCL,
|
||||
S_IWUSR|S_IRUSR);
|
||||
if (ofd < 0) {
|
||||
cli_warnmsg("cli_decode_ole_object: can't create %s\n", fullname);
|
||||
free(fullname);
|
||||
return -1;
|
||||
} else {
|
||||
cli_dbgmsg("cli_decode_ole_object: decoding to %s\n", fullname);
|
||||
return CL_EIO;
|
||||
}
|
||||
free(fullname);
|
||||
cli_dbgmsg("cli_decode_ole_object: decoding to %s\n", fullname);
|
||||
ole_copy_file_data(fd, ofd, object_size);
|
||||
lseek(ofd, 0, SEEK_SET);
|
||||
return ofd;
|
||||
ret = cli_magic_scandesc(ofd, ctx);
|
||||
close(ofd);
|
||||
if(!cli_leavetemps_flag)
|
||||
if (cli_unlink(fullname))
|
||||
ret = CL_EIO;
|
||||
free(fullname);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -797,23 +759,10 @@ ppt_stream_iter(int fd, const char *dir)
|
|||
}
|
||||
|
||||
char *
|
||||
cli_ppt_vba_read(const char *filename)
|
||||
cli_ppt_vba_read(int ifd)
|
||||
{
|
||||
char *dir;
|
||||
const char *ret;
|
||||
int fd;
|
||||
char fullname[NAME_MAX + 1];
|
||||
|
||||
if(filename == NULL)
|
||||
return NULL;
|
||||
|
||||
snprintf(fullname, sizeof(fullname) - 1, "%s/PowerPoint Document",
|
||||
filename);
|
||||
fd = open(fullname, O_RDONLY|O_BINARY);
|
||||
if (fd == -1) {
|
||||
cli_dbgmsg("Open PowerPoint Document failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create a directory to store the extracted OLE2 objects */
|
||||
dir = cli_gentemp(NULL);
|
||||
|
@ -824,8 +773,7 @@ cli_ppt_vba_read(const char *filename)
|
|||
free(dir);
|
||||
return NULL;
|
||||
}
|
||||
ret = ppt_stream_iter(fd, dir);
|
||||
close(fd);
|
||||
ret = ppt_stream_iter(ifd, dir);
|
||||
if(ret == NULL) {
|
||||
cli_rmdirs(dir);
|
||||
free(dir);
|
||||
|
@ -1083,43 +1031,32 @@ word_skip_macro_intnames(int fd)
|
|||
}
|
||||
|
||||
vba_project_t *
|
||||
cli_wm_readdir(const char *dir)
|
||||
cli_wm_readdir(int fd)
|
||||
{
|
||||
int fd, done;
|
||||
int done;
|
||||
off_t end_offset;
|
||||
unsigned char info_id;
|
||||
macro_info_t macro_info;
|
||||
vba_project_t *vba_project;
|
||||
mso_fib_t fib;
|
||||
char fullname[NAME_MAX + 1];
|
||||
uint32_t hash, hashcnt;
|
||||
char fullname[1024];
|
||||
|
||||
if(dir == NULL)
|
||||
|
||||
if (!word_read_fib(fd, &fib))
|
||||
return NULL;
|
||||
|
||||
snprintf(fullname, sizeof(fullname) - 1, "%s/WordDocument", dir);
|
||||
fd = open(fullname, O_RDONLY|O_BINARY);
|
||||
if (fd == -1) {
|
||||
cli_dbgmsg("Open WordDocument failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!word_read_fib(fd, &fib)) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
if(fib.macro_len == 0) {
|
||||
cli_dbgmsg("No macros detected\n");
|
||||
cli_dbgmsg("wm_readdir: No macros detected\n");
|
||||
/* Must be clean */
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
cli_dbgmsg("macro offset: 0x%.4x\n", (int)fib.macro_offset);
|
||||
cli_dbgmsg("macro len: 0x%.4x\n\n", (int)fib.macro_len);
|
||||
cli_dbgmsg("wm_readdir: macro offset: 0x%.4x\n", (int)fib.macro_offset);
|
||||
cli_dbgmsg("wm_readdir: macro len: 0x%.4x\n\n", (int)fib.macro_len);
|
||||
|
||||
/* Go one past the start to ignore start_id */
|
||||
if (lseek(fd, fib.macro_offset + 1, SEEK_SET) != (off_t)(fib.macro_offset + 1)) {
|
||||
cli_dbgmsg("lseek macro_offset failed\n");
|
||||
close(fd);
|
||||
cli_dbgmsg("wm_readdir: lseek macro_offset failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1129,7 +1066,7 @@ cli_wm_readdir(const char *dir)
|
|||
|
||||
while((lseek(fd, 0, SEEK_CUR) < end_offset) && !done) {
|
||||
if (cli_readn(fd, &info_id, 1) != 1) {
|
||||
cli_dbgmsg("read macro_info failed\n");
|
||||
cli_dbgmsg("wm_readdir: read macro_info failed\n");
|
||||
break;
|
||||
}
|
||||
switch (info_id) {
|
||||
|
@ -1160,17 +1097,16 @@ cli_wm_readdir(const char *dir)
|
|||
done = TRUE;
|
||||
break;
|
||||
default:
|
||||
cli_dbgmsg("unknown type: 0x%x\n", info_id);
|
||||
cli_dbgmsg("wm_readdir: unknown type: 0x%x\n", info_id);
|
||||
done = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
if(macro_info.count == 0)
|
||||
return NULL;
|
||||
|
||||
vba_project = create_vba_project(macro_info.count, dir);
|
||||
vba_project = create_vba_project(macro_info.count, "", NULL);
|
||||
|
||||
if(vba_project) {
|
||||
vba_project->length = (uint32_t *)cli_malloc(sizeof(uint32_t) *
|
||||
|
@ -1183,7 +1119,6 @@ cli_wm_readdir(const char *dir)
|
|||
const macro_entry_t *m = macro_info.entries;
|
||||
|
||||
for(i = 0; i < macro_info.count; i++) {
|
||||
vba_project->name[i] = cli_strdup("WordDocument");
|
||||
vba_project->offset[i] = m->offset;
|
||||
vba_project->length[i] = m->len;
|
||||
vba_project->key[i] = m->key;
|
||||
|
@ -1191,6 +1126,7 @@ cli_wm_readdir(const char *dir)
|
|||
}
|
||||
} else {
|
||||
free(vba_project->name);
|
||||
free(vba_project->colls);
|
||||
free(vba_project->dir);
|
||||
free(vba_project->offset);
|
||||
if(vba_project->length)
|
||||
|
@ -1295,7 +1231,7 @@ seekandread(int fd, off_t offset, int whence, void *data, size_t len)
|
|||
* Create and initialise a vba_project structure
|
||||
*/
|
||||
static vba_project_t *
|
||||
create_vba_project(int record_count, const char *dir)
|
||||
create_vba_project(int record_count, const char *dir, struct uniq *U)
|
||||
{
|
||||
vba_project_t *ret;
|
||||
|
||||
|
@ -1304,13 +1240,16 @@ create_vba_project(int record_count, const char *dir)
|
|||
if(ret == NULL)
|
||||
return NULL;
|
||||
|
||||
ret->name = (char **)cli_malloc(sizeof(char *) * record_count);
|
||||
ret->name = (uint32_t *)cli_malloc(sizeof(uint32_t) * record_count);
|
||||
ret->colls = (uint32_t *)cli_malloc(sizeof(uint32_t) * record_count);
|
||||
ret->dir = cli_strdup(dir);
|
||||
ret->offset = (uint32_t *)cli_malloc (sizeof(uint32_t) * record_count);
|
||||
|
||||
if((ret->name == NULL) || (ret->dir == NULL) || (ret->offset == NULL)) {
|
||||
if(ret->dir)
|
||||
free(ret->dir);
|
||||
if(ret->colls)
|
||||
free(ret->colls);
|
||||
if(ret->name)
|
||||
free(ret->name);
|
||||
if(ret->offset)
|
||||
|
@ -1319,6 +1258,7 @@ create_vba_project(int record_count, const char *dir)
|
|||
return NULL;
|
||||
}
|
||||
ret->count = record_count;
|
||||
ret->U = U;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -23,22 +23,26 @@
|
|||
#ifndef __VBA_EXTRACT_H
|
||||
#define __VBA_EXTRACT_H
|
||||
|
||||
#include "others.h"
|
||||
#include "cltypes.h"
|
||||
#include "hashtab.h"
|
||||
|
||||
typedef struct vba_project_tag {
|
||||
char **name;
|
||||
uint32_t *name;
|
||||
uint32_t *colls;
|
||||
uint32_t *offset;
|
||||
uint32_t *length; /* for Word 6 macros */
|
||||
unsigned char *key; /* for Word 6 macros */
|
||||
char *dir;
|
||||
struct uniq *U;
|
||||
int count;
|
||||
} vba_project_t;
|
||||
|
||||
vba_project_t *cli_vba_readdir(const char *dir);
|
||||
vba_project_t *cli_vba_readdir(const char *dir, struct uniq *U, uint32_t which);
|
||||
vba_project_t *cli_wm_readdir(int fd);
|
||||
unsigned char *cli_vba_inflate(int fd, off_t offset, int *size);
|
||||
int cli_decode_ole_object(int fd, const char *dir);
|
||||
char *cli_ppt_vba_read(const char *filename);
|
||||
vba_project_t *cli_wm_readdir(const char *dir);
|
||||
int cli_scan_ole10(int fd, cli_ctx *ctx);
|
||||
char *cli_ppt_vba_read(int fd);
|
||||
unsigned char *cli_wm_decrypt_macro(int fd, off_t offset, uint32_t len,
|
||||
unsigned char key);
|
||||
|
||||
|
|
|
@ -293,6 +293,7 @@ struct cfgstruct *getcfg(const char *cfgfile, int verbose)
|
|||
if(ctype == 'm' || ctype == 'k') {
|
||||
char *cpy = (char *) calloc(strlen(arg), 1);
|
||||
strncpy(cpy, arg, strlen(arg) - 1);
|
||||
cpy[strlen(arg)-1]='\0';
|
||||
if(!cli_isnumber(cpy)) {
|
||||
if(verbose)
|
||||
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name);
|
||||
|
|
|
@ -72,6 +72,7 @@ int tar_addfile(int fd, gzFile *gzs, const char *file)
|
|||
|
||||
memset(&hdr, 0, TARBLK);
|
||||
strncpy(hdr.name, file, 100);
|
||||
hdr.name[99]='\0';
|
||||
snprintf(hdr.size, 12, "%o", (unsigned int) sb.st_size);
|
||||
pt = (unsigned char *) &hdr;
|
||||
for(i = 0; i < TARBLK; i++)
|
||||
|
|
|
@ -258,6 +258,7 @@ static char *getdsig(const char *host, const char *user, const unsigned char *da
|
|||
|
||||
if((pt = getenv("SIGNDPASS"))) {
|
||||
strncpy(pass, pt, sizeof(pass));
|
||||
pass[sizeof(pass)-1]='\0';
|
||||
} else {
|
||||
mprintf("Password: ");
|
||||
|
||||
|
@ -281,12 +282,13 @@ static char *getdsig(const char *host, const char *user, const unsigned char *da
|
|||
return NULL;
|
||||
}
|
||||
strncpy(pass, pt, sizeof(pass));
|
||||
pass[sizeof(pass)-1]='\0';
|
||||
free(pt);
|
||||
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
if(tcsetattr(0, TCSAFLUSH, &old)) {
|
||||
mprintf("!getdsig: tcsetattr() failed\n");
|
||||
memset(pass, 0, strlen(pass));
|
||||
memset(pass, 0, sizeof(pass));
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
@ -300,7 +302,7 @@ static char *getdsig(const char *host, const char *user, const unsigned char *da
|
|||
#endif
|
||||
perror("socket()");
|
||||
mprintf("!getdsig: Can't create socket\n");
|
||||
memset(pass, 0, strlen(pass));
|
||||
memset(pass, 0, sizeof(pass));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -312,7 +314,7 @@ static char *getdsig(const char *host, const char *user, const unsigned char *da
|
|||
close(sockd);
|
||||
perror("connect()");
|
||||
mprintf("!getdsig: Can't connect to ClamAV Signing Service at %s\n", host);
|
||||
memset(pass, 0, strlen(pass));
|
||||
memset(pass, 0, sizeof(pass));
|
||||
return NULL;
|
||||
}
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
|
@ -330,13 +332,13 @@ static char *getdsig(const char *host, const char *user, const unsigned char *da
|
|||
if(write(sockd, cmd, len) < 0) {
|
||||
mprintf("!getdsig: Can't write to socket\n");
|
||||
close(sockd);
|
||||
memset(cmd, 0, len);
|
||||
memset(pass, 0, strlen(pass));
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
memset(pass, 0, sizeof(pass));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(cmd, 0, len);
|
||||
memset(pass, 0, strlen(pass));
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
memset(pass, 0, sizeof(pass));
|
||||
memset(buff, 0, sizeof(buff));
|
||||
|
||||
if((bread = cli_readn(sockd, buff, sizeof(buff))) > 0) {
|
||||
|
@ -587,6 +589,7 @@ static int build(struct optstruct *opt)
|
|||
if(opt->filename) {
|
||||
if(cli_strbcasestr(opt->filename, ".cvd") || cli_strbcasestr(opt->filename, ".cld")) {
|
||||
strncpy(olddb, opt->filename, sizeof(olddb));
|
||||
olddb[sizeof(olddb)-1]='\0';
|
||||
} else {
|
||||
mprintf("!build: Not a CVD/CLD file\n");
|
||||
return -1;
|
||||
|
@ -655,6 +658,7 @@ static int build(struct optstruct *opt)
|
|||
|
||||
if((pt = getenv("SIGNDUSER"))) {
|
||||
strncpy(builder, pt, sizeof(builder));
|
||||
builder[sizeof(builder)-1]='\0';
|
||||
} else {
|
||||
mprintf("Builder name: ");
|
||||
if(scanf("%as", &pt) == EOF) {
|
||||
|
@ -662,6 +666,7 @@ static int build(struct optstruct *opt)
|
|||
return -1;
|
||||
}
|
||||
strncpy(builder, pt, sizeof(builder));
|
||||
builder[sizeof(builder)-1]='\0';
|
||||
free(pt);
|
||||
}
|
||||
|
||||
|
@ -816,6 +821,7 @@ static int build(struct optstruct *opt)
|
|||
return -1;
|
||||
}
|
||||
strncpy(olddb, pt, sizeof(olddb));
|
||||
olddb[sizeof(olddb)-1]='\0';
|
||||
free(pt);
|
||||
|
||||
if(!(pt = cli_gentemp(NULL))) {
|
||||
|
@ -896,6 +902,7 @@ static int unpack(struct optstruct *opt)
|
|||
|
||||
} else {
|
||||
strncpy(name, opt_arg(opt, "unpack"), sizeof(name));
|
||||
name[sizeof(name)-1]='\0';
|
||||
}
|
||||
|
||||
if(cvd_unpack(name, ".") == -1) {
|
||||
|
@ -1171,6 +1178,7 @@ static int vbadump(struct optstruct *opt)
|
|||
int fd, hex_output;
|
||||
char *dir;
|
||||
const char *pt;
|
||||
struct uniq *vba;
|
||||
|
||||
|
||||
if(opt_check(opt, "vba-hex")) {
|
||||
|
@ -1200,15 +1208,15 @@ static int vbadump(struct optstruct *opt)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if(cli_ole2_extract(fd, dir, NULL)) {
|
||||
if(cli_ole2_extract(fd, dir, NULL, &vba)) {
|
||||
cli_rmdirs(dir);
|
||||
free(dir);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
sigtool_vba_scandir(dir, hex_output);
|
||||
if (vba)
|
||||
sigtool_vba_scandir(dir, hex_output, vba);
|
||||
cli_rmdirs(dir);
|
||||
free(dir);
|
||||
return 0;
|
||||
|
@ -1305,6 +1313,7 @@ static int compare(const char *oldpath, const char *newpath, FILE *diff)
|
|||
|
||||
if(found) {
|
||||
strncpy(tbuff, obuff, sizeof(tbuff));
|
||||
tbuff[sizeof(tbuff)-1]='\0';
|
||||
for(i = 0; i < tline; i++) {
|
||||
tbuff[16] = 0;
|
||||
if((pt = strchr(tbuff, ' ')))
|
||||
|
|
170
sigtool/vba.c
170
sigtool/vba.c
|
@ -33,6 +33,10 @@
|
|||
#include "libclamav/cltypes.h"
|
||||
#include "libclamav/ole2_extract.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
typedef struct mac_token_tag
|
||||
{
|
||||
unsigned char token;
|
||||
|
@ -46,7 +50,7 @@ typedef struct mac_token2_tag
|
|||
|
||||
} mac_token2_t;
|
||||
|
||||
int sigtool_vba_scandir(const char *dirname, int hex_output);
|
||||
int sigtool_vba_scandir(const char *dirname, int hex_output, struct uniq *U);
|
||||
|
||||
static char *get_unicode_name (char *name, int size)
|
||||
{
|
||||
|
@ -979,6 +983,7 @@ static int sigtool_scandir (const char *dirname, int hex_output)
|
|||
}
|
||||
} else {
|
||||
if (S_ISREG (statbuf.st_mode)) {
|
||||
struct uniq *vba;
|
||||
tmpdir = getenv ("TMPDIR");
|
||||
|
||||
if (tmpdir == NULL)
|
||||
|
@ -1000,14 +1005,14 @@ static int sigtool_scandir (const char *dirname, int hex_output)
|
|||
return 1;
|
||||
}
|
||||
|
||||
if ((ret = cli_ole2_extract (desc, dir, NULL))) {
|
||||
if ((ret = cli_ole2_extract (desc, dir, NULL, &vba))) {
|
||||
printf ("ERROR %s\n", cl_strerror (ret));
|
||||
cli_rmdirs (dir);
|
||||
free (dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sigtool_vba_scandir (dir, hex_output);
|
||||
sigtool_vba_scandir (dir, hex_output, vba);
|
||||
|
||||
cli_rmdirs (dir);
|
||||
free (dir);
|
||||
|
@ -1028,94 +1033,93 @@ static int sigtool_scandir (const char *dirname, int hex_output)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sigtool_vba_scandir (const char *dirname, int hex_output)
|
||||
int sigtool_vba_scandir (const char *dirname, int hex_output, struct uniq *U)
|
||||
{
|
||||
int ret = CL_CLEAN, i, fd, data_len;
|
||||
int ret = CL_CLEAN, i, j, fd, data_len;
|
||||
vba_project_t *vba_project;
|
||||
DIR *dd;
|
||||
struct dirent *dent;
|
||||
struct stat statbuf;
|
||||
char *fname, *fullname;
|
||||
char *fullname, vbaname[1024];
|
||||
unsigned char *data;
|
||||
uint32_t hashcnt, hash;
|
||||
|
||||
cli_dbgmsg ("VBA scan dir: %s\n", dirname);
|
||||
if ((vba_project = (vba_project_t *)cli_vba_readdir(dirname))) {
|
||||
hashcnt = uniq_get(U, "_vba_project", 12, NULL);
|
||||
while(hashcnt--) {
|
||||
if(!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) continue;
|
||||
|
||||
for (i = 0; i < vba_project->count; i++) {
|
||||
fullname = (char *) malloc (strlen (vba_project->dir) + strlen (vba_project->name[i]) + 2);
|
||||
sprintf (fullname, "%s/%s", vba_project->dir, vba_project->name[i]);
|
||||
fd = open (fullname, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
cli_errmsg ("Scan->OLE2 -> Can't open file %s\n", fullname);
|
||||
free (fullname);
|
||||
ret = CL_EOPEN;
|
||||
break;
|
||||
for(i = 0; i < vba_project->count; i++) {
|
||||
for(j = 0; j < vba_project->colls[i]; j++) {
|
||||
snprintf(vbaname, 1024, "%s/%u_%u", vba_project->dir, vba_project->name[i], j);
|
||||
vbaname[sizeof(vbaname)-1] = '\0';
|
||||
fd = open(vbaname, O_RDONLY|O_BINARY);
|
||||
if(fd == -1) continue;
|
||||
data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
|
||||
close(fd);
|
||||
|
||||
if(data) {
|
||||
data = (unsigned char *) realloc (data, data_len + 1);
|
||||
data[data_len]='\0';
|
||||
printf ("-------------- start of code ------------------\n%s\n-------------- end of code ------------------\n", data);
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
free (fullname);
|
||||
cli_dbgmsg ("decompress VBA project '%s'\n", vba_project->name[i]);
|
||||
printf ("-------------- start of %s ------------------\n", vba_project->name[i]);
|
||||
data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
|
||||
close (fd);
|
||||
|
||||
if (!data) {
|
||||
cli_dbgmsg ("WARNING: VBA project '%s' decompressed to NULL\n", vba_project->name[i]);
|
||||
} else {
|
||||
data = (unsigned char *) realloc (data, data_len + 1);
|
||||
data[data_len] = '\0';
|
||||
printf ("%s", data);
|
||||
free (data);
|
||||
|
||||
}
|
||||
printf ("-------------- end of %s ------------------\n", vba_project->name[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < vba_project->count; i++)
|
||||
free (vba_project->name[i]);
|
||||
free (vba_project->name);
|
||||
free (vba_project->dir);
|
||||
free (vba_project->offset);
|
||||
free (vba_project);
|
||||
} else if ((fullname = cli_ppt_vba_read(dirname))) {
|
||||
if (sigtool_scandir (fullname, hex_output) == CL_VIRUS) {
|
||||
ret = CL_VIRUS;
|
||||
}
|
||||
cli_rmdirs (fullname);
|
||||
free (fullname);
|
||||
} else if ((vba_project = (vba_project_t *)cli_wm_readdir(dirname))) {
|
||||
for (i = 0; i < vba_project->count; i++) {
|
||||
fullname = (char *) malloc (strlen (vba_project->dir) + strlen (vba_project->name[i]) + 2);
|
||||
sprintf (fullname, "%s/%s", vba_project->dir, vba_project->name[i]);
|
||||
fd = open (fullname, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
cli_errmsg ("Scan->OLE2 -> Can't open file %s\n", fullname);
|
||||
free (fullname);
|
||||
ret = CL_EOPEN;
|
||||
break;
|
||||
}
|
||||
free (fullname);
|
||||
cli_dbgmsg ("decompress WM project '%s' macro %d\n", vba_project->name[i], i);
|
||||
printf ("\n\n-------------- start of macro:%d key:%d length:%d ------------------\n", i,
|
||||
vba_project->key[i], vba_project->length[i]);
|
||||
data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], vba_project->length[i],
|
||||
vba_project->key[i]);
|
||||
close (fd);
|
||||
free(vba_project->name);
|
||||
free(vba_project->colls);
|
||||
free(vba_project->dir);
|
||||
free(vba_project->offset);
|
||||
free(vba_project);
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
cli_dbgmsg ("WARNING: WM project '%s' macro %d decrypted to NULL\n", vba_project->name[i], i);
|
||||
} else {
|
||||
wm_decode_macro (data, vba_project->length[i], hex_output);
|
||||
free (data);
|
||||
}
|
||||
printf ("\n-------------- end of macro %d ------------------\n\n", i);
|
||||
|
||||
if((hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
|
||||
while(hashcnt--) {
|
||||
snprintf(vbaname, 1024, "%s/%u_%u", dirname, hash, hashcnt);
|
||||
vbaname[sizeof(vbaname)-1] = '\0';
|
||||
fd = open(vbaname, O_RDONLY|O_BINARY);
|
||||
if (fd == -1) continue;
|
||||
if ((fullname = cli_ppt_vba_read(fd)))
|
||||
sigtool_scandir(fullname, hex_output);
|
||||
cli_rmdirs(fullname);
|
||||
free(fullname);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((hashcnt = uniq_get(U, "worddocument", 12, &hash))) {
|
||||
while(hashcnt--) {
|
||||
snprintf(vbaname, sizeof(vbaname), "%s/%u_%u", dirname, hash, hashcnt);
|
||||
vbaname[sizeof(vbaname)-1] = '\0';
|
||||
fd = open(vbaname, O_RDONLY|O_BINARY);
|
||||
if (fd == -1) continue;
|
||||
|
||||
if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd))) {
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < vba_project->count; i++) {
|
||||
data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], vba_project->length[i], vba_project->key[i]);
|
||||
if(data) {
|
||||
data = (unsigned char *) realloc (data, data_len + 1);
|
||||
data[data_len]='\0';
|
||||
printf ("-------------- start of code ------------------\n%s\n-------------- end of code ------------------\n", data);
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
free(vba_project->name);
|
||||
free(vba_project->colls);
|
||||
free(vba_project->dir);
|
||||
free(vba_project->offset);
|
||||
free(vba_project->key);
|
||||
free(vba_project->length);
|
||||
free(vba_project);
|
||||
}
|
||||
for (i = 0; i < vba_project->count; i++)
|
||||
free (vba_project->name[i]);
|
||||
free (vba_project->key);
|
||||
free (vba_project->length);
|
||||
free (vba_project->offset);
|
||||
free (vba_project->name);
|
||||
free (vba_project->dir);
|
||||
free (vba_project);
|
||||
}
|
||||
|
||||
if ((dd = opendir (dirname)) != NULL) {
|
||||
|
@ -1123,15 +1127,15 @@ int sigtool_vba_scandir (const char *dirname, int hex_output)
|
|||
if (dent->d_ino) {
|
||||
if (strcmp (dent->d_name, ".") && strcmp (dent->d_name, "..")) {
|
||||
/* build the full name */
|
||||
fname = calloc (strlen (dirname) + strlen (dent->d_name) + 2, sizeof (char));
|
||||
sprintf (fname, "%s/%s", dirname, dent->d_name);
|
||||
fullname = calloc (strlen (dirname) + strlen (dent->d_name) + 2, sizeof (char));
|
||||
sprintf (fullname, "%s/%s", dirname, dent->d_name);
|
||||
|
||||
/* stat the file */
|
||||
if (lstat (fname, &statbuf) != -1) {
|
||||
if (lstat (fullname, &statbuf) != -1) {
|
||||
if (S_ISDIR (statbuf.st_mode) && !S_ISLNK (statbuf.st_mode))
|
||||
sigtool_vba_scandir (fname, hex_output);
|
||||
sigtool_vba_scandir (fullname, hex_output, U);
|
||||
}
|
||||
free (fname);
|
||||
free (fullname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#ifndef __VBA_H
|
||||
#define __VBA_H
|
||||
|
||||
int sigtool_vba_scandir(const char *dirname, int hex_output);
|
||||
#include "libclamav/hashtab.h"
|
||||
int sigtool_vba_scandir(const char *dirname, int hex_output, struct uniq *U);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue