mirror of
https://github.com/androguard/androguard.git
synced 2024-11-23 13:09:55 +00:00
export to ipython will probably not go into this release...
This commit is contained in:
parent
c22ccf799d
commit
f723a57d75
@ -459,8 +459,19 @@ class MethodClassAnalysis:
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Returns the name of this method"""
|
||||
return self.method.get_name()
|
||||
|
||||
@property
|
||||
def descriptor(self):
|
||||
"""Returns the type descriptor for this method"""
|
||||
return self.method.get_descriptor()
|
||||
|
||||
@property
|
||||
def access(self):
|
||||
"""Returns the access flags to the method as a string"""
|
||||
return self.method.get_access_flags_string()
|
||||
|
||||
def AddXrefTo(self, classobj, methodobj, offset):
|
||||
"""
|
||||
Add a crossreference to another method
|
||||
@ -1433,48 +1444,47 @@ class Analysis:
|
||||
|
||||
def create_ipython_exports(self):
|
||||
"""
|
||||
Creates attributes for all classes, methods, fields and strings on the Analysis object itself.
|
||||
.. warning:: this feature is experimental and is currently not enabled by default! Use with caution!
|
||||
|
||||
Creates attributes for all classes, methods and fields on the Analysis object itself.
|
||||
This makes it easier to work with Analysis module in an iPython shell.
|
||||
|
||||
Classes can be search by typing :code:`dx.CLASS_<tab>`, as each class is added via this attribute name.
|
||||
Each class will have all methods attached to it via :code:`dx.CLASS_Foobar.METHOD_<tab>`.
|
||||
Fields have a similar syntax: :code:`dx.CLASS_Foobar.FIELD_<tab>`.
|
||||
|
||||
Strings are added directly to the dx object, similar to classes: :code:`dx.STR_<tab>`.
|
||||
As strings might be very long, they are truncated to 64 characters.
|
||||
|
||||
.. todo:: If strings do contain the same first 64 chars, a number is appended to the string.
|
||||
As Strings can contain nearly anything, use :meth:`find_strings` instead.
|
||||
|
||||
* Each `CLASS_` item will return a :class:`~ClassAnalysis`
|
||||
* Each `METHOD_` item will return a :class:`~MethodClassAnalysis`
|
||||
* Each `FIELD_` item will return a :class:`~FieldClassAnalysis`
|
||||
* Each `STR_` item will return a :class:`~StringAnalysis`
|
||||
"""
|
||||
|
||||
# TODO: it would be fun to have the classes organized like the packages. I.e. you could do dx.CLASS_xx.yyy.zzz
|
||||
for cls in self.get_classes():
|
||||
name = "CLASS_" + bytecode.FormatClassToPython(cls.name)
|
||||
if hasattr(self, name):
|
||||
log.warning("Already existing!")
|
||||
log.warning("Already existing class {}!".format(name))
|
||||
setattr(self, name, cls)
|
||||
|
||||
for meth in cls.get_methods():
|
||||
mname = "METH_" + bytecode.FormatNameToPython(meth.name)
|
||||
method_name = meth.name
|
||||
if method_name in ["<init>", "<clinit>"]:
|
||||
_, method_name = bytecode.get_package_class_name(cls.name)
|
||||
|
||||
# FIXME this naming schema is not very good... but to describe a method uniquely, we need all of it
|
||||
mname = "METH_" + method_name + "_" + bytecode.FormatDescriptorToPython(meth.access) + "_" + bytecode.FormatDescriptorToPython(meth.descriptor)
|
||||
if hasattr(cls, mname):
|
||||
log.warning("already existing method: {} at class {}".format(mname, name))
|
||||
setattr(cls, mname, meth)
|
||||
|
||||
# FIXME: syntetic classes produce problems here.
|
||||
# If the field name is the same in the parent as in the syntetic one, we can only add one!
|
||||
for field in cls.get_fields():
|
||||
mname = "FIELD_" + bytecode.FormatNameToPython(field.name)
|
||||
if hasattr(cls, mname):
|
||||
log.warning("already existing field: {} at class {}".format(mname, name))
|
||||
setattr(cls, mname, field)
|
||||
|
||||
for s in self.get_strings():
|
||||
name = "STR_" + bytecode.FormatNameToPython(s[:64])
|
||||
if hasattr(self, mname):
|
||||
log.warning("already existing string: {}".format(name))
|
||||
setattr(self, name, s)
|
||||
|
||||
|
||||
def is_ascii_obfuscation(vm):
|
||||
"""
|
||||
|
@ -894,6 +894,34 @@ def FormatClassToPython(i):
|
||||
return i
|
||||
|
||||
|
||||
def get_package_class_name(name):
|
||||
"""
|
||||
Return package and class name in a java variant from a typed variant name.
|
||||
|
||||
If no package could be found, the package is an empty string.
|
||||
|
||||
example::
|
||||
|
||||
>>> get_package_class_name('Ljava/lang/Object;')
|
||||
('java.lang', 'Object')
|
||||
|
||||
:param name: the name
|
||||
:rtype: tuple
|
||||
:return:
|
||||
"""
|
||||
if name[0] != 'L' and name[-1] != ';':
|
||||
raise ValueError("The name '{}' does not look like a typed name!".format(name))
|
||||
|
||||
name = name[1:-1]
|
||||
if '/' not in name:
|
||||
return '', name
|
||||
|
||||
package, clsname = name.rsplit('/', 1)
|
||||
package = package.replace('/', '.')
|
||||
|
||||
return package, clsname
|
||||
|
||||
|
||||
def FormatNameToPython(i):
|
||||
"""
|
||||
Transform a (method) name into a form which can be used as a python
|
||||
|
@ -20,6 +20,22 @@ class MiscTest(unittest.TestCase):
|
||||
with tempfile.NamedTemporaryFile() as fp:
|
||||
self.assertEqual(fp.name + "_0", clean_file_name(fp.name, unique=True))
|
||||
|
||||
def testClassNameFormatting(self):
|
||||
from androguard.core.bytecode import get_package_class_name
|
||||
|
||||
self.assertEqual(get_package_class_name('Ljava/lang/Object;'), ('java.lang', 'Object'))
|
||||
self.assertEqual(get_package_class_name('LFoobar;'), ('', 'Foobar'))
|
||||
self.assertEqual(get_package_class_name('Lsdflkjdsklfjsdkjfklsdjfkljsdkflsd/shdfjksdhkjfhsdkjfsh;'),
|
||||
('sdflkjdsklfjsdkjfklsdjfkljsdkflsd', 'shdfjksdhkjfhsdkjfsh'))
|
||||
self.assertEqual(get_package_class_name('L;'), ('', ''))
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
get_package_class_name('Foobar')
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
get_package_class_name('java.lang.Object')
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
Reference in New Issue
Block a user