improve handling of PDF, CAB, RTF, OLE2 and HTML files (sync with branch/0.93)

git-svn: trunk@3862
This commit is contained in:
Tomasz Kojm 2008-05-27 16:30:47 +00:00
parent cb4e478c1a
commit 72ce4b70eb
34 changed files with 917 additions and 672 deletions

View file

@ -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) Sat May 24 21:38:47 EEST 2008 (edwin)
------------------------------------- -------------------------------------
* clamd/others.c, session.c, m4/fdpassing.m4: * clamd/others.c, session.c, m4/fdpassing.m4:

View file

@ -1167,6 +1167,7 @@ main(int argc, char **argv)
memset(&ifr, '\0', sizeof(struct ifreq)); memset(&ifr, '\0', sizeof(struct ifreq));
strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1); 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) { if(setsockopt(broadcastSock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) {
perror(iface); perror(iface);
return EX_CONFIG; return EX_CONFIG;
@ -1515,6 +1516,7 @@ main(int argc, char **argv)
memset((char *)&sockun, 0, sizeof(struct sockaddr_un)); memset((char *)&sockun, 0, sizeof(struct sockaddr_un));
sockun.sun_family = AF_UNIX; sockun.sun_family = AF_UNIX;
strncpy(sockun.sun_path, localSocket, sizeof(sockun.sun_path)); 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)); sessions = (struct session *)cli_malloc(sizeof(struct session));
if((sessions[0].sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { 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)); memset((char *)&server, 0, sizeof(struct sockaddr_un));
server.sun_family = AF_UNIX; server.sun_family = AF_UNIX;
strncpy(server.sun_path, localSocket, sizeof(server.sun_path)); 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) { if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror(localSocket); perror(localSocket);
@ -2749,6 +2752,7 @@ clamfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
} }
#else #else
strncpy(ip, (char *)inet_ntoa(*(struct in_addr *)hostent.h_addr), sizeof(ip)); strncpy(ip, (char *)inet_ntoa(*(struct in_addr *)hostent.h_addr), sizeof(ip));
ip[sizeof(ip)-1]='\0';
#endif #endif
/* /*
@ -3409,6 +3413,7 @@ clamfi_eom(SMFICTX *ctx)
memset((char *)&server, 0, sizeof(struct sockaddr_un)); memset((char *)&server, 0, sizeof(struct sockaddr_un));
server.sun_family = AF_UNIX; server.sun_family = AF_UNIX;
strncpy(server.sun_path, localSocket, sizeof(server.sun_path)); 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) { if(connect(privdata->cmdSocket, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) < 0) {
perror(localSocket); perror(localSocket);
@ -3530,19 +3535,20 @@ clamfi_eom(SMFICTX *ctx)
const char *j = smfi_getsymval(ctx, "{j}"); const char *j = smfi_getsymval(ctx, "{j}");
if(j) if(j)
strncpy(hostname, j, strncpy(hostname, j, sizeof(hostname) - 1);
sizeof(hostname) - 1);
else else
strcpy(hostname, _("Error determining host")); strcpy(hostname, _("Error determining host"));
hostname[sizeof(hostname)-1]='\0';
} else if(strchr(hostname, '.') == NULL) { } else if(strchr(hostname, '.') == NULL) {
/* /*
* Determine fully qualified name * Determine fully qualified name
*/ */
struct hostent hostent; struct hostent hostent;
if((r_gethostbyname(hostname, &hostent, buf, sizeof(buf)) == 0) && if((r_gethostbyname(hostname, &hostent, buf, sizeof(buf)) == 0) && hostent.h_name) {
hostent.h_name)
strncpy(hostname, hostent.h_name, sizeof(hostname)); strncpy(hostname, hostent.h_name, sizeof(hostname));
hostname[sizeof(hostname)-1]='\0';
}
} }
#ifdef SESSION #ifdef SESSION
@ -4557,6 +4563,7 @@ connect2clamd(struct privdata *privdata)
memset((char *)&server, 0, sizeof(struct sockaddr_un)); memset((char *)&server, 0, sizeof(struct sockaddr_un));
server.sun_family = AF_UNIX; server.sun_family = AF_UNIX;
strncpy(server.sun_path, localSocket, sizeof(server.sun_path)); 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) { if((privdata->cmdSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("socket"); perror("socket");
@ -6405,6 +6412,7 @@ spf(struct privdata *privdata, table_t *prevhosts)
continue; continue;
} }
strncpy(txt, (const char *)&p[1], sizeof(txt) - 1); strncpy(txt, (const char *)&p[1], sizeof(txt) - 1);
txt[sizeof(txt)-1]='\0';
txt[len - 1] = '\0'; txt[len - 1] = '\0';
if((strncmp(txt, "v=spf1 ", 7) == 0) || (strncmp(txt, "spf2.0/pra ", 11) == 0)) { if((strncmp(txt, "v=spf1 ", 7) == 0) || (strncmp(txt, "spf2.0/pra ", 11) == 0)) {
int j; int j;

View file

@ -173,11 +173,13 @@ int dazukoRegister_TS(dazuko_id_t **dazuko_id, const char *groupName, const char
if (strcasecmp(mode, "r") == 0) if (strcasecmp(mode, "r") == 0)
{ {
strncpy(regMode, "R", sizeof(regMode)); strncpy(regMode, "R", sizeof(regMode));
regMode[sizeof(regMode)-1]='\0';
write_mode = 0; write_mode = 0;
} }
else if (strcasecmp(mode, "r+") == 0 || strcasecmp(mode, "rw") == 0) else if (strcasecmp(mode, "r+") == 0 || strcasecmp(mode, "rw") == 0)
{ {
strncpy(regMode, "RW", sizeof(regMode)); strncpy(regMode, "RW", sizeof(regMode));
regMode[sizeof(regMode)-1]='\0';
write_mode = 1; write_mode = 1;
} }
else else

View file

@ -116,6 +116,7 @@ int dazukoRegister_TS_compat12(struct dazuko_id *dazuko, const char *groupName)
opt->command = REGISTER; opt->command = REGISTER;
strncpy(opt->buffer, groupName, sizeof(opt->buffer) - 1); strncpy(opt->buffer, groupName, sizeof(opt->buffer) - 1);
opt->buffer[sizeof(opt->buffer)-1]='\0';
opt->buffer_length = strlen(opt->buffer) + 1; opt->buffer_length = strlen(opt->buffer) + 1;
if (ioctl(dazuko->device, _IOW(dazuko->dev_major, IOCTL_SET_OPTION, void *), opt) != 0) 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; opt->command = command;
strncpy(opt->buffer, path, sizeof(opt->buffer) - 1); strncpy(opt->buffer, path, sizeof(opt->buffer) - 1);
opt->buffer[sizeof(opt->buffer)-1]='\0';
opt->buffer_length = strlen(opt->buffer) + 1; opt->buffer_length = strlen(opt->buffer) + 1;
if (ioctl(dazuko->device, _IOW(dazuko->dev_major, IOCTL_SET_OPTION, void *), opt) != 0) if (ioctl(dazuko->device, _IOW(dazuko->dev_major, IOCTL_SET_OPTION, void *), opt) != 0)

View file

@ -64,6 +64,7 @@ int localserver(const struct cfgstruct *copt)
memset((char *) &server, 0, sizeof(server)); memset((char *) &server, 0, sizeof(server));
server.sun_family = AF_UNIX; server.sun_family = AF_UNIX;
strncpy(server.sun_path, cfgopt(copt, "LocalSocket")->strarg, sizeof(server.sun_path)); 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) { if((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
estr = strerror(errno); estr = strerror(errno);

View file

@ -376,6 +376,8 @@ int readsock(int sockfd, char *buf, size_t size, unsigned char delim, int timeou
break; break;
} else { } else {
n = recv(sockfd, buf+boff, n, 0); n = recv(sockfd, buf+boff, n, 0);
if(n < 0)
return -1;
if((boff+n) == size) if((boff+n) == size)
break; break;
boff += n; boff += n;

View file

@ -284,6 +284,7 @@ static int dconnect(const struct optstruct *opt)
server.sun_family = AF_UNIX; server.sun_family = AF_UNIX;
strncpy(server.sun_path, cpt->strarg, sizeof(server.sun_path)); 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) { if((sockd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("socket()"); perror("socket()");

View file

@ -226,6 +226,7 @@ int scanmanager(const struct optstruct *opt)
if(tolower(ptr[strlen(ptr) - 1]) == 'm') { if(tolower(ptr[strlen(ptr) - 1]) == 'm') {
cpy = calloc(strlen(ptr), 1); cpy = calloc(strlen(ptr), 1);
strncpy(cpy, ptr, strlen(ptr) - 1); strncpy(cpy, ptr, strlen(ptr) - 1);
cpy[strlen(ptr)-1]='\0';
limits.maxscansize = atoi(cpy) * 1024 * 1024; limits.maxscansize = atoi(cpy) * 1024 * 1024;
free(cpy); free(cpy);
} else } else
@ -239,6 +240,7 @@ int scanmanager(const struct optstruct *opt)
if(tolower(ptr[strlen(ptr) - 1]) == 'm') { if(tolower(ptr[strlen(ptr) - 1]) == 'm') {
cpy = calloc(strlen(ptr), 1); cpy = calloc(strlen(ptr), 1);
strncpy(cpy, ptr, strlen(ptr) - 1); strncpy(cpy, ptr, strlen(ptr) - 1);
cpy[strlen(ptr)-1]='\0';
limits.maxfilesize = atoi(cpy) * 1024 * 1024; limits.maxfilesize = atoi(cpy) * 1024 * 1024;
free(cpy); free(cpy);
} else } 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 */ if(tolower(ptr[strlen(ptr) - 1]) == 'm') { /* megabytes */
cpy = calloc(strlen(ptr), 1); cpy = calloc(strlen(ptr), 1);
strncpy(cpy, ptr, strlen(ptr) - 1); strncpy(cpy, ptr, strlen(ptr) - 1);
cpy[strlen(ptr)-1]='\0';
maxscansize = atoi(cpy) * 1024; maxscansize = atoi(cpy) * 1024;
free(cpy); free(cpy);
} else /* default - kilobytes */ } else /* default - kilobytes */

View file

@ -150,14 +150,17 @@ int match_regex(const char *filename, const char *pattern)
#else #else
if(pattern[strlen(pattern) - 1] == '\\') { if(pattern[strlen(pattern) - 1] == '\\') {
strncpy(fname, filename, 510); strncpy(fname, filename, 510);
fname[509]='\0';
len = strlen(fname); len = strlen(fname);
if(fname[len - 1] != '\\') { if(fname[len - 1] != '\\') {
fname[len] = '\\'; fname[len] = '\\';
fname[len + 1] = 0; fname[len + 1] = 0;
} }
#endif #endif
} else } else {
strncpy(fname, filename, 513); strncpy(fname, filename, 513);
fname[512]='\0';
}
match = (cli_regexec(&reg, fname, 0, NULL, 0) == REG_NOMATCH) ? 0 : 1; match = (cli_regexec(&reg, fname, 0, NULL, 0) == REG_NOMATCH) ? 0 : 1;
cli_regfree(&reg); cli_regfree(&reg);

View file

@ -73,6 +73,7 @@ int notify(const char *cfgfile)
socktype = "UNIX"; socktype = "UNIX";
server.sun_family = AF_UNIX; server.sun_family = AF_UNIX;
strncpy(server.sun_path, cpt->strarg, sizeof(server.sun_path)); 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) { if((sockd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
logg("^Clamd was NOT notified: Can't create socket endpoint for %s\n", cpt->strarg); logg("^Clamd was NOT notified: Can't create socket endpoint for %s\n", cpt->strarg);

View file

@ -122,7 +122,6 @@ static char *cab_readstr(int fd, int *ret)
} }
if(lseek(fd, (off_t) (pos + i + 1), SEEK_SET) == -1) { if(lseek(fd, (off_t) (pos + i + 1), SEEK_SET) == -1) {
/* *ret = CL_EIO; */
*ret = CL_EFORMAT; /* most likely a corrupted file */ *ret = CL_EFORMAT; /* most likely a corrupted file */
return NULL; return NULL;
} }
@ -136,15 +135,17 @@ static char *cab_readstr(int fd, int *ret)
return str; return str;
} }
static int cab_chkname(const char *name) static int cab_chkname(char *name, int san)
{ {
size_t i, len = strlen(name); size_t i, len = strlen(name);
for(i = 0; i < len; i++) { 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"); cli_dbgmsg("cab_chkname: File name contains disallowed characters\n");
return 1; 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) 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_file *file, *lfile = NULL;
struct cab_folder *folder, *lfolder = NULL; struct cab_folder *folder, *lfolder = NULL;
struct cab_hdr hdr; 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)) { if(cli_readn(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
cli_dbgmsg("cab_open: Can't read cabinet header\n"); cli_dbgmsg("cab_open: Can't read cabinet header\n");
/* return CL_EIO; */
return CL_EFORMAT; /* most likely a corrupted file */ 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); cab->length = EC32(hdr.cbCabinet);
cli_dbgmsg("CAB: Cabinet length: %u\n", cab->length); cli_dbgmsg("CAB: Cabinet length: %u\n", cab->length);
if((off_t) cab->length > rsize) { if((off_t) cab->length > rsize) {
cli_dbgmsg("CAB: Truncating file size from %lu to %lu\n", (unsigned long int) cab->length, (unsigned long int) rsize);
cab->length = (uint32_t) rsize; cab->length = (uint32_t) rsize;
bscore++;
} }
cab->nfolders = EC16(hdr.cFolders); 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) { if(cab->nfolders > CAB_FOLDER_LIMIT) {
cab->nfolders = CAB_FOLDER_LIMIT; cab->nfolders = CAB_FOLDER_LIMIT;
cli_dbgmsg("CAB: *** Number of folders limited to %u ***\n", cab->nfolders); 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) { if(cab->nfiles > CAB_FILE_LIMIT) {
cab->nfiles = CAB_FILE_LIMIT; cab->nfiles = CAB_FILE_LIMIT;
cli_dbgmsg("CAB: *** Number of files limited to %u ***\n", cab->nfiles); cli_dbgmsg("CAB: *** Number of files limited to %u ***\n", cab->nfiles);
bscore++;
} }
} }
cli_dbgmsg("CAB: File format version: %u.%u\n", hdr.versionMajor, hdr.versionMinor); 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); cab->flags = EC16(hdr.flags);
if(cab->flags & 0x0004) { if(cab->flags & 0x0004) {
if(cli_readn(fd, &hdr_opt, sizeof(hdr_opt)) != sizeof(hdr_opt)) { if(cli_readn(fd, &hdr_opt, sizeof(hdr_opt)) != sizeof(hdr_opt)) {
cli_dbgmsg("cab_open: Can't read file header (fake cab?)\n"); cli_dbgmsg("cab_open: Can't read file header (fake cab?)\n");
/* return CL_EIO; */
return CL_EFORMAT; /* most likely a corrupted file */ 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(cab->reshdr) {
if(lseek(fd, cab->reshdr, SEEK_CUR) == -1) { if(lseek(fd, cab->reshdr, SEEK_CUR) == -1) {
cli_dbgmsg("cab_open: Can't lseek to %u (fake cab?)\n", cab->reshdr); 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 */ 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); pt = cab_readstr(fd, &ret);
if(ret) if(ret)
return ret; return ret;
if(cab_chkname(pt)) if(cab_chkname(pt, 0))
badname = 1; cli_dbgmsg("CAB: Invalid name of preceeding cabinet\n");
else else
cli_dbgmsg("CAB: Preceeding cabinet name: %s\n", pt); cli_dbgmsg("CAB: Preceeding cabinet name: %s\n", pt);
free(pt); free(pt);
@ -301,8 +295,8 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
pt = cab_readstr(fd, &ret); pt = cab_readstr(fd, &ret);
if(ret) if(ret)
return ret; return ret;
if(cab_chkname(pt)) if(cab_chkname(pt, 0))
badname = 1; cli_dbgmsg("CAB: Invalid info for preceeding cabinet\n");
else else
cli_dbgmsg("CAB: Preceeding cabinet info: %s\n", pt); cli_dbgmsg("CAB: Preceeding cabinet info: %s\n", pt);
free(pt); free(pt);
@ -313,8 +307,8 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
pt = cab_readstr(fd, &ret); pt = cab_readstr(fd, &ret);
if(ret) if(ret)
return ret; return ret;
if(cab_chkname(pt)) if(cab_chkname(pt, 0))
badname = 1; cli_dbgmsg("CAB: Invalid name of next cabinet\n");
else else
cli_dbgmsg("CAB: Next cabinet name: %s\n", pt); cli_dbgmsg("CAB: Next cabinet name: %s\n", pt);
free(pt); free(pt);
@ -322,37 +316,37 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
pt = cab_readstr(fd, &ret); pt = cab_readstr(fd, &ret);
if(ret) if(ret)
return ret; return ret;
if(cab_chkname(pt)) if(cab_chkname(pt, 0))
badname = 1; cli_dbgmsg("CAB: Invalid info for next cabinet\n");
else else
cli_dbgmsg("CAB: Next cabinet info: %s\n", pt); cli_dbgmsg("CAB: Next cabinet info: %s\n", pt);
free(pt); free(pt);
} }
bscore += badname;
if(bscore >= 4) {
cli_dbgmsg("CAB: bscore == %u, most likely a fake cabinet\n", bscore);
return CL_EFORMAT;
}
/* folders */ /* folders */
for(i = 0; i < cab->nfolders; i++) { for(i = 0; i < cab->nfolders; i++) {
if(cli_readn(fd, &folder_hdr, sizeof(folder_hdr)) != sizeof(folder_hdr)) { 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); cli_dbgmsg("cab_open: Can't read header for folder %u\n", i);
cab_free(cab); break;
/* return CL_EIO; */
return CL_EFORMAT; /* most likely a corrupted file */
} }
if(resfold) { if(resfold) {
if(lseek(fd, resfold, SEEK_CUR) == -1) { if(lseek(fd, resfold, SEEK_CUR) == -1) {
cli_errmsg("cab_open: Can't lseek to %u (resfold)\n", (unsigned int) resfold); cli_dbgmsg("cab_open: Can't lseek to %u (resfold)\n", (unsigned int) resfold);
cab_free(cab); break;
/* return CL_EIO; */
return CL_EFORMAT; /* most likely a corrupted file */
} }
} }
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)); folder = (struct cab_folder *) cli_calloc(1, sizeof(struct cab_folder));
if(!folder) { if(!folder) {
cli_errmsg("cab_open: Can't allocate memory for folder\n"); 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->cab = (struct cab_archive *) cab;
folder->offset = (off_t) EC32(folder_hdr.coffCabStart) + offset; folder->offset = (off_t) EC32(folder_hdr.coffCabStart) + offset;
if(folder->offset > rsize)
bscore++;
folder->nblocks = EC16(folder_hdr.cCFData); folder->nblocks = EC16(folder_hdr.cCFData);
folder->cmethod = EC16(folder_hdr.typeCompress); folder->cmethod = EC16(folder_hdr.typeCompress);
cli_dbgmsg("CAB: Folder record %u\n", i); cli_dbgmsg("CAB: Folder record %u\n", i);
cli_dbgmsg("CAB: Folder offset: %u\n", (unsigned int) folder->offset); cli_dbgmsg("CAB: Folder offset: %u\n", (unsigned int) folder->offset);
cli_dbgmsg("CAB: Folder compression method: %d\n", folder->cmethod); cli_dbgmsg("CAB: Folder compression method: %d\n", folder->cmethod);
if((folder->cmethod & 0x000f) > 3)
bscore++;
if(!lfolder) if(!lfolder)
cab->folders = folder; cab->folders = folder;
@ -379,27 +369,20 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
lfolder->next = folder; lfolder->next = folder;
lfolder = folder; lfolder = folder;
folders++;
if(bscore > 10) {
cab_free(cab);
cli_dbgmsg("CAB: bscore == %u, most likely a fake cabinet\n", bscore);
return CL_EFORMAT;
}
} }
cli_dbgmsg("CAB: Recorded folders: %u\n", folders);
/* files */ /* 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++) { 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)) { if(cli_readn(fd, &file_hdr, sizeof(file_hdr)) != sizeof(file_hdr)) {
cli_errmsg("cab_open: Can't read file %u header\n", i); cli_dbgmsg("cab_open: Can't read file %u header\n", i);
cab_free(cab); break;
/* return CL_EIO; */
return CL_EFORMAT; /* most likely a corrupted file */
} }
file = (struct cab_file *) cli_calloc(1, sizeof(struct cab_file)); 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->cab = cab;
file->fd = fd; file->fd = fd;
file->length = EC32(file_hdr.cbFile);
file->offset = EC32(file_hdr.uoffFolderStart); file->offset = EC32(file_hdr.uoffFolderStart);
file->length = EC32(file_hdr.cbFile);
file->attribs = EC32(file_hdr.attribs); file->attribs = EC32(file_hdr.attribs);
fidx = EC32(file_hdr.iFolder); fidx = EC32(file_hdr.iFolder);
file->error = CL_SUCCESS;
file->name = cab_readstr(fd, &ret); file->name = cab_readstr(fd, &ret);
if(ret) { if(ret) {
free(file); free(file);
cab_free(cab); continue;
return ret;
} }
cab_chkname(file->name, 1);
cli_dbgmsg("CAB: File record %u\n", i); cli_dbgmsg("CAB: File record %u\n", i);
cli_dbgmsg("CAB: File name: %s\n", file->name); 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 */ /* folder index */
if(fidx < 0xfffd) { if(fidx < 0xfffd) {
if(fidx > cab->nfolders) { if(fidx > cab->nfolders) {
if(bscore < 3) cli_dbgmsg("cab_open: File %s is not associated with any folder\n", file->name);
cli_dbgmsg("cab_open: File %s is not associated with any folder\n", file->name);
bscore++;
free(file->name); free(file->name);
free(file); free(file);
continue; continue;
@ -457,11 +439,10 @@ int cab_open(int fd, off_t offset, struct cab_archive *cab)
file->folder = file->folder->next; file->folder = file->folder->next;
if(!file->folder) { 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->name);
free(file); free(file);
cab_free(cab); continue;
return CL_EFORMAT;
} }
} else { } 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)) { if(cli_readn(fd, &block_hdr, sizeof(block_hdr)) != sizeof(block_hdr)) {
cli_dbgmsg("cab_read_block: Can't read block header\n"); cli_dbgmsg("cab_read_block: Can't read block header\n");
/* return CL_EIO; */
return CL_EFORMAT; /* most likely a corrupted file */ return CL_EFORMAT; /* most likely a corrupted file */
} }
if(resdata && lseek(fd, (off_t) resdata, SEEK_CUR) == -1) { if(resdata && lseek(fd, (off_t) resdata, SEEK_CUR) == -1) {
cli_dbgmsg("cab_read_block: lseek failed\n"); cli_dbgmsg("cab_read_block: lseek failed\n");
/* return CL_EIO; */
return CL_EFORMAT; /* most likely a corrupted file */ 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) { if(cli_readn(fd, state->block, state->blklen) != state->blklen) {
cli_dbgmsg("cab_read_block: Can't read block data\n"); cli_dbgmsg("cab_read_block: Can't read block data\n");
/* return CL_EIO; */
return CL_EFORMAT; /* most likely a corrupted file */ 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; uint16_t todo, left;
if((file->cab->state->blknum > file->folder->nblocks) && !file->lread) {
file->error = CL_BREAK;
return -1;
}
todo = bytes; todo = bytes;
while(todo > 0) { while(todo > 0) {
left = file->cab->state->end - file->cab->state->pt; 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; todo -= left;
} else { } else {
if(file->cab->state->blknum++ >= file->folder->nblocks) { if(file->cab->state->blknum++ >= file->folder->nblocks)
file->error = CL_EFORMAT;
break; break;
}
file->error = cab_read_block(file->fd, file->cab->state, file->cab->resdata); file->error = cab_read_block(file->fd, file->cab->state, file->cab->resdata);
if(file->error) 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) 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; break;
default: 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; ret = CL_EFORMAT;
} }
close(file->ofd); close(file->ofd);
if(ret == CL_BREAK)
ret = CL_SUCCESS;
return ret; return ret;
} }

View file

@ -54,6 +54,7 @@ struct cab_file {
char *name; char *name;
uint32_t length; uint32_t length;
int error; int error;
int lread;
int fd; int fd;
int ofd; int ofd;
struct cab_folder *folder; struct cab_folder *folder;

View file

@ -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) 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; int bread, sret;
cli_file_t ret = CL_TYPE_BINARY_DATA; cli_file_t ret = CL_TYPE_BINARY_DATA;
struct cli_matcher *root; struct cli_matcher *root;
@ -147,12 +147,13 @@ cli_file_t cli_filetype2(int desc, const struct cl_engine *engine)
return CL_TYPE_ERROR; return CL_TYPE_ERROR;
} }
memset(smallbuff, 0, sizeof(smallbuff)); memset(buff, 0, sizeof(buff));
bread = cli_readn(desc, smallbuff, MAGIC_BUFFER_SIZE); bread = cli_readn(desc, buff, MAGIC_BUFFER_SIZE);
if(bread == -1) if(bread == -1)
return CL_TYPE_ERROR; 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) { if(ret >= CL_TYPE_TEXT_ASCII && ret <= CL_TYPE_BINARY_DATA) {
/* HTML files may contain special characters and could be /* 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)) if(cli_ac_initdata(&mdata, root->ac_partsigs, AC_DEFAULT_TRACKLEN))
return ret; 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); 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)) if(cli_ac_initdata(&mdata, root->ac_partsigs, AC_DEFAULT_TRACKLEN))
return ret; return ret;
decoded = (unsigned char *) cli_utf16toascii((char *) smallbuff, bread); decoded = (unsigned char *) cli_utf16toascii((char *) buff, bread);
if(decoded) { 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); 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); 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. /* check if we can autodetect this encoding.
* If we can't don't try to detect HTML sig, since * If we can't don't try to detect HTML sig, since
* we just tried that above, and failed */ * we just tried that above, and failed */
if((encoding = encoding_detect_bom(smallbuff, bread))) { if((encoding = encoding_detect_bom(buff, bread))) {
unsigned char decodedbuff[sizeof(smallbuff)*2]; unsigned char decodedbuff[sizeof(buff)*2];
m_area_t in_area, out_area; 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.length = bread;
in_area.offset = 0; in_area.offset = 0;
out_area.buffer = decodedbuff; 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(ret == CL_TYPE_BINARY_DATA) {
switch(is_tar(buff, bread)) {
if(!(bigbuff = (unsigned char *) cli_calloc(37638 + 1, sizeof(unsigned char)))) case 1:
return ret; ret = CL_TYPE_OLD_TAR;
cli_dbgmsg("Recognized old fashioned tar file\n");
lseek(desc, 0, SEEK_SET); break;
if((bread = cli_readn(desc, bigbuff, 37638)) > 0) { case 2:
ret = CL_TYPE_POSIX_TAR;
bigbuff[bread] = 0; cli_dbgmsg("Recognized POSIX tar file\n");
break;
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;
}
} }
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; return ret;

View file

@ -315,6 +315,7 @@ int hashtab_insert(struct hashtable *s, const char* key, const size_t len, const
if(!thekey) if(!thekey)
return CL_EMEM; return CL_EMEM;
strncpy(thekey, key, len+1); strncpy(thekey, key, len+1);
thekey[len]='\0';
element->key = thekey; element->key = thekey;
element->data = data; element->data = data;
element->len = len; element->len = len;
@ -557,3 +558,26 @@ ssize_t hashset_toarray(const struct hashset* hs, uint32_t** array)
} }
return j; 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];
}

View file

@ -20,11 +20,11 @@
* MA 02110-1301, USA. * MA 02110-1301, USA.
*/ */
#include <stdio.h>
#include <stddef.h>
#ifndef _HASHTAB_H #ifndef _HASHTAB_H
#define _HASHTAB_H #define _HASHTAB_H
#include <stdio.h>
#include <stddef.h>
#include "cltypes.h"
typedef long element_data; typedef long element_data;
/* define this for debugging/profiling purposes only, NOT in production/release code */ /* 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); void hashset_destroy(struct hashset* hs);
ssize_t hashset_toarray(const struct hashset* hs, uint32_t** array); 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 #endif

View file

@ -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 */ /* this will still contains scripts that are inside comments */
snprintf(filename, 1024, "%s/nocomment.html", dirname); snprintf(filename, 1024, "%s/nocomment.html", dirname);
file_buff_o2->fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR); 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); cli_dbgmsg("open failed: %s\n", filename);
free(file_buff_o2); free(file_buff_o2);
file_buff_o2 = file_buff_text = NULL; 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)); file_buff_text = (file_buff_t *) cli_malloc(sizeof(file_buff_t));
if(!file_buff_text) { if(!file_buff_text) {
close(file_buff_o2->fd);
free(file_buff_o2); free(file_buff_o2);
file_buff_o2 = file_buff_text = NULL; file_buff_o2 = file_buff_text = NULL;
goto abort; 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); snprintf(filename, 1024, "%s/notags.html", dirname);
file_buff_text->fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR); 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); cli_dbgmsg("open failed: %s\n", filename);
close(file_buff_o2->fd); close(file_buff_o2->fd);
free(file_buff_o2); free(file_buff_o2);
free(file_buff_text); free(file_buff_text);
file_buff_o2 = file_buff_text = NULL; file_buff_o2 = file_buff_text = NULL;
goto abort;
} }
file_buff_o2->length = 0; file_buff_o2->length = 0;
file_buff_text->length = 0; file_buff_text->length = 0;

View file

@ -74,6 +74,7 @@ CLAMAV_PRIVATE {
cli_warnmsg; cli_warnmsg;
cli_strtokbuf; cli_strtokbuf;
cli_leavetemps_flag; cli_leavetemps_flag;
uniq_get;
local: local:
*; *;
}; };

View file

@ -1079,6 +1079,7 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
return CL_EMEM; return CL_EMEM;
} }
strncpy(new->virname, virname, namelen); strncpy(new->virname, virname, namelen);
new->virname[namelen]='\0';
if(offset) { if(offset) {
new->offset = cli_strdup(offset); new->offset = cli_strdup(offset);

View file

@ -104,7 +104,7 @@ static const unsigned short mszip_bit_mask_tab[17] = {
if (mszip_read_input(zip)) return zip->error; \ if (mszip_read_input(zip)) return zip->error; \
i_ptr = zip->i_ptr; \ i_ptr = zip->i_ptr; \
i_end = zip->i_end; \ 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; \ 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) { 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); 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_ptr = &zip->inbuf[0];
zip->i_end = &zip->inbuf[nread]; 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) { 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); 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 /* huff decode's ENSURE_BYTES(16) might overrun the input stream, even
* if those bits aren't used, so fake 2 more bytes */ * 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) { 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); 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_ptr = &qtm->inbuf[0];
qtm->i_end = &qtm->inbuf[nread]; qtm->i_end = &qtm->inbuf[nread];

View file

@ -47,9 +47,10 @@
#include "cltypes.h" #include "cltypes.h"
#include "others.h" #include "others.h"
#include "ole2_extract.h" #include "ole2_extract.h"
#include "scanners.h"
#include "hashtab.h"
#include "mbox.h" #include "mbox.h"
#include "blob.h" /* sanitiseName() */
#define ole2_endian_convert_16(v) le16_to_host((uint16_t)(v)) #define ole2_endian_convert_16(v) le16_to_host((uint16_t)(v))
#define ole2_endian_convert_32(v) le32_to_host((uint32_t)(v)) #define ole2_endian_convert_32(v) le32_to_host((uint32_t)(v))
@ -70,6 +71,7 @@
#define O_BINARY 0 #define O_BINARY 0
#endif #endif
typedef struct ole2_header_tag typedef struct ole2_header_tag
{ {
unsigned char magic[8]; /* should be: 0xd0cf11e0a1b11ae1 */ unsigned char magic[8]; /* should be: 0xd0cf11e0a1b11ae1 */
@ -102,8 +104,11 @@ typedef struct ole2_header_tag
unsigned char *m_area; unsigned char *m_area;
off_t m_length; off_t m_length;
bitset_t *bitset; bitset_t *bitset;
struct uniq *U;
int has_vba;
} ole2_header_t; } ole2_header_t;
typedef struct property_tag typedef struct property_tag
{ {
char name[64]; /* in unicode */ 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 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; int i, j;
char *newname; char *newname;
@ -153,7 +159,7 @@ static char *get_property_name(char *name, int size)
/* size-2 to ignore trailing NULL */ /* size-2 to ignore trailing NULL */
for (i=0 ; i < size-2; i+=2) { for (i=0 ; i < size-2; i+=2) {
if((!(name[i]&0x80)) && isprint(name[i])) { if((!(name[i]&0x80)) && isprint(name[i])) {
newname[j++] = name[i]; newname[j++] = tolower(name[i]);
} else { } else {
if (name[i] < 10 && name[i] >= 0) { if (name[i] < 10 && name[i] >= 0) {
newname[j++] = '_'; newname[j++] = '_';
@ -179,50 +185,72 @@ static char *get_property_name(char *name, int size)
return newname; return newname;
} }
static void print_property_name(char *pname, int size) static char *get_property_name(char *name, int size) {
{ const char *carray = "0123456789abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz._";
char *name; int csize = size>>1;
char *newname, *cname;
char *oname = name;
name = get_property_name(pname, size); if (csize<=0) return NULL;
if (!name) {
return; newname = cname = (char *)cli_malloc(size);
} if (!newname) return NULL;
cli_dbgmsg("%34s ", name);
free(name); while(--csize) {
return; 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) static void print_ole2_property(property_t *property)
{ {
char spam[128], *buf;
if (property->name_size > 64) { if (property->name_size > 64) {
cli_dbgmsg("[err name len: %d]\n", property->name_size); cli_dbgmsg("[err name len: %d]\n", property->name_size);
return; 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) { switch (property->type) {
case 2: case 2:
cli_dbgmsg(" [file] "); strncat(spam, " [file] ", sizeof(spam) - 1 - strlen(spam));
break; break;
case 1: case 1:
cli_dbgmsg(" [dir ] "); strncat(spam, " [dir ] ", sizeof(spam) - 1 - strlen(spam));
break; break;
case 5: case 5:
cli_dbgmsg(" [root] "); strncat(spam, " [root] ", sizeof(spam) - 1 - strlen(spam));
break; break;
default: default:
cli_dbgmsg(" [%d]", property->type); strncat(spam, " [unkn] ", sizeof(spam) - 1 - strlen(spam));
} }
spam[sizeof(spam)-1]='\0';
switch (property->color) { switch (property->color) {
case 0: case 0:
cli_dbgmsg(" r "); strncat(spam, " r ", sizeof(spam) - 1 - strlen(spam));
break; break;
case 1: case 1:
cli_dbgmsg(" b "); strncat(spam, " b ", sizeof(spam) - 1 - strlen(spam));
break; break;
default: 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) 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, 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), 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) unsigned int rec_level, unsigned int *file_count, cli_ctx *ctx, unsigned long *scansize)
{ {
property_t prop_block[4]; property_t prop_block[4];
int32_t idx, current_block, i; int32_t idx, current_block, i;
char *dirname; char *dirname;
int ret;
const struct cl_limits *limits = ctx ? ctx->limits : NULL; const struct cl_limits *limits = ctx ? ctx->limits : NULL;
current_block = hdr->prop_start; current_block = hdr->prop_start;
if ((prop_index < 0) || (prop_index > (int32_t) hdr->max_block_no) || (rec_level > 100) || (*file_count > 100000)) { 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)) { if (limits && limits->maxfiles && (*file_count > limits->maxfiles)) {
cli_dbgmsg("OLE2: File limit reached (max: %d)\n", 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)) { if (limits && limits->maxreclevel && (rec_level > limits->maxreclevel)) {
cli_dbgmsg("OLE2: Recursion limit reached (max: %d)\n", limits->maxreclevel); cli_dbgmsg("OLE2: Recursion limit reached (max: %d)\n", limits->maxreclevel);
return; return CL_SUCCESS;
} }
idx = prop_index / 4; idx = prop_index / 4;
for (i=0 ; i < idx ; i++) { for (i=0 ; i < idx ; i++) {
current_block = ole2_get_next_block_number(fd, hdr, current_block); current_block = ole2_get_next_block_number(fd, hdr, current_block);
if (current_block < 0) { if (current_block < 0) {
return; return CL_SUCCESS;
} }
} }
idx = prop_index % 4; idx = prop_index % 4;
if (!ole2_read_block(fd, hdr, prop_block, if (!ole2_read_block(fd, hdr, prop_block,
current_block)) { current_block)) {
return; return CL_SUCCESS;
} }
if (prop_block[idx].type <= 0) { 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].name_size = ole2_endian_convert_16(prop_block[idx].name_size);
prop_block[idx].prev = ole2_endian_convert_32(prop_block[idx].prev); 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].start_block = ole2_endian_convert_32(prop_block[idx].start_block);
prop_block[idx].size = ole2_endian_convert_32(prop_block[idx].size); 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 */ /* Check we aren't in a loop */
if (cli_bitset_test(hdr->bitset, (unsigned long) prop_index)) { if (cli_bitset_test(hdr->bitset, (unsigned long) prop_index)) {
/* Loop in property tree detected */ /* Loop in property tree detected */
cli_dbgmsg("OLE2: Property tree loop detected at index %d\n", prop_index); 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)) { if (!cli_bitset_set(hdr->bitset, (unsigned long) prop_index)) {
return; return CL_SUCCESS;
} }
switch (prop_block[idx].type) { 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)) { (*file_count != 0)) {
/* Can only have RootEntry as the top */ /* Can only have RootEntry as the top */
cli_dbgmsg("ERROR: illegal Root Entry\n"); cli_dbgmsg("ERROR: illegal Root Entry\n");
return; return CL_SUCCESS;
} }
hdr->sbat_root_start = prop_block[idx].start_block; hdr->sbat_root_start = prop_block[idx].start_block;
ole2_walk_property_tree(fd, hdr, dir, if (
prop_block[idx].prev, handler, rec_level+1, file_count, ctx, scansize); (ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].prev, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
ole2_walk_property_tree(fd, hdr, dir, ||
prop_block[idx].next, handler, rec_level+1, file_count, ctx, scansize); (ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].next, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
ole2_walk_property_tree(fd, hdr, dir, ||
prop_block[idx].child, handler, rec_level+1, file_count, ctx, scansize); (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; break;
case 2: /* File */ case 2: /* File */
if (limits && limits->maxfiles && ctx->scannedfiles + *file_count > limits->maxfiles) { if (limits && limits->maxfiles && ctx->scannedfiles + *file_count > limits->maxfiles) {
cli_dbgmsg("ole2: files limit reached (max: %u)\n", ctx->limits->maxfiles); cli_dbgmsg("OLE2: files limit reached (max: %u)\n", ctx->limits->maxfiles);
break; return CL_BREAK;
} }
if (!limits || !limits->maxfilesize || prop_block[idx].size <= limits->maxfilesize || *scansize == -1 || prop_block[idx].size <= *scansize) { if (!limits || !limits->maxfilesize || prop_block[idx].size <= limits->maxfilesize || *scansize == -1 || prop_block[idx].size <= *scansize) {
(*file_count)++; (*file_count)++;
*scansize-=prop_block[idx].size; *scansize-=prop_block[idx].size;
if (!handler(fd, hdr, &prop_block[idx], dir)) { if ((ret=handler(fd, hdr, &prop_block[idx], dir, ctx)) != CL_SUCCESS)
cli_dbgmsg("ERROR: handler failed\n"); return ret;
/* If we don't return on this error then
we can sometimes pull VBA code
from corrupted files.
*/
}
} else { } else {
cli_dbgmsg("ole2: filesize exceeded\n"); cli_dbgmsg("OLE2: filesize exceeded\n");
} }
ole2_walk_property_tree(fd, hdr, dir, if (
prop_block[idx].prev, handler, rec_level, file_count, ctx, scansize); (ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].prev, handler, rec_level, file_count, ctx, scansize))!=CL_SUCCESS
ole2_walk_property_tree(fd, hdr, dir, ||
prop_block[idx].next, handler, rec_level, file_count, ctx, scansize); (ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].next, handler, rec_level, file_count, ctx, scansize))!=CL_SUCCESS
ole2_walk_property_tree(fd, hdr, dir, ||
prop_block[idx].child, handler, rec_level, file_count, ctx, scansize); (ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].child, handler, rec_level, file_count, ctx, scansize))!=CL_SUCCESS
) return ret;
break; break;
case 1: /* Directory */ case 1: /* Directory */
dirname = (char *) cli_malloc(strlen(dir)+8); if (dir) {
if (!dirname) { dirname = (char *) cli_malloc(strlen(dir)+8);
return; if (!dirname) return CL_BREAK;
} snprintf(dirname, strlen(dir)+8, "%s/%.6d", dir, prop_index);
snprintf(dirname, strlen(dir)+8, "%s/%.6d", dir, prop_index); if (mkdir(dirname, 0700) != 0) {
if (mkdir(dirname, 0700) != 0) { free(dirname);
free(dirname); return CL_BREAK;
return; }
} cli_dbgmsg("OLE2 dir entry: %s\n",dirname);
cli_dbgmsg("OLE2 dir entry: %s\n",dirname); } else dirname = NULL;
ole2_walk_property_tree(fd, hdr, dir, if (
prop_block[idx].prev, handler, rec_level+1, file_count, ctx, scansize); (ret=ole2_walk_property_tree(fd, hdr, dir, prop_block[idx].prev, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
ole2_walk_property_tree(fd, hdr, dir, ||
prop_block[idx].next, handler, rec_level+1, file_count, ctx, scansize); (ret=ole2_walk_property_tree(fd, hdr, dir,prop_block[idx].next, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
ole2_walk_property_tree(fd, hdr, dirname, ||
prop_block[idx].child, handler, rec_level+1, file_count, ctx, scansize); (ret=ole2_walk_property_tree(fd, hdr, dirname, prop_block[idx].child, handler, rec_level+1, file_count, ctx, scansize))!=CL_SUCCESS
free(dirname); ) {}
if (dirname) free(dirname);
return ret;
break; break;
default: default:
cli_dbgmsg("ERROR: unknown OLE2 entry type: %d\n", prop_block[idx].type); cli_dbgmsg("ERROR: unknown OLE2 entry type: %d\n", prop_block[idx].type);
break; break;
} }
return; return CL_SUCCESS;
} }
/* Write file Handler - write the contents of the entry to a file */ /* 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; unsigned char *buff;
int32_t current_block, ofd, len, offset; int32_t current_block, ofd, len, offset;
char *name, *newname; char *name, newname[1024];
bitset_t *blk_bitset; bitset_t *blk_bitset;
uint32_t hash, cnt;
if (prop->type != 2) { if (prop->type != 2) {
/* Not a file */ /* Not a file */
return TRUE; return CL_SUCCESS;
} }
if (prop->name_size > 64) { if (prop->name_size > 64) {
cli_dbgmsg("\nERROR: property name too long: %d\n", prop->name_size); cli_dbgmsg("OLE2 [handler_writefile]: property name too long: %d\n", prop->name_size);
return FALSE; return CL_SUCCESS;
} }
if (! (name = get_property_name(prop->name, prop->name_size))) { name = get_property_name2(prop->name, prop->name_size);
/* File without a name - create a name for it */ if (name) cnt = uniq_add(hdr->U, name, strlen(name), &hash);
off_t i; else cnt = uniq_add(hdr->U, NULL, 0, &hash);
snprintf(newname, sizeof(newname), "%s/%u_%u", dir, hash, cnt);
i = lseek(fd, 0, SEEK_CUR); newname[sizeof(newname)-1]='\0';
name = (char *) cli_malloc(11); cli_dbgmsg("OLE2 [handler_writefile]: Dumping '%s' to '%s'\n", name ? name : "<empty>", newname);
if (!name) { if (name) free(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);
ofd = open(newname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU); ofd = open(newname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU);
if (ofd < 0) { if (ofd < 0) {
cli_errmsg("ERROR: failed to create file: %s\n", newname); cli_errmsg("OLE2 [handler_writefile]: failed to create file: %s\n", newname);
free(newname); return CL_SUCCESS;
return FALSE;
} }
free(newname);
current_block = prop->start_block; current_block = prop->start_block;
len = prop->size; len = prop->size;
buff = (unsigned char *) cli_malloc(1 << hdr->log2_big_block_size); buff = (unsigned char *) cli_malloc(1 << hdr->log2_big_block_size);
if (!buff) { if (!buff) {
close(ofd); close(ofd);
return FALSE; return CL_BREAK;
} }
blk_bitset = cli_bitset_init(); blk_bitset = cli_bitset_init();
if (!blk_bitset) { if (!blk_bitset) {
cli_errmsg("ERROR [handler_writefile]: init bitset failed\n"); cli_errmsg("OLE2 [handler_writefile]: init bitset failed\n");
close(ofd); close(ofd);
return FALSE; return CL_BREAK;
} }
while((current_block >= 0) && (len > 0)) { while((current_block >= 0) && (len > 0)) {
if (current_block > (int32_t) hdr->max_block_no) { 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); close(ofd);
free(buff); free(buff);
cli_bitset_free(blk_bitset); cli_bitset_free(blk_bitset);
return FALSE; return CL_SUCCESS;
} }
/* Check we aren't in a loop */ /* Check we aren't in a loop */
if (cli_bitset_test(blk_bitset, (unsigned long) current_block)) { if (cli_bitset_test(blk_bitset, (unsigned long) current_block)) {
/* Loop in block list */ /* Loop in block list */
cli_dbgmsg("OLE2: Block list loop detected\n"); cli_dbgmsg("OLE2 [handler_writefile]: Block list loop detected\n");
close(ofd); close(ofd);
free(buff); free(buff);
cli_bitset_free(blk_bitset); cli_bitset_free(blk_bitset);
return FALSE; return CL_BREAK;
} }
if (!cli_bitset_set(blk_bitset, (unsigned long) current_block)) { if (!cli_bitset_set(blk_bitset, (unsigned long) current_block)) {
close(ofd); close(ofd);
free(buff); free(buff);
cli_bitset_free(blk_bitset); cli_bitset_free(blk_bitset);
return FALSE; return CL_BREAK;
} }
if (prop->size < (int64_t)hdr->sbat_cutoff) { if (prop->size < (int64_t)hdr->sbat_cutoff) {
/* Small block file */ /* Small block file */
if (!ole2_get_sbat_data_block(fd, hdr, buff, current_block)) { 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); close(ofd);
free(buff); free(buff);
cli_bitset_free(blk_bitset); cli_bitset_free(blk_bitset);
return FALSE; return CL_SUCCESS;
} }
/* buff now contains the block with 8 small blocks in it */ /* buff now contains the block with 8 small blocks in it */
offset = 64 * (current_block % 8); 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); close(ofd);
free(buff); free(buff);
cli_bitset_free(blk_bitset); cli_bitset_free(blk_bitset);
return FALSE; return CL_BREAK;
} }
len -= MIN(len,64); len -= MIN(len,64);
@ -704,14 +714,14 @@ static int handler_writefile(int fd, ole2_header_t *hdr, property_t *prop, const
close(ofd); close(ofd);
free(buff); free(buff);
cli_bitset_free(blk_bitset); cli_bitset_free(blk_bitset);
return FALSE; return CL_SUCCESS;
} }
if (cli_writen(ofd, buff, MIN(len,(1 << hdr->log2_big_block_size))) != if (cli_writen(ofd, buff, MIN(len,(1 << hdr->log2_big_block_size))) !=
MIN(len,(1 << hdr->log2_big_block_size))) { MIN(len,(1 << hdr->log2_big_block_size))) {
close(ofd); close(ofd);
free(buff); free(buff);
cli_bitset_free(blk_bitset); cli_bitset_free(blk_bitset);
return FALSE; return CL_BREAK;
} }
current_block = ole2_get_next_block_number(fd, hdr, current_block); 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); close(ofd);
free(buff); free(buff);
cli_bitset_free(blk_bitset); 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) #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 #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; ole2_header_t hdr;
int hdr_size; int hdr_size, ret=CL_CLEAN;
struct stat statbuf; struct stat statbuf;
unsigned int file_count=0; unsigned int file_count=0;
unsigned long scansize; unsigned long scansize, scansize2;
cli_dbgmsg("in cli_ole2_extract()\n"); cli_dbgmsg("in cli_ole2_extract()\n");
@ -803,16 +994,18 @@ int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx)
return CL_EMAXSIZE; return CL_EMAXSIZE;
} else scansize = -1; } else scansize = -1;
scansize2 = scansize;
/* size of header - size of other values in struct */ /* 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(unsigned char *) - sizeof(off_t) - sizeof(bitset_t *) -
sizeof(uint32_t); sizeof(struct uniq *) - sizeof(int);
hdr.m_area = NULL; hdr.m_area = NULL;
if (fstat(fd, &statbuf) == 0) { if (fstat(fd, &statbuf) == 0) {
if (statbuf.st_size < hdr_size) { if (statbuf.st_size < hdr_size) {
return 0; return CL_CLEAN;
} }
#ifdef HAVE_MMAP #ifdef HAVE_MMAP
hdr.m_length = statbuf.st_size; 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) { if (hdr.m_area == NULL) {
hdr.bitset = NULL;
#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK) || defined(HAVE_PRAGMA_PACK_HPPA) #if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK) || defined(HAVE_PRAGMA_PACK_HPPA)
if (cli_readn(fd, &hdr, hdr_size) != hdr_size) { if (cli_readn(fd, &hdr, hdr_size) != hdr_size) {
return 0; goto abort;
} }
#else #else
if (!ole2_read_header(fd, &hdr)) { if (!ole2_read_header(fd, &hdr)) {
return 0; goto abort;
} }
#endif #endif
} }
@ -854,19 +1048,14 @@ int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx)
hdr.sbat_root_start = -1; hdr.sbat_root_start = -1;
hdr.bitset = cli_bitset_init(); hdr.bitset = cli_bitset_init();
if (!hdr.bitset) { if (!hdr.bitset) { /* FIXME: mmap leaks here */
return CL_EOLE2; return CL_EOLE2;
} }
if (memcmp(hdr.magic, magic_id, 8) != 0) { if (memcmp(hdr.magic, magic_id, 8) != 0) {
cli_dbgmsg("OLE2 magic failed!\n"); cli_dbgmsg("OLE2 magic failed!\n");
#ifdef HAVE_MMAP ret=CL_EOLE2;
if (hdr.m_area != NULL) { goto abort;
munmap(hdr.m_area, hdr.m_length);
}
#endif
cli_bitset_free(hdr.bitset);
return CL_EOLE2;
} }
if (hdr.log2_big_block_size != 9) { if (hdr.log2_big_block_size != 9) {
@ -894,7 +1083,35 @@ int cli_ole2_extract(int fd, const char *dirname, cli_ctx *ctx)
/* OR */ /* 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: abort:
#ifdef HAVE_MMAP #ifdef HAVE_MMAP
@ -902,6 +1119,8 @@ abort:
munmap(hdr.m_area, hdr.m_length); munmap(hdr.m_area, hdr.m_length);
} }
#endif #endif
cli_bitset_free(hdr.bitset); if(hdr.bitset)
return 0; cli_bitset_free(hdr.bitset);
return ret;
} }

View file

@ -24,7 +24,8 @@
#define __OLE2_EXTRACT_H #define __OLE2_EXTRACT_H
#include "others.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 #endif

View file

@ -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; \ int len = sizeof(x) - 1; \
char buff[BUFSIZ]; \ char buff[BUFSIZ]; \
strncpy(buff, x, len); \ strncpy(buff, x, len); \
buff[BUFSIZ-1]='\0'; \
va_start(args, str); \ va_start(args, str); \
vsnprintf(buff + len, sizeof(buff) - len, str, args); \ vsnprintf(buff + len, sizeof(buff) - len, str, args); \
buff[sizeof(buff) - 1] = '\0'; \ buff[sizeof(buff) - 1] = '\0'; \

View file

@ -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) * TODO: handle embedded URLs if (options&CL_SCAN_MAILURL)
*/ */
int 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 size; /* total number of bytes in the file */
off_t bytesleft, trailerlength; off_t bytesleft, trailerlength;
@ -99,12 +99,12 @@ cli_pdf(const char *dir, int desc, cli_ctx *ctx)
return CL_EOPEN; return CL_EOPEN;
} }
size = statb.st_size; size = statb.st_size - offset;
if(size <= 7) /* doesn't even include the file header */ if(size <= 7) /* doesn't even include the file header */
return CL_CLEAN; 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) { if(buf == MAP_FAILED) {
cli_errmsg("cli_pdf: mmap() failed\n"); cli_errmsg("cli_pdf: mmap() failed\n");
return CL_EMEM; 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 */ /* Lines are terminated by \r, \n or both */
/* File Header */ /* File Header */
if(memcmp(p, "%PDF-1.", 7) != 0) { bytesleft = size - 5;
munmap(buf, size); for(q = p; bytesleft; bytesleft--, q++) {
cli_dbgmsg("cli_pdf: file header not found\n"); if(!strncasecmp(q, "%PDF-", 5)) {
return CL_CLEAN; bytesleft = size - (off_t) (q - p);
p = q;
break;
}
} }
#if 0 if(!bytesleft) {
q = pdf_nextlinestart(&p[6], size - 6); munmap(buf, size);
if(q == NULL) { cli_dbgmsg("cli_pdf: file header not found\n");
munmap(buf, size); return CL_CLEAN;
return CL_CLEAN;
} }
bytesleft = size - (long)(q - p);
p = q;
#else
p = &p[6];
bytesleft = size - 6;
#endif
/* Find the file trailer */ /* Find the file trailer */
for(q = &p[bytesleft - 6]; q > p; --q) for(q = &p[bytesleft - 5]; q > p; --q)
if(memcmp(q, "%%EOF", 5) == 0) if(strncasecmp(q, "%%EOF", 5) == 0)
break; break;
if(q <= p) { if(q <= p) {
@ -868,7 +864,7 @@ cli_pmemstr(const char *haystack, size_t hs, const char *needle, size_t ns)
#include "pdf.h" #include "pdf.h"
int 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"); cli_dbgmsg("File not decoded - PDF decoding needs mmap() (for now)\n");
return CL_CLEAN; return CL_CLEAN;

View file

@ -22,6 +22,6 @@
#include "others.h" #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 #endif

View file

@ -260,6 +260,7 @@ int cli_parse_add(struct cli_matcher *root, const char *virname, const char *hex
} }
strncpy(bm_new->virname, virname, virlen); strncpy(bm_new->virname, virname, virlen);
bm_new->virname[virlen]='\0';
if(offset) { if(offset) {
bm_new->offset = cli_strdup(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]) if(!ftypes_int[line])
break; break;
strncpy(buffer, ftypes_int[line], sizeof(buffer)); strncpy(buffer, ftypes_int[line], sizeof(buffer));
buffer[sizeof(buffer)-1]='\0';
} else { } else {
if(!cli_dbgets(buffer, FILEBUFF, fs, dbio)) if(!cli_dbgets(buffer, FILEBUFF, fs, dbio))
break; break;

View file

@ -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) static int compare_state(const struct rtf_state* a,const struct rtf_state* b)
{ {
return (a->controlword_param == b->controlword_param && return (a->parse_state == b->parse_state &&
a->parse_state == b->parse_state && a->encounteredTopLevel == b->encounteredTopLevel &&
a->encounteredTopLevel == b->encounteredTopLevel && a->cb_begin == b->cb_begin &&
memcmp(a->controlword,b->controlword,33)==0 && a->cb_process == b->cb_process &&
a->cb_begin == b->cb_begin && a->cb_end == b->cb_end &&
a->cb_process == b->cb_process && a->cb_data == b->cb_data);
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) { if(stack->stack_cnt >= stack->stack_size) {
/* grow stack */ /* grow stack */
struct rtf_state *states;
stack->stack_size += 128; stack->stack_size += 128;
stack->states = cli_realloc2(stack->states, stack->stack_size*sizeof(*stack->states)); states = cli_realloc2(stack->states, stack->stack_size*sizeof(*stack->states));
if(!stack->states) if(!states)
return CL_EMEM; return CL_EMEM;
stack->states = states;
} }
stack->states[stack->stack_cnt++] = *state; stack->states[stack->stack_cnt++] = *state;
toplevel = state->encounteredTopLevel; 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) 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); cli_dbgmsg("RTF:Scanning embedded object:%s\n",data->name);
if(data->bread == 1 && data->fd > 0) { if(data->bread == 1 && data->fd > 0) {
cli_dbgmsg("Decoding ole object\n"); cli_dbgmsg("Decoding ole object\n");
lseek(data->fd,0,SEEK_SET); ret = cli_scan_ole10(data->fd, ctx);
ofd = cli_decode_ole_object(data->fd,data->tmpdir);
if (ofd >= 0) {
ret = cli_magic_scandesc(ofd, ctx);
close(ofd);
}
} }
else if(data->fd > 0) else if(data->fd > 0)
ret = cli_magic_scandesc(data->fd,ctx); 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) 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*/) { while(stack && stack->stack_cnt /* && state->default_elements*/) {
pop_state(stack,state); pop_state(stack,state);
if(state->cb_data && state->cb_end) if(state->cb_data && state->cb_end)

View file

@ -722,9 +722,9 @@ static int cli_scanmscab(int desc, cli_ctx *ctx, off_t sfx_offset)
return ret; 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; vba_project_t *vba_project;
DIR *dd; DIR *dd;
struct dirent *dent; struct dirent *dent;
@ -735,84 +735,88 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx)
} result; } result;
#endif #endif
struct stat statbuf; struct stat statbuf;
char *fname, *fullname; char *fullname, vbaname[1024];
unsigned char *data; unsigned char *data;
uint32_t hash, hashcnt;
cli_dbgmsg("VBADir: %s\n", dirname); 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++) { for(i = 0; i < vba_project->count; i++) {
fullname = (char *) cli_malloc(strlen(vba_project->dir) + strlen(vba_project->name[i]) + 2); for(j = 0; j < vba_project->colls[i]; j++) {
if(!fullname) { snprintf(vbaname, 1024, "%s/%u_%u", vba_project->dir, vba_project->name[i], j);
ret = CL_EMEM; vbaname[sizeof(vbaname)-1] = '\0';
break; fd = open(vbaname, O_RDONLY|O_BINARY);
} if(fd == -1) continue;
sprintf(fullname, "%s/%s", vba_project->dir, vba_project->name[i]); cli_dbgmsg("VBADir: Decompress VBA project '%u_%u'\n", vba_project->name[i], j);
fd = open(fullname, O_RDONLY|O_BINARY); data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
if(fd == -1) { close(fd);
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);
if(!data) { if(!data) {
cli_dbgmsg("VBADir: WARNING: VBA project '%s' decompressed to NULL\n", vba_project->name[i]); cli_dbgmsg("VBADir: WARNING: VBA project '%u_%u' decompressed to NULL\n", vba_project->name[i], j);
} else { } else {
if(ctx->scanned) /* cli_dbgmsg("Project content:\n%s", data); */
*ctx->scanned += data_len / CL_COUNT_PRECISION; if(ctx->scanned)
*ctx->scanned += data_len / CL_COUNT_PRECISION;
if(cli_scanbuff(data, data_len, ctx, CL_TYPE_MSOLE2) == CL_VIRUS) { if(cli_scanbuff(data, data_len, ctx, CL_TYPE_MSOLE2) == CL_VIRUS) {
free(data);
ret = CL_VIRUS;
break;
}
free(data); 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->name);
free(vba_project->colls);
free(vba_project->dir); free(vba_project->dir);
free(vba_project->offset); free(vba_project->offset);
free(vba_project); free(vba_project);
} else if ((fullname = cli_ppt_vba_read(dirname))) { if (ret == CL_VIRUS) break;
if(cli_scandir(fullname, ctx, 0) == CL_VIRUS) { }
ret = CL_VIRUS;
} if(ret == CL_CLEAN && (hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
if(!cli_leavetemps_flag) while(hashcnt--) {
cli_rmdirs(fullname); snprintf(vbaname, 1024, "%s/%u_%u", dirname, hash, hashcnt);
free(fullname); vbaname[sizeof(vbaname)-1] = '\0';
} else if ((vba_project = (vba_project_t *)cli_wm_readdir(dirname))) { fd = open(vbaname, O_RDONLY|O_BINARY);
for (i = 0; i < vba_project->count; i++) { if (fd == -1) continue;
fullname = (char *) cli_malloc(strlen(vba_project->dir) + strlen(vba_project->name[i]) + 2); if ((fullname = cli_ppt_vba_read(fd))) {
if(!fullname) { if(cli_scandir(fullname, ctx, 0) == CL_VIRUS) {
ret = CL_EMEM; ret = CL_VIRUS;
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(!cli_leavetemps_flag)
cli_rmdirs(fullname);
free(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); 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) { if(!data) {
cli_dbgmsg("VBADir: WARNING: WM project '%s' macro %d decrypted to NULL\n", vba_project->name[i], i); cli_dbgmsg("VBADir: WARNING: WM project '%s' macro %d decrypted to NULL\n", vba_project->name[i], i);
} else { } else {
cli_dbgmsg("Project content:\n%s", data);
if(ctx->scanned) if(ctx->scanned)
*ctx->scanned += vba_project->length[i] / CL_COUNT_PRECISION; *ctx->scanned += vba_project->length[i] / CL_COUNT_PRECISION;
if(cli_scanbuff(data, vba_project->length[i], ctx, CL_TYPE_MSOLE2) == CL_VIRUS) { 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); 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) if(ret != CL_CLEAN)
return ret; return ret;
/* Check directory for embedded OLE objects */ /* Check directory for embedded OLE objects */
fullname = (char *) cli_malloc(strlen(dirname) + 16); hashcnt = uniq_get(U, "_1_ole10native", 14, &hash);
if(!fullname) while(hashcnt--) {
return CL_EMEM; snprintf(vbaname, sizeof(vbaname), "%s/%u_%u", dirname, hash, hashcnt);
vbaname[sizeof(vbaname)-1] = '\0';
sprintf(fullname, "%s/_1_Ole10Native", dirname); fd = open(vbaname, O_RDONLY|O_BINARY);
fd = open(fullname, O_RDONLY|O_BINARY); if (fd >= 0) {
free(fullname); ret = cli_scan_ole10(fd, ctx);
if (fd >= 0) { close(fd);
ofd = cli_decode_ole_object(fd, dirname); if(ret != CL_CLEAN)
if (ofd >= 0) { return ret;
ret = cli_scandesc(ofd, ctx, 0, 0, NULL, AC_SCAN_VIR);
close(ofd);
} }
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) { if((dd = opendir(dirname)) != NULL) {
#ifdef HAVE_READDIR_R_3 #ifdef HAVE_READDIR_R_3
while(!readdir_r(dd, &result.d, &dent) && dent) { 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, "..")) { if(strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
/* build the full name */ /* build the full name */
fname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2); fullname = cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
if(!fname) { if(!fullname) {
ret = CL_EMEM; ret = CL_EMEM;
break; break;
} }
sprintf(fname, "%s/%s", dirname, dent->d_name); sprintf(fullname, "%s/%s", dirname, dent->d_name);
/* stat the file */ /* 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(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; ret = CL_VIRUS;
free(fname); free(fullname);
break; break;
} }
} }
free(fname); free(fullname);
} }
} }
} }
@ -1086,7 +1094,7 @@ static int cli_scanole2(int desc, cli_ctx *ctx)
{ {
char *dir; char *dir;
int ret = CL_CLEAN; int ret = CL_CLEAN;
struct uniq *vba = NULL;
cli_dbgmsg("in cli_scanole2()\n"); cli_dbgmsg("in cli_scanole2()\n");
@ -1103,25 +1111,26 @@ static int cli_scanole2(int desc, cli_ctx *ctx)
return CL_ETMPDIR; 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)); cli_dbgmsg("OLE2: %s\n", cl_strerror(ret));
if(!cli_leavetemps_flag) if(!cli_leavetemps_flag)
cli_rmdirs(dir); cli_rmdirs(dir);
free(dir); free(dir);
ctx->recursion--;
return ret; return ret;
} }
ctx->recursion++; if (vba) {
ctx->recursion++;
if((ret = cli_vba_scandir(dir, ctx)) != CL_VIRUS) { ret = cli_vba_scandir(dir, ctx, vba);
if(cli_scandir(dir, ctx, 0) == CL_VIRUS) { free(vba);
ret = CL_VIRUS; if(ret != CL_VIRUS)
} if(cli_scandir(dir, ctx, 0) == CL_VIRUS)
ret = CL_VIRUS;
ctx->recursion--;
} }
ctx->recursion--;
if(!cli_leavetemps_flag) if(!cli_leavetemps_flag)
cli_rmdirs(dir); cli_rmdirs(dir);
free(dir); free(dir);
@ -1380,7 +1389,7 @@ static int cli_scancryptff(int desc, cli_ctx *ctx)
return ret; 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; int ret;
char *dir = cli_gentemp(NULL); char *dir = cli_gentemp(NULL);
@ -1394,7 +1403,7 @@ static int cli_scanpdf(int desc, cli_ctx *ctx)
return CL_ETMPDIR; return CL_ETMPDIR;
} }
ret = cli_pdf(dir, desc, ctx); ret = cli_pdf(dir, desc, ctx, offset);
if(!cli_leavetemps_flag) if(!cli_leavetemps_flag)
cli_rmdirs(dir); cli_rmdirs(dir);
@ -1717,6 +1726,13 @@ static int cli_scanraw(int desc, cli_ctx *ctx, cli_file_t type, uint8_t typercg,
} }
break; 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: case CL_TYPE_MSEXE:
if(SCAN_PE && ctx->dconf->pe && fpt->offset) { if(SCAN_PE && ctx->dconf->pe && fpt->offset) {
cli_dbgmsg("PE signature found at %u\n", (unsigned int) 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! */ case CL_TYPE_PDF: /* FIXMELIMITS: pdf should be an archive! */
if(SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF)) if(SCAN_PDF && (DCONF_DOC & DOC_CONF_PDF))
ret = cli_scanpdf(desc, ctx); ret = cli_scanpdf(desc, ctx, 0);
break; break;
case CL_TYPE_CRYPTFF: case CL_TYPE_CRYPTFF:
@ -2105,3 +2121,9 @@ int cl_scanfile(const char *filename, const char **virname, unsigned long int *s
return ret; return ret;
} }
/*
Local Variables:
c-basic-offset: 4
End:
*/

View file

@ -37,6 +37,7 @@
#include "clamav.h" #include "clamav.h"
#include "others.h" #include "others.h"
#include "scanners.h"
#include "vba_extract.h" #include "vba_extract.h"
#ifdef CL_DEBUG #ifdef CL_DEBUG
#include "mbox.h" #include "mbox.h"
@ -71,29 +72,11 @@ typedef struct {
int big_endian; /* e.g. MAC Office */ int big_endian; /* e.g. MAC Office */
} vba_version_t; } 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 skip_past_nul(int fd);
static int read_uint16(int fd, uint16_t *u, int big_endian); 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 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 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 static uint16_t
vba_endian_convert_16(uint16_t value, int big_endian) 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); return le32_to_host(value);
} }
static char * static char *
get_unicode_name(const char *name, int size, int big_endian) 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; ret = newname;
for(i = 0; i < size; i += increment) { for(i = 0; i < size; i += increment) {
if(isprint(name[i])) if((!(name[i]&0x80)) && isprint(name[i])) {
*ret++ = name[i]; *ret++ = tolower(name[i]);
else { } else {
if((name[i] < 10) && (name[i] >= 0)) { if((name[i] < 10) && (name[i] >= 0)) {
*ret++ = '_'; *ret++ = '_';
*ret++ = (char)(name[i] + '0'); *ret++ = (char)(name[i] + '0');
@ -195,17 +179,16 @@ vba_read_project_strings(int fd, int big_endian)
{ {
unsigned char *buf = NULL; unsigned char *buf = NULL;
uint16_t buflen = 0; uint16_t buflen = 0;
int ret = 0;
for(;;) { for(;;) {
off_t offset; off_t offset;
uint16_t length; uint16_t length;
char *name; char *name;
if(!read_uint16(fd, &length, big_endian)) { if(!read_uint16(fd, &length, big_endian))
if(buf) break;
free(buf);
return FALSE;
}
if (length < 6) { if (length < 6) {
lseek(fd, -2, SEEK_CUR); lseek(fd, -2, SEEK_CUR);
break; break;
@ -215,7 +198,7 @@ vba_read_project_strings(int fd, int big_endian)
if(newbuf == NULL) { if(newbuf == NULL) {
if(buf) if(buf)
free(buf); free(buf);
return FALSE; return 0;
} }
buflen = length; buflen = length;
buf = newbuf; 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]"); cli_dbgmsg("length: %d, name: %s\n", length, (name) ? name : "[null]");
if((name == NULL) || (memcmp("*\\", name, 2) != 0) || if((name == NULL) || (memcmp("*\\", name, 2) != 0) ||
(strchr("GCHD", name[2]) == NULL)) { (strchr("ghcd", name[2]) == NULL)) {
/* Not a string */ /* Not a string */
lseek(fd, -(length+2), SEEK_CUR); lseek(fd, -(length+2), SEEK_CUR);
if(name) if(name)
@ -244,9 +227,11 @@ vba_read_project_strings(int fd, int big_endian)
if(!read_uint16(fd, &length, big_endian)) { if(!read_uint16(fd, &length, big_endian)) {
if(buf) if(buf)
free(buf); free(buf);
return FALSE; break;
} }
ret++;
if ((length != 0) && (length != 65535)) { if ((length != 0) && (length != 65535)) {
lseek(fd, -2, SEEK_CUR); lseek(fd, -2, SEEK_CUR);
continue; continue;
@ -257,21 +242,22 @@ vba_read_project_strings(int fd, int big_endian)
} }
if(buf) if(buf)
free(buf); free(buf);
return TRUE; return ret;
} }
vba_project_t * vba_project_t *
cli_vba_readdir(const char *dir) cli_vba_readdir(const char *dir, struct uniq *U, uint32_t which)
{ {
unsigned char *buf; unsigned char *buf;
const unsigned char vba56_signature[] = { 0xcc, 0x61 }; const unsigned char vba56_signature[] = { 0xcc, 0x61 };
uint16_t record_count, buflen, ffff, byte_count; uint16_t record_count, buflen, ffff, byte_count;
uint32_t offset, sig; uint32_t offset, sig, hash, colls;
int i, fd, big_endian; int i, j, fd, big_endian = FALSE;
vba_project_t *vba_project; vba_project_t *vba_project;
const vba_version_t *v; const vba_version_t *v;
struct vba56_header v56h; struct vba56_header v56h;
char fullname[NAME_MAX + 1]; off_t seekback;
char fullname[1024];
cli_dbgmsg("in cli_vba_readdir()\n"); 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) * _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); fd = open(fullname, O_RDONLY|O_BINARY);
if(fd == -1) { if(fd == -1)
cli_dbgmsg("Can't open %s\n", fullname);
return NULL; return NULL;
}
if(cli_readn(fd, &v56h, sizeof(struct vba56_header)) != sizeof(struct vba56_header)) { if(cli_readn(fd, &v56h, sizeof(struct vba56_header)) != sizeof(struct vba56_header)) {
close(fd); close(fd);
@ -298,37 +286,22 @@ cli_vba_readdir(const char *dir)
return NULL; return NULL;
} }
sig = cli_readint32(v56h.version); i = vba_read_project_strings(fd, TRUE);
for(v = vba_versions; v->sig; v++) seekback = lseek(fd, 0, SEEK_CUR);
if(v->sig == sig) if (lseek(fd, sizeof(struct vba56_header), SEEK_SET) == -1)
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);
return NULL; 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 */ /* junk some more stuff */
@ -369,7 +342,7 @@ cli_vba_readdir(const char *dir)
close(fd); close(fd);
return NULL; 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) { if (record_count == 0) {
/* No macros, assume clean */ /* No macros, assume clean */
close(fd); close(fd);
@ -377,12 +350,12 @@ cli_vba_readdir(const char *dir)
} }
if (record_count > MAX_VBA_COUNT) { if (record_count > MAX_VBA_COUNT) {
/* Almost certainly an error */ /* Almost certainly an error */
cli_dbgmsg("VBA Record count too big\n"); cli_dbgmsg("vba_readdir: VBA Record count too big\n");
close(fd); close(fd);
return NULL; return NULL;
} }
vba_project = create_vba_project(record_count, dir); vba_project = create_vba_project(record_count, dir, U);
if(vba_project == NULL) { if(vba_project == NULL) {
close(fd); close(fd);
return NULL; return NULL;
@ -393,11 +366,12 @@ cli_vba_readdir(const char *dir)
uint16_t length; uint16_t length;
char *ptr; char *ptr;
vba_project->colls[i] = 0;
if(!read_uint16(fd, &length, big_endian)) if(!read_uint16(fd, &length, big_endian))
break; break;
if (length == 0) { if (length == 0) {
cli_dbgmsg("zero name length\n"); cli_dbgmsg("vba_readdir: zero name length\n");
break; break;
} }
if(length > buflen) { if(length > buflen) {
@ -408,51 +382,39 @@ cli_vba_readdir(const char *dir)
buf = newbuf; buf = newbuf;
} }
if (cli_readn(fd, buf, length) != length) { if (cli_readn(fd, buf, length) != length) {
cli_dbgmsg("read name failed\n"); cli_dbgmsg("vba_readdir: read name failed\n");
break; break;
} }
ptr = get_unicode_name((const char *)buf, length, big_endian); ptr = get_unicode_name((const char *)buf, length, big_endian);
if(ptr == NULL) { if(ptr == NULL) break;
offset = lseek(fd, 0, SEEK_CUR); if (!(vba_project->colls[i]=uniq_get(U, ptr, strlen(ptr), &hash))) {
ptr = (char *)cli_malloc(18); cli_dbgmsg("vba_readdir: cannot find project %s (%u)\n", ptr, hash);
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);
break; 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); lseek(fd, length, SEEK_CUR);
if(!read_uint16(fd, &ffff, big_endian)) { if(!read_uint16(fd, &ffff, big_endian))
free(ptr);
break; break;
}
if (ffff == 0xFFFF) { if (ffff == 0xFFFF) {
lseek(fd, 2, SEEK_CUR); lseek(fd, 2, SEEK_CUR);
if(!read_uint16(fd, &ffff, big_endian)) { if(!read_uint16(fd, &ffff, big_endian))
free(ptr);
break; break;
}
lseek(fd, ffff + 8, SEEK_CUR); lseek(fd, ffff + 8, SEEK_CUR);
} else } else
lseek(fd, ffff + 10, SEEK_CUR); lseek(fd, ffff + 10, SEEK_CUR);
if(!read_uint16(fd, &byte_count, big_endian)) { if(!read_uint16(fd, &byte_count, big_endian))
free(ptr);
break; break;
}
lseek(fd, (8 * byte_count) + 5, SEEK_CUR); lseek(fd, (8 * byte_count) + 5, SEEK_CUR);
if(!read_uint32(fd, &offset, big_endian)) { if(!read_uint32(fd, &offset, big_endian))
free(ptr);
break; break;
} cli_dbgmsg("vba_readdir: offset: %u\n", (unsigned int)offset);
cli_dbgmsg("offset: %u\n", (unsigned int)offset);
vba_project->offset[i] = offset; vba_project->offset[i] = offset;
vba_project->name[i] = ptr;
lseek(fd, 2, SEEK_CUR); lseek(fd, 2, SEEK_CUR);
} }
@ -462,10 +424,8 @@ cli_vba_readdir(const char *dir)
close(fd); close(fd);
if(i < record_count) { if(i < record_count) {
while(--i >= 0)
free(vba_project->name[i]);
free(vba_project->name); free(vba_project->name);
free(vba_project->colls);
free(vba_project->dir); free(vba_project->dir);
free(vba_project->offset); free(vba_project->offset);
free(vba_project); free(vba_project);
@ -585,66 +545,68 @@ ole_copy_file_data(int s, int d, uint32_t len)
} }
int 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; uint32_t object_size;
struct stat statbuf; struct stat statbuf;
char *fullname; char *fullname;
if(dir == NULL)
return -1;
if(fd < 0) if(fd < 0)
return -1; return CL_CLEAN;
lseek(fd, 0, SEEK_SET);
if(!read_uint32(fd, &object_size, FALSE)) if(!read_uint32(fd, &object_size, FALSE))
return -1; return CL_CLEAN;
if(fstat(fd, &statbuf) == -1) if(fstat(fd, &statbuf) == -1)
return -1; return CL_EIO;
if ((statbuf.st_size - object_size) >= 4) { if ((statbuf.st_size - object_size) >= 4) {
/* Probably the OLE type id */ /* Probably the OLE type id */
if (lseek(fd, 2, SEEK_CUR) == -1) { if (lseek(fd, 2, SEEK_CUR) == -1) {
return -1; return CL_CLEAN;
} }
/* Attachment name */ /* Attachment name */
if(!skip_past_nul(fd)) if(!skip_past_nul(fd))
return -1; return CL_CLEAN;
/* Attachment full path */ /* Attachment full path */
if(!skip_past_nul(fd)) if(!skip_past_nul(fd))
return -1; return CL_CLEAN;
/* ??? */ /* ??? */
if(lseek(fd, 8, SEEK_CUR) == -1) if(lseek(fd, 8, SEEK_CUR) == -1)
return -1; return CL_CLEAN;
/* Attachment full path */ /* Attachment full path */
if(!skip_past_nul(fd)) if(!skip_past_nul(fd))
return -1; return CL_CLEAN;
if(!read_uint32(fd, &object_size, FALSE)) if(!read_uint32(fd, &object_size, FALSE))
return -1; return CL_CLEAN;
} }
if(!(fullname = cli_gentemp(dir))) { if(!(fullname = cli_gentemp(NULL))) {
return -1; return CL_EMEM;
} }
ofd = open(fullname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY|O_EXCL, ofd = open(fullname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY|O_EXCL,
S_IWUSR|S_IRUSR); S_IWUSR|S_IRUSR);
if (ofd < 0) { if (ofd < 0) {
cli_warnmsg("cli_decode_ole_object: can't create %s\n", fullname); cli_warnmsg("cli_decode_ole_object: can't create %s\n", fullname);
free(fullname); free(fullname);
return -1; return CL_EIO;
} else {
cli_dbgmsg("cli_decode_ole_object: decoding to %s\n", fullname);
} }
free(fullname); cli_dbgmsg("cli_decode_ole_object: decoding to %s\n", fullname);
ole_copy_file_data(fd, ofd, object_size); ole_copy_file_data(fd, ofd, object_size);
lseek(ofd, 0, SEEK_SET); 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 * char *
cli_ppt_vba_read(const char *filename) cli_ppt_vba_read(int ifd)
{ {
char *dir; char *dir;
const char *ret; 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 */ /* Create a directory to store the extracted OLE2 objects */
dir = cli_gentemp(NULL); dir = cli_gentemp(NULL);
@ -824,8 +773,7 @@ cli_ppt_vba_read(const char *filename)
free(dir); free(dir);
return NULL; return NULL;
} }
ret = ppt_stream_iter(fd, dir); ret = ppt_stream_iter(ifd, dir);
close(fd);
if(ret == NULL) { if(ret == NULL) {
cli_rmdirs(dir); cli_rmdirs(dir);
free(dir); free(dir);
@ -1083,43 +1031,32 @@ word_skip_macro_intnames(int fd)
} }
vba_project_t * vba_project_t *
cli_wm_readdir(const char *dir) cli_wm_readdir(int fd)
{ {
int fd, done; int done;
off_t end_offset; off_t end_offset;
unsigned char info_id; unsigned char info_id;
macro_info_t macro_info; macro_info_t macro_info;
vba_project_t *vba_project; vba_project_t *vba_project;
mso_fib_t fib; 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; 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) { if(fib.macro_len == 0) {
cli_dbgmsg("No macros detected\n"); cli_dbgmsg("wm_readdir: No macros detected\n");
/* Must be clean */ /* Must be clean */
close(fd);
return NULL; return NULL;
} }
cli_dbgmsg("macro offset: 0x%.4x\n", (int)fib.macro_offset); cli_dbgmsg("wm_readdir: 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 len: 0x%.4x\n\n", (int)fib.macro_len);
/* Go one past the start to ignore start_id */ /* Go one past the start to ignore start_id */
if (lseek(fd, fib.macro_offset + 1, SEEK_SET) != (off_t)(fib.macro_offset + 1)) { if (lseek(fd, fib.macro_offset + 1, SEEK_SET) != (off_t)(fib.macro_offset + 1)) {
cli_dbgmsg("lseek macro_offset failed\n"); cli_dbgmsg("wm_readdir: lseek macro_offset failed\n");
close(fd);
return NULL; return NULL;
} }
@ -1129,7 +1066,7 @@ cli_wm_readdir(const char *dir)
while((lseek(fd, 0, SEEK_CUR) < end_offset) && !done) { while((lseek(fd, 0, SEEK_CUR) < end_offset) && !done) {
if (cli_readn(fd, &info_id, 1) != 1) { 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; break;
} }
switch (info_id) { switch (info_id) {
@ -1160,17 +1097,16 @@ cli_wm_readdir(const char *dir)
done = TRUE; done = TRUE;
break; break;
default: default:
cli_dbgmsg("unknown type: 0x%x\n", info_id); cli_dbgmsg("wm_readdir: unknown type: 0x%x\n", info_id);
done = TRUE; done = TRUE;
} }
} }
close(fd);
if(macro_info.count == 0) if(macro_info.count == 0)
return NULL; return NULL;
vba_project = create_vba_project(macro_info.count, dir); vba_project = create_vba_project(macro_info.count, "", NULL);
if(vba_project) { if(vba_project) {
vba_project->length = (uint32_t *)cli_malloc(sizeof(uint32_t) * 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; const macro_entry_t *m = macro_info.entries;
for(i = 0; i < macro_info.count; i++) { for(i = 0; i < macro_info.count; i++) {
vba_project->name[i] = cli_strdup("WordDocument");
vba_project->offset[i] = m->offset; vba_project->offset[i] = m->offset;
vba_project->length[i] = m->len; vba_project->length[i] = m->len;
vba_project->key[i] = m->key; vba_project->key[i] = m->key;
@ -1191,6 +1126,7 @@ cli_wm_readdir(const char *dir)
} }
} else { } else {
free(vba_project->name); free(vba_project->name);
free(vba_project->colls);
free(vba_project->dir); free(vba_project->dir);
free(vba_project->offset); free(vba_project->offset);
if(vba_project->length) 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 * Create and initialise a vba_project structure
*/ */
static vba_project_t * 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; vba_project_t *ret;
@ -1304,13 +1240,16 @@ create_vba_project(int record_count, const char *dir)
if(ret == NULL) if(ret == NULL)
return 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->dir = cli_strdup(dir);
ret->offset = (uint32_t *)cli_malloc (sizeof(uint32_t) * record_count); ret->offset = (uint32_t *)cli_malloc (sizeof(uint32_t) * record_count);
if((ret->name == NULL) || (ret->dir == NULL) || (ret->offset == NULL)) { if((ret->name == NULL) || (ret->dir == NULL) || (ret->offset == NULL)) {
if(ret->dir) if(ret->dir)
free(ret->dir); free(ret->dir);
if(ret->colls)
free(ret->colls);
if(ret->name) if(ret->name)
free(ret->name); free(ret->name);
if(ret->offset) if(ret->offset)
@ -1319,6 +1258,7 @@ create_vba_project(int record_count, const char *dir)
return NULL; return NULL;
} }
ret->count = record_count; ret->count = record_count;
ret->U = U;
return ret; return ret;
} }

View file

@ -23,22 +23,26 @@
#ifndef __VBA_EXTRACT_H #ifndef __VBA_EXTRACT_H
#define __VBA_EXTRACT_H #define __VBA_EXTRACT_H
#include "others.h"
#include "cltypes.h" #include "cltypes.h"
#include "hashtab.h"
typedef struct vba_project_tag { typedef struct vba_project_tag {
char **name; uint32_t *name;
uint32_t *colls;
uint32_t *offset; uint32_t *offset;
uint32_t *length; /* for Word 6 macros */ uint32_t *length; /* for Word 6 macros */
unsigned char *key; /* for Word 6 macros */ unsigned char *key; /* for Word 6 macros */
char *dir; char *dir;
struct uniq *U;
int count; int count;
} vba_project_t; } 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); unsigned char *cli_vba_inflate(int fd, off_t offset, int *size);
int cli_decode_ole_object(int fd, const char *dir); int cli_scan_ole10(int fd, cli_ctx *ctx);
char *cli_ppt_vba_read(const char *filename); char *cli_ppt_vba_read(int fd);
vba_project_t *cli_wm_readdir(const char *dir);
unsigned char *cli_wm_decrypt_macro(int fd, off_t offset, uint32_t len, unsigned char *cli_wm_decrypt_macro(int fd, off_t offset, uint32_t len,
unsigned char key); unsigned char key);

View file

@ -293,6 +293,7 @@ struct cfgstruct *getcfg(const char *cfgfile, int verbose)
if(ctype == 'm' || ctype == 'k') { if(ctype == 'm' || ctype == 'k') {
char *cpy = (char *) calloc(strlen(arg), 1); char *cpy = (char *) calloc(strlen(arg), 1);
strncpy(cpy, arg, strlen(arg) - 1); strncpy(cpy, arg, strlen(arg) - 1);
cpy[strlen(arg)-1]='\0';
if(!cli_isnumber(cpy)) { if(!cli_isnumber(cpy)) {
if(verbose) if(verbose)
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name); fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name);

View file

@ -72,6 +72,7 @@ int tar_addfile(int fd, gzFile *gzs, const char *file)
memset(&hdr, 0, TARBLK); memset(&hdr, 0, TARBLK);
strncpy(hdr.name, file, 100); strncpy(hdr.name, file, 100);
hdr.name[99]='\0';
snprintf(hdr.size, 12, "%o", (unsigned int) sb.st_size); snprintf(hdr.size, 12, "%o", (unsigned int) sb.st_size);
pt = (unsigned char *) &hdr; pt = (unsigned char *) &hdr;
for(i = 0; i < TARBLK; i++) for(i = 0; i < TARBLK; i++)

View file

@ -258,6 +258,7 @@ static char *getdsig(const char *host, const char *user, const unsigned char *da
if((pt = getenv("SIGNDPASS"))) { if((pt = getenv("SIGNDPASS"))) {
strncpy(pass, pt, sizeof(pass)); strncpy(pass, pt, sizeof(pass));
pass[sizeof(pass)-1]='\0';
} else { } else {
mprintf("Password: "); mprintf("Password: ");
@ -281,12 +282,13 @@ static char *getdsig(const char *host, const char *user, const unsigned char *da
return NULL; return NULL;
} }
strncpy(pass, pt, sizeof(pass)); strncpy(pass, pt, sizeof(pass));
pass[sizeof(pass)-1]='\0';
free(pt); free(pt);
#ifdef HAVE_TERMIOS_H #ifdef HAVE_TERMIOS_H
if(tcsetattr(0, TCSAFLUSH, &old)) { if(tcsetattr(0, TCSAFLUSH, &old)) {
mprintf("!getdsig: tcsetattr() failed\n"); mprintf("!getdsig: tcsetattr() failed\n");
memset(pass, 0, strlen(pass)); memset(pass, 0, sizeof(pass));
return NULL; return NULL;
} }
#endif #endif
@ -300,7 +302,7 @@ static char *getdsig(const char *host, const char *user, const unsigned char *da
#endif #endif
perror("socket()"); perror("socket()");
mprintf("!getdsig: Can't create socket\n"); mprintf("!getdsig: Can't create socket\n");
memset(pass, 0, strlen(pass)); memset(pass, 0, sizeof(pass));
return NULL; return NULL;
} }
@ -312,7 +314,7 @@ static char *getdsig(const char *host, const char *user, const unsigned char *da
close(sockd); close(sockd);
perror("connect()"); perror("connect()");
mprintf("!getdsig: Can't connect to ClamAV Signing Service at %s\n", host); 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; return NULL;
} }
memset(cmd, 0, sizeof(cmd)); 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) { if(write(sockd, cmd, len) < 0) {
mprintf("!getdsig: Can't write to socket\n"); mprintf("!getdsig: Can't write to socket\n");
close(sockd); close(sockd);
memset(cmd, 0, len); memset(cmd, 0, sizeof(cmd));
memset(pass, 0, strlen(pass)); memset(pass, 0, sizeof(pass));
return NULL; return NULL;
} }
memset(cmd, 0, len); memset(cmd, 0, sizeof(cmd));
memset(pass, 0, strlen(pass)); memset(pass, 0, sizeof(pass));
memset(buff, 0, sizeof(buff)); memset(buff, 0, sizeof(buff));
if((bread = cli_readn(sockd, buff, sizeof(buff))) > 0) { if((bread = cli_readn(sockd, buff, sizeof(buff))) > 0) {
@ -587,6 +589,7 @@ static int build(struct optstruct *opt)
if(opt->filename) { if(opt->filename) {
if(cli_strbcasestr(opt->filename, ".cvd") || cli_strbcasestr(opt->filename, ".cld")) { if(cli_strbcasestr(opt->filename, ".cvd") || cli_strbcasestr(opt->filename, ".cld")) {
strncpy(olddb, opt->filename, sizeof(olddb)); strncpy(olddb, opt->filename, sizeof(olddb));
olddb[sizeof(olddb)-1]='\0';
} else { } else {
mprintf("!build: Not a CVD/CLD file\n"); mprintf("!build: Not a CVD/CLD file\n");
return -1; return -1;
@ -655,6 +658,7 @@ static int build(struct optstruct *opt)
if((pt = getenv("SIGNDUSER"))) { if((pt = getenv("SIGNDUSER"))) {
strncpy(builder, pt, sizeof(builder)); strncpy(builder, pt, sizeof(builder));
builder[sizeof(builder)-1]='\0';
} else { } else {
mprintf("Builder name: "); mprintf("Builder name: ");
if(scanf("%as", &pt) == EOF) { if(scanf("%as", &pt) == EOF) {
@ -662,6 +666,7 @@ static int build(struct optstruct *opt)
return -1; return -1;
} }
strncpy(builder, pt, sizeof(builder)); strncpy(builder, pt, sizeof(builder));
builder[sizeof(builder)-1]='\0';
free(pt); free(pt);
} }
@ -816,6 +821,7 @@ static int build(struct optstruct *opt)
return -1; return -1;
} }
strncpy(olddb, pt, sizeof(olddb)); strncpy(olddb, pt, sizeof(olddb));
olddb[sizeof(olddb)-1]='\0';
free(pt); free(pt);
if(!(pt = cli_gentemp(NULL))) { if(!(pt = cli_gentemp(NULL))) {
@ -896,6 +902,7 @@ static int unpack(struct optstruct *opt)
} else { } else {
strncpy(name, opt_arg(opt, "unpack"), sizeof(name)); strncpy(name, opt_arg(opt, "unpack"), sizeof(name));
name[sizeof(name)-1]='\0';
} }
if(cvd_unpack(name, ".") == -1) { if(cvd_unpack(name, ".") == -1) {
@ -1171,6 +1178,7 @@ static int vbadump(struct optstruct *opt)
int fd, hex_output; int fd, hex_output;
char *dir; char *dir;
const char *pt; const char *pt;
struct uniq *vba;
if(opt_check(opt, "vba-hex")) { if(opt_check(opt, "vba-hex")) {
@ -1200,15 +1208,15 @@ static int vbadump(struct optstruct *opt)
return -1; return -1;
} }
if(cli_ole2_extract(fd, dir, NULL)) { if(cli_ole2_extract(fd, dir, NULL, &vba)) {
cli_rmdirs(dir); cli_rmdirs(dir);
free(dir); free(dir);
close(fd); close(fd);
return -1; return -1;
} }
close(fd); close(fd);
sigtool_vba_scandir(dir, hex_output); if (vba)
sigtool_vba_scandir(dir, hex_output, vba);
cli_rmdirs(dir); cli_rmdirs(dir);
free(dir); free(dir);
return 0; return 0;
@ -1305,6 +1313,7 @@ static int compare(const char *oldpath, const char *newpath, FILE *diff)
if(found) { if(found) {
strncpy(tbuff, obuff, sizeof(tbuff)); strncpy(tbuff, obuff, sizeof(tbuff));
tbuff[sizeof(tbuff)-1]='\0';
for(i = 0; i < tline; i++) { for(i = 0; i < tline; i++) {
tbuff[16] = 0; tbuff[16] = 0;
if((pt = strchr(tbuff, ' '))) if((pt = strchr(tbuff, ' ')))

View file

@ -33,6 +33,10 @@
#include "libclamav/cltypes.h" #include "libclamav/cltypes.h"
#include "libclamav/ole2_extract.h" #include "libclamav/ole2_extract.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
typedef struct mac_token_tag typedef struct mac_token_tag
{ {
unsigned char token; unsigned char token;
@ -46,7 +50,7 @@ typedef struct mac_token2_tag
} mac_token2_t; } 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) static char *get_unicode_name (char *name, int size)
{ {
@ -979,6 +983,7 @@ static int sigtool_scandir (const char *dirname, int hex_output)
} }
} else { } else {
if (S_ISREG (statbuf.st_mode)) { if (S_ISREG (statbuf.st_mode)) {
struct uniq *vba;
tmpdir = getenv ("TMPDIR"); tmpdir = getenv ("TMPDIR");
if (tmpdir == NULL) if (tmpdir == NULL)
@ -1000,14 +1005,14 @@ static int sigtool_scandir (const char *dirname, int hex_output)
return 1; 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)); printf ("ERROR %s\n", cl_strerror (ret));
cli_rmdirs (dir); cli_rmdirs (dir);
free (dir); free (dir);
return ret; return ret;
} }
sigtool_vba_scandir (dir, hex_output); sigtool_vba_scandir (dir, hex_output, vba);
cli_rmdirs (dir); cli_rmdirs (dir);
free (dir); free (dir);
@ -1028,94 +1033,93 @@ static int sigtool_scandir (const char *dirname, int hex_output)
return 0; 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; vba_project_t *vba_project;
DIR *dd; DIR *dd;
struct dirent *dent; struct dirent *dent;
struct stat statbuf; struct stat statbuf;
char *fname, *fullname; char *fullname, vbaname[1024];
unsigned char *data; unsigned char *data;
uint32_t hashcnt, hash;
cli_dbgmsg ("VBA scan dir: %s\n", dirname); hashcnt = uniq_get(U, "_vba_project", 12, NULL);
if ((vba_project = (vba_project_t *)cli_vba_readdir(dirname))) { while(hashcnt--) {
if(!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) continue;
for (i = 0; i < vba_project->count; i++) { for(i = 0; i < vba_project->count; i++) {
fullname = (char *) malloc (strlen (vba_project->dir) + strlen (vba_project->name[i]) + 2); for(j = 0; j < vba_project->colls[i]; j++) {
sprintf (fullname, "%s/%s", vba_project->dir, vba_project->name[i]); snprintf(vbaname, 1024, "%s/%u_%u", vba_project->dir, vba_project->name[i], j);
fd = open (fullname, O_RDONLY); vbaname[sizeof(vbaname)-1] = '\0';
if (fd == -1) { fd = open(vbaname, O_RDONLY|O_BINARY);
cli_errmsg ("Scan->OLE2 -> Can't open file %s\n", fullname); if(fd == -1) continue;
free (fullname); data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
ret = CL_EOPEN; close(fd);
break;
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);
free (vba_project->name[i]); free(vba_project->colls);
free (vba_project->name); free(vba_project->dir);
free (vba_project->dir); free(vba_project->offset);
free (vba_project->offset); free(vba_project);
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);
if (!data) {
cli_dbgmsg ("WARNING: WM project '%s' macro %d decrypted to NULL\n", vba_project->name[i], i); if((hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
} else { while(hashcnt--) {
wm_decode_macro (data, vba_project->length[i], hex_output); snprintf(vbaname, 1024, "%s/%u_%u", dirname, hash, hashcnt);
free (data); vbaname[sizeof(vbaname)-1] = '\0';
} fd = open(vbaname, O_RDONLY|O_BINARY);
printf ("\n-------------- end of macro %d ------------------\n\n", i); 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) { if ((dd = opendir (dirname)) != NULL) {
@ -1123,15 +1127,15 @@ int sigtool_vba_scandir (const char *dirname, int hex_output)
if (dent->d_ino) { if (dent->d_ino) {
if (strcmp (dent->d_name, ".") && strcmp (dent->d_name, "..")) { if (strcmp (dent->d_name, ".") && strcmp (dent->d_name, "..")) {
/* build the full name */ /* build the full name */
fname = calloc (strlen (dirname) + strlen (dent->d_name) + 2, sizeof (char)); fullname = calloc (strlen (dirname) + strlen (dent->d_name) + 2, sizeof (char));
sprintf (fname, "%s/%s", dirname, dent->d_name); sprintf (fullname, "%s/%s", dirname, dent->d_name);
/* stat the file */ /* 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 (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);
} }
} }
} }

View file

@ -20,6 +20,7 @@
#ifndef __VBA_H #ifndef __VBA_H
#define __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 #endif