#!/usr/bin/python
import os
import sys
import time
import subprocess
import argparse
import sys
import shutil
import sqlite3
import glob

sys.path.append('/home/Research/tools/apktool')
from  pyappinfo.AppPipeline import AppPipeline

result_dir = None
device_port = None
index = 0
cmd_template = ( 'python3 start.py'
				+ ' -d %s'											
				+ ' -a %s'
				+ ' -o %s'
				+ ' -policy %s'
				+ ' -timeout  %s'
				+ ' -keep_app'
				)


def is_db_empty(app_api_db):
    db_connection = sqlite3.connect(app_api_db)
    sql_query = "select id, mtdsig from apitrace"
    db_cursor = db_connection.execute(sql_query)
    rows = [row for row in db_cursor]
    if rows:
    	# print "rows",rows
    	return False
    return True

def is_all_test_pkgs_installed():
	proc = subprocess.Popen([ "adb", "shell", "pm", "list", "packages"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
	stdout,stderr = proc.communicate()
	pkgs = stdout.split('\r\n')
	if "package:de.robv.android.xposed.installer" not in pkgs or "package:guard.api.sensitive.ui.sapiguard" not in pkgs or "package:eu.chainfire.supersu" not in pkgs:
		return False
	else:
		return True

def get_appresultpaths_of_fail_images():
	fail_image_path = '/home/Research/results/datas_old/fail_image'
	images = glob.glob(os.path.join(fail_image_path, '*.jpg'))
	
	appresultpaths = set()
	images = [image.split('/')[-1] for image in images]

	for root, dirs, files in os.walk("/home/Research/results/malware"):
		for file in files:
			if file in images:
				# print(os.path.join(root, file))
				appresultpaths.add(root.split('/')[-3])
	return appresultpaths				

def dynamic_analysis(app_path,pkgname,apkname):
	app_result_dir = os.path.join(result_dir, apkname)
	app_droidbot = os.path.join(app_result_dir, 'droidbot') 
	logcatfile = os.path.join(app_droidbot, 'logcat.txt')
	app_api_db = os.path.join(app_result_dir, 'sapiguard.db') 
	global index


	# if index <1005:
	# 	return

	# if index<1200 and not os.path.exists(app_result_dir):
	# 	print "analysed1: ",app_path
	# 	return

	# if os.path.exists(app_api_db) and os.path.exists(logcatfile):
	# 	lines = set(line.strip() for line in open(logcatfile))
	# 	for ln in lines:
	# 		if 'jie-' in ln:
	# 			print "analysed2: ",app_path
	# 			return
	# 	if is_db_empty(app_api_db):
	# 		print "analysed3: ",app_path
	# 		return

	if not is_all_test_pkgs_installed():
		print "monitor apks missing: ",app_path
		exit(1)


	# return
	# os.system('adb -s device-serial wait-for-device install '+ app_path)
	


	proc = subprocess.Popen(["adb", "-s", device_port, "wait-for-device", "install", app_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
	stdout,stderr = proc.communicate()
	if 'Failure' in stdout:
		print 'fail,',app_path
		recordFile = open('fail_apks.txt', 'a')
		recordFile.write('%s\n' % (app_path))
		recordFile.close()
		return

	print "installed"
	os.system('adb -s device-serial shell am broadcast -n guard.api.sensitive.ui.sapiguard/guard.api.sensitive.ui.sapiguard.components.PkgChange --es hookpkg '+ pkgname)
	time.sleep(5)
	# # run
	if os.path.exists(app_result_dir):
		shutil.rmtree(app_result_dir)
	os.makedirs(app_result_dir)
	app_droidbot = os.path.join(app_result_dir, 'droidbot') 
	os.makedirs(app_droidbot)

	cmd = cmd_template % (device_port, app_path, app_droidbot, "bfs_naive", '300')
	# print cmd
	os.system(cmd)

	time.sleep(2)

	os.system("adb -s device-serial shell am broadcast -n guard.api.sensitive.ui.sapiguard/guard.api.sensitive.ui.sapiguard.components.PkgChange -a android.intent.action.DB_EXTRACTED")


	
	app_screenshots = os.path.join(app_result_dir, 'screenshots') 
	time.sleep(5)

	os.system("adb -s device-serial pull /storage/emulated/0/sapiguard/sapiguard.db " + app_api_db)
	os.system("adb -s device-serial pull /sdcard/sapiguardSS " + app_screenshots)
	
	os.system("adb -s device-serial uninstall "+pkgname)
	print "uninstalled"
	# time.sleep(3)
	
	os.system("echo "+app_path+" "+pkgname+" >> ./out.txt")

def analysis_apps(app_info_db):
	db_pipeline = AppPipeline(app_info_db)
	db_pipeline.initialize()
	app_infos = db_pipeline.get_all_apps_apppath_apkname_pkgname_mainaty_perms()
	db_pipeline.finalize()
	global index
	mill1 = int(round(time.time()))
	appresultpaths_of_fail_images = get_appresultpaths_of_fail_images()
	# index = 0
	for info in app_infos:
		apppath,apkname,pkgname,mainaty,perms = info
		if   perms is None :
			os.system("echo "+apppath+" >> ./out_none_perms.txt")
			# continue
		if  apkname not in appresultpaths_of_fail_images:
			continue

		print index, '-----',apppath

		dynamic_analysis(apppath,pkgname,apkname)
		mill2 = int(round(time.time()))
		if (mill2-mill1)>3600:
			time.sleep(1200)
			mill1 = int(round(time.time()))
		index+=1


#python ./main.py -appinfodb /home/Research/tools/apktool/results/fdroid_28_9_2018.db -devicePort device-serial 
if __name__ == "__main__":
	#process arguments
	parser = argparse.ArgumentParser(prog = 'python main_start.py', description = 'execute app on the phone and collect sensitive api info at runtime')
	parser.add_argument('-malinfo', nargs = 1, help = 'specify the path of the db file which includes malwares paths', default = ['/home/Research/tools/apktool/results/drebin_179f_1500_appsinfo.db'])

	parser.add_argument('-resultdir', nargs = 1, help = 'specify the directory of the file saving results of the analysis', default = ['/home/Research/results/malwarenew'])
	parser.add_argument('-devicePort', nargs = 1, help = 'android device port', default = ['device-serial'])

	args = parser.parse_args()


	if args.malinfo is None or args.devicePort is None:
		parser.print_help()
		sys.exit()

	device_port = args.devicePort[0]
	result_dir = args.resultdir[0]
	mal_info = args.malinfo[0]
	
	analysis_apps(mal_info)
		