Beispiel #1
0
    def testPermissions(self):
        """Test the get_permissions and get_permission_usage methods"""
        a, _, dx = AnalyzeAPK("examples/android/TestsAndroguard/bin/TestActivity.apk")

        api_level = a.get_effective_target_sdk_version()
        used_permissions = ['android.permission.BROADCAST_STICKY', 'android.permission.ACCESS_NETWORK_STATE']
        sticky_meths = ['onMenuItemSelected', 'navigateUpTo']
        network_meths = ['getNetworkInfo', 'getActiveNetworkInfo', 'isActiveNetworkMetered']

        for _, perm in dx.get_permissions(api_level):
            for p in perm:
                self.assertIn(p, used_permissions)
        meths = [x.name for x in dx.get_permission_usage('android.permission.BROADCAST_STICKY', api_level)]
        self.assertListEqual(sorted(meths), sorted(sticky_meths))
        meths = [x.name for x in dx.get_permission_usage('android.permission.ACCESS_NETWORK_STATE', api_level)]
        self.assertListEqual(sorted(meths), sorted(network_meths))

        # Should give same result if no API level is given
        for _, perm in dx.get_permissions():
            for p in perm:
                self.assertIn(p, used_permissions)
        meths = [x.name for x in dx.get_permission_usage('android.permission.BROADCAST_STICKY')]
        self.assertListEqual(sorted(meths), sorted(sticky_meths))
        meths = [x.name for x in dx.get_permission_usage('android.permission.ACCESS_NETWORK_STATE')]
        self.assertListEqual(sorted(meths), sorted(network_meths))
Beispiel #2
0
def main():
    parser = ArgumentParser(description="Create a call graph based on the data"
            "of Analysis and export it into a graph format.")

    parser.add_argument("APK", nargs=1, help="The APK to analyze")
    parser.add_argument("--output", "-o", default="callgraph.gml",
            help="Filename of the output file, the extension is used to decide which format to use (default callgraph.gml)")
    parser.add_argument("--show", "-s", action="store_true", default=False,
            help="instead of saving the graph, print it with mathplotlib (you might not see anything!")
    parser.add_argument("--verbose", "-v", action="store_true", default=False,
            help="Print more output")
    parser.add_argument("--classname", default=".*", help="Regex to filter by classname")
    parser.add_argument("--methodname", default=".*", help="Regex to filter by methodname")
    parser.add_argument("--descriptor", default=".*", help="Regex to filter by descriptor")
    parser.add_argument("--accessflag", default=".*", help="Regex to filter by accessflags")
    parser.add_argument("--no-isolated", default=False, action="store_true",
            help="Do not store methods which has no xrefs")

    args = parser.parse_args()

    if args.verbose:
        show_logging(logging.INFO)

    a, d, dx = AnalyzeAPK(args.APK[0])

    entry_points = map(FormatClassToJava, a.get_activities() + a.get_providers() + a.get_services() + a.get_receivers())
    entry_points = list(entry_points)

    log.info("Found The following entry points by search AndroidManifest.xml: {}".format(entry_points))

    CG = dx.get_call_graph(args.classname,
                           args.methodname,
                           args.descriptor,
                           args.accessflag,
                           args.no_isolated,
                           entry_points,
                           )

    write_methods = dict(gml=_write_gml,
                         gexf=nx.write_gexf,
                         gpickle=nx.write_gpickle,
                         graphml=nx.write_graphml,
                         yaml=nx.write_yaml,
                         net=nx.write_pajek,
                        )

    if args.show:
        plot(CG)
    else:
        writer = args.output.rsplit(".", 1)[1]
        if writer in ["bz2", "gz"]:
            writer = args.output.rsplit(".", 2)[1]
        if writer not in write_methods:
            print("Could not find a method to export files to {}!".format(writer))
            sys.exit(1)

        write_methods[writer](CG, args.output)
Beispiel #3
0
def androcg_main(verbose,
                 APK,
                 classname,
                 methodname,
                 descriptor,
                 accessflag,
                 no_isolated,
                 show,
                 output):
    from androguard.core.androconf import show_logging
    from androguard.core.bytecode import FormatClassToJava
    from androguard.misc import AnalyzeAPK
    import networkx as nx
    import logging
    log = logging.getLogger("androcfg")
    if verbose:
        show_logging(logging.INFO)

    a, d, dx = AnalyzeAPK(APK)

    entry_points = map(FormatClassToJava,
                       a.get_activities() + a.get_providers() +
                       a.get_services() + a.get_receivers())
    entry_points = list(entry_points)

    log.info("Found The following entry points by search AndroidManifest.xml: "
             "{}".format(entry_points))

    CG = dx.get_call_graph(classname,
                           methodname,
                           descriptor,
                           accessflag,
                           no_isolated,
                           entry_points,
                           )

    write_methods = dict(gml=_write_gml,
                         gexf=nx.write_gexf,
                         gpickle=nx.write_gpickle,
                         graphml=nx.write_graphml,
                         yaml=nx.write_yaml,
                         net=nx.write_pajek,
                         )

    if show:
        plot(CG)
    else:
        writer = output.rsplit(".", 1)[1]
        if writer in ["bz2", "gz"]:
            writer = output.rsplit(".", 2)[1]
        if writer not in write_methods:
            print("Could not find a method to export files to {}!"
                  .format(writer))
            sys.exit(1)

        write_methods[writer](CG, output)
Beispiel #4
0
    def testAPKWrapperUnsigned(self):
        from androguard.misc import AnalyzeAPK
        from androguard.core.bytecodes.apk import APK
        from androguard.core.bytecodes.dvm import DalvikVMFormat
        from androguard.core.analysis.analysis import Analysis
        a, d, dx = AnalyzeAPK("examples/android/TestsAndroguard/bin/TestActivity_unsigned.apk")

        self.assertIsInstance(a, APK)
        self.assertIsInstance(d, DalvikVMFormat)
        self.assertIsInstance(dx, Analysis)

        self.assertEqual(a.get_signature_name(), None)
        self.assertEqual(a.get_signature_names(), [])
Beispiel #5
0
    def testAPKWrapper(self):
        from androguard.misc import AnalyzeAPK
        from androguard.core.bytecodes.apk import APK
        from androguard.core.bytecodes.dvm import DalvikVMFormat
        from androguard.core.analysis.analysis import Analysis
        a, d, dx = AnalyzeAPK("examples/android/TestsAndroguard/bin/TestActivity.apk")

        self.assertIsInstance(a, APK)
        self.assertIsInstance(d, DalvikVMFormat)
        self.assertIsInstance(dx, Analysis)

        self.assertEqual(a.get_signature_name(), "META-INF/CERT.RSA")
        self.assertEqual(a.get_signature_names(), ["META-INF/CERT.RSA"])

        self.assertIsNotNone(a.get_certificate(a.get_signature_name()))
Beispiel #6
0
    def testAPKWrapperRaw(self):
        from androguard.misc import AnalyzeAPK
        from androguard.core.bytecodes.apk import APK
        from androguard.core.bytecodes.dvm import DalvikVMFormat
        from androguard.core.analysis.analysis import Analysis
        with open(
            "examples/android/TestsAndroguard/bin/TestActivity.apk", 'rb') \
                as file_obj:
            file_contents = file_obj.read()
        a, d, dx = AnalyzeAPK(file_contents, raw=True)
        self.assertIsInstance(a, APK)
        self.assertIsInstance(d[0], DalvikVMFormat)
        self.assertIsInstance(dx, Analysis)

        self.assertEqual(a.get_signature_name(), "META-INF/CERT.RSA")
        self.assertEqual(a.get_signature_names(), ["META-INF/CERT.RSA"])

        self.assertIsNotNone(a.get_certificate(a.get_signature_name()))
Beispiel #7
0
    def testMultidex(self):
        a, d, dx = AnalyzeAPK("examples/tests/multidex/multidex.apk")

        cls = list(map(lambda x: x.get_vm_class().get_name(), dx.get_classes()))
        self.assertIn('Lcom/foobar/foo/Foobar;', cls)
        self.assertIn('Lcom/blafoo/bar/Blafoo;', cls)
def get_permissions(apk_file: AnalyzeAPK) -> List[str]:
    return apk_file.get_permissions()
Beispiel #9
0
class Apkinfo:

    def __init__(self, apk_filepath):
        self.a, self.d, self.dx = AnalyzeAPK(apk_filepath)

        # Create Class, Method, String and Field
        # crossreferences for all classes in the Analysis.
        # self.dx.create_xref()

    @property
    def permissions(self):
        """
        :returns: A list of permissions
        :rtype: list
        """
        return self.a.get_permissions()

    def find_method(self, class_name=".*", method_name=".*"):
        """
        Find method from given class_name and method_name,
        default is find all.

        :returns: an generator of MethodClassAnalysis
        :rtype: generator
        """

        result = self.dx.find_methods(class_name, method_name)

        if len(list(result)) > 0:
            return self.dx.find_methods(class_name, method_name)

        else:
            # Method Not Found
            return None

    def upperfunc(self, class_name, method_name):
        """
        Return the upper level method from given class name and
        method name.
        :param class_name:
        :param method_name:
        :return: list
        """

        result = []
        method_set = self.find_method(class_name, method_name)

        if method_set is not None:
            for md in method_set:
                for _, call, _ in md.get_xref_from():
                    # Get class name and method name:
                    # call.class_name, call.name
                    result.append((call.class_name, call.name))

            return tools.remove_dup_list(result)
        else:
            return None

    def get_method_bytecode(self, class_name, method_name):
        """
        Return the corresponding bytecode according to the
        given class name and method name.
        :param class_name:
        :param method_name:
        :return: generator
        """

        result = self.dx.find_methods(class_name, method_name)

        if len(list(result)) > 0:
            for m in self.dx.find_methods(class_name, method_name):
                for idx, ins in m.get_method().get_instructions_idx():
                    bytecode_obj = None
                    reg_list = []

                    # count the number of the registers.
                    length_operands = len(ins.get_operands())
                    if length_operands == 0:
                        # No register, no parm
                        bytecode_obj = BytecodeObject(ins.get_name(), None, None)
                    elif length_operands == 1:
                        # Only one register

                        reg_list.append(
                            "v" + str(ins.get_operands()[length_operands - 1][1])
                        )
                        bytecode_obj = BytecodeObject(ins.get_name(), reg_list, None, )
                    elif length_operands >= 2:
                        # the last one is parm, the other are registers.

                        parameter = ins.get_operands()[length_operands - 1]
                        for i in range(0, length_operands - 1):
                            reg_list.append("v" + str(ins.get_operands()[i][1]))
                        if len(parameter) == 3:
                            # method or value
                            parameter = parameter[2]
                        else:
                            # Operand.OFFSET
                            parameter = parameter[1]

                        bytecode_obj = BytecodeObject(
                            ins.get_name(), reg_list, parameter,
                        )

                    yield bytecode_obj
        else:
            return None
        for feature in features:
            f.write("feature::%s\n" % feature)


num = 0
for path, subdirs, files in os.walk(rootdir):
    for name in files:
        if name.endswith(".apk"):
            num = num + 1
            filepath = os.path.join(path, name)
            appName = name[:-4]
            #print("File %d: %s"%(num,name))
            print(num)

            try:
                a, d, dx = AnalyzeAPK(filepath)

                permission_file_path = os.path.join(permission_dir, appName)
                write_permissions(a, permission_file_path)

                icc_file_path = os.path.join(icc_dir, appName)
                write_icc(a, icc_file_path)

                api_file_path = os.path.join(api_dir, appName)
                write_api(dx, api_file_path)

            except Exception as e:
                with open('exception.txt', 'a') as exceptionfile:
                    exceptionfile.write('{}\n'.format(appName))
                continue
Beispiel #11
0
def get_package_name(filename):
    a, d, dx = AnalyzeAPK(filename)
    return a.get_package()
 def get_detailed_analysis(self, app_path):
     from androguard.misc import AnalyzeAPK
     self.a, self.d, self.dx = AnalyzeAPK(app_path)
                        action="store_true")
    parser.add_argument("--hex",
                        "-H",
                        help="Give hex string of the bytecode",
                        action="store_true")
    args = parser.parse_args()

    if not os.path.isfile(args.APK):
        print("This file does not exist")
        sys.exit(-1)

    if androconf.is_android(args.APK) != 'APK':
        print("This is not an APK file :o")
        sys.exit(-1)
    else:
        a, d, dx = AnalyzeAPK(args.APK)
        class_name = args.CLASS.replace('.', '/')
        if args.verbose:
            print("Searching for {}".format(class_name))
        cc = [d for d in dx.get_classes() if class_name in d.name]
        if len(cc) == 0:
            print("Class not found")
        else:
            for c in cc:
                methods = [
                    m for m in c.get_methods()
                    if m.get_method().name == args.METHOD
                ]
                print("{} methods found in {}".format(len(methods), c.name))
                for m in methods:
                    m.get_method().show_info()
    workbook = xlsxwriter.Workbook("APK1funcallapi.xlsx")
    worksheet = workbook.add_worksheet()
    exapiname = api_classes
    funcname = []
    funcnameapi = []
    for i in range(len(exapiname)):
        for meth in dx.classes[exapiname[i]].get_methods():
            for _, call, _ in meth.get_xref_from():
                funcname.append(call.name)
                funcnameapi.append(([call.name, exapiname[i]]))
    funcname = list(set(funcname))
    k = 0
    funcallapi = []
    for i in range(len(funcname)):
        for j in range(len(funcnameapi)):
            if funcname[i] == funcnameapi[j][0]:
                funcallapi.append(funcnameapi[j][1])
                funcallapi = list(set(funcallapi))
        worksheet.write(i, 0, funcname[i])
        for k in range(len(funcallapi)):
            worksheet.write(i, k + 1, funcallapi[k])
        funcallapi = []
    workbook.close()


if __name__ == "__main__":
    a, d, dx = AnalyzeAPK("E:/Code/APK1.apk")
    exclassname = get_source_call(a, d, dx)
    apiClass = select_api(exclassname)
    build_methodnameapi_relationship(a, d, dx, apiClass)
 def get_detailed_analysis(self):
     self.a, self.ds, self.dx = AnalyzeAPK(self.app_path)
     print("decompiler done.")
class androidguard_decompiler(object):
    """
    analysis result of androguard
    """
    def __init__(self, app_path):
        """
        :param app_path: local file path of app, should not be None
        analyse app specified by app_path
        """
        self.app_path = app_path
        try:
            self.a = APK(self.app_path)
        except:
            raise
        self.ds = None
        self.dx = None

    def get_detailed_analysis(self):
        self.a, self.ds, self.dx = AnalyzeAPK(self.app_path)
        print("decompiler done.")

    #
    # def get_fast_analysis(self):
    #     self.ds = DalvikVMFormat( self.a.get_dex() )

    def save_session(self, outputpath):
        save_session([self.a, self.ds, self.dx],
                     "{}/session.json".format(outputpath))

    def process_and_savesession_multiplefolder(self, outputdirs):
        print("filename: ", os.path.basename(self.app_path))
        filename = os.path.basename(self.app_path)
        filename = filename.replace(".apk", "")
        for outputdir in outputdirs:
            outputpath = "{}{}".format(outputdir, filename)
            if os.path.exists(outputpath):
                print("skip based on filename: {}.".format(filename))
                return
        self.process_and_savesession(outputdirs[-1])

    def process_and_savesession(self, outputdir):
        packagename = self.a.get_package()
        outputpath = "{}{}".format(outputdir, packagename)
        if os.path.exists(outputpath):
            print("skip based on package name: {}.".format(packagename))
            return
        os.mkdir(outputpath)
        try:
            if self.ds == None:
                self.get_detailed_analysis()
            self.save_session(outputpath)
            # writeDexToFile(self.ds, packagename, outputpath)
        except Exception as e:
            print(e)
            os.rmdir(outputpath)

    def output_sorce(self, outputdir):
        packagename = self.a.get_package()
        outputpath = "{}{}".format(outputdir, packagename)
        if os.path.exists(outputpath):
            print("skip {}.".format(packagename))
            return
        os.mkdir(outputpath)
        try:
            if self.ds == None:
                self.get_detailed_analysis()
            writeDexToFile(self.ds, packagename, outputpath)
        except Exception as e:
            print(e)
            os.rmdir(outputpath)
Beispiel #17
0
class APKStringResourceExtractor:
    def __init__(self, file, print_func=print):
        self.file = file
        self.print = print_func

        self.apk = None
        self.apk_analysis = None
        self.resources = None
        self.package_names = []
        self.locales_priority = []

        self.strings_in_resources = set()
        self.strings_in_code = set()
        self.id_names = set()

    def run(self):
        start_time = datetime.datetime.now()

        self.load_apk()
        self.select_locales()
        self.create_string_resources_list()
        self.create_resource_ids_list()

    def create_resource_ids_list(self):
        for package in self.package_names:
            for locale in self.locales_priority:
                if locale not in self.resources.values[package]:
                    continue
                for res_type, values in self.resources.values[package][
                        locale].items():
                    for value in values:
                        if len(value) == 1 or len(value) == 2:
                            self.id_names.add(value[0])
                        elif len(value) == 3:
                            self.id_names.add(value[1])

    def load_apk(self):
        self.apk, _, self.apk_analysis = AnalyzeAPK(self.file)
        self.resources = self.apk.get_android_resources()
        self.package_names = self.resources.get_packages_names()

    def select_locales(self):
        all_locales = set()
        for apk_package_name in self.package_names:
            all_locales.update(self.resources.get_locales(apk_package_name))

        all_locales = list(all_locales)
        all_locales = [
            l if l != "\x00\x00" else "DEFAULT" for l in all_locales
        ]

        if len(all_locales) == 1:
            self.locales_priority = all_locales
            return

        # prioritized locales

        # first: pure english
        if "en" in all_locales:
            self.locales_priority.append("en")
        # then: country-specific english
        self.locales_priority += [
            l for l in all_locales if l.startswith("en-")
        ]

        # then: default language
        if "DEFAULT" in all_locales:
            self.locales_priority.append("DEFAULT")
            self.locales_priority.append("\x00\x00")

        # if still no locale found, raise error
        if len(self.locales_priority) == 0:
            raise Exception("no locale found")

    def create_string_resources_list(self):
        strings = {}

        for pkg, locales_res in self.resources.get_resolved_strings().items():
            for locale in self.locales_priority:
                if locale in locales_res:
                    for id, value in locales_res[locale].items():
                        value = value.strip()
                        if len(value) == 0:
                            continue
                        if id not in strings:
                            strings[id] = value

        self.strings_in_resources = set(strings.values())

        self.strings_in_code = set(
            [s.value.strip() for s in self.apk_analysis.get_strings()])

    def get_all_strings(self):
        return list(self.strings_in_resources) + list(self.strings_in_code)

    def get_code_strings(self):
        return list(self.strings_in_code)

    def get_resource_strings(self):
        return list(self.strings_in_resources)

    def get_id_names(self):
        return list(self.id_names)

    def save(self, out_file):
        with open(out_file, "wb") as fp:
            data = (self.get_id_names(), self.get_code_strings(),
                    self.get_resource_strings())
            pickle.dump(data, fp)
Beispiel #18
0
 def load_apk(self):
     self.apk, _, self.apk_analysis = AnalyzeAPK(self.file)
     self.resources = self.apk.get_android_resources()
     self.package_names = self.resources.get_packages_names()
Beispiel #19
0
    0xf05368c0: 'SIGNv3',
    0x2146444e: 'Google Metadata',
    0x42726577: 'Padding'
}

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Process some apks')
    parser.add_argument('APK', help='APK')
    args = parser.parse_args()

    if os.path.isdir(args.APK):
        for f in os.listdir(args.APK):
            apk_path = os.path.join(args.APK, f)
            if os.path.isfile(apk_path):
                if androconf.is_android(apk_path) == 'APK':
                    a, d, dx = AnalyzeAPK(apk_path)
                    a.parse_v2_v3_signature()
                    if 0x2146444e in a._v2_blocks:
                        print("{} : FROSTING".format(f))
                    else:
                        print("{} : NOPE".format(f))
                else:
                    print("{} not an APK".format(f))
    else:
        if androconf.is_android(args.APK) == 'APK':
            a, d, dx = AnalyzeAPK(args.APK)
            if a.is_signed_v1():
                print("V1 Signature")
            if a.is_signed_v2():
                print("V2 Signature")
            if a.is_signed_v3():
Beispiel #20
0
def run_application_checks(PATH_TO_FILES,results_file):
	files=[]
	for i in range(0,5):
		P=PATH_TO_FILES.replace("_i","_"+str(i))
		for path, subdirs, files_w in os.walk(P):
			for name in files_w:
				n=os.path.join(path, name)
				if not n.endswith(".apk"):
					continue
				files.append(n)
	results=open(results_file,"a",buffering=0)#open the results file 
	#loop the files

	for f in files:
		subprocess.Popen("adb logcat -b all -c", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
		try:
			a, d, dx = AnalyzeAPK(f)
			package_name=a.get_package()
			os.system("adb install "+f)#install the app
			p = subprocess.Popen("adb shell pm dump "+package_name+" | grep -A 1 MAIN",shell=True,stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]#+" | grep -A 1 MAIN", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
			lines=p.split("\n")
			#print lines
			intent_main="android.intent.action.MAIN:"
			activity_name=""
			activity_check=0
			#get the main activity
			for line in lines:
				if intent_main in line:
					index=lines.index(line)
					opts=lines[index+1].split(" ")
					for option in opts:
						if option.startswith(package_name):#found the activity name
							activity_name=option
							activity_check=1
							break 
					break
	
			if activity_check==1:
				try:
				
					os.system("adb shell am start -a android.intent.action.MAIN -n "+activity_name)#run the app
					time.sleep(1.5)
					out = subprocess.Popen("adb logcat -d", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
					lines=out.split("\n")
					dictOfLines = { l : 0 for l in lines}
					if "--------- beginning of crash" in dictOfLines:
							results.write(package_name+" 1\n")
					
					else:
						results.write(package_name+" 0\n")
					os.system("adb shell am force-stop "+package_name)#stop the app
					
				except:
					results.write(package_name+" 3\n")
			else:
				results.write(package_name+" 2\n")
			subprocess.Popen("adb logcat -b all -c", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
			os.system("adb shell pm uninstall "+package_name)
		except:
			subprocess.Popen("adb logcat -b all -c", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
			os.system("adb shell pm uninstall "+package_name)
			continue
Beispiel #21
0
class Apkinfo:
    """Information about apk based on androguard analysis"""
    def __init__(self, apk_filepath):
        """Information about apk based on androguard analysis"""
        # return the APK, list of DalvikVMFormat, and Analysis objects
        self.apk, self.dalvikvmformat, self.analysis = AnalyzeAPK(apk_filepath)
        self.apk_filename = os.path.basename(apk_filepath)
        self.apk_filepath = apk_filepath

    def __repr__(self):
        return f"<Apkinfo-APK:{self.apk_filename}>"

    @property
    def filename(self):
        """
        Return the filename of apk.

        :return: a string of apk filename
        """
        return os.path.basename(self.apk_filepath)

    @property
    def filesize(self):
        """
        Return the file size of apk file by bytes.

        :return: a number of size bytes
        """
        return os.path.getsize(self.apk_filepath)

    @property
    def md5(self):
        """
        Return the md5 checksum of the apk file.

        :return: a string of md5 checksum of the apk file
        """
        md5 = hashlib.md5()
        with open(self.apk_filepath, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                md5.update(chunk)
        return md5.hexdigest()

    @property
    def permissions(self):
        """
        Return all permissions from given APK.

        :return: a list of all permissions
        """
        return self.apk.get_permissions()

    def find_method(self, class_name=".*", method_name=".*"):
        """
        Find method from given class_name and method_name,
        default is find all method.

        :param class_name: the class name of the Android API
        :param method_name: the method name of the Android API
        :return: a generator of MethodClassAnalysis
        """

        result = self.analysis.find_methods(class_name, method_name)

        if list(result):
            return self.analysis.find_methods(class_name, method_name)

        return None

    def upperfunc(self, class_name, method_name):
        """
        Return the upper level method from given class name and
        method name.

        :param class_name: the class name of the Android API
        :param method_name: the method name of the Android API
        :return: a list of all upper functions
        """

        upperfunc_result = []
        method_set = self.find_method(class_name, method_name)

        if method_set is not None:
            for method in method_set:
                for _, call, _ in method.get_xref_from():
                    # Get class name and method name:
                    # call.class_name, call.name
                    upperfunc_result.append((call.class_name, call.name))

            return tools.remove_dup_list(upperfunc_result)

        return None

    def get_method_bytecode(self, class_name, method_name):
        """
        Return the corresponding bytecode according to the
        given class name and method name.

        :param class_name: the class name of the Android API
        :param method_name: the method name of the Android API
        :return: a generator of all bytecode instructions
        """

        result = self.analysis.find_methods(class_name, method_name)

        if list(result):
            for method in self.analysis.find_methods(class_name, method_name):
                try:
                    for _, ins in method.get_method().get_instructions_idx():
                        bytecode_obj = None
                        reg_list = []

                        # count the number of the registers.
                        length_operands = len(ins.get_operands())
                        if length_operands == 0:
                            # No register, no parameter
                            bytecode_obj = BytecodeObject(
                                ins.get_name(),
                                None,
                                None,
                            )
                        elif length_operands == 1:
                            # Only one register

                            reg_list.append(
                                f"v{ins.get_operands()[length_operands - 1][1]}",
                            )
                            bytecode_obj = BytecodeObject(
                                ins.get_name(),
                                reg_list,
                                None,
                            )
                        elif length_operands >= 2:
                            # the last one is parameter, the other are registers.

                            parameter = ins.get_operands()[length_operands - 1]
                            for i in range(0, length_operands - 1):
                                reg_list.append(
                                    "v" + str(ins.get_operands()[i][1]), )
                            if len(parameter) == 3:
                                # method or value
                                parameter = parameter[2]
                            else:
                                # Operand.OFFSET
                                parameter = parameter[1]

                            bytecode_obj = BytecodeObject(
                                ins.get_name(),
                                reg_list,
                                parameter,
                            )

                        yield bytecode_obj
                except AttributeError as error:
                    # TODO Log the rule here
                    continue
Beispiel #22
0
 def __init__(self, apk_filepath):
     self.a, self.d, self.dx = AnalyzeAPK(apk_filepath)
Beispiel #23
0
 def __init__(self, apk_filepath):
     """Information about apk based on androguard analysis"""
     # return the APK, list of DalvikVMFormat, and Analysis objects
     self.apk, self.dalvikvmformat, self.analysis = AnalyzeAPK(apk_filepath)
     self.apk_filename = os.path.basename(apk_filepath)
     self.apk_filepath = apk_filepath
Beispiel #24
0
    def extract_features_task(self, args):

        apk_info = {}
        apk_analysis = {}
        apk_features = {}

        drebin_apk_file_list = dict(args[0])
        analysis_mode = args[1]

        url_patterns = ['http://', 'https://', 'www\.', '\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}\b']
        regex_patterns = []

        apks_to_ignore = []
        # apks_to_ignore = ['7a513817c9eac7f249c939252b48572824c9bb423ca31b3c5d84b242661d74bb',
        # '0899e04e972faded4f22138e6c1289f1095e9bfe5281d10c2866c7a5a9eec0b6',
        # '8994684817eb83cf360822238925c0025682a9ee804edbf40693a0320a444ed7',
        # '7bbd566f2f3abb78b3ffcc23ba4ad84e06a00f758d245c660c61b21814a850a5',
        # 'd53e4087beeee9323f86c7c65944cd10b8eb7bb78ca50de5a01e048b659aecb7',
        # 'ea153a9dc50f5f9dbaaa29d764b54a819e6b8c0917b000f1c78a32be77f2f804',
        # 'b7c760781b8d3cfbf7b6657b8ec5f232405038ff399f78f8d05c391de54401b9',
        #  '6337b2ed626ae2ff6f9bd7e09a90abf78cc61c301d5dd18fa936a893766c819e']

        for url_pattern in url_patterns:
            regex_patterns.append(re.compile('^' + url_pattern + '[a-zA-Z]+'))

        for drebin_apk_name, drebin_apk_path in drebin_apk_file_list.items():
            if drebin_apk_name not in apks_to_ignore:

                try:
                    apk_features[drebin_apk_name] = []

                    url_features = []
                    calls = []
                    api_calls = []

                    if analysis_mode is False:
                        apk_info[drebin_apk_name] = apk.APK(drebin_apk_path, raw=False, skip_analysis=False,
                                                            testzip=False)
                    else:

                        apk_object, dalvik_vmf, analysis_obj = AnalyzeAPK(drebin_apk_path)
                        apk_info[drebin_apk_name] = apk_object

                        strings = analysis_obj.get_strings_analysis()
                        for s in strings.keys():
                            if s != '':
                                for url_pattern in regex_patterns:
                                    if re.search(url_pattern, s):
                                        if s not in url_features:
                                            url_features.append(s)

                        for c in analysis_obj.get_classes():
                            for meth in c.get_methods():
                                for _, call, _ in meth.get_xref_to():
                                    calls.append(str(call.class_name) + "->" + str(call.name))
                                for _, call, _ in meth.get_xref_from():
                                    api_calls.append(str(call.class_name) + "->" + str(call.name))

                    features_dict = {
                        'permission': apk_info[drebin_apk_name].get_permissions(),
                        'activity': apk_info[drebin_apk_name].get_activities(),
                        'real_permission': apk_info[drebin_apk_name].get_requested_permissions(),
                        'feature': apk_object.get_features(),
                        'service_receiver': apk_info[drebin_apk_name].get_services() + apk_info[
                            drebin_apk_name].get_receivers(),
                        'provider': apk_info[drebin_apk_name].get_providers(),
                        'url': url_features,
                    }

                    possible_feature_names = ['permission', 'activity', 'provider', 'feature', 'url', 'network',
                                              'feature', 'call', 'api_call'
                                                                 'real_permission', 'service_receiver']

                    intents = []

                    for item_type in possible_feature_names:
                        for key in features_dict.keys():
                            for val in features_dict[key]:
                                intent_filters = apk_info[drebin_apk_name].get_intent_filters(item_type, val)

                                if len(intent_filters) > 0:
                                    for intent in intent_filters.values():
                                        if intent not in intents:
                                            intents.append(intent)

                    features_dict['intent'] = intents
                    features_dict['call'] = calls
                    features_dict['api_call'] = api_calls

                    apk_features[drebin_apk_name].append(features_dict)



                except OSError as exception:
                    Log.log_message(log_level="ERROR",
                                    log_message='cannot process file:' + drebin_apk_name + ' path:' + drebin_apk_path,
                                    exception=exception)

        return apk_features
Beispiel #25
0
class Apkinfo:
    """Information about apk based on androguard analysis"""

    __slots__ = [
        "ret_type", "apk", "dalvikvmformat", "analysis", "apk_filename",
        "apk_filepath"
    ]

    def __init__(self, apk_filepath):
        """Information about apk based on androguard analysis"""
        self.ret_type = androconf.is_android(apk_filepath)

        if self.ret_type == "APK":
            # return the APK, list of DalvikVMFormat, and Analysis objects
            self.apk, self.dalvikvmformat, self.analysis = AnalyzeAPK(
                apk_filepath)

        if self.ret_type == "DEX":
            # return the sha256hash, DalvikVMFormat, and Analysis objects
            _, _, self.analysis = AnalyzeDex(apk_filepath)

        self.apk_filename = os.path.basename(apk_filepath)
        self.apk_filepath = apk_filepath

    def __repr__(self):
        return f"<Apkinfo-APK:{self.apk_filename}>"

    @property
    def filename(self):
        """
        Return the filename of apk.

        :return: a string of apk filename
        """
        return os.path.basename(self.apk_filepath)

    @property
    def filesize(self):
        """
        Return the file size of apk file by bytes.

        :return: a number of size bytes
        """
        return os.path.getsize(self.apk_filepath)

    @property
    def md5(self):
        """
        Return the md5 checksum of the apk file.

        :return: a string of md5 checksum of the apk file
        """
        md5 = hashlib.md5()
        with open(self.apk_filepath, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                md5.update(chunk)
        return md5.hexdigest()

    @property
    def permissions(self):
        """
        Return all permissions from given APK.

        :return: a list of all permissions
        """
        if self.ret_type == "APK":
            return self.apk.get_permissions()

        if self.ret_type == "DEX":
            return []

    @functools.lru_cache()
    def find_method(self, class_name=".*", method_name=".*", descriptor=".*"):
        """
        Find method from given class_name, method_name and the descriptor.
        default is find all method.

        :param class_name: the class name of the Android API
        :param method_name: the method name of the Android API
        :param descriptor: the descriptor of the Android API
        :return: a generator of MethodClassAnalysis
        """

        regex_class_name = re.escape(class_name)
        regex_method_name = f"^{re.escape(method_name)}$"
        regex_descriptor = re.escape(descriptor)

        method_result = self.analysis.find_methods(
            classname=regex_class_name,
            methodname=regex_method_name,
            descriptor=regex_descriptor)
        if list(method_result):
            result, = list(
                self.analysis.find_methods(classname=regex_class_name,
                                           methodname=regex_method_name,
                                           descriptor=regex_descriptor))

            return result
        else:
            return None

    @functools.lru_cache()
    def upperfunc(self, method_analysis):
        """
        Return the xref from method from given method analysis instance.

        :param method_analysis: the method analysis in androguard
        :return: a set of all xref from functions
        """
        upperfunc_result = set()

        for _, call, _ in method_analysis.get_xref_from():
            # Call is the MethodAnalysis in the androguard
            # call.class_name, call.name, call.descriptor
            upperfunc_result.add(call)

        return upperfunc_result

    def get_method_bytecode(self, method_analysis):
        """
        Return the corresponding bytecode according to the
        given class name and method name.

        :param method_analysis: the method analysis in androguard
        :return: a generator of all bytecode instructions
        """

        try:
            for _, ins in method_analysis.get_method().get_instructions_idx():
                bytecode_obj = None
                reg_list = []

                # count the number of the registers.
                length_operands = len(ins.get_operands())
                if length_operands == 0:
                    # No register, no parameter
                    bytecode_obj = BytecodeObject(
                        ins.get_name(),
                        None,
                        None,
                    )
                elif length_operands == 1:
                    # Only one register

                    reg_list.append(
                        f"v{ins.get_operands()[length_operands - 1][1]}", )
                    bytecode_obj = BytecodeObject(
                        ins.get_name(),
                        reg_list,
                        None,
                    )
                elif length_operands >= 2:
                    # the last one is parameter, the other are registers.

                    parameter = ins.get_operands()[length_operands - 1]
                    for i in range(0, length_operands - 1):
                        reg_list.append("v" + str(ins.get_operands()[i][1]), )
                    if len(parameter) == 3:
                        # method or value
                        parameter = parameter[2]
                    else:
                        # Operand.OFFSET
                        parameter = parameter[1]

                    bytecode_obj = BytecodeObject(
                        ins.get_name(),
                        reg_list,
                        parameter,
                    )

                yield bytecode_obj
        except AttributeError as error:
            # TODO Log the rule here
            pass
def generate_facts(app_folder,result_prefix,rules,storage=None):
    files = get_all_in_dir(app_folder,"*")
    send_intent_actions_stats = Counter()
    recv_intent_actions_stats = Counter()
    len_files = 0
    is_apk = None
    for file in files:
        logging.info("Analyzing file %s",file)
        try:
            a,d, dx = AnalyzeAPK(file)
            is_apk = True
            # Create package to file relations
        except:
            is_apk = None
            print "Not valid APK file:  "+file
        try:
            if is_apk:
                with open(result_prefix+"_packages.txt", 'a') as f:
                    f.write("package('"+a.get_package()+"','"+ntpath.basename(file)+"').\n")
                # Permissions
                permissions = []
                permissions.extend([(str(a.get_package()), permission) for permission in a.get_permissions()])
                with open(result_prefix+"_uses_aux.txt", 'a') as f:
                    for permission in permissions:
                        f.write("uses('"+permission[0]+"','"+permission[1]+"').\n")
                # Intents
                logging.info("Looking for Intent Sends")
                sends = Set()
                sends.update([(str(a.get_package()),"i_"+intent.action) for intent in get_implicit_intents(a,d,dx)])
                send_intent_actions_stats.update([send[1] for send in sends])
                # Shared Prefs
                logging.info("Looking for Shared Prefs Sends")
                sends.update([(str(a.get_package()),"sp_"+shared.package+"_"+shared.preference_file) for shared in get_shared_preferences_writes(a,d,dx)])
                with open(result_prefix+"_trans_aux.txt", 'a') as f:
                    for send in sends:
                        f.write("trans('"+send[0]+"','"+escape_quotes(send[1])+"').\n")
                # Receivers
                logging.info("Looking for Dynamic Receivers")
                receives = Set()
                receives.update([(str(a.get_package()),"i_"+receiver.get_action()) for receiver in get_dynamic_receivers(a,d,dx)])
                logging.info("Looking for Static Receivers")
                receives.update([(str(a.get_package()),"i_"+receiver.get_action()) for receiver in get_static_receivers(a)])
                recv_intent_actions_stats.update([receive[1] for receive in receives])
                # Shared Prefs
                logging.info("Looking for Shared Prefs Receives")
                receives.update([(str(a.get_package()),"sp_"+shared.package+"_"+shared.preference_file) for shared in get_shared_preferences_reads(a,d,dx)])
                with open(result_prefix+"_recv_aux.txt", 'a') as f:
                     for receive in receives:
                        f.write("recv('"+receive[0]+"','"+escape_quotes(receive[1])+"').\n")
                len_files += 1
                utils.remove_duplicate_lines(result_prefix+"_uses_aux.txt",result_prefix+"_uses.txt",True)
                utils.remove_duplicate_lines(result_prefix+"_trans_aux.txt",result_prefix+"_trans.txt",True)
                utils.remove_duplicate_lines(result_prefix+"_recv_aux.txt",result_prefix+"_recv.txt",True)
        except:
            print "Error during analysis:  "+file
            traceback.print_exc()
    if rules != "":
        with open(os.path.splitext(rules)[0]+"_program.pl", 'w') as f:
            #write packages
            with open(result_prefix+"_packages.txt", 'r') as to_read:
                f.writelines(to_read.readlines())
            #write uses
            with open(result_prefix+"_uses.txt", 'r') as to_read:
                f.writelines(to_read.readlines())
            #write trans
            with open(result_prefix+"_trans.txt", 'r') as to_read:
                f.writelines(to_read.readlines())
                if storage:
                    f.write("trans(A,'external_storage'):- uses(A,'android.permission.WRITE_EXTERNAL_STORAGE').\n")
            #write receives
            with open(result_prefix+"_recv.txt", 'r') as to_read:
                f.writelines(to_read.readlines())
                if storage:
                    f.write("recv(A,'external_storage'):- uses(A,'android.permission.WRITE_EXTERNAL_STORAGE').\n")
                    f.write("recv(A,'external_storage'):- uses(A,'android.permission.READ_EXTERNAL_STORAGE').\n")
            with open(rules, 'r') as to_read:
                f.writelines(to_read.readlines())
    with open(result_prefix+"_intent_send_stats",'w') as send_stats_file:
        send_stats_file.write("**** Results for send intent analysis ****\n")
        send_stats_file.write("Files analized: ")
        send_stats_file.write(str(len_files))
        send_stats_file.write("\n")
        for send_stat in send_intent_actions_stats.most_common():
            freq = send_stat[1]/len_files
            send_stats_file.write(send_stat[0]+", "+"{0:.2f}".format(round(freq,2))+", "+str(send_stat[1])+"\n")
    with open(result_prefix+"_intent_recv_stats",'w') as recv_stats_file:
        recv_stats_file.write("**** Results for send intent analysis ****\n")
        recv_stats_file.write("Files analized: ")
        recv_stats_file.write(str(len_files))
        recv_stats_file.write("\n")
        for recv_stat in recv_intent_actions_stats.most_common():
            freq = recv_stat[1]/len_files
            recv_stats_file.write(recv_stat[0]+", "+"{0:.2f}".format(round(freq,2))+", "+str(recv_stat[1])+"\n")
    logging.info("Results saved in %s files",result_prefix)
    return os.path.splitext(rules)[0]+"_program.pl"
def main():
    a, d, dx = AnalyzeAPK('demo.apk')
    subclasses = extendsApplication(d)
    #print(subclasses)
    fields = callsGAC(d, subclasses)
def analyze_apk_androguard(apk_file: str,
                           md5_app: str = None,
                           dict_analysis_apk: dict = None):
    """

    Parameters
    ----------
    apk_file

    Returns
    -------

    """
    tracker_name_package = {}  # package name analytics to monitoring
    logger.info("Start App Analyzer")
    start = time.time()
    application, dalvik, analysis = AnalyzeAPK(apk_file)

    # read all trackers package name inside app
    with open(
            os.path.join(os.getcwd(), "resources",
                         "package_name_trackers_most_used.txt"), "r") as file:
        tracker_list = file.readlines()
        tracker_list = [x.strip() for x in tracker_list]

    # creation of regular expression for searching methods inside apps
    for tracker in tracker_list:
        name = tracker.split(",")[0]
        packages = tracker.split(",")[1].split("|")
        packages_new = []
        for package in packages:
            package_new = "L" + package.replace(".", "/")
            if package_new.endswith("/"):
                package_new = package_new + ".*"
            else:
                package_new = package_new + "/.*"
            packages_new.append(package_new)
        tracker_name_package[name] = packages_new

    # creation list of API for monitoring
    n_method = 0
    list_tracker_inside_app = []
    trackers_api_to_monitoring = {
    }  # dict api to monitoring during dynamic analysis
    for key, list_package_name in tracker_name_package.items():
        for package_name in list_package_name:
            methods = list(
                analysis.find_methods(package_name)
            )  # find all methods that satisfy regular expression

            if len(methods) > 0:
                trackers_api_to_monitoring[package_name] = []
                list_tracker_inside_app.append(key)

            # add each method to list for monitoring during dynamic analysis
            for method in methods:
                n_method = n_method + 1
                trackers_api_to_monitoring[package_name].append(
                    (method.get_method().get_class_name().replace(
                        "L", "", 1).replace("/", ".").replace(";", ""),
                     method.get_method().get_name()))

            if len(methods) > 0:
                # remove duplicate
                trackers_api_to_monitoring[package_name] = list(
                    set(trackers_api_to_monitoring[package_name]))

    list_tracker_inside_app = list(set(list_tracker_inside_app))
    list_permissions_app = application.get_permissions()
    end = time.time()
    logger.info(
        "Permission requested by the app {}".format(list_permissions_app))
    logger.info("Tracker inside the app {}".format(list_tracker_inside_app))
    logger.info("Execution time App Analyzer {}".format(end - start))
    # logger.info("API to Monitoring (Trackers) {}".format(n_method))

    dict_analysis_apk["permission_requested"] = list_permissions_app
    dict_analysis_apk["trackers_inside"] = list_tracker_inside_app
    dict_analysis_apk["execution_time_app_analyzer"] = end - start
    # dict_analysis_apk["api_to_monitoring_trackers"] = n_method

    write_result_md5_app(md5_app, list_tracker_inside_app,
                         list_permissions_app, end - start, dict_analysis_apk)
    logger.info("End App Analyzer")

    return list_tracker_inside_app, list_permissions_app, trackers_api_to_monitoring, application, dict_analysis_apk
Beispiel #29
0
from androguard.core.bytecodes import apk
from androguard.core.bytecodes import dvm
from androguard.core.analysis import analysis 
from androguard.misc import AnalyzeAPK

b = apk.APK("C://xampp//htdocs//Upload//sample.apk")
app_name=b.get_app_name()
pk_name = b.get_package()
android_version=b.get_androidversion_name()
permissions=b.get_permissions()
print(app_name)
print (pk_name)
print(android_version)
print(permissions)
a,d,dx = AnalyzeAPK("C://xampp//htdocs//Upload//sample.apk")
apis=dx.get_classes()
print(apis)