1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <errno.h>
6
7 #include "logger.h"
8 #include "pldstr.h"
9
10 #include "bytedecoders.h"
11 #include "olestream-unwrap.h"
12
13 #define DUW if (oleuw->debug)
14
15 struct OLE10_header{
16 unsigned char data[6];
17 char *attach_name;
18 unsigned char data2[8];
19 char *fname_1;
20 char *fname_2;
21 size_t attach_size;
22 size_t attach_size_1;
23 size_t attach_start_offset;
24 };
25
26 struct ESCHER_header_fixed {
27 int spid_max;
28 size_t cidcl;
29 size_t cspsaved;
30 size_t cdgsaved;
31 };
32
33 struct typesig {
34 char *sequence;
35 int length;
36 int offset;
37 };
38
39
40 /*-----------------------------------------------------------------\
41 Function Name : OLEUNWRAP_init
42 Returns Type : int
43 ----Parameter List
44 1. struct OLEUNWRAP_object *oleuw ,
45 ------------------
46 Exit Codes :
47 Side Effects :
48 --------------------------------------------------------------------
49 Comments:
50
51 --------------------------------------------------------------------
52 Changes:
53
54 \------------------------------------------------------------------*/
OLEUNWRAP_init(struct OLEUNWRAP_object * oleuw)55 int OLEUNWRAP_init( struct OLEUNWRAP_object *oleuw )
56 {
57 oleuw->debug = 0;
58 oleuw->verbose = 0;
59 oleuw->filename_report_fn = NULL;
60
61 return OLEUW_OK;
62 }
63
64 /*-----------------------------------------------------------------\
65 Function Name : OLEUNWRAP_set_debug
66 Returns Type : int
67 ----Parameter List
68 1. struct OLEUNWRAP_object *oleuw,
69 2. int level ,
70 ------------------
71 Exit Codes :
72 Side Effects :
73 --------------------------------------------------------------------
74 Comments:
75
76 --------------------------------------------------------------------
77 Changes:
78
79 \------------------------------------------------------------------*/
OLEUNWRAP_set_debug(struct OLEUNWRAP_object * oleuw,int level)80 int OLEUNWRAP_set_debug( struct OLEUNWRAP_object *oleuw, int level )
81 {
82 oleuw->debug = level;
83 return OLEUW_OK;
84 }
85
86 /*-----------------------------------------------------------------\
87 Function Name : OLEUNWRAP_set_verbose
88 Returns Type : int
89 ----Parameter List
90 1. struct OLEUNWRAP_object *oleuw,
91 2. int level ,
92 ------------------
93 Exit Codes :
94 Side Effects :
95 --------------------------------------------------------------------
96 Comments:
97
98 --------------------------------------------------------------------
99 Changes:
100
101 \------------------------------------------------------------------*/
OLEUNWRAP_set_verbose(struct OLEUNWRAP_object * oleuw,int level)102 int OLEUNWRAP_set_verbose( struct OLEUNWRAP_object *oleuw, int level )
103 {
104 oleuw->verbose = level;
105 return OLEUW_OK;
106 }
107
108 /*-----------------------------------------------------------------\
109 Function Name : OLEUNWRAP_set_save_unknown_streams
110 Returns Type : int
111 ----Parameter List
112 1. struct OLEUNWRAP_object *oleuw,
113 2. int level ,
114 ------------------
115 Exit Codes :
116 Side Effects :
117 --------------------------------------------------------------------
118 Comments:
119
120 --------------------------------------------------------------------
121 Changes:
122
123 \------------------------------------------------------------------*/
OLEUNWRAP_set_save_unknown_streams(struct OLEUNWRAP_object * oleuw,int level)124 int OLEUNWRAP_set_save_unknown_streams( struct OLEUNWRAP_object *oleuw, int level )
125 {
126 oleuw->save_unknown_streams = level;
127 return OLEUW_OK;
128 }
129
130
131 /*-----------------------------------------------------------------\
132 Function Name : OLEUNWRAP_save_stream
133 Returns Type : int
134 ----Parameter List
135 1. char *fname,
136 2. char *stream,
137 3. size_t bytes ,
138 ------------------
139 Exit Codes :
140 Side Effects :
141 --------------------------------------------------------------------
142 Comments:
143
144 --------------------------------------------------------------------
145 Changes:
146
147 \------------------------------------------------------------------*/
OLEUNWRAP_save_stream(struct OLEUNWRAP_object * oleuw,char * fname,char * decode_path,char * stream,size_t bytes)148 int OLEUNWRAP_save_stream( struct OLEUNWRAP_object *oleuw, char *fname, char *decode_path, char *stream, size_t bytes )
149 {
150 char *full_name;
151 FILE *f;
152 int result = 0;
153
154 DUW LOGGER_log("%s:%d:OLEUNWRAP_save_stream:DEBUG: fname=%s, decodepath=%s, size=%ld"
155 ,FL
156 ,fname
157 ,decode_path
158 ,bytes
159 );
160
161 full_name = PLD_dprintf("%s/%s", decode_path, fname );
162 if (full_name == NULL)
163 {
164 LOGGER_log("%s:%d:OLEUNWRAP_save_stream:ERROR: Unable to create filename string from '%s' and '%s'",FL,fname,decode_path);
165 return -1;
166 }
167
168 f = fopen(full_name,"w");
169 if (f != NULL)
170 {
171 size_t write_count;
172
173 write_count = fwrite( stream, 1, bytes, f );
174 if (write_count != bytes)
175 {
176 LOGGER_log("%s:%d:OLEUNWRAP_save_stream:WARNING: Only wrote %d of %d bytes to file %s\n",FL, write_count, bytes, full_name );
177 }
178
179 fclose(f);
180
181
182 } else {
183 LOGGER_log("%s:%d:OLEUNWRAP_save_stream:ERROR: Unable to open %s for writing (%s)\n",FL,full_name, strerror(errno));
184 result = -1;
185 }
186
187 if (full_name) free(full_name);
188
189 DUW LOGGER_log("%s:%d:OLEUNWRAP_save_stream:DEBUG: Done saving '%s'",FL, fname);
190
191 return result;
192 }
193
194 /*-----------------------------------------------------------------\
195 Function Name : OLEUNWRAP_sanitize_filename
196 Returns Type : int
197 ----Parameter List
198 1. char *fname ,
199 ------------------
200 Exit Codes :
201 Side Effects :
202 --------------------------------------------------------------------
203 Comments:
204
205 --------------------------------------------------------------------
206 Changes:
207
208 \------------------------------------------------------------------*/
OLEUNWRAP_sanitize_filename(char * fname)209 int OLEUNWRAP_sanitize_filename( char *fname )
210 {
211
212 if (fname == NULL) return 0;
213
214 while (*fname)
215 {
216 if( !isalnum((int)*fname) && (*fname != '.') ) *fname='_';
217 if( (*fname < ' ')||(*fname > '~') ) *fname='_';
218 fname++;
219 }
220 return 0;
221 }
222
223 /*-----------------------------------------------------------------\
224 Function Name : OLEUNWRAP_seach_for_file_sig
225 Returns Type : int
226 ----Parameter List
227 1. char *block ,
228 ------------------
229 Exit Codes : Returns the offset from the block to the
230 start of the signature.
231 Returns -1 if not found.
232
233 Side Effects :
234 --------------------------------------------------------------------
235 Comments:
236
237 --------------------------------------------------------------------
238 Changes:
239
240 \------------------------------------------------------------------*/
OLEUNWRAP_seach_for_file_sig(struct OLEUNWRAP_object * oleuw,char * block,size_t block_len)241 int OLEUNWRAP_seach_for_file_sig( struct OLEUNWRAP_object *oleuw, char *block, size_t block_len )
242 {
243 int result = -1;
244 int hit = 0;
245 char *p; /** signature pointer **/
246 char *bp; /** pointer in the block **/
247 struct typesig sigs[]= {
248 { "\x89\x50\x4e\x47", 4, 0 }, /** PNG **/
249 { "\xff\xd8\xff", 3, 0 }, /** JPEG **/
250 { NULL, -1, -1 } /** End of array **/
251 };
252
253 bp = block;
254 block_len -= 4;
255
256 /** While there's more data in the block and we're not found a match **/
257 while ((block_len > 0)&&(hit==0)) {
258 struct typesig *tsp; /** Type signature pointer **/
259
260 block_len--;
261
262 tsp = sigs; /** tsp points to the first signature in the array **/
263
264 /** While there's more valid signatures in the array **/
265 while (tsp->length > 0) {
266 int cmpresult = 0;
267
268 p = tsp->sequence; /** set p to point to the start of the image signature sequence **/
269 cmpresult = memcmp(bp, p, 3);
270 if (cmpresult == 0) {
271 DUW LOGGER_log("%s:%d:OLEUNWRAP_seach_for_file_sig:DEBUG: Hit at offset %d for signature %d",FL,(bp-block),(tsp -sigs));
272 hit = 1;
273 break;
274 } /** If we had a match in the signatures **/
275
276 tsp++; /** go to the next signature **/
277
278 } /** While more signatures **/
279
280 if (hit == 0) bp++; /** If we didn't get a hit, move to the next byte in the file **/
281
282 } /** while more data in the block **/
283
284 if (hit == 1) {
285 result = bp -block;
286 } else {
287 result = -1;
288 }
289
290 return result;
291 }
292
293
294
295 /** Look for PNG signature **/
296 /*-----------------------------------------------------------------\
297 Function Name : OLEUNWRAP_decode_attachment
298 Returns Type : int
299 ----Parameter List
300 1. char *stream ,
301 ------------------
302 Exit Codes :
303 Side Effects :
304 --------------------------------------------------------------------
305 Comments:
306
307 --------------------------------------------------------------------
308 Changes:
309
310 \------------------------------------------------------------------*/
OLEUNWRAP_decode_attachment(struct OLEUNWRAP_object * oleuw,char * stream,size_t stream_size,char * decode_path)311 int OLEUNWRAP_decode_attachment( struct OLEUNWRAP_object *oleuw, char *stream, size_t stream_size, char *decode_path )
312 {
313 struct OLE10_header oh;
314 char *sp = stream;
315 char *data_start_point = stream;
316 int result = OLEUW_OK;
317
318 // Get the data size
319 oh.attach_size_1 = (size_t)get_int32( sp );
320 sp += 4;
321
322 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: attachsize = %d [ 0x%x ], stream length = %d [ 0x%x] \n", FL, oh.attach_size_1, oh.attach_size_1, stream_size, stream_size );
323
324 oh.attach_start_offset = (stream_size -oh.attach_size_1);
325 data_start_point = stream +oh.attach_start_offset;
326
327 //if (oh.attach_start_offset == 4)
328 if (oh.attach_start_offset < 4)
329 {
330 int cbheader; // number of bytes in PIC
331 int mfpmm;
332 int mfpxext;
333 int mfpyext;
334 int mfphmf;
335
336 // check next 4 bytes.
337
338 cbheader = get_uint16( sp );
339 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: cbHeader = %d [ 0x%x ]", FL, cbheader, cbheader);
340 mfpmm = get_uint16( sp +2 );
341 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: mfp.mm = %d [ 0x%x ]", FL, mfpmm, mfpmm);
342 mfpxext = get_uint16( sp +4 );
343 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: mfp.xext = %d [ 0x%x ]", FL, mfpxext, mfpxext);
344 mfpyext = get_uint16( sp +8 );
345 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: mfp.yext = %d [ 0x%x ]", FL, mfpyext, mfpyext);
346 mfphmf = get_uint16( sp +10 );
347 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: mfp.hmf = %d [ 0x%x ]", FL, mfphmf, mfphmf);
348 // If we only had the stream byte-lenght in our header
349 // then we know we don't have a complex header.
350
351 DUW {
352 switch (mfpmm) {
353 case 100:
354 LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Image is Escher format",FL);
355 break;
356 case 99:
357 LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Image is Bitmapped",FL);
358 break;
359 case 98:
360 LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Image is TIFF",FL);
361 break;
362 default:
363 LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Unknown image type for code '%d'",FL, mfpmm);
364 }
365 }
366
367 data_start_point = sp +cbheader -4;
368
369
370 if (mfpmm == 100) {
371 int imageoffset = 0;
372 int search_size = 500;
373
374 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: searcing for image signatures",FL);
375 if (stream_size < (search_size +68)) search_size = (stream_size -69); /** just make sure we don't over-search the stream **/
376
377 imageoffset = OLEUNWRAP_seach_for_file_sig(oleuw, data_start_point, search_size);
378 if (imageoffset >= 0) {
379 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Image data found at offset %d",FL,imageoffset);
380 data_start_point += imageoffset;
381 } else {
382 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Could not detect image signature, dumping whole stream",FL);
383 }
384 }
385
386 oh.attach_name = PLD_dprintf("image-%ld",oh.attach_size_1);
387 oh.attach_size = oh.attach_size_1;
388 oh.fname_1 = oh.fname_2 = NULL;
389 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Setting attachment name to '%s', size = %d",FL,oh.attach_name, oh.attach_size);
390 } else {
391
392 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Decoding file information header",FL);
393 // Unknown memory segment
394 memcpy( oh.data, sp, 2 );
395 sp += 2;
396
397 // Full attachment string
398 oh.attach_name = strdup( sp );
399 sp = sp + strlen(oh.attach_name) +1;
400
401 // Attachment full path
402 oh.fname_1 = strdup( sp );
403 sp += strlen(oh.fname_1) +1;
404
405 // Unknown memory segment
406 memcpy( oh.data2, sp, 8 );
407 sp = sp +8;
408
409 // Attachment full path
410 oh.fname_2 = strdup( sp );
411 sp += strlen(oh.fname_2) +1;
412
413 oh.attach_size = (size_t)get_uint32( sp );
414 sp += 4;
415
416 if (oh.attach_size > stream_size) oh.attach_size = stream_size;
417
418 data_start_point = sp;
419 }
420
421 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Attachment %s:%s:%s size = %d\n",FL, oh.attach_name, oh.fname_1, oh.fname_2, oh.attach_size );
422
423
424 /** 20050119:2053:PLD - Added to sanitize 8-bit filenames **/
425 /** Sanitize the output filename **/
426 OLEUNWRAP_sanitize_filename(oh.attach_name);
427 OLEUNWRAP_sanitize_filename(oh.fname_1);
428 OLEUNWRAP_sanitize_filename(oh.fname_2);
429
430 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Sanitized attachment filenames",FL);
431
432 result = OLEUNWRAP_save_stream( oleuw, oh.attach_name, decode_path, data_start_point, oh.attach_size );
433 if (result == OLEUW_OK)
434 {
435 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Calling reporter for the filename",FL);
436 if ((oleuw->verbose > 0)&&(oleuw->filename_report_fn != NULL))
437 {
438 oleuw->filename_report_fn(oh.attach_name);
439 }
440 // Do call back to reporting function
441 }
442
443 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Cleaning up",FL);
444 // Clean up our previously allocated data
445 if (oh.fname_1 != NULL) free(oh.fname_1);
446 if (oh.attach_name != NULL) free(oh.attach_name);
447 if (oh.fname_2 != NULL) free(oh.fname_2);
448
449 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: done.",FL);
450 return OLEUW_OK;
451 }
452
453 /*-----------------------------------------------------------------\
454 Function Name : OLEUNWRAP_decodestream
455 Returns Type : int
456 ----Parameter List
457 1. char *element_string,
458 2. char *stream ,
459 ------------------
460 Exit Codes :
461 Side Effects :
462 --------------------------------------------------------------------
463 Comments:
464
465 --------------------------------------------------------------------
466 Changes:
467
468 \------------------------------------------------------------------*/
OLEUNWRAP_decodestream(struct OLEUNWRAP_object * oleuw,char * element_string,char * stream,size_t stream_size,char * decode_path)469 int OLEUNWRAP_decodestream( struct OLEUNWRAP_object *oleuw, char *element_string, char *stream, size_t stream_size, char *decode_path )
470 {
471 int result = OLEUW_OK;
472
473 if (strstr(element_string, OLEUW_ELEMENT_10NATIVE_STRING) != NULL)
474 {
475
476 DUW LOGGER_log("%s:%d:OLEUNWRAP_decodestream:DEBUG: Debugging element '%s'",FL, element_string);
477 OLEUNWRAP_decode_attachment( oleuw, stream, stream_size, decode_path );
478
479 } else if (strstr(element_string, OLEUW_ELEMENT_DATA) != NULL) {
480
481 DUW LOGGER_log("%s:%d:OLEUNWRAP_decodestream:DEBUG: Debugging element '%s'",FL, element_string);
482 OLEUNWRAP_decode_attachment( oleuw, stream, stream_size, decode_path );
483
484 } else {
485 DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Unable to decode stream with element string '%s'\n", FL, element_string);
486 result = OLEUW_STREAM_NOT_DECODED;
487 }
488
489 return result;
490 }
491
492
493 /*-----------------------------------------------------------------\
494 Function Name : OLEUNWRAP_set_filename_report_fn
495 Returns Type : int
496 ----Parameter List
497 1. struct OLEUNWRAP_object *oleuw,
498 2. int (*ptr_to_fn)(char *) ,
499 ------------------
500 Exit Codes :
501 Side Effects :
502 --------------------------------------------------------------------
503 Comments:
504
505 --------------------------------------------------------------------
506 Changes:
507
508 \------------------------------------------------------------------*/
OLEUNWRAP_set_filename_report_fn(struct OLEUNWRAP_object * oleuw,int (* ptr_to_fn)(char *))509 int OLEUNWRAP_set_filename_report_fn( struct OLEUNWRAP_object *oleuw, int (*ptr_to_fn)(char *) )
510 {
511
512 oleuw->filename_report_fn = ptr_to_fn;
513
514 return 0;
515 }
516
517