├── .gitmodules
├── FIRST_org_IoCannon.pdf
├── GraphDracula_Recon17.pdf
├── H2HC_RogueBehaviorDetection.pdf
├── LICENSE.txt
├── README.md
├── cache
├── 04960b61e5cbf5a81957d88c91fb202b4be6d522.dbg
└── 04960b61e5cbf5a81957d88c91fb202b4be6d522.txt
├── csv2neo4j.py
├── d3js
├── d3.json
└── forcedir.html
├── graphity.py
├── graphityFunc.py
├── graphityOps.py
├── graphityOut.py
├── graphityUtils.py
├── graphityViz.py
├── output
├── APT28.csv
├── Animalfarm.csv
├── ConsoleApplication1.exe.png
├── ConsoleApplication1Virtual.exe.png
├── ConsoleApplication1_fullOpt.exe.png
├── ConsoleApplication1_optSize.exe.png
├── ConsoleApplication1vc110_mb.exe.png
├── ConsoleApplication1vc120.exe.png
├── ConsoleApplication1vc150dbg.exe.png
├── HIDRV.png
├── Packrat.csv
├── avdetect_3798f745fb9dbad6a20e794f5ed9d45f9b60b198567f41e5b794c19e78c9599e.png
├── banito_cpp.bin.png
├── banito_cpp.txt
├── benign_0b0b3ec1d33d272104a4c37b5e5693b9544f737863a736386abcc89a32f8a222.png
├── benign_0b67b7d86ad47d4537c6612a39863ff732fa0b0f005fcd209cb46bf90338b2b9.png
├── benign_0bfbda37af78a9d0318b0d0e3024d831c271e6d42f0da41372c8785425a864aa.png
├── c3f8690087a454fa45e8975fd0b8b0b76aba554f540d7c2c98d3e15512268b52.png
├── c3f8690087a454fa45e8975fd0b8b0b76aba554f540d7c2c98d3e15512268b52.txt
├── coolstuff_5fd8c932fc92abe417acf6990165ff520df1c5911da7b77b31e67861ad06078a.png
├── gephi
│ ├── allocgraph.png
│ ├── animalfarm1.png
│ ├── animalfarm2.png
│ ├── apifeatures.png
│ ├── apilesssubgraph.png
│ ├── apiloading.png
│ ├── apiloading2.png
│ ├── babar_mnem_black.png
│ ├── forceatlas.png
│ ├── forceatlas2.png
│ ├── funcsize_vs_outdegree.png
│ ├── graphviz.png
│ ├── graphviz2.png
│ ├── rbot_behavior.png
│ ├── rbot_behavior_close.png
│ ├── sopretty.png
│ ├── subgraph1.png
│ ├── subgraph2.png
│ └── viz.png
├── packed_59128307.png
├── randomdropper.txt
├── ransomware.png
├── ransomware.txt
├── ransomware_2.txt
├── ransomware_3.txt
├── shadowbrokers.exe.png
├── spaghetticode.png
├── stuxnet_meta.csv
└── turla_57b8c2f5cfeaca97da58cfcdaf10c88dbc2c987c436ddc1ad7b7ed31879cb665.png
├── prepare_misp_object.py
├── requirements.txt
└── signatures
└── putFlirtSignaturesHere.sig
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "misp-objects"]
2 | path = misp-objects
3 | url = https://github.com/MISP/misp-objects.git
4 |
--------------------------------------------------------------------------------
/FIRST_org_IoCannon.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/FIRST_org_IoCannon.pdf
--------------------------------------------------------------------------------
/GraphDracula_Recon17.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/GraphDracula_Recon17.pdf
--------------------------------------------------------------------------------
/H2HC_RogueBehaviorDetection.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/H2HC_RogueBehaviorDetection.pdf
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 G Data Advanced Analytics
4 | Copyright (c) 2017 Marion Marschalek
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # r2graphity
2 |
3 | Usage
4 | =====
5 |
6 | graphity.py [-h] [-p] [-i] [-l] [-b] [-n] [-c CSVDUMP] input
7 |
8 |
9 | positional arguments:
10 |
11 | input Tool requires an input file or directory; directory, i.e. batch processing, only possible and feasible for csvdump option and Neo4j dump
12 |
13 |
14 | optional arguments:
15 |
16 | -h, --help show this help message and exit
17 |
18 | -d, --deactivatecache Deactivate caching of graphs, for debugging of graph generation
19 |
20 | -p, --printing Print the graph as text, as in, nodes with respective content
21 |
22 | -i, --info Print info and stats of the graph
23 |
24 | -l, --plotting Plotting the graph via pyplot
25 |
26 | -b, --behavior Scan for behaviors listed in graphityFunc.py
27 |
28 | -n, --neodump Dump graph to Neo4j (configured to flush previous data from Neo, might wanna change that)
29 |
30 | -c CSVDUMP, --csvdump CSVDUMP Dump info data to a given csv file, appends a line per sample
31 |
32 |
33 |
34 | R2Graphity is built to construct a graph structure based on the function call graph of a Windows executable. Details on how the graph is built and processing options can be found in the attached slide deck, presented at H2HC 2016 in Sao Paulo, Brasil.
35 |
36 |
37 | Dependencies
38 | ============
39 |
40 |
41 | Watch out to get the Python3 packages, or install directly with pip3.
42 |
43 | radare2 https://github.com/radare/radare2
44 |
45 | r2pipe https://github.com/radare/radare2/wiki/R2PipeAPI
46 |
47 | NetworkX https://github.com/networkx/
48 |
49 | Neo4j https://neo4j.com/download/
50 |
51 | py2neo http://py2neo.org/v3/
52 |
53 | numpy https://github.com/numpy/numpy
54 |
55 | pefile https://github.com/erocarrera/pefile
56 |
57 | pydeep https://github.com/kbandla/pydeep
58 |
59 |
60 | Watch out to install radare2 from the git repository, do not use the Debian package. Tested to run best with radare2 1.6.0-git 15013 @ linux-x86-64, commit: f590de9e71ed87ebf276083a2876d006d87a506d build: 2017-06-08__12:52:05
61 |
62 |
63 | Installation
64 | ============
65 |
66 | ```
67 | (sudo) pip3 install -r requirements.txt
68 | ```
69 |
70 |
--------------------------------------------------------------------------------
/cache/04960b61e5cbf5a81957d88c91fb202b4be6d522.dbg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/cache/04960b61e5cbf5a81957d88c91fb202b4be6d522.dbg
--------------------------------------------------------------------------------
/cache/04960b61e5cbf5a81957d88c91fb202b4be6d522.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/cache/04960b61e5cbf5a81957d88c91fb202b4be6d522.txt
--------------------------------------------------------------------------------
/csv2neo4j.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | import csv
5 | from py2neo import authenticate, Graph, Relationship
6 | from py2neo.ogm import GraphObject, Property
7 |
8 |
9 | match_method = {
10 | #'filename': True,
11 | #'filetype': True,
12 | #'filesize': 1000,
13 | #'md5': True,
14 | #'imphash': True,
15 | #'compilationtime': True,
16 | #'addressep': True,
17 | #'sectionep': True,
18 | #'tlssections': True,
19 | #'originalfilename': True,
20 | #'sectioncount': 1,
21 | #'secname1': True,
22 | #'secname2': True,
23 | #'secname3': True,
24 | #'secname4': True,
25 | #'secname5': True,
26 | #'secname6': True,
27 | #'secsize1': 1000,
28 | #'secsize2': 1000,
29 | #'secsize3': 1000,
30 | #'secsize4': 1000,
31 | #'secsize5': 1000,
32 | #'secsize6': 1000,
33 | #'secent1': 0.1,
34 | #'secent2': 0.1,
35 | #'secent3': 0.1,
36 | #'secent4': 0.1,
37 | #'secent5': 0.1,
38 | #'secent6': 0.1,
39 | 'functionstotal': 1,
40 | 'refslocal': 1,
41 | #'refsglobalvar': 1,
42 | 'refsunknown': 1,
43 | 'apitotal': 1,
44 | #'apimisses': 1,
45 | 'stringsreferenced': 1,
46 | #'stringsdangling': 1,
47 | 'stringsnoref': 1
48 | }
49 |
50 |
51 | class Sample(GraphObject):
52 | __primarykey__ = "md5"
53 |
54 | md5 = Property()
55 | filename = Property()
56 | filetype = Property()
57 | filesize = Property()
58 | imphash = Property()
59 | compilationtime = Property()
60 | addressep = Property()
61 | sectionep = Property()
62 | tlssections = Property()
63 | originalfilename = Property()
64 | sectioncount = Property()
65 | secname1 = Property()
66 | secname2 = Property()
67 | secname3 = Property()
68 | secname4 = Property()
69 | secname5 = Property()
70 | secname6 = Property()
71 | secsize1 = Property()
72 | secsize2 = Property()
73 | secsize3 = Property()
74 | secsize4 = Property()
75 | secsize5 = Property()
76 | secsize6 = Property()
77 | secent1 = Property()
78 | secent2 = Property()
79 | secent3 = Property()
80 | secent4 = Property()
81 | secent5 = Property()
82 | secent6 = Property()
83 | functionstotal = Property()
84 | refslocal = Property()
85 | refsglobalvar = Property()
86 | refsunknown = Property()
87 | apitotal = Property()
88 | apimisses = Property()
89 | stringsreferenced = Property()
90 | stringsdangling = Property()
91 | stringsnoref = Property()
92 |
93 | host = 'localhost:7474'
94 | username = 'neo4j'
95 | password = 'neo4j'
96 |
97 | authenticate(host, username, password)
98 |
99 | graph = Graph("http://{}/db/data/".format(host))
100 | graph.delete_all()
101 |
102 | with open('test.csv') as csvfile:
103 | reader = csv.DictReader(csvfile)
104 | tx = graph.begin()
105 | for row in reader:
106 | sample = Sample()
107 | for k, v in row.items():
108 | if v is not None and v != '0':
109 | setattr(sample, k, v)
110 | graph.push(sample)
111 | tx.commit()
112 | for s in Sample.select(graph):
113 | for k, v in match_method.items():
114 | tx = graph.begin()
115 | if k == 'md5' or 'sec' in k or not getattr(s, k):
116 | continue
117 | elif isinstance(v, bool):
118 | for rel in Sample.select(graph).where("_.{val} = '{data}'".format(val=k, data=getattr(s, k))):
119 | if s == rel:
120 | continue
121 | if len(list(graph.match(start_node=rel.__ogm__.node, end_node=s.__ogm__.node, rel_type=k))) > 0:
122 | continue
123 | r = Relationship(s.__ogm__.node, k, rel.__ogm__.node, bidirectional=True)
124 | tx.create(r)
125 | else:
126 | for rel in Sample.select(graph).where("_.{val} >= '{min}' AND _.{val} <= '{max}'".format(val=k, min=float(getattr(s, k)) - v, max=float(getattr(s, k)) + v)):
127 | if s == rel:
128 | continue
129 | if len(list(graph.match(start_node=rel.__ogm__.node, end_node=s.__ogm__.node, rel_type=k))) > 0:
130 | continue
131 | r = Relationship(s.__ogm__.node, k, rel.__ogm__.node, bidirectional=True)
132 | tx.create(r)
133 | tx.commit()
134 |
--------------------------------------------------------------------------------
/d3js/forcedir.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
29 |
30 |
31 |
32 |
33 |
36 |
37 |
38 |
593 |
594 |
--------------------------------------------------------------------------------
/graphity.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import r2pipe
4 | import sys
5 | import os
6 | import json
7 | import re
8 | import networkx as nx
9 | from time import time
10 | from datetime import datetime
11 | from argparse import ArgumentParser
12 | from base64 import b64decode
13 | from collections import Counter
14 | from graphityOut import toNeo, fromNeo, printGraph, printGraphInfo, dumpGraphInfoCsv, toPickle, fromPickle
15 | from graphityViz import graphvizPlot, dumpJsonForJit, dumpGml, dumpGmlSubgraph, dumpJsonForD3
16 | from graphityUtils import gimmeDatApiName, sha1hash, getAllAttributes, is_ascii, Hvalue, check_pe_header
17 | from graphityOps import patternScan
18 | import graphityFunc
19 |
20 |
21 | # Works, takes its time, sometimes assigns wrong names to functions
22 | # DEPRECATED
23 | def loadFlirts():
24 |
25 | try:
26 | # load FLIRT signatures from local flirt directory
27 | flirtDir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'flirt')
28 | sigFiles = [f for f in os.listdir(flirtDir) if os.path.isfile(os.path.join(flirtDir, f))]
29 |
30 | for sigFile in sigFiles:
31 | r2cmd = "zfs %s" % os.path.join(flirtDir, sigFile)
32 | R2PY.cmd(r2cmd)
33 |
34 | except Exception as e:
35 | print(str(e) + " FAIL loading FLIRT sig file")
36 |
37 |
38 | # Too slow for now, waiting for fix
39 | def loadZigs():
40 |
41 | try:
42 | # load directory of zigs
43 | print('Loading msvcrt.sdb {:%Y-%m-%d %H:%M:%S}'.format(datetime.now()))
44 |
45 | zigpath = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'signatures')
46 | zigfile = os.path.join(zigpath, 'msvcrt.sdb')
47 | r2cmd = "zo %s" % zigfile
48 | # TODO load all signatures
49 | R2PY.cmd(r2cmd)
50 |
51 | print('msvcrt.sdb loaded {:%Y-%m-%d %H:%M:%S}'.format(datetime.now()))
52 |
53 | R2PY.cmd("e search.in = io.sections.exec")
54 | # e search.in = raw --- ?
55 |
56 | #toScan = getCodeSections()
57 | #for section in toScan:
58 |
59 | r2cmd = "z/" #%d %d" % (section[0], section[1])
60 | R2PY.cmd(r2cmd)
61 |
62 | print('msvcrt.zig scan on code section(s) finished {:%Y-%m-%d %H:%M:%S}'.format(datetime.now()))
63 |
64 | except Exception as e:
65 | print(str(e))
66 |
67 |
68 | def flagLibraryCode(graphity):
69 |
70 | signList = R2PY.cmd("fs sign; fj")
71 | #print (signList)
72 | if signList:
73 | signListJ = json.loads(signList)
74 | for item in signListJ:
75 | libfunction = hex(item['offset'])
76 | if libfunction in graphity:
77 | print (graphity.node[libfunction])
78 |
79 | # Checks whether an address is located in an executable section
80 | def isValidCode(callAddress, sectionsList):
81 |
82 | # sectionsList contains executable sections as 2-element lists, containing start and end of each section
83 | for execSection in sectionsList:
84 | if int(callAddress, 16) >= execSection[0] and int(callAddress, 16) < execSection[1]:
85 | return True
86 | return False
87 |
88 |
89 | # Returns a list of executable sections
90 | def getCodeSections():
91 |
92 | returnSections = []
93 |
94 | # regular expression to pick out the executable section(s)
95 | execSection = re.compile("perm=....x")
96 |
97 | # will return the section table from radare2
98 | sections = R2PY.cmd("iS")
99 |
100 | sectionData = {}
101 |
102 | for line in sections.splitlines():
103 | if re.search(execSection, line):
104 | for element in line.split():
105 | items = element.split('=')
106 | sectionData[items[0]] = items[1]
107 |
108 | start = int(sectionData['vaddr'], 16)
109 | end = start + int(sectionData['vsz'])
110 | psize = int(sectionData['sz'])
111 | returnSections.append([start, end, psize])
112 |
113 | return returnSections
114 |
115 |
116 | # Returns an executables imports as a list
117 | def getIat():
118 |
119 | iatlist = []
120 | cmd = "iij"
121 | iatjson = json.loads(R2PY.cmd(cmd))
122 | for item in iatjson:
123 | iatlist.append(hex(item['plt']))
124 | return iatlist
125 |
126 |
127 | # Returns a dictionary of xrefs to symbols
128 | def crossRefScan():
129 |
130 | cmd = "axtj @@ sym.*"
131 | finalCalls = {}
132 |
133 | # fixing the JSON... issue reported to radare2, keep in mind to remove workaround
134 | temp = R2PY.cmd(cmd).replace('\n', ',')
135 | temp = "[" + temp + "]"
136 |
137 | xrefj = json.loads(temp)
138 | # TODO check!!
139 |
140 | for xrefitem in xrefj:
141 | for xreflevel2 in xrefitem:
142 |
143 | # not data xref means its code or call
144 | if xreflevel2['type'] != 'd':
145 | finalCalls[hex(xreflevel2['from'])] = xreflevel2['opcode']
146 | pass
147 |
148 | # data potentially means API referenced by register; please note these are rather uncommon in the long list of symbol refs
149 | # thus, bottelneck in parsing speed lies in number of refs
150 | if xreflevel2['type'] == 'd' and ( xreflevel2['opcode'].startswith('mov') or xreflevel2['opcode'].startswith('lea') ):
151 |
152 | # 'grepping' out the register from mov/lea operation
153 | register = xreflevel2['opcode'].split()[1].replace(',','')
154 |
155 | # disassemble downwards; mmmaybe smarter to disassemble until end of function, but possible that there is no function at all
156 | # TODO find end of function, just in case
157 | cmd = "pd 300 @ " + hex(xreflevel2['from'])
158 | moreDisasm = R2PY.cmd(cmd)
159 |
160 | # possible branches towards target
161 | realCall = "call %s" % register
162 | aJmp = "jmp %s" % register
163 |
164 | for disasmLine in moreDisasm.splitlines()[1:]:
165 | if realCall in disasmLine or aJmp in disasmLine:
166 | #found a call!!
167 | temp = disasmLine + ";" + xreflevel2['opcode'].split(',')[1].rstrip()
168 | tempSplit = temp.split()
169 | finalCalls[hex(int(tempSplit[0], 16))] = ' '.join(tempSplit[1:])
170 |
171 | elif register in disasmLine:
172 | # TODO if mov dword abc, reg is found -> follow abc?
173 | # TODO could be parsed in more detail, e.g. mov dword, reg won't change the reg
174 | #print disasmLine
175 |
176 | break
177 | #pass
178 | return finalCalls
179 |
180 |
181 | # Parses the binary for strings and their references to nodes
182 | def stringScan(debugDict):
183 |
184 | # Workflow is: get string, get xrefs to string if any, get functions of xrefs if any; fit node in graph with the string
185 | allMyStrings = []
186 |
187 | # izzj parses entire binary
188 | stringCmd = "izzj"
189 | strings = R2PY.cmd(stringCmd)
190 |
191 | parsedStrings = json.loads(strings)
192 |
193 | debugDict['stringsDangling'] = []
194 | debugDict['stringsNoRef'] = []
195 |
196 | i = 0
197 | j = 1
198 | while i < len(parsedStrings["strings"]):
199 | stringItem = parsedStrings["strings"][i]
200 |
201 | # Strings when retrieved through izzj command are BASE64 encoded
202 | thatOneString = b64decode(stringItem['string']).replace(b'\\', b' \\\\ ')
203 | thatOneString.replace(b'\'', b'')
204 |
205 | try:
206 |
207 | thatOneString = thatOneString.decode()
208 |
209 | xrefCmd = "axtj @ " + hex(stringItem['vaddr'])
210 | stringXrefsJ = R2PY.cmd(xrefCmd)
211 |
212 | # TODO this should be a list, but is returned as a string now?
213 | #if stringXrefsJ != []:
214 | if len(stringXrefsJ) > 2:
215 | stringXrefs = json.loads(stringXrefsJ)
216 |
217 | # check whether string item is root of list of strings
218 | j = 1
219 | lastItem = stringItem
220 | while (i + j) < len(parsedStrings["strings"]):
221 | nextStringItem = parsedStrings["strings"][i + j]
222 | lastAddr = lastItem['vaddr']
223 | lastSize = lastItem['size']
224 |
225 | # string offsets are 4 byte aligned, TODO check whether this is always the case
226 | padding = 4 - (lastSize % 4)
227 | if padding == 4:
228 | padding = 0
229 | nextAddr = lastAddr + lastSize + padding
230 |
231 | if nextAddr != nextStringItem['vaddr'] or hasXref(hex(nextStringItem['vaddr'])):
232 | # end.. exit here
233 | break
234 | else:
235 | thatOneString = thatOneString + "|" + b64decode(nextStringItem['string']).decode()
236 | j = j + 1
237 | lastItem = nextStringItem
238 |
239 | # iterate refs on string, if any
240 | for ref in stringXrefs:
241 |
242 | # sort out strings with code ref, i.e. non-strings
243 | if ref['type'] != 'c' and ref['type'] != 'C':
244 | stringAddr = hex(ref['from'])
245 | stringFuncRef = gimmeRespectiveFunction(stringAddr)
246 | if stringFuncRef != '0x0':
247 | allMyStrings.append([stringAddr, stringFuncRef, thatOneString])
248 | else:
249 | # TODO this is merely still useful strings, see how to fit them in the graphs and db
250 | print("DANGLING STRING NO FUNCREF %s %s" % (stringAddr, thatOneString))
251 | debugDict['stringsDangling'].append(thatOneString)
252 |
253 | else:
254 | debugDict['stringsNoRef'].append(thatOneString)
255 |
256 |
257 | except UnicodeDecodeError:
258 | pass
259 | if j > 1:
260 | i = i + j
261 | else:
262 | i = i + 1
263 |
264 | debugDict['stringsDanglingTotal'] = len(debugDict['stringsDangling'])
265 | debugDict['stringsNoRefTotal'] = len(debugDict['stringsNoRef'])
266 | return allMyStrings
267 |
268 |
269 | # Text whether xrefs exist for given address
270 | def hasXref(vaddr):
271 |
272 | refs = R2PY.cmd("axtj @ " + vaddr)
273 | if refs:
274 | return True
275 | else:
276 | return False
277 |
278 |
279 | # Creating the NetworkX graph, nodes are functions, edges are calls or callbacks
280 | def createRawGraph():
281 |
282 | graphity = nx.DiGraph()
283 | debugDict = {}
284 |
285 | functions = R2PY.cmd("aflj")
286 | if functions:
287 | functionList=json.loads(functions)
288 | #print json.dumps(functionList, indent=4, sort_keys=True)
289 | else:
290 | functionList = []
291 |
292 | # figuring out code section size total
293 | sectionsList = getCodeSections()
294 | xlen = 0
295 | for execSec in sectionsList:
296 | xlen = xlen + execSec[2]
297 | debugDict['xsectionsize'] = xlen
298 |
299 | # CREATING THE GRAPH
300 |
301 | refsGlobalVar = 0
302 | refsUnrecognized = 0
303 | refsFunc = 0
304 | debugDict['functions'] = len(functionList)
305 |
306 | ### NetworkX Graph Structure ###
307 |
308 | # FUNCTION as node, attributes: function address, size, calltype, list of calls, list of strings, count of calls; functiontype[Callback, Export], alias (e.g. export name), mnemonic distribution
309 | # FUNCTIoN REFERENCE as edge (function address -> target address), attributes: ref offset (at)
310 | # INDIRECT REFERENCE as edge (currently for threads and Windows hooks, also indirect code and indirect data references)
311 | # API CALLS (list attribute of function node): address, API name
312 | # STRINGS (list attribute of function node): address, string, evaluation
313 |
314 | ####
315 |
316 | # TODO add count of refs from A to B as weights to edges
317 | # TODO count calls to global vars, to indirect targets
318 |
319 | for item in functionList:
320 |
321 | #print hex(item['offset'])
322 | graphity.add_node(hex(item['offset']), size=item['realsz'], calltype=item['calltype'], calls=[], apicallcount=0, strings=[], stringcount=0, functiontype='')
323 |
324 | for item in functionList:
325 |
326 | # TODO look into new values provided by aflj
327 | for xref in item['callrefs']:
328 |
329 | if xref['type'] == 'C':
330 |
331 | # If an edge is added, that includes a non-existent node, the node will be added, but w/o the necessary attributes
332 | # Thasss why we iterate twice, can theoretically be speeded up but needs testing
333 | if hex(xref['addr']) in graphity:
334 | if item['offset'] != xref['addr']:
335 | graphity.add_edge(hex(item['offset']), hex(xref['addr']), pos=hex(xref['at']))
336 | refsFunc = refsFunc + 1
337 |
338 | elif hex(xref['addr']) in getIat():
339 | pass
340 |
341 | elif not isValidCode(hex(xref['addr']), sectionsList):
342 | # TODO do something
343 | print("DANGLING call to address outside code section, glob var, dynamic API loading %s -> %s" % (hex(item['offset']), hex(xref['addr'])))
344 | refsGlobalVar = refsGlobalVar + 1
345 |
346 | else:
347 | print("FAIL: Call to code thats not a function, an import/symbol or otherwise recognized. Missed function perhaps. %s -> %s" % (hex(item['offset']), hex(xref['addr'])))
348 | refsUnrecognized = refsUnrecognized + 1
349 |
350 | print('* %s Graph created with NetworkX ' % str(datetime.now()))
351 | debugDict['refsFunctions'] = refsFunc
352 | debugDict['refsGlobalVar'] = refsGlobalVar
353 | debugDict['refsUnrecognized'] = refsUnrecognized
354 |
355 | apiRefs = crossRefScan()
356 |
357 | callNum = len(apiRefs)
358 | missesNum = 0
359 |
360 | # FITTING GRAPH WITH API REFS
361 |
362 | for call in apiRefs:
363 |
364 | # get the address of the function, that contains the call to a given symbol
365 | funcAddress = gimmeRespectiveFunction(call)
366 |
367 | # TODO check if funcAddress is the real function address
368 | if funcAddress in graphity:
369 |
370 | # node(funcAddress) has attribute calls, which contains a list of API calls
371 | api = gimmeDatApiName(apiRefs[call])
372 |
373 | graphity.node[funcAddress]['calls'].append([call, api])
374 |
375 | # detected API call reference does not resolve to a function offset, insert handling for this here
376 | else:
377 | print("DANGLING API CALL %s %s" % (call, apiRefs[call]))
378 | missesNum = missesNum+1
379 |
380 | # debug: print total API refs and functionless API refs, maybe indicator for obfuscated code
381 | print('* %s Graph extended with API calls, %d calls in total, %d dangling w/o function reference ' % (str(datetime.now()), callNum, missesNum))
382 | debugDict['apiTotal'] = callNum
383 | debugDict['apiMisses'] = missesNum
384 |
385 |
386 | # FITTING GRAPH WITH STRING REFS
387 |
388 | allTheStrings = stringScan(debugDict)
389 | stringrefs = 0
390 |
391 | for aString in allTheStrings:
392 |
393 | stringAddr = aString[0]
394 | stringFunc = aString[1]
395 | stringData = aString[2]
396 |
397 | # add string to respective function node in graph
398 | if stringFunc in graphity:
399 | graphity.node[stringFunc]['strings'].append([stringAddr, stringData])
400 | stringrefs = stringrefs + 1
401 |
402 | else:
403 | print("\n*** BIG FAIL *** String's function not in graph %s %s" % (stringFunc, stringData))
404 |
405 | print('* %s Graph extended with string references ' % (str(datetime.now())))
406 | debugDict['stringsReferencedTotal'] = stringrefs
407 |
408 | return graphity, debugDict
409 |
410 |
411 | # Tag exports of DLLs
412 | # TODO : check whether exports are coming back after bugfix (?)
413 | def analyzeExports(graphity):
414 |
415 | exportsj = json.loads(R2PY.cmd("iEj"))
416 | for item in exportsj:
417 |
418 | exportAddress = hex(item['vaddr'])
419 | exportName = item['name']
420 |
421 | exportFunction = gimmeRespectiveFunction(exportAddress)
422 |
423 | if exportFunction in graphity:
424 | graphity.node[exportFunction]['functiontype'] = 'Export'
425 | graphity.node[exportFunction]['alias'] = exportName
426 |
427 |
428 | # Removing thunks as they make my graphs fat, replace by API calls
429 | def thunkPruning(graphity):
430 |
431 | for aNode in graphity.nodes(data=True):
432 |
433 | # most obvious thunks, other thunks exist too, len seen was 11, 13
434 | # TODO !!!!!!!! check for 64bit
435 | # TODO check with radare for thunk detection?
436 | # funclets that contain nothing but a jump to an import, and do not call other functions
437 | if len(aNode[1]['calls']) == 1 and aNode[1]['size'] == 6 and not graphity.successors(aNode[0]):
438 |
439 | thunk = aNode[0]
440 | thunkApi = aNode[1]['calls'][0]
441 |
442 | # need to go on with radare from here, cause graphity doesn't know all the addressed of the xrefs to thunks from within a function
443 | # getting all xrefs on thunk, then getting function its located in to get to node of graph
444 | temp = R2PY.cmd("axtj " + thunk)
445 |
446 | thunkRefs = []
447 | if temp:
448 | thunkRefs = json.loads(temp)
449 |
450 | for aRef in thunkRefs:
451 |
452 | thunkCallAddr = hex(aRef['from'])
453 | thunkFuncRef = gimmeRespectiveFunction(thunkCallAddr)
454 |
455 | # if thunk's xrefs include a detected function then add thunk as a regular API call to calls list of respective node
456 | if thunkFuncRef != '0x0':
457 | graphity.node[thunkFuncRef]['calls'].append([thunkCallAddr, thunkApi[1]])
458 |
459 | # after xref to thunk has been added to all calling functions, remove thunk node from graph
460 | graphity.remove_node(thunk)
461 |
462 |
463 | # Adding edges to indirectly referenced functions, thread handlers and hook functions for now only
464 | def tagCallbacks(graphity):
465 |
466 | for aNode in graphity.nodes(data=True):
467 | for call in aNode[1]['calls']:
468 |
469 | xrefTarget = ''
470 | # TODO consider this bad practise, do something smarter, not sure yet what, consider _beginthread API etc. etc.
471 | # also, maybe this is fixed in radare later, so consider this code redundant by then
472 | if 'CreateThread' in call[1]:
473 | xrefTarget = getCallback(call[0], 3)
474 |
475 | if 'SetWindowsHookEx' in call[1]:
476 | xrefTarget = getCallback(call[0], 2)
477 |
478 | if xrefTarget:
479 | print (xrefTarget, aNode[0])
480 | addIndirectEdge(graphity, aNode[0], xrefTarget, "apicallback", "Callback")
481 |
482 | # implicitly filters out callbacks fixed already - gets all nodes with zero in-degre
483 | # TODO see if feasible for all functions, even with such already having in edges
484 | for aNode in graphity.nodes(data=True):
485 | if graphity.in_degree(aNode[0]) == 0:
486 | jay = R2PY.cmd("axtj @ " + aNode[0])
487 |
488 | if jay:
489 | xrefs = json.loads(jay)
490 | for xref in xrefs:
491 |
492 | # if xref is code its almost certainly an edge to add
493 | if xref['type'] == 'c':
494 |
495 | # TODO circle back on jumptable-as-a-function bug from r2
496 | # really ugly workaround, really really ugly..
497 | if not 'dword [' in xref['opcode']:
498 | addIndirectEdge(graphity, hex(xref['from']), aNode[0], "coderef", "IndirectCode")
499 |
500 | # if xref is data
501 | if xref['type'] == 'd':
502 |
503 | opcd = xref['opcode']
504 | # TODO run more tests on this list not sure these are all possible cases
505 | # TODO make datarefs optional!
506 | if opcd.startswith('push') or opcd.startswith('lea') or opcd.startswith('mov'):
507 | print (hex(xref['from']), opcd)
508 | addIndirectEdge(graphity, hex(xref['from']), aNode[0], "dataref", "IndirectData")
509 | else:
510 | # TODO look into add reg, ThreadRoutine -> as xref
511 | print ("up for discussion: " + hex(xref['from']), xref['type'], xref['opcode'])
512 |
513 |
514 | def addIndirectEdge(graphity, fromAddr, toAddr, calltype, functiontype):
515 |
516 | fromNode = gimmeRespectiveFunction(fromAddr)
517 | toNode = gimmeRespectiveFunction(toAddr)
518 | if fromNode in graphity and toNode in graphity:
519 | graphity.node[toNode]['functiontype'] = functiontype
520 | graphity.add_edge(fromNode, toNode, calltype=calltype)
521 | print ("added callback edge", fromNode, toNode, calltype, "\n")
522 | else:
523 | print ("Something went wrong with indirect edge ", fromAddr, toAddr, calltype)
524 |
525 |
526 | # Parsing the handler offset out of the function arguments
527 | def getCallback(call, argcount):
528 |
529 | # simplistic: walk up the code until xref to code is found, works as long as API only receives one code ref, works well with Windows APIs
530 | disasmMore = "pd -30 @" + call
531 | upwards = R2PY.cmd(disasmMore)
532 |
533 | for otherLine in reversed(upwards.splitlines()):
534 | if 'push' in otherLine:
535 | argcount = argcount - 1
536 |
537 | # TODO better done with a regex, bug prone
538 | if not argcount:
539 | address = otherLine.split("push",1)[1].split()[0]
540 | if 'fcn.' in address:
541 | return hex(int(address.split('.')[1], 16))
542 | if '0x' in address:
543 | return hex(int(address.split('0x')[1], 16))
544 | else:
545 | return ''
546 |
547 |
548 | # WORKAROUND until function detection - bug? feature? in radare is fixed and export vaddr equal actual offsets again
549 | def gimmeRespectiveFunction(address):
550 | if address:
551 | return R2PY.cmd("?v $FB @ " + address)
552 | return ''
553 |
554 | def mnemonicism(offset):
555 |
556 | mnems = []
557 | fsize = 0
558 | weight = 0
559 |
560 | funcdump = R2PY.cmd("pdfj @ " + offset)
561 | if funcdump:
562 | dumpj = json.loads(funcdump)
563 | for item in dumpj["ops"]:
564 | mnems.append(item["type"])
565 | #print (item["type"], item["opcode"])
566 | fsize = dumpj["size"]
567 |
568 | #print ("\n" + offset + " " + str(fsize))
569 | mnemdict = Counter(mnems)
570 | #for mnem in sorted(mnemdict):
571 | # print (mnem, mnemdict[mnem])
572 |
573 | for mnem in mnemdict:
574 | if mnem in ['shl', 'shr', 'mul', 'div', 'rol', 'ror', 'sar', 'load', 'store']:
575 | weight += mnemdict[mnem]
576 | return (weight * 10) / fsize
577 |
578 | # TODO count how many above certain threshold, see how close they are together in the graph?
579 |
580 |
581 | # super graph creation function, radare-analyses the sample, puts together all of the graph and debug info
582 | def graphMagix(filepath, allAtts, deactivatecache):
583 |
584 | global R2PY
585 |
586 | if (os.path.isfile("cache/" + allAtts['sha1'] + ".txt") and os.path.isfile("cache/" + allAtts['sha1'] + ".dbg") and deactivatecache == False):
587 | print('* %s Loading graph from cache under ./cache/[sha1].txt or .dbg' % str(datetime.now()))
588 | graphity, debug = fromPickle(allAtts['sha1'])
589 |
590 | else:
591 | print('* %s R2 started analysis ' % str(datetime.now()))
592 |
593 | BENCH['r2_start'] = time()
594 |
595 | R2PY = r2pipe.open(filepath)
596 |
597 | R2PY.cmd("e asm.lines = false")
598 | R2PY.cmd("e asm.fcnlines = false")
599 | R2PY.cmd("e anal.autoname= false")
600 | R2PY.cmd("e anal.jmptbl = true")
601 | R2PY.cmd("e anal.hasnext = true")
602 | #R2PY.cmd("e src.null = true")
603 | R2PY.cmd("aaa")
604 | #R2PY.cmd("afr")
605 | #R2PY.cmd("afr @@ sym*")
606 |
607 | #loadZigs()
608 | #loadFlirts()
609 |
610 | BENCH['r2_end'] = time()
611 | print('* %s R2 finished analysis' % str(datetime.now()))
612 |
613 | # GRAPH CREATION
614 | graphity, debug = createRawGraph()
615 |
616 | # TODO testing lib code detected
617 | #flagLibraryCode(graphity)
618 |
619 | # DLL PROCESSING
620 | if 'DLL' in allAtts['filetype']:
621 | analyzeExports(graphity)
622 |
623 | # Thunk pruning, thunks are unnecessary information in the graph
624 | thunkPruning(graphity)
625 |
626 | # handler tagging
627 | tagCallbacks(graphity)
628 |
629 | # update api and string count attributes
630 | for aNode in graphity.nodes(data=True):
631 | aNode[1]['apicallcount'] = len(aNode[1]['calls'])
632 | aNode[1]['stringcount'] = len(aNode[1]['strings'])
633 |
634 | # calc mnemonic dist
635 | for aNode in graphity.nodes():
636 | graphity.node[aNode]['mnemonicism'] = mnemonicism(aNode)
637 |
638 | BENCH['graph_end'] = time()
639 |
640 | # graph and debug info caching to save parsing time, potentially
641 | if (deactivatecache == False):
642 | toPickle(graphity, debug, allAtts['sha1'])
643 |
644 | return graphity, debug
645 |
646 |
647 | if __name__ == '__main__':
648 |
649 | #global R2PY
650 | global BENCH
651 | BENCH = {}
652 |
653 | parser = ArgumentParser()
654 | parser.add_argument("input", help="Tool requires an input file or directory; directory, i.e. batch processing, only possible and feasible for csvdump option")
655 | parser.add_argument("-d", "--deactivatecache", action="store_true", help="Deactivate caching of graphs, for debugging of graph generation")
656 |
657 | # Text output options
658 | parser.add_argument("-p", "--printing", action="store_true", help="Print the graph as text, as in, nodes with respective content")
659 | parser.add_argument("-i", "--info", action="store_true", help="Print info and stats of the graph")
660 | parser.add_argument("-b", "--behavior", action="store_true", help="Scan for behaviors listed in graphityFunc.py")
661 |
662 | # Visualization & viz data options
663 | parser.add_argument("-l", "--plotting", action="store_true", help="Plotting the graph via pyplot")
664 | parser.add_argument("-g", "--gml", action="store_true", help="Spit out GML data for Gephi and what not")
665 | parser.add_argument("-s", "--gmlsub", help="Define an offset in the form e.g. 0x401000 to dump the subgraph starting there")
666 | parser.add_argument("-j", "--jit", action="store_true", help="Spits out JSON data, ready to be visualized within JS InfoVis as force directed graph")
667 |
668 | # Batch processing options
669 | parser.add_argument("-n", "--neodump", action="store_true", help="Dump graph to Neo4j (configured to flush previous data from Neo, might wanna change that) - BATCH PROCESSING ONLY")
670 | parser.add_argument("-c", "--csvdump", help="Dump info data to a given csv file, appends a line per sample, for testing now also dumps strings per binary in dedicated csv file - BATCH PROCESSING ONLY")
671 |
672 | args = parser.parse_args()
673 | # TODO check the path pythonically
674 |
675 | # Batch processing options: csvdump, neodump, TBC
676 |
677 | if args.input and os.path.isdir(args.input):
678 |
679 | for (dirpath, dirnames, filenames) in os.walk(args.input):
680 | for filename in filenames:
681 | filepath = os.path.join(dirpath, filename)
682 |
683 | if check_pe_header(filepath):
684 |
685 | print('* %s Parsing %s ' % (str(datetime.now()), filename))
686 |
687 | allAtts = getAllAttributes(filepath)
688 | graphity, debug = graphMagix(filepath, allAtts, args.deactivatecache)
689 |
690 | if args.csvdump:
691 | # CSVDUMP
692 | dumpGraphInfoCsv(graphity, debug, allAtts, args.csvdump)
693 | print('* %s Dumping graph info to indicated csv file ' % str(datetime.now()))
694 |
695 | if args.neodump:
696 | # TO NEO STUFF
697 | toNeo(graphity, allAtts)
698 | print('* %s Dumped to Neo4J ' % str(datetime.now()))
699 |
700 | elif args.input and check_pe_header(args.input):
701 |
702 | # ATTRIBUTES: md5, sha1, filename, filetype, ssdeep, filesize, imphash, compilationts, addressep, sectionep,
703 | # sectioncount, sectioninfo, tlssections, originalfilename
704 |
705 | allAtts = getAllAttributes(args.input)
706 | graphity, debug = graphMagix(args.input, allAtts, args.deactivatecache)
707 |
708 | # TODO decide what to do with dangling strings/APIs (string filtering with frequency analysis?)
709 |
710 |
711 | if args.printing:
712 | # PRINT GRAPH TO CMDLINE
713 | print("* %s Printing the graph - nodes and node attributes" % str(datetime.now()))
714 | BENCH['printing_start'] = time()
715 | printGraph(graphity)
716 | BENCH['printing_end'] = time()
717 |
718 | if args.info:
719 | # PRINT GRAPH INFO
720 | BENCH['info_start'] = time()
721 | printGraphInfo(graphity, debug)
722 | BENCH['info_end'] = time()
723 |
724 | # TODO look into certificate info: iC
725 |
726 | if args.plotting:
727 | # GRAPH PLOTTING STUFF
728 | #try:
729 | print('* %s Plotting routine starting ' % str(datetime.now()))
730 | BENCH['plotting_start'] = time()
731 | graphvizPlot(graphity, allAtts)
732 | BENCH['plotting_end'] = time()
733 | print('* %s Plotting routine finished ' % str(datetime.now()))
734 | #except:
735 | # print '* %s Cant plot this with pydot, too big ' % str(datetime.now())
736 |
737 | if args.neodump:
738 | # TO NEO STUFF
739 | BENCH['neo_start'] = time()
740 | toNeo(graphity, allAtts)
741 | BENCH['neo_end'] = time()
742 | print('* %s Dumped to Neo4J ' % str(datetime.now()))
743 |
744 | if args.behavior:
745 | # BEHAVIOR
746 | # TODO enable switching of behavior dictionaries
747 | print('* %s Scanning for API patterns ' % str(datetime.now()))
748 | BENCH['behavior_start'] = time()
749 | allThePatterns = graphityFunc.funcDict
750 |
751 | for patty in allThePatterns:
752 | findings = patternScan(graphity, allThePatterns[patty])
753 |
754 | for hit in findings:
755 | if not False in hit['patterns'].values():
756 | print("For %s found %s" % (patty, str(hit['patterns'])))
757 | BENCH['behavior_end'] = time()
758 |
759 | if args.gml:
760 | # GML and stuff
761 | BENCH['gml_start'] = time()
762 | dumpGml(graphity, allAtts)
763 | BENCH['gml_end'] = time()
764 |
765 | if args.gmlsub:
766 | # TODO add bench
767 | dumpGmlSubgraph(graphity, gmlsub)
768 |
769 | if args.jit:
770 | #dumpJsonForJit(graphity, indent=2)
771 | BENCH['d3_start'] = time()
772 | dumpJsonForD3(graphity)
773 | BENCH['d3_end'] = time()
774 |
775 |
776 | # TODO calculate dispersion for 2-n anchor addresses
777 | # TODO handling of LoadLib/GetPAddr. for "hiding something" question, follow GetProc return value
778 |
779 |
780 | print('* %s Stuffs all finished ' % str(datetime.now()))
781 |
782 | # TIME
783 | print("\n__..--*** I WANNA BE A BENCHMARK WHEN I GROW UP ***--..__")
784 |
785 | if 'r2_start' in BENCH:
786 | print("__ %5f R2 Analysis" % (BENCH['r2_end'] - BENCH['r2_start']))
787 | if 'graph_end' in BENCH:
788 | print("__ %5f Graph construction" % (BENCH['graph_end'] - BENCH['r2_end']))
789 |
790 | if 'printing_start' in BENCH:
791 | print("__ %5f Printing" % (BENCH['printing_end'] - BENCH['printing_start']))
792 | if 'info_start' in BENCH:
793 | print("__ %5f Info" % (BENCH['info_end'] - BENCH['info_start']))
794 | if 'plotting_start' in BENCH:
795 | print("__ %5f Plotting" % (BENCH['plotting_end'] - BENCH['plotting_start']))
796 | if 'behavior_start' in BENCH:
797 | print("__ %5f Behavior" % (BENCH['behavior_end'] - BENCH['behavior_start']))
798 | if 'neo_start' in BENCH:
799 | print("__ %5f Neo4j" % (BENCH['neo_end'] - BENCH['neo_start']))
800 | if 'csv_start' in BENCH:
801 | print("__ %5f CSV dump" % (BENCH['csv_end'] - BENCH['csv_start']))
802 | if 'gml_start' in BENCH:
803 | print("__ %5f GML dump" % (BENCH['gml_end'] - BENCH['gml_start']))
804 | if 'd3_start' in BENCH:
805 | print("__ %5f D3 dump" % (BENCH['d3_end'] - BENCH['d3_start']))
806 |
807 | else:
808 | print("Potentially not a PE file %s" % args.input)
809 |
810 |
811 |
--------------------------------------------------------------------------------
/graphityFunc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 |
4 | funcDict = {
5 | #
6 | 'CREATETHREAD': ['CreateThread'],
7 | 'PROCESSITER': ['CreateToolhelp32Snapshot', 'Process32First', 'Process32Next'],
8 | 'WINHOOK': ['SetWindowsHookEx'],
9 | 'RETROINJECTION': ['GetCurrentProcess', 'CreatePipe', 'DuplicateHandle'],
10 | 'WINEXEC': ['WinExec'],
11 | 'SHELLEXEC': ['ShellExecute'],
12 | 'CREATEPROC': ['CreateProcess'],
13 | 'EXITSYSTEM': ['ExitWindows'],
14 | 'REMTHREAD': ['CreateThread', 'WriteProcessMemory', 'ReadProcessMemory', 'ResumeThread'],
15 |
16 | # Autostarts & infiltration
17 | 'REGSETVAL': ['RegOpenKey', 'RegSetValue'],
18 | 'REGQUERY': ['RegOpenKey', 'RegQueryValue'],
19 | 'CREATESTARTSERVICE': ['OpenSCManager', 'CreateService', 'OpenService', 'StartService'],
20 | 'DUMPRSRC': ['FindResource', 'LoadResource', 'CreateFile', 'WriteFile'],
21 | 'LOADRSRC': ['FindResource', 'LoadResource', 'LockResource'],
22 | 'UPDATERESOURCE': ['BeginUpdateResource', 'UpdateResource', 'EndUpdateResource'],
23 |
24 | # Dynamic API loading
25 | 'APILOADING': ['GetProcAddress'],
26 | #'APILOADING2': ['GetModuleHandle', 'GetProcAddress'],
27 |
28 | # File interaction
29 | 'WRITEFILE': ['CreateFile', 'WriteFile'],
30 | 'READFILE': ['CreateFile', 'ReadFile'],
31 | 'TEMPFILEWRITE': ['GetTempFileName', 'CreateFile', 'WriteFile'],
32 | 'FPRINT': ['fopen', 'fprintf', 'fclose'],
33 |
34 | # Malware activity
35 | 'DRIVESITER': ['GetLogicalDriveStrings', 'GetDriveType'],
36 | 'FILEITER': ['FindFirstFile', 'FindNextFile', 'FindClose'],
37 | 'WINDOW': ['CreateWindow', 'RegisterClass', 'DispatchMessage'],
38 | 'SCREENSHOT': ['CreateCompatibleDC', 'GetDeviceCaps', 'CreateCompatibleBitmap', 'BitBlt'],
39 | 'CRYPTENCRYPT': ['CryptEncrypt'],
40 |
41 | # Network activity
42 | 'WSASEND': ['WSAStartup', 'gethostbyname', 'send'],
43 | 'RECV': ['recv'],
44 | 'SEND': ['send']
45 |
46 |
47 | }
48 |
49 | rbotDict = {
50 | 'DOWNLOAD': ['InternetOpenUrl', 'CreateFile', 'GetTickCount', 'WriteFile', 'CloseHandle', 'ShellExecute', 'CreateProcess'],
51 | 'DRIVEINFO': ['GetDriveType', 'GetDiskFreeSpace', 'GetLogicalDriveStrings', 'DriveSpace'],
52 | 'FINDFILE': ['FindFirstFile', 'FindNextFile', 'FindClose', 'ExitThread']
53 | }
54 |
55 |
56 |
57 |
58 |
59 | # TODO extend on those, and add moarrr:
60 | # spawn a process
61 | # execute a file
62 | # move file, delete, create dir -
63 | # regenumkey
64 | # createmutex
65 | # fopen, fread, fwrite
66 | # clipboard
67 | # screen capture etc.
68 |
69 |
--------------------------------------------------------------------------------
/graphityOps.py:
--------------------------------------------------------------------------------
1 | import networkx as nx
2 | import graphityFunc
3 | from graphityUtils import stringCharFrequency, stringCharVariance
4 |
5 |
6 | ### SCANNING ###
7 |
8 | # searching nodes and nearby nodes a pattern defined by graphityFunc.py
9 | def patternScan(graphity, pattern):
10 |
11 | # search is performed by defining "anchor" node, where initial pattern is found
12 | # search then moved from there 1 level up to search surrounding nodes (number of levels could be increased)
13 | # pattern lists for now are kept rather small
14 | # TODO determine distance between found patterns to see which functionalities lie close to each other
15 | patternNum = len(pattern)
16 | anchorList = []
17 |
18 | allCalls = nx.get_node_attributes(graphity, 'calls')
19 |
20 | for function in allCalls:
21 |
22 | # TODO make this prettier!
23 | # apis = [el[1] for el in allCalls[function]]
24 | # if 'CreateThread' in apis:
25 | # print (function)
26 |
27 | for call in allCalls[function]:
28 |
29 | api = call[1]
30 | anchorpat = pattern[0]
31 |
32 | if anchorpat in api:
33 | if not list(filter(lambda daAnchor: daAnchor['address'] == function, anchorList)):
34 |
35 | # maintain a dict of patterns per anchor to keep track of found patterns
36 | patternCheck = {}
37 | for item in pattern:
38 | patternCheck[item] = False
39 | patternCheck[anchorpat] = function
40 |
41 | anchorList.append({'address':function, 'patterns':patternCheck})
42 |
43 | # anchor nodes found and more than one pattern searched for
44 | if patternNum > 1 and len(anchorList) > 0:
45 | for anchor in anchorList:
46 |
47 | functionalityScanForApi(graphity, anchor, anchor['address'], patternNum)
48 | if False in anchor['patterns'].values():
49 |
50 | anchorNeighbors = nx.all_neighbors(graphity, anchor['address'])
51 | for neighbor in anchorNeighbors:
52 | functionalityScanForApi(graphity, anchor, neighbor, patternNum)
53 |
54 | return anchorList
55 |
56 |
57 | # Search for a specific pattern within a node, orient by anchor pattern
58 | def functionalityScanForApi(graphity, anchor, seNode, patternNum):
59 |
60 | for patt in anchor['patterns']:
61 |
62 | # anchor has a dict that saves which patterns were found already
63 | for call in graphity.node[seNode]['calls']:
64 | api = call[1]
65 |
66 | # found a pattern in an api call, that hasnt been found before
67 | if patt in api and anchor['patterns'][patt] == False:
68 | anchor['patterns'][patt] = seNode
69 |
70 | if not False in anchor['patterns'].values():
71 | # all patterns found - done
72 | break
73 |
74 |
75 | ### STRINGS ###
76 |
77 | def stringData(graphity, debug):
78 |
79 | # string data format:
80 | # string literal,
81 | # type(ref|dangling|noref),
82 | # character frequency,
83 | # char frequ with char repetition penalty
84 | theData = []
85 |
86 | allStrings = nx.get_node_attributes(graphity, 'strings')
87 | for node in allStrings:
88 | for string in allStrings[node]:
89 | charfrequ = stringCharFrequency(string[1])
90 | charvar = stringCharVariance(string[1])
91 | theData.append([string[1], 'ref', len(string[1]), charfrequ, charfrequ-(charvar/10.0)])
92 |
93 | for item in debug['stringsDangling']:
94 | charfrequ = stringCharFrequency(item)
95 | charvar = stringCharVariance(item)
96 | theData.append([item, 'dangling', len(item), charfrequ, charfrequ-(charvar/10.0)])
97 |
98 | # Strings w/o associated node, evaluated
99 | for item in debug['stringsNoRef']:
100 | charfrequ = stringCharFrequency(item)
101 | charvar = stringCharVariance(item)
102 |
103 | # too much garbage below the 0.04
104 | if charfrequ > 0.04 and len(item) > 4:
105 | theData.append([item, 'noref', len(item), charfrequ, charfrequ-(charvar/10.0)])
106 |
107 | return theData
108 |
109 |
110 | ### TRANSFORMATION ###
111 |
112 | # Create a copy of the graphity structure, with APIs and strings as separate nodes
113 | # Returns extended graph
114 | def fetchExtendedGraph(graphity, allAtts):
115 |
116 | # copy NetworkX graph structure
117 | analysisGraph = graphity.copy()
118 |
119 | # per node, add string/api nodes and respective edges, networkx cares about possible duplicates automatically
120 | for aNode in analysisGraph.nodes(data=True):
121 |
122 | stringList = aNode[1]['strings']
123 | for stringData in stringList:
124 | charfrequ = stringCharFrequency(stringData[1])
125 | charvar = stringCharVariance(stringData[1])
126 | analysisGraph.add_node(stringData[1], type='String', stringeval=charfrequ-(charvar/10.0))
127 | analysisGraph.add_edge(aNode[0], stringData[1])
128 |
129 | apiList = aNode[1]['calls']
130 | for apiData in apiList:
131 | analysisGraph.add_node(apiData[1], type='Api')
132 | analysisGraph.add_edge(aNode[0], apiData[1])
133 |
134 | # delete lists from nodes
135 | del analysisGraph.node[aNode[0]]['calls']
136 | del analysisGraph.node[aNode[0]]['strings']
137 |
138 | # add super node as SHA1
139 | analysisGraph.add_node(allAtts['sha1'], fileSize=allAtts['filesize'], binType=allAtts['filetype'], imphash=allAtts['imphash'], compilation=allAtts['compilationts'], addressEp=allAtts['addressep'], sectionEp=allAtts['sectionep'], sectionCount=allAtts['sectioncount'], originalFilename=allAtts['originalfilename'], type='supernode')
140 |
141 | # add edges to super node
142 | indegrees = graphity.in_degree()
143 | for val in indegrees:
144 | if indegrees[val] == 0:
145 | analysisGraph.add_edge(allAtts['sha1'], val)
146 |
147 | return analysisGraph
148 |
149 |
150 | # Returns the subgraph following [address] extended with APIs/Strings as separate nodes
151 | def fetchExtendedSubgraph(graphity, address):
152 |
153 | theSub = nx.DiGraph()
154 | theSub.add_node(address, type='function', size=graphity.node[address]['size'], apicallcount=graphity.node[address]['apicallcount'])
155 | subGraphity(graphity, theSub, address)
156 | return theSub
157 |
158 | def subGraphity(graphity, theSub, address):
159 |
160 | for acall in graphity.node[address]['calls']:
161 | label = acall[0] + '|' + acall[1]
162 | theSub.add_node(label, type='api', apiname=acall[1])
163 | theSub.add_edge(address, label)
164 |
165 | for astring in graphity.node[address]['strings']:
166 | label = astring[0] + '|' + astring[1]
167 | theSub.add_node(label, type='string', string=astring[1])
168 | theSub.add_edge(address, label)
169 |
170 | neighbors = graphity.successors(address)
171 |
172 | for neigh in neighbors:
173 | theSub.add_node(neigh, type='function', size=graphity.node[neigh]['size'], apicallcount=graphity.node[neigh]['apicallcount']) # add attributes
174 | theSub.add_edge(address, neigh)
175 | subGraphity(graphity, theSub, neigh)
176 |
177 | return
178 |
179 |
180 | # returns the graph, nodes containing each their detected patterns, and a list of all detected patterns
181 | # but no more string and api lists
182 | def fetchBehaviorgadgetGraph(graphity):
183 |
184 | behaviorGraph = graphity.copy()
185 |
186 | allThePatterns = graphityFunc.funcDict
187 | allTheFindings = []
188 | for patty in allThePatterns:
189 | findings = patternScan(graphity, allThePatterns[patty])
190 | for hit in findings:
191 | if not False in hit['patterns'].values():
192 | for node in hit['patterns']:
193 | theNode = hit['patterns'][node]
194 | behaviorGraph.node[theNode][patty] = patty
195 |
196 | for node in behaviorGraph:
197 | del behaviorGraph.node[node]['calls']
198 | del behaviorGraph.node[node]['strings']
199 | behaviorGraph.node[node]['behaviors'] = ''
200 | for patty in allThePatterns:
201 | if behaviorGraph.node[node].get(patty):
202 | behaviorGraph.node[node]['behaviors'] += '|' + patty
203 | if behaviorGraph.node[node]['behaviors'] != '':
204 | behaviorGraph.node[node]['behaviors'] += '|'
205 |
206 | return behaviorGraph
207 |
208 | # fetch a graph with particular patterns in APIs/Strings highlighted, e.g. allocs
209 | def fetchSpecialGraph(graphity, specials):
210 |
211 | # TODO extend for strings
212 | specialGraph = graphity.copy()
213 | for node in specialGraph.nodes():
214 | for spec in specials:
215 | specialGraph.node[node][spec] = 0
216 |
217 | allCalls = nx.get_node_attributes(specialGraph, 'calls')
218 | for function in allCalls:
219 | for call in allCalls[function]:
220 | for spec in specials:
221 | if spec in call[1].lower():
222 | specialGraph.node[function][spec] += 1
223 |
224 | # TODO add one partition feature for all specs
225 |
226 | for node in specialGraph:
227 | del specialGraph.node[node]['calls']
228 | del specialGraph.node[node]['strings']
229 |
230 | # add list of all specials per node
231 | specialGraph.node[node]['specialhits'] = ''
232 | for spec in specials:
233 | if specialGraph.node[node].get(spec):
234 | specialGraph.node[node]['specialhits'] += '|' + spec
235 | if specialGraph.node[node]['specialhits'] != '':
236 | specialGraph.node[node]['specialhits'] += '|'
237 |
238 | return specialGraph
239 |
240 | # TODO node eval for visualization, apis, strings and their evals, lengths, instruction entropy?
241 |
242 | # prepare graph for visualization with D3
243 | def fetchD3Graph(graphity):
244 |
245 | d3graph = graphity.copy()
246 |
247 | for item in d3graph.nodes(data=True):
248 | for callItem in item[1]['calls']:
249 | callItem.insert(1, '[C]')
250 | for stringItem in item[1]['strings']:
251 | stringItem.insert(1, '[S]')
252 |
253 | # mix up API calls and strings and sort by offset
254 | callStringMerge = item[1]['calls'] + item[1]['strings']
255 | callStringMerge.sort(key=lambda x: x[0])
256 |
257 | item[1]['content'] = callStringMerge
258 |
259 | for node in d3graph:
260 | del d3graph.node[node]['calls']
261 | del d3graph.node[node]['strings']
262 |
263 | return d3graph
--------------------------------------------------------------------------------
/graphityOut.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import sys
4 | import os
5 | import py2neo
6 | import networkx as nx
7 | import numpy as np
8 | import pickle
9 | import re
10 | import json
11 | from graphityUtils import gimmeDatApiName, getAllAttributes
12 | from graphityOps import fetchExtendedGraph, stringData
13 |
14 |
15 | def toNeo(graphity, allAtts):
16 |
17 | # GRAPH DB STUFF - NEO4J
18 | # receives the NetworkX graph and accompanying sample data
19 | # pushes the graph to Neo4J
20 |
21 | ### NetworkX Graph Structure ###
22 |
23 | # FUNCTION as node, attributes: function address, size, calltype, list of calls, list of strings, count of calls; functiontype[Standard, Callback, Export], alias (e.g. export name)
24 | # FUNCTIoN REFERENCE as edge (function address -> target address), attributes: ref offset (at)
25 | # CALLBACK REFERENCE as edge (currently for threads and Windows hooks)
26 | # API CALLS (list attribute of function node): address, API name
27 | # STRINGS (list attribute of function node): address, string
28 |
29 | ####
30 |
31 | py2neo.authenticate("localhost:7474", "neo4j", "neo4j")
32 | neoGraph = py2neo.Graph("http://localhost:7474/")
33 | neoSelector = py2neo.NodeSelector(neoGraph)
34 |
35 | # flush of the DB, for test purposes
36 | neoGraph.delete_all()
37 |
38 | mySha1 = allAtts['sha1']
39 |
40 | if neoSelector.select("SAMPLE", sha1=mySha1).first():
41 | print("Graph for sample %s already exists in Neo4j instance!" % mySha1)
42 |
43 | else:
44 |
45 | # create master node for binary information
46 | sampleNode = py2neo.Node("SAMPLE", sha1=mySha1, fileSize=allAtts['filesize'], binType=allAtts['filetype'], imphash=allAtts['imphash'], compilation=allAtts['compilationts'], addressEp=allAtts['addressep'], sectionEp=allAtts['sectionep'], sectionCount=allAtts['sectioncount'], originalFilename=allAtts['originalfilename'])
47 | neoGraph.create(sampleNode)
48 |
49 | # get nodes with 0 indegree, prepare relations from master node
50 | indegrees = graphity.in_degree()
51 | rootlist = []
52 | for val in indegrees:
53 | if indegrees[val] == 0:
54 | rootlist.append(val)
55 |
56 | # parsing of the NetworkX graph - functions, APIs and strings are all Neo4j nodes
57 | for nxNode in graphity.nodes(data=True):
58 |
59 | funcAddress = nxNode[0]
60 | funcCalltype = nxNode[1]['calltype']
61 | funcSize = nxNode[1]['size']
62 | funcAlias = ''
63 | funcType = ''
64 | if nxNode[1].get('functiontype') : funcType = nxNode[1]['functiontype']
65 | if nxNode[1].get('alias') : funcAlias = nxNode[1]['alias']
66 |
67 | # sha1 serves as link to master node, but also as node identifier in combination with the function address
68 | # TODO for saving memory, explore possibility of replacing sha1 with an index, as sha info is held in master node anyway
69 | functionNode = py2neo.Node("FUNCTION", sample=mySha1, address=funcAddress, callType=funcCalltype, funcSize=funcSize, funcType=funcType, alias=funcAlias)
70 | neoGraph.create(functionNode)
71 |
72 | if funcAddress in rootlist:
73 | rootrel = py2neo.Relationship(sampleNode, "virtual_relationship", functionNode)
74 | neoGraph.create(rootrel)
75 |
76 | stringList = nxNode[1]['strings']
77 |
78 | for stringData in stringList:
79 | strRefAddress = stringData[0]
80 | theString = stringData[1]
81 |
82 | # TODO think about string attributes to store, e.g. entropy, len
83 | try:
84 |
85 | # create string node or merge if string already exists, add relationship
86 | stringNode = py2neo.Node("STRING", string=theString)
87 | # TODO try this using Subgraph class, less interaction with DB server
88 | neoGraph.merge(stringNode)
89 |
90 | stringRel = py2neo.Relationship(functionNode, "references_string", stringNode, address=strRefAddress)
91 | neoGraph.create(stringRel)
92 |
93 | except:
94 | print("ERROR with this string %s" % theString)
95 |
96 | callsList = nxNode[1]['calls']
97 |
98 | for callData in callsList:
99 | callRefAddress = callData[0]
100 | callApiName = callData[1]
101 |
102 | # create API node or merge if API already exists, add relationship
103 | apiNode = py2neo.Node("API", apiname=callApiName)
104 | neoGraph.merge(apiNode)
105 |
106 | apiRel = py2neo.Relationship(functionNode, "calls_api", apiNode, address=callRefAddress)
107 | neoGraph.create(apiRel)
108 |
109 | for from_node, to_node, properties in graphity.edges(data=True):
110 |
111 | realFromNode = neoSelector.select("FUNCTION", sample=mySha1, address=from_node).first()
112 | realToNode = neoSelector.select("FUNCTION", sample=mySha1, address=to_node).first()
113 |
114 | funcCallsFunc = py2neo.Relationship(realFromNode, "calls_sub", realToNode)
115 | neoGraph.create(funcCallsFunc)
116 |
117 |
118 | # EXPERIMENTAL fetching queries from Neo
119 | def fromNeo():
120 |
121 | py2neo.authenticate("localhost:7474", "neo4j", "neo4j")
122 | neoGraph = py2neo.Graph("http://localhost:7474/")
123 | neoSelector = py2neo.NodeSelector(neoGraph)
124 |
125 | query = neoGraph.run("MATCH (f:FUNCTION)-->(s:STRING) WHERE s.string CONTAINS 'OpenSSL' RETURN DISTINCT f.sample")
126 | print (query.dump())
127 |
128 | query = neoGraph.run("MATCH (s:SAMPLE {sha1: '04301b59c6eb71db2f701086b617a98c6e026872'})-[rels*]->(c) RETURN *")
129 | print (query.dump())
130 |
131 |
132 | # dump entire NetworkX graph + debug info to text files, graph caching to save parsing time for already parsed binaries
133 | def toPickle(graphity, debug, sha1):
134 |
135 | dumpfile = "cache/" + sha1 + ".txt"
136 | debugfile = "cache/" + sha1 + ".dbg"
137 | pickle.dump(graphity, open(dumpfile, 'wb'))
138 | pickle.dump(debug, open(debugfile, 'wb'))
139 |
140 |
141 | # load graph and its debug info from cache, identified by SHA1
142 | def fromPickle(sha1):
143 |
144 | dumpfile = "cache/" + sha1 + ".txt"
145 | debugfile = "cache/" + sha1 + ".dbg"
146 | graphity = pickle.load(open(dumpfile, 'rb'))
147 | debug = pickle.load(open(debugfile, 'rb'))
148 | return graphity, debug
149 |
150 |
151 | # print functions, their APIs and strings to the commandline, enhancements needed
152 | def printGraph(graphity):
153 |
154 | # TODO add more info to print, alias and stuff, sample info
155 | # print dangling APIs
156 | # print dangling strings
157 |
158 | # urgent TODO sort nodes before printing by address
159 |
160 | for item in graphity.nodes(data=True):
161 | print(item[0], item[1]['apicallcount'], item[1]['stringcount'])
162 | if 'alias' in item[1]:
163 | print("Node alias: " + item[1]['alias'])
164 |
165 | for callItem in item[1]['calls']:
166 | callItem.append('C')
167 | for stringItem in item[1]['strings']:
168 | stringItem.append('S')
169 |
170 | # mix up API calls and strings and sort by offset
171 | callStringMerge = item[1]['calls'] + item[1]['strings']
172 | callStringMerge.sort(key=lambda x: x[0])
173 |
174 | for cx in callStringMerge:
175 | print(cx)
176 |
177 |
178 | # Printing all the meta info to cmdline
179 | def printGraphInfo(graphity, debug):
180 |
181 | # GENERAL INFO
182 |
183 | print(".\nGeneral graph info:")
184 | allAtts = getAllAttributes(sys.argv[1])
185 | print("SAMPLE " + allAtts['filename'])
186 | print("Type: " + allAtts['filetype'])
187 | print("Size: " + str(allAtts['filesize']))
188 | print("MD5: " + allAtts['md5'])
189 | print("SHA1: " + allAtts['sha1'])
190 | print(nx.info(graphity))
191 |
192 | # GRAPH PARSING INFO
193 |
194 | print(".\nGraph measurement data:")
195 | print("%6d Total functions detected with 'aflj'" % debug['functions'])
196 | print("%6d Count of references to local functions" % debug['refsFunctions'])
197 | print("%6d Count of references to data section, global variables" % debug['refsGlobalVar'])
198 | print("%6d Count of references to unrecognized locations" % debug['refsUnrecognized'])
199 | print("%6d Total API refs found via symbol xref check" % debug['apiTotal'])
200 | print("%6d Count APIs w/o function xref" % debug['apiMisses'])
201 | print("%6d Total referenced Strings" % debug['stringsReferencedTotal'])
202 | print("%6d Count of dangling strings (w/o function reference)" % debug['stringsDanglingTotal'])
203 | print("%6d Count of strings w/o any reference" % debug['stringsNoRefTotal'])
204 |
205 | # PE DETAILS
206 |
207 | print(".\nPE details:")
208 | print("Imphash:\t\t" + allAtts['imphash'])
209 | print("Compilation time:\t" + allAtts['compilationts'])
210 | print("Entrypoint address:\t" + hex(allAtts['addressep']))
211 | print("Entrypoint section:\t" + allAtts['sectionep'])
212 | print("TLS section count:\t" + str(allAtts['tlssections']))
213 | print("Original filename:\t" + allAtts['originalfilename'])
214 | print("Section count:\t\t" + str(allAtts['sectioncount']))
215 | print("Section details:")
216 |
217 | i=0
218 | while i < allAtts['sectioncount'] and i < 12:
219 | print("%8s %8d %s" % (allAtts['sectioninfo'][i], allAtts['sectioninfo'][i+12], allAtts['sectioninfo'][i+24]))
220 | i = i + 1
221 |
222 |
223 | # TODO resources list
224 |
225 |
226 | try:
227 | degrees = nx.out_degree_centrality(graphity)
228 | except:
229 | degrees = 0
230 |
231 | indegrees = graphity.in_degree()
232 |
233 | # SPAGHETTI CODE METRICS
234 |
235 | print(".\nFat node detection with out-degree centrality, count calls, count strings:")
236 | if degrees:
237 | sortit = sorted(degrees, key=degrees.get, reverse=True)
238 | for val in sortit[:20]:
239 | # TODO check the numbers
240 | print("%s %.6f %d %d" % (val, degrees[val], len(graphity.node[val]['calls']), len(graphity.node[val]['strings'])))
241 |
242 | print('.')
243 |
244 | # OUT DEGREE CENTRALITY HISTOGRAM
245 |
246 | print("Histogram of out degree centrality:")
247 | nummy = np.array(list(degrees.values()))
248 | bins = [0, 0.0005, 0.001, 0.0015, 0.002, 0.004, 0.006, 0.008, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.2, 0.3, 0.4, 0.5]
249 | hist, bin_edges = np.histogram(nummy, bins=bins)
250 | for be in bin_edges:
251 | print(be, end=' ')
252 | print("")
253 | for hi in hist:
254 | print(hi, end=' ')
255 | print("\n.")
256 |
257 | # LOOSE NODE COUNT
258 |
259 | numInZero = 0
260 | for val in indegrees:
261 | if indegrees[val] == 0:
262 | numInZero = numInZero + 1
263 | nodeNum = graphity.number_of_nodes()
264 | if not nodeNum:
265 | nodeNum = 1
266 |
267 | print("Loose nodes %d of total %d, thats %f%%" % (numInZero, nodeNum, 100.0 * (float(numInZero) / float(nodeNum))))
268 |
269 | # RATIO OF API CALLS AND STRINGS WITHING CODE SECTION
270 |
271 | print(".\nExecSize FunctionCount ApiCount StringCount")
272 | print("%d %d %d %d" % (debug['xsectionsize'], debug['functions'], debug['apiTotal'], debug['stringsReferencedTotal'])) # code section size, function count, total api, total string
273 |
274 | kilobytes = (float(debug['xsectionsize']) / 1000.0)
275 | if kilobytes > 0:
276 | print("Per-Kilobyte ratio")
277 | print(float(debug['functions']) / kilobytes, float(debug['apiTotal']) / kilobytes, float(debug['stringsReferencedTotal']) / kilobytes)
278 |
279 | # AVERAGE DEGREE CONNECTIVITY
280 |
281 | print(".\nAverage degree connectivity per degree k:") #average nearest neighbor degree of nodes with degree k
282 | avConn = nx.average_degree_connectivity(graphity)
283 | for connectivity in avConn:
284 | print("%3d %.6f" % (connectivity, avConn[connectivity]))
285 |
286 | print(".")
287 |
288 | # GETPROCADDRESS DETECTION, not a suuuuper useful metric, but interesting to look at, different from beh. detection, cause count is total
289 |
290 | allCalls = nx.get_node_attributes(graphity, 'calls')
291 | gpaCount = 0
292 |
293 | for function in allCalls:
294 | for call in allCalls[function]:
295 | if 'GetProcAddress' in call[1]:
296 | gpaCount = gpaCount + 1
297 |
298 | print("Found %d calls to GetProcAddress\n." % gpaCount)
299 |
300 | # TODO number of nodes w strings/apis vs. nodes w/o
301 |
302 |
303 | def dumpGraphInfoCsv(graphity, debug, allAtts, csvfile):
304 |
305 | # filename, filetype, filesize, codesectionsize, md5, compilationtime, addressep, sectionep, tlssections, originalfilename, sectioncount, sectiondata, functionstotal, refslocal, refsglobalvar,
306 | # refsunknown, apitotal, apimisses, stringsreferenced, stringsdangling, stringsnoref, ratiofunc, ratioapi, ratiostring, getproc, createthreat, memalloc
307 |
308 | final = []
309 | if os.path.isfile(csvfile):
310 | dumpfile = open(csvfile, 'a')
311 | else:
312 | try:
313 | dumpfile = open(csvfile, 'w')
314 | dumpfile.write("filename,filetype,filesize,codesecsize,md5,imphash,compilationtime,addressep,sectionep,tlssections,originalfilename,sectioncount,secname1,secname2,secname3,secname4,secname5,secname6,secsize1,secsize2,secsize3,secsize4,secsize5,secsize6,secent1,secent2,secent3,secent4,secent5,secent6,functionstotal,refslocal,refsglobalvar,refsunknown,apitotal,apimisses,stringsreferenced,stringsdangling,stringsnoref,ratiofunc,ratioapi,ratiostring,getprocaddress,memallocation,createthread,ctshortestpath,callbackcount,cbaveragesize,cblargestsize,stringsrefhisto")
315 | dumpfile.write("\n")
316 | except:
317 | print("ERROR couldn't create the csv dump file")
318 | return
319 |
320 |
321 | final.append(allAtts['filename'])
322 | final.append(allAtts['filetype'].replace(',',''))
323 | final.append(str(allAtts['filesize']))
324 | final.append(str(debug['xsectionsize']))
325 | final.append(allAtts['md5'])
326 | final.append(allAtts['imphash'])
327 | final.append(allAtts['compilationts'])
328 | final.append(hex(allAtts['addressep']))
329 | final.append(allAtts['sectionep'])
330 | final.append(str(allAtts['tlssections']))
331 | final.append(allAtts['originalfilename'])
332 | final.append(str(allAtts['sectioncount']))
333 |
334 | secStuff = allAtts['sectioninfo'][:6] + allAtts['sectioninfo'][12:18] + allAtts['sectioninfo'][24:30]
335 | final = final + secStuff
336 |
337 | final.append(debug['functions'])
338 | final.append(debug['refsFunctions'])
339 | final.append(debug['refsGlobalVar'])
340 | final.append(debug['refsUnrecognized'])
341 | final.append(debug['apiTotal'])
342 | final.append(debug['apiMisses'])
343 | final.append(debug['stringsReferencedTotal'])
344 | final.append(debug['stringsDanglingTotal'])
345 | final.append(debug['stringsNoRefTotal'])
346 |
347 | # Ratios: functions, APIs, strings per kilobyte of code section
348 | kilobytes = (float(debug['xsectionsize']) / 1000.0)
349 | if kilobytes > 0:
350 | final.append(str(float(debug['functions']) / kilobytes))
351 | final.append(str(float(debug['apiTotal']) / kilobytes))
352 | final.append(str(float(debug['stringsReferencedTotal']) / kilobytes))
353 | else:
354 | final.append('')
355 | final.append('')
356 | final.append('')
357 |
358 | # Counting total calls to APIs of interest
359 | allCalls = nx.get_node_attributes(graphity, 'calls')
360 | gpaCount = 0
361 | createThCount = 0
362 | memAllocs = 0
363 |
364 | # TODO replace this with exGraph
365 | for function in allCalls:
366 | for call in allCalls[function]:
367 | if 'GetProcAddress' in call[1]:
368 | gpaCount = gpaCount + 1
369 | if 'CreateThread' in call[1]:
370 | createThCount = createThCount + 1
371 | if 'alloc' in call[1].lower():
372 | memAllocs = memAllocs + 1
373 |
374 | final.append(str(gpaCount))
375 | final.append(str(memAllocs))
376 | final.append(str(createThCount))
377 |
378 | # Extended version of graphity, where strings/apis are nodes by themselves + graph has a supernode
379 | exGraph = fetchExtendedGraph(graphity, allAtts)
380 |
381 | shortestPathLen = 0
382 | if createThCount > 0:
383 | #shortestPath = nx.shortest_path(exGraph, allAtts['sha1'], 'CreateThread')[1:]
384 | #allShortestPaths = nx.all_shortest_paths(exGraph, allAtts['sha1'], 'CreateThread')
385 | try:
386 | shortestPathLen = nx.shortest_path_length(exGraph, allAtts['sha1'], 'CreateThread')
387 |
388 | except:
389 | #print (exGraph.node['CreateThread'], exGraph.node[allAtts['sha1']])
390 | pass
391 | # add shortest path length as metric
392 | final.append(str(shortestPathLen))
393 |
394 | # Callback sizes
395 | callbackCount = 0
396 | callbackSizes = []
397 | callbacks = (n for n in exGraph if 'functiontype' in exGraph.node[n] and exGraph.node[n]['functiontype'] == 'Callback')
398 | for cback in callbacks:
399 | callbackCount += 1
400 | callbackSizes.append(exGraph.node[cback]['size'])
401 |
402 | final.append(str(callbackCount))
403 | avSize = 0
404 | maxSize = 0
405 | if callbackCount > 0:
406 | avSize = int(np.mean(callbackSizes))
407 | maxSize = max(callbackSizes)
408 | final.append(avSize)
409 | final.append(maxSize)
410 |
411 |
412 | # TODO convert stringdata to dictionary
413 | stringStuff = stringData(graphity, debug)
414 | refHistoList = []
415 | # slice data to get eval column
416 | for line in stringStuff:
417 | if line[1] == 'ref':
418 | refHistoList.append(line[3])
419 |
420 | nummy = np.array(refHistoList)
421 | bins = [0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1]
422 | histo, bin_edges = np.histogram(nummy, bins=bins)
423 | histolist = []
424 | for hi in histo:
425 | histolist.append(str(hi))
426 | final.append(','.join(histolist))
427 |
428 |
429 |
430 | theline = ",".join(map(str, final)) + "\n"
431 |
432 | dumpfile.write(theline)
433 | dumpfile.close()
434 |
435 | # Dumping dedicated CSV for string eval data, per binary
436 | stringCsv = "output/" + csvfile + "_" + allAtts['sha1'] + ".csv"
437 | stringFile = open(stringCsv, 'w')
438 |
439 | for list in stringStuff:
440 | list[0] = list[0].replace(',', '.')
441 | list[0] = list[0].replace(';', '.')
442 |
443 | for item in stringStuff:
444 | content = ','.join(map(str, item)) + "\n"
445 | stringFile.write(content)
446 | stringFile.close()
447 |
448 |
449 |
--------------------------------------------------------------------------------
/graphityUtils.py:
--------------------------------------------------------------------------------
1 | from hashlib import sha1, md5
2 | from os.path import basename, getsize
3 | import magic
4 | import pydeep
5 | import pefile
6 | import time
7 | import math
8 | import struct
9 | from io import open
10 | from collections import Counter
11 |
12 | # receives a string, containing a symbol a la radare2
13 | # returns the sole API name
14 |
15 | def gimmeDatApiName(wholeString):
16 |
17 | separators = ['.dll_', '.sys_', '.exe_', '.sym_']
18 |
19 | for sep in separators:
20 |
21 | if sep in wholeString:
22 | apiName = wholeString.split(sep)[1].replace(']','')
23 | return apiName
24 |
25 | elif sep.upper() in wholeString:
26 | apiName = wholeString.split(sep.upper())[1].replace(']','')
27 | return apiName
28 |
29 | return wholeString
30 |
31 |
32 | # checks whether a string is pure ascii
33 |
34 | def is_ascii(myString):
35 | try:
36 | myString.decode('ascii')
37 | return True
38 | except UnicodeDecodeError:
39 | return False
40 |
41 | # String evaluation
42 |
43 | def stringCharFrequency(seString):
44 |
45 | # english language character frequencies
46 | freqs = {
47 | 'a': 0.0651738,
48 | 'b': 0.0124248,
49 | 'c': 0.0217339,
50 | 'd': 0.0349835,
51 | 'e': 0.1041442,
52 | 'f': 0.0197881,
53 | 'g': 0.0158610,
54 | 'h': 0.0492888,
55 | 'i': 0.0558094,
56 | 'j': 0.0109033,
57 | 'k': 0.0150529,
58 | 'l': 0.0331490,
59 | 'm': 0.0202124,
60 | 'n': 0.0564513,
61 | 'o': 0.0596302,
62 | 'p': 0.0137645,
63 | 'q': 0.0058606,
64 | 'r': 0.0497563,
65 | 's': 0.0515760,
66 | 't': 0.0729357,
67 | 'u': 0.0225134,
68 | 'v': 0.0182903,
69 | 'w': 0.0271272,
70 | 'x': 0.0013692,
71 | 'y': 0.0145984,
72 | 'z': 0.0017836,
73 | ' ': 0.0500000,
74 | '0': 0.0500000,
75 | '1': 0.0500000,
76 | '2': 0.0500000,
77 | '3': 0.0500000,
78 | '4': 0.0500000,
79 | '5': 0.0500000,
80 | '6': 0.0500000,
81 | '7': 0.0500000,
82 | '8': 0.0500000,
83 | '9': 0.0500000,
84 | '.': 0.0400000,
85 | '_': 0.0400000
86 | }
87 |
88 | score = 0
89 |
90 | for i in seString:
91 | ch = i.lower()
92 | if ch in freqs:
93 | score += freqs[ch]
94 |
95 | if len(seString) > 15:
96 | return score / float(len(seString)/2)
97 |
98 | return score / float(len(seString))
99 |
100 | def stringCharVariance(seString):
101 |
102 | charFrequs = Counter(seString)
103 | total = 0
104 | for letter in charFrequs:
105 | if charFrequs[letter] < 4:
106 | total += (charFrequs[letter]-1)
107 | elif charFrequs[letter] < 5:
108 | total += (charFrequs[letter]-0.75)
109 | elif charFrequs[letter] < 6:
110 | total += (charFrequs[letter]-0.5)
111 | elif charFrequs[letter] < 7:
112 | total += (charFrequs[letter]-0.25)
113 | else:
114 | total += charFrequs[letter]
115 |
116 |
117 | #print (seString, total)
118 |
119 | return total / float(len(seString)*2)
120 |
121 | # Check for PE header, return false if not a PE
122 | def check_pe_header(filepath):
123 | try:
124 | with open(filepath, 'rb') as fp:
125 | if (fp.read(2) == b'MZ'):
126 | fp.read(58)
127 | peoff = struct.unpack('i', fp.read(4))
128 | advance = peoff[0] - 64
129 | fp.read(advance)
130 | if (fp.read(2) == b'PE'):
131 | return True
132 | return False
133 |
134 | except(Exception) as e:
135 | print("LOG - PE Parsing Error, sure this is a PE file?")
136 | return False
137 | return False
138 |
139 |
140 | # SAMPLE ATTRIBUTE GETTERS
141 |
142 | # MD5
143 | # filename
144 | # filetype
145 | # ssdeep
146 | # imphash
147 | # size
148 | # compilationTS
149 | # address of EP
150 | # EP section
151 | # number of section
152 | # original filename
153 | # number TLS sections
154 |
155 | def sha1hash(path):
156 | with open(path, 'rb') as f:
157 | return sha1(f.read()).hexdigest()
158 |
159 | def md5hash(path):
160 | with open(path, 'rb') as f:
161 | return md5(f.read()).hexdigest()
162 |
163 | def getFilename(path):
164 | return basename(path)
165 |
166 | def getFiletype(path):
167 | return magic.from_file(path)
168 |
169 | def getFilesize(path):
170 | return getsize(path)
171 |
172 | def getPeSubsystem(path):
173 | pass
174 |
175 | def getSsdeep(path):
176 | return pydeep.hash_file(path)
177 |
178 | def getImphash(pe):
179 | return pe.get_imphash()
180 |
181 | def getCompilationTS(pe):
182 | return time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(pe.FILE_HEADER.TimeDateStamp))
183 |
184 | def getEPAddress(pe):
185 | return pe.OPTIONAL_HEADER.AddressOfEntryPoint
186 |
187 | def getSectionCount(pe):
188 | return pe.FILE_HEADER.NumberOfSections
189 |
190 | def getOriginalFilename(pe):
191 | oriFilename = ""
192 | if hasattr(pe, 'VS_VERSIONINFO'):
193 | if hasattr(pe, 'FileInfo'):
194 | for entry in pe.FileInfo:
195 | if hasattr(entry, 'StringTable'):
196 | for st_entry in entry.StringTable:
197 | ofn = st_entry.entries.get(b'OriginalFilename')
198 | if ofn:
199 | if isinstance(ofn, bytes):
200 | oriFilename = ofn.decode()
201 | else:
202 | oriFilename = ofn
203 | return oriFilename
204 |
205 |
206 | def getEPSection(pe):
207 | name = ''
208 | if hasattr(pe, 'OPTIONAL_HEADER'):
209 | ep = pe.OPTIONAL_HEADER.AddressOfEntryPoint
210 | else:
211 | return False
212 | pos = 0
213 | for sec in pe.sections:
214 | if (ep >= sec.VirtualAddress) and (ep < (sec.VirtualAddress + sec.Misc_VirtualSize)):
215 | name = sec.Name.replace(b'\x00', b'')
216 | break
217 | else:
218 | pos += 1
219 | if name:
220 | return (name.decode('utf-8', 'ignore') + "|" + pos.__str__())
221 | return ''
222 |
223 | def getTLSSectionCount(pe):
224 | idx = 0
225 | if (hasattr(pe, 'DIRECTORY_ENTRY_TLS') and pe.DIRECTORY_ENTRY_TLS and pe.DIRECTORY_ENTRY_TLS.struct and pe.DIRECTORY_ENTRY_TLS.struct.AddressOfCallBacks):
226 | callback_array_rva = pe.DIRECTORY_ENTRY_TLS.struct.AddressOfCallBacks - pe.OPTIONAL_HEADER.ImageBase
227 |
228 | while True:
229 | func = pe.get_dword_from_data(pe.get_data(callback_array_rva + 4 * idx, 4), 0)
230 | if func == 0:
231 | break
232 | idx += 1
233 | return idx
234 |
235 |
236 | # Returns Entropy value for given data chunk
237 | def Hvalue(data):
238 | if not data:
239 | return 0.0
240 |
241 | occurences = Counter(bytearray(data))
242 |
243 | entropy = 0
244 | for x in occurences.values():
245 | p_x = float(x) / len(data)
246 | if p_x > 0:
247 | entropy += - p_x * math.log(p_x, 2)
248 |
249 | return entropy
250 |
251 |
252 | def getCodeSectionSize(pe):
253 |
254 | for section in pe.sections:
255 | print(section)
256 |
257 |
258 | def getSectionInfo(pe):
259 |
260 | # Section info: names, sizes, entropy vals
261 | sects = []
262 | vadd = []
263 | ent = []
264 | secnumber = getSectionCount(pe)
265 |
266 | for i in range(12):
267 |
268 | if (i + 1 > secnumber):
269 | strip = ""
270 | strap = ""
271 | entropy = ""
272 |
273 | else:
274 | stuff = pe.sections[i]
275 | strip = stuff.Name.replace(b'\x00', b'')
276 | strap = stuff.SizeOfRawData
277 |
278 | entropy = Hvalue(stuff.get_data())
279 |
280 | section_name = ""
281 | try:
282 | if strip != "":
283 | section_name = strip.decode()
284 | except:
285 | section_name = "PARSINGERR"
286 |
287 | sects.append(section_name)
288 | ent.append(entropy)
289 | vadd.append(strap)
290 |
291 | secinfo = sects + vadd + ent
292 | return secinfo
293 |
294 |
295 | # ATTRIBUTES: md5, sha1, filename, filetype, ssdeep, filesize, imphash, compilationts, addressep, sectionep,
296 | # sectioncount, sectioninfo, tlssections, originalfilename
297 |
298 | def getAllAttributes(path):
299 |
300 | allAtts = {}
301 |
302 | allAtts['md5'] = md5hash(path)
303 | allAtts['sha1'] = sha1hash(path)
304 | allAtts['filename'] = getFilename(path)
305 | allAtts['filetype'] = getFiletype(path)
306 | allAtts['ssdeep'] = getSsdeep(path)
307 | allAtts['filesize'] = getFilesize(path)
308 |
309 | try:
310 | pe = pefile.PE(path)
311 | if (pe.DOS_HEADER.e_magic == int(0x5a4d) and pe.NT_HEADERS.Signature == int(0x4550)):
312 | allAtts['imphash'] = getImphash(pe)
313 | allAtts['compilationts'] = getCompilationTS(pe)
314 | allAtts['addressep'] = getEPAddress(pe)
315 | allAtts['sectionep'] = getEPSection(pe)
316 | allAtts['sectioncount'] = getSectionCount(pe)
317 | allAtts['sectioninfo'] = getSectionInfo(pe)
318 | allAtts['tlssections'] = getTLSSectionCount(pe)
319 | allAtts['originalfilename'] = getOriginalFilename(pe)
320 |
321 | except (pefile.PEFormatError):
322 | allAtts['imphash'] = ''
323 | allAtts['compilationts'] = ''
324 | allAtts['addressep'] = ''
325 | allAtts['sectionep'] = ''
326 | allAtts['sectioncount'] = ''
327 | allAtts['sectioninfo'] = ''
328 | allAtts['tlssections'] = ''
329 | allAtts['originalfilename'] = ''
330 |
331 | return allAtts
332 |
--------------------------------------------------------------------------------
/graphityViz.py:
--------------------------------------------------------------------------------
1 | from pydotplus.graphviz import Node
2 | import networkx as nx
3 | from networkx.readwrite import json_graph
4 | import json
5 | import os
6 |
7 | from graphityOps import fetchExtendedGraph, fetchExtendedSubgraph, fetchBehaviorgadgetGraph, fetchSpecialGraph, fetchD3Graph
8 | import graphityFunc
9 |
10 |
11 | def dumpGml(graphity, allAtts):
12 |
13 | gmlData = graphity.copy()
14 |
15 | # gotta fix the lists of lists to list for gml, otherwise incompatible
16 | for node in gmlData.node:
17 | for attr in gmlData.node[node]:
18 | if type(gmlData.node[node][attr]) == list:
19 | listOfLists = gmlData.node[node][attr]
20 | seList = map(' '.join, listOfLists)
21 | gmlData.node[node][attr] = ' | '.join(seList)
22 |
23 | nx.write_gml(gmlData, "output/callgraph.gml")
24 |
25 |
26 | # generates GML for graph containing behavior gadgets, no strings/apis
27 | behaviorGraph = fetchBehaviorgadgetGraph(graphity)
28 | nx.write_gml(behaviorGraph, "output/behaviorgaddgets.gml")
29 |
30 | # generates GML for special gadgets, handed over as list, searched for within API calls
31 | allocGraph = fetchSpecialGraph(graphity, ['alloc', 'mem'])
32 | nx.write_gml(allocGraph, "output/allocgadgets.gml")
33 |
34 | # generates GML for extended Graph, where APIs and strings are dedicated nodes
35 | extendedGraph = fetchExtendedGraph(graphity, allAtts)
36 | nx.write_gml(extendedGraph, "output/extendedgraph.gml")
37 |
38 |
39 | # dumps the gml data for a subgraph starting at [address] with APIs/strings as dedicated nodes
40 | def dumpGmlSubgraph(graphity, address):
41 | if address in graphity:
42 | subgraph = fetchExtendedSubgraph(graphity, address)
43 | gmlfile = "output/subgraph_" + address + ".gml"
44 | nx.write_gml(subgraph, gmlfile)
45 |
46 |
47 | # Graph plotting with pydotplus from within NetworkX, format is dot
48 | def graphvizPlot(graphity, allAtts):
49 |
50 | pydotMe = nx.drawing.nx_pydot.to_pydot(graphity)
51 | for node in pydotMe.get_nodes():
52 |
53 | # get node address to be able to fetch node directly from graphity to preserve data types of attributes
54 | nodeaddr = node.to_string().split()[0].replace('\"', '')
55 | finalString = ''
56 |
57 | if node.get('calls') != '[]' or node.get('strings') != '[]':
58 |
59 | finalList = []
60 |
61 | # fetching string and call lists directly from graphity
62 | callList = graphity.node[nodeaddr]['calls']
63 | stringList = graphity.node[nodeaddr]['strings']
64 |
65 | for item in callList:
66 | finalList.append(str(item[0]) + ": [C] " + str(item[1]))
67 | for otem in stringList:
68 | finalList.append(str(otem[0]) + ": [S] " + str(otem[1]))
69 |
70 | finalList.sort()
71 | finalString = '\n'.join(finalList)
72 |
73 | if node.get('functiontype') == 'Export':
74 | label = "Export " + nodeaddr + node.get('alias')
75 | label = label + "\n" + finalString
76 | node.set_fillcolor('skyblue')
77 | node.set_style('filled,setlinewidth(3.0)')
78 | node.set_label(label)
79 |
80 | elif node.get('functiontype') == 'Callback':
81 | label = "Callback " + nodeaddr + "\n" + finalString
82 | node.set_fillcolor('darkolivegreen1')
83 | node.set_style('filled,setlinewidth(3.0)')
84 | node.set_label(label)
85 |
86 | elif node.get('functiontype').startswith('Indirect'):
87 | label = "IndirectRef " + nodeaddr + "\n" + finalString
88 | node.set_fillcolor('lemonchiffon1')
89 | node.set_style('filled,setlinewidth(3.0)')
90 | node.set_label(label)
91 |
92 | elif finalString != '':
93 | finalString = nodeaddr + "\n" + finalString
94 | node.set_fillcolor('lightpink1')
95 | node.set_style('filled,setlinewidth(3.0)')
96 | node.set_label(finalString)
97 |
98 | 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']
99 |
100 | titleNode = Node()
101 | titleNode.set_label(graphinfo)
102 | titleNode.set_shape('rectangle')
103 | titleNode.set_fillcolor('grey')
104 | titleNode.set_style('filled')
105 | pydotMe.add_node(titleNode)
106 |
107 | graphname = allAtts['filename'] + ".png"
108 | try:
109 | # TODO pydotplus throws an error sometimes (Error: /tmp/tmp6XgKth: syntax error in line 92 near '[') look into pdp code to see why
110 | pydotMe.write_png(os.path.join(os.path.abspath(os.path.dirname(__file__)), graphname))
111 | except Exception as e:
112 | print("ERROR drawing graph")
113 | print(str(e))
114 |
115 |
116 | # Experimental Javascript InfoVis Tk data generation
117 | def dumpJsonForJit(graphity, indent=None):
118 |
119 | json_graph = []
120 | for node in graphity.nodes():
121 | json_node = {
122 | 'id': node,
123 | 'name': node
124 | }
125 | # node data
126 | json_node['data'] = graphity.node[node]
127 |
128 | # Style
129 | if graphity.node[node].get('calls') != []:
130 | json_node['data']['$color'] = '#FFFF00' # yellow
131 |
132 | if graphity.node[node].get('functiontype') == 'Callback':
133 | json_node['data']['$dim'] = 8
134 | json_node['data']['$type'] = 'square'
135 | json_node['data']['$color'] = '#FF0080' # pink
136 | json_node['name'] = node + " Callback"
137 |
138 | if graphity.node[node].get('functiontype') == 'Export':
139 | json_node['data']['$dim'] = 8
140 | json_node['data']['$type'] = 'square'
141 | json_node['data']['$color'] = '#3ADF00' # green
142 | json_node['name'] = node + " Export"
143 |
144 |
145 | # adjacencies
146 | if graphity[node]:
147 | json_node['adjacencies'] = []
148 |
149 | for neighbour in graphity[node]:
150 | adjacency = {'nodeTo': neighbour}
151 | # adjacency data
152 | adjacency['data'] = graphity.edge[node][neighbour]
153 | json_node['adjacencies'].append(adjacency)
154 | #print (json_node)
155 | json_graph.append(json_node)
156 |
157 | #print(json.dumps(json_graph, indent=indent))
158 | return json.dumps(json_graph, indent=indent)
159 |
160 |
161 | def dumpJsonForD3(graphity):
162 |
163 | # TODO transform graph to visualization needs
164 |
165 | d3graph = fetchD3Graph(graphity)
166 |
167 | data = json.dumps(json_graph.node_link_data(d3graph), indent=2)
168 | d3file = "d3js/d3.json"
169 | d3handle = open(d3file, 'w')
170 | d3handle.write(data)
171 | d3handle.close()
--------------------------------------------------------------------------------
/output/Animalfarm.csv:
--------------------------------------------------------------------------------
1 | filename,filetype,filesize,codesecsize,md5,imphash,compilationtime,addressep,sectionep,tlssections,originalfilename,sectioncount,secname1,secname2,secname3,secname4,secname5,secname6,secsize1,secsize2,secsize3,secsize4,secsize5,secsize6,secent1,secent2,secent3,secent4,secent5,secent6,functionstotal,refslocal,refsglobalvar,refsunknown,apitotal,apimisses,stringsreferenced,stringsdangling,stringsnoref,ratiofunc,ratioapi,ratiostring,getprocaddress,memallocation,createthread,ctshortestpath,callbackcount,cbaveragesize,cblargestsize,stringsrefhisto
2 | 058f97f04ceffef08f39a71af71e537cbb66ad34762eac10861ba9014c4027e1,PE32 executable (GUI) Intel 80386 for MS Windows,434176,196608,bbf4b1961ff0ce19db748616754da76e,041c554f36c4fe7e843f8de97f7bae99,2010-06-21 09:35:15,0x1c26d,.text|0,0,,5,.text,.rdata,.data,.rsrc,.reloc,,196608,28672,12288,4096,188416,,6.6827832360775705,4.918666461209748,4.184370767947775,0.3918833886381113,7.887215327766603,,1395,4356,5,1,551,1,321,0,6596,7.0953369140625,2.8025309244791665,1.6326904296875,12,24,1,2,1,220,220,4-9-38-86-115-14-13-11-23
3 | 1994a8943b1e153db30a1417fd7ca8454abc38f9be8bc56ea1c898642acbe076,PE32 executable (GUI) Intel 80386 for MS Windows,458559,114176,68232e5b569fa58917b884ad8acd79ed,a9e537e04767ea26d8cf8705fea73bdd,2013-06-19 17:15:23,0x8fcb,.text|0,0,,5,.text,.rdata,.data,.reloc,.rsrc,,114176,23552,7168,9216,8192,,6.650839395247582,4.848302077581436,3.7738213979848685,5.068448054432351,3.862058010573144,,876,2580,6,1,308,0,72,0,7610,7.672365470852018,2.6975896860986546,0.6306053811659192,20,7,1,4,1,101,101,2-1-8-12-25-1-2-3-14
4 | 43861501e7e7bb546b55a9323d1cff132dddb750b3e86823af7ea08d45357e28,PE32 executable (GUI) Intel 80386 for MS Windows,192512,139264,51cd931e9352b3b8f293bf3b9a9449d2,da740fe1aca64c193d2c6ee1facd2104,2010-05-06 13:47:37,0x1284b,.text|0,0,,5,.text,.rdata,.data,.rsrc,.reloc,,139264,20480,12288,4096,12288,,6.547450609009741,5.288756666223076,3.827964653369115,0.0,4.675338314777438,,875,3523,3,2,679,1,365,0,2327,6.283030790441176,4.875631893382352,2.620921415441176,11,20,8,2,7,503,864,3-10-31-133-107-12-17-18-23
5 | 4f4b484acc053687d6e4365f0f19e926b1a44cc665182aa6b9417fa43264b240,PE32 executable (GUI) Intel 80386 for MS Windows,192512,139264,e8a333a726481a72b267ec6109939b0d,da740fe1aca64c193d2c6ee1facd2104,2010-05-06 13:47:37,0x1284b,.text|0,0,,5,.text,.rdata,.data,.rsrc,.reloc,,139264,20480,12288,4096,12288,,6.547450609009741,5.288756666223076,3.827964653369115,0.0,4.675338314777438,,875,3523,3,2,679,1,365,0,2327,6.283030790441176,4.875631893382352,2.620921415441176,11,20,8,2,7,503,864,3-10-31-133-107-12-17-18-23
6 | 5b54508b69a6d8a7630f9f6b627cba6dc80320f2f762a2cc8ba4dd4519ef500a,PE32 executable (GUI) Intel 80386 for MS Windows,290816,233472,83b7c532663f11bf994a1b518880557d,e5c91819994f87e4b5099e1d342bbec5,2010-03-09 14:32:03,0x20ec5,.text|0,0,,4,.text,.rdata,.data,.rsrc,,,233472,36864,12288,4096,,,6.636650721734158,4.698327673778753,4.863273179778104,0.0,,,1571,5266,5,2,740,1,393,0,3577,6.728858278508771,3.1695449561403506,1.6832853618421053,12,20,7,3,6,539,863,3-13-27-140-110-14-19-18-33
7 | 5ef78d7c2d3b7201e540e6c1909174c7133fca8bafc44ac53ce275e04559c393,PE32 executable (GUI) Intel 80386 for MS Windows,192512,139264,d5a80844c54059654688ae7abfc1fad9,da740fe1aca64c193d2c6ee1facd2104,2010-05-06 13:47:37,0x1284b,.text|0,0,,5,.text,.rdata,.data,.rsrc,.reloc,,139264,20480,12288,4096,12288,,6.547450609009741,5.288756666223076,3.827964653369115,0.0,4.675338314777438,,875,3523,3,2,679,1,365,0,2327,6.283030790441176,4.875631893382352,2.620921415441176,11,20,8,2,7,503,864,3-10-31-133-107-12-17-18-23
8 | 7d1e5c4afb1682087d86e793b3fc5a8371dc7c28e27e7196e3b258934f6bafb5,PE32 executable (GUI) Intel 80386 for MS Windows,802144,583680,b8ac16701c3c15b103e61b5a317692bc,c0b4d1880addd1fcab5095057ac559e2,2011-10-25 19:28:39,0x572ae,.text|0,0,netmgr.exe,5,.text,.rdata,.data,.rsrc,.reloc,,583680,112128,68608,2560,24064,,6.34353480646419,6.1564028320667905,3.790503667137237,6.1419732599426435,6.099956952230222,,3685,14429,4,2,1156,70,1009,59,6919,6.313390899122807,1.9805372807017545,1.7286869517543861,25,39,8,2,4,734,1241,16-59-103-195-191-36-34-79-135
9 | 82daadf1558692587f82d6ad545b7e6ba2c98a88a20604e2f074f39248aa2712,PE32 executable (GUI) Intel 80386 for MS Windows,184320,139264,8132ee00f64856cf10930fd72505cebe,ab6ca4f362ad7e1f7c89ed74c127c9ff,2010-03-11 16:55:03,0x12b76,.text|0,0,,4,.text,.rdata,.data,.rsrc,,,139264,24576,12288,4096,,,6.530174474181165,4.64687943062068,3.779560986539929,0.0,,,895,3518,4,2,679,1,359,0,2104,6.426642922794117,4.875631893382352,2.577837775735294,11,20,7,3,6,550,863,3-10-27-132-103-12-19-20-22
10 | 82e6f9c10c7ba737f8c79deae4132b9ff82090ccd220eb3d3739365b5276c3c8,PE32 executable (GUI) Intel 80386 for MS Windows,710141,79872,8b3961f7f743daacfd67380a9085da4f,f445666591b9dc1e4fa252be6b3a3a67,2011-07-06 13:50:11,0x691a,.text|0,0,,4,.text,.rdata,.data,.rsrc,,,79872,24576,4608,512,,,6.587479863059564,6.818946676979433,2.4062969218711365,0.0,,,624,1905,3,4,291,0,140,0,13564,7.8125,3.643329326923077,1.7528044871794872,15,12,0,0,0,0,0,3-66-3-14-24-19-0-4-2
11 | 8e6402c8703e9f10493222a26afeb0fc575bb879d6c82d89c1a79aa75be645d0,PE32 executable (GUI) Intel 80386 for MS Windows,520704,87040,4d7ca8d467770f657305c16474b845fe,2059382daa611ced9176544e1286e55c,2010-06-18 14:18:13,0xdbca,.text|0,0,,6,.text,.rdata,.data,.rsrc,.reloc,.idata,87040,19456,7680,1024,7168,397312,6.5594749855049015,5.921400725408906,1.6283115340650474,1.1189015333263308,4.455092453676996,7.999446110463291,643,2291,4,1,308,1,155,0,9299,7.3874080882352935,3.53860294117647,1.7807904411764706,10,8,1,3,1,111,111,2-14-7-44-65-10-1-3-5
12 | 9f7cc8de9c5c08d71cbe692232e4e33a6afd6d30d40df33036be8b09751b0823,PE32 executable (GUI) Intel 80386 for MS Windows,299008,81920,6cd2413064c65804c4025f7865a2fe20,0226ff46c04d70487272245eae4d2eba,2010-01-15 08:59:20,0xb380,.text|0,0,,4,.text,.rdata,.data,.rsrc,,,81920,16384,8192,188416,,,6.563337554442985,4.534740004958626,4.332237928201181,7.964408021031477,,,489,2038,3,4,391,1,249,0,5178,5.96923828125,4.77294921875,3.03955078125,11,22,0,0,0,0,0,2-5-38-65-94-12-8-17-5
13 | a1973790e277b489110ae8ed625c13c2e9a79afaa2aed5d27904dcfa46481ae3,PE32 executable (GUI) Intel 80386 for MS Windows,184320,139264,2a64d331964dbdec8141f16585f392ba,ab6ca4f362ad7e1f7c89ed74c127c9ff,2010-02-16 17:05:54,0x12996,.text|0,0,,4,.text,.rdata,.data,.rsrc,,,139264,24576,12288,4096,,,6.515372504348373,4.756600838892071,3.7515592922515517,0.0,,,896,3529,3,2,673,1,354,0,2090,6.4338235294117645,4.83254825367647,2.5419347426470584,11,20,7,3,5,502,863,3-9-27-132-99-12-20-19-22
14 | aa73634ca325022dd6daff2df30484ec9031939044cf4c2a004cbdb66108281d,PE32 executable (DLL) (GUI) Intel 80386 for MS Windows,599438,418304,4525141d9e6e7b5a7f4e8c3db3f0c24c,caf7624af4696ebede0878f506c8cc01,2011-08-29 13:02:29,0x4b0a1,.text|0,0,,5,.text,.rdata,.data,.ss,.reloc,,418304,129536,28160,512,20992,,6.7268471806075505,6.973714438652485,5.846983875501922,0.0,5.778329178154962,,2819,8247,39,2,832,0,343,0,6169,6.739117962056304,1.988984088127295,0.8199778151774786,17,19,1,3,1,69,69,17-81-25-55-42-29-10-18-40
15 | b2370013167bd617a1b76f75bae05c7715fed3a99fa9f0fce8728bce49f0fb79,PE32 executable (GUI) Intel 80386 for MS Windows,290816,233472,40e0f0681c79d70ac0329e68a94294cb,e5c91819994f87e4b5099e1d342bbec5,2010-03-09 13:16:25,0x20ec5,.text|0,0,,4,.text,.rdata,.data,.rsrc,,,233472,36864,12288,4096,,,6.636607210760108,4.698624497641232,4.861823606874447,0.0,,,1571,5266,5,2,740,1,393,0,3576,6.728858278508771,3.1695449561403506,1.6832853618421053,12,20,7,3,6,539,863,3-13-27-140-110-14-21-16-33
16 | be14d781b85125a6074724964622ab05f89f41e6bacbda398bc7709d1d98a2ef,PE32 executable (GUI) Intel 80386 for MS Windows,792064,583680,3bbb59afdf9bda4ffdc644d9d51c53e7,c0b4d1880addd1fcab5095057ac559e2,2011-10-25 19:28:39,0x572ae,.text|0,0,netmgr.exe,5,.text,.rdata,.data,.rsrc,.reloc,,583680,112128,68608,2560,24064,,6.34353480646419,6.1564028320667905,3.790503667137237,6.1419732599426435,6.099956952230222,,3685,14429,4,2,1156,70,1009,59,6676,6.313390899122807,1.9805372807017545,1.7286869517543861,25,39,8,2,4,734,1241,16-59-103-195-191-36-34-79-135
17 | bf206a0c9ec43d3839b56c12028c173e7a60dcb8156697808afff95057981d40,PE32 executable (GUI) Intel 80386 for MS Windows,438272,196608,330dc1a7f3930a2234e505ba11da0eea,d81fb1ad49ac1d15be483ab1934dd568,2010-04-30 09:05:36,0x1bca8,.text|0,0,,4,.text,.rdata,.data,.rsrc,,,196608,28672,12288,196608,,,6.65801829697673,4.849198870414372,4.120673090290144,7.968149642165874,,,1386,4385,5,2,528,1,317,0,6928,7.049560546875,2.685546875,1.6123453776041667,17,23,1,2,1,220,220,4-8-39-86-112-14-13-11-22
18 | c6a182f410b4cda0665cd792f00177c56338018fbc31bb34e41b72f8195c20cc,PE32 executable (GUI) Intel 80386 for MS Windows,966144,128512,c40e3ee23cf95d992b7cd0b7c01b8599,1619a99ed0881ebb9f760cfdef47c2b5,2011-10-25 19:28:00,0xf6f1,.text|0,0,,5,.text,.rdata,.data,.rsrc,.reloc,,128512,27648,6656,792576,9728,,6.682241535291592,4.848795535908612,4.089951691049512,6.417268481291405,5.033690056635027,,983,2611,4,1,299,0,140,0,9693,7.649091135458168,2.3266309760956174,1.0893924302788844,12,6,1,4,1,60,60,3-6-8-22-42-4-0-7-36
19 | c72a055b677cd9e5e2b2dcbba520425d023d906e6ee609b79c643d9034938ebf,PE32 executable (GUI) Intel 80386 for MS Windows,710075,79872,9fff114f15b86896d8d4978c0ad2813d,f445666591b9dc1e4fa252be6b3a3a67,2011-08-29 11:48:42,0x691a,.text|0,0,,4,.text,.rdata,.data,.rsrc,,,79872,24576,4608,512,,,6.587479863059564,6.8188321895961375,2.4062969218711365,0.0,,,624,1905,3,4,291,0,140,0,13344,7.8125,3.643329326923077,1.7528044871794872,15,12,0,0,0,0,0,3-66-3-14-24-19-0-4-2
20 | c9197a1fa5f911d11c51a66cfc1424063ed80547ca3f8637b77d06f36fc96e7d,PE32 executable (GUI) Intel 80386 for MS Windows,847872,583261,eb2f16a59b07d3a196654c6041d0066e,,2011-10-25 19:28:39,0x572ae,.text|0,0,netmgr.exe,6,.text,.rdata,.data,.rsrc,.reloc,.idata2,583261,111836,114508,2344,23922,512,6.345652697535456,6.185691439024143,2.5509116787765977,6.077540420727092,6.122214169286252,0.0,3685,14435,1014,2,0,0,1014,59,6684,6.317926280001577,0.0,1.7385012884454816,0,0,0,0,0,0,0,16-59-103-195-191-36-39-79-135
21 | daa56e7acd5fb69ecefdbf5179c5ef4776ccc41ebe7e14920f11b84678c83a00,PE32 executable (GUI) Intel 80386 for MS Windows,182784,137728,cc87d090a1607b4dde18730b79b78632,2db5d5a2d4e4ea9c09b7d86e99210bdb,2010-06-18 14:18:18,0x16760,.text|0,0,"svchost.exe",6,.text,.rdata,.data,.rsrc,.reloc,.idata,137728,24576,8192,1024,9216,1024,6.606206549010942,5.849986210924849,1.994312850360272,3.3697542961313447,5.044197946641016,4.952636846291531,803,3665,5,2,417,0,214,0,1818,5.830332249070632,3.027706784386617,1.5537871747211895,10,6,1,3,1,147,147,5-12-9-45-82-21-13-12-7
22 | dump21cb.dll,PE32 executable (DLL) (GUI) Intel 80386 for MS Windows,599504,418304,4582d9d2120fb9c80ef01e2135fa3515,caf7624af4696ebede0878f506c8cc01,2011-07-06 14:59:52,0x4b061,.text|0,0,,5,.text,.rdata,.data,.ss,.reloc,,418304,129536,28160,512,20992,,6.725987232625879,6.9697101712884715,5.843836429683213,0.0,5.783160881659421,,2817,8255,39,2,832,0,343,0,6167,6.734336750305998,1.988984088127295,0.8199778151774786,17,19,1,3,1,69,69,17-82-25-55-42-29-10-18-40
23 | f580ccf887f64544095e85256a860af8294fb8ca2785a90c61ba1494e6c61191,PE32 executable (GUI) Intel 80386 for MS Windows,299008,229955,a7a22d250314d8319627c746664045b3,,2010-03-09 13:16:25,0x20ec5,.text|0,0,,5,.text,.rdata,.data,.rsrc,.idata2,,229955,33566,19624,16,512,,6.690082490342923,5.0803068782686776,3.611426902302909,0.0,0.0,,1571,5266,598,2,0,0,394,0,3587,6.831771433541345,0.0,1.7133787045291469,0,0,0,0,0,0,0,3-13-27-140-110-14-22-16-33
24 | ntrass.exe_,PE32 executable (GUI) Intel 80386 for MS Windows,172032,118784,4040b9a7fd9f247685d51a3a45f31a7e,3221fdab2986a1d1789ee0c434cf0040,2010-06-21 09:31:38,0xf8a6,.text|0,0,,5,.text,.rdata,.data,.rsrc,.reloc,,118784,24576,8192,4096,12288,,6.591519311867101,6.558351110322685,4.487952235047445,3.0566776817036985,4.161778581699636,,715,2884,5,5,585,1,232,0,2287,6.019329202586206,4.924905711206896,1.953125,11,20,3,2,2,277,344,3-14-22-94-60-7-7-9-9
25 | wsock32.dll,PE32 executable (DLL) (GUI) Intel 80386 for MS Windows,471552,37376,8e3a0306c31db2cdd66e1613dae59d57,fc2bf1ae3d138694ca6fcdf7b68f1755,2010-09-02 09:30:33,0x1e35,.text|0,0,,5,.text,.rdata,.data,.rsrc,.reloc,,37376,12800,413696,512,6144,,6.525944321150616,4.714443464868741,3.415468652146986,5.119673628583671,3.4906569050309284,,331,937,3,1,206,0,42,0,2511,8.855950342465754,5.511558219178083,1.1237157534246576,10,7,0,0,0,0,0,2-2-9-7-14-1-0-3-2
26 |
--------------------------------------------------------------------------------
/output/ConsoleApplication1.exe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/ConsoleApplication1.exe.png
--------------------------------------------------------------------------------
/output/ConsoleApplication1Virtual.exe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/ConsoleApplication1Virtual.exe.png
--------------------------------------------------------------------------------
/output/ConsoleApplication1_fullOpt.exe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/ConsoleApplication1_fullOpt.exe.png
--------------------------------------------------------------------------------
/output/ConsoleApplication1_optSize.exe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/ConsoleApplication1_optSize.exe.png
--------------------------------------------------------------------------------
/output/ConsoleApplication1vc110_mb.exe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/ConsoleApplication1vc110_mb.exe.png
--------------------------------------------------------------------------------
/output/ConsoleApplication1vc120.exe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/ConsoleApplication1vc120.exe.png
--------------------------------------------------------------------------------
/output/ConsoleApplication1vc150dbg.exe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/ConsoleApplication1vc150dbg.exe.png
--------------------------------------------------------------------------------
/output/HIDRV.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/HIDRV.png
--------------------------------------------------------------------------------
/output/Packrat.csv:
--------------------------------------------------------------------------------
1 | filename,filetype,filesize,codesecsize,md5,imphash,compilationtime,addressep,sectionep,tlssections,originalfilename,sectioncount,secname1,secname2,secname3,secname4,secname5,secname6,secsize1,secsize2,secsize3,secsize4,secsize5,secsize6,secent1,secent2,secent3,secent4,secent5,secent6,functionstotal,refslocal,refsglobalvar,refsunknown,apitotal,apimisses,stringsreferenced,stringsdangling,stringsnoref,ratiofunc,ratioapi,ratiostring,getprocaddress,memallocation,createthread,ctshortestpath,callbackcount,cbaveragesize,cblargestsize,stringsrefhisto
2 | 038ee601e4d9702cf23133b7bf694beb5d28afb999739c354c4d6e0f7c269f22,PE32 executable (GUI) Intel 80386 for MS Windows,1562601,524800,1e6d0b59d4fb7650453c207688385f3a,aaaa8913c89c8aa4a5d93f06853894da,2010-04-16 07:47:33,0x16310,.text|0,0,,4,.text,.rdata,.data,.rsrc,,,524800,55808,26624,96768,,,6.634724770481731,4.880067258044234,2.201764989626115,4.794571332238528,,,2675,13282,22,4,2443,20,562,0,18069,5.097179878048781,4.655106707317073,1.0708841463414636,29,31,4,4,4,84,131,5-22-65-179-152-44-3-13-35
3 | 0ff72ba33898c07eb26ffea210fab9fbe199aa54f55b2be68b9dea94273e624a,PE32 executable (GUI) Intel 80386 for MS Windows UPX compressed,892350,270848,779a79c11f581b84e7c81f321fd8d743,890e522b31701e079a367b89393329e6,2012-01-29 21:32:28,0xb7e70,UPX1|1,0,,3,UPX0,UPX1,.rsrc,,,,0,270848,27136,,,,0.0,7.929033954133817,5.402807530618025,,,,2,0,0,0,0,0,0,0,18707,0.007384215500945179,0.0,0.0,0,0,0,0,0,0,0,0-0-0-0-0-0-0-0-0
4 | 1f76c2957c2c39ec83a817479dda38c5047d153dbe466c2aabff7b4354e0647f,PE32 executable (GUI) Intel 80386 for MS Windows,1157417,526336,6c34d4296126679d9c6a0bc2660dc453,d3bf8a7746a8d1ee8f6e5960c3f69378,2012-01-29 21:32:28,0x165c1,.text|0,0,,4,.text,.rdata,.data,.rsrc,,,526336,57344,26624,35328,,,6.684690148171277,4.799741132252141,2.150071539167753,5.630671057543231,,,2613,12988,37,1,2540,36,536,12,17475,4.964509362840467,4.825814688715953,1.0183608949416343,25,33,4,4,4,71,101,7-16-63-176-138-40-4-12-35
5 | 3c22bcf90b1f94691f9982de6d603f27517799684cbc77e0e1b08e327a0e4c00,PE32 executable (GUI) Intel 80386 for MS Windows,75776,23552,2827450763b55c5e71fda3caaf8e75f9,394b3e18e03537a1c51f949fab757567,2013-05-07 13:22:08,0x17e00,.rsrc|1,0,Dropbox.exe,3,pec1,.rsrc,.rsrc,,,,23552,25600,25600,,,,7.893564360023055,5.537302700294467,7.38508764470497,,,,0,0,0,0,0,0,0,0,1238,0.0,0.0,0.0,0,0,0,0,0,0,0,0-0-0-0-0-0-0-0-0
6 | 56ea4781ccefb7596e77fcb7a57fb703007f2fb9b94fe33a3cc5257ab7996d1c,PE32 executable (GUI) Intel 80386 for MS Windows,307200,12288,dd1101adc86fd282f5f183942cc2f3b7,afa6774859bc8161a025b0577286ce3e,2012-08-26 05:50:37,0x10ec,.text|0,0,Stub.exe,3,.text,.data,.rsrc,,,,12288,0,290816,,,,4.869821891477226,0.0,7.951756184515005,,,,9,2,0,0,23,13,1,0,5854,0.732421875,1.8717447916666665,0.08138020833333333,0,0,0,0,0,0,0,0-1-0-0-0-0-0-0-0
7 | 647dc0a8981f507602d2b8963420892e253742c5f93536e5a857ac585a9544a6,PE32 executable (GUI) Intel 80386 for MS Windows,1352589,524800,a74ef893b1bf21c9df6d8e31285db981,aaaa8913c89c8aa4a5d93f06853894da,2010-04-16 07:47:33,0x16310,.text|0,0,,4,.text,.rdata,.data,.rsrc,,,524800,55808,26624,97280,,,6.634724770481731,4.880067258044234,2.201764989626115,6.3652812675883474,,,2675,13282,22,4,2443,20,562,0,31476,5.097179878048781,4.655106707317073,1.0708841463414636,29,31,4,4,4,84,131,5-22-65-179-152-44-3-13-35
8 | 6a0d1ea10ad7821a2b07ab5b1aa71365a1d3af06788154025eb30314823b9670,PE32 executable (GUI) Intel 80386 for MS Windows,1092866,524800,a988235ad7d47acbeca5ccb4ea5a1ed5,aaaa8913c89c8aa4a5d93f06853894da,2010-04-16 07:47:33,0x16310,.text|0,0,,4,.text,.rdata,.data,.rsrc,,,524800,55808,26624,28672,,,6.634724770481731,4.880067258044234,2.201764989626115,5.286292699816573,,,2675,13282,22,4,2443,20,562,0,18652,5.097179878048781,4.655106707317073,1.0708841463414636,29,31,4,4,4,84,131,5-22-65-179-152-44-3-13-35
9 | 6eeb5bcfc5d28ccad251035b11b08d553f7d10e22574209524b71a0dff1dcd3f,PE32 executable (GUI) Intel 80386 for MS Windows,75776,23552,c2237e9d415f542ce6e73adb260af123,394b3e18e03537a1c51f949fab757567,2013-05-07 13:22:08,0x17e00,.rsrc|1,0,Dropbox.exe,3,pec1,.rsrc,.rsrc,,,,23552,25600,25600,,,,7.893564360023055,5.537302700294467,7.3872149234740645,,,,0,0,0,0,0,0,0,0,1234,0.0,0.0,0.0,0,0,0,0,0,0,0,0-0-0-0-0-0-0-0-0
10 | 74e21a71ded8ce81aafc380e439c0851a1df9001f4c342a7c11bd71c3c9c3a80,PE32 executable (GUI) Intel 80386 for MS Windows,1494961,526336,e03be1849ad7cecba1e20923074cd22f,d3bf8a7746a8d1ee8f6e5960c3f69378,2012-01-29 21:32:28,0x165c1,.text|0,0,,4,.text,.rdata,.data,.rsrc,,,526336,57344,26624,28672,,,6.684690148171277,4.799741132252141,2.150071539167753,5.223011124474851,,,2613,12988,37,1,2540,36,536,12,40555,4.964509362840467,4.825814688715953,1.0183608949416343,25,33,4,4,4,71,101,7-16-63-176-138-40-4-12-35
11 | 7525af4888f939e7a1df51bb8737a887af0b705d72e89a0b573f35ea57ace888,PE32 executable (GUI) Intel 80386 Mono/.Net assembly for MS Windows,598062,208896,5a8975873f52436377d8fb0b5ab0d87a,a7f367ba8a92c23dbdc563065bea5060,2012-10-22 21:25:00,0x1100,.jkjfgbj|0,0,°§ã±¬òäöýÝÅ£°ð廙äƒÎ¾¦ð‰ë¬åïÍ.exe,3,.jkjfgbj,.ljkndj,.klmnfjh,,,,208896,0,102400,,,,5.166262146483606,0.0,6.766430933743999,,,,25,1,0,0,23,0,1,0,7642,0.11967677696078433,0.11010263480392157,0.004787071078431373,0,0,0,0,0,0,0,0-1-0-0-0-0-0-0-0
12 | 7a763ecc8ab23c3ade2455c2e91b506be910bed686fc3d32acb9574d7d5abf27,PE32 executable (GUI) Intel 80386 for MS Windows,105984,41984,d7f34168b1a7dd7cbd8e62a5ab1ebc0e,394b3e18e03537a1c51f949fab757567,2014-06-07 12:05:20,0x3ae00,.rsrc|1,0,š×Ÿ¦.exe,3,pec1,.rsrc,.rsrc,,,,41984,25600,37376,,,,7.916291344084975,5.850645501202936,7.67640648101998,,,,0,0,0,0,0,0,0,0,1875,0.0,0.0,0.0,0,0,0,0,0,0,0,0-0-0-0-0-0-0-0-0
13 | a8379b51bbc6b2bb37ca4d15afb59dd645cb565ee3f0460ff0bd257352d85c6c,PE32 executable (GUI) Intel 80386 for MS Windows UPX compressed,704456,270848,13d939b2412c6adbab3cc1b539166671,890e522b31701e079a367b89393329e6,2012-01-29 21:32:28,0xb6e70,UPX1|1,0,,3,UPX0,UPX1,.rsrc,,,,0,270848,21504,,,,0.0,7.929074048843723,5.2994430216788055,,,,6,0,0,0,0,0,0,0,14900,0.02215264650283554,0.0,0.0,0,0,0,0,0,0,0,0-0-0-0-0-0-0-0-0
14 | ab40d67f4ed686f8f7cf686fc9c8a6f9f8f2b6fd80e0bf8e129875e2e428f24e,PE32 executable (GUI) Intel 80386 for MS Windows Petite compressed,992486,156672,2d722592a4e3c8030410dccccb221ce4,1f6d4944c0a3d88fe2382097dbb39b31,2012-08-20 18:37:52,0x2c046,,0,Proyecto1.exe,4,.petite,,.rsrc,,,,2425393152,0,2252,1024,,,5.455354649662423,0.0,3.0304381958718034,4.645673551248216,,,12,8,0,0,0,0,0,0,8022,0.07659313725490197,0.0,0.0,0,0,0,0,0,0,0,0-0-0-0-0-0-0-0-0
15 | c10f703839ec0a82a248883b1b8885747b5fb145d0aeb0bad71e06980425a4fa,PE32 executable (GUI) Intel 80386 for MS Windows,315427,24576,93b630891db21a4a2350280a360c713d,2ecbded1987b7ffdd7cf0e5e85d399dd,2012-09-21 19:59:43,0x10b0,.text|0,0,Stub.exe,3,.text,.data,.rsrc,,,,24576,0,4096,,,,4.996390595111941,0.0,1.8562034913770455,,,,20,1,0,0,16,0,1,0,4561,0.8138020833333334,0.6510416666666666,0.040690104166666664,0,0,0,0,0,0,0,0-1-0-0-0-0-0-0-0
16 | cfb7d7c6a5dbda5737e492bb2bacfecd975a4c0977050184a948dd5c25ab8b7d,PE32 executable (GUI) Intel 80386 for MS Windows,1157435,526336,bc97437fec7e7e8634c2eabae3cc4832,d3bf8a7746a8d1ee8f6e5960c3f69378,2012-01-29 21:32:28,0x165c1,.text|0,0,Dropbox.exe,4,.text,.rdata,.data,.rsrc,,,526336,57344,26624,35328,,,6.684690148171277,4.799741132252141,2.150071539167753,5.542513922602705,,,2613,12988,37,1,2540,36,536,12,17207,4.964509362840467,4.825814688715953,1.0183608949416343,25,33,4,4,4,71,101,7-16-63-176-138-40-4-12-35
17 | db6883b0dd7c5d3a23fb9609b087e8494cb08ca9d478878e07d868bf68e52267,PE32 executable (GUI) Intel 80386 for MS Windows,375392,32768,ed8d7ed45b64890b8901b735018318f3,6128d5560c00a7a89ac8a995f4877e9a,2012-10-30 20:29:27,0x10e0,.text|0,0,STB.exe,3,.text,.data,.rsrc,,,,32768,0,4096,,,,6.398706793436938,0.0,2.235185364607506,,,,18,2,0,0,20,3,1,0,5569,0.54931640625,0.6103515625,0.030517578125,0,0,0,0,0,0,0,0-1-0-0-0-0-0-0-0
18 | dcea2e230e0d0c483e0b816f4a8b58d9c0f0eab18a2d4db03a04fa257dcce4d9,PE32 executable (GUI) Intel 80386 for MS Windows,1064354,526336,15ebe16cd9500de534d5bfd5eeceaf73,d3bf8a7746a8d1ee8f6e5960c3f69378,2011-12-23 10:59:31,0x165c1,.text|0,0,,4,.text,.rdata,.data,.rsrc,,,526336,57344,26624,28672,,,6.684966596832797,4.799718777418673,2.150071539167753,5.261547292967067,,,2618,12995,37,1,2540,35,536,12,15504,4.974008998054474,4.825814688715953,1.0183608949416343,25,33,4,4,4,71,101,7-16-63-176-138-40-4-12-35
19 | e125218316467d4749e957b87201f8fd4c4ba14857588d2aca57d94294137a00,PE32 executable (GUI) Intel 80386 for MS Windows UPX compressed,282624,278016,a73351623577f44a2b578fed1e78e37e,cba5bd52b3e624400ffe41eb22644b79,1992-06-19 22:22:17,0x55bf0,UPX1|1,0,,3,UPX0,UPX1,.rsrc,,,,0,278016,3584,,,,0.0,7.7540879892552965,5.571304966611435,,,,32,1,0,0,0,0,0,0,4240,0.1151012891344383,0.0,0.0,0,0,0,0,0,0,0,0-0-0-0-0-0-0-0-0
20 | e17bdf72b3c6c53a3ee77e3edc0b9cf7a2eb194210e071f4eb80aa1d6ee3cb2d,PE32 executable (GUI) Intel 80386 for MS Windows,487501,180224,d2adecc6287dd4d559fe6ce2ce7a7e31,1bab4908de92fac1c6ff4d553b1fd920,2012-06-25 20:21:50,0x1678,.text|0,0,sdhartiuj5ri45qwhfdberaured.exe,3,.text,.data,.rsrc,,,,180224,4096,16384,,,,7.220307676148524,0.0,7.3868568244364585,,,,223,339,0,2,114,0,21,1,9939,1.2373490767045456,0.6325461647727273,0.11652166193181819,0,0,0,0,0,0,0,1-8-1-3-3-2-0-2-1
21 | e57653ec973719780bdd85c6fa09d25d61848c421c3819de02f3ea24a1235456,PE32 executable (GUI) Intel 80386 for MS Windows,1127716,524800,8e0f021dcbbfa586a1c6780e77ac0fb6,aaaa8913c89c8aa4a5d93f06853894da,2010-04-16 07:47:33,0x16310,.text|0,0,,4,.text,.rdata,.data,.rsrc,,,524800,55808,26624,29184,,,6.634724770481731,4.880067258044234,2.201764989626115,5.363998884921135,,,2675,13282,22,4,2443,20,562,0,19025,5.097179878048781,4.655106707317073,1.0708841463414636,29,31,4,4,4,84,131,5-22-65-179-152-44-3-13-35
22 | f8ff6706daafd040978f77ced7b5965aaa8304cd5297197f790c3532462667de,PE32 executable (GUI) Intel 80386 for MS Windows,1238252,507392,01dec1b1d0760d5a1a562edcfeb478d1,7aacc6b600bd900374e9529a20c9b64c,2008-12-24 09:00:07,0x17770,.text|0,0,,4,.text,.rdata,.data,.rsrc,,,507392,54784,11776,282624,,,6.620303987624808,4.9179360029243835,3.6952785183023527,5.645015931487277,,,2347,11991,23,4,2432,165,662,24,16962,4.6256149091826435,4.79313824419778,1.3047111503531785,28,25,4,4,4,84,131,6-29-78-204-180-47-4-28-37
23 |
--------------------------------------------------------------------------------
/output/avdetect_3798f745fb9dbad6a20e794f5ed9d45f9b60b198567f41e5b794c19e78c9599e.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/avdetect_3798f745fb9dbad6a20e794f5ed9d45f9b60b198567f41e5b794c19e78c9599e.png
--------------------------------------------------------------------------------
/output/banito_cpp.bin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/banito_cpp.bin.png
--------------------------------------------------------------------------------
/output/banito_cpp.txt:
--------------------------------------------------------------------------------
1 | * 2016-10-18 19:13:43.319959 R2 started analysis
2 | * 2016-10-18 19:14:04.466698 R2 finished analysis
3 | DANGLING call to address outside code section, glob var, dynamic API loading 0x42e960 -> 0x437718
4 | * 2016-10-18 19:14:05.059362 Graph created with NetworkX
5 | * 2016-10-18 19:14:10.907997 Graph extended with API calls, 34 calls in total, 0 dangling w/o function reference
6 | * 2016-10-18 19:14:11.754323 Graph extended with string references
7 | .
8 | General graph info:
9 | SAMPLE banito.bin
10 | Type: PE32 executable (GUI) Intel 80386, for MS Windows
11 | Size: 275883
12 | MD5: 172aed81c4fde1cf23f1615acedfad65
13 | Name:
14 | Type: DiGraph
15 | Number of nodes: 1374
16 | Number of edges: 1415
17 | Average in degree: 1.0298
18 | Average out degree: 1.0298
19 | .
20 | Graph measurement data:
21 | 1386 Total functions detected with 'aflj'
22 | 2826 Count of references to local functions
23 | 1 Count of references to data section, global variables
24 | 0 Count of references to unrecognized locations
25 | 34 Total API refs found via symbol xref check
26 | 0 Count APIs w/o function xref
27 | 53 Total referenced Strings
28 | 0 Count of dangling strings (w/o function reference)
29 | 2922 Count of strings w/o any reference
30 | .
31 | Fat node detection with out-degree centrality, count calls, count strings:
32 | 0x421bd9 0.032775 25 1
33 | 0x42605f 0.016752 16 0
34 | 0x401040 0.015295 11 1
35 | 0x427fb3 0.012382 2 1
36 | 0x4228c6 0.012382 2 0
37 | 0x4270fe 0.010197 2 1
38 | 0x428834 0.009468 3 1
39 | 0x410a40 0.009468 0 0
40 | 0x424f6d 0.008740 3 0
41 | 0x427816 0.008740 1 0
42 | 0x42ae52 0.008740 19 0
43 | 0x4255a5 0.008740 3 0
44 | 0x427bb8 0.008012 3 2
45 | 0x426ada 0.008012 2 0
46 | 0x426dea 0.008012 2 1
47 | 0x4259f6 0.008012 2 1
48 | 0x42d1f0 0.008012 1 0
49 | 0x428a91 0.008012 3 0
50 | 0x42d569 0.008012 2 0
51 | 0x42dacb 0.007283 4 0
52 | .
53 | Histogram of out degree centrality:
54 | 0.0 0.0005 0.001 0.0015 0.002 0.004 0.006 0.008 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1 0.2 0.3 0.4 0.5
55 | 751 439 52 0 78 17 18 13 5 0 1 0 0 0 0 0 0 0 0 0 0
56 | .
57 | Loose nodes 721 of total 1374, thats 52.474527%
58 | .
59 | ExecSize FunctionCount ApiCount StringCount
60 | 221184 1386 34 53
61 | Per-Kilobyte ratio
62 | 6.26627604167 0.153718171296 0.239619502315
63 | .
64 | Average degree connectivity per degree k:
65 | 0 0.000000
66 | 1 11.483491
67 | 2 10.856502
68 | 3 10.114379
69 | 4 9.581633
70 | 5 13.538095
71 | 6 15.541667
72 | 7 12.670330
73 | 8 18.000000
74 | 9 1.629630
75 | 10 17.106667
76 | 11 14.393939
77 | 12 9.154762
78 | 13 6.200000
79 | 14 5.785714
80 | 15 2.733333
81 | 17 12.764706
82 | 22 2.454545
83 | 23 5.152174
84 | 25 0.120000
85 | 27 0.148148
86 | 39 0.076923
87 | 45 6.266667
88 | 53 0.000000
89 | 65 0.015385
90 | 116 0.000000
91 | .
92 | Found 1 calls to GetProcAddress
93 | .
94 | * 2016-10-18 19:14:13.391371 Plotting routine starting
95 | dot: graph is too large for cairo-renderer bitmaps. Scaling by 0.181638 to fit
96 |
97 | * 2016-10-18 19:14:21.854261 Plotting routine finished
98 | * 2016-10-18 19:14:51.634648 Dumped to Neo4J
99 | * 2016-10-18 19:14:51.634672 Scanning for API patterns
100 | For APILOADING found {'GetProcAddress': '0x402db0', 'LoadLibrary': '0x402db0'}
101 | * 2016-10-18 19:14:51.654236 Scan finished
102 |
--------------------------------------------------------------------------------
/output/benign_0b0b3ec1d33d272104a4c37b5e5693b9544f737863a736386abcc89a32f8a222.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/benign_0b0b3ec1d33d272104a4c37b5e5693b9544f737863a736386abcc89a32f8a222.png
--------------------------------------------------------------------------------
/output/benign_0b67b7d86ad47d4537c6612a39863ff732fa0b0f005fcd209cb46bf90338b2b9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/benign_0b67b7d86ad47d4537c6612a39863ff732fa0b0f005fcd209cb46bf90338b2b9.png
--------------------------------------------------------------------------------
/output/benign_0bfbda37af78a9d0318b0d0e3024d831c271e6d42f0da41372c8785425a864aa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/benign_0bfbda37af78a9d0318b0d0e3024d831c271e6d42f0da41372c8785425a864aa.png
--------------------------------------------------------------------------------
/output/c3f8690087a454fa45e8975fd0b8b0b76aba554f540d7c2c98d3e15512268b52.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/c3f8690087a454fa45e8975fd0b8b0b76aba554f540d7c2c98d3e15512268b52.png
--------------------------------------------------------------------------------
/output/c3f8690087a454fa45e8975fd0b8b0b76aba554f540d7c2c98d3e15512268b52.txt:
--------------------------------------------------------------------------------
1 | * 2016-10-21 21:37:48.951404 R2 started analysis
2 | * 2016-10-21 21:37:49.656135 R2 finished analysis
3 | DANGLING call to address outside code section, glob var, dynamic API loading 0x10004550 -> 0x1000b200
4 | * 2016-10-21 21:37:50.955467 Graph created with NetworkX
5 | * 2016-10-21 21:37:52.777888 Graph extended with API calls, 238 calls in total, 0 dangling w/o function reference
6 | * 2016-10-21 21:37:53.169808 Graph extended with string references
7 | * 2016-10-21 21:37:53.229584 Printing the graph - nodes and node attributes
8 | .
9 | General graph info:
10 | SAMPLE c3f8690087a454fa45e8975fd0b8b0b76aba554f540d7c2c98d3e15512268b52
11 | Type: PE32 executable (DLL) (GUI) Intel 80386, for MS Windows
12 | Size: 71168
13 | MD5: a372c78309a2a521ac4d6899d0ef2369
14 | Name:
15 | Type: DiGraph
16 | Number of nodes: 134
17 | Number of edges: 170
18 | Average in degree: 1.2687
19 | Average out degree: 1.2687
20 | .
21 | Graph measurement data:
22 | 157 Total functions detected with 'aflj'
23 | 344 Count of references to local functions
24 | 1 Count of references to data section, global variables
25 | 0 Count of references to unrecognized locations
26 | 238 Total API refs found via symbol xref check
27 | 0 Count APIs w/o function xref
28 | 180 Total referenced Strings
29 | 0 Count of dangling strings (w/o function reference)
30 | 438 Count of strings w/o any reference
31 | .
32 | Fat node detection with out-degree centrality, count calls, count strings:
33 | 0x10003080 0.172932 23 29
34 | 0x100023a0 0.142857 13 14
35 | 0x10002210 0.075188 4 4
36 | 0x10007dd0 0.060150 0 0
37 | 0x10005ea0 0.045113 0 21
38 | 0x10004550 0.045113 0 1
39 | 0x100058d0 0.037594 0 4
40 | 0x10005320 0.037594 0 2
41 | 0x10001410 0.037594 3 3
42 | 0x10002060 0.030075 6 6
43 | 0x10002710 0.030075 1 1
44 | 0x10002b30 0.030075 1 1
45 | 0x100044c0 0.030075 0 0
46 | 0x100040e0 0.022556 0 1
47 | 0x10001200 0.022556 3 1
48 | 0x10003750 0.022556 5 3
49 | 0x10005020 0.022556 0 0
50 | 0x100041b0 0.022556 0 1
51 | 0x10003890 0.022556 1 2
52 | 0x10007fe0 0.022556 0 0
53 | .
54 | Histogram of out degree centrality:
55 | 0.0 0.0005 0.001 0.0015 0.002 0.004 0.006 0.008 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1 0.2 0.3 0.4 0.5
56 | 79 0 0 0 0 0 25 0 9 8 7 2 0 1 1 0 0 2 0 0 0
57 | .
58 | Loose nodes 24 of total 134, thats 17.910448%
59 | .
60 | ExecSize FunctionCount ApiCount StringCount
61 | 37888 157 238 180
62 | Per-Kilobyte ratio
63 | 4.14379222973 6.2816722973 4.75084459459
64 | .
65 | Average degree connectivity per degree k:
66 | 0 0.000000
67 | 1 0.358491
68 | 2 1.153846
69 | 3 2.416667
70 | 4 0.863636
71 | 5 2.777778
72 | 6 0.833333
73 | 7 2.285714
74 | 8 1.375000
75 | 10 0.900000
76 | 11 3.000000
77 | 20 3.250000
78 | 24 3.958333
79 | .
80 | Found 4 calls to GetProcAddress
81 | .
82 | * 2016-10-21 21:37:59.756642 Dumped to Neo4J
83 | * 2016-10-21 21:37:59.756664 Scanning for API patterns
84 | For RECV found {'recv': '0x10003a40', 'send': '0x10003a40'}
85 | For FPRINT found {'fclose': '0x10004060', 'fopen': '0x10004060', 'fprintf': '0x10004060'}
86 | For CREATETHREAD found {'CreateThread': '0x10002010'}
87 | For CREATETHREAD found {'CreateThread': '0x10003080'}
88 | For CREATETHREAD found {'CreateThread': '0x10001bb0'}
89 | For CREATETHREAD found {'CreateThread': '0x100034f0'}
90 | For CREATETHREAD found {'CreateThread': '0x10002030'}
91 | For CREATEPROC found {'CreateProcess': '0x10001cd0'}
92 | For READFILE found {'CreateFile': '0x10003dc0', 'ReadFile': '0x10003dc0'}
93 | For READFILE found {'CreateFile': '0x10002ce0', 'ReadFile': '0x10002ce0'}
94 | For EXITSYSTEM found {'ExitWindows': '0x10002a20'}
95 | For EXITSYSTEM found {'ExitWindows': '0x10002aa0'}
96 | For REGQUERY found {'RegQueryValue': '0x10001790', 'RegOpenKey': '0x10001790'}
97 | For SHELLEXEC found {'ShellExecute': '0x10002960'}
98 | For SHELLEXEC found {'ShellExecute': '0x10002930'}
99 | For APILOADING found {'GetProcAddress': '0x10003f40', 'LoadLibrary': '0x10003f40'}
100 | For APILOADING found {'GetProcAddress': '0x10002e40', 'LoadLibrary': '0x10002e40'}
101 | For APILOADING found {'GetProcAddress': '0x10001cd0', 'LoadLibrary': '0x10001cd0'}
102 | For APILOADING found {'GetProcAddress': '0x10001be0', 'LoadLibrary': '0x10001be0'}
103 | For FILEITER found {'FindNextFile': '0x100027b0', 'FindClose': '0x100027b0', 'FindFirstFile': '0x100027b0'}
104 | For FILEITER found {'FindNextFile': '0x10001290', 'FindClose': '0x10001290', 'FindFirstFile': '0x10001290'}
105 | For WRITEFILE found {'WriteFile': '0x10002f90', 'CreateFile': '0x10002f90'}
106 | For WRITEFILE found {'WriteFile': '0x10002db0', 'CreateFile': '0x10002db0'}
107 | * 2016-10-21 21:37:59.760701 Scan finished
108 |
--------------------------------------------------------------------------------
/output/coolstuff_5fd8c932fc92abe417acf6990165ff520df1c5911da7b77b31e67861ad06078a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/coolstuff_5fd8c932fc92abe417acf6990165ff520df1c5911da7b77b31e67861ad06078a.png
--------------------------------------------------------------------------------
/output/gephi/allocgraph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/allocgraph.png
--------------------------------------------------------------------------------
/output/gephi/animalfarm1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/animalfarm1.png
--------------------------------------------------------------------------------
/output/gephi/animalfarm2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/animalfarm2.png
--------------------------------------------------------------------------------
/output/gephi/apifeatures.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/apifeatures.png
--------------------------------------------------------------------------------
/output/gephi/apilesssubgraph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/apilesssubgraph.png
--------------------------------------------------------------------------------
/output/gephi/apiloading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/apiloading.png
--------------------------------------------------------------------------------
/output/gephi/apiloading2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/apiloading2.png
--------------------------------------------------------------------------------
/output/gephi/babar_mnem_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/babar_mnem_black.png
--------------------------------------------------------------------------------
/output/gephi/forceatlas.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/forceatlas.png
--------------------------------------------------------------------------------
/output/gephi/forceatlas2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/forceatlas2.png
--------------------------------------------------------------------------------
/output/gephi/funcsize_vs_outdegree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/funcsize_vs_outdegree.png
--------------------------------------------------------------------------------
/output/gephi/graphviz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/graphviz.png
--------------------------------------------------------------------------------
/output/gephi/graphviz2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/graphviz2.png
--------------------------------------------------------------------------------
/output/gephi/rbot_behavior.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/rbot_behavior.png
--------------------------------------------------------------------------------
/output/gephi/rbot_behavior_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/rbot_behavior_close.png
--------------------------------------------------------------------------------
/output/gephi/sopretty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/sopretty.png
--------------------------------------------------------------------------------
/output/gephi/subgraph1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/subgraph1.png
--------------------------------------------------------------------------------
/output/gephi/subgraph2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/subgraph2.png
--------------------------------------------------------------------------------
/output/gephi/viz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/gephi/viz.png
--------------------------------------------------------------------------------
/output/packed_59128307.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/packed_59128307.png
--------------------------------------------------------------------------------
/output/randomdropper.txt:
--------------------------------------------------------------------------------
1 | * 2016-10-22 13:57:58.981259 R2 started analysis
2 | * 2016-10-22 13:57:59.255685 R2 finished analysis
3 | DANGLING call to address outside code section, glob var, dynamic API loading 0x401d1e -> 0x40d110
4 | DANGLING call to address outside code section, glob var, dynamic API loading 0x401d1e -> 0x40d110
5 | DANGLING call to address outside code section, glob var, dynamic API loading 0x401d29 -> 0x40d110
6 | DANGLING call to address outside code section, glob var, dynamic API loading 0x401d29 -> 0x40d110
7 | DANGLING call to address outside code section, glob var, dynamic API loading 0x4053a5 -> 0x40f920
8 | DANGLING call to address outside code section, glob var, dynamic API loading 0x4053a5 -> 0x40f920
9 | * 2016-10-22 13:58:00.139132 Graph created with NetworkX
10 | * 2016-10-22 13:58:01.368531 Graph extended with API calls, 179 calls in total, 0 dangling w/o function reference
11 | * 2016-10-22 13:58:01.540143 Graph extended with string references
12 | * 2016-10-22 13:58:01.541155 Printing the graph - nodes and node attributes
13 | .
14 | General graph info:
15 | SAMPLE 79a26b420ec901423b46ac5e5399ad00c4923a68c9f06233c6214ca3aba6b1a9
16 | Type: PE32 executable (GUI) Intel 80386, for MS Windows
17 | Size: 65536
18 | MD5: 46d030b4253fa7911c3748f04420d1c4
19 | Name:
20 | Type: DiGraph
21 | Number of nodes: 115
22 | Number of edges: 167
23 | Average in degree: 1.4522
24 | Average out degree: 1.4522
25 | .
26 | Graph measurement data:
27 | 116 Total functions detected with 'aflj'
28 | 265 Count of references to local functions
29 | 6 Count of references to data section, global variables
30 | 0 Count of references to unrecognized locations
31 | 179 Total API refs found via symbol xref check
32 | 0 Count APIs w/o function xref
33 | 57 Total referenced Strings
34 | 0 Count of dangling strings (w/o function reference)
35 | 570 Count of strings w/o any reference
36 | .
37 | Fat node detection with out-degree centrality, count calls, count strings:
38 | 0x40613f 0.105263 5 0
39 | 0x401c33 0.096491 4 1
40 | 0x405ef9 0.078947 1 1
41 | 0x403e69 0.070175 3 9
42 | 0x401618 0.061404 30 3
43 | 0x401e61 0.052632 3 4
44 | 0x403513 0.052632 0 0
45 | 0x403d01 0.043860 3 3
46 | 0x401b18 0.035088 1 0
47 | 0x4035cc 0.035088 1 0
48 | 0x4011e4 0.035088 9 2
49 | 0x404b17 0.035088 1 2
50 | 0x403bf0 0.026316 0 2
51 | 0x405644 0.026316 0 1
52 | 0x403819 0.026316 8 2
53 | 0x4060d8 0.026316 0 0
54 | 0x401d1e 0.026316 0 0
55 | 0x406452 0.026316 0 0
56 | 0x402e45 0.026316 1 0
57 | 0x401fa9 0.026316 2 0
58 | .
59 | Histogram of out degree centrality:
60 | 0.0 0.0005 0.001 0.0015 0.002 0.004 0.006 0.008 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1 0.2 0.3 0.4 0.5
61 | 51 0 0 0 0 0 0 27 15 10 4 1 2 1 2 0 1 1 0 0 0
62 | .
63 | Loose nodes 14 of total 115, thats 12.173913%
64 | .
65 | ExecSize FunctionCount ApiCount StringCount
66 | 24576 116 179 57
67 | Per-Kilobyte ratio
68 | 4.72005208333 7.28352864583 2.3193359375
69 | .
70 | Average degree connectivity per degree k:
71 | 0 0.000000
72 | 1 0.137931
73 | 2 0.940000
74 | 3 2.280702
75 | 4 2.633333
76 | 5 1.433333
77 | 6 1.083333
78 | 7 3.857143
79 | 8 4.375000
80 | 9 3.166667
81 | 10 3.400000
82 | 11 3.909091
83 | 12 0.250000
84 | 13 3.615385
85 | .
86 | Found 3 calls to GetProcAddress
87 | .
88 | * 2016-10-22 13:58:05.179154 Dumped to Neo4J
89 | * 2016-10-22 13:58:05.179173 Scanning for API patterns
90 | For REGSETVAL found {'RegOpenKey': '0x4011c0', 'RegSetValue': '0x4011e4'}
91 | For CREATEPROC found {'CreateProcess': '0x401000'}
92 | For CREATEPROC found {'CreateProcess': '0x4013c5'}
93 | For READFILE found {'CreateFile': '0x401618', 'ReadFile': '0x401618'}
94 | For APILOADING found {'GetProcAddress': '0x4053a5', 'LoadLibrary': '0x4053a5'}
95 | For WRITEFILE found {'WriteFile': '0x401618', 'CreateFile': '0x401618'}
96 | For WINEXEC found {'WinExec': '0x401618'}
97 | * 2016-10-22 13:58:05.181795 Scan finished
98 |
--------------------------------------------------------------------------------
/output/ransomware.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/ransomware.png
--------------------------------------------------------------------------------
/output/ransomware.txt:
--------------------------------------------------------------------------------
1 | * 2017-02-28 19:14:55.323687 Loading graph from cache under ./cache/[sha1].txt or .dbg
2 | .
3 | General graph info:
4 | SAMPLE ransom1
5 | Type: PE32 executable (GUI) Intel 80386, for MS Windows
6 | Size: 114688
7 | MD5: 9a7f87c91bf7e602055a5503e80e2313
8 | SHA1: 193f407a2f0c7e1eaa65c54cd9115c418881de42
9 | Name:
10 | Type: DiGraph
11 | Number of nodes: 482
12 | Number of edges: 1293
13 | Average in degree: 2.6826
14 | Average out degree: 2.6826
15 | .
16 | Graph measurement data:
17 | 491 Total functions detected with 'aflj'
18 | 2078 Count of references to local functions
19 | 0 Count of references to data section, global variables
20 | 0 Count of references to unrecognized locations
21 | 844 Total API refs found via symbol xref check
22 | 0 Count APIs w/o function xref
23 | 115 Total referenced Strings
24 | 0 Count of dangling strings (w/o function reference)
25 | 1620 Count of strings w/o any reference
26 | .
27 | PE details:
28 | Imphash: e58257679a7b694b926252a661453ab3
29 | Compilation time: 2016-02-23 08:07:31
30 | Entrypoint address: 0x6bed
31 | Entrypoint section: .text|0
32 | TLS section count: 0
33 | Original filename:
34 | Section count: 5
35 | Section details:
36 | .text 81408 6.63818822145
37 | .rdata 15872 6.6011769535
38 | .data 3072 4.12824777917
39 | .rsrc 7680 7.96772070636
40 | .reloc 5632 5.19527889732
41 | .
42 | Fat node detection with out-degree centrality, count calls, count strings:
43 | 0x4067f0 0.070686 23 2
44 | 0x406bed 0.039501 12 0
45 | 0x4048e9 0.031185 1 2
46 | 0x412872 0.029106 0 0
47 | 0x412c5a 0.027027 0 0
48 | 0x403f8a 0.027027 22 0
49 | 0x406428 0.027027 11 0
50 | 0x407ed4 0.027027 2 1
51 | 0x403006 0.027027 9 0
52 | 0x40ca15 0.027027 0 0
53 | 0x411aa2 0.024948 0 0
54 | 0x409615 0.024948 0 1
55 | 0x407818 0.024948 10 0
56 | 0x41246f 0.022869 0 0
57 | 0x40227e 0.020790 6 1
58 | 0x408600 0.020790 0 0
59 | 0x402665 0.020790 1 1
60 | 0x412684 0.020790 0 0
61 | 0x40cb86 0.020790 0 0
62 | 0x40ce25 0.020790 1 1
63 | .
64 | Histogram of out degree centrality:
65 | 0.0 0.0005 0.001 0.0015 0.002 0.004 0.006 0.008 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1 0.2 0.3 0.4 0.5
66 | 118 0 0 0 86 91 58 44 64 18 2 0 0 0 1 0 0 0 0 0 0
67 | .
68 | Loose nodes 73 of total 482, thats 15.145228%
69 | .
70 | ExecSize FunctionCount ApiCount StringCount
71 | 81408 491 844 115
72 | Per-Kilobyte ratio
73 | 6.03134827044 10.3675314465 1.41263757862
74 | .
75 | Average degree connectivity per degree k:
76 | 0 0.000000
77 | 1 8.966667
78 | 2 18.629032
79 | 3 19.545045
80 | 4 20.815972
81 | 5 21.114286
82 | 6 17.804598
83 | 7 20.844156
84 | 8 15.708333
85 | 9 15.907407
86 | 10 21.350000
87 | 11 14.575758
88 | 12 10.138889
89 | 13 19.246154
90 | 14 11.023810
91 | 15 9.288889
92 | 16 8.796875
93 | 19 20.789474
94 | 20 0.100000
95 | 22 3.181818
96 | 23 2.173913
97 | 29 0.000000
98 | 35 9.257143
99 | 37 0.108108
100 | 41 0.000000
101 | 42 0.000000
102 | 135 0.800000
103 | 87 0.114943
104 | .
105 | Found 4 calls to GetProcAddress
106 | .
107 | * 2017-02-28 19:14:55.894262 Scanning for API patterns
108 | For WSASEND found {'WSAStartup': '0x407818', 'gethostbyname': '0x40e18a', 'send': '0x407818'}
109 | For LOADRSRC found {'FindResource': '0x4058a2', 'LoadResource': '0x4058a2', 'LockResource': '0x4058a2'}
110 | For LOADRSRC found {'FindResource': '0x401000', 'LoadResource': '0x401000', 'LockResource': '0x401000'}
111 | For REGSETVAL found {'RegOpenKey': '0x402d24', 'RegSetValue': '0x402c9e'}
112 | For REGSETVAL found {'RegOpenKey': '0x410af6', 'RegSetValue': '0x410cd0'}
113 | For WINDOW found {'RegisterClass': '0x406677', 'DispatchMessage': '0x406677', 'CreateWindow': '0x406677'}
114 | For CREATETHREAD found {'CreateThread': '0x40e461'}
115 | For CREATETHREAD found {'CreateThread': '0x403295'}
116 | For CREATETHREAD found {'CreateThread': '0x410087'}
117 | For CREATETHREAD found {'CreateThread': '0x408eee'}
118 | For CREATETHREAD found {'CreateThread': '0x403006'}
119 | For PROCESSITER found {'CreateToolhelp32Snapshot': '0x4016e0', 'Process32First': '0x4016e0', 'Process32Next': '0x4016e0'}
120 | For PROCESSITER found {'CreateToolhelp32Snapshot': '0x408db8', 'Process32First': '0x408db8', 'Process32Next': '0x408db8'}
121 | For PROCESSITER found {'CreateToolhelp32Snapshot': '0x40a601', 'Process32First': '0x40a582', 'Process32Next': '0x40a582'}
122 | For PROCESSITER found {'CreateToolhelp32Snapshot': '0x4011f4', 'Process32First': '0x4011f4', 'Process32Next': '0x4011f4'}
123 | For PROCESSITER found {'CreateToolhelp32Snapshot': '0x40a39e', 'Process32First': '0x40a39e', 'Process32Next': '0x40a39e'}
124 | For APILOADING2 found {'GetModuleHandle': '0x40b702', 'GetProcAddress': '0x40b702'}
125 | For APILOADING2 found {'GetModuleHandle': '0x403f47', 'GetProcAddress': '0x403f47'}
126 | For APILOADING2 found {'GetModuleHandle': '0x40a62b', 'GetProcAddress': '0x40a62b'}
127 | For CREATEPROC found {'CreateProcess': '0x40a9ab'}
128 | For CREATEPROC found {'CreateProcess': '0x408ff2'}
129 | For CREATEPROC found {'CreateProcess': '0x405052'}
130 | For CREATEPROC found {'CreateProcess': '0x406309'}
131 | For CREATEPROC found {'CreateProcess': '0x40318b'}
132 | For CREATEPROC found {'CreateProcess': '0x406428'}
133 | For READFILE found {'CreateFile': '0x403f8a', 'ReadFile': '0x403f8a'}
134 | For EXITSYSTEM found {'ExitWindows': '0x403006'}
135 | For REGQUERY found {'RegQueryValue': '0x40227e', 'RegOpenKey': '0x40227e'}
136 | For REGQUERY found {'RegQueryValue': '0x401b25', 'RegOpenKey': '0x402406'}
137 | For REGQUERY found {'RegQueryValue': '0x40377a', 'RegOpenKey': '0x403cec'}
138 | For REGQUERY found {'RegQueryValue': '0x4097fa', 'RegOpenKey': '0x4097fa'}
139 | For REGQUERY found {'RegQueryValue': '0x40377a', 'RegOpenKey': '0x40377a'}
140 | For REGQUERY found {'RegQueryValue': '0x40b767', 'RegOpenKey': '0x40b767'}
141 | For REGQUERY found {'RegQueryValue': '0x40377a', 'RegOpenKey': '0x403aa0'}
142 | For REGQUERY found {'RegQueryValue': '0x410a8d', 'RegOpenKey': '0x410af6'}
143 | For REGQUERY found {'RegQueryValue': '0x408e72', 'RegOpenKey': '0x408e72'}
144 | For SHELLEXEC found {'ShellExecute': '0x404e2c'}
145 | For SHELLEXEC found {'ShellExecute': '0x409256'}
146 | For SHELLEXEC found {'ShellExecute': '0x402dcc'}
147 | For SHELLEXEC found {'ShellExecute': '0x408b8a'}
148 | For SHELLEXEC found {'ShellExecute': '0x408eee'}
149 | For APILOADING found {'GetProcAddress': '0x405c20', 'LoadLibrary': '0x405c20'}
150 | For FILEITER found {'FindNextFile': '0x40c231', 'FindClose': '0x40c231', 'FindFirstFile': '0x40c231'}
151 | For FILEITER found {'FindNextFile': '0x41096e', 'FindClose': '0x41096e', 'FindFirstFile': '0x41096e'}
152 | For FILEITER found {'FindNextFile': '0x409a5f', 'FindClose': '0x409a5f', 'FindFirstFile': '0x409a5f'}
153 | For FILEITER found {'FindNextFile': '0x410716', 'FindClose': '0x410716', 'FindFirstFile': '0x410716'}
154 | For WRITEFILE found {'WriteFile': '0x4091e6', 'CreateFile': '0x4091e6'}
155 | For WRITEFILE found {'WriteFile': '0x40461b', 'CreateFile': '0x40461b'}
156 | For WRITEFILE found {'WriteFile': '0x405139', 'CreateFile': '0x405139'}
157 | For WRITEFILE found {'WriteFile': '0x403f8a', 'CreateFile': '0x403f8a'}
158 | * 2017-02-28 19:14:55.906869 Stuffs all finished
159 |
160 | __..--*** I WANNA BE A BENCHMARK WHEN I GROW UP ***--..__
161 | __ 0.528890 Info
162 | __ 0.012579 Behavior
163 |
--------------------------------------------------------------------------------
/output/ransomware_2.txt:
--------------------------------------------------------------------------------
1 | * 2016-11-25 16:26:52.920998 R2 started analysis
2 | * 2016-11-25 16:26:55.633645 R2 finished analysis
3 | * 2016-11-25 16:27:12.542669 Graph created with NetworkX
4 | DANGLING API CALL 0x40a4d2 call dword [sym.imp.KERNEL32.dll_VirtualFree]
5 | DANGLING API CALL 0x40b139 call dword [sym.imp.KERNEL32.dll_SetLastError]
6 | DANGLING API CALL 0x40b274 call dword [sym.imp.KERNEL32.dll_SetLastError]
7 | DANGLING API CALL 0x410927 call dword [sym.imp.ole32.dll_CoUninitialize]
8 | DANGLING API CALL 0x40b1aa call dword [sym.imp.KERNEL32.dll_SetLastError]
9 | DANGLING API CALL 0x40a4e6 call dword [sym.imp.KERNEL32.dll_OpenProcess]
10 | DANGLING API CALL 0x40b213 call dword [sym.imp.KERNEL32.dll_SetLastError]
11 | * 2016-11-25 16:27:18.334807 Graph extended with API calls, 850 calls in total, 7 dangling w/o function reference
12 | * 2016-11-25 16:27:18.674472 Graph extended with string references
13 | .
14 | General graph info:
15 | SAMPLE ransom1
16 | Type: PE32 executable (GUI) Intel 80386, for MS Windows
17 | Size: 114688
18 | MD5: 9a7f87c91bf7e602055a5503e80e2313
19 | Name:
20 | Type: DiGraph
21 | Number of nodes: 484
22 | Number of edges: 1307
23 | Average in degree: 2.7004
24 | Average out degree: 2.7004
25 | .
26 | Graph measurement data:
27 | 493 Total functions detected with 'aflj'
28 | 2502 Count of references to local functions
29 | 0 Count of references to data section, global variables
30 | 0 Count of references to unrecognized locations
31 | 850 Total API refs found via symbol xref check
32 | 7 Count APIs w/o function xref
33 | 118 Total referenced Strings
34 | 0 Count of dangling strings (w/o function reference)
35 | 1620 Count of strings w/o any reference
36 | .
37 | PE details:
38 | Imphash: e58257679a7b694b926252a661453ab3
39 | Compilation time: 2016-02-23 08:07:31
40 | Entrypoint address: 0x6bed
41 | Entrypoint section: .text|0
42 | TLS section count: 0
43 | Original filename:
44 | Section count: 5
45 | Section details:
46 | .text 81408 6.63818822145
47 | .rdata 15872 6.6011769535
48 | .data 3072 4.12824777917
49 | .rsrc 7680 7.96772070636
50 | .reloc 5632 5.19527889732
51 | .
52 | Fat node detection with out-degree centrality, count calls, count strings:
53 | 0x4067f0 0.070393 23 2
54 | 0x406bed 0.039337 12 0
55 | 0x4048e9 0.031056 1 2
56 | 0x412872 0.028986 0 0
57 | 0x403f8a 0.026915 22 0
58 | 0x406428 0.026915 11 0
59 | 0x412c5a 0.026915 0 0
60 | 0x407ed4 0.026915 2 1
61 | 0x403006 0.026915 9 0
62 | 0x40ca15 0.026915 0 0
63 | 0x407818 0.024845 10 0
64 | 0x411aa2 0.024845 0 0
65 | 0x409615 0.024845 0 1
66 | 0x41246f 0.022774 0 0
67 | 0x40227e 0.020704 6 1
68 | 0x408600 0.020704 0 0
69 | 0x402665 0.020704 1 1
70 | 0x412684 0.020704 0 0
71 | 0x40cb86 0.020704 0 0
72 | 0x40ce25 0.020704 1 1
73 | .
74 | Histogram of out degree centrality:
75 | 0.0 0.0005 0.001 0.0015 0.002 0.004 0.006 0.008 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1 0.2 0.3 0.4 0.5
76 | 115 0 0 0 88 91 59 46 64 18 2 0 0 0 1 0 0 0 0 0 0
77 | .
78 | Loose nodes 75 of total 484, thats 15.495868%
79 | .
80 | ExecSize FunctionCount ApiCount StringCount
81 | 81408 493 850 118
82 | Per-Kilobyte ratio
83 | 6.0559158805 10.4412342767 1.44948899371
84 | .
85 | Average degree connectivity per degree k:
86 | 0 0.000000
87 | 1 9.473684
88 | 2 19.226562
89 | 3 19.052381
90 | 4 20.892361
91 | 5 19.734545
92 | 6 17.311111
93 | 7 20.889610
94 | 8 15.736111
95 | 9 16.594771
96 | 10 21.366667
97 | 11 13.220779
98 | 12 10.138889
99 | 13 19.246154
100 | 14 11.023810
101 | 15 9.333333
102 | 16 8.859375
103 | 19 20.789474
104 | 20 0.100000
105 | 22 3.227273
106 | 23 4.391304
107 | 24 0.000000
108 | 29 0.000000
109 | 35 9.257143
110 | 37 0.108108
111 | 41 0.000000
112 | 42 0.000000
113 | 135 0.800000
114 | 87 0.114943
115 | .
116 | Found 4 calls to GetProcAddress
117 | .
118 | * 2016-11-25 16:27:19.411253 Scanning for API patterns
119 | For WSASEND found {'WSAStartup': '0x407818', 'gethostbyname': '0x40e18a', 'send': '0x407818'}
120 | For LOADRSRC found {'FindResource': '0x4058a2', 'LoadResource': '0x4058a2', 'LockResource': '0x4058a2'}
121 | For LOADRSRC found {'FindResource': '0x401000', 'LoadResource': '0x401000', 'LockResource': '0x401000'}
122 | For REGSETVAL found {'RegOpenKey': '0x402d24', 'RegSetValue': '0x402c9e'}
123 | For REGSETVAL found {'RegOpenKey': '0x410af6', 'RegSetValue': '0x410cd0'}
124 | For WINDOW found {'RegisterClass': '0x406677', 'DispatchMessage': '0x406677', 'CreateWindow': '0x406677'}
125 | For CREATETHREAD found {'CreateThread': '0x40e461'}
126 | For CREATETHREAD found {'CreateThread': '0x403295'}
127 | For CREATETHREAD found {'CreateThread': '0x410087'}
128 | For CREATETHREAD found {'CreateThread': '0x408eee'}
129 | For CREATETHREAD found {'CreateThread': '0x403006'}
130 | For PROCESSITER found {'CreateToolhelp32Snapshot': '0x4016e0', 'Process32First': '0x4016e0', 'Process32Next': '0x4016e0'}
131 | For PROCESSITER found {'CreateToolhelp32Snapshot': '0x408db8', 'Process32First': '0x408db8', 'Process32Next': '0x408db8'}
132 | For PROCESSITER found {'CreateToolhelp32Snapshot': '0x40a601', 'Process32First': '0x40a582', 'Process32Next': '0x40a582'}
133 | For PROCESSITER found {'CreateToolhelp32Snapshot': '0x4011f4', 'Process32First': '0x4011f4', 'Process32Next': '0x4011f4'}
134 | For PROCESSITER found {'CreateToolhelp32Snapshot': '0x40a39e', 'Process32First': '0x40a39e', 'Process32Next': '0x40a39e'}
135 | For APILOADING2 found {'GetModuleHandle': '0x40b702', 'GetProcAddress': '0x40b702'}
136 | For APILOADING2 found {'GetModuleHandle': '0x403f47', 'GetProcAddress': '0x403f47'}
137 | For APILOADING2 found {'GetModuleHandle': '0x40a62b', 'GetProcAddress': '0x40a62b'}
138 | For CREATEPROC found {'CreateProcess': '0x40a9ab'}
139 | For CREATEPROC found {'CreateProcess': '0x408ff2'}
140 | For CREATEPROC found {'CreateProcess': '0x405052'}
141 | For CREATEPROC found {'CreateProcess': '0x406309'}
142 | For CREATEPROC found {'CreateProcess': '0x40318b'}
143 | For CREATEPROC found {'CreateProcess': '0x406428'}
144 | For READFILE found {'CreateFile': '0x403f8a', 'ReadFile': '0x403f8a'}
145 | For EXITSYSTEM found {'ExitWindows': '0x403006'}
146 | For REGQUERY found {'RegQueryValue': '0x40227e', 'RegOpenKey': '0x40227e'}
147 | For REGQUERY found {'RegQueryValue': '0x401b25', 'RegOpenKey': '0x402406'}
148 | For REGQUERY found {'RegQueryValue': '0x40377a', 'RegOpenKey': '0x403cec'}
149 | For REGQUERY found {'RegQueryValue': '0x4097fa', 'RegOpenKey': '0x4097fa'}
150 | For REGQUERY found {'RegQueryValue': '0x40377a', 'RegOpenKey': '0x40377a'}
151 | For REGQUERY found {'RegQueryValue': '0x40b767', 'RegOpenKey': '0x40b767'}
152 | For REGQUERY found {'RegQueryValue': '0x40377a', 'RegOpenKey': '0x403aa0'}
153 | For REGQUERY found {'RegQueryValue': '0x410a8d', 'RegOpenKey': '0x410af6'}
154 | For REGQUERY found {'RegQueryValue': '0x408e72', 'RegOpenKey': '0x408e72'}
155 | For SHELLEXEC found {'ShellExecute': '0x404e2c'}
156 | For SHELLEXEC found {'ShellExecute': '0x409256'}
157 | For SHELLEXEC found {'ShellExecute': '0x402dcc'}
158 | For SHELLEXEC found {'ShellExecute': '0x408eee'}
159 | For SHELLEXEC found {'ShellExecute': '0x408b8a'}
160 | For APILOADING found {'GetProcAddress': '0x405c20', 'LoadLibrary': '0x405c20'}
161 | For FILEITER found {'FindNextFile': '0x40c231', 'FindClose': '0x40c231', 'FindFirstFile': '0x40c231'}
162 | For FILEITER found {'FindNextFile': '0x409a5f', 'FindClose': '0x409a5f', 'FindFirstFile': '0x409a5f'}
163 | For FILEITER found {'FindNextFile': '0x41096e', 'FindClose': '0x41096e', 'FindFirstFile': '0x41096e'}
164 | For FILEITER found {'FindNextFile': '0x410716', 'FindClose': '0x410716', 'FindFirstFile': '0x410716'}
165 | For WRITEFILE found {'WriteFile': '0x4091e6', 'CreateFile': '0x4091e6'}
166 | For WRITEFILE found {'WriteFile': '0x40461b', 'CreateFile': '0x40461b'}
167 | For WRITEFILE found {'WriteFile': '0x405139', 'CreateFile': '0x405139'}
168 | For WRITEFILE found {'WriteFile': '0x403f8a', 'CreateFile': '0x403f8a'}
169 | * 2016-11-25 16:27:19.435900 Stuffs all finished
170 |
171 | __..--*** I WANNA BE A BENCHMARK WHEN I GROW UP ***--..__
172 | __ 2.712296 R2 Analysis
173 | __ 23.102750 Graph construction
174 | __ 0.674854 Info
175 | __ 0.024621 Behavior
176 |
--------------------------------------------------------------------------------
/output/ransomware_3.txt:
--------------------------------------------------------------------------------
1 | * 2016-11-25 18:44:33.424095 R2 started analysis
2 | * 2016-11-25 18:44:35.934941 R2 finished analysis
3 | * 2016-11-25 18:44:52.938879 Graph created with NetworkX
4 | DANGLING API CALL 0x40a4d2 call dword [sym.imp.KERNEL32.dll_VirtualFree]
5 | DANGLING API CALL 0x40b139 call dword [sym.imp.KERNEL32.dll_SetLastError]
6 | DANGLING API CALL 0x40b274 call dword [sym.imp.KERNEL32.dll_SetLastError]
7 | DANGLING API CALL 0x410927 call dword [sym.imp.ole32.dll_CoUninitialize]
8 | DANGLING API CALL 0x40b1aa call dword [sym.imp.KERNEL32.dll_SetLastError]
9 | DANGLING API CALL 0x40a4e6 call dword [sym.imp.KERNEL32.dll_OpenProcess]
10 | DANGLING API CALL 0x40b213 call dword [sym.imp.KERNEL32.dll_SetLastError]
11 | * 2016-11-25 18:44:58.495465 Graph extended with API calls, 850 calls in total, 7 dangling w/o function reference
12 | * 2016-11-25 18:44:58.820228 Graph extended with string references
13 | .
14 | General graph info:
15 | SAMPLE ransom1
16 | Type: PE32 executable (GUI) Intel 80386, for MS Windows
17 | Size: 114688
18 | MD5: 9a7f87c91bf7e602055a5503e80e2313
19 | Name:
20 | Type: DiGraph
21 | Number of nodes: 484
22 | Number of edges: 1307
23 | Average in degree: 2.7004
24 | Average out degree: 2.7004
25 | .
26 | Graph measurement data:
27 | 493 Total functions detected with 'aflj'
28 | 2502 Count of references to local functions
29 | 0 Count of references to data section, global variables
30 | 0 Count of references to unrecognized locations
31 | 850 Total API refs found via symbol xref check
32 | 7 Count APIs w/o function xref
33 | 118 Total referenced Strings
34 | 0 Count of dangling strings (w/o function reference)
35 | 1620 Count of strings w/o any reference
36 | .
37 | PE details:
38 | Imphash: e58257679a7b694b926252a661453ab3
39 | Compilation time: 2016-02-23 08:07:31
40 | Entrypoint address: 0x6bed
41 | Entrypoint section: .text|0
42 | TLS section count: 0
43 | Original filename:
44 | Section count: 5
45 | Section details:
46 | .text 81408 6.63818822145
47 | .rdata 15872 6.6011769535
48 | .data 3072 4.12824777917
49 | .rsrc 7680 7.96772070636
50 | .reloc 5632 5.19527889732
51 | .
52 | Fat node detection with out-degree centrality, count calls, count strings:
53 | 0x4067f0 0.070393 23 2
54 | 0x406bed 0.039337 12 0
55 | 0x4048e9 0.031056 1 2
56 | 0x412872 0.028986 0 0
57 | 0x403f8a 0.026915 22 0
58 | 0x406428 0.026915 11 0
59 | 0x412c5a 0.026915 0 0
60 | 0x407ed4 0.026915 2 1
61 | 0x403006 0.026915 9 0
62 | 0x40ca15 0.026915 0 0
63 | 0x407818 0.024845 10 0
64 | 0x411aa2 0.024845 0 0
65 | 0x409615 0.024845 0 1
66 | 0x41246f 0.022774 0 0
67 | 0x40227e 0.020704 6 1
68 | 0x408600 0.020704 0 0
69 | 0x402665 0.020704 1 1
70 | 0x412684 0.020704 0 0
71 | 0x40cb86 0.020704 0 0
72 | 0x40ce25 0.020704 1 1
73 | .
74 | Histogram of out degree centrality:
75 | 0.0 0.0005 0.001 0.0015 0.002 0.004 0.006 0.008 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1 0.2 0.3 0.4 0.5
76 | 115 0 0 0 88 91 59 46 64 18 2 0 0 0 1 0 0 0 0 0 0
77 | .
78 | Loose nodes 75 of total 484, thats 15.495868%
79 | .
80 | ExecSize FunctionCount ApiCount StringCount
81 | 81408 493 850 118
82 | Per-Kilobyte ratio
83 | 6.0559158805 10.4412342767 1.44948899371
84 | .
85 | Average degree connectivity per degree k:
86 | 0 0.000000
87 | 1 9.473684
88 | 2 19.226562
89 | 3 19.052381
90 | 4 20.892361
91 | 5 19.734545
92 | 6 17.311111
93 | 7 20.889610
94 | 8 15.736111
95 | 9 16.594771
96 | 10 21.366667
97 | 11 13.220779
98 | 12 10.138889
99 | 13 19.246154
100 | 14 11.023810
101 | 15 9.333333
102 | 16 8.859375
103 | 19 20.789474
104 | 20 0.100000
105 | 22 3.227273
106 | 23 4.391304
107 | 24 0.000000
108 | 29 0.000000
109 | 35 9.257143
110 | 37 0.108108
111 | 41 0.000000
112 | 42 0.000000
113 | 135 0.800000
114 | 87 0.114943
115 | .
116 | Found 4 calls to GetProcAddress
117 | .
118 | * 2016-11-25 18:44:59.462709 Scanning for API patterns
119 | For WSASEND found {'WSAStartup': '0x407818', 'gethostbyname': '0x40e18a', 'send': '0x407818'}
120 | For LOADRSRC found {'FindResource': '0x4058a2', 'LoadResource': '0x4058a2', 'LockResource': '0x4058a2'}
121 | For LOADRSRC found {'FindResource': '0x401000', 'LoadResource': '0x401000', 'LockResource': '0x401000'}
122 | For REGSETVAL found {'RegOpenKey': '0x402d24', 'RegSetValue': '0x402c9e'}
123 | For REGSETVAL found {'RegOpenKey': '0x410af6', 'RegSetValue': '0x410cd0'}
124 | For WINDOW found {'RegisterClass': '0x406677', 'DispatchMessage': '0x406677', 'CreateWindow': '0x406677'}
125 | For CREATETHREAD found {'CreateThread': '0x40e461'}
126 | For CREATETHREAD found {'CreateThread': '0x403295'}
127 | For CREATETHREAD found {'CreateThread': '0x410087'}
128 | For CREATETHREAD found {'CreateThread': '0x408eee'}
129 | For CREATETHREAD found {'CreateThread': '0x403006'}
130 | For PROCESSITER found {'CreateToolhelp32Snapshot': '0x4016e0', 'Process32First': '0x4016e0', 'Process32Next': '0x4016e0'}
131 | For PROCESSITER found {'CreateToolhelp32Snapshot': '0x408db8', 'Process32First': '0x408db8', 'Process32Next': '0x408db8'}
132 | For PROCESSITER found {'CreateToolhelp32Snapshot': '0x40a601', 'Process32First': '0x40a582', 'Process32Next': '0x40a582'}
133 | For PROCESSITER found {'CreateToolhelp32Snapshot': '0x4011f4', 'Process32First': '0x4011f4', 'Process32Next': '0x4011f4'}
134 | For PROCESSITER found {'CreateToolhelp32Snapshot': '0x40a39e', 'Process32First': '0x40a39e', 'Process32Next': '0x40a39e'}
135 | For APILOADING2 found {'GetModuleHandle': '0x40b702', 'GetProcAddress': '0x40b702'}
136 | For APILOADING2 found {'GetModuleHandle': '0x403f47', 'GetProcAddress': '0x403f47'}
137 | For APILOADING2 found {'GetModuleHandle': '0x40a62b', 'GetProcAddress': '0x40a62b'}
138 | For CREATEPROC found {'CreateProcess': '0x40a9ab'}
139 | For CREATEPROC found {'CreateProcess': '0x408ff2'}
140 | For CREATEPROC found {'CreateProcess': '0x405052'}
141 | For CREATEPROC found {'CreateProcess': '0x406309'}
142 | For CREATEPROC found {'CreateProcess': '0x40318b'}
143 | For CREATEPROC found {'CreateProcess': '0x406428'}
144 | For READFILE found {'CreateFile': '0x403f8a', 'ReadFile': '0x403f8a'}
145 | For EXITSYSTEM found {'ExitWindows': '0x403006'}
146 | For REGQUERY found {'RegQueryValue': '0x40227e', 'RegOpenKey': '0x40227e'}
147 | For REGQUERY found {'RegQueryValue': '0x401b25', 'RegOpenKey': '0x402406'}
148 | For REGQUERY found {'RegQueryValue': '0x40377a', 'RegOpenKey': '0x403cec'}
149 | For REGQUERY found {'RegQueryValue': '0x4097fa', 'RegOpenKey': '0x4097fa'}
150 | For REGQUERY found {'RegQueryValue': '0x40377a', 'RegOpenKey': '0x40377a'}
151 | For REGQUERY found {'RegQueryValue': '0x40b767', 'RegOpenKey': '0x40b767'}
152 | For REGQUERY found {'RegQueryValue': '0x40377a', 'RegOpenKey': '0x403aa0'}
153 | For REGQUERY found {'RegQueryValue': '0x410a8d', 'RegOpenKey': '0x410af6'}
154 | For REGQUERY found {'RegQueryValue': '0x408e72', 'RegOpenKey': '0x408e72'}
155 | For SHELLEXEC found {'ShellExecute': '0x404e2c'}
156 | For SHELLEXEC found {'ShellExecute': '0x409256'}
157 | For SHELLEXEC found {'ShellExecute': '0x402dcc'}
158 | For SHELLEXEC found {'ShellExecute': '0x408eee'}
159 | For SHELLEXEC found {'ShellExecute': '0x408b8a'}
160 | For APILOADING found {'GetProcAddress': '0x405c20', 'LoadLibrary': '0x405c20'}
161 | For FILEITER found {'FindNextFile': '0x40c231', 'FindClose': '0x40c231', 'FindFirstFile': '0x40c231'}
162 | For FILEITER found {'FindNextFile': '0x409a5f', 'FindClose': '0x409a5f', 'FindFirstFile': '0x409a5f'}
163 | For FILEITER found {'FindNextFile': '0x41096e', 'FindClose': '0x41096e', 'FindFirstFile': '0x41096e'}
164 | For FILEITER found {'FindNextFile': '0x410716', 'FindClose': '0x410716', 'FindFirstFile': '0x410716'}
165 | For WRITEFILE found {'WriteFile': '0x4091e6', 'CreateFile': '0x4091e6'}
166 | For WRITEFILE found {'WriteFile': '0x40461b', 'CreateFile': '0x40461b'}
167 | For WRITEFILE found {'WriteFile': '0x405139', 'CreateFile': '0x405139'}
168 | For WRITEFILE found {'WriteFile': '0x403f8a', 'CreateFile': '0x403f8a'}
169 | * 2016-11-25 18:44:59.477431 Stuffs all finished
170 |
171 | __..--*** I WANNA BE A BENCHMARK WHEN I GROW UP ***--..__
172 | __ 2.510206 R2 Analysis
173 | __ 22.942147 Graph construction
174 | __ 0.585613 Info
175 | __ 0.014689 Behavior
176 |
--------------------------------------------------------------------------------
/output/shadowbrokers.exe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/shadowbrokers.exe.png
--------------------------------------------------------------------------------
/output/spaghetticode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/spaghetticode.png
--------------------------------------------------------------------------------
/output/stuxnet_meta.csv:
--------------------------------------------------------------------------------
1 | filename,filetype,filesize,codesecsize,md5,imphash,compilationtime,addressep,sectionep,tlssections,originalfilename,sectioncount,secname1,secname2,secname3,secname4,secname5,secname6,secsize1,secsize2,secsize3,secsize4,secsize5,secsize6,secent1,secent2,secent3,secent4,secent5,secent6,functionstotal,refslocal,refsglobalvar,refsunknown,apitotal,apimisses,stringsreferenced,stringsdangling,stringsnoref,ratiofunc,ratioapi,ratiostring,getprocaddress,memallocation,createthread,ctshortestpath,callbackcount,cbaveragesize,cblargestsize
2 | 6d7d771a9e2a6add227597f9c07c324c,PE32 executable (GUI) Intel 80386 for MS Windows,24576,6656,6d7d771a9e2a6add227597f9c07c324c,,2009-06-20 10:38:50,0x14df,.verif|0,0,,4,.verif,.text,.bin,.reloc,,,0,6656,512,512,,,0.0,0.006374463454139935,0.0,4.995303943015908,,,0,0,0,0,0,0,0,0,109,0.0,0.0,0.0,0,0,0,0,0,0,0
3 | 7682d7e8b1c44949c0fa934e6705e200,PE32 executable (DLL) (GUI) Intel 80386 for MS Windows UPX compressed,498176,495104,7682d7e8b1c44949c0fa934e6705e200,,2010-03-01 05:54:43,0x136000,UPX1|1,0,,3,UPX0,UPX1,.rsrc,,,,0,495104,2048,,,,0.0,6.333282146896331,3.1414237652179047,,,,5912,11515,0,11,0,0,141,23,3217,11.940925542916236,0.0,0.2847886504653568,0,0,0,0,0,0,0
4 | 9fb893c39df51a5fdd6cbf1172fc5e1d,PE32 executable (DLL) (GUI) Intel 80386 for MS Windows UPX compressed,498176,495104,9fb893c39df51a5fdd6cbf1172fc5e1d,,2010-03-01 05:54:43,0x136000,UPX1|1,0,,3,UPX0,UPX1,.rsrc,,,,0,495104,2048,,,,0.0,6.2979413494133745,3.131437045010657,,,,5924,11518,0,11,0,0,139,24,2914,11.965162874870735,0.0,0.28074909513960705,0,0,0,0,0,0,0
5 | fc43eeac93601764a7c506f8f9fd5fd5,PE32 executable (DLL) (GUI) Intel 80386 for MS Windows UPX compressed,1277952,495104,fc43eeac93601764a7c506f8f9fd5fd5,,2010-03-01 05:54:43,0x136000,UPX1|1,0,,3,UPX0,UPX1,.rsrc,,,,0,495104,2048,,,,0.0,6.328962611742998,3.1362914536224733,,,,5924,11516,0,11,0,0,141,14,3567,11.965162874870735,0.0,0.2847886504653568,0,0,0,0,0,0,0
6 | 11753a4773ebf2118d228ea71a6c13bd,PE32 executable (GUI) Intel 80386 for MS Windows,517632,6144,11753a4773ebf2118d228ea71a6c13bd,,2010-03-01 05:52:35,0x103d,.text|0,0,,5,.text,.rdata,.data,.reloc,.stub,,6144,1536,512,512,507904,,5.9775987031421005,4.560715548290745,0.020393135236084953,3.559416028154956,7.993817912590633,,53,76,21,15,0,0,6,8,10159,8.626302083333334,0.0,0.9765625,0,0,0,0,0,0,0
7 | 5cd18a4c824c22c88e180b4f81d00873,PE32 executable (DLL) (GUI) Intel 80386 for MS Windows,14660,6144,5cd18a4c824c22c88e180b4f81d00873,230cb3dd9e4543152cce198082ba4974,2009-06-22 15:31:38,0x1000,.text|0,0,S7HKIMDX.DLL,5,.text,.rdata,.data,.rsrc,.reloc,,6144,1536,512,4608,512,,5.911839410065305,3.8497606079908935,0.020393135236084953,3.3959401037369528,4.192936248375133,,36,50,0,15,50,0,25,8,202,5.859375,8.138020833333334,4.069010416666667,16,1,1,2,1,106,106
8 | 732dd10fc5f3d53ced22ee3c5910fce4,PE32 executable (DLL) (GUI) Intel 80386 for MS Windows,2048,4096,732dd10fc5f3d53ced22ee3c5910fce4,,2010-03-01 05:52:35,0x101b,.text|0,0,,5,.text,.rdata,.data,.reloc,.stub,,6144,1536,512,512,507904,,6.091139071350777,0.0,0.0,0.0,0.0,,13,9,9,18,0,0,1,0,16,3.173828125,0.0,0.244140625,0,0,0,0,0,0,0
9 | 7c9380745e1b0e2a235c024db59152f0,PE32 executable (native) Intel 80386 for MS Windows,11264,8192,7c9380745e1b0e2a235c024db59152f0,ceff124c701793ccb77a6c4fade60c11,2014-03-12 03:20:13,0x503e,INIT|3,0,,5,.text,.rdata,.data,INIT,.reloc,,7168,1024,512,1024,512,,5.547811890538197,2.7718933370930636,0.4785768520376241,4.360697748279329,4.297120893454738,,61,61,0,0,44,0,3,4,67,7.4462890625,5.37109375,0.3662109375,0,5,0,0,0,0,0
10 | c6f4a5f6717f7319c188c47cc0571b99,PE32 executable (native) Intel 80386 for MS Windows,11264,8192,c6f4a5f6717f7319c188c47cc0571b99,ceff124c701793ccb77a6c4fade60c11,2014-03-11 08:19:54,0x503e,INIT|3,0,,5,.text,.rdata,.data,INIT,.reloc,,7168,1024,512,1024,512,,5.547811890538197,2.7826293902763557,0.4785768520376241,4.360697748279329,4.297120893454738,,61,61,0,0,44,0,3,4,67,7.4462890625,5.37109375,0.3662109375,0,5,0,0,0,0,0
11 | shadowbrokers.exe,PE32 executable (console) Intel 80386 for MS Windows,22016,9728,0bc136522423099f72dbf8f67f99e7d8,b6c04ac2fb7e4cb3b48f73b1f94b39e9,2009-11-02 15:18:04,0x2f7f,.text|0,0,,5,.text,.rdata,.data,.rsrc,.reloc,,9728,5632,3072,512,2048,,6.172218082414134,5.122118078751301,6.096959720550209,5.097979088823027,3.148399419255397,,107,249,2,0,94,5,123,0,348,10.999177631578947,9.662828947368421,12.64391447368421,0,5,0,0,0,0,0
12 | 98b8e890a3b0ffefcbb4abf3099dc55d,PE32+ executable (native) x86-64 for MS Windows,15872,11776,98b8e890a3b0ffefcbb4abf3099dc55d,7e6264b4d77763c050c7ba32736e4959,2014-03-11 08:26:24,0x7064,INIT|4,0,,6,.text,.rdata,.data,.pdata,INIT,.reloc,10752,1024,512,1024,1024,512,5.391931821736166,3.446901163114639,0.5556202440094367,2.5901886974030566,4.630246046408556,0.22167620545804623,66,63,0,0,43,0,4,1,479,5.604619565217392,3.6514945652173916,0.33967391304347827,0,5,0,0,0,0,0
13 | 70748fd6da61317bd7f3ed4c8b011f23,PE32 executable (DLL) (GUI) Intel 80386 for MS Windows,25720,13312,70748fd6da61317bd7f3ed4c8b011f23,,2010-02-03 06:32:00,0x1e20,.text|0,0,,4,.text,.rdata,.data,.reloc,,,13312,3072,512,1024,,,6.2650977488267685,0.34914922405133786,0.0,0.1893906582563515,,,95,124,112,15,0,0,18,9,304,7.136418269230769,0.0,1.3521634615384617,0,0,0,0,0,0,0
14 | 851ae4a1b6784448ff39a12f72743d01,PE32 executable (DLL) (GUI) Intel 80386 for MS Windows,25720,13312,851ae4a1b6784448ff39a12f72743d01,,2010-02-03 06:30:27,0x1e20,.text|0,0,,4,.text,.rdata,.data,.reloc,,,13312,3072,512,1024,,,6.803311898824901,7.938473223893479,7.5666983713060025,7.805969431804279,,,89,116,114,15,0,0,28,10,321,6.685697115384616,0.0,2.1033653846153846,0,0,0,0,0,0,0
15 | 2f21eaef0f5fdc500ec556f098b56006,PE32 executable (DLL) (GUI) Intel 80386 for MS Windows,236544,168960,2f21eaef0f5fdc500ec556f098b56006,3f432c0f5e33e72ce2b07f60ea67a86a,2006-01-01 09:17:51,0x1b294,.text|0,0,,5,.text,.rdata,.data,.rsrc,.reloc,,168960,34304,5120,8192,18944,,6.594448014627349,4.60052174305734,2.7370399761522437,7.853621739087239,4.63193048305984,,2281,4763,4,16,827,3,412,10,2350,13.500236742424242,4.894649621212121,2.4384469696969697,37,17,8,2,8,44,79
16 |
--------------------------------------------------------------------------------
/output/turla_57b8c2f5cfeaca97da58cfcdaf10c88dbc2c987c436ddc1ad7b7ed31879cb665.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/output/turla_57b8c2f5cfeaca97da58cfcdaf10c88dbc2c987c436ddc1ad7b7ed31879cb665.png
--------------------------------------------------------------------------------
/prepare_misp_object.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import pefile
5 | import pydeep
6 | from pymisp import MISPEvent, MISPAttribute
7 | import os
8 | from io import BytesIO
9 | from hashlib import md5, sha1, sha256, sha512
10 | import magic
11 | import math
12 | from collections import Counter
13 | import json
14 | import uuid
15 | import abc
16 |
17 | misp_objects_path = './misp-objects/objects'
18 |
19 |
20 | class MISPObjectGenerator(metaclass=abc.ABCMeta):
21 |
22 | def __init__(self):
23 | self.misp_event = MISPEvent()
24 | self.uuid = str(uuid.uuid4())
25 | self.links = []
26 |
27 | def _fill_object(self, obj_def, values):
28 | empty_object = self.__new_empty_object(obj_def)
29 | if self.links:
30 | empty_object["ObjectReference"] = []
31 | for link in self.links:
32 | uuid, comment = link
33 | empty_object['ObjectReference'].append({'referenced_object_uuid': uuid, 'comment': comment})
34 | for object_type, value in values.items():
35 | if value.get('value') is None:
36 | continue
37 | attribute = MISPAttribute(self.misp_event.describe_types)
38 | value['type'] = obj_def['attributes'][object_type]['misp-attribute']
39 | if value.get('disable_correlation') is None:
40 | value['disable_correlation'] = obj_def['attributes'][object_type].get('disable_correlation')
41 | if value.get('to_ids') is None:
42 | value['to_ids'] = obj_def['attributes'][object_type].get('to_ids')
43 | attribute.set_all_values(**value)
44 | empty_object['ObjectAttribute'].append({'type': object_type, 'Attribute': attribute._json()})
45 | return empty_object
46 |
47 | def add_link(self, uuid, comment=None):
48 | self.links.append((uuid, comment))
49 |
50 | def __new_empty_object(self, object_definiton):
51 | return {'name': object_definiton['name'], 'meta-category': object_definiton['meta-category'],
52 | 'uuid': self.uuid, 'description': object_definiton['description'],
53 | 'version': object_definiton['version'], 'ObjectAttribute': []}
54 |
55 | @abc.abstractmethod
56 | def generate_attributes(self):
57 | pass
58 |
59 | @abc.abstractmethod
60 | def dump(self):
61 | pass
62 |
63 |
64 | class FileObject(MISPObjectGenerator):
65 |
66 | def __init__(self, filepath):
67 | MISPObjectGenerator.__init__(self)
68 | with open(os.path.join(misp_objects_path, 'file/definition.json'), 'r') as f:
69 | self.mo_file = json.load(f)
70 | self.filepath = filepath
71 | with open(self.filepath, 'rb') as f:
72 | self.pseudo_file = BytesIO(f.read())
73 | self.data = self.pseudo_file.getvalue()
74 | self.generate_attributes()
75 |
76 | def generate_attributes(self):
77 | self.filename = os.path.basename(self.filepath)
78 | self.size = os.path.getsize(self.filepath)
79 | if self.size > 0:
80 | self.filetype = magic.from_buffer(self.data)
81 | self.entropy = self.__entropy_H(self.data)
82 | self.md5 = md5(self.data).hexdigest()
83 | self.sha1 = sha1(self.data).hexdigest()
84 | self.sha256 = sha256(self.data).hexdigest()
85 | self.sha512 = sha512(self.data).hexdigest()
86 | self.ssdeep = pydeep.hash_buf(self.data).decode()
87 |
88 | def __entropy_H(self, data):
89 | """Calculate the entropy of a chunk of data."""
90 | # NOTE: copy of the entropy function from pefile, the entropy of the
91 | # full file isn't computed
92 |
93 | if len(data) == 0:
94 | return 0.0
95 |
96 | occurences = Counter(bytearray(data))
97 |
98 | entropy = 0
99 | for x in occurences.values():
100 | p_x = float(x) / len(data)
101 | entropy -= p_x * math.log(p_x, 2)
102 |
103 | return entropy
104 |
105 | def dump(self):
106 | file_object = {}
107 | file_object['filename'] = {'value': self.filename}
108 | file_object['size-in-bytes'] = {'value': self.size}
109 | if self.size > 0:
110 | file_object['entropy'] = {'value': self.entropy}
111 | file_object['ssdeep'] = {'value': self.ssdeep}
112 | file_object['sha512'] = {'value': self.sha512}
113 | file_object['md5'] = {'value': self.md5}
114 | file_object['sha1'] = {'value': self.sha1}
115 | file_object['sha256'] = {'value': self.sha256}
116 | file_object['malware-sample'] = {'value': '{}|{}'.format(self.filename, self.md5), 'data': self.pseudo_file}
117 | # file_object['authentihash'] = self.
118 | # file_object['sha-224'] = self.
119 | # file_object['sha-384'] = self.
120 | # file_object['sha512/224'] = self.
121 | # file_object['sha512/256'] = self.
122 | # file_object['tlsh'] = self.
123 | return self._fill_object(self.mo_file, file_object)
124 |
125 |
126 | class PEObject(MISPObjectGenerator):
127 |
128 | def __init__(self, data):
129 | MISPObjectGenerator.__init__(self)
130 | with open(os.path.join(misp_objects_path, 'pe/definition.json'), 'r') as f:
131 | self.mo_pe = json.load(f)
132 | self.data = data
133 | self.pe = pefile.PE(data=self.data)
134 | self.generate_attributes()
135 |
136 | def generate_attributes(self):
137 | if self.pe.is_dll():
138 | self.pe_type = 'dll'
139 | elif self.pe.is_driver():
140 | self.pe_type = 'driver'
141 | elif self.pe.is_exe():
142 | self.pe_type = 'exe'
143 | else:
144 | self.pe_type = 'unknown'
145 | # file_object['pehash'] = self.
146 | # General information
147 | self.imphash = self.pe.get_imphash()
148 | all_data = self.pe.dump_dict()
149 | if (all_data.get('Debug information') and all_data['Debug information'][0].get('TimeDateStamp') and
150 | all_data['Debug information'][0]['TimeDateStamp'].get('ISO Time')):
151 | self.compilation_timestamp = all_data['Debug information'][0]['TimeDateStamp']['ISO Time']
152 | if (all_data.get('OPTIONAL_HEADER') and all_data['OPTIONAL_HEADER'].get('AddressOfEntryPoint')):
153 | self.entrypoint_address = all_data['OPTIONAL_HEADER']['AddressOfEntryPoint']['Value']
154 | if all_data.get('File Info'):
155 | self.original_filename = all_data['File Info'][1].get('OriginalFilename')
156 | self.internal_filename = all_data['File Info'][1].get('InternalName')
157 | self.file_description = all_data['File Info'][1].get('FileDescription')
158 | self.file_version = all_data['File Info'][1].get('FileVersion')
159 | self.lang_id = all_data['File Info'][1].get('LangID')
160 | self.product_name = all_data['File Info'][1].get('ProductName')
161 | self.product_version = all_data['File Info'][1].get('ProductVersion')
162 | self.company_name = all_data['File Info'][1].get('CompanyName')
163 | self.legal_copyright = all_data['File Info'][1].get('LegalCopyright')
164 | # Sections
165 | self.sections = []
166 | if all_data.get('PE Sections'):
167 | pos = 0
168 | for s in all_data['PE Sections']:
169 | s_obj = self.pe.sections[pos]
170 | section = PESectionObject(s, s_obj.get_data())
171 | self.add_link(section.uuid, 'Section {} of PE'.format(pos))
172 | if ((self.entrypoint_address >= s['VirtualAddress']['Value']) and
173 | (self.entrypoint_address < (s['VirtualAddress']['Value'] + s['Misc_VirtualSize']['Value']))):
174 | self.entrypoint_section = (s['Name']['Value'], pos) # Tuple: (section_name, position)
175 | pos += 1
176 | self.sections.append(section)
177 | self.nb_sections = len(self.sections)
178 | # TODO: TLSSection / DIRECTORY_ENTRY_TLS
179 |
180 | def dump(self):
181 | pe_object = {}
182 | pe_object['type'] = {'value': self.pe_type}
183 | if hasattr(self, 'imphash'):
184 | pe_object['imphash'] = {'value': self.imphash}
185 | if hasattr(self, 'original_filename'):
186 | pe_object['original-filename'] = {'value': self.original_filename}
187 | if hasattr(self, 'internal_filename'):
188 | pe_object['internal-filename'] = {'value': self.internal_filename}
189 | if hasattr(self, 'compilation_timestamp'):
190 | pe_object['compilation-timestamp'] = {'value': self.compilation_timestamp}
191 | if hasattr(self, 'entrypoint_section'):
192 | pe_object['entrypoint-section|position'] = {'value': '{}|{}'.format(*self.entrypoint_section)}
193 | if hasattr(self, 'entrypoint_address'):
194 | pe_object['entrypoint-address'] = {'value': self.entrypoint_address}
195 | if hasattr(self, 'file_description'):
196 | pe_object['file-description'] = {'value': self.file_description}
197 | if hasattr(self, 'file_version'):
198 | pe_object['file-version'] = {'value': self.file_version}
199 | if hasattr(self, 'lang_id'):
200 | pe_object['lang-id'] = {'value': self.lang_id}
201 | if hasattr(self, 'product_name'):
202 | pe_object['product-name'] = {'value': self.product_name}
203 | if hasattr(self, 'product_version'):
204 | pe_object['product-version'] = {'value': self.product_version}
205 | if hasattr(self, 'company_name'):
206 | pe_object['company-name'] = {'value': self.company_name}
207 | if hasattr(self, 'nb_sections'):
208 | pe_object['number-sections'] = {'value': self.nb_sections}
209 | return self._fill_object(self.mo_pe, pe_object)
210 |
211 |
212 | class PESectionObject(MISPObjectGenerator):
213 |
214 | def __init__(self, section_info, data):
215 | MISPObjectGenerator.__init__(self)
216 | with open(os.path.join(misp_objects_path, 'pe-section/definition.json'), 'r') as f:
217 | self.mo_pe_section = json.load(f)
218 | self.section_info = section_info
219 | self.data = data
220 | self.generate_attributes()
221 |
222 | def generate_attributes(self):
223 | self.name = self.section_info['Name']['Value']
224 | self.size = self.section_info['SizeOfRawData']['Value']
225 | if self.size > 0:
226 | self.entropy = self.section_info['Entropy']
227 | self.md5 = self.section_info['MD5']
228 | self.sha1 = self.section_info['SHA1']
229 | self.sha256 = self.section_info['SHA256']
230 | self.sha512 = self.section_info['SHA512']
231 | self.ssdeep = pydeep.hash_buf(self.data).decode()
232 |
233 | def dump(self):
234 | section = {}
235 | section['name'] = {'value': self.name}
236 | section['size-in-bytes'] = {'value': self.size}
237 | if self.size > 0:
238 | section['entropy'] = {'value': self.entropy}
239 | section['md5'] = {'value': self.md5}
240 | section['sha1'] = {'value': self.sha1}
241 | section['sha256'] = {'value': self.sha256}
242 | section['sha512'] = {'value': self.sha512}
243 | section['ssdeep'] = {'value': self.ssdeep}
244 | return self._fill_object(self.mo_pe_section, section)
245 |
246 |
247 | def make_objects(filepath):
248 | misp_file = FileObject(filepath)
249 | try:
250 | misp_pe = PEObject(misp_file.data)
251 | misp_file.add_link(misp_pe.uuid, 'PE indicators')
252 | file_object = misp_file.dump()
253 | pe_object = misp_pe.dump()
254 | pe_sections = []
255 | for s in misp_pe.sections:
256 | pe_sections.append(s.dump())
257 | return file_object, pe_object, pe_sections
258 | except pefile.PEFormatError:
259 | pass
260 | file_object = misp_file.dump()
261 | return file_object, None, None
262 |
263 |
264 | if __name__ == '__main__':
265 | import glob
266 | for f in glob.glob('/path/to/samples/*'):
267 | fo, peo, seos = make_objects(f)
268 | #print(json.dumps([fo, peo, seos]))
269 | #break
270 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | r2pipe
2 | networkx
3 | py2neo
4 | pydotplus
5 | numpy
6 | python-magic
7 | git+https://github.com/kbandla/pydeep.git#egg=pydeep
8 | git+https://github.com/viper-framework/pefile.git#egg=pefile
9 |
10 | # For MISP Objects
11 |
12 | pymisp
13 |
--------------------------------------------------------------------------------
/signatures/putFlirtSignaturesHere.sig:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pinkflawd/r2graphity/ca0c6b9e1acfdd8cc24a59903c580f1996fbd242/signatures/putFlirtSignaturesHere.sig
--------------------------------------------------------------------------------