mirror of
https://github.com/androguard/androguard.git
synced 2024-11-27 06:50:41 +00:00
adding simple is_android_api methods
This commit is contained in:
parent
b1ccfe11a4
commit
861a62139b
@ -453,6 +453,9 @@ class MethodClassAnalysis:
|
||||
self.xrefto = set()
|
||||
self.xreffrom = set()
|
||||
|
||||
# Reserved for further use
|
||||
self.apilist = None
|
||||
|
||||
def AddXrefTo(self, classobj, methodobj, offset):
|
||||
"""
|
||||
Add a crossreference to another method
|
||||
@ -507,6 +510,34 @@ class MethodClassAnalysis:
|
||||
"""
|
||||
return isinstance(self.method, ExternalMethod)
|
||||
|
||||
def is_android_api(self):
|
||||
"""
|
||||
Returns True if the method seems to be an Android API method.
|
||||
|
||||
This method might be not very precise unless an list of known API methods
|
||||
is given.
|
||||
|
||||
:return: boolean
|
||||
"""
|
||||
if not self.is_external():
|
||||
# Method must be external to be an API
|
||||
return False
|
||||
|
||||
# Packages found at https://developer.android.com/reference/packages.html
|
||||
api_candidates = ["Landroid/", "Lcom/android/internal/util", "Ldalvik/", "Ljava/", "Ljavax/", "Lorg/apache/",
|
||||
"Lorg/json/", "Lorg/w3c/dom/", "Lorg/xml/sax", "Lorg/xmlpull/v1/", "Ljunit/"]
|
||||
|
||||
if self.apilist:
|
||||
# FIXME: This will not work... need to introduce a name for lookup (like EncodedMethod.__str__ but without
|
||||
# the offsert! Such a name is also needed for the lookup in permissions
|
||||
return self.method.get_name() in self.apilist
|
||||
else:
|
||||
for candidate in api_candidates:
|
||||
if self.method.get_class_name().startswith(candidate):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def get_method(self):
|
||||
"""
|
||||
Return the `EncodedMethod` object that relates to this object
|
||||
@ -529,7 +560,7 @@ class MethodClassAnalysis:
|
||||
|
||||
def __repr__(self):
|
||||
return "<analysis.MethodClassAnalysis {}{}>".format(self.method,
|
||||
" EXTERNAL" if isinstance(self.method, ExternalMethod) else "")
|
||||
" EXTERNAL" if isinstance(self.method, ExternalMethod) else "")
|
||||
|
||||
|
||||
class FieldClassAnalysis:
|
||||
@ -666,7 +697,7 @@ class ClassAnalysis:
|
||||
:param classobj: class:`~androguard.core.bytecode.dvm.ClassDefItem` or :class:`ExternalClass`
|
||||
"""
|
||||
|
||||
# Automaticallt decide if the class is external or not
|
||||
# Automatically decide if the class is external or not
|
||||
self.external = isinstance(classobj, ExternalClass)
|
||||
|
||||
self.orig_class = classobj
|
||||
@ -677,6 +708,9 @@ class ClassAnalysis:
|
||||
self.xrefto = collections.defaultdict(set)
|
||||
self.xreffrom = collections.defaultdict(set)
|
||||
|
||||
# Reserved for further use
|
||||
self.apilist = None
|
||||
|
||||
def is_external(self):
|
||||
"""
|
||||
Tests wheather this class is an external class
|
||||
@ -685,6 +719,34 @@ class ClassAnalysis:
|
||||
"""
|
||||
return self.external
|
||||
|
||||
def is_android_api(self):
|
||||
"""
|
||||
Tries to guess if the current class is an Android API class.
|
||||
|
||||
This might be not very precise unless an apilist is given, with classes that
|
||||
are in fact known APIs.
|
||||
Such a list might be generated by using the android.jar files.
|
||||
|
||||
:return: boolean
|
||||
"""
|
||||
|
||||
# Packages found at https://developer.android.com/reference/packages.html
|
||||
api_candidates = ["Landroid/", "Lcom/android/internal/util", "Ldalvik/", "Ljava/", "Ljavax/", "Lorg/apache/",
|
||||
"Lorg/json/", "Lorg/w3c/dom/", "Lorg/xml/sax", "Lorg/xmlpull/v1/", "Ljunit/"]
|
||||
|
||||
if not self.is_external():
|
||||
# API must be external
|
||||
return False
|
||||
|
||||
if self.apilist:
|
||||
return self.orig_class.get_name() in self.apilist
|
||||
else:
|
||||
for candidate in api_candidates:
|
||||
if self.orig_class.get_name().startswith(candidate):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def get_methods(self):
|
||||
"""
|
||||
Return all `MethodClassAnalysis` objects of this class
|
||||
|
@ -176,36 +176,37 @@ def PrettyShow(m_a, basic_blocks, notes={}):
|
||||
print_fct("\n")
|
||||
|
||||
|
||||
def method2dot(mx, colors={}):
|
||||
def method2dot(mx, colors=None):
|
||||
"""
|
||||
Export analysis method to dot format
|
||||
Export analysis method to dot format
|
||||
|
||||
@param mx : MethodAnalysis object
|
||||
@param colors : MethodAnalysis object
|
||||
:param mx: :class:`~androguard.core.analysis.analysis.MethodAnalysis`
|
||||
:param colors: dict of colors to use, if colors is None the default colors are used
|
||||
|
||||
@rtype : dot format buffer (it is a subgraph (dict))
|
||||
:returns: a string which contains the dot graph
|
||||
"""
|
||||
|
||||
colors = colors or {
|
||||
"true_branch": "green",
|
||||
"false_branch": "red",
|
||||
"default_branch": "purple",
|
||||
"jump_branch": "blue",
|
||||
"bg_idx": "lightgray",
|
||||
"idx": "blue",
|
||||
"bg_start_idx": "yellow",
|
||||
"bg_instruction": "lightgray",
|
||||
"instruction_name": "black",
|
||||
"instructions_operands": "yellow",
|
||||
"raw": "red",
|
||||
"string": "red",
|
||||
"literal": "green",
|
||||
"offset": "#4000FF",
|
||||
"method": "#DF3A01",
|
||||
"field": "#088A08",
|
||||
"type": "#0000FF",
|
||||
"registers_range": ("#999933", "#6666FF")
|
||||
}
|
||||
if not colors:
|
||||
colors = {
|
||||
"true_branch": "green",
|
||||
"false_branch": "red",
|
||||
"default_branch": "purple",
|
||||
"jump_branch": "blue",
|
||||
"bg_idx": "lightgray",
|
||||
"idx": "blue",
|
||||
"bg_start_idx": "yellow",
|
||||
"bg_instruction": "lightgray",
|
||||
"instruction_name": "black",
|
||||
"instructions_operands": "yellow",
|
||||
"raw": "red",
|
||||
"string": "red",
|
||||
"literal": "green",
|
||||
"offset": "#4000FF",
|
||||
"method": "#DF3A01",
|
||||
"field": "#088A08",
|
||||
"type": "#0000FF",
|
||||
"registers_range": ("#999933", "#6666FF")
|
||||
}
|
||||
|
||||
node_tpl = "\nstruct_%s [label=<\n<TABLE BORDER=\"0\" CELLBORDER=\"0\" CELLSPACING=\"3\">\n%s</TABLE>>];\n"
|
||||
label_tpl = "<TR><TD ALIGN=\"LEFT\" BGCOLOR=\"%s\"> <FONT FACE=\"Times-Bold\" color=\"%s\">%x</FONT> </TD><TD ALIGN=\"LEFT\" BGCOLOR=\"%s\"> <FONT FACE=\"Times-Bold\" color=\"%s\">%s </FONT> %s </TD></TR>\n"
|
||||
@ -243,8 +244,7 @@ def method2dot(mx, colors={}):
|
||||
|
||||
for DVMBasicMethodBlock in mx.basic_blocks.gets():
|
||||
ins_idx = DVMBasicMethodBlock.start
|
||||
block_id = hashlib.md5(bytearray(sha256 + DVMBasicMethodBlock.get_name(
|
||||
), "UTF-8")).hexdigest()
|
||||
block_id = hashlib.md5(bytearray(sha256 + DVMBasicMethodBlock.get_name(), "UTF-8")).hexdigest()
|
||||
|
||||
content = link_tpl % 'header'
|
||||
|
||||
@ -252,12 +252,10 @@ def method2dot(mx, colors={}):
|
||||
if DVMBasicMethodBlockInstruction.get_op_value(
|
||||
) == 0x2b or DVMBasicMethodBlockInstruction.get_op_value() == 0x2c:
|
||||
new_links.append((DVMBasicMethodBlock, ins_idx,
|
||||
DVMBasicMethodBlockInstruction.get_ref_off(
|
||||
) * 2 + ins_idx))
|
||||
DVMBasicMethodBlockInstruction.get_ref_off() * 2 + ins_idx))
|
||||
elif DVMBasicMethodBlockInstruction.get_op_value() == 0x26:
|
||||
new_links.append((DVMBasicMethodBlock, ins_idx,
|
||||
DVMBasicMethodBlockInstruction.get_ref_off(
|
||||
) * 2 + ins_idx))
|
||||
DVMBasicMethodBlockInstruction.get_ref_off() * 2 + ins_idx))
|
||||
|
||||
operands = DVMBasicMethodBlockInstruction.get_operands(ins_idx)
|
||||
output = ", ".join(mx.get_vm().get_operand_html(
|
||||
@ -359,12 +357,12 @@ def method2dot(mx, colors={}):
|
||||
|
||||
def method2format(output, _format="png", mx=None, raw=None):
|
||||
"""
|
||||
Export method to a specific file format
|
||||
Export method to a specific file format
|
||||
|
||||
@param output : output filename
|
||||
@param _format : format type (png, jpg ...) (default : png)
|
||||
@param mx : specify the MethodAnalysis object
|
||||
@param raw : use directly a dot raw buffer if None
|
||||
@param output : output filename
|
||||
@param _format : format type (png, jpg ...) (default : png)
|
||||
@param mx : specify the MethodAnalysis object
|
||||
@param raw : use directly a dot raw buffer if None
|
||||
"""
|
||||
# pydot is optional!
|
||||
import pydot
|
||||
@ -379,8 +377,7 @@ def method2format(output, _format="png", mx=None, raw=None):
|
||||
data = method2dot(mx)
|
||||
|
||||
# subgraphs cluster
|
||||
buff += "subgraph cluster_" + hashlib.md5(bytearray(output, "UTF-8")).hexdigest(
|
||||
) + " {\nlabel=\"%s\"\n" % data['name']
|
||||
buff += "subgraph cluster_" + hashlib.md5(bytearray(output, "UTF-8")).hexdigest() + " {\nlabel=\"%s\"\n" % data['name']
|
||||
buff += data['nodes']
|
||||
buff += "}\n"
|
||||
|
||||
@ -395,14 +392,14 @@ def method2format(output, _format="png", mx=None, raw=None):
|
||||
|
||||
def method2png(output, mx, raw=False):
|
||||
"""
|
||||
Export method to a png file format
|
||||
Export method to a png file format
|
||||
|
||||
:param output: output filename
|
||||
:type output: string
|
||||
:param mx: specify the MethodAnalysis object
|
||||
:type mx: :class:`MethodAnalysis` object
|
||||
:param raw: use directly a dot raw buffer
|
||||
:type raw: string
|
||||
:param output: output filename
|
||||
:type output: string
|
||||
:param mx: specify the MethodAnalysis object
|
||||
:type mx: :class:`MethodAnalysis` object
|
||||
:param raw: use directly a dot raw buffer
|
||||
:type raw: string
|
||||
"""
|
||||
buff = raw
|
||||
if not raw:
|
||||
@ -413,14 +410,14 @@ def method2png(output, mx, raw=False):
|
||||
|
||||
def method2jpg(output, mx, raw=False):
|
||||
"""
|
||||
Export method to a jpg file format
|
||||
Export method to a jpg file format
|
||||
|
||||
:param output: output filename
|
||||
:type output: string
|
||||
:param mx: specify the MethodAnalysis object
|
||||
:type mx: :class:`MethodAnalysis` object
|
||||
:param raw: use directly a dot raw buffer (optional)
|
||||
:type raw: string
|
||||
:param output: output filename
|
||||
:type output: string
|
||||
:param mx: specify the MethodAnalysis object
|
||||
:type mx: :class:`MethodAnalysis` object
|
||||
:param raw: use directly a dot raw buffer (optional)
|
||||
:type raw: string
|
||||
"""
|
||||
buff = raw
|
||||
if not raw:
|
||||
@ -430,6 +427,12 @@ def method2jpg(output, mx, raw=False):
|
||||
|
||||
|
||||
def vm2json(vm):
|
||||
"""
|
||||
Get a JSON representation of a DEX file
|
||||
|
||||
:param vm: :class:`~androguard.core.bytecodes.dvm.DalvikVMFormat`
|
||||
:return:
|
||||
"""
|
||||
d = {"name": "root", "children": []}
|
||||
|
||||
for _class in vm.get_classes():
|
||||
@ -455,12 +458,24 @@ class TmpBlock(object):
|
||||
|
||||
|
||||
def method2json(mx, directed_graph=False):
|
||||
"""
|
||||
Create directed or undirected graph in the json format.
|
||||
|
||||
:param mx: :class:`~androguard.core.analysis.analysis.MethodAnalysis`
|
||||
:param directed_graph: True if a directed graph should be created (default: False)
|
||||
:return:
|
||||
"""
|
||||
if directed_graph:
|
||||
return method2json_direct(mx)
|
||||
return method2json_undirect(mx)
|
||||
|
||||
|
||||
def method2json_undirect(mx):
|
||||
"""
|
||||
|
||||
:param mx: :class:`~androguard.core.analysis.analysis.MethodAnalysis`
|
||||
:return:
|
||||
"""
|
||||
d = {}
|
||||
reports = []
|
||||
d["reports"] = reports
|
||||
@ -488,6 +503,11 @@ def method2json_undirect(mx):
|
||||
|
||||
|
||||
def method2json_direct(mx):
|
||||
"""
|
||||
|
||||
:param mx: :class:`~androguard.core.analysis.analysis.MethodAnalysis`
|
||||
:return:
|
||||
"""
|
||||
d = {}
|
||||
reports = []
|
||||
d["reports"] = reports
|
||||
@ -496,10 +516,8 @@ def method2json_direct(mx):
|
||||
|
||||
l = []
|
||||
for DVMBasicMethodBlock in mx.basic_blocks.gets():
|
||||
for index, DVMBasicMethodBlockChild in enumerate(
|
||||
DVMBasicMethodBlock.childs):
|
||||
if DVMBasicMethodBlock.get_name(
|
||||
) == DVMBasicMethodBlockChild[-1].get_name():
|
||||
for index, DVMBasicMethodBlockChild in enumerate(DVMBasicMethodBlock.childs):
|
||||
if DVMBasicMethodBlock.get_name() == DVMBasicMethodBlockChild[-1].get_name():
|
||||
|
||||
preblock = TmpBlock(DVMBasicMethodBlock.get_name() + "-pre")
|
||||
|
||||
@ -560,12 +578,9 @@ def method2json_direct(mx):
|
||||
for DVMBasicMethodBlockChild in DVMBasicMethodBlock.childs:
|
||||
ok = False
|
||||
if DVMBasicMethodBlock.get_name() in hooks:
|
||||
if DVMBasicMethodBlockChild[-1] in hooks[
|
||||
DVMBasicMethodBlock.get_name()
|
||||
]:
|
||||
if DVMBasicMethodBlockChild[-1] in hooks[DVMBasicMethodBlock.get_name()]:
|
||||
ok = True
|
||||
cblock["Edge"].append(hooks[DVMBasicMethodBlock.get_name(
|
||||
)][0].get_name())
|
||||
cblock["Edge"].append(hooks[DVMBasicMethodBlock.get_name()][0].get_name())
|
||||
|
||||
if not ok:
|
||||
cblock["Edge"].append(DVMBasicMethodBlockChild[-1].get_name())
|
||||
|
Loading…
Reference in New Issue
Block a user