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