git-svn: trunk@3352
Nigel Horne authored on 2007/11/02 03:32:17... | ... |
@@ -1,3 +1,8 @@ |
1 |
+Thu Nov 1 17:42:12 GMT 2007 (njh) |
|
2 |
+---------------------------------- |
|
3 |
+ * libclamav/vba_extract.c: More tidy ups. Fixed memory leak on error |
|
4 |
+ return |
|
5 |
+ |
|
1 | 6 |
Thu Nov 1 16:14:50 CET 2007 (acab) |
2 | 7 |
* libclamav/autoit: add support for type10(int64) and some misc fixes |
3 | 8 |
|
... | ... |
@@ -105,7 +105,7 @@ static uint32_t vba_endian_convert_32(uint32_t value, int is_mac) |
105 | 105 |
} |
106 | 106 |
|
107 | 107 |
#define NUM_VBA_VERSIONS 14 |
108 |
-static const vba_version_t vba_version[] = { |
|
108 |
+static const vba_version_t vba_version[NUM_VBA_VERSIONS] = { |
|
109 | 109 |
{ { 0x5e, 0x00, 0x00, 0x01 }, "Office 97", 5, FALSE}, |
110 | 110 |
{ { 0x5f, 0x00, 0x00, 0x01 }, "Office 97 SR1", 5, FALSE }, |
111 | 111 |
{ { 0x65, 0x00, 0x00, 0x01 }, "Office 2000 alpha?", 6, FALSE }, |
... | ... |
@@ -160,8 +160,10 @@ get_unicode_name(const char *name, int size, int is_mac) |
160 | 160 |
newname[j++] = (char)('a'+((x&0xF))); |
161 | 161 |
newname[j++] = (char)('a'+((x>>4)&0xF)); |
162 | 162 |
newname[j++] = (char)('a'+((x>>8)&0xF)); |
163 |
+#if 0 |
|
163 | 164 |
newname[j++] = (char)('a'+((x>>16)&0xF)); /* FIXME: x>>16 MUST == 0 */ |
164 | 165 |
newname[j++] = (char)('a'+((x>>24)&0xF)); /* FIXME: x>>24 MUST == 0 */ |
166 |
+#endif |
|
165 | 167 |
} |
166 | 168 |
newname[j++] = '_'; |
167 | 169 |
} |
... | ... |
@@ -199,7 +201,8 @@ static void vba56_test_middle(int fd) |
199 | 199 |
return; |
200 | 200 |
} |
201 | 201 |
|
202 |
-static int vba_read_project_strings(int fd, int is_mac) |
|
202 |
+static int |
|
203 |
+vba_read_project_strings(int fd, int is_mac) |
|
203 | 204 |
{ |
204 | 205 |
for (;;) { |
205 | 206 |
uint32_t offset; |
... | ... |
@@ -215,7 +218,6 @@ static int vba_read_project_strings(int fd, int is_mac) |
215 | 215 |
lseek(fd, -2, SEEK_CUR); |
216 | 216 |
break; |
217 | 217 |
} |
218 |
- cli_dbgmsg ("length: %d, ", length); |
|
219 | 218 |
buff = (unsigned char *) cli_malloc(length); |
220 | 219 |
if (!buff) { |
221 | 220 |
cli_errmsg("cli_malloc failed\n"); |
... | ... |
@@ -230,46 +232,35 @@ static int vba_read_project_strings(int fd, int is_mac) |
230 | 230 |
break; |
231 | 231 |
} |
232 | 232 |
name = get_unicode_name((const char *)buff, length, is_mac); |
233 |
- if (name) { |
|
234 |
- cli_dbgmsg("name: %s\n", name); |
|
235 |
- } else { |
|
236 |
- cli_dbgmsg("name: [null]\n"); |
|
237 |
- } |
|
233 |
+ if (name) |
|
234 |
+ cli_dbgmsg("length: %d, name: %s\n", length, name); |
|
235 |
+ else |
|
236 |
+ cli_dbgmsg("length: %d, name: [null]\n", length); |
|
238 | 237 |
free(buff); |
239 | 238 |
|
240 | 239 |
/* Ignore twelve bytes from entries of type 'G'. |
241 | 240 |
Type 'C' entries come in pairs, the second also |
242 | 241 |
having a 12 byte trailer */ |
243 | 242 |
/* TODO: Need to check if types H(same as G) and D(same as C) exist */ |
244 |
- if (name && (!strncmp ("*\\G", name, 3) || !strncmp ("*\\H", name, 3) |
|
245 |
- || !strncmp("*\\C", name, 3) || !strncmp("*\\D", name, 3))) { |
|
246 |
- char namebuff[10]; |
|
247 |
- |
|
248 |
- if (cli_readn(fd, &length, 2) != 2) { |
|
249 |
- return FALSE; |
|
250 |
- } |
|
251 |
- length = vba_endian_convert_16(length, is_mac); |
|
252 |
- if ((length != 0) && (length != 65535)) { |
|
253 |
- lseek(fd, -2, SEEK_CUR); |
|
254 |
- free(name); |
|
255 |
- continue; |
|
256 |
- } |
|
257 |
- if (cli_readn(fd, namebuff, sizeof(namebuff)) != sizeof(namebuff)) { |
|
258 |
- cli_errmsg("failed to read namebuff\n"); |
|
259 |
- free(name); |
|
260 |
- close(fd); |
|
261 |
- return FALSE; |
|
262 |
- } |
|
263 |
- } else { |
|
243 |
+ if((name == NULL) || (memcmp("*\\", name, 2) != 0) || |
|
244 |
+ (strchr("GCHD", name[2]) == NULL)) { |
|
264 | 245 |
/* Unknown type - probably ran out of strings - rewind */ |
265 | 246 |
lseek(fd, -(length+2), SEEK_CUR); |
266 |
- if (name) { |
|
247 |
+ if(name) |
|
267 | 248 |
free(name); |
268 |
- } |
|
269 | 249 |
break; |
270 | 250 |
} |
271 | 251 |
free(name); |
272 |
- offset = lseek(fd, 0, SEEK_CUR); |
|
252 |
+ |
|
253 |
+ if (cli_readn(fd, &length, 2) != 2) |
|
254 |
+ return FALSE; |
|
255 |
+ |
|
256 |
+ length = vba_endian_convert_16(length, is_mac); |
|
257 |
+ if ((length != 0) && (length != 65535)) { |
|
258 |
+ lseek(fd, -2, SEEK_CUR); |
|
259 |
+ continue; |
|
260 |
+ } |
|
261 |
+ offset = lseek(fd, 10, SEEK_CUR); |
|
273 | 262 |
cli_dbgmsg("offset: %u\n", offset); |
274 | 263 |
vba56_test_middle(fd); |
275 | 264 |
} |
... | ... |
@@ -337,14 +328,6 @@ vba_project_t *vba56_dir_read(const char *dir) |
337 | 337 |
is_mac = vba_version[i].is_mac; |
338 | 338 |
} |
339 | 339 |
|
340 |
-#if 0 |
|
341 |
- if((vba_endian_convert_16(v56h.ooff, is_mac) != 0xFF00)) { |
|
342 |
- cli_warnmsg("Expected 0xFF00, got 0x%x\n", v56h.ooff); |
|
343 |
- close(fd); |
|
344 |
- return NULL; |
|
345 |
- } |
|
346 |
-#endif |
|
347 |
- |
|
348 | 340 |
if (!vba_read_project_strings(fd, is_mac)) { |
349 | 341 |
close(fd); |
350 | 342 |
return NULL; |
... | ... |
@@ -447,17 +430,16 @@ vba_project_t *vba56_dir_read(const char *dir) |
447 | 447 |
break; |
448 | 448 |
} |
449 | 449 |
vba_project->name[i] = get_unicode_name((const char *)buff, length, is_mac); |
450 |
+ free(buff); |
|
450 | 451 |
if (!vba_project->name[i]) { |
451 | 452 |
offset = lseek(fd, 0, SEEK_CUR); |
452 | 453 |
vba_project->name[i] = (char *) cli_malloc(18); |
453 | 454 |
if(vba_project->name[i] == NULL) { |
454 |
- free(buff); |
|
455 | 455 |
break; |
456 | 456 |
} |
457 | 457 |
snprintf(vba_project->name[i], 18, "clamav-%.10d", (int)offset); |
458 | 458 |
} |
459 | 459 |
cli_dbgmsg("project name: %s, ", vba_project->name[i]); |
460 |
- free(buff); |
|
461 | 460 |
|
462 | 461 |
/* some kind of string identifier ?? */ |
463 | 462 |
if (cli_readn(fd, &length, 2) != 2) { |
... | ... |
@@ -785,6 +767,7 @@ static int ppt_unlzw(const char *dir, int fd, uint32_t length) |
785 | 785 |
|
786 | 786 |
if (cli_readn(fd, inbuff, stream.avail_in) != (int64_t)stream.avail_in) { |
787 | 787 |
close(ofd); |
788 |
+ unlink(fullname); |
|
788 | 789 |
return FALSE; |
789 | 790 |
} |
790 | 791 |
length -= stream.avail_in; |
... | ... |
@@ -888,16 +871,12 @@ static char *ppt_stream_iter(int fd) |
888 | 888 |
|
889 | 889 |
char *ppt_vba_read(const char *dir) |
890 | 890 |
{ |
891 |
- char *fullname, *out_dir; |
|
891 |
+ char *out_dir; |
|
892 | 892 |
int fd; |
893 |
+ char fullname[NAME_MAX + 1]; |
|
893 | 894 |
|
894 |
- fullname = (char *) cli_malloc(strlen(dir) + 21); |
|
895 |
- if (!fullname) { |
|
896 |
- return NULL; |
|
897 |
- } |
|
898 |
- sprintf(fullname, "%s/PowerPoint Document", dir); |
|
895 |
+ snprintf(fullname, sizeof(fullname) - 1, "%s/PowerPoint Document", dir); |
|
899 | 896 |
fd = open(fullname, O_RDONLY|O_BINARY); |
900 |
- free(fullname); |
|
901 | 897 |
if (fd == -1) { |
902 | 898 |
cli_dbgmsg("Open PowerPoint Document failed\n"); |
903 | 899 |
return NULL; |
... | ... |
@@ -917,7 +896,6 @@ typedef struct mso_fib_tag { |
917 | 917 |
char ununsed[sizeof(uint16_t) + sizeof(uint16_t) + |
918 | 918 |
sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) + |
919 | 919 |
sizeof(uint16_t)]; |
920 |
- /* block of 268 bytes - ignore */ |
|
921 | 920 |
uint32_t macro_offset; |
922 | 921 |
uint32_t macro_len; |
923 | 922 |
} mso_fib_t; |
... | ... |
@@ -970,11 +948,6 @@ typedef struct menu_entry_tag { |
970 | 970 |
uint16_t pos; |
971 | 971 |
} menu_entry_t; |
972 | 972 |
|
973 |
-typedef struct menu_info_tag { |
|
974 |
- uint16_t count; |
|
975 |
- struct menu_entry_tag *menu_entry; |
|
976 |
-} menu_info_t; |
|
977 |
- |
|
978 | 973 |
typedef struct mac_token_tag { |
979 | 974 |
unsigned char token; |
980 | 975 |
unsigned char *str; |
... | ... |
@@ -1149,74 +1122,22 @@ static int wm_read_oxo3(int fd) |
1149 | 1149 |
return TRUE; |
1150 | 1150 |
} |
1151 | 1151 |
|
1152 |
-static menu_info_t *wm_read_menu_info(int fd) |
|
1152 |
+static int |
|
1153 |
+wm_skip_menu_info(int fd) |
|
1153 | 1154 |
{ |
1154 |
- int i; |
|
1155 |
- menu_info_t *menu_info; |
|
1156 |
- menu_entry_t *menu_entry; |
|
1157 |
- |
|
1158 |
- menu_info = (menu_info_t *) cli_malloc(sizeof(menu_info_t)); |
|
1159 |
- if (!menu_info) { |
|
1160 |
- return NULL; |
|
1161 |
- } |
|
1155 |
+ uint16_t count; |
|
1162 | 1156 |
|
1163 |
- if (cli_readn(fd, &menu_info->count, 2) != 2) { |
|
1157 |
+ if (cli_readn(fd, &count, sizeof(uint16_t)) != sizeof(uint16_t)) { |
|
1164 | 1158 |
cli_dbgmsg("read menu_info failed\n"); |
1165 |
- free(menu_info); |
|
1166 |
- return NULL; |
|
1167 |
- } |
|
1168 |
- menu_info->count = vba_endian_convert_16(menu_info->count, FALSE); |
|
1169 |
- cli_dbgmsg("menu_info count: %d\n", menu_info->count); |
|
1170 |
- |
|
1171 |
- menu_info->menu_entry = |
|
1172 |
- (menu_entry_t *) cli_malloc(sizeof(menu_entry_t) * menu_info->count); |
|
1173 |
- if (!menu_info->menu_entry) { |
|
1174 |
- free(menu_info); |
|
1175 |
- return NULL; |
|
1176 |
- } |
|
1177 |
- |
|
1178 |
- for (i=0 ; i < menu_info->count ; i++) { |
|
1179 |
- menu_entry = &menu_info->menu_entry[i]; |
|
1180 |
- if (cli_readn(fd, &menu_entry->context, 2) != 2) { |
|
1181 |
- goto abort; |
|
1182 |
- } |
|
1183 |
- if (cli_readn(fd, &menu_entry->menu, 2) != 2) { |
|
1184 |
- goto abort; |
|
1185 |
- } |
|
1186 |
- if (cli_readn(fd, &menu_entry->extname_i, 2) != 2) { |
|
1187 |
- goto abort; |
|
1188 |
- } |
|
1189 |
- if (cli_readn(fd, &menu_entry->unknown, 2) != 2) { |
|
1190 |
- goto abort; |
|
1191 |
- } |
|
1192 |
- if (cli_readn(fd, &menu_entry->intname_i, 2) != 2) { |
|
1193 |
- goto abort; |
|
1194 |
- } |
|
1195 |
- if (cli_readn(fd, &menu_entry->pos, 2) != 2) { |
|
1196 |
- goto abort; |
|
1197 |
- } |
|
1198 |
- menu_entry->context = vba_endian_convert_16(menu_entry->context, FALSE); |
|
1199 |
- menu_entry->menu = vba_endian_convert_16(menu_entry->menu, FALSE); |
|
1200 |
- menu_entry->extname_i = vba_endian_convert_16(menu_entry->extname_i, FALSE); |
|
1201 |
- menu_entry->intname_i = vba_endian_convert_16(menu_entry->intname_i, FALSE); |
|
1202 |
- menu_entry->pos = vba_endian_convert_16(menu_entry->pos, FALSE); |
|
1203 |
- cli_dbgmsg("menu entry: %d.%d\n", menu_entry->menu, menu_entry->pos); |
|
1159 |
+ return FALSE; |
|
1204 | 1160 |
} |
1205 |
- return menu_info; |
|
1206 |
- |
|
1207 |
-abort: |
|
1208 |
- cli_dbgmsg("read menu_entry failed\n"); |
|
1209 |
- free(menu_info->menu_entry); |
|
1210 |
- free(menu_info); |
|
1211 |
- return NULL; |
|
1212 |
-} |
|
1161 |
+ count = vba_endian_convert_16(count, FALSE); |
|
1162 |
+ cli_dbgmsg("menu_info count: %d\n", count); |
|
1213 | 1163 |
|
1214 |
-static void wm_free_menu_info(menu_info_t *menu_info) |
|
1215 |
-{ |
|
1216 |
- if (menu_info) { |
|
1217 |
- free(menu_info->menu_entry); |
|
1218 |
- free(menu_info); |
|
1219 |
- } |
|
1164 |
+ if(count) |
|
1165 |
+ if(lseek(fd, count * 12, SEEK_CUR) == -1) |
|
1166 |
+ return FALSE; |
|
1167 |
+ return TRUE; |
|
1220 | 1168 |
} |
1221 | 1169 |
|
1222 | 1170 |
static macro_extnames_t *wm_read_macro_extnames(int fd) |
... | ... |
@@ -1420,20 +1341,13 @@ vba_project_t *wm_dir_read(const char *dir) |
1420 | 1420 |
int fd, done=FALSE, i; |
1421 | 1421 |
mso_fib_t fib; |
1422 | 1422 |
off_t end_offset; |
1423 |
- unsigned char start_id, info_id; |
|
1423 |
+ unsigned char info_id; |
|
1424 | 1424 |
macro_info_t *macro_info=NULL; |
1425 |
- macro_extnames_t *macro_extnames=NULL; |
|
1426 |
- macro_intnames_t *macro_intnames=NULL; |
|
1427 | 1425 |
vba_project_t *vba_project=NULL; |
1428 |
- char *fullname; |
|
1426 |
+ char fullname[NAME_MAX + 1]; |
|
1429 | 1427 |
|
1430 |
- fullname = (char *) cli_malloc(strlen(dir) + 14); |
|
1431 |
- if (!fullname) { |
|
1432 |
- return NULL; |
|
1433 |
- } |
|
1434 |
- sprintf(fullname, "%s/WordDocument", dir); |
|
1428 |
+ snprintf(fullname, sizeof(fullname) - 1, "%s/WordDocument", dir); |
|
1435 | 1429 |
fd = open(fullname, O_RDONLY|O_BINARY); |
1436 |
- free(fullname); |
|
1437 | 1430 |
if (fd == -1) { |
1438 | 1431 |
cli_dbgmsg("Open WordDocument failed\n"); |
1439 | 1432 |
return NULL; |
... | ... |
@@ -1443,9 +1357,16 @@ vba_project_t *wm_dir_read(const char *dir) |
1443 | 1443 |
close(fd); |
1444 | 1444 |
return NULL; |
1445 | 1445 |
} |
1446 |
+ if(fib.macro_len == 0) { |
|
1447 |
+ cli_dbgmsg("No macros detected\n"); |
|
1448 |
+ /* Must be clean */ |
|
1449 |
+ close(fd); |
|
1450 |
+ return NULL; |
|
1451 |
+ } |
|
1446 | 1452 |
wm_print_fib(&fib); |
1447 | 1453 |
|
1448 |
- if (lseek(fd, fib.macro_offset, SEEK_SET) != (int64_t)fib.macro_offset) { |
|
1454 |
+ /* Go one past the start to ignore start_id */ |
|
1455 |
+ if (lseek(fd, fib.macro_offset + 1, SEEK_SET) != (off_t)(fib.macro_offset + 1)) { |
|
1449 | 1456 |
cli_dbgmsg("lseek macro_offset failed\n"); |
1450 | 1457 |
close(fd); |
1451 | 1458 |
return NULL; |
... | ... |
@@ -1453,15 +1374,9 @@ vba_project_t *wm_dir_read(const char *dir) |
1453 | 1453 |
|
1454 | 1454 |
end_offset = fib.macro_offset + fib.macro_len; |
1455 | 1455 |
|
1456 |
- if (cli_readn(fd, &start_id, 1) != 1) { |
|
1457 |
- cli_dbgmsg("read start_id failed\n"); |
|
1458 |
- close(fd); |
|
1459 |
- return NULL; |
|
1460 |
- } |
|
1461 |
- cli_dbgmsg("start_id: %d\n", start_id); |
|
1462 |
- |
|
1463 | 1456 |
while ((lseek(fd, 0, SEEK_CUR) < end_offset) && !done) { |
1464 |
- menu_info_t *menu_info; |
|
1457 |
+ macro_intnames_t *macro_intnames; |
|
1458 |
+ macro_extnames_t *macro_extnames; |
|
1465 | 1459 |
|
1466 | 1460 |
if (cli_readn(fd, &info_id, 1) != 1) { |
1467 | 1461 |
cli_dbgmsg("read macro_info failed\n"); |
... | ... |
@@ -1476,42 +1391,40 @@ vba_project_t *wm_dir_read(const char *dir) |
1476 | 1476 |
} |
1477 | 1477 |
break; |
1478 | 1478 |
case 0x03: |
1479 |
- if (!wm_read_oxo3(fd)) { |
|
1479 |
+ if(!wm_read_oxo3(fd)) |
|
1480 | 1480 |
done = TRUE; |
1481 |
- } |
|
1482 | 1481 |
break; |
1483 | 1482 |
case 0x05: |
1484 |
- menu_info = wm_read_menu_info(fd); |
|
1485 |
- if(menu_info) |
|
1486 |
- wm_free_menu_info(menu_info); |
|
1487 |
- else |
|
1483 |
+ if(!wm_skip_menu_info(fd)) |
|
1488 | 1484 |
done = TRUE; |
1489 | 1485 |
break; |
1490 | 1486 |
case 0x10: |
1491 | 1487 |
macro_extnames = wm_read_macro_extnames(fd); |
1492 |
- if (macro_extnames == NULL) { |
|
1488 |
+ if(macro_extnames) |
|
1489 |
+ wm_free_extnames(macro_extnames); |
|
1490 |
+ else |
|
1493 | 1491 |
done = TRUE; |
1494 |
- } |
|
1495 | 1492 |
break; |
1496 | 1493 |
case 0x11: |
1497 | 1494 |
macro_intnames = wm_read_macro_intnames(fd); |
1498 |
- if (macro_intnames == NULL) { |
|
1495 |
+ if(macro_intnames) |
|
1496 |
+ wm_free_intnames(macro_intnames); |
|
1497 |
+ else |
|
1499 | 1498 |
done = TRUE; |
1500 |
- } |
|
1501 | 1499 |
break; |
1502 | 1500 |
case 0x12: |
1503 | 1501 |
/* No sure about these, always seems to |
1504 | 1502 |
come after the macros though, so finish |
1505 | 1503 |
*/ |
1506 |
- done = 1; |
|
1504 |
+ done = TRUE; |
|
1507 | 1505 |
break; |
1508 | 1506 |
case 0x40: |
1509 | 1507 |
/* end marker */ |
1510 |
- done = 1; |
|
1508 |
+ done = TRUE; |
|
1511 | 1509 |
break; |
1512 | 1510 |
default: |
1513 | 1511 |
cli_dbgmsg("\nunknown type: 0x%x\n", info_id); |
1514 |
- done = 1; |
|
1512 |
+ done = TRUE; |
|
1515 | 1513 |
} |
1516 | 1514 |
} |
1517 | 1515 |
|
... | ... |
@@ -1568,15 +1481,8 @@ vba_project_t *wm_dir_read(const char *dir) |
1568 | 1568 |
} |
1569 | 1569 |
/* Fall through */ |
1570 | 1570 |
abort: |
1571 |
- if (macro_info) { |
|
1571 |
+ if (macro_info) |
|
1572 | 1572 |
wm_free_macro_info(macro_info); |
1573 |
- } |
|
1574 |
- if (macro_extnames) { |
|
1575 |
- wm_free_extnames(macro_extnames); |
|
1576 |
- } |
|
1577 |
- if (macro_intnames) { |
|
1578 |
- wm_free_intnames(macro_intnames); |
|
1579 |
- } |
|
1580 | 1573 |
close(fd); |
1581 | 1574 |
return vba_project; |
1582 | 1575 |
} |