├── .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 |
34 |

35 |
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 --------------------------------------------------------------------------------