Exemplo n.º 1
0
def clear():
	"""
	Making space for progressbars
	"""
	with common.term.location():
		logger.info('Please wait while QARK tries to decompile the code back to source using multiple decompilers. This may take a while.')
		print("\n"*11)
Exemplo n.º 2
0
def clear():
    """
	Making space for progressbars
	"""
    with common.term.location():
        logger.info(
            'Please wait while QARK tries to decompile the code back to source using multiple decompilers. This may take a while.'
        )
        print("\n" * 11)
Exemplo n.º 3
0
def find_manifest_in_unpacked_apk(path, name):
    """
	Finds manifest.xml from the unpacked APK
	"""
    pathFromAPK = path.rsplit(".", 1)[0]
    common.sourceDirectory = pathFromAPK
    logger.info('Finding %s in %s', name, pathFromAPK)
    common.logger.debug(pathFromAPK, name)
    for root, dirs, files in os.walk(pathFromAPK):
        for file in files:
            if name in file:
                logger.info('%s found', name)
                return os.path.join(root, name)
Exemplo n.º 4
0
def find_manifest_in_unpacked_apk(path, name):
	"""
	Finds manifest.xml from the unpacked APK
	"""
	pathFromAPK = path.rsplit(".",1)[0]
	common.sourceDirectory=pathFromAPK
	logger.info('Finding %s in %s', name,pathFromAPK)
	common.logger.debug(pathFromAPK, name)
	for root, dirs, files in os.walk(pathFromAPK):
		for file in files:
			if name in file:
				logger.info('%s found', name)
				return os.path.join(root, name)
Exemplo n.º 5
0
def unpack():
    """
	APK to DEX
	"""
    logger.info('Unpacking %s', common.apkPath)
    #Get the directory to unpack to
    try:
        dirname, extension = common.apkPath.rsplit(".", 1)
        #workaround for cases where path may include whitespace
        file_temp = open(common.apkPath, 'r')
        zf = zipfile.ZipFile(file_temp)
        logger.info('Zipfile: %s', zf)
        for filename in [zf.namelist()]:
            logger.info('UnpackAPK: in for loop file: %s', filename)
            if not os.path.exists(dirname + "/"):
                os.makedirs(dirname + "/")
            zf.extractall(
                dirname + "/",
                zf.namelist(),
            )
            logger.info('Extracted APK to %s', dirname + '/')
            common.pathToDEX = dirname + "/classes.dex"
            common.pathToUnpackedAPK = dirname + '/'
            return True
    except Exception as e:
        print(e)
        if not common.interactive_mode:
            logger.error(common.args.pathtoapk +
                         common.config.get('qarkhelper', 'NOT_A_VALID_APK'))
            exit()
        logger.error(
            common.config.get('qarkhelper', 'NOT_A_VALID_APK_INTERACTIVE'))
        raise
Exemplo n.º 6
0
def unpack():
	"""
	APK to DEX
	"""
	logger.info('Unpacking %s', common.apkPath)
	#Get the directory to unpack to
	try:
		dirname, extension = common.apkPath.rsplit(".",1)
		#workaround for cases where path may include whitespace
		file_temp = open(common.apkPath,'r')
		zf = zipfile.ZipFile(file_temp)
		logger.info('Zipfile: %s', zf)
		for filename in [ zf.namelist()]:
			if not os.path.exists(dirname + "/"):
				os.makedirs(dirname + "/")
			zf.extractall(dirname + "/", zf.namelist(), )
			logger.info('Extracted APK to %s', dirname + '/')
			common.pathToDEX = dirname + "/classes.dex"
			common.pathToUnpackedAPK = dirname + '/'
			return True
	except Exception as e:
		if not common.interactive_mode:
				logger.error(common.args.pathtoapk + common.config.get('qarkhelper', 'NOT_A_VALID_APK'))
				exit()
		logger.error(common.config.get('qarkhelper', 'NOT_A_VALID_APK_INTERACTIVE'))
		raise
Exemplo n.º 7
0
def unpack():
    """
	APK to DEX
	"""
    logger.info('Unpacking %s', common.apkPath)
    # Get the directory to unpack to
    try:
        dirname, extension = common.apkPath.rsplit(".", 1)
        # workaround for cases where path may include whitespace
        file_temp = open(common.apkPath, 'r')
        zf = zipfile.ZipFile(file_temp)
        logger.info('Zipfile: %s', zf)
        for filename in [zf.namelist()]:
            if not os.path.exists(dirname + "/"):
                os.makedirs(dirname + "/")
            zf.extractall(
                dirname + "/",
                zf.namelist(),
            )
            logger.info('Extracted APK to %s', dirname + '/')
            common.pathToDEX = dirname + "/classes.dex"
            if not os.path.exists(
                    common.pathToDEX
            ):  # Some default/system APKs from Google don't have this file
                logger.error(
                    "The classes.dex file was not found for this APK! Please select a different APK."
                )
                raise Exception
            common.pathToUnpackedAPK = dirname + '/'
            return True
    except Exception as e:
        if not common.interactive_mode:
            logger.error(common.args.apkpath +
                         common.config.get('qarkhelper', 'NOT_A_VALID_APK'))
            exit()
        logger.error(
            common.config.get('qarkhelper', 'NOT_A_VALID_APK_INTERACTIVE'))
        raise
Exemplo n.º 8
0
def decompile(path):
    """
	Converts DEX to JAR(containing class files) and then class files to near original java code using 3 different decompilers and selecting the best available decompiled code
	"""
    common.pathToDEX = path
    pathToDex2jar = common.rootDir + "/lib/dex2jar/dex2jar.sh"
    sp = subprocess.Popen([pathToDex2jar, common.pathToDEX],
                          shell=False,
                          stdout=subprocess.PIPE,
                          stderr=subprocess.STDOUT)
    output, error = sp.communicate()
    common.pathToJar = common.pathToDEX.rsplit(".", 1)[0] + "_dex2jar.jar"
    dirname, extension = common.pathToJar.rsplit(".", 1)
    zf = zipfile.ZipFile(common.pathToJar)

    # Total number of class files that need to be decompiled
    total_files = len(zf.namelist())
    report.write("totalfiles", total_files)
    common.count = len(
        [s for s in zf.namelist() if ((".class" in s) and ("$" not in s))])

    pub.subscribe(decompiler_update, 'decompile')

    thread0 = Process(name='clear', target=clear, args=())
    thread1 = Process(name='jdcore',
                      target=jdcore,
                      args=(zf.filename, dirname))
    thread2 = Process(name='procyon', target=cfr, args=(zf.filename, dirname))
    thread3 = Process(name='cfr', target=procyon, args=(zf.filename, dirname))

    thread0.start()
    thread0.join()

    progressbar1.start()
    progressbar2.start()
    progressbar3.start()

    thread1.start()
    thread2.start()
    thread3.start()
    thread1.join(0)
    thread2.join(0)
    thread3.join(0)

    with common.term.cbreak():
        val = None
        while val not in (u'c', u'C'):
            with common.term.location(0, common.term.height - 3):
                print "Decompilation may hang/take too long (usually happens when the source is obfuscated)."
                print "At any time," + common.term.bold_underline_red_on_white(
                    'Press C to continue'
                ) + " and QARK will attempt to run SCA on whatever was decompiled."
                val = common.term.inkey(timeout=1)
                if not (thread1.is_alive() or thread2.is_alive()
                        or thread3.is_alive()):
                    break

    if thread1.is_alive():
        thread1.terminate()
    if thread2.is_alive():
        thread2.terminate()
    if thread3.is_alive():
        thread3.terminate()

    # Go back to the bottom of the screen
    with common.term.location(0, common.term.height):
        print ""

    g1 = grep_1(dirname, "// Byte code:")
    g2 = grep_1(dirname + "1", "// This method has failed to decompile.")
    g3 = grep_1(dirname + "2", "// This method could not be decompiled.")

    # print list(set(g1) - set(g2))
    logger.info("Trying to improve accuracy of the decompiled files")
    restored = 0
    try:
        for filename in g1:
            relative_filename = str(filename).split(dirname)[1]
            if any(relative_filename in s for s in g2):
                if any(relative_filename in s for s in g3):
                    logger.debug("Failed to reconstruct: " + relative_filename)
                else:
                    shutil.copy(dirname + "2" + relative_filename, filename)
                    restored = restored + 1
            else:
                shutil.copy(dirname + "1" + relative_filename, filename)
                restored = restored + 1
    except Exception as e:
        print e.message
    report.write(
        "restorestats", "Restored " + str(restored) + " file(s) out of " +
        str(len(g1)) + " corrupt file(s)")
    logger.info("Restored " + str(restored) + " file(s) out of " +
                str(len(g1)) + " corrupt file(s)")
    logger.debug("Deleting redundant decompiled files")
    try:
        shutil.rmtree(dirname + "1")
        logger.debug("Deleted " + dirname + "1")
        shutil.rmtree(dirname + "2")
        logger.debug("Deleted " + dirname + "2")
    except Exception as e:
        logger.debug(
            "Unable to delete redundant decompiled files (no impact on scan results): "
            + str(e))
Exemplo n.º 9
0
def decompile(path):
	"""
	Converts DEX to JAR(containing class files) and then class files to near original java code using 3 different decompilers and selecting the best available decompiled code
	"""
	common.pathToDEX = path
	pathToDex2jar = common.rootDir + "/lib/dex2jar/dex2jar.sh"
	sp = subprocess.Popen([pathToDex2jar, common.pathToDEX], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
	output, error = sp.communicate()
	common.pathToJar = common.pathToDEX.rsplit(".",1)[0] + "_dex2jar.jar"
	dirname, extension = common.pathToJar.rsplit(".",1)
	zf = zipfile.ZipFile(common.pathToJar)

	#Total number of class files that need to be decompiled
	total_files = len(zf.namelist())
	report.write("totalfiles", total_files)
	common.count = len([s for s in zf.namelist() if ((".class" in s) and ("$" not in s))])

	pub.subscribe(decompiler_update, 'decompile')

	thread0 = Process(name='clear', target=clear, args = ())
	thread1 = Process(name='jdcore', target=jdcore, args = (zf.filename,dirname))
	thread2 = Process(name='procyon', target=cfr, args = (zf.filename,dirname))
	thread3 = Process(name='cfr', target=procyon, args = (zf.filename,dirname))

	thread0.start()
	thread0.join()

	progressbar1.start()
	progressbar2.start()
	progressbar3.start()


	thread1.start()
	thread2.start()
	thread3.start()
	thread1.join(0)
	thread2.join(0)
	thread3.join(0)

	with common.term.cbreak():
		val = None
		while val not in (u'c', u'C'):
			with common.term.location(0,common.term.height-3):
				print "Decompilation may hang/take too long (usually happens when the source is obfuscated)."
				print "At any time," + common.term.bold_underline_red_on_white('Press C to continue') + " and QARK will attempt to run SCA on whatever was decompiled."
				val = common.term.inkey(timeout=1)
				if not (thread1.is_alive() or thread2.is_alive() or thread3.is_alive()):
					break

	if thread1.is_alive():
		thread1.terminate()
	if thread2.is_alive():
		thread2.terminate()
	if thread3.is_alive():
		thread3.terminate()

	#Go back to the bottom of the screen
	with common.term.location(0,common.term.height):
		print ""

	g1 = grep_1(dirname, "// Byte code:")
	g2 = grep_1(dirname+"1", "// This method has failed to decompile.")
	g3 = grep_1(dirname+"2", "// This method could not be decompiled.")

	#print list(set(g1) - set(g2))
	logger.info("Trying to improve accuracy of the decompiled files")
	restored = 0
	try:
		for filename in g1:
			relative_filename = str(filename).split(dirname)[1]
			if any(relative_filename in s for s in g2):
				if any(relative_filename in s for s in g3):
					logger.debug("Failed to reconstruct: " + relative_filename)
				else:
					shutil.copy(dirname+"2"+relative_filename, filename)
					restored = restored +1
			else:
				shutil.copy(dirname+"1"+relative_filename, filename)
				restored = restored +1
	except Exception as e:
		print e.message
	report.write("restorestats","Restored " + str(restored) + " file(s) out of " + str(len(g1)) + " corrupt file(s)")
	logger.info("Restored " + str(restored) + " file(s) out of " + str(len(g1)) + " corrupt file(s)")
	logger.debug("Deleting redundant decompiled files")
	try:
		shutil.rmtree(dirname+"1")
		logger.debug("Deleted " + dirname+"1")
		shutil.rmtree(dirname+"2")
		logger.debug("Deleted " + dirname+"2")
	except Exception as e:
		logger.debug("Unable to delete redundant decompiled files (no impact on scan results): " + str(e))