class CFG(): def __init__(self, filename): self.filename = filename try: self.a = APK(filename) self.d = DalvikVMFormat(self.a.get_dex()) self.d.create_python_export() self.dx = Analysis(self.d) except zipfile.BadZipfile: # if file is not an APK, may be a dex object _, self.d, self.dx = AnalyzeDex(self.filename) self.d.set_vmanalysis(self.dx) self.dx.create_xref() self.cfg = self.build_cfg() def get_cg(self): return self.cfg def get_cfg(self): return self.dx.get_call_graph() def build_cfg(self): """ Using NX and Androguard, build a directed graph NX object so that: - node names are analysis.MethodClassAnalysis objects - each node has a label that encodes the method behavior """ cfg = self.get_cfg() ##/////////My changes/////////////// for n in cfg.nodes: instructions = [] # print(n) try: ops = n.get_instructions() for i in ops: instructions.append(i.get_name()) # print(ops) encoded_label = self.color_instructions(instructions) # print("No Exception") except AttributeError: encoded_label = np.array([0] * 15) cfg.node[n]["label"] = encoded_label return cfg def color_instructions(self, instructions): """ Node label based on coloring technique by Kruegel """ h = [0] * len(INSTRUCTION_CLASS_COLOR) for i in instructions: h[INSTRUCTION_SET_COLOR[i]] = 1 return np.array(h) def get_classes_from_label(self, label): classes = [ INSTRUCTION_CLASSES[i] for i in range(len(label)) if label[i] == 1 ] return classes
def addDEX(self, filename, data, dx=None, postpone_xref=False): """ Add a DEX file to the Session and run analysis. :param filename: the (file)name of the DEX file :param data: binary data of the dex file :param dx: an existing Analysis Object (optional) :param postpone_xref: True if no xref shall be created, and will be called manually :return: A tuple of SHA256 Hash, DalvikVMFormat Object and Analysis object """ digest = hashlib.sha256(data).hexdigest() log.debug("add DEX:%s" % digest) log.debug("Parsing format ...") d = DalvikVMFormat(data) log.debug("added DEX:%s" % digest) self.analyzed_files[filename].append(digest) self.analyzed_digest[digest] = filename self.analyzed_dex[digest] = d if dx is None: dx = Analysis() dx.add(d) if not postpone_xref: dx.create_xref() # TODO: If multidex: this will called many times per dex, even if already set for d in dx.vms: # TODO: allow different decompiler here! d.set_decompiler(DecompilerDAD(d, dx)) d.set_vmanalysis(dx) self.analyzed_vms[digest] = dx if self.export_ipython: log.debug("Exporting in ipython") d.create_python_export() return digest, d, dx
def addDEX(self, filename, data, dx=None): """ Add a DEX file to the Session and run analysis. :param filename: the (file)name of the DEX file :param data: binary data of the dex file :param dx: an existing Analysis Object (optional) :return: A tuple of SHA256 Hash, DalvikVMFormat Object and Analysis object """ digest = hashlib.sha256(data).hexdigest() log.debug("add DEX:%s" % digest) log.debug("Parsing format ...") d = DalvikVMFormat(data) log.debug("added DEX:%s" % digest) self.analyzed_files[filename].append(digest) self.analyzed_digest[digest] = filename self.analyzed_dex[digest] = d if dx is None: dx = Analysis() dx.add(d) dx.create_xref() # TODO: If multidex: this will called many times per dex, even if already set for d in dx.vms: # TODO: allow different decompiler here! d.set_decompiler(DecompilerDAD(d, dx)) d.set_vmanalysis(dx) self.analyzed_vms[digest] = dx if self.export_ipython: log.debug("Exporting in ipython") d.create_python_export() return digest, d, dx
class PDG(): def __init__(self, filename): """ :type self: object """ self.filename = filename try: self.a = APK(filename) self.d = DalvikVMFormat(self.a.get_dex()) self.d.create_python_export() self.dx = Analysis(self.d) except zipfile.BadZipfile: # if file is not an APK, may be a dex object _, self.d, self.dx = AnalyzeDex(self.filename) self.d.set_vmanalysis(self.dx) self.dx.create_xref() self.fcg = self.dx.get_call_graph() self.icfg = self.build_icfg() def get_graph(self): return self.icfg def build_icfg(self): icfg = nx.DiGraph() methods = self.d.get_methods() for method in methods: for bb in self.dx.get_method(method).basic_blocks.get(): children = [] label = self.get_bb_label(bb) children = self.get_children(bb, self.dx) icfg.add_node(label) icfg.add_edges_from([(label, child) for child in children]) return icfg def get_bb_label(self, bb): """ Return the descriptive name of a basic block """ return self.get_method_label(bb.method) + (bb.name, ) def get_method_label(self, method): """ Return the descriptive name of a method """ return (method.get_class_name(), method.get_name(), method.get_descriptor()) def get_children(self, bb, dx): """ Return the labels of the basic blocks that are children of the input basic block in and out of its method """ return self.get_bb_intra_method_children( bb) + self.get_bb_extra_method_children(bb, dx) def get_bb_intra_method_children(self, bb): """ Return the labels of the basic blocks that are children of the input basic block within a method """ child_labels = [] for c_in_bb in bb.get_next(): next_bb = c_in_bb[2] child_labels.append(self.get_bb_label(next_bb)) return child_labels def get_bb_extra_method_children(self, bb, dx): """ Given a basic block, find the calls to external methods and return the label of the first basic block in these methods """ call_labels = [] # iterate over calls from bb method to external methods try: xrefs = dx.get_method_analysis(bb.method).get_xref_to() except AttributeError: return call_labels for xref in xrefs: remote_method_offset = xref[2] if self.call_in_bb(bb, remote_method_offset): try: remote_method = dx.get_method( self.d.get_method_by_idx(remote_method_offset)) if remote_method: remote_bb = next(remote_method.basic_blocks.get()) call_labels.append(self.get_bb_label(remote_bb)) except StopIteration: pass return call_labels def call_in_bb(self, bb, idx): return bb.get_start() <= idx <= bb.get_end()
if depth == 0: print(m.class_name + " -> " + m.name) for item in m.XREFfrom.items: if item[0].class_name != class_name or item[ 0].name != method_name: for x in range(1, depth): sys.stdout.write('--') sys.stdout.write('>' + item[0].class_name + "->" + item[0].name + "\n") XrefTraverse(methods, item[0].class_name, item[0].name, depth) if len(sys.argv) > 2: filename = sys.argv[1] class_name = sys.argv[2] class_name = 'L' + class_name.replace(".", "/") + ";" #print class_name method_name = '<init>' d = DalvikVMFormat(APK(filename, False).get_dex()) d.create_python_export() dx = uVMAnalysis(d) gx = GVMAnalysis(dx, None) d.set_vmanalysis(dx) d.set_gvmanalysis(gx) d.create_xref() XrefTraverse(d.get_methods(), class_name, method_name, 0) else: print "usage: XrefTree.py [filename] [class_name]" print "usage: XrefTree.py filename.apk com.xyz.abc"
class FCG(): ##/////////////Changed for testing///////////////////// def __init__(self, filename): self.filename = filename # print(os.path.exists(filename)) # a,d,dx = AnalyzeAPK(filename) # print(dx.get_call_graph()) try: self.a = APK(filename) self.d = DalvikVMFormat(self.a.get_dex()) self.d.create_python_export() self.dx = Analysis(self.d) except zipfile.BadZipfile: # if file is not an APK, may be a dex object _, self.d, self.dx = AnalyzeDex(self.filename) self.d.set_vmanalysis(self.dx) self.dx.create_xref() self.fcg = self.build_fcg() def get_fcg(self): return self.fcg def get_lock_graph(self): graph_list = [] # print("LockGraphs", self.dx) call_graph = self.dx.get_call_graph() # print("Call Graphs") for m in (self.dx.find_methods( classname='Landroid.os.PowerManager.WakeLock' )): ##//////////Work fine but found 3 method so will use when done # print("Method=", m.get_method()) ancestors = nx.ancestors(call_graph, m.get_method()) ancestors.add(m.get_method()) graph = call_graph.subgraph(ancestors) graph_list.append(graph) wake_graph = nx.compose_all(graph_list) return wake_graph def build_fcg(self): """ Using NX and Androguard, build a directed graph NX object so that: - node names are analysis.MethodClassAnalysis objects - each node has a label that encodes the method behavior """ fcg = self.get_lock_graph() ##/////////My changes/////////////// for n in fcg.nodes: instructions = [] try: ops = n.get_instructions() for i in ops: instructions.append(i.get_name()) encoded_label = self.color_instructions(instructions) except AttributeError: encoded_label = np.array([0] * 15) fcg.node[n]["label"] = encoded_label return fcg def color_instructions(self, instructions): """ Node label based on coloring technique by Kruegel """ h = [0] * len(INSTRUCTION_CLASS_COLOR) for i in instructions: h[INSTRUCTION_SET_COLOR[i]] = 1 return np.array(h) def get_classes_from_label(self, label): classes = [ INSTRUCTION_CLASSES[i] for i in range(len(label)) if label[i] == 1 ] return classes
def XrefTraverse(methods, class_name, method_name, depth): depth += 1 for m in methods: if m.class_name == class_name and m.name == method_name: if depth == 0: print (m.class_name + " -> " + m.name) for item in m.XREFfrom.items: if item[0].class_name != class_name or item[0].name != method_name: for x in range(1, depth): sys.stdout.write('--') sys.stdout.write ('>' + item[0].class_name + "->" + item[0].name + "\n") XrefTraverse(methods, item[0].class_name, item[0].name, depth) if len(sys.argv) > 2: filename = sys.argv[1] class_name = sys.argv[2] class_name = 'L' + class_name.replace(".", "/") + ";" #print class_name method_name = '<init>' d = DalvikVMFormat(APK(filename, False).get_dex()) d.create_python_export() dx = uVMAnalysis(d) gx = GVMAnalysis(dx, None) d.set_vmanalysis(dx) d.set_gvmanalysis(gx) d.create_xref() XrefTraverse(d.get_methods(), class_name, method_name, 0) else: print "usage: XrefTree.py [filename] [class_name]" print "usage: XrefTree.py filename.apk com.xyz.abc"