-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy pathhaystack-reverse
More file actions
188 lines (147 loc) · 6.62 KB
/
haystack-reverse
File metadata and controls
188 lines (147 loc) · 6.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2011 Loic Jaquemet loic.jaquemet+python@gmail.com
#
__author__ = "Loic Jaquemet loic.jaquemet+python@gmail.com"
__doc__ = '''
Reverse heap analysis.
'''
import argparse
import logging
import os
import sys
import haystack
from haystack import argparse_utils
from haystack.config import Config
from haystack.reverse import signature, reversers
log = logging.getLogger('haystack-reverse')
def reverseInstances(opt):
context = reversers.reverseInstances(opt.dumpname)
return
def writeReversedTypes(opt):
'''reverse types from a memorydump, and write structure definition to file '''
context, sizeCache = signature.makeSizeCaches(opt.dumpname)
context = signature.makeReversedTypes(context, sizeCache)
outfile = file(Config.getCacheFilename(Config.REVERSED_TYPES_FILENAME, context.dumpname),'w')
for revStructType in context.listReversedTypes():
outfile.write(revStructType.toString())
outfile.close()
log.info('[+] Wrote to %s'%(outfile.name))
return
def groupStructures(opt):
''' show sorted structure instances groups to stdout '''
context, sizeCache = signature.makeSizeCaches(opt.dumpname)
for chains in signature.buildStructureGroup(context, sizeCache, opt.size ):
signature.printStructureGroups(context, chains, opt.address )
return
def saveSignatures(opt):
''' translate a memdump into a signature based file NULL,POINTERS,OTHERS'''
context, sig = signature.makeSignatures(opt.dumpname)
outfile = Config.getCacheFilename(Config.SIGNATURES_FILENAME, context.dumpname)
file(outfile,'w').write(sig)
log.info('[+] Signature written to %s'%(outfile))
return
def show(opt):
''' Show a structure '''
log.info('[+] Load context')
context = reversers.getContext(opt.dumpname)
log.info('[+] Find Structure at: @%x'%(opt.address))
try:
st = context.getStructureForOffset(opt.address)
st.decodeFields()
print st.toString()
except ValueError,e:
log.info('[+] Found no structure.')
return
return
def printParents(opt):
''' print the parental structures '''
log.info('[+] Load context')
context = reversers.getContext(opt.dumpname)
log.info('[+] find offsets of struct_addr:%x'%(opt.address))
i = 0
try:
child_address = context.getStructureAddrForOffset(opt.address)
for st in context.listStructuresForPointerValue(child_address):
st.decodeFields()
print st.toString()
i+=1
except ValueError,e:
log.info('[+] Found no structures.')
return
log.info('[+] Found %d structures.'%( i ))
return
def clean(opt):
log.info('[+] Cleaning cache')
context = Config.cleanCache(opt.dumpname)
def graph(opt):
''' show sorted structure instances groups to gefx '''
#log.info('[+] Graphing')
#context, sizeCache = signature.makeSizeCaches(opt.dumpname)
#for chains in signature.buildStructureGroup(context, sizeCache, opt.size ):
# signature.graphStructureGroups(context, chains, opt.address )
# TODO change to generic fn, and output graph
return
def argparser():
rootparser = argparse.ArgumentParser(prog='haystack-reverser',
description='Several tools to reverse engineer structures on the heap.')
rootparser.add_argument('--debug', action='store_true', help='Debug mode on.')
rootparser.add_argument('dumpname', type=argparse_utils.readable, action='store', help='Source memory dump by haystack.')
subparsers = rootparser.add_subparsers(help='sub-command help')
instances = subparsers.add_parser('instances',
help='List all structures instances with virtual address, member types guess and info.')
instances.set_defaults(func=reverseInstances)
typemap = subparsers.add_parser('typemap',
help='Try to reverse generic types from instances\' similarities.')
typemap.set_defaults(func=writeReversedTypes)
groupparser = subparsers.add_parser('group', help='Show structure instances groups by size and signature.')
groupparser.add_argument('--size', type=int, action='store', default=None,
help='Limit to a specific structure size')
groupparser.add_argument('--address', type=argparse_utils.int16, action='store', default=None,
help='Limit to structure similar to the structure pointed at <address>')
groupparser.set_defaults(func=groupStructures)
parent = subparsers.add_parser('parent', help='Print the parent structures pointing to the structure located at this address.')
parent.add_argument('address', type=argparse_utils.int16, action='store', default=None,
help='Hex address of the child structure.')
parent.set_defaults(func=printParents)
graphparser = subparsers.add_parser('graph', help='DISABLED - Show sorted structure instances groups by size and signature in a graph.')
graphparser.add_argument('--size', type=int, action='store', default=None,
help='Limit to a specific structure size')
graphparser.add_argument('--address', type=argparse_utils.int16, action='store', default=None,
help='Limit to structure similar to the structure pointed at <address>')
graphparser.set_defaults(func=graph)
showparser = subparsers.add_parser('show', help='Show one structure instance.')
showparser.add_argument('address', type=argparse_utils.int16, action='store', default=None,
help='Specify the address of the structure, or of a structure member.')
showparser.set_defaults(func=show)
# XXX delete ?
makesig = subparsers.add_parser('makesig', help='Create a simple signature file of the heap - NULL, POINTERS, OTHER VALUES.')
makesig.set_defaults(func=saveSignatures)
cleanp = subparsers.add_parser('clean', help='Clean the memory dump from cached info.')
cleanp.set_defaults(func=clean)
return rootparser
def main(argv):
parser = argparser()
opts = parser.parse_args(argv)
level=logging.WARNING
if opts.debug :
level=logging.DEBUG
flog = os.path.normpath('log')
logging.basicConfig(level=level, filename=flog, filemode='w')
logging.getLogger('haystack-reverse').setLevel(logging.DEBUG)
logging.getLogger('signature').setLevel(logging.DEBUG)
logging.getLogger('reversers').setLevel(logging.DEBUG)
print ('[+] **** COMPLETE debug log to %s'%(flog))
else:
logging.getLogger('haystack-reverse').setLevel(logging.INFO)
logging.getLogger('signature').setLevel(logging.INFO)
logging.getLogger('reversers').setLevel(logging.INFO)
sh=logging.StreamHandler(sys.stdout) # 2.6, 2.7 compat
logging.getLogger('signature').addHandler( sh )
logging.getLogger('reversers').addHandler( sh )
logging.getLogger('haystack-reverse').addHandler( sh )
opts.func(opts)
if __name__ == "__main__":
sys.path.append(os.getcwd())
main(sys.argv[1:])