-
Notifications
You must be signed in to change notification settings - Fork 0
/
graphityViz.py
175 lines (133 loc) · 5.62 KB
/
graphityViz.py
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
from pydotplus.graphviz import Node
import networkx as nx
from networkx.readwrite import json_graph
import json
import os
from graphityOps import fetchExtendedGraph, fetchExtendedSubgraph, fetchBehaviorgadgetGraph, fetchSpecialGraph, fetchD3Graph
import graphityFunc
def dumpGml(graphity, allAtts):
gmlData = graphity.copy()
# gotta fix the lists of lists to list for gml, otherwise incompatible
for node in gmlData.node:
for attr in gmlData.node[node]:
if type(gmlData.node[node][attr]) == list:
listOfLists = gmlData.node[node][attr]
seList = map(' '.join, listOfLists)
gmlData.node[node][attr] = ' | '.join(seList)
nx.write_gml(gmlData, "output/callgraph.gml")
# generates GML for graph containing behavior gadgets, no strings/apis
behaviorGraph = fetchBehaviorgadgetGraph(graphity)
nx.write_gml(behaviorGraph, "output/behaviorgaddgets.gml")
# generates GML for special gadgets, handed over as list, searched for within API calls
allocGraph = fetchSpecialGraph(graphity, ['alloc', 'mem'])
nx.write_gml(allocGraph, "output/allocgadgets.gml")
# generates GML for extended Graph, where APIs and strings are dedicated nodes
extendedGraph = fetchExtendedGraph(graphity, allAtts)
nx.write_gml(extendedGraph, "output/extendedgraph.gml")
# dumps the gml data for a subgraph starting at [address] with APIs/strings as dedicated nodes
def dumpGmlSubgraph(graphity, address):
if address in graphity:
subgraph = fetchExtendedSubgraph(graphity, address)
gmlfile = "output/subgraph_" + address + ".gml"
nx.write_gml(subgraph, gmlfile)
# Graph plotting with pydotplus from within NetworkX, format is dot
def graphvizPlot(graphity, allAtts):
pydotMe = nx.drawing.nx_pydot.to_pydot(graphity)
for node in pydotMe.get_nodes():
# get node address to be able to fetch node directly from graphity to preserve data types of attributes
nodeaddr = node.to_string().split()[0].replace('\"', '')
finalString = ''
if node.get('calls') != '[]' or node.get('strings') != '[]':
finalList = []
# fetching string and call lists directly from graphity
callList = graphity.node[nodeaddr]['calls']
stringList = graphity.node[nodeaddr]['strings']
for item in callList:
finalList.append(str(item[0]) + ": [C] " + str(item[1]))
for otem in stringList:
finalList.append(str(otem[0]) + ": [S] " + str(otem[1]))
finalList.sort()
finalString = '\n'.join(finalList)
if node.get('functiontype') == 'Export':
label = "Export " + nodeaddr + node.get('alias')
label = label + "\n" + finalString
node.set_fillcolor('skyblue')
node.set_style('filled,setlinewidth(3.0)')
node.set_label(label)
elif node.get('functiontype') == 'Callback':
label = "Callback " + nodeaddr + "\n" + finalString
node.set_fillcolor('darkolivegreen1')
node.set_style('filled,setlinewidth(3.0)')
node.set_label(label)
elif node.get('functiontype').startswith('Indirect'):
label = "IndirectRef " + nodeaddr + "\n" + finalString
node.set_fillcolor('lemonchiffon1')
node.set_style('filled,setlinewidth(3.0)')
node.set_label(label)
elif finalString != '':
finalString = nodeaddr + "\n" + finalString
node.set_fillcolor('lightpink1')
node.set_style('filled,setlinewidth(3.0)')
node.set_label(finalString)
print(finalString)
graphinfo = "SAMPLE " + allAtts['filename'] + "\nType: " + allAtts['filetype'] + "\nSize: " + str(allAtts['filesize']) + "\nMD5: " + allAtts['md5'] + "\nImphash:\t\t" + allAtts['imphash'] + "\nCompilation time:\t" + allAtts['compilationts'] + "\nEntrypoint section:\t" + allAtts['sectionep']
print(graphinfo)
titleNode = Node()
titleNode.set_label(graphinfo)
titleNode.set_shape('rectangle')
titleNode.set_fillcolor('grey')
titleNode.set_style('filled')
pydotMe.add_node(titleNode)
graphname = allAtts['filename'] + ".png"
print(graphname)
try:
# TODO pydotplus throws an error sometimes (Error: /tmp/tmp6XgKth: syntax error in line 92 near '[') look into pdp code to see why
out_filename = os.path.join(os.path.abspath(os.path.dirname(__file__)), graphname)
print(out_filename)
pydotMe.write_png(out_filename)
except Exception as e:
print("ERROR drawing graph")
print(str(e))
# Experimental Javascript InfoVis Tk data generation
def dumpJsonForJit(graphity, indent=None):
json_graph = []
for node in graphity.nodes():
json_node = {
'id': node,
'name': node
}
# node data
json_node['data'] = graphity.node[node]
# Style
if graphity.node[node].get('calls') != []:
json_node['data']['$color'] = '#FFFF00' # yellow
if graphity.node[node].get('functiontype') == 'Callback':
json_node['data']['$dim'] = 8
json_node['data']['$type'] = 'square'
json_node['data']['$color'] = '#FF0080' # pink
json_node['name'] = node + " Callback"
if graphity.node[node].get('functiontype') == 'Export':
json_node['data']['$dim'] = 8
json_node['data']['$type'] = 'square'
json_node['data']['$color'] = '#3ADF00' # green
json_node['name'] = node + " Export"
# adjacencies
if graphity[node]:
json_node['adjacencies'] = []
for neighbour in graphity[node]:
adjacency = {'nodeTo': neighbour}
# adjacency data
adjacency['data'] = graphity.edge[node][neighbour]
json_node['adjacencies'].append(adjacency)
#print (json_node)
json_graph.append(json_node)
#print(json.dumps(json_graph, indent=indent))
return json.dumps(json_graph, indent=indent)
def dumpJsonForD3(graphity):
# TODO transform graph to visualization needs
d3graph = fetchD3Graph(graphity)
data = json.dumps(json_graph.node_link_data(d3graph), indent=2)
d3file = "d3js/d3.json"
d3handle = open(d3file, 'w')
d3handle.write(data)
d3handle.close()