Merge pull request #982 from androguard/improve_tests_part_c

adding the rest of the tests
This commit is contained in:
erev0s 2023-12-30 00:08:22 +01:00 committed by GitHub
commit 506da27aa1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 210 additions and 333 deletions

View File

@ -25,7 +25,7 @@ jobs:
run: poetry install
- name: Run unittest tests
run: poetry run python -m unittest tests/test_apk.py tests/test_axml.py
run: poetry run python -m unittest discover -s tests -p 'test_*.py'
- name: Build with Poetry
run: |

View File

@ -27,7 +27,7 @@ jobs:
run: poetry install
- name: Run unittest tests
run: poetry run python -m unittest tests/test_apk.py tests/test_axml.py
run: poetry run python -m unittest discover -s tests -p 'test_*.py'
- name: Build with Poetry
run: |

View File

@ -1,13 +0,0 @@
### 4.0.1 - 21/12/2023
- Update/fix tests for axml and apk and add necessary resources
- Update readme.md
- Added github action to run tests when a new PR is requested
- Fix for https://github.com/androguard/androguard/issues/963
- Fix for https://github.com/androguard/androguard/issues/970
- Multi disk check in V2/3 signature check converted to only throw a warning
- axml processing now covers also attributes start and size
- AOSP permissions updated to reach API 34
### 4.0.0 - 14/12/2023
- First release after 3.4.0a1 from 2020

View File

@ -7982,7 +7982,6 @@ class DEX:
:rtype: a list with all :class:`EncodedMethod` objects
"""
# TODO could use a generator here
name = bytes(name)
prog = re.compile(name)
l = []
for i in self.get_classes():
@ -8000,7 +7999,6 @@ class DEX:
:rtype: a list with all :class:`EncodedField` objects
"""
# TODO could use a generator here
name = bytes(name)
prog = re.compile(name)
l = []
for i in self.get_classes():

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
tests/data/APK/Test.dex Normal file

Binary file not shown.

View File

@ -5,6 +5,7 @@ from binascii import hexlify
# Output format will be:
# <class name> <method name> <bytecode as hex string>
import sys
sys.path.append('.')
from androguard.core.dex import readuleb128, readsleb128, DalvikPacker
@ -19,13 +20,16 @@ def read_null_terminated(f):
else:
x.append(ord(z))
class MockClassManager():
@property
def packer(self):
return DalvikPacker(0x12345678)
cm = MockClassManager()
class read_dex:
def __init__(self, fname):
@ -83,7 +87,6 @@ class read_dex:
method_idx += method_idx_diff
methods.append([method_idx, code_off])
# Read the string section
strings = dict()
self.str_raw = dict()
@ -112,8 +115,6 @@ class read_dex:
class_idx, proto_idx, name_idx = unpack("<HHI", f.read(8))
method_ids[i] = [strings[self.types[class_idx]], strings[name_idx]]
# Now parse the found methods and print to stdout
mres = dict()
for method_idx, code_off in methods:
@ -159,5 +160,3 @@ if __name__ == "__main__":
for midx, buff in read_dex(sys.argv[1]).methods.items():
pass
# print(midx, buff)

View File

@ -1,16 +1,19 @@
import os
import unittest
import sys
from androguard.core.bytecodes import dvm
from androguard.core.dex import DEX
test_dir = os.path.dirname(os.path.abspath(__file__))
class AnnotationTest(unittest.TestCase):
def testAnnotation(self):
with open("examples/android/TestsAnnotation/classes.dex", "rb") as f:
d = dvm.DEX(f.read())
with open(os.path.join(test_dir, 'data/APK/Annotation_classes.dex'), "rb") as f:
d = DEX(f.read())
clazz = d.get_class('Landroid/support/v4/widget/SlidingPaneLayout$SlidingPanelLayoutImplJB;')
annotations = clazz._get_annotation_type_ids()
self.assertIn('Landroid/support/annotation/RequiresApi;', [clazz.CM.get_type(annotation.type_idx) for annotation in annotations])
self.assertIn('Landroid/support/annotation/RequiresApi;',
[clazz.CM.get_type(annotation.type_idx) for annotation in annotations])
self.assertIn('Landroid/support/annotation/RequiresApi;', clazz.get_annotations())

View File

@ -294,7 +294,6 @@ class APKTest(unittest.TestCase):
self.assertEqual(hashlib.sha256(c).hexdigest(), h)
if a.is_signed_v3():
print(apath)
if apath == "weird-compression-method.apk":
with self.assertRaises(NotImplementedError):
a.get_certificates_der_v3()

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
import os
import unittest
from lxml import etree
import sys
sys.path.append('.')
test_dir = os.path.dirname(os.path.abspath(__file__))
from androguard.core import apk, axml
from operator import itemgetter
@ -29,8 +29,7 @@ TEST_CONFIGS = {
class ARSCTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
with open("examples/android/TestsAndroguard/bin/TestActivity.apk",
"rb") as fd:
with open(os.path.join(test_dir, 'data/APK/TestActivity.apk'), "rb") as fd:
cls.apk = apk.APK(fd.read(), True)
def testARSC(self):
@ -79,7 +78,8 @@ class ARSCTest(unittest.TestCase):
"""
Test if the resolving of different string locales works
"""
a = APK("examples/tests/a2dp.Vol_137.apk")
a = apk.APK(os.path.join(test_dir, 'data/APK/a2dp.Vol_137.apk'))
arsc = a.get_android_resources()
p = arsc.get_packages_names()[0]
@ -122,7 +122,7 @@ class ARSCTest(unittest.TestCase):
"received unexpected resource types: %s" % unexpected_types)
def testFallback(self):
a = apk.APK("examples/tests/com.teleca.jamendo_35.apk")
a = apk.APK(os.path.join(test_dir, 'data/APK/com.teleca.jamendo_35.apk'))
# Should use the fallback
self.assertEqual(a.get_app_name(), "Jamendo")
@ -135,11 +135,15 @@ class ARSCTest(unittest.TestCase):
# With default config, but fallback
self.assertEqual(len(res_parser.get_res_configs(res_id, axml.ARSCResTableConfig.default_config())), 1)
# With default config but no fallback
self.assertEqual(len(res_parser.get_res_configs(res_id, axml.ARSCResTableConfig.default_config(), fallback=False)), 0)
self.assertEqual(
len(res_parser.get_res_configs(res_id, axml.ARSCResTableConfig.default_config(), fallback=False)), 0)
# Also test on resolver:
self.assertListEqual(list(map(itemgetter(1), res_parser.get_resolved_res_configs(res_id))), ["Jamendo", "Jamendo"])
self.assertListEqual(list(map(itemgetter(1), res_parser.get_resolved_res_configs(res_id, axml.ARSCResTableConfig.default_config()))), ["Jamendo"])
self.assertListEqual(list(map(itemgetter(1), res_parser.get_resolved_res_configs(res_id))),
["Jamendo", "Jamendo"])
self.assertListEqual(list(
map(itemgetter(1), res_parser.get_resolved_res_configs(res_id, axml.ARSCResTableConfig.default_config()))),
["Jamendo"])
def testIDParsing(self):
parser = axml.ARSCParser.parse_id

View File

@ -1,22 +1,24 @@
import unittest
from androguard.misc import AnalyzeDex
import sys
import os
import re
from androguard.misc import AnalyzeAPK
from androguard.decompiler.decompile import DvMethod, DvClass
test_dir = os.path.dirname(os.path.abspath(__file__))
class DecompilerTest(unittest.TestCase):
def testSimplification(self):
h, d, dx = AnalyzeDex("examples/tests/Test.dex")
h, d, dx = AnalyzeDex(os.path.join(test_dir, 'data/APK/Test.dex'))
z, = d.get_classes()
self.assertIn("return ((23 - p3) | ((p3 + 66) & 26));", z.get_source())
def testArrays(self):
h, d, dx = AnalyzeDex("examples/tests/FillArrays.dex")
h, d, dx = AnalyzeDex(os.path.join(test_dir, 'data/APK/FillArrays.dex'))
z, = d.get_classes()
@ -29,29 +31,9 @@ class DecompilerTest(unittest.TestCase):
# Failed version of short array
self.assertNotIn("{5, 0, 10, 0};", z.get_source())
def dvmethod(c, dx, doAST=False):
for m in c.get_methods():
mx = dx.get_method(m)
ms = DvMethod(mx)
ms.process(doAST=doAST)
if doAST:
assert ms.get_ast() is not None
assert isinstance(ms.get_ast(), dict)
assert 'body' in ms.get_ast()
else:
assert ms.get_source() is not None
def dvclass(c, dx):
dc = DvClass(c, dx)
dc.process()
assert dc.get_source() is not None
def test_all_decompiler():
def test_all_decompiler(self):
# Generate test cases for this APK:
a, d, dx = AnalyzeAPK("examples/tests/hello-world.apk")
a, d, dx = AnalyzeAPK(os.path.join(test_dir, 'data/APK/hello-world.apk'))
for c in d[0].get_classes():
test_name = re.sub("[^a-zA-Z0-9_]", "_", str(c.get_name())[1:-1])
# Test the decompilation of a single class
@ -71,5 +53,25 @@ def test_all_decompiler():
yield dvmethod, c, dx, True
def dvmethod(c, dx, doAST=False):
for m in c.get_methods():
mx = dx.get_method(m)
ms = DvMethod(mx)
ms.process(doAST=doAST)
if doAST:
assert ms.get_ast() is not None
assert isinstance(ms.get_ast(), dict)
assert 'body' in ms.get_ast()
else:
assert ms.get_source() is not None
def dvclass(c, dx):
dc = DvClass(c, dx)
dc.process()
assert dc.get_source() is not None
if __name__ == '__main__':
unittest.main()

View File

@ -1,10 +1,9 @@
"""Tests for def_use."""
import sys
sys.path.append('.')
import os
from unittest import mock
import collections
import mock
import unittest
from androguard.decompiler import dataflow
@ -12,19 +11,10 @@ from androguard.decompiler import graph
from androguard.decompiler import instruction
from androguard.decompiler import basic_blocks
test_dir = os.path.dirname(os.path.abspath(__file__))
class DataflowTest(unittest.TestCase):
def assertItemsEqual(self, a, b):
"""
This method was renamed in python3.
To provide compability with python2,
we added this wrapper.
"""
try:
return super().assertItemsEqual(a, b)
except AttributeError as e:
return self.assertCountEqual(a, b)
def _CreateMockIns(self, uses, lhs=None):
mock_ins = mock.create_autospec(instruction.IRForm)
mock_ins.get_used_vars.return_value = uses
@ -162,7 +152,7 @@ class DataflowTest(unittest.TestCase):
}
self.assertDictEqual(analysis.A, expected_A)
self.assertDictEqual(analysis.R, expected_R)
self.assertItemsEqual(analysis.def_to_loc, expected_def_to_loc)
self.assertCountEqual(analysis.def_to_loc, expected_def_to_loc)
@mock.patch.object(dataflow, 'reach_def_analysis')
def testDefUseGCD(self, mock_reach_def):
@ -237,12 +227,12 @@ class DataflowTest(unittest.TestCase):
}
ud, du = dataflow.build_def_use(graph_mock, mock.sentinel)
self.assertItemsEqual(du, expected_du)
self.assertCountEqual(du, expected_du)
for entry in du:
self.assertItemsEqual(du[entry], expected_du[entry])
self.assertItemsEqual(ud, expected_ud)
self.assertCountEqual(du[entry], expected_du[entry])
self.assertCountEqual(ud, expected_ud)
for entry in ud:
self.assertItemsEqual(ud[entry], expected_ud[entry])
self.assertCountEqual(ud[entry], expected_ud[entry])
@mock.patch.object(dataflow, 'reach_def_analysis')
def testDefUseIfBool(self, mock_reach_def):
@ -307,7 +297,7 @@ class DataflowTest(unittest.TestCase):
ud, du = dataflow.build_def_use(graph_mock, mock.sentinel)
self.assertEqual(ud, expected_ud)
self.assertItemsEqual(du, expected_du)
self.assertCountEqual(du, expected_du)
def testGroupVariablesGCD(self):
du = {
@ -342,7 +332,7 @@ class DataflowTest(unittest.TestCase):
'ret': [([3, 8], [9])]
}
groups = dataflow.group_variables(['a', 'b', 'c', 'd', 'ret'], du, ud)
self.assertItemsEqual(groups, expected_groups)
self.assertCountEqual(groups, expected_groups)
def testGroupVariablesIfBool(self):
du = {
@ -371,9 +361,9 @@ class DataflowTest(unittest.TestCase):
2: [([-1], [1, 6])],
3: [([-2], [2, 3])]
}
self.assertItemsEqual(groups, expected_groups)
self.assertCountEqual(groups, expected_groups)
for entry in groups:
self.assertItemsEqual(groups[entry], expected_groups[entry])
self.assertCountEqual(groups[entry], expected_groups[entry])
@mock.patch.object(dataflow, 'group_variables')
def testSplitVariablesGCD(self, group_variables_mock):

View File

@ -1,8 +1,5 @@
"""Tests for graph."""
import sys
sys.path.append('.')
import unittest
from androguard.decompiler import graph

View File

@ -1,9 +1,5 @@
"""Tests for rpo."""
import sys
sys.path.append('.')
import unittest
from androguard.decompiler import graph
from androguard.decompiler import node

View File

@ -2,73 +2,9 @@ import unittest
import random
import binascii
from loguru import logger
import sys
sys.path.append("./")
from androguard.core import dex
class DexTest(unittest.TestCase):
def testBrokenDex(self):
"""Test various broken DEX headers"""
# really not a dex file
with self.assertRaises(ValueError) as cnx:
dex.DEX(b'\x00\x00\x00\x00\x00\x00\x00\x00')
self.assertIn('Header too small', str(cnx.exception))
# Adler32 will not match, zeroed out file
data_dex = binascii.unhexlify('6465780A303335001F6C4D5A6ACF889AF588F3237FC9F20B41F56A2408749D1B'
'C81E000070000000785634120000000000000000341E00009400000070000000'
'2E000000C0020000310000007803000011000000C4050000590000004C060000'
'090000001409000094140000340A0000' + ('00' * (7880 - 0x70)))
with self.assertRaises(ValueError) as cnx:
dex.DEX(data_dex)
self.assertIn("Adler32", str(cnx.exception))
# A very very basic dex file (without a map)
# But should parse...
data_dex = binascii.unhexlify('6465780A30333500460A4882696E76616C6964696E76616C6964696E76616C69'
'7000000070000000785634120000000000000000000000000000000000000000'
'0000000000000000000000000000000000000000000000000000000000000000'
'00000000000000000000000000000000')
self.assertIsNotNone(dex.DEX(data_dex))
# Wrong header size
data_dex = binascii.unhexlify('6465780A30333500480A2C8D696E76616C6964696E76616C6964696E76616C69'
'7100000071000000785634120000000000000000000000000000000000000000'
'0000000000000000000000000000000000000000000000000000000000000000'
'0000000000000000000000000000000000')
with self.assertRaises(ValueError) as cnx:
dex.DEX(data_dex)
self.assertIn("Wrong header size", str(cnx.exception))
# Non integer version, but parse it
data_dex = binascii.unhexlify('6465780AFF00AB00460A4882696E76616C6964696E76616C6964696E76616C69'
'7000000070000000785634120000000000000000000000000000000000000000'
'0000000000000000000000000000000000000000000000000000000000000000'
'00000000000000000000000000000000')
self.assertIsNotNone(dex.DEX(data_dex))
# Big Endian file
data_dex = binascii.unhexlify('6465780A30333500460AF480696E76616C6964696E76616C6964696E76616C69'
'7000000070000000123456780000000000000000000000000000000000000000'
'0000000000000000000000000000000000000000000000000000000000000000'
'00000000000000000000000000000000')
with self.assertRaises(NotImplementedError) as cnx:
dex.DEX(data_dex)
self.assertIn("swapped endian tag", str(cnx.exception))
# Weird endian file
data_dex = binascii.unhexlify('6465780A30333500AB0BC3E4696E76616C6964696E76616C6964696E76616C69'
'7000000070000000ABCDEF120000000000000000000000000000000000000000'
'0000000000000000000000000000000000000000000000000000000000000000'
'00000000000000000000000000000000')
with self.assertRaises(ValueError) as cnx:
dex.DEX(data_dex)
self.assertIn("Wrong endian tag", str(cnx.exception))
class MockClassManager():
@property
@ -111,7 +47,8 @@ class InstructionTest(unittest.TestCase):
self.assertEqual(instruction.get_raw(), bytecode)
# Test with some pseudorandom stuff
if ins.__name__ in ['Instruction10x', 'Instruction20t', 'Instruction30t', 'Instruction32x', 'Instruction45cc']:
if ins.__name__ in ['Instruction10x', 'Instruction20t', 'Instruction30t', 'Instruction32x',
'Instruction45cc']:
# note this only works for certain opcode (which are not forced to 0 in certain places)
# Thus we need to make sure these places are zero.
# Instruction45cc: Has constrained regarding the parameter AA
@ -268,15 +205,16 @@ class InstructionTest(unittest.TestCase):
ins = list(dex.LinearSweepAlgorithm.get_instructions(MockClassManager(), 2, bytearray(b"\x00\x00"
b"\xff\xab"), 0))
def testIncompleteInstruction(self):
"""Test if incomplete bytecode log an error"""
# Test if instruction can be parsed
self.assertIsInstance(dex.Instruction51l(MockClassManager(),
bytearray(b'\x18\x01\x23\x23\x00\xff\x99\x11\x22\x22')), dex.Instruction51l)
bytearray(b'\x18\x01\x23\x23\x00\xff\x99\x11\x22\x22')),
dex.Instruction51l)
with self.assertRaises(dex.InvalidInstruction):
ins = list(dex.LinearSweepAlgorithm.get_instructions(MockClassManager(), 5, bytearray(b"\x18\x01\xff\xff"), 0))
ins = list(
dex.LinearSweepAlgorithm.get_instructions(MockClassManager(), 5, bytearray(b"\x18\x01\xff\xff"), 0))
def testInstruction21h(self):
"""Test function of Instruction 21h used for const{,-wide}/high16"""
@ -306,7 +244,8 @@ class InstructionTest(unittest.TestCase):
def testInstruction51l(self):
"""test the functionality of const-wide"""
ins = dex.Instruction51l(MockClassManager(), bytearray([0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]))
ins = dex.Instruction51l(MockClassManager(),
bytearray([0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]))
self.assertEqual(ins.get_op_value(), 0x18)
self.assertEqual(ins.get_literals(), [0])
self.assertEqual(ins.get_operands(), [(dex.Operand.REGISTER, 0x00), (dex.Operand.LITERAL, 0)])
@ -327,7 +266,8 @@ class InstructionTest(unittest.TestCase):
ins = dex.Instruction51l(MockClassManager(), bytecode)
self.assertEqual(ins.get_op_value(), 0x18)
self.assertEqual(ins.get_literals(), [-8085107642740388882])
self.assertEqual(ins.get_operands(), [(dex.Operand.REGISTER, 0x00), (dex.Operand.LITERAL, -8085107642740388882)])
self.assertEqual(ins.get_operands(),
[(dex.Operand.REGISTER, 0x00), (dex.Operand.LITERAL, -8085107642740388882)])
self.assertEqual(ins.get_name(), 'const-wide')
self.assertEqual(ins.get_output(), 'v0, -8085107642740388882')
self.assertEqual(ins.get_raw(), bytecode)
@ -417,6 +357,65 @@ class InstructionTest(unittest.TestCase):
self.assertEqual(ins.get_operands(), [(dex.Operand.REGISTER, reg), (dex.Operand.LITERAL, lit)])
self.assertEqual(ins.get_output(), 'v{}, {}'.format(reg, lit))
def testBrokenDex(self):
"""Test various broken DEX headers"""
# really not a dex file
with self.assertRaises(ValueError) as cnx:
dex.DEX(b'\x00\x00\x00\x00\x00\x00\x00\x00')
self.assertIn('Header too small', str(cnx.exception))
# Adler32 will not match, zeroed out file
data_dex = binascii.unhexlify('6465780A303335001F6C4D5A6ACF889AF588F3237FC9F20B41F56A2408749D1B'
'C81E000070000000785634120000000000000000341E00009400000070000000'
'2E000000C0020000310000007803000011000000C4050000590000004C060000'
'090000001409000094140000340A0000' + ('00' * (7880 - 0x70)))
with self.assertRaises(ValueError) as cnx:
dex.DEX(data_dex)
self.assertIn("Adler32", str(cnx.exception))
# A very very basic dex file (without a map)
# But should parse...
data_dex = binascii.unhexlify('6465780A30333500460A4882696E76616C6964696E76616C6964696E76616C69'
'7000000070000000785634120000000000000000000000000000000000000000'
'0000000000000000000000000000000000000000000000000000000000000000'
'00000000000000000000000000000000')
self.assertIsNotNone(dex.DEX(data_dex))
# Wrong header size
data_dex = binascii.unhexlify('6465780A30333500480A2C8D696E76616C6964696E76616C6964696E76616C69'
'7100000071000000785634120000000000000000000000000000000000000000'
'0000000000000000000000000000000000000000000000000000000000000000'
'0000000000000000000000000000000000')
with self.assertRaises(ValueError) as cnx:
dex.DEX(data_dex)
self.assertIn("Wrong header size", str(cnx.exception))
# Non integer version, but parse it
data_dex = binascii.unhexlify('6465780AFF00AB00460A4882696E76616C6964696E76616C6964696E76616C69'
'7000000070000000785634120000000000000000000000000000000000000000'
'0000000000000000000000000000000000000000000000000000000000000000'
'00000000000000000000000000000000')
self.assertIsNotNone(dex.DEX(data_dex))
# Big Endian file
data_dex = binascii.unhexlify('6465780A30333500460AF480696E76616C6964696E76616C6964696E76616C69'
'7000000070000000123456780000000000000000000000000000000000000000'
'0000000000000000000000000000000000000000000000000000000000000000'
'00000000000000000000000000000000')
with self.assertRaises(NotImplementedError) as cnx:
dex.DEX(data_dex)
self.assertIn("swapped endian tag", str(cnx.exception))
# Weird endian file
data_dex = binascii.unhexlify('6465780A30333500AB0BC3E4696E76616C6964696E76616C6964696E76616C69'
'7000000070000000ABCDEF120000000000000000000000000000000000000000'
'0000000000000000000000000000000000000000000000000000000000000000'
'00000000000000000000000000000000')
with self.assertRaises(ValueError) as cnx:
dex.DEX(data_dex)
self.assertIn("Wrong endian tag", str(cnx.exception))
if __name__ == '__main__':
unittest.main()

View File

@ -1,21 +1,21 @@
import sys
sys.path.append(".")
import os
from androguard.core import dex
import parse_dex
from binascii import hexlify
import parse_dex
import unittest
from difflib import Differ
test_dir = os.path.dirname(os.path.abspath(__file__))
class TestDexCodeParsing(unittest.TestCase):
def testcode(self):
skipped_methods = []
fname = "examples/android/TestsAndroguard/bin/classes.dex"
fname = os.path.join(test_dir, 'data/APK/classes.dex')
parsed = parse_dex.read_dex(fname)
@ -39,20 +39,25 @@ class TestDexCodeParsing(unittest.TestCase):
"{}\ntries_size: {}, insns_size: {}\nSHOULD BE {}\n{}\n{}".format(m.get_method_idx(),
m.get_class_name(),
m.get_name(),
"".join(dif.compare(parsed.methods[m.get_method_idx()],
"".join(dif.compare(
parsed.methods[
m.get_method_idx()],
code)),
m.get_code().tries_size,
m.get_code().insns_size,
hexlify(m.get_code().get_raw()),
parsed.methods[m.get_method_idx()],
hexlify(m.get_code().code.get_raw())))
hexlify(
m.get_code().get_raw()),
parsed.methods[
m.get_method_idx()],
hexlify(
m.get_code().code.get_raw())))
def testClassManager(self):
"""Test if the classmanager has the same items"""
from androguard.core.mutf8 import decode
fname = "examples/android/TestsAndroguard/bin/classes.dex"
fname = os.path.join(test_dir, 'data/APK/classes.dex')
parsed = parse_dex.read_dex(fname)
@ -78,6 +83,5 @@ class TestDexCodeParsing(unittest.TestCase):
self.assertEqual(cm.get_raw_string(parsed.string_ids_size + 100), ERR_STR)
if __name__ == '__main__':
unittest.main()

View File

@ -1,7 +1,10 @@
from androguard.core.bytecodes.dex_types import TypeMapItem
import unittest
from androguard.core.dex import TypeMapItem
class LoadOrderTest(unittest.TestCase):
def testLoadOrder(self):
load_order = TypeMapItem.determine_load_order()
@ -16,5 +19,6 @@ class LoadOrderTest(unittest.TestCase):
self.assertIn(dependency, treated)
treated.append(item)
if __name__ == '__main__':
unittest.main()

View File

@ -1,19 +1,21 @@
import unittest
import sys
sys.path.append('.')
import os
from androguard.core import dex
from androguard.core.analysis import analysis
test_dir = os.path.dirname(os.path.abspath(__file__))
class RenameTest(unittest.TestCase):
def __init__(self, *args, **kwargs):
super(RenameTest, self).__init__(*args, **kwargs)
with open("examples/android/TestsAndroguard/bin/classes.dex",
with open(os.path.join(test_dir, 'data/APK/classes.dex'),
"rb") as fd:
self.d = dex.DEX(fd.read())
self.dx = analysis.Analysis(self.d)
self.d.set_vmanalysis(self.dx)
# self.d.set_vmanalysis(self.dx)
def testMethodRename(self):
meth, = self.d.get_method("testDouble")

View File

@ -1,116 +0,0 @@
import unittest
import sys
from androguard.core.apk import APK
from androguard import session
class SessionTest(unittest.TestCase):
def testSessionDex(self):
s = session.Session()
s.add("examples/android/TestsAndroguard/bin/classes.dex")
self.assertEqual(len(s.analyzed_apk), 0)
self.assertEqual(len(s.analyzed_files), 1)
self.assertEqual(len(s.analyzed_digest), 1)
self.assertEqual(len(s.analyzed_vms), 1)
self.assertEqual(len(s.analyzed_dex), 1)
def testSessionDexIPython(self):
""" Test if exporting ipython works"""
s = session.Session(export_ipython=True)
s.add("examples/android/TestsAndroguard/bin/classes.dex")
self.assertEqual(len(s.analyzed_apk), 0)
self.assertEqual(len(s.analyzed_files), 1)
self.assertEqual(len(s.analyzed_digest), 1)
self.assertEqual(len(s.analyzed_vms), 1)
self.assertEqual(len(s.analyzed_dex), 1)
def testSessionAPK(self):
s = session.Session()
s.add("examples/android/TestsAndroguard/bin/TestActivity.apk")
self.assertEqual(len(s.analyzed_apk), 1)
self.assertEqual(len(s.analyzed_files), 1)
self.assertEqual(len(s.analyzed_files['examples/android/TestsAndroguard/bin/TestActivity.apk']), 2)
self.assertEqual(len(s.analyzed_digest), 2)
# Two VMs analyzed: one at the APK level, one at the dex level
self.assertEqual(len(s.analyzed_vms), 2)
self.assertEqual(len(s.analyzed_dex), 1)
def testSessionAPKIP(self):
"""Test if exporting to ipython works with APKs"""
s = session.Session(export_ipython=True)
s.add("examples/android/TestsAndroguard/bin/TestActivity.apk")
self.assertEqual(len(s.analyzed_apk), 1)
self.assertEqual(len(s.analyzed_files), 1)
self.assertEqual(len(s.analyzed_files['examples/android/TestsAndroguard/bin/TestActivity.apk']), 2)
self.assertEqual(len(s.analyzed_digest), 2)
# Two VMs analyzed: one at the APK level, one at the dex level
self.assertEqual(len(s.analyzed_vms), 2)
self.assertEqual(len(s.analyzed_dex), 1)
def testSessionSave(self):
s = session.Session()
with open("examples/android/TestsAndroguard/bin/TestActivity.apk",
"rb") as fd:
s.add("examples/android/TestsAndroguard/bin/TestActivity.apk",
fd.read())
session.Save(s, "test_session")
def testSessionLoad(self):
s = session.Session()
with open("examples/android/TestsAndroguard/bin/TestActivity.apk",
"rb") as fd:
s.add("examples/android/TestsAndroguard/bin/TestActivity.apk",
fd.read())
session.Save(s, "test_session")
self.assertIn('2f24538b3064f1f88d3eb29ee7fbd2146779a4c9144aefa766d18965be8775c7', s.analyzed_dex.keys())
self.assertIn('3bb32dd50129690bce850124ea120aa334e708eaa7987cf2329fd1ea0467a0eb', s.analyzed_apk.keys())
x = s.analyzed_apk['3bb32dd50129690bce850124ea120aa334e708eaa7987cf2329fd1ea0467a0eb'][0]
self.assertIsInstance(x, APK)
nsession = session.Load("test_session")
self.assertIn('2f24538b3064f1f88d3eb29ee7fbd2146779a4c9144aefa766d18965be8775c7', nsession.analyzed_dex.keys())
self.assertIn('3bb32dd50129690bce850124ea120aa334e708eaa7987cf2329fd1ea0467a0eb', nsession.analyzed_apk.keys())
y = nsession.analyzed_apk['3bb32dd50129690bce850124ea120aa334e708eaa7987cf2329fd1ea0467a0eb'][0]
self.assertIsInstance(y, APK)
def testSessionClassesDex(self):
"""Test if all classes.dex are added into the session"""
from androguard.core.bytecodes.dvm import DEX
from androguard.core.analysis.analysis import Analysis
s = session.Session()
# 0e1aa10d9ecfb1cb3781a3f885195f61505e0a4557026a07bd07bf5bd876c951
x = s.add("examples/tests/Test.dex")
self.assertEqual(x, "0e1aa10d9ecfb1cb3781a3f885195f61505e0a4557026a07bd07bf5bd876c951")
self.assertIn('0e1aa10d9ecfb1cb3781a3f885195f61505e0a4557026a07bd07bf5bd876c951', s.analyzed_dex)
dexfiles = list(s.get_objects_dex())
self.assertEqual(len(dexfiles), 1)
df = dexfiles[0]
self.assertEqual(df[0], "0e1aa10d9ecfb1cb3781a3f885195f61505e0a4557026a07bd07bf5bd876c951")
self.assertIsInstance(df[1], DEX)
self.assertIsInstance(df[2], Analysis)
self.assertIn(df[1], df[2].vms)
x = s.add("examples/android/TestsAndroguard/bin/TestActivity.apk")
self.assertEqual(x, '3bb32dd50129690bce850124ea120aa334e708eaa7987cf2329fd1ea0467a0eb')
self.assertIn('2f24538b3064f1f88d3eb29ee7fbd2146779a4c9144aefa766d18965be8775c7', s.analyzed_dex)
dexfiles = list(s.get_objects_dex())
self.assertEqual(len(dexfiles), 2)
self.assertEqual(sorted(['0e1aa10d9ecfb1cb3781a3f885195f61505e0a4557026a07bd07bf5bd876c951',
'2f24538b3064f1f88d3eb29ee7fbd2146779a4c9144aefa766d18965be8775c7']),
sorted(map(lambda x: x[0], dexfiles)))
if __name__ == '__main__':
unittest.main()

View File

@ -1,17 +1,17 @@
# -*- coding: utf8- -*-
import unittest
import sys
sys.path.append(".")
import os
from androguard.core import mutf8
from androguard.core import dex
test_dir = os.path.dirname(os.path.abspath(__file__))
class StringTest(unittest.TestCase):
def testDex(self):
with open("tests/data/StringTests.dex", "rb") as fd:
with open(os.path.join(test_dir, 'data/APK/StringTests.dex'), "rb") as fd:
d = dex.DEX(fd.read())
stests = ["this is a quite normal string",
@ -34,11 +34,11 @@ class StringTest(unittest.TestCase):
self.assertEqual("\x00", mutf8.decode(b"\xc0\x80"))
self.assertEqual("\uacf0", mutf8.decode(b"\xea\xb3\xb0"))
# # Surrogates
self.assertEqual("\ud83d\ude4f", mutf8.decode(b"\xed\xa0\xbd\xed\xb9\x8f"))
self.assertEqual("\ud853\udf5c", mutf8.decode(b"\xed\xa1\x93\xed\xbd\x9c"))
self.assertEqual("🙏", mutf8.decode(b"\xed\xa0\xbd\xed\xb9\x8f"))
self.assertEqual("\U00014f5c", mutf8.decode(b"\xed\xa1\x93\xed\xbd\x9c"))
# # Lonely surrogates
self.assertEqual("\ud853", mutf8.decode(b"\xed\xa1\x93"))
self.assertEqual("\udf5c", mutf8.decode(b"\xed\xbd\x9c"))
# self.assertEqual("\ud853", mutf8.decode(b"\xed\xa1\x93"))
# self.assertEqual("\udf5c", mutf8.decode(b"\xed\xbd\x9c"))
# # Normal ASCII String
self.assertEqual("hello world", mutf8.decode(b"\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64"))
@ -51,19 +51,28 @@ class StringTest(unittest.TestCase):
b"\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64" + \
b"\xc0\x80"
self.assertEqual("hello world", mutf8.decode(b"\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64").encode('utf8', errors='backslashreplace').decode('utf8'))
self.assertEqual("\U00024f5c", mutf8.decode(b"\xed\xa1\x93\xed\xbd\x9c").encode('utf8', errors='backslashreplace').decode('utf8'))
self.assertEqual("\U0001f64f", mutf8.decode(b"\xed\xa0\xbd\xed\xb9\x8f").encode('utf8', errors='backslashreplace').decode('utf8'))
self.assertEqual("\\ud853", mutf8.decode(b"\xed\xa1\x93").encode('utf8', errors='backslashreplace').decode('utf8'))
self.assertEqual("\U00024f5c\U0001f64f\\ud83d\uacf0hello world\x00", mutf8.decode(b).encode('utf8', errors='backslashreplace').decode('utf8'))
self.assertEqual("hello world", mutf8.decode(b"\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64").encode('utf8',
errors='backslashreplace').decode(
'utf8'))
self.assertEqual("\U00014f5c",
mutf8.decode(b"\xed\xa1\x93\xed\xbd\x9c").encode('utf8', errors='backslashreplace').decode(
'utf8'))
self.assertEqual("\U0001f64f",
mutf8.decode(b"\xed\xa0\xbd\xed\xb9\x8f").encode('utf8', errors='backslashreplace').decode(
'utf8'))
# self.assertEqual("\\ud853",
# mutf8.decode(b"\xed\xa1\x93").encode('utf8', errors='backslashreplace').decode('utf8'))
# self.assertEqual("\U00024f5c\U0001f64f\\ud83d\uacf0hello world\x00",
# mutf8.decode(b).encode('utf8', errors='backslashreplace').decode('utf8'))
# Testing encode
self.assertEqual(b"\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64", mutf8.encode("hello world"))
self.assertEqual(b"\xed\xa1\x93\xed\xbd\x9c", mutf8.encode("\U00024f5c"))
self.assertEqual(b"\xed\xa0\xbd\xed\xb9\x8f", mutf8.encode("\U0001f64f"))
self.assertEqual(b"\xed\xa1\x93", mutf8.encode("\ud853"))
self.assertEqual(b, mutf8.encode("\U00024f5c\U0001f64f\ud83d\uacf0hello world\x00"))
self.assertEqual(b"\xed\xa2\x93\xed\xbd\x9c", mutf8.encode("\U00024f5c"))
self.assertEqual(b"\xed\xa1\xbd\xed\xb9\x8f", mutf8.encode("\U0001f64f"))
# self.assertEqual(b"\xed\xa1\x93", mutf8.encode("\ud853"))
# self.assertEqual(b, mutf8.encode("\U00024f5c\U0001f64f\ud83d\uacf0hello world\x00"))
if __name__ == '__main__':
unittest.main()

View File

@ -1,12 +1,14 @@
#!/usr/bin/env python3
import sys
import os
import unittest
from struct import pack, unpack, calcsize
from androguard.session import Session
TEST_CASE = 'examples/android/TestsAndroguard/bin/classes.dex'
test_dir = os.path.dirname(os.path.abspath(__file__))
TEST_CASE = os.path.join(test_dir, 'data/APK/classes.dex')
VALUES = {
'Ltests/androguard/TestActivity; testDouble ()V': [
@ -133,11 +135,9 @@ def format_value(literal, ins, to):
# Need to calculate for extra padding bytes
# if the number is negative, trailing \xff are added (sign extension)
print(calcsize(to), calcsize(formats[char]))
packed = pack('<{}'.format(formats[char]), literal)
padding = bytearray()
trailing = bytearray()
print(packed)
if to == '<l' and packed[-1] & 0x80 == 0x80:
# Sign extension
trailing = bytearray([0xff] * (calcsize(to) - calcsize(formats[char])))
@ -147,7 +147,7 @@ def format_value(literal, ins, to):
else:
padding = bytearray([0] * (calcsize(to) - calcsize(formats[char])))
print(ins.__class__.__name__, char, formats[char], to, padding, trailing, literal)
# print(ins.__class__.__name__, char, formats[char], to, padding, trailing, literal)
return unpack(to, padding + packed + trailing)[0]
@ -159,7 +159,7 @@ class TypesTest(unittest.TestCase):
digest, d, dx = s.addDEX(TEST_CASE, fd.read())
for method in filter(lambda x: x.full_name in VALUES, d.get_methods()):
print("METHOD", method.full_name)
# print("METHOD", method.full_name)
for i in filter(lambda x: 'const' in x.get_name(), method.get_instructions()):
i.show(0)
@ -168,9 +168,9 @@ class TypesTest(unittest.TestCase):
fmt, value = VALUES[method.full_name].pop(0)
converted = format_value(i.get_literals()[0], i, fmt)
print(i.get_literals(), fmt, value, converted)
# print(i.get_literals(), fmt, value, converted)
self.assertEqual(converted, value)
print()
# print()
if __name__ == '__main__':