Skip to content

Instantly share code, notes, and snippets.

@ca0s

ca0s/rtf.py

Created Dec 4, 2017
Embed
What would you like to do?
Simple RTF tool
#!/usr/bin/python2
import argparse
import olefile
import struct
import sys
def parse_objdata(obj):
cobj = obj.lstrip('\\')
cobj = cobj.lstrip("objdata ")
hobj = cobj.decode("hex")
hversion = hobj[:4]
hunk1 = hobj[4:8]
hsignlen = hobj[8:12]
p = 0
oleversion = hobj[p : p + 4]
p += 4
formatid = hobj[p : p + 4]
p += 4
classname_len = struct.unpack("<I", hobj[p : p + 4])[0]
p += 4
classname = hobj[p : p + classname_len]
p += classname_len
topicname_len = struct.unpack("<I", hobj[p : p + 4])[0]
p += 4
topicname = hobj[p : p + topicname_len]
p += topicname_len
itemname_len = struct.unpack("<I", hobj[p : p + 4])[0]
p += 4
itemname = hobj[p : p + itemname_len]
p += itemname_len
datasize = struct.unpack("<I", hobj[p : p + 4])[0]
p += 4
data = hobj[p : p + datasize]
p += datasize
ending = hobj[p : ]
return {
'version': oleversion,
'formatid': formatid,
'classname_len': classname_len,
'classname': classname,
'topicname_len': topicname_len,
'topicname': topicname,
'itemname_len': itemname_len,
'itemname': itemname,
'datalen': datasize,
'data': data,
'ending': ending
}
def create_objdata(data):
buf = 'objdata '
# version
buf += data['version'].encode("hex")
#formatid
buf += data['formatid'].encode("hex")
# classname_len
buf += struct.pack("<I", len(data['classname'])).encode("hex")
# classname
buf += data['classname'].encode("hex")
# topicname_len + empty topicname
buf += '00000000'
# itemname_len + empty itemname
buf += '00000000'
# data len
buf += struct.pack("<I", len(data['data'])).encode("hex")
# data
buf += data['data'].encode("hex")
# ending
buf += data['ending'].encode("hex")
return buf
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='RTF object mod tool')
parser.add_argument('--input', type=str, help='Input RTF file', required=True)
parser.add_argument('--output', type=str, help='Output RTF file')
parser.add_argument('--list', help='List objets in input RTF file', action='store_true')
parser.add_argument('--dump', help='Print the contents of the RTF file in a human-friendly format', action='store_true')
parser.add_argument('--replace', type=int, help='Object index to replace')
parser.add_argument('--withfile', type=str, help='File path of the new contents')
args = parser.parse_args()
if args.replace:
if (not args.output) or (not args.withfile):
parser.print_help()
sys.exit(-1)
try:
srcfd = open(args.input, "rb")
except:
print 'Could not open input file'
sys.exit(-1)
src = srcfd.read()
srcfd.close()
if args.replace:
try:
rplfd = open(args.withfile, "rb")
except:
print 'Could not open replacement file'
sys.exit(-1)
rpl = rplfd.read()
rplfd.close()
outbuf = ''
objcount = 0
level = 0
acc = ''
def handle_acc():
global args, acc, level, rpl, objcount, outbuf
ret = acc
if acc.startswith("objdata"):
objdata = parse_objdata(acc)
if args.list:
print '[+] Found object - index %s' % objcount
print '\tSignLen: %s - Sign: %s - DataLen: %s' % (objdata['classname_len'], objdata['classname'], objdata['datalen'])
print '\tReal data len: %s - Data starts with: %s' % (len(objdata['data']), objdata['data'][:16].encode("hex"))
ole = olefile.OleFileIO(objdata['data'])
try:
for s in ole.listdir():
sname = s[0]
print '\t\tStream/storage: %s (%s)' % (sname, sname.encode("hex"))
sdata = ole.openstream(sname).read()
print '\t\tStarts with: %s' % sdata[:10].encode("hex")
except:
print '\t\tOLE file seems to be malformed'
if args.replace == objcount:
no = dict(objdata)
no['datalen'] = len(rpl)
no['data'] = rpl
newobj = create_objdata(no)
ret = newobj
objcount += 1
if acc != '':
if args.dump:
print level * '\t' + '\\' + acc
acc = ''
outbuf += ret
return ret
for b in src:
if b == '{':
handle_acc()
level += 1
outbuf += b
elif b == '\\':
handle_acc()
outbuf += b
elif b == '}':
handle_acc()
outbuf += b
level -= 1
if level == 0:
break
else:
acc += b
if args.replace:
try:
fo = open(args.output, "wb")
fo.write(outbuf)
fo.close()
print '[+] Replaced'
except:
print 'Could not open output file'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.