37
36
#include "clamav.h"
39
#include "clamav-config.h"
42
#include "vba_extract.h"
39
43
#include "others.h"
41
#include "vba_extract.h"
47
#define PPT_LZW_BUFFSIZE 8192
48
#define VBA_COMPRESSION_WINDOW 4096
49
#define MIDDLE_SIZE 20
50
#define MAX_VBA_COUNT 1000 /* If there's more than 1000 macros something's up! */
52
#ifndef HAVE_ATTRIB_PACKED
53
#define __attribute__(x)
57
* VBA (Visual Basic for Applications), versions 5 and 6
60
unsigned char magic[2];
61
unsigned char version[4];
62
unsigned char ignore[28];
68
int big_endian; /* e.g. MAC Office */
49
typedef struct vba_version_tag {
50
unsigned char signature[4];
71
static int skip_past_nul(int fd);
72
static int read_uint16(int fd, uint16_t *u, int big_endian);
73
static int read_uint32(int fd, uint32_t *u, int big_endian);
74
static int seekandread(int fd, off_t offset, int whence, void *data, size_t len);
75
static vba_project_t *create_vba_project(int record_count, const char *dir, struct uniq *U);
78
vba_endian_convert_16(uint16_t value, int big_endian)
57
static uint16_t vba_endian_convert_16(uint16_t value, int is_mac)
81
return (uint16_t)be16_to_host(value);
60
return be16_to_host(value);
83
62
return le16_to_host(value);
86
/* Seems to be a duplicate of riff_endian_convert_32() */
88
vba_endian_convert_32(uint32_t value, int big_endian)
65
static uint32_t vba_endian_convert_32(uint32_t value, int is_mac)
91
68
return be32_to_host(value);
93
70
return le32_to_host(value);
98
get_unicode_name(const char *name, int size, int big_endian)
73
typedef struct byte_array_tag {
78
#define NUM_VBA_VERSIONS 14
79
vba_version_t vba_version[] = {
80
{ { 0x5e, 0x00, 0x00, 0x01 }, "Office 97", 5, FALSE},
81
{ { 0x5f, 0x00, 0x00, 0x01 }, "Office 97 SR1", 5, FALSE },
82
{ { 0x65, 0x00, 0x00, 0x01 }, "Office 2000 alpha?", 6, FALSE },
83
{ { 0x6b, 0x00, 0x00, 0x01 }, "Office 2000 beta?", 6, FALSE },
84
{ { 0x6d, 0x00, 0x00, 0x01 }, "Office 2000", 6, FALSE },
85
{ { 0x6f, 0x00, 0x00, 0x01 }, "Office 2000", 6, FALSE },
86
{ { 0x70, 0x00, 0x00, 0x01 }, "Office XP beta 1/2", 6, FALSE },
87
{ { 0x73, 0x00, 0x00, 0x01 }, "Office XP", 6, FALSE },
88
{ { 0x76, 0x00, 0x00, 0x01 }, "Office 2003", 6, FALSE },
89
{ { 0x79, 0x00, 0x00, 0x01 }, "Office 2003", 6, FALSE },
90
{ { 0x60, 0x00, 0x00, 0x0e }, "MacOffice 98", 5, TRUE },
91
{ { 0x62, 0x00, 0x00, 0x0e }, "MacOffice 2001", 5, TRUE },
92
{ { 0x63, 0x00, 0x00, 0x0e }, "MacOffice X", 6, TRUE },
93
{ { 0x64, 0x00, 0x00, 0x0e }, "MacOffice 2004", 6, TRUE },
96
#define VBA56_DIRENT_RECORD_COUNT (2 + /* magic */ \
100
#define VBA56_DIRENT_HEADER_SIZE (VBA56_DIRENT_RECORD_COUNT + \
101
2 + /* type1 record count */ \
104
static char *get_unicode_name(char *name, int size, int is_mac)
103
if((name == NULL) || (*name == '\0') || (size <= 0))
106
newname = (char *)cli_malloc(size * 7 + 1);
110
if((!big_endian) && (size & 0x1)) {
111
cli_dbgmsg("get_unicode_name: odd number of bytes %d\n", size);
115
increment = (big_endian) ? 1 : 2;
118
for(i = 0; i < size; i += increment) {
119
if((!(name[i]&0x80)) && isprint(name[i])) {
120
*ret++ = tolower(name[i]);
122
if((name[i] < 10) && (name[i] >= 0)) {
124
*ret++ = (char)(name[i] + '0');
126
const uint16_t x = (uint16_t)((name[i] << 8) | name[i + 1]);
129
*ret++ = (char)('a'+((x&0xF)));
130
*ret++ = (char)('a'+((x>>4)&0xF));
131
*ret++ = (char)('a'+((x>>8)&0xF));
109
if (!name || *name == 0 || size <= 0) {
113
newname = (char *) cli_malloc(size*7);
118
for (i=0 ; i < size; i += (is_mac ? 1 : 2) ) {
119
if (isprint(name[i])) {
120
newname[j++] = name[i];
122
if (name[i] < 10 && name[i] >= 0) {
124
newname[j++] = name[i] + '0';
127
const uint16_t x = (((uint16_t)name[i]) << 8) | name[i+1];
129
newname[j++] = 'a'+((x&0xF));
130
newname[j++] = 'a'+((x>>4)&0xF);
131
newname[j++] = 'a'+((x>>8)&0xF);
132
newname[j++] = 'a'+((x>>16)&0xF);
133
newname[j++] = 'a'+((x>>24)&0xF);
141
/* Saves a lot of memory */
142
ret = cli_realloc(newname, (ret - newname) + 1);
143
return ret ? ret : newname;
147
142
static void vba56_test_middle(int fd)
149
char test_middle[MIDDLE_SIZE];
144
char test_middle[20];
151
146
/* MacOffice middle */
152
static const uint8_t middle1_str[MIDDLE_SIZE] = {
147
static const uint8_t middle1_str[20] = {
153
148
0x00, 0x01, 0x0d, 0x45, 0x2e, 0xe1, 0xe0, 0x8f, 0x10, 0x1a,
154
149
0x85, 0x2e, 0x02, 0x60, 0x8c, 0x4d, 0x0b, 0xb4, 0x00, 0x00
156
151
/* MS Office middle */
157
static const uint8_t middle2_str[MIDDLE_SIZE] = {
158
0x00, 0x00, 0xe1, 0x2e, 0x45, 0x0d, 0x8f, 0xe0, 0x1a, 0x10,
152
static const uint8_t middle2_str[20] = {
153
0x00, 0x00, 0xe1, 0x2e, 0x45, 0x0d, 0x8f, 0xe0, 0x1a, 0x10,
159
154
0x85, 0x2e, 0x02, 0x60, 0x8c, 0x4d, 0x0b, 0xb4, 0x00, 0x00
162
if(cli_readn(fd, &test_middle, MIDDLE_SIZE) != MIDDLE_SIZE)
157
if (cli_readn(fd, &test_middle, 20) != 20) {
165
if((memcmp(test_middle, middle1_str, MIDDLE_SIZE) != 0) &&
166
(memcmp(test_middle, middle2_str, MIDDLE_SIZE) != 0)) {
161
if ((memcmp(test_middle, middle1_str, 20) != 0) &&
162
(memcmp(test_middle, middle2_str, 20) != 0)) {
167
163
cli_dbgmsg("middle not found\n");
168
lseek(fd, -MIDDLE_SIZE, SEEK_CUR);
164
lseek(fd, -20, SEEK_CUR);
170
166
cli_dbgmsg("middle found\n");
174
vba_read_project_strings(int fd, int big_endian)
171
static int vba_read_project_strings(int fd, int is_mac)
176
unsigned char *buf = NULL;
185
if(!read_uint16(fd, &length, big_endian))
174
unsigned char *buff, *name;
178
if (cli_readn(fd, &length, 2) != 2) {
181
length = vba_endian_convert_16(length, is_mac);
188
182
if (length < 6) {
189
183
lseek(fd, -2, SEEK_CUR);
192
if(length > buflen) {
193
unsigned char *newbuf = (unsigned char *)cli_realloc(buf, length);
186
cli_dbgmsg ("length: %d, ", length);
187
buff = (unsigned char *) cli_malloc(length);
189
cli_errmsg("cli_malloc failed\n");
203
192
offset = lseek(fd, 0, SEEK_CUR);
205
if(cli_readn(fd, buf, length) != (int)length) {
193
if (cli_readn(fd, buff, length) != length) {
206
194
cli_dbgmsg("read name failed - rewinding\n");
207
195
lseek(fd, offset, SEEK_SET);
210
name = get_unicode_name((const char *)buf, length, big_endian);
211
cli_dbgmsg("length: %d, name: %s\n", length, (name) ? name : "[null]");
199
name = get_unicode_name(buff, length, is_mac);
201
cli_dbgmsg("name: %s\n", name);
203
cli_dbgmsg("name: [null]\n");
213
if((name == NULL) || (memcmp("*\\", name, 2) != 0) ||
214
(strchr("ghcd", name[2]) == NULL)) {
207
/* Ignore twelve bytes from entries of type 'G'.
208
Type 'C' entries come in pairs, the second also
209
having a 12 byte trailer */
210
/* TODO: Need to check if types H(same as G) and D(same as C) exist */
211
if (name && (!strncmp ("*\\G", name, 3) || !strncmp ("*\\H", name, 3)
212
|| !strncmp("*\\C", name, 3) || !strncmp("*\\D", name, 3))) {
213
if (cli_readn(fd, &length, 2) != 2) {
216
length = vba_endian_convert_16(length, is_mac);
217
if ((length != 0) && (length != 65535)) {
218
lseek(fd, -2, SEEK_CUR);
222
buff = (unsigned char *) cli_malloc(10);
228
if (cli_readn(fd, buff, 10) != 10) {
229
cli_errmsg("failed to read blob\n");
237
/* Unknown type - probably ran out of strings - rewind */
216
238
lseek(fd, -(length+2), SEEK_CUR);
223
if(!read_uint16(fd, &length, big_endian)) {
233
if ((length != 0) && (length != 65535)) {
234
lseek(fd, -2, SEEK_CUR);
237
offset = lseek(fd, 10, SEEK_CUR);
238
cli_dbgmsg("offset: %lu\n", (unsigned long)offset);
245
offset = lseek(fd, 0, SEEK_CUR);
246
cli_dbgmsg("offset: %u\n", offset);
239
247
vba56_test_middle(fd);
247
cli_vba_readdir(const char *dir, struct uniq *U, uint32_t which)
252
vba_project_t *vba56_dir_read(const char *dir)
250
const unsigned char vba56_signature[] = { 0xcc, 0x61 };
251
uint16_t record_count, buflen, ffff, byte_count;
254
unsigned char magic[2];
255
unsigned char version[4];
257
unsigned char vba56_signature[] = { 0xcc, 0x61 };
258
uint16_t record_count, length;
253
int i, j, fd, big_endian = FALSE;
262
uint32_t LidA; /* Language identifiers */
271
int i, j, fd, is_mac;
254
272
vba_project_t *vba_project;
255
struct vba56_header v56h;
257
char fullname[1024], *hash;
259
cli_dbgmsg("in cli_vba_readdir()\n");
265
* _VBA_PROJECT files are embedded within office documents (OLE2)
275
cli_dbgmsg("in vba56_dir_read()\n");
277
fullname = (char *) cli_malloc(strlen(dir) + 14);
281
sprintf(fullname, "%s/_VBA_PROJECT", dir);
282
fd = open(fullname, O_RDONLY|O_BINARY);
285
cli_dbgmsg("Can't open %s\n", fullname);
287
/* vba56_old_dir_read(dir); */
292
if (cli_readn(fd, &magic, 2) != 2) {
296
if (memcmp(magic, vba56_signature, 2) != 0) {
301
if (cli_readn(fd, &version, 4) != 4) {
305
for (i=0 ; i < NUM_VBA_VERSIONS ; i++) {
306
if (memcmp(version, vba_version[i].signature, 4) == 0) {
311
if (i == NUM_VBA_VERSIONS) {
312
cli_warnmsg("Unknown VBA version signature %x %x %x %x\n",
313
version[0], version[1], version[2], version[3]);
314
if (version[3] == 0x01) {
315
cli_warnmsg("Guessing little-endian\n");
317
} else if (version[3] == 0x0e) {
318
cli_warnmsg("Guessing big-endian\n");
321
cli_warnmsg("Unable to guess VBA type\n");
326
cli_dbgmsg("VBA Project: %s, VBA Version=%d\n", vba_version[i].name,
327
vba_version[i].vba_version);
328
is_mac = vba_version[i].is_mac;
331
/*****************************************/
333
/* two bytes, should be equal to 0x00ff */
334
if (cli_readn(fd, &ooff, 2) != 2) {
339
if (cli_readn(fd, &LidA, 4) != 4) {
344
if (cli_readn(fd, &LidB, 4) != 4) {
349
if (cli_readn(fd, &CharSet, 2) != 2) {
353
if (cli_readn(fd, &LenA, 2) != 2) {
358
if (cli_readn(fd, &UnknownB, 4) != 4) {
362
if (cli_readn(fd, &UnknownC, 4) != 4) {
367
if (cli_readn(fd, &LenB, 2) != 2) {
371
if (cli_readn(fd, &LenC, 2) != 2) {
375
if (cli_readn(fd, &LenD, 2) != 2) {
380
LidA = vba_endian_convert_32(LidA, is_mac);
381
LidB = vba_endian_convert_32(LidB, is_mac);
382
CharSet = vba_endian_convert_16(CharSet, is_mac);
383
LenA = vba_endian_convert_16(LenA, is_mac);
384
LenB = vba_endian_convert_16(LenB, is_mac);
385
LenC = vba_endian_convert_16(LenC, is_mac);
386
LenD = vba_endian_convert_16(LenD, is_mac);
388
cli_dbgmsg(" LidA: %d\n LidB: %d\n CharSet: %d\n", LidA, LidB, CharSet);
389
cli_dbgmsg(" LenA: %d\n UnknownB: %d\n UnknownC: %d\n", LenA, UnknownB, UnknownC);
390
cli_dbgmsg(" LenB: %d\n LenC: %d\n LenD: %d\n", LenB, LenC, LenD);
394
if (!vba_read_project_strings(fd, is_mac)) {
268
if (!uniq_get(U, "_vba_project", 12, &hash))
270
snprintf(fullname, sizeof(fullname), "%s"PATHSEP"%s_%u", dir, hash, which);
271
fullname[sizeof(fullname)-1] = '\0';
272
fd = open(fullname, O_RDONLY|O_BINARY);
277
if(cli_readn(fd, &v56h, sizeof(struct vba56_header)) != sizeof(struct vba56_header)) {
281
if (memcmp(v56h.magic, vba56_signature, sizeof(v56h.magic)) != 0) {
286
i = vba_read_project_strings(fd, TRUE);
287
seekback = lseek(fd, 0, SEEK_CUR);
288
if (lseek(fd, sizeof(struct vba56_header), SEEK_SET) == -1) {
292
j = vba_read_project_strings(fd, FALSE);
295
cli_dbgmsg("vba_readdir: Unable to guess VBA type\n");
300
lseek(fd, seekback, SEEK_SET);
301
cli_dbgmsg("vba_readdir: Guessing big-endian\n");
303
cli_dbgmsg("vba_readdir: Guessing little-endian\n");
306
399
/* junk some more stuff */
308
if (cli_readn(fd, &ffff, 2) != 2) {
401
if (cli_readn(fd, &ooff, 2) != 2) {
312
while(ffff != 0xFFFF);
405
} while(ooff != 0xFFFF);
314
407
/* check for alignment error */
315
if(!seekandread(fd, -3, SEEK_CUR, &ffff, sizeof(uint16_t))) {
408
lseek(fd, -3, SEEK_CUR);
409
if (cli_readn(fd, &ooff, 2) != 2) {
413
if (ooff != 0xFFFF) {
320
414
lseek(fd, 1, SEEK_CUR);
322
if(!read_uint16(fd, &ffff, big_endian)) {
328
lseek(fd, ffff, SEEK_CUR);
330
if(!read_uint16(fd, &ffff, big_endian)) {
338
lseek(fd, ffff + 100, SEEK_CUR);
340
if(!read_uint16(fd, &record_count, big_endian)) {
344
cli_dbgmsg("vba_readdir: VBA Record count %d\n", record_count);
417
if (cli_readn(fd, &ooff, 2) != 2) {
422
/* no idea what this stuff is */
423
if (ooff != 0xFFFF) {
424
ooff = vba_endian_convert_16(ooff, is_mac);
425
lseek(fd, ooff, SEEK_CUR);
427
if (cli_readn(fd, &ooff, 2) != 2) {
431
if (ooff != 0xFFFF) {
432
ooff = vba_endian_convert_16(ooff, is_mac);
433
lseek(fd, ooff, SEEK_CUR);
435
lseek(fd, 100, SEEK_CUR);
437
if (cli_readn(fd, &record_count, 2) != 2) {
441
record_count = vba_endian_convert_16(record_count, is_mac);
442
cli_dbgmsg("\nVBA Record count: %d\n", record_count);
345
443
if (record_count == 0) {
346
/* No macros, assume clean */
350
if (record_count > MAX_VBA_COUNT) {
447
if (record_count > 1000) {
351
448
/* Almost certainly an error */
352
cli_dbgmsg("vba_readdir: VBA Record count too big\n");
357
vba_project = create_vba_project(record_count, dir, U);
358
if(vba_project == NULL) {
364
for(i = 0; i < record_count; i++) {
368
vba_project->colls[i] = 0;
369
if(!read_uint16(fd, &length, big_endian))
449
cli_dbgmsg("\nVBA Record count too big");
454
vba_project = (vba_project_t *) cli_malloc(sizeof(struct vba_project_tag));
459
vba_project->name = (char **) cli_malloc(sizeof(char *) * record_count);
460
if (!vba_project->name) {
465
vba_project->dir = cli_strdup(dir);
466
vba_project->offset = (uint32_t *) cli_malloc (sizeof(uint32_t) *
468
if (!vba_project->offset) {
469
free(vba_project->dir);
470
free(vba_project->name);
475
vba_project->count = record_count;
476
for (i=0 ; i < record_count ; i++) {
477
if (cli_readn(fd, &length, 2) != 2) {
480
length = vba_endian_convert_16(length, is_mac);
372
481
if (length == 0) {
373
cli_dbgmsg("vba_readdir: zero name length\n");
376
if(length > buflen) {
377
unsigned char *newbuf = (unsigned char *)cli_realloc(buf, length);
383
if (cli_readn(fd, buf, length) != length) {
384
cli_dbgmsg("vba_readdir: read name failed\n");
387
ptr = get_unicode_name((const char *)buf, length, big_endian);
388
if(ptr == NULL) break;
389
if (!(vba_project->colls[i]=uniq_get(U, ptr, strlen(ptr), &hash))) {
390
cli_dbgmsg("vba_readdir: cannot find project %s (%s)\n", ptr, hash);
393
cli_dbgmsg("vba_readdir: project name: %s (%s)\n", ptr, hash);
395
vba_project->name[i] = hash;
396
if(!read_uint16(fd, &length, big_endian))
482
cli_dbgmsg("zero name length\n");
485
buff = (unsigned char *) cli_malloc(length);
487
cli_dbgmsg("cli_malloc failed\n");
490
if (cli_readn(fd, buff, length) != length) {
491
cli_dbgmsg("read name failed\n");
495
vba_project->name[i] = get_unicode_name(buff, length, is_mac);
496
if (!vba_project->name[i]) {
497
offset = lseek(fd, 0, SEEK_CUR);
498
vba_project->name[i] = (char *) cli_malloc(18);
499
snprintf(vba_project->name[i], 18, "clamav-%.10d", offset);
501
cli_dbgmsg("project name: %s, ", vba_project->name[i]);
504
/* some kind of string identifier ?? */
505
if (cli_readn(fd, &length, 2) != 2) {
506
free(vba_project->name[i]);
509
length = vba_endian_convert_16(length, is_mac);
398
510
lseek(fd, length, SEEK_CUR);
400
if(!read_uint16(fd, &ffff, big_endian))
402
if (ffff == 0xFFFF) {
513
if (cli_readn(fd, &ooff, 2) != 2) {
514
free(vba_project->name[i]);
517
ooff = vba_endian_convert_16(ooff, is_mac);
518
if (ooff == 0xFFFF) {
403
519
lseek(fd, 2, SEEK_CUR);
404
if(!read_uint16(fd, &ffff, big_endian))
406
lseek(fd, ffff + 8, SEEK_CUR);
408
lseek(fd, ffff + 10, SEEK_CUR);
520
if (cli_readn(fd, &ooff, 2) != 2) {
521
free(vba_project->name[i]);
524
ooff = vba_endian_convert_16(ooff, is_mac);
525
lseek(fd, ooff, SEEK_CUR);
527
lseek(fd, 2 + ooff, SEEK_CUR);
410
if(!read_uint16(fd, &byte_count, big_endian))
412
lseek(fd, (8 * byte_count) + 5, SEEK_CUR);
413
if(!read_uint32(fd, &offset, big_endian))
415
cli_dbgmsg("vba_readdir: offset: %u\n", (unsigned int)offset);
530
lseek(fd, 8, SEEK_CUR);
531
if (cli_readn(fd, &byte_count, 2) != 2) {
532
free(vba_project->name[i]);
535
byte_count = vba_endian_convert_16(byte_count, is_mac);
536
for (j=0 ; j<byte_count; j++) {
537
lseek(fd, 8, SEEK_CUR);
539
lseek(fd, 5, SEEK_CUR);
540
if (cli_readn(fd, &offset, 4) != 4) {
541
free(vba_project->name[i]);
544
offset = vba_endian_convert_32(offset, is_mac);
416
545
vba_project->offset[i] = offset;
546
cli_dbgmsg("offset:%u\n", offset);
417
547
lseek(fd, 2, SEEK_CUR);
551
{ /* There appears to be some code in here */
555
foffset = lseek(fd, 0, SEEK_CUR);
556
cli_dbgmsg("\nOffset: 0x%x\n", (unsigned int)foffset);
425
if(i < record_count) {
426
free(vba_project->name);
427
free(vba_project->colls);
428
free(vba_project->dir);
429
free(vba_project->offset);
434
559
return vba_project;
438
cli_vba_inflate(int fd, off_t offset, int *size)
440
unsigned int pos, shift, mask, distance, clean;
562
/* Note: only to be called from the above loop
563
when i == number of allocated stings */
564
for (j=0 ; j<i ; j++) {
565
free(vba_project->name[j]);
567
free(vba_project->name);
568
free(vba_project->dir);
569
free(vba_project->offset);
575
#define VBA_COMPRESSION_WINDOW 4096
577
static void byte_array_append(byte_array_t *array, unsigned char *src, unsigned int len)
579
if (array->length == 0) {
580
array->data = (unsigned char *) cli_malloc(len);
585
memcpy(array->data, src, len);
587
array->data = realloc(array->data, array->length+len);
591
memcpy(array->data+array->length, src, len);
592
array->length += len;
596
unsigned char *vba_decompress(int fd, uint32_t offset, int *size)
598
unsigned int i, pos=0, shift, win_pos, clean=TRUE, mask, distance;
444
601
unsigned char buffer[VBA_COMPRESSION_WINDOW];
454
lseek(fd, offset+3, SEEK_SET); /* 1byte ?? , 2byte length ?? */
607
lseek(fd, offset+3, SEEK_SET); /* 1byte ?? , 2byte length ?? */
458
609
while (cli_readn(fd, &flag, 1) == 1) {
459
for(mask = 1; mask < 0x100; mask<<=1) {
460
unsigned int winpos = pos % VBA_COMPRESSION_WINDOW;
610
for (mask = 1; mask < 0x100; mask<<=1) {
461
611
if (flag & mask) {
465
if(!read_uint16(fd, &token, FALSE)) {
612
if (cli_readn(fd, &token, 2) != 2) {
471
shift = 12 - (winpos > 0x10)
479
len = (uint16_t)((token & ((1 << shift) - 1)) + 3);
621
token = vba_endian_convert_16(token, FALSE);
622
win_pos = pos % VBA_COMPRESSION_WINDOW;
623
if (win_pos <= 0x80) {
624
if (win_pos <= 0x20) {
625
shift = (win_pos <= 0x10) ? 12:11;
627
shift = (win_pos <= 0x40) ? 10:9;
630
if (win_pos <= 0x200) {
631
shift = (win_pos <= 0x100) ? 8:7;
632
} else if (win_pos <= 0x800) {
633
shift = (win_pos <= 0x400) ? 6:5;
638
len = (token & ((1 << shift) -1)) + 3;
480
639
distance = token >> shift;
482
srcpos = pos - distance - 1;
483
if((((srcpos + len) % VBA_COMPRESSION_WINDOW) < winpos) &&
484
((winpos + len) < VBA_COMPRESSION_WINDOW) &&
485
(((srcpos % VBA_COMPRESSION_WINDOW) + len) < VBA_COMPRESSION_WINDOW) &&
486
(len <= VBA_COMPRESSION_WINDOW)) {
487
srcpos %= VBA_COMPRESSION_WINDOW;
488
memcpy(&buffer[winpos], &buffer[srcpos],
493
srcpos = (pos - distance - 1) % VBA_COMPRESSION_WINDOW;
494
buffer[pos++ % VBA_COMPRESSION_WINDOW] = buffer[srcpos];
642
for (i=0 ; i < len; i++) {
646
srcpos = (pos - distance - 1) % VBA_COMPRESSION_WINDOW;
648
buffer[pos++ % VBA_COMPRESSION_WINDOW]= c;
497
if((pos != 0) && (winpos == 0) && clean) {
652
((pos % VBA_COMPRESSION_WINDOW) == 0) && clean) {
498
654
if (cli_readn(fd, &token, 2) != 2) {
504
(void)blobAddData(b, buffer, VBA_COMPRESSION_WINDOW);
664
byte_array_append(&result, buffer, VBA_COMPRESSION_WINDOW);
508
if(cli_readn(fd, &buffer[winpos], 1) == 1)
667
if (cli_readn(fd, buffer+(pos%VBA_COMPRESSION_WINDOW), 1) == 1){
515
if(blobAddData(b, buffer, pos%VBA_COMPRESSION_WINDOW) < 0) {
523
*size = (int)blobGetDataSize(b);
524
return (unsigned char *)blobToMem(b);
528
* See also cli_filecopy()
531
ole_copy_file_data(int s, int d, uint32_t len)
533
unsigned char data[FILEBUFF];
536
int todo = MIN(sizeof(data), len);
538
if(cli_readn(s, data, (unsigned int)todo) != todo)
540
if(cli_writen(d, data, (unsigned int)todo) != todo)
547
cli_scan_ole10(int fd, cli_ctx *ctx)
675
if (pos % VBA_COMPRESSION_WINDOW) {
676
byte_array_append(&result, buffer, pos % VBA_COMPRESSION_WINDOW);
679
*size = result.length;
685
static uint32_t ole_copy_file_data(int ifd, int ofd, uint32_t len)
687
unsigned char data[8192];
688
unsigned int count, rem;
694
todo = MIN(8192, rem);
695
count = cli_readn(ifd, data, todo);
699
if (cli_writen(ofd, data, count) != count) {
700
return len-rem-count;
707
int cli_decode_ole_object(int fd, const char *dir)
550
712
uint32_t object_size;
557
lseek(fd, 0, SEEK_SET);
558
if(!read_uint32(fd, &object_size, FALSE))
561
if(fstat(fd, &statbuf) == -1)
564
if ((statbuf.st_size - object_size) >= 4) {
714
if (fstat(fd, &statbuf) == -1) {
718
if (cli_readn(fd, &object_size, 4) != 4) {
721
object_size = vba_endian_convert_32(object_size, FALSE);
723
if ((statbuf.st_size - object_size) >= 4) {
565
724
/* Probably the OLE type id */
566
725
if (lseek(fd, 2, SEEK_CUR) == -1) {
570
/* Attachment name */
571
if(!skip_past_nul(fd))
574
/* Attachment full path */
575
if(!skip_past_nul(fd))
579
if(lseek(fd, 8, SEEK_CUR) == -1)
582
/* Attachment full path */
583
if(!skip_past_nul(fd))
586
if(!read_uint32(fd, &object_size, FALSE))
589
if(!(fullname = cli_gentemp(ctx ? ctx->engine->tmpdir : NULL))) {
592
ofd = open(fullname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY|O_EXCL,
595
cli_warnmsg("cli_decode_ole_object: can't create %s\n", fullname);
599
cli_dbgmsg("cli_decode_ole_object: decoding to %s\n", fullname);
729
/* Skip attachment name */
731
if (cli_readn(fd, &ch, 1) != 1) {
736
/* Skip attachment full path */
738
if (cli_readn(fd, &ch, 1) != 1) {
743
/* Skip unknown data */
744
if (lseek(fd, 8, SEEK_CUR) == -1) {
748
/* Skip attachment full path */
750
if (cli_readn(fd, &ch, 1) != 1) {
755
if (cli_readn(fd, &object_size, 4) != 4) {
758
object_size = vba_endian_convert_32(object_size, FALSE);
760
fullname = cli_malloc(strlen(dir) + 18);
761
sprintf(fullname, "%s/_clam_ole_object", dir);
762
ofd = open(fullname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600);
600
767
ole_copy_file_data(fd, ofd, object_size);
601
768
lseek(ofd, 0, SEEK_SET);
602
ret = cli_magic_scandesc(ofd, ctx);
604
if(ctx && !ctx->engine->keeptmp)
605
if (cli_unlink(fullname))
772
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
773
/* Code to extract Power Point Embedded OLE2 Objects */
774
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
776
typedef struct atom_header_tag {
620
ppt_read_atom_header(int fd, atom_header_t *atom_header)
785
static int ppt_read_atom_header(int fd, atom_header_t *atom_header)
629
cli_dbgmsg("in ppt_read_atom_header\n");
630
if(cli_readn(fd, &h, sizeof(struct ppt_header)) != sizeof(struct ppt_header)) {
631
cli_dbgmsg("read ppt_header failed\n");
634
v = vba_endian_convert_16(h.ver, FALSE);
635
cli_dbgmsg("\tversion: 0x%.2x\n", v & 0xF);
636
cli_dbgmsg("\tinstance: 0x%.2x\n", v >> 4);
638
atom_header->type = vba_endian_convert_16(h.type, FALSE);
639
cli_dbgmsg("\ttype: 0x%.4x\n", atom_header->type);
640
atom_header->length = vba_endian_convert_32(h.length, FALSE);
641
cli_dbgmsg("\tlength: 0x%.8x\n", (int)atom_header->length);
787
atom_header->foffset = lseek(fd, 0, SEEK_CUR);
788
if (cli_readn(fd, &atom_header->ver_inst, 2) != 2) {
789
cli_dbgmsg("read ppt_current_user failed\n");
792
atom_header->ver_inst = vba_endian_convert_16(atom_header->ver_inst, FALSE);
793
atom_header->version = atom_header->ver_inst & 0x000f;
794
atom_header->instance = atom_header->ver_inst >> 4;
795
if (cli_readn(fd, &atom_header->type, 2) != 2) {
796
cli_dbgmsg("read ppt_current_user failed\n");
799
if (cli_readn(fd, &atom_header->length, 4) != 4) {
800
cli_dbgmsg("read ppt_current_user failed\n");
803
atom_header->type = vba_endian_convert_16(atom_header->type, FALSE);
804
atom_header->length = vba_endian_convert_32(atom_header->length, FALSE);
647
* TODO: combine shared code with flatedecode() or cli_unzip_single()
648
* Needs cli_unzip_single to have a "length" argument
651
ppt_unlzw(const char *dir, int fd, uint32_t length)
808
static void ppt_print_atom_header(atom_header_t *atom_header)
810
cli_dbgmsg("Atom Hdr:\n");
811
cli_dbgmsg(" Version: 0x%.2x\n", atom_header->version);
812
cli_dbgmsg(" Instance: 0x%.4x\n", atom_header->instance);
813
cli_dbgmsg(" Type: 0x%.4x\n", atom_header->type);
814
cli_dbgmsg(" Length: 0x%.8x\n", atom_header->length);
817
#define PPT_LZW_BUFFSIZE 8192
818
static int ppt_unlzw(const char *dir, int fd, uint32_t length)
821
unsigned char inbuff[PPT_LZW_BUFFSIZE], outbuff[PPT_LZW_BUFFSIZE];
655
unsigned char inbuff[PPT_LZW_BUFFSIZE], outbuff[PPT_LZW_BUFFSIZE];
656
char fullname[NAME_MAX + 1];
658
snprintf(fullname, sizeof(fullname) - 1, "%s"PATHSEP"ppt%.8lx.doc",
659
dir, (long)lseek(fd, 0L, SEEK_CUR));
661
ofd = open(fullname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY|O_EXCL,
664
cli_warnmsg("ppt_unlzw: can't create %s\n", fullname);
826
fullname = cli_malloc(strlen(dir) + 17);
830
sprintf(fullname, "%s/ppt%.8lx.doc", dir, lseek(fd, 0, SEEK_CUR));
832
ofd = open(fullname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600);
835
cli_dbgmsg("ppt_unlzw Open outfile failed\n");
668
839
stream.zalloc = Z_NULL;
669
840
stream.zfree = Z_NULL;
670
stream.opaque = (void *)NULL;
671
stream.next_in = (Bytef *)inbuff;
841
stream.opaque = (void *)0;
843
stream.next_in = inbuff;
844
bufflen = stream.avail_in = MIN(length, PPT_LZW_BUFFSIZE);
846
if (cli_readn(fd, inbuff, stream.avail_in) != (int64_t)stream.avail_in) {
850
length -= stream.avail_in;
852
retval = inflateInit(&stream);
853
if (retval != Z_OK) {
854
cli_dbgmsg(" ppt_unlzw !Z_OK: %d\n", retval);
672
857
stream.next_out = outbuff;
673
stream.avail_out = sizeof(outbuff);
674
stream.avail_in = MIN(length, PPT_LZW_BUFFSIZE);
676
if(cli_readn(fd, inbuff, stream.avail_in) != (int)stream.avail_in) {
678
cli_unlink(fullname);
681
length -= stream.avail_in;
683
if(inflateInit(&stream) != Z_OK) {
685
cli_unlink(fullname);
686
cli_warnmsg("ppt_unlzw: inflateInit failed\n");
858
stream.avail_out = PPT_LZW_BUFFSIZE;
691
861
if (stream.avail_out == 0) {
692
862
if (cli_writen(ofd, outbuff, PPT_LZW_BUFFSIZE)
701
871
if (stream.avail_in == 0) {
702
872
stream.next_in = inbuff;
703
stream.avail_in = MIN(length, PPT_LZW_BUFFSIZE);
704
if (cli_readn(fd, inbuff, stream.avail_in) != (int)stream.avail_in) {
873
bufflen = stream.avail_in = MIN(length, PPT_LZW_BUFFSIZE);
874
if (cli_readn(fd, inbuff, stream.avail_in) != (int64_t)stream.avail_in) {
706
876
inflateEnd(&stream);
709
879
length -= stream.avail_in;
711
} while(inflate(&stream, Z_NO_FLUSH) == Z_OK);
713
if (cli_writen(ofd, outbuff, PPT_LZW_BUFFSIZE-stream.avail_out) != (int)(PPT_LZW_BUFFSIZE-stream.avail_out)) {
881
retval = inflate(&stream, Z_NO_FLUSH);
882
} while (retval == Z_OK);
884
if (cli_writen(ofd, outbuff, bufflen) != (int64_t)bufflen) {
715
886
inflateEnd(&stream);
719
return inflateEnd(&stream) == Z_OK;
723
ppt_stream_iter(int fd, const char *dir)
894
static char *ppt_stream_iter(int fd)
725
896
atom_header_t atom_header;
727
while(ppt_read_atom_header(fd, &atom_header)) {
728
if(atom_header.length == 0)
901
/* Create a directory to store the extracted OLE2 objects */
902
out_dir = cli_gentemp(NULL);
903
if(mkdir(out_dir, 0700)) {
904
printf("ScanOLE2 -> Can't create temporary directory %s\n", out_dir);
911
if (!ppt_read_atom_header(fd, &atom_header)) {
914
ppt_print_atom_header(&atom_header);
916
if (atom_header.length == 0) {
731
if(atom_header.type == 0x1011) {
735
if(lseek(fd, sizeof(uint32_t), SEEK_CUR) == -1) {
736
cli_dbgmsg("ppt_stream_iter: seek failed\n");
922
if (atom_header.type == 0x1011) {
923
if (cli_readn(fd, &ole_id, 4) != 4) {
924
cli_dbgmsg("read ole_id failed\n");
739
length = atom_header.length - 4;
740
cli_dbgmsg("length: %d\n", (int)length);
741
if (!ppt_unlzw(dir, fd, length)) {
929
ole_id = vba_endian_convert_32(ole_id, FALSE);
930
cli_dbgmsg("OleID: %d, length: %d\n",
931
ole_id, atom_header.length-4);
932
if (!ppt_unlzw(out_dir, fd, atom_header.length-4)) {
742
933
cli_dbgmsg("ppt_unlzw failed\n");
746
off_t offset = lseek(fd, 0, SEEK_CUR);
940
offset = lseek(fd, 0, SEEK_CUR);
747
941
/* Check we don't wrap */
748
942
if ((offset + (off_t)atom_header.length) < offset) {
751
945
offset += atom_header.length;
752
if (lseek(fd, offset, SEEK_SET) != offset) {
946
if (lseek(fd, offset, SEEK_SET) != offset ) {
761
cli_ppt_vba_read(int ifd, cli_ctx *ctx)
954
char *ppt_vba_read(const char *dir)
956
char *fullname, *out_dir;
766
/* Create a directory to store the extracted OLE2 objects */
767
dir = cli_gentemp(ctx ? ctx->engine->tmpdir : NULL);
770
if(mkdir(dir, 0700)) {
771
cli_errmsg("cli_ppt_vba_read: Can't create temporary directory %s\n", dir);
775
ret = ppt_stream_iter(ifd, dir);
959
fullname = (char *) cli_malloc(strlen(dir) + 21);
963
sprintf(fullname, "%s/PowerPoint Document", dir);
964
fd = open(fullname, O_RDONLY|O_BINARY);
967
cli_dbgmsg("Open PowerPoint Document failed\n");
971
out_dir = ppt_stream_iter(fd);
788
unsigned char unused[12];
789
uint32_t macro_offset;
977
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
978
/* Code to extract Word6 macros */
979
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
981
typedef struct mso_fib_tag {
988
/* block of 268 bytes - ignore */
989
uint32_t macro_offset;
793
993
typedef struct macro_entry_tag {
994
unsigned char version;
795
1002
uint32_t offset;
797
1003
} macro_entry_t;
799
1005
typedef struct macro_info_tag {
800
struct macro_entry_tag *entries;
1007
struct macro_entry_tag *macro_entry;
805
word_read_fib(int fd, mso_fib_t *fib)
812
if(!seekandread(fd, 0x118, SEEK_SET, ¯o_details, sizeof(macro_details))) {
813
cli_dbgmsg("read word_fib failed\n");
816
fib->macro_offset = vba_endian_convert_32(macro_details.offset, FALSE);
817
fib->macro_len = vba_endian_convert_32(macro_details.len, FALSE);
823
word_read_macro_entry(int fd, macro_info_t *macro_info)
826
int count = macro_info->count;
827
macro_entry_t *macro_entry;
828
#ifdef HAVE_PRAGMA_PACK
832
#ifdef HAVE_PRAGMA_PACK_HPPA
836
unsigned char version;
838
unsigned char ignore[10];
839
uint32_t len __attribute__ ((packed));
840
uint32_t state __attribute__ ((packed));
841
uint32_t offset __attribute__ ((packed));
843
const struct macro *n;
844
#ifdef HAVE_PRAGMA_PACK
848
#ifdef HAVE_PRAGMA_PACK_HPPA
854
msize = count * sizeof(struct macro);
855
m = cli_malloc(msize);
859
if(cli_readn(fd, m, msize) != msize) {
861
cli_warnmsg("read %d macro_entries failed\n", count);
864
macro_entry = macro_info->entries;
867
macro_entry->key = n->key;
868
macro_entry->len = vba_endian_convert_32(n->len, FALSE);
869
macro_entry->offset = vba_endian_convert_32(n->offset, FALSE);
872
} while(--count > 0);
877
static macro_info_t *
878
word_read_macro_info(int fd, macro_info_t *macro_info)
880
if(!read_uint16(fd, ¯o_info->count, FALSE)) {
1010
typedef struct macro_extname_tag {
1012
unsigned char *extname;
1016
typedef struct macro_extnames_tag {
1018
struct macro_extname_tag *macro_extname;
1021
typedef struct macro_intnames_tag {
1023
struct macro_intname_tag *macro_intname;
1026
typedef struct macro_intname_tag {
1029
unsigned char *intname;
1032
typedef struct menu_entry_tag {
1041
typedef struct menu_info_tag {
1043
struct menu_entry_tag *menu_entry;
1046
typedef struct mac_token_tag {
1047
unsigned char token;
1051
typedef struct mac_token2_tag {
1057
static void wm_print_fib(mso_fib_t *fib)
1059
cli_dbgmsg("magic: 0x%.4x\n", fib->magic);
1060
cli_dbgmsg("version: 0x%.4x\n", fib->version);
1061
cli_dbgmsg("product: 0x%.4x\n", fib->product);
1062
cli_dbgmsg("lid: 0x%.4x\n", fib->lid);
1063
cli_dbgmsg("macro offset: 0x%.4x\n", fib->macro_offset);
1064
cli_dbgmsg("macro len: 0x%.4x\n\n", fib->macro_len);
1067
static int wm_read_fib(int fd, mso_fib_t *fib)
1069
if (cli_readn(fd, &fib->magic, 2) != 2) {
1070
cli_dbgmsg("read wm_fib failed\n");
1073
if (cli_readn(fd, &fib->version, 2) != 2) {
1074
cli_dbgmsg("read wm_fib failed\n");
1077
if (cli_readn(fd, &fib->product, 2) != 2) {
1078
cli_dbgmsg("read wm_fib failed\n");
1081
if (cli_readn(fd, &fib->lid, 2) != 2) {
1082
cli_dbgmsg("read wm_fib failed\n");
1085
if (cli_readn(fd, &fib->next, 2) != 2) {
1086
cli_dbgmsg("read wm_fib failed\n");
1089
if (cli_readn(fd, &fib->status, 2) != 2) {
1090
cli_dbgmsg("read wm_fib failed\n");
1094
/* don't need the information is this block, so seek forward */
1095
if (lseek(fd, 0x118, SEEK_SET) != 0x118) {
1096
cli_dbgmsg("lseek wm_fib failed\n");
1100
if (cli_readn(fd, &fib->macro_offset, 4) != 4) {
1101
cli_dbgmsg("read wm_fib failed\n");
1104
if (cli_readn(fd, &fib->macro_len, 4) != 4) {
1105
cli_dbgmsg("read wm_fib failed\n");
1108
fib->magic = vba_endian_convert_16(fib->magic, FALSE);
1109
fib->version = vba_endian_convert_16(fib->version, FALSE);
1110
fib->product = vba_endian_convert_16(fib->product, FALSE);
1111
fib->lid = vba_endian_convert_16(fib->lid, FALSE);
1112
fib->next = vba_endian_convert_16(fib->next, FALSE);
1113
fib->status = vba_endian_convert_16(fib->status, FALSE);
1114
fib->macro_offset = vba_endian_convert_32(fib->macro_offset, FALSE);
1115
fib->macro_len = vba_endian_convert_32(fib->macro_len, FALSE);
1120
static int wm_read_macro_entry(int fd, macro_entry_t *macro_entry)
1122
if (cli_readn(fd, ¯o_entry->version, 1) != 1) {
1123
cli_dbgmsg("read macro_entry failed\n");
1126
if (cli_readn(fd, ¯o_entry->key, 1) != 1) {
1127
cli_dbgmsg("read macro_entry failed\n");
1130
if (cli_readn(fd, ¯o_entry->intname_i, 2) != 2) {
1131
cli_dbgmsg("read macro_entry failed\n");
1134
if (cli_readn(fd, ¯o_entry->extname_i, 2) != 2) {
1135
cli_dbgmsg("read macro_entry failed\n");
1138
if (cli_readn(fd, ¯o_entry->xname_i, 2) != 2) {
1139
cli_dbgmsg("read macro_entry failed\n");
1142
if (cli_readn(fd, ¯o_entry->unknown, 4) != 4) {
1143
cli_dbgmsg("read macro_entry failed\n");
1146
if (cli_readn(fd, ¯o_entry->len, 4) != 4) {
1147
cli_dbgmsg("read macro_entry failed\n");
1150
if (cli_readn(fd, ¯o_entry->state, 4) != 4) {
1151
cli_dbgmsg("read macro_entry failed\n");
1154
if (cli_readn(fd, ¯o_entry->offset, 4) != 4) {
1155
cli_dbgmsg("read macro_entry failed\n");
1159
macro_entry->intname_i = vba_endian_convert_16(macro_entry->intname_i, FALSE);
1160
macro_entry->extname_i = vba_endian_convert_16(macro_entry->extname_i, FALSE);
1161
macro_entry->xname_i = vba_endian_convert_16(macro_entry->xname_i, FALSE);
1162
macro_entry->len = vba_endian_convert_32(macro_entry->len, FALSE);
1163
macro_entry->state = vba_endian_convert_32(macro_entry->state, FALSE);
1164
macro_entry->offset = vba_endian_convert_32(macro_entry->offset, FALSE);
1168
static macro_info_t *wm_read_macro_info(int fd)
1171
macro_info_t *macro_info;
1173
macro_info = (macro_info_t *) cli_malloc(sizeof(macro_info_t));
1177
if (cli_readn(fd, ¯o_info->count, 2) != 2) {
881
1178
cli_dbgmsg("read macro_info failed\n");
882
macro_info->count = 0;
1182
macro_info->count = vba_endian_convert_16(macro_info->count, FALSE);
885
1183
cli_dbgmsg("macro count: %d\n", macro_info->count);
886
if(macro_info->count == 0)
888
macro_info->entries = (macro_entry_t *)cli_malloc(sizeof(macro_entry_t) * macro_info->count);
889
if(macro_info->entries == NULL) {
890
macro_info->count = 0;
1184
macro_info->macro_entry = (macro_entry_t *)
1185
cli_malloc(sizeof(macro_entry_t) * macro_info->count);
1186
if (!macro_info->macro_entry) {
893
if(!word_read_macro_entry(fd, macro_info)) {
894
free(macro_info->entries);
895
macro_info->count = 0;
1190
for (i=0 ; i < macro_info->count ; i++) {
1191
if (!wm_read_macro_entry(fd,
1192
¯o_info->macro_entry[i])) {
1193
free(macro_info->macro_entry);
898
1198
return macro_info;
902
word_skip_oxo3(int fd)
1201
static void wm_free_macro_info(macro_info_t *macro_info)
1204
free(macro_info->macro_entry);
1210
static int wm_read_oxo3(int fd)
907
1215
cli_dbgmsg("read oxo3 record1 failed\n");
1218
if (lseek(fd, count*14, SEEK_CUR) == -1) {
1219
cli_dbgmsg("lseek oxo3 record1 failed\n");
910
1222
cli_dbgmsg("oxo3 records1: %d\n", count);
912
if(!seekandread(fd, count * 14, SEEK_CUR, &count, 1)) {
1224
if (cli_readn(fd, &count, 1) != 1) {
913
1225
cli_dbgmsg("read oxo3 record2 failed\n");
920
if(cli_readn(fd, twobytes, 2) != 2) {
1229
if (cli_readn(fd, &count, 1) != 1) {
921
1230
cli_dbgmsg("read oxo3 failed\n");
924
if(twobytes[0] != 2) {
925
lseek(fd, -2, SEEK_CUR);
1234
lseek(fd, -1, SEEK_CUR);
1237
if (cli_readn(fd, &count, 1) != 1) {
1238
cli_dbgmsg("read oxo3 failed\n");
931
1243
if (lseek(fd, (count*4)+1, SEEK_CUR) == -1) {
932
1244
cli_dbgmsg("lseek oxo3 failed\n");
936
1248
cli_dbgmsg("oxo3 records2: %d\n", count);
941
word_skip_menu_info(int fd)
1252
static menu_info_t *wm_read_menu_info(int fd)
945
if(!read_uint16(fd, &count, FALSE)) {
1255
menu_info_t *menu_info;
1256
menu_entry_t *menu_entry;
1258
menu_info = (menu_info_t *) cli_malloc(sizeof(menu_info_t));
1263
if (cli_readn(fd, &menu_info->count, 2) != 2) {
946
1264
cli_dbgmsg("read menu_info failed\n");
949
cli_dbgmsg("menu_info count: %d\n", count);
952
if(lseek(fd, count * 12, SEEK_CUR) == -1)
958
word_skip_macro_extnames(int fd)
960
int is_unicode, nbytes;
1268
menu_info->count = vba_endian_convert_16(menu_info->count, FALSE);
1269
cli_dbgmsg("menu_info count: %d\n", menu_info->count);
1271
menu_info->menu_entry =
1272
(menu_entry_t *) cli_malloc(sizeof(menu_entry_t) * menu_info->count);
1273
if (!menu_info->menu_entry) {
1278
for (i=0 ; i < menu_info->count ; i++) {
1279
menu_entry = &menu_info->menu_entry[i];
1280
if (cli_readn(fd, &menu_entry->context, 2) != 2) {
1283
if (cli_readn(fd, &menu_entry->menu, 2) != 2) {
1286
if (cli_readn(fd, &menu_entry->extname_i, 2) != 2) {
1289
if (cli_readn(fd, &menu_entry->unknown, 2) != 2) {
1292
if (cli_readn(fd, &menu_entry->intname_i, 2) != 2) {
1295
if (cli_readn(fd, &menu_entry->pos, 2) != 2) {
1298
menu_entry->context = vba_endian_convert_16(menu_entry->context, FALSE);
1299
menu_entry->menu = vba_endian_convert_16(menu_entry->menu, FALSE);
1300
menu_entry->extname_i = vba_endian_convert_16(menu_entry->extname_i, FALSE);
1301
menu_entry->intname_i = vba_endian_convert_16(menu_entry->intname_i, FALSE);
1302
menu_entry->pos = vba_endian_convert_16(menu_entry->pos, FALSE);
1303
cli_dbgmsg("menu entry: %d.%d\n", menu_entry->menu, menu_entry->pos);
1308
cli_dbgmsg("read menu_entry failed\n");
1309
free(menu_info->menu_entry);
1314
static void wm_free_menu_info(menu_info_t *menu_info)
1317
free(menu_info->menu_entry);
1323
static macro_extnames_t *wm_read_macro_extnames(int fd)
1325
int i, is_unicode=0;
963
if(!read_uint16(fd, (uint16_t *)&size, FALSE)) {
1328
macro_extnames_t *macro_extnames;
1329
macro_extname_t *macro_extname;
1330
unsigned char *name_tmp;
1332
macro_extnames = (macro_extnames_t *) cli_malloc(sizeof(macro_extnames_t));
1333
if (!macro_extnames) {
1336
macro_extnames->count = 0;
1337
macro_extnames->macro_extname = NULL;
1339
offset_end = lseek(fd, 0, SEEK_CUR);
1340
if (cli_readn(fd, &size, 2) != 2) {
964
1341
cli_dbgmsg("read macro_extnames failed\n");
1342
free(macro_extnames);
1345
size = vba_endian_convert_16(size, FALSE);
967
1346
if (size == -1) { /* Unicode flag */
968
if(!read_uint16(fd, (uint16_t *)&size, FALSE)) {
1348
if (cli_readn(fd, &size, 2) != 2) {
969
1349
cli_dbgmsg("read macro_extnames failed\n");
1350
free(macro_extnames);
1353
size = vba_endian_convert_16(size, FALSE);
976
1355
cli_dbgmsg("ext names size: 0x%x\n", size);
983
if (cli_readn(fd, &length, 1) != 1) {
984
cli_dbgmsg("read macro_extnames failed\n");
989
offset = (off_t)length * 2 + 1;
991
offset = (off_t)length;
993
/* ignore numref as well */
994
if(lseek(fd, offset + sizeof(uint16_t), SEEK_CUR) == -1) {
995
cli_dbgmsg("read macro_extnames failed to seek\n");
1004
word_skip_macro_intnames(int fd)
1008
if(!read_uint16(fd, &count, FALSE)) {
1358
while (lseek(fd, 0, SEEK_CUR) < offset_end) {
1359
macro_extnames->count++;
1360
macro_extnames->macro_extname = (macro_extname_t *)
1361
cli_realloc(macro_extnames->macro_extname,
1362
sizeof(macro_extname_t) * macro_extnames->count);
1363
if (macro_extnames->macro_extname == NULL) {
1364
cli_dbgmsg("read macro_extnames failed\n");
1368
macro_extname = ¯o_extnames->macro_extname[macro_extnames->count-1];
1370
if (cli_readn(fd, ¯o_extname->length, 1) != 1) {
1371
cli_dbgmsg("read macro_extnames failed\n");
1374
lseek(fd, 1, SEEK_CUR);
1375
if (macro_extname->length > 0) {
1376
name_tmp = (char *) cli_malloc(macro_extname->length*2);
1377
if (name_tmp == NULL) {
1380
if (cli_readn(fd, name_tmp, macro_extname->length*2) !=
1381
macro_extname->length*2) {
1382
cli_dbgmsg("read macro_extnames failed\n");
1386
macro_extname->extname =
1387
get_unicode_name(name_tmp, macro_extname->length*2, FALSE);
1390
macro_extname->extname = cli_strdup("[no name]");
1391
macro_extname->length = 10;
1394
if (cli_readn(fd, ¯o_extname->length, 1) != 1) {
1395
cli_dbgmsg("read macro_extnames failed\n");
1398
if (macro_extname->length > 0) {
1399
macro_extname->extname = (char *) cli_malloc(macro_extname->length+1);
1400
if (!macro_extname->extname) {
1403
if (cli_readn(fd, macro_extname->extname, macro_extname->length) !=
1404
macro_extname->length) {
1405
cli_dbgmsg("read macro_extnames failed\n");
1406
free(macro_extname->extname);
1409
macro_extname->extname[macro_extname->length] = '\0';
1411
macro_extname->extname = cli_strdup("[no name]");
1412
macro_extname->length = 10;
1415
if (cli_readn(fd, ¯o_extname->numref, 2) != 2) {
1416
cli_dbgmsg("read macro_extnames failed\n");
1419
macro_extname->numref = vba_endian_convert_16(macro_extname->numref, FALSE);
1420
cli_dbgmsg("ext name: %s\n", macro_extname->extname);
1422
return macro_extnames;
1425
if (macro_extnames->macro_extname != NULL) {
1426
for (i=0 ; i < macro_extnames->count-1 ; i++) {
1427
free(macro_extnames->macro_extname[i].extname);
1429
free(macro_extnames->macro_extname);
1431
free(macro_extnames);
1435
static void wm_free_extnames(macro_extnames_t *macro_extnames)
1439
if (macro_extnames) {
1440
for (i=0 ; i < macro_extnames->count ; i++) {
1441
free(macro_extnames->macro_extname[i].extname);
1443
free(macro_extnames->macro_extname);
1444
free(macro_extnames);
1449
static macro_intnames_t *wm_read_macro_intnames(int fd)
1452
macro_intnames_t *macro_intnames;
1453
macro_intname_t *macro_intname;
1456
macro_intnames = (macro_intnames_t *) cli_malloc(sizeof(macro_intnames_t));
1457
if (!macro_intnames) {
1461
if (cli_readn(fd, ¯o_intnames->count, 2) != 2) {
1009
1462
cli_dbgmsg("read macro_intnames failed\n");
1012
cli_dbgmsg("intnames count: %u\n", (unsigned int)count);
1014
while(count-- > 0) {
1018
if(!seekandread(fd, sizeof(uint16_t), SEEK_CUR, &length, sizeof(uint8_t))) {
1019
cli_dbgmsg("skip_macro_intnames failed\n");
1023
/* Internal name, plus one byte of unknown data */
1024
if(lseek(fd, length + 1, SEEK_CUR) == -1) {
1025
cli_dbgmsg("skip_macro_intnames failed\n");
1033
cli_wm_readdir(int fd)
1465
macro_intnames->count = vba_endian_convert_16(macro_intnames->count, FALSE);
1466
cli_dbgmsg("int names count: %d\n", macro_intnames->count);
1468
macro_intnames->macro_intname =
1469
(macro_intname_t *) cli_malloc(sizeof(macro_intname_t) * macro_intnames->count);
1470
if (!macro_intnames->macro_intname) {
1471
free(macro_intnames);
1474
for (i=0 ; i < macro_intnames->count ; i++) {
1475
macro_intname = ¯o_intnames->macro_intname[i];
1476
if (cli_readn(fd, ¯o_intname->id, 2) != 2) {
1477
cli_dbgmsg("read macro_intnames failed\n");
1478
macro_intnames->count = i;
1481
macro_intname->id = vba_endian_convert_16(macro_intname->id, FALSE);
1482
if (cli_readn(fd, ¯o_intname->length, 1) != 1) {
1483
cli_dbgmsg("read macro_intnames failed\n");
1484
macro_intnames->count = i;
1487
macro_intname->intname = (char *) cli_malloc(macro_intname->length+1);
1488
if (!macro_intname->intname) {
1489
macro_intnames->count = i;
1492
if (cli_readn(fd, macro_intname->intname, macro_intname->length) != macro_intname->length) {
1493
cli_dbgmsg("read macro_intnames failed\n");
1494
macro_intnames->count = i+1;
1497
macro_intname->intname[macro_intname->length] = '\0';
1498
if (cli_readn(fd, &junk, 1) != 1) {
1499
cli_dbgmsg("read macro_intnames failed\n");
1500
macro_intnames->count = i+1;
1503
cli_dbgmsg("int name: %s\n", macro_intname->intname);
1505
return macro_intnames;
1507
for (i=0 ; i < macro_intnames->count ; i++) {
1508
free(macro_intnames->macro_intname[i].intname);
1510
free(macro_intnames->macro_intname);
1511
free(macro_intnames);
1515
static void wm_free_intnames(macro_intnames_t *macro_intnames)
1519
if (macro_intnames) {
1520
for (i=0 ; i < macro_intnames->count ; i++) {
1521
free(macro_intnames->macro_intname[i].intname);
1523
free(macro_intnames->macro_intname);
1524
free(macro_intnames);
1529
vba_project_t *wm_dir_read(const char *dir)
1531
int fd, done=FALSE, i;
1036
1533
off_t end_offset;
1037
unsigned char info_id;
1038
macro_info_t macro_info;
1039
vba_project_t *vba_project;
1042
if (!word_read_fib(fd, &fib))
1045
if(fib.macro_len == 0) {
1046
cli_dbgmsg("wm_readdir: No macros detected\n");
1050
cli_dbgmsg("wm_readdir: macro offset: 0x%.4x\n", (int)fib.macro_offset);
1051
cli_dbgmsg("wm_readdir: macro len: 0x%.4x\n\n", (int)fib.macro_len);
1053
/* Go one past the start to ignore start_id */
1054
if (lseek(fd, fib.macro_offset + 1, SEEK_SET) != (off_t)(fib.macro_offset + 1)) {
1055
cli_dbgmsg("wm_readdir: lseek macro_offset failed\n");
1534
unsigned char start_id, info_id;
1535
macro_info_t *macro_info=NULL;
1536
menu_info_t *menu_info=NULL;
1537
macro_extnames_t *macro_extnames=NULL;
1538
macro_intnames_t *macro_intnames=NULL;
1539
vba_project_t *vba_project=NULL;
1542
fullname = (char *) cli_malloc(strlen(dir) + 14);
1546
sprintf(fullname, "%s/WordDocument", dir);
1547
fd = open(fullname, O_RDONLY|O_BINARY);
1550
cli_dbgmsg("Open WordDocument failed\n");
1554
if (!wm_read_fib(fd, &fib)) {
1560
if (lseek(fd, fib.macro_offset, SEEK_SET) != (int64_t)fib.macro_offset) {
1561
cli_dbgmsg("lseek macro_offset failed\n");
1059
1566
end_offset = fib.macro_offset + fib.macro_len;
1061
memset(¯o_info, '\0', sizeof(macro_info));
1063
while((lseek(fd, 0, SEEK_CUR) < end_offset) && !done) {
1568
if (cli_readn(fd, &start_id, 1) != 1) {
1569
cli_dbgmsg("read start_id failed\n");
1573
cli_dbgmsg("start_id: %d\n", start_id);
1575
while ((lseek(fd, 0, SEEK_CUR) < end_offset) && !done) {
1064
1576
if (cli_readn(fd, &info_id, 1) != 1) {
1065
cli_dbgmsg("wm_readdir: read macro_info failed\n");
1577
cli_dbgmsg("read macro_info failed\n");
1068
1581
switch (info_id) {
1070
if(macro_info.count)
1071
free(macro_info.entries);
1072
word_read_macro_info(fd, ¯o_info);
1583
macro_info = wm_read_macro_info(fd);
1584
if (macro_info == NULL) {
1076
if(!word_skip_oxo3(fd))
1589
if (!wm_read_oxo3(fd)) {
1080
if(!word_skip_menu_info(fd))
1594
menu_info = wm_read_menu_info(fd);
1595
if (menu_info == NULL) {
1084
if(!word_skip_macro_extnames(fd))
1600
macro_extnames = wm_read_macro_extnames(fd);
1601
if (macro_extnames == NULL) {
1088
if(!word_skip_macro_intnames(fd))
1606
macro_intnames = wm_read_macro_intnames(fd);
1607
if (macro_intnames == NULL) {
1091
case 0x40: /* end marker */
1092
case 0x12: /* ??? */
1612
/* No sure about these, always seems to
1613
come after the macros though, so finish
1096
cli_dbgmsg("wm_readdir: unknown type: 0x%x\n", info_id);
1102
if(macro_info.count == 0)
1105
vba_project = create_vba_project(macro_info.count, "", NULL);
1108
vba_project->length = (uint32_t *)cli_malloc(sizeof(uint32_t) *
1110
vba_project->key = (unsigned char *)cli_malloc(sizeof(unsigned char) *
1112
if((vba_project->length != NULL) &&
1113
(vba_project->key != NULL)) {
1115
const macro_entry_t *m = macro_info.entries;
1117
for(i = 0; i < macro_info.count; i++) {
1118
vba_project->offset[i] = m->offset;
1119
vba_project->length[i] = m->len;
1120
vba_project->key[i] = m->key;
1124
free(vba_project->name);
1125
free(vba_project->colls);
1126
free(vba_project->dir);
1127
free(vba_project->offset);
1128
if(vba_project->length)
1129
free(vba_project->length);
1130
if(vba_project->key)
1131
free(vba_project->key);
1136
free(macro_info.entries);
1622
cli_dbgmsg("\nunknown type: 0x%x\n", info_id);
1628
vba_project = (vba_project_t *) cli_malloc(sizeof(struct vba_project_tag));
1632
vba_project->name = (char **) cli_malloc(sizeof(char *) *macro_info->count);
1633
if (!vba_project->name) {
1638
vba_project->dir = cli_strdup(dir);
1639
vba_project->offset = (uint32_t *) cli_malloc(sizeof(uint32_t) *
1641
if (!vba_project->offset) {
1642
free(vba_project->name);
1643
free(vba_project->dir);
1648
vba_project->length = (uint32_t *) cli_malloc(sizeof(uint32_t) *
1650
if (!vba_project->length) {
1651
free(vba_project->offset);
1652
free(vba_project->name);
1653
free(vba_project->dir);
1658
vba_project->key = (unsigned char *) cli_malloc(sizeof(unsigned char) *
1660
if (!vba_project->key) {
1661
free(vba_project->length);
1662
free(vba_project->offset);
1663
free(vba_project->name);
1664
free(vba_project->dir);
1669
vba_project->count = macro_info->count;
1670
for (i=0 ; i < macro_info->count ; i++) {
1671
vba_project->name[i] = cli_strdup("WordDocument");
1672
vba_project->offset[i] = macro_info->macro_entry[i].offset;
1673
vba_project->length[i] = macro_info->macro_entry[i].len;
1674
vba_project->key[i] = macro_info->macro_entry[i].key;
1680
wm_free_macro_info(macro_info);
1683
wm_free_menu_info(menu_info);
1685
if (macro_extnames) {
1686
wm_free_extnames(macro_extnames);
1688
if (macro_intnames) {
1689
wm_free_intnames(macro_intnames);
1138
1692
return vba_project;
1142
cli_wm_decrypt_macro(int fd, off_t offset, uint32_t len, unsigned char key)
1695
unsigned char *wm_decrypt_macro(int fd, uint32_t offset, uint32_t len,
1144
1698
unsigned char *buff;
1152
buff = (unsigned char *)cli_malloc(len);
1156
if(!seekandread(fd, offset, SEEK_SET, buff, len)) {
1701
if (lseek(fd, offset, SEEK_SET) != (int64_t)offset) {
1704
buff = (unsigned char *) cli_malloc(len);
1709
if (cli_readn(fd, buff, len) != (int64_t)len) {
1163
for(p = buff; p < &buff[len]; p++)
1714
for (i=0 ; i < len; i++) {
1715
buff[i] = buff[i] ^ key;
1170
* Keep reading bytes until we reach a NUL. Returns 0 if none is found
1173
skip_past_nul(int fd)
1179
int nread = cli_readn(fd, smallbuf, sizeof(smallbuf));
1182
end = memchr(smallbuf, '\0', nread);
1184
if (lseek(fd, 1 + (end-smallbuf) - nread, SEEK_CUR) < 0)
1192
* Read 2 bytes as a 16-bit number, host byte order. Return success or fail
1195
read_uint16(int fd, uint16_t *u, int big_endian)
1197
if(cli_readn(fd, u, sizeof(uint16_t)) != sizeof(uint16_t))
1200
*u = vba_endian_convert_16(*u, big_endian);
1206
* Read 4 bytes as a 32-bit number, host byte order. Return success or fail
1209
read_uint32(int fd, uint32_t *u, int big_endian)
1211
if(cli_readn(fd, u, sizeof(uint32_t)) != sizeof(uint32_t))
1214
*u = vba_endian_convert_32(*u, big_endian);
1220
* Miss some bytes then read a bit
1223
seekandread(int fd, off_t offset, int whence, void *data, size_t len)
1225
if(lseek(fd, offset, whence) == (off_t)-1) {
1226
cli_dbgmsg("lseek failed\n");
1229
return cli_readn(fd, data, (unsigned int)len) == (int)len;
1233
* Create and initialise a vba_project structure
1235
static vba_project_t *
1236
create_vba_project(int record_count, const char *dir, struct uniq *U)
1240
ret = (vba_project_t *) cli_malloc(sizeof(struct vba_project_tag));
1245
ret->name = (char **)cli_malloc(sizeof(char *) * record_count);
1246
ret->colls = (uint32_t *)cli_malloc(sizeof(uint32_t) * record_count);
1247
ret->dir = cli_strdup(dir);
1248
ret->offset = (uint32_t *)cli_malloc (sizeof(uint32_t) * record_count);
1250
if((ret->name == NULL) || (ret->dir == NULL) || (ret->offset == NULL)) {
1262
ret->count = record_count;