Commit 209688eb7ca9580c3e8264865193f2a595d9972f

Authored by Philippe Lagadec
1 parent 31ce789a

rtfobj: added option -d to set the output directory (contribution by Thomas Jarosch)

Showing 1 changed file with 22 additions and 8 deletions
oletools/rtfobj.py
... ... @@ -48,8 +48,10 @@ http://www.decalage.info/python/oletools
48 48 # - extract files from OLE Package objects
49 49 # 2016-04-01 v0.04 PL: - fixed logging output to use stdout instead of stderr
50 50 # 2016-04-07 v0.45 PL: - improved parsing to handle some malware tricks
  51 +# 2016-05-06 v0.47 TJ: - added option -d to set the output directory
  52 +# (contribution by Thomas Jarosch)
51 53  
52   -__version__ = '0.45'
  54 +__version__ = '0.47'
53 55  
54 56 #------------------------------------------------------------------------------
55 57 # TODO:
... ... @@ -60,7 +62,7 @@ __version__ = '0.45'
60 62  
61 63 #=== IMPORTS =================================================================
62 64  
63   -import re, sys, string, binascii, logging, optparse
  65 +import re, os, sys, string, binascii, logging, optparse
64 66  
65 67 from thirdparty.xglob import xglob
66 68 from oleobj import OleObject, OleNativeStream
... ... @@ -280,7 +282,16 @@ def rtf_iter_objects (data, min_size=32):
280 282 match = re_hexblock.search(data, pos=current)
281 283  
282 284  
283   -def process_file(container, filename, data):
  285 +def process_file(container, filename, data, output_dir=None):
  286 + if output_dir:
  287 + if not os.path.isdir(output_dir):
  288 + log.info('creating output directory %s' % output_dir)
  289 + os.mkdir(output_dir)
  290 +
  291 + fname_prefix = os.path.join(output_dir, os.path.basename(filename))
  292 + else:
  293 + fname_prefix = filename
  294 +
284 295 # TODO: option to extract objects to files (false by default)
285 296 if data is None:
286 297 data = open(filename, 'rb').read()
... ... @@ -288,7 +299,7 @@ def process_file(container, filename, data):
288 299 print 'File: %r - %d bytes' % (filename, len(data))
289 300 for index, orig_len, objdata in rtf_iter_objects(data):
290 301 print 'found object size %d at index %08X - end %08X' % (len(objdata), index, index+orig_len)
291   - fname = '%s_object_%08X.raw' % (filename, index)
  302 + fname = '%s_object_%08X.raw' % (fname_prefix, index)
292 303 print 'saving object to file %s' % fname
293 304 open(fname, 'wb').write(objdata)
294 305 # TODO: check if all hex data is extracted properly
... ... @@ -308,7 +319,8 @@ def process_file(container, filename, data):
308 319 ext = 'package'
309 320 else:
310 321 ext = 'bin'
311   - fname = '%s_object_%08X.%s' % (filename, index, ext)
  322 +
  323 + fname = '%s_object_%08X.%s' % (fname_prefix, index, ext)
312 324 print 'saving to file %s' % fname
313 325 open(fname, 'wb').write(obj.data)
314 326 if obj.class_name.lower() == 'package':
... ... @@ -318,9 +330,9 @@ def process_file(container, filename, data):
318 330 print 'Source path = %r' % opkg.src_path
319 331 print 'Temp path = %r' % opkg.temp_path
320 332 if opkg.filename:
321   - fname = '%s_%s' % (filename, opkg.filename)
  333 + fname = '%s_%s' % (fname_prefix, opkg.filename)
322 334 else:
323   - fname = '%s_object_%08X.noname' % (filename, index)
  335 + fname = '%s_object_%08X.noname' % (fname_prefix, index)
324 336 print 'saving to file %s' % fname
325 337 open(fname, 'wb').write(opkg.data)
326 338 except:
... ... @@ -354,6 +366,8 @@ if __name__ == '__main__':
354 366 # help='export results to a CSV file')
355 367 parser.add_option("-r", action="store_true", dest="recursive",
356 368 help='find files recursively in subdirectories.')
  369 + parser.add_option("-d", type="str", dest="output_dir",
  370 + help='use specified directory to output files.', default=None)
357 371 parser.add_option("-z", "--zip", dest='zip_password', type='str', default=None,
358 372 help='if the file is a zip archive, open first file from it, using the provided password (requires Python 2.6+)')
359 373 parser.add_option("-f", "--zipfname", dest='zip_fname', type='str', default='*',
... ... @@ -384,7 +398,7 @@ if __name__ == '__main__':
384 398 # ignore directory names stored in zip files:
385 399 if container and filename.endswith('/'):
386 400 continue
387   - process_file(container, filename, data)
  401 + process_file(container, filename, data, options.output_dir)
388 402  
389 403  
390 404  
... ...