def get_env(md5_hash, package, launcher): base_dir = settings.BASE_DIR app_dir = os.path.join(settings.UPLD_DIR, md5_hash + '/') # APP DIRECTORY app_file = md5_hash + '.apk' # NEW FILENAME app_path = app_dir + app_file # APP PATH toolsdir = os.path.join(base_dir, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(toolsdir) #if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": # proxy_ip = '127.0.0.1' #else: # proxy_ip = settings.PROXY_IP # Proxy IP #start_proxy(settings.PORT, package) # AVD only needs to wait, vm needs the connect function try: if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": avd_load_wait(adb) else: connect(toolsdir) except Exception as exp: print("\n[WARNING] ADB Load Wait Failed") return HttpResponseRedirect('/error/') # Change True to support non-activity components install_and_run(toolsdir, app_path, package, launcher, True) screen_width, screen_width = get_res() data = { 'ready': 'yes', 'screen_witdth': screen_width, 'screen_height': screen_width, } return data
def TakeScreenShot(request): print "\n[INFO] Taking Screenshot" try: if request.method == 'POST': MD5 = request.POST['md5'] m = re.match('^[0-9a-f]{32}$', MD5) if m: data = {} r = random.randint(1, 1000000) DIR = settings.BASE_DIR # make sure that list only png from this directory SCRDIR = os.path.join( settings.UPLD_DIR, MD5 + '/screenshots-apk/') TOOLSDIR = os.path.join( DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(TOOLSDIR) subprocess.call([adb, "-s", getIdentifier(), "shell", "screencap", "-p", "/data/local/screen.png"]) subprocess.call([adb, "-s", getIdentifier(), "pull", "/data/local/screen.png", SCRDIR + "screenshot-" + str(r) + ".png"]) print "\n[INFO] Screenshot Taken" data = {'screenshot': 'yes'} return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Taking Screenshot") return HttpResponseRedirect('/error/')
def execute_adb(request): """Execute ADB Commands""" print("\n[INFO] Executing ADB Commands") try: if request.method == 'POST': data = {} cmd = request.POST['cmd'] ''' Allow dangerous chars as it's functional TODO: Deal with it. ''' adb = getADB() args = [adb, "-s", get_identifier()] + cmd.split(' ') resp = "error" try: resp = adb except: PrintException("[ERROR] Executing ADB Commands") data = {'cmd': 'yes', 'resp': resp.decode("utf8", "ignore")} return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Executing ADB Commands") return HttpResponseRedirect('/error/')
def clip_dump(request): """ Dump Android ClipBoard """ print "\n[INFO] Starting Clipboard Dump Service in VM/Device" try: data = {} if request.method == 'POST': tools_dir = os.path.join( settings.BASE_DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(tools_dir) args = [adb, "-s", getIdentifier(), "shell", "am", "startservice", "opensecurity.clipdump/.ClipDumper"] try: subprocess.call(args) data = {'status': 'success'} except: PrintException("[ERROR] Dumping Clipboard") data = {'status': 'error'} else: data = {'status': 'failed'} return HttpResponse(json.dumps(data), content_type='application/json') except: PrintException("[ERROR] Dumping Clipboard") return HttpResponseRedirect('/error/')
def install_and_run(toolsdir, apk_path, package, launcher, is_activity): """Install APK and Run it""" print("\n[INFO] Starting App for Dynamic Analysis") adb = getADB(toolsdir) print("\n[INFO] Installing APK") install_result = subprocess.check_output( [adb, "-s", get_identifier(), "install", "-r", apk_path]) print(install_result) # not signed error # sign example: jarsigner -verbose -keystore davidblus_android.keystore -storepass davidblus -signedjar app_signed.apk app.apk davidblus_android.keystore if b'INSTALL_PARSE_FAILED_NO_CERTIFICATES' in install_result: signed_apk_path = sign_apk(apk_path) install_result = subprocess.check_output( [adb, "-s", get_identifier(), "install", "-r", signed_apk_path]) print(install_result) if b'Success' not in install_result: raise Exception('Install Error') if is_activity: run_app = package + "/" + launcher print("\n[INFO] Launching APK Main Activity") subprocess.call([ adb, "-s", get_identifier(), "shell", "am", "start", "-n", run_app ]) else: print("\n[INFO] App Doesn't have a Main Activity") print("[INFO] Testing Environment is Ready!")
def ExecuteADB(request): print "\n[INFO] Executing ADB Commands" try: if request.method == 'POST': data = {} CMD = request.POST['cmd'] ''' #Allow it Since it's functional if re.findall(";|\$\(|\|\||&&",CMD): print "[ATTACK] Possible RCE" return HttpResponseRedirect('/error/') ''' TOOLSDIR = os.path.join( settings.BASE_DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(TOOLSDIR) args = [adb, "-s", getIdentifier()] + CMD.split(' ') resp = "error" try: resp = subprocess.check_output(args) except: PrintException("[ERROR] Executing ADB Commands") data = {'cmd': 'yes', 'resp': resp} return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Executing ADB Commands") return HttpResponseRedirect('/error/')
def get_res(): """Get Screen Resolution or Device or VM""" print "\n[INFO] Getting Screen Resolution" try: toolsdir = os.path.join( settings.BASE_DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(toolsdir) resp = subprocess.check_output( [adb, "-s", get_identifier(), "shell", "dumpsys", "window"]) resp = resp.split("\n") res = "" for line in resp: if "mUnrestrictedScreen" in line: res = line break res = res.split("(0,0)")[1] res = res.strip() res = res.split("x") if len(res) == 2: return res[0], res[1] # width, height return "", "" except: PrintException("[ERROR] Getting Screen Resolution") return "", ""
def install_and_run(toolsdir, apk_path, package, launcher, is_activity): """Install APK and Run it""" print "\n[INFO] Starting App for Dynamic Analysis" # try: adb = getADB(toolsdir) print "\n[INFO] Installing APK" install_result = subprocess.check_output( [adb, "-s", get_identifier(), "install", "-r", apk_path]) print install_result # 如果是未签名的错误,则对其进行签名并安装, # 签名命令示例:jarsigner -verbose -keystore davidblus_android.keystore -storepass davidblus -signedjar app_signed.apk app.apk davidblus_android.keystore if 'INSTALL_PARSE_FAILED_NO_CERTIFICATES' in install_result: signed_apk_path = sign_apk(apk_path) install_result = subprocess.check_output( [adb, "-s", get_identifier(), "install", "-r", signed_apk_path]) print install_result if 'Success' not in install_result: raise Exception('Install Error') if is_activity: run_app = package + "/" + launcher print "\n[INFO] Launching APK Main Activity" subprocess.call([ adb, "-s", get_identifier(), "shell", "am", "start", "-n", run_app ]) else: print "\n[INFO] App Doesn't have a Main Activity" # Handle Service or Give Choice to Select in Future. print "[INFO] Testing Environment is Ready!"
def MobSFCA(request): try: if request.method == 'POST': data = {} act = request.POST['action'] TOOLSDIR = os.path.join( settings.BASE_DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR ROOTCA = os.path.join( settings.BASE_DIR, 'DynamicAnalyzer/pyWebProxy/ca.crt') adb = getADB(TOOLSDIR) if act == "install": print "\n[INFO] Installing MobSF RootCA" subprocess.call([adb, "-s", getIdentifier(), "push", ROOTCA, "/data/local/tmp/" + settings.ROOT_CA]) subprocess.call([adb, "-s", getIdentifier(), "shell", "su", "-c", "cp", "/data/local/tmp/" + settings.ROOT_CA, "/system/etc/security/cacerts/" + settings.ROOT_CA]) subprocess.call([adb, "-s", getIdentifier(), "shell", "su", "-c", "chmod", "644", "/system/etc/security/cacerts/" + settings.ROOT_CA]) subprocess.call([adb, "-s", getIdentifier(), "shell", "rm", "/data/local/tmp/" + settings.ROOT_CA]) data = {'ca': 'installed'} elif act == "remove": print "\n[INFO] Removing MobSF RootCA" subprocess.call([adb, "-s", getIdentifier(), "shell", "su", "-c", "rm", "/system/etc/security/cacerts/" + settings.ROOT_CA]) data = {'ca': 'removed'} return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] MobSF RootCA Handler") return HttpResponseRedirect('/error/')
def touch(request): """Sending Touch Events""" logger.info("Sending Touch Events") try: data = {} if (request.method == 'POST') and (is_number(request.POST['x'])) and (is_number(request.POST['y'])): x_axis = request.POST['x'] y_axis = request.POST['y'] adb = getADB() args = ["input", "tap", x_axis, y_axis] data = {'status': 'success'} try: adb_command(args, True) except: data = {'status': 'error'} PrintException("Performing Touch Action") else: data = {'status': 'failed'} return HttpResponse(json.dumps(data), content_type='application/json') except: PrintException("Sending Touch Events") return print_n_send_error_response(request, "Error Sending Touch Events", True)
def start_dm(md5_hash, package, launcher): # Start DM #stop_capfuzz(settings.PORT) toolsdir = os.path.join(settings.BASE_DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(toolsdir) if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_REAL_DEVICE": print( "\n[INFO] MobSF will perform Dynamic Analysis on real Android Device" ) is_avd = False elif settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": # adb, avd_path, reference_name, dup_name, emulator is_avd = True refresh_avd(adb, settings.AVD_PATH, settings.AVD_REFERENCE_NAME, settings.AVD_DUP_NAME, settings.AVD_EMULATOR) else: # Refersh VM is_avd = False refresh_vm(settings.UUID, settings.SUUID, settings.VBOX) context = { 'md5': md5_hash, 'pkg': package, 'lng': launcher, 'title': 'Start Testing', 'AVD': is_avd, } return context
def auto_app_test(app_info): base_dir = settings.BASE_DIR toolsdir = os.path.join(base_dir, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(toolsdir) print(u'\n[INFO] 开始自动化测试...') # monkey script 测试,用于进入初始化界面 monkey_script_test(adb, app_info) packagename = app_info['packagename'] # monkey 测试,输出太多,重定向输出 p = subprocess.Popen([ adb, '-s', get_identifier(), 'shell', 'monkey', '-p', packagename, '--ignore-crashes', '--ignore-timeouts', '--monitor-native-crashes', '-v', '-v', '-v', '300' ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) # 设置超时检查 start_time = time.time() while True: if p.poll() is not None: #useless_out, useless_err = p.communicate() break if time.time() - start_time > 60: p.terminate() break time.sleep(0.5) # TODO: 添加其他测试方法 return
def clip_dump(request): """Dump Android ClipBoard""" print("\n[INFO] Starting Clipboard Dump Service in VM/Device") try: data = {} if request.method == 'POST': toolsdir = os.path.join( settings.BASE_DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(toolsdir) args = [adb, "-s", get_identifier(), "shell", "am", "startservice", "opensecurity.clipdump/.ClipDumper"] try: subprocess.call(args) data = {'status': 'success'} except: PrintException("[ERROR] Dumping Clipboard") data = {'status': 'error'} else: data = {'status': 'failed'} return HttpResponse(json.dumps(data), content_type='application/json') except: PrintException("[ERROR] Dumping Clipboard") return HttpResponseRedirect('/error/')
def connect(): """Connect to VM/Device""" logger.info("Connecting to VM/Device") adb = getADB() subprocess.call([adb, "kill-server"]) subprocess.call([adb, "start-server"]) logger.info("ADB Started") wait(5) logger.info("Connecting to VM/Device") out = subprocess.check_output([adb, "connect", get_identifier()]) if b"unable to connect" in out: raise ValueError("ERROR Connecting to VM/Device. ", out.decode("utf-8").replace("\n", "")) try: subprocess.call([adb, "-s", get_identifier(), "wait-for-device"]) logger.info("Mounting") if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_REAL_DEVICE": adb_command(["su", "-c", "mount", "-o", "rw,remount,rw", "/system"], True) else: adb_command(["su", "-c", "mount", "-o", "rw,remount,rw", "/system"], True) # This may not work for VMs other than the default MobSF VM adb_command(["mount", "-o", "rw,remount", "-t", "rfs", "/dev/block/sda6", "/system"], True) except: PrintException("Connecting to VM/Device")
def final_test(request): """Collecting Data and Cleanup""" global TCP_SERVER_MODE print("\n[INFO] Collecting Data and Cleaning Up") try: if request.method == 'POST': data = {} md5_hash = request.POST['md5'] package = request.POST['pkg'] if re.findall(r";|\$\(|\|\||&&", package): print("[ATTACK] Possible RCE") return HttpResponseRedirect('/error/') if re.match('^[0-9a-f]{32}$', md5_hash): # Stop ScreenCast Client if it is running TCP_SERVER_MODE = "off" base_dir = settings.BASE_DIR apk_dir = os.path.join(settings.UPLD_DIR, md5_hash + '/') toolsdir = os.path.join(base_dir, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(toolsdir) # Change to check output of subprocess when analysis is done # Can't RCE os.system(adb + ' -s ' + get_identifier() + ' logcat -d dalvikvm:W ActivityManager:I > "' + apk_dir + 'logcat.txt"') print("\n[INFO] Downloading Logcat logs") subprocess.call([ adb, "-s", get_identifier(), "pull", "/data/data/de.robv.android.xposed.installer/log/error.log", apk_dir + "x_logcat.txt" ]) print("\n[INFO] Downloading Droidmon API Monitor Logcat logs") # Can't RCE os.system(adb + ' -s ' + get_identifier() + ' shell dumpsys > "' + apk_dir + 'dump.txt"') print("\n[INFO] Downloading Dumpsys logs") subprocess.call([ adb, "-s", get_identifier(), "shell", "am", "force-stop", package ]) print("\n[INFO] Stopping Application") subprocess.call([ adb, "-s", get_identifier(), "shell", "am", "force-stop", "opensecurity.screencast" ]) print("\n[INFO] Stopping ScreenCast Service") data = {'final': 'yes'} return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Clean Up") return HttpResponseRedirect('/error/')
def android_dynamic_analyzer(request): """Android Dynamic Analyzer View""" print("\n[INFO] Dynamic Analysis Started") try: if request.method == 'POST': md5_hash = request.POST['md5'] package = request.POST['pkg'] launcher = request.POST['lng'] if re.findall(r';|\$\(|\|\||&&', package) or re.findall( r';|\$\(|\|\||&&', launcher): print("[ATTACK] Possible RCE") return HttpResponseRedirect('/error/') if re.match('^[0-9a-f]{32}$', md5_hash): # Delete ScreenCast Cache screen_file = os.path.join(settings.SCREEN_DIR, 'screen.png') if os.path.exists(screen_file): os.remove(screen_file) # Delete Contents of Screenshot Dir screen_dir = os.path.join(settings.UPLD_DIR, md5_hash + '/screenshots-apk/') if os.path.isdir(screen_dir): shutil.rmtree(screen_dir) else: os.makedirs(screen_dir) # Start DM stop_capfuzz(settings.PORT) toolsdir = os.path.join(settings.BASE_DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(toolsdir) if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_REAL_DEVICE": print( "\n[INFO] MobSF will perform Dynamic Analysis on real Android Device" ) is_avd = False elif settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": # adb, avd_path, reference_name, dup_name, emulator is_avd = True refresh_avd(adb, settings.AVD_PATH, settings.AVD_REFERENCE_NAME, settings.AVD_DUP_NAME, settings.AVD_EMULATOR) else: # Refersh VM is_avd = False refresh_vm(settings.UUID, settings.SUUID, settings.VBOX) context = { 'md5': md5_hash, 'pkg': package, 'lng': launcher, 'title': 'Start Testing', 'AVD': is_avd, } template = "dynamic_analysis/start_test.html" return render(request, template, context) else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] DynamicAnalyzer") return HttpResponseRedirect('/error/')
def execute_adb(request): """Execute ADB Commands""" print("\n[INFO] Executing ADB Commands") try: if request.method == 'POST': data = {} cmd = request.POST['cmd'] ''' Allow dangerous chars as it's functional TODO: Deal with it. ''' toolsdir = os.path.join( settings.BASE_DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(toolsdir) args = [adb, "-s", get_identifier()] + cmd.split(' ') resp = "error" try: resp = subprocess.check_output(args) except: PrintException("[ERROR] Executing ADB Commands") data = {'cmd': 'yes', 'resp': resp.decode("utf8", "ignore")} return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Executing ADB Commands") return HttpResponseRedirect('/error/')
def touch(request): """Sending Touch Events""" print("\n[INFO] Sending Touch Events") try: data = {} if (request.method == 'POST') and (is_number(request.POST['x'])) and (is_number(request.POST['y'])): x_axis = request.POST['x'] y_axis = request.POST['y'] toolsdir = os.path.join( settings.BASE_DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(toolsdir) args = [adb, "-s", get_identifier(), "shell", "input", "tap", x_axis, y_axis] data = {'status': 'success'} try: subprocess.call(args) except: data = {'status': 'error'} PrintException("[ERROR] Performing Touch Action") else: data = {'status': 'failed'} return HttpResponse(json.dumps(data), content_type='application/json') except: PrintException("[ERROR] Sending Touch Events") return HttpResponseRedirect('/error/')
def yield_dynamic_run(apk_path): try: #step1: app_info app_info = get_base_info(apk_path) #step2 init virtual android devices by virtualbox refresh_vm(SETTINGS.UUID, SETTINGS.SUUID, SETTINGS.VBOX) connect(DYNAMIC_TOOL_DIR) #step3 install, run install_and_run(DYNAMIC_TOOL_DIR, app_info['apk_path'], app_info['packagename'], app_info['main_activity'], True) #step4 auto_app_test and start download x_logcat.txt #auto_app_test in another thread, download in main thread set_run_state(True) adb = getADB(DYNAMIC_TOOL_DIR) monkey = threading.Thread(target=monkey_test, args=(adb, app_info)) monkey.start() for cnt in yield_droidmon_download(adb, app_info['detail_dir'], app_info['packagename']): yield cnt if not check_run_state(): break monkey.join() except Exception as e: result = {} traceback.print_exc()
def connect(toolsdir): """Connect to VM/Device""" print "\n[INFO] Connecting to VM/Device" try: adb = getADB(toolsdir) subprocess.call([adb, "kill-server"]) subprocess.call([adb, "start-server"]) print "\n[INFO] ADB Started" wait(5) print "\n[INFO] Connecting to VM/Device" subprocess.call([adb, "connect", get_identifier()]) subprocess.call([adb, "-s", get_identifier(), "wait-for-device"]) print "\n[INFO] Mounting" if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_REAL_DEVICE": subprocess.call([ adb, "-s", get_identifier(), "shell", "su", "-c", "mount", "-o", "rw,remount,rw", "/system" ]) else: subprocess.call([ adb, "-s", get_identifier(), "shell", "su", "-c", "mount", "-o", "rw,remount,rw", "/system" ]) # This may not work for VMs other than the default MobSF VM subprocess.call([ adb, "-s", get_identifier(), "shell", "mount", "-o", "rw,remount", "-t", "rfs", "/dev/block/sda6", "/system" ]) except: PrintException("[ERROR] Connecting to VM/Device")
def get_res(): """Get Screen Resolution or Device or VM""" print("\n[INFO] Getting Screen Resolution") try: toolsdir = os.path.join(settings.BASE_DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(toolsdir) resp = subprocess.check_output( [adb, "-s", get_identifier(), "shell", "dumpsys", "window"]) resp = resp.decode("utf-8").split("\n") res = "" for line in resp: if "mUnrestrictedScreen" in line: res = line break res = res.split("(0,0)")[1] res = res.strip() res = res.split("x") if len(res) == 2: return res[0], res[1] # width, height return "", "" except: PrintException("[ERROR] Getting Screen Resolution") return "", ""
def touch(request): """Sending Touch Events""" print("\n[INFO] Sending Touch Events") try: data = {} if (request.method == 'POST') and (is_number(request.POST['x'])) and (is_number(request.POST['y'])): x_axis = request.POST['x'] y_axis = request.POST['y'] adb = getADB() args = ["input", "tap", x_axis, y_axis] data = {'status': 'success'} try: adb_command(args, True) except: data = {'status': 'error'} PrintException("[ERROR] Performing Touch Action") else: data = {'status': 'failed'} return HttpResponse(json.dumps(data), content_type='application/json') except: PrintException("[ERROR] Sending Touch Events") return HttpResponseRedirect('/error/')
def ActivityTester(request): print "\n[INFO] Activity Tester" try: MD5 = request.POST['md5'] PKG = request.POST['pkg'] m = re.match('^[0-9a-f]{32}$', MD5) if m: if re.findall(";|\$\(|\|\||&&", PKG): print "[ATTACK] Possible RCE" return HttpResponseRedirect('/error/') if request.method == 'POST': DIR = settings.BASE_DIR APP_DIR = os.path.join(settings.UPLD_DIR, MD5 + '/') TOOLS_DIR = os.path.join( DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR SCRDIR = os.path.join(APP_DIR, 'screenshots-apk/') data = {} adb = getADB(TOOLS_DIR) DB = StaticAnalyzerAndroid.objects.filter(MD5=MD5) if DB.exists(): print "\n[INFO] Fetching Activity List from DB" ACTIVITIES = python_list(DB[0].ACTIVITIES) if ACTIVITIES: n = 0 print "\n[INFO] Starting Activity Tester..." print "\n[INFO] " + str(len(ACTIVITIES)) + " Activities Identified" for line in ACTIVITIES: try: n += 1 print "\n[INFO] Launching Activity - " + str(n) + ". " + line subprocess.call( [adb, "-s", getIdentifier(), "shell", "am", "start", "-n", PKG + "/" + line]) Wait(4) subprocess.call( [adb, "-s", getIdentifier(), "shell", "screencap", "-p", "/data/local/screen.png"]) #? get appended from Air :-() if activity names are used subprocess.call( [adb, "-s", getIdentifier(), "pull", "/data/local/screen.png", SCRDIR + "act-" + str(n) + ".png"]) print "\n[INFO] Activity Screenshot Taken" subprocess.call( [adb, "-s", getIdentifier(), "shell", "am", "force-stop", PKG]) print "\n[INFO] Stopping App" except: PrintException("Activity Tester") data = {'acttest': 'done'} else: print "\n[INFO] Activity Tester - No Activity Found!" data = {'acttest': 'noact'} return HttpResponse(json.dumps(data), content_type='application/json') else: print "\n[ERROR] Entry does not exist in DB." return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Activity Tester") return HttpResponseRedirect('/error/')
def dynamic_main(file_path): # download_dir = ORIGIN_DOWNLOAD_DIR + app_info['file_md5'] + '/' try: file_md5 = genMD5(file_path) print('file_md5:', file_md5) app_info = get_static_info(file_path, file_md5) # 开始动态分析 adb = getADB(DYNAMIC_TOOL_DIR) init_environment(adb) #set_web_proxy(app_info['file_md5']) connect_device(adb) # Change True to support non-activity components install_and_run(DYNAMIC_TOOL_DIR, app_info['apk_path'], app_info['packagename'], app_info['mainactivity'], True) # 开启下载 log 线程, 60s download_dir = os.path.dirname(os.path.dirname(app_info["apk_path"])) #t = start_strace(adb, download_dir, app_info['packagename']) t = start_download(adb, download_dir, app_info['packagename']) #time.sleep(40) #至少运行60s auto_app_test(adb, app_info) # 停止代理服务器,另一个线程会把网络传输数据保存到 UPLOAD_DIR 对应的文件夹中的 urls, WebTraffic.txt, requestdb 文件。 #Proxy('', '', '', '') # 关闭下载 log 线程 t.join() droidmon_log = os.path.join(download_dir, 'x_logcat.txt') droidmon_analysis(droidmon_log, app_info['packagename']) time.sleep(1) # 复制 apk 运行时访问的 url 到结果目录 #shutil.copy(os.path.join(os.path.join(UPLOAD_DIR, app_info['file_md5']), 'urls'), os.path.join(download_dir, 'urls')) #result = analysis_x_logcat(download_dir + 'x_logcat.txt', app_info) #print(u'分析结果目录:', download_dir) # 由于临时文件比较大,当硬盘空间不足时,则删除临时文件,比如:UPLOAD_DIR, shutil.rmtree(os.path.dirname(app_info['apk_path']), ignore_errors=True) return 1 except Exception as e: result = {} # Install Error 表示安装 apk 文件时报错。 # Parsing Manifest Error 表示解析 AndroidManifest.xml 文件时报错。 print(traceback.format_exc()) #shutil.rmtree(os.path.dirname(app_info['apk_path'])) return 0
def mobsf_ca(request): """Install and Remove MobSF Proxy RootCA""" try: if request.method == 'POST': data = {} act = request.POST['action'] rootca = get_ca_dir() adb = getADB() if act == "install": logger.info("Installing MobSF RootCA") adb_command( ["push", rootca, "/data/local/tmp/" + settings.ROOT_CA]) if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": # For some reason, avd emulator does not have cp binary adb_command([ "/data/local/tmp/busybox", "cp", "/data/local/tmp/" + settings.ROOT_CA, "/system/etc/security/cacerts/" + settings.ROOT_CA ], True) adb_command([ "chmod", "644", "/system/etc/security/cacerts/" + settings.ROOT_CA ], True) else: adb_command([ "su", "-c", "cp", "/data/local/tmp/" + settings.ROOT_CA, "/system/etc/security/cacerts/" + settings.ROOT_CA ], True) adb_command([ "su", "-c", "chmod", "644", "/system/etc/security/cacerts/" + settings.ROOT_CA ], True) adb_command(["rm", "/data/local/tmp/" + settings.ROOT_CA], True) data = {'ca': 'installed'} elif act == "remove": logger.info("Removing MobSF RootCA") if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": adb_command([ "rm", "/system/etc/security/cacerts/" + settings.ROOT_CA ], True) else: adb_command([ "su", "-c", "rm", "/system/etc/security/cacerts/" + settings.ROOT_CA ], True) data = {'ca': 'removed'} return HttpResponse(json.dumps(data), content_type='application/json') else: return print_n_send_error_response(request, "Only POST allowed", True) except: PrintException("MobSF RootCA Handler") return print_n_send_error_response(request, "Error in RootCA Handler", True)
def get_env(request): """Get Dynamic Analysis Environment for Android""" print("\n[INFO] Setting up Dynamic Analysis Environment") try: if request.method == 'POST': data = {} md5_hash = request.POST['md5'] package = request.POST['pkg'] launcher = request.POST['lng'] if re.findall(r";|\$\(|\|\||&&", package) or re.findall( r";|\$\(|\|\||&&", launcher): print("[ATTACK] Possible RCE") return HttpResponseRedirect('/error/') if re.match('^[0-9a-f]{32}$', md5_hash): base_dir = settings.BASE_DIR app_dir = os.path.join(settings.UPLD_DIR, md5_hash + '/') # APP DIRECTORY app_file = md5_hash + '.apk' # NEW FILENAME app_path = app_dir + app_file # APP PATH toolsdir = os.path.join(base_dir, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(toolsdir) if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": proxy_ip = '127.0.0.1' else: proxy_ip = settings.PROXY_IP # Proxy IP start_proxy(settings.PORT, package) # AVD only needs to wait, vm needs the connect function try: if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": avd_load_wait(adb) else: connect(toolsdir) except Exception as exp: data = { 'ready': 'no', 'msg': 'Cannot Connect to the VM/Device.', 'error': str(exp) } return HttpResponse(json.dumps(data), content_type='application/json') # Change True to support non-activity components install_and_run(toolsdir, app_path, package, launcher, True) screen_width, screen_width = get_res() data = { 'ready': 'yes', 'screen_witdth': screen_width, 'screen_height': screen_width, } return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Setting up Dynamic Analysis Environment") return HttpResponseRedirect('/error/')
def get_env(request): """Get Dynamic Analysis Environment for Android""" logger.info("Setting up Dynamic Analysis Environment") try: if request.method == 'POST': data = {} md5_hash = request.POST['md5'] package = request.POST['pkg'] launcher = request.POST['lng'] if re.findall(r";|\$\(|\|\||&&", package) or re.findall( r";|\$\(|\|\||&&", launcher): return print_n_send_error_response(request, "Possible RCE Attack", True) if re.match('^[0-9a-f]{32}$', md5_hash): base_dir = settings.BASE_DIR app_dir = os.path.join(settings.UPLD_DIR, md5_hash + '/') # APP DIRECTORY app_file = md5_hash + '.apk' # NEW FILENAME app_path = app_dir + app_file # APP PATH adb = getADB() if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": proxy_ip = '127.0.0.1' else: proxy_ip = settings.PROXY_IP # Proxy IP start_proxy(settings.PORT, package) # vm needs the connect function try: if not settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": connect() except Exception as exp: data = { 'ready': 'no', 'msg': 'Cannot Connect to the VM/Device.', 'error': str(exp) } return HttpResponse(json.dumps(data), content_type='application/json') # Change True to support non-activity components install_and_run(app_path, package, launcher, True) screen_width, screen_width = get_res() data = { 'ready': 'yes', 'screen_witdth': screen_width, 'screen_height': screen_width, } return HttpResponse(json.dumps(data), content_type='application/json') else: return print_n_send_error_response(request, "Invalid Scan Hash", True) else: return print_n_send_error_response(request, "Only POST allowed", True) except: PrintException("Setting up Dynamic Analysis Environment") return print_n_send_error_response(request, "Environment Setup Failed", True)
def get_packages(toolsdir): """Get List of Pacakges""" adb = getADB(toolsdir) args = [adb, "-s", get_identifier(), "shell", "ls", "/data/data"] # prolly a better way to get packages is needed try: return subprocess.check_output(args) except: return "error"
def RunFridaServer(tools_dir, frida_server): """Invoke Frida Server in VM/Device""" print "\n[INFO] Starting Frida Server" try: adb = getADB(tools_dir) subprocess.Popen([adb, '-s', getIdentifier(), 'shell', 'su', '-c', '/data/local/tmp/'+frida_server, '&']) Wait(3) except: PrintException("[ERROR] Running Frida Server in the Device/VM")
def screen_cast(request): """Start or Stop ScreenCast Feature""" print("\n[INFO] Invoking ScreenCast Service in VM/Device") try: global TCP_SERVER_MODE data = {} if request.method == 'POST': mode = request.POST['mode'] toolsdir = os.path.join( settings.BASE_DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(toolsdir) if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": ip_address = '10.0.2.2' else: ip_address = settings.SCREEN_IP port = str(settings.SCREEN_PORT) if mode == "on": args = [adb, "-s", get_identifier(), "shell", "am", "startservice", "-a", ip_address + ":" + port, "opensecurity.screencast/.StartScreenCast"] data = {'status': 'on'} TCP_SERVER_MODE = "on" elif mode == "off": args = [adb, "-s", get_identifier(), "shell", "am", "force-stop", "opensecurity.screencast"] data = {'status': 'off'} TCP_SERVER_MODE = "off" if (mode in ["on", "off"]): try: subprocess.call(args) screen_trd = threading.Thread(target=screencast_service) screen_trd.setDaemon(True) screen_trd.start() except: PrintException("[ERROR] Casting Screen") data = {'status': 'error'} return HttpResponse(json.dumps(data), content_type='application/json') else: data = {'status': 'failed'} else: data = {'status': 'failed'} return HttpResponse(json.dumps(data), content_type='application/json') except: PrintException("[ERROR] Casting Screen") return HttpResponseRedirect('/error/')
def final_test(request): """Collecting Data and Cleanup""" global TCP_SERVER_MODE logger.info("Collecting Data and Cleaning Up") try: if request.method == 'POST': data = {} md5_hash = request.POST['md5'] package = request.POST['pkg'] if re.findall(r";|\$\(|\|\||&&", package): return print_n_send_error_response(request, "Possible RCE Attack", True) if re.match('^[0-9a-f]{32}$', md5_hash): # Stop ScreenCast Client if it is running TCP_SERVER_MODE = "off" base_dir = settings.BASE_DIR apk_dir = os.path.join(settings.UPLD_DIR, md5_hash + '/') adb = getADB() # Change to check output of subprocess when analysis is done # Can't RCE os.system(adb + ' -s ' + get_identifier() + ' logcat -d dalvikvm:W ActivityManager:I > "' + apk_dir + 'logcat.txt"') logger.info("Downloading Logcat logs") adb_command([ "pull", "/data/data/de.robv.android.xposed.installer/log/error.log", apk_dir + "x_logcat.txt" ]) logger.info("Downloading Droidmon API Monitor Logcat logs") # Can't RCE os.system(adb + ' -s ' + get_identifier() + ' shell dumpsys > "' + apk_dir + 'dump.txt"') logger.info("Downloading Dumpsys logs") adb_command(["am", "force-stop", package], True) logger.info("Stopping Application") adb_command(["am", "force-stop", "opensecurity.screencast"], True) logger.info("Stopping ScreenCast Service") data = {'final': 'yes'} return HttpResponse(json.dumps(data), content_type='application/json') else: return print_n_send_error_response(request, "Invalid Scan Hash", True) else: return print_n_send_error_response(request, "Only POST allowed", True) except: PrintException("Data Collection & Clean Up") return print_n_send_error_response( request, "Data Collection & Clean Up failed", True)
def DumpData(request): # Closing External Services and Dumping data print "\n[INFO] Device Data Dump" try: if request.method == 'POST': data = {} PACKAGE = request.POST['pkg'] MD5 = request.POST['md5'] m = re.match('^[0-9a-f]{32}$', MD5) if m: if re.findall(";|\$\(|\|\||&&", PACKAGE): print "[ATTACK] Possible RCE" return HttpResponseRedirect('/error/') DIR = settings.BASE_DIR APKDIR = os.path.join(settings.UPLD_DIR, MD5 + '/') TOOLSDIR = os.path.join( DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(TOOLSDIR) # Let's try to close Proxy a bit early as we don't have much # control on the order of thread execution Proxy("", "", "", "") print "\n[INFO] Deleting Dump Status File" subprocess.call([adb, "-s", getIdentifier(), "shell", "rm", "/sdcard/mobsec_status"]) print "\n[INFO] Creating TAR of Application Files." subprocess.call([adb, "-s", getIdentifier(), "shell", "am", "startservice", "-a", PACKAGE, "opensecurity.ajin.datapusher/.GetPackageLocation"]) print "\n[INFO] Waiting for TAR dump to complete..." if settings.REAL_DEVICE: timeout = settings.DEVICE_TIMEOUT else: timeout = settings.VM_TIMEOUT start_time = time.time() while True: current_time = time.time() if "MOBSEC-TAR-CREATED" in subprocess.check_output([adb, "-s", getIdentifier(), "shell", "cat", "/sdcard/mobsec_status"]): break if (current_time - start_time) > timeout: print "\n[ERROR] TAR Generation Failed. Process timed out." break print "\n[INFO] Dumping Application Files from Device/VM" subprocess.call([adb, "-s", getIdentifier(), "pull", "/data/local/" + PACKAGE + ".tar", APKDIR + PACKAGE + ".tar"]) print "\n[INFO] Stopping ADB" subprocess.call([adb, "-s", getIdentifier(), "kill-server"]) data = {'dump': 'yes'} return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Device Data Dump") return HttpResponseRedirect('/error/')
def android_dynamic_analyzer(request): """Android Dynamic Analyzer View""" print("\n[INFO] Dynamic Analysis Started") try: if request.method == 'POST': md5_hash = request.POST['md5'] package = request.POST['pkg'] launcher = request.POST['lng'] if re.findall(r';|\$\(|\|\||&&', package) or re.findall(r';|\$\(|\|\||&&', launcher): print("[ATTACK] Possible RCE") return HttpResponseRedirect('/error/') if re.match('^[0-9a-f]{32}$', md5_hash): # Delete ScreenCast Cache screen_file = os.path.join(settings.SCREEN_DIR, 'screen.png') if os.path.exists(screen_file): os.remove(screen_file) # Delete Contents of Screenshot Dir screen_dir = os.path.join( settings.UPLD_DIR, md5_hash + '/screenshots-apk/') if os.path.isdir(screen_dir): shutil.rmtree(screen_dir) else: os.makedirs(screen_dir) # Start DM stop_capfuzz(settings.PORT) adb = getADB() is_avd = False if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_REAL_DEVICE": print( "\n[INFO] MobSF will perform Dynamic Analysis on real Android Device") elif settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": # adb, avd_path, reference_name, dup_name, emulator is_avd = True if not os.path.exists(settings.AVD_EMULATOR): return HttpResponseRedirect('/error/') if not refresh_avd(): return HttpResponseRedirect('/error/') else: # Refersh VM refresh_vm(settings.UUID, settings.SUUID, settings.VBOX) context = {'md5': md5_hash, 'pkg': package, 'lng': launcher, 'title': 'Start Testing', 'AVD': is_avd, } template = "dynamic_analysis/start_test.html" return render(request, template, context) else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] DynamicAnalyzer") return HttpResponseRedirect('/error/')
def clean(): base_dir = settings.BASE_DIR toolsdir = os.path.join(base_dir, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(toolsdir) print("\n[INFO] Stopping ADB") subprocess.call([adb, "-s", get_identifier(), "kill-server"]) # Close VM args = [settings.VBOX, 'controlvm', settings.UUID, 'poweroff'] subprocess.call(args) print("\n[INFO] VM Closed") return
def FinalTest(request): # Closing Services in VM/Device global tcp_server_mode print "\n[INFO] Collecting Data and Cleaning Up" try: if request.method == 'POST': data = {} MD5 = request.POST['md5'] PACKAGE = request.POST['pkg'] if re.findall(";|\$\(|\|\||&&", PACKAGE): print "[ATTACK] Possible RCE" return HttpResponseRedirect('/error/') m = re.match('^[0-9a-f]{32}$', MD5) if m: # Stop ScreenCast Client if it is running tcp_server_mode = "off" DIR = settings.BASE_DIR APKDIR = os.path.join(settings.UPLD_DIR, MD5 + '/') TOOLSDIR = os.path.join( DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(TOOLSDIR) # Change to check output of subprocess when analysis is done # Can't RCE os.system(adb + ' -s ' + getIdentifier() + ' logcat -d dalvikvm:W ActivityManager:I > "' + APKDIR + 'logcat.txt"') print "\n[INFO] Downloading Logcat logs" #os.system(adb+' -s '+getIdentifier()+' logcat -d Xposed:I *:S > "'+APKDIR + 'x_logcat.txt"') subprocess.call([adb, "-s", getIdentifier(), "pull", "/data/data/de.robv.android.xposed.installer/log/error.log", APKDIR + "x_logcat.txt"]) print "\n[INFO] Downloading Droidmon API Monitor Logcat logs" # Can't RCE os.system(adb + ' -s ' + getIdentifier() + ' shell dumpsys > "' + APKDIR + 'dump.txt"') print "\n[INFO] Downloading Dumpsys logs" subprocess.call([adb, "-s", getIdentifier(), "shell", "am", "force-stop", PACKAGE]) print "\n[INFO] Stopping Application" subprocess.call([adb, "-s", getIdentifier(), "shell", "am", "force-stop", "opensecurity.screencast"]) print "\n[INFO] Stopping ScreenCast Service" data = {'final': 'yes'} return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Clean Up") return HttpResponseRedirect('/error/')
def mobsf_ca(request): """Install and Remove MobSF Proxy RootCA""" try: if request.method == 'POST': data = {} act = request.POST['action'] rootca = get_ca_dir() adb = getADB() if act == "install": print("\n[INFO] Installing MobSF RootCA") adb_command( ["push", rootca, "/data/local/tmp/" + settings.ROOT_CA]) if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": # For some reason, avd emulator does not have cp binary adb_command(["/data/local/tmp/busybox", "cp", "/data/local/tmp/" + settings.ROOT_CA, "/system/etc/security/cacerts/" + settings.ROOT_CA], True) adb_command(["chmod", "644", "/system/etc/security/cacerts/" + settings.ROOT_CA], True) else: adb_command(["su", "-c", "cp", "/data/local/tmp/" + settings.ROOT_CA, "/system/etc/security/cacerts/" + settings.ROOT_CA], True) adb_command(["su", "-c", "chmod", "644", "/system/etc/security/cacerts/" + settings.ROOT_CA], True) adb_command( ["rm", "/data/local/tmp/" + settings.ROOT_CA], True) data = {'ca': 'installed'} elif act == "remove": print("\n[INFO] Removing MobSF RootCA") if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": adb_command( ["rm", "/system/etc/security/cacerts/" + settings.ROOT_CA], True) else: adb_command(["su", "-c", "rm", "/system/etc/security/cacerts/" + settings.ROOT_CA], True) data = {'ca': 'removed'} return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] MobSF RootCA Handler") return HttpResponseRedirect('/error/')
def final_test(request): """Collecting Data and Cleanup""" global TCP_SERVER_MODE print("\n[INFO] Collecting Data and Cleaning Up") try: if request.method == 'POST': data = {} md5_hash = request.POST['md5'] package = request.POST['pkg'] if re.findall(r";|\$\(|\|\||&&", package): print("[ATTACK] Possible RCE") return HttpResponseRedirect('/error/') if re.match('^[0-9a-f]{32}$', md5_hash): # Stop ScreenCast Client if it is running TCP_SERVER_MODE = "off" base_dir = settings.BASE_DIR apk_dir = os.path.join(settings.UPLD_DIR, md5_hash + '/') adb = getADB() # Change to check output of subprocess when analysis is done # Can't RCE os.system(adb + ' -s ' + get_identifier() + ' logcat -d dalvikvm:W ActivityManager:I > "' + apk_dir + 'logcat.txt"') print("\n[INFO] Downloading Logcat logs") adb_command(["pull", "/data/data/de.robv.android.xposed.installer/log/error.log", apk_dir + "x_logcat.txt"]) print("\n[INFO] Downloading Droidmon API Monitor Logcat logs") # Can't RCE os.system(adb + ' -s ' + get_identifier() + ' shell dumpsys > "' + apk_dir + 'dump.txt"') print("\n[INFO] Downloading Dumpsys logs") adb_command(["am", "force-stop", package], True) print("\n[INFO] Stopping Application") adb_command( ["am", "force-stop", "opensecurity.screencast"], True) print("\n[INFO] Stopping ScreenCast Service") data = {'final': 'yes'} return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Clean Up") return HttpResponseRedirect('/error/')
def get_env(request): """Get Dynamic Analysis Environment for Android""" print("\n[INFO] Setting up Dynamic Analysis Environment") try: if request.method == 'POST': data = {} md5_hash = request.POST['md5'] package = request.POST['pkg'] launcher = request.POST['lng'] if re.findall(r";|\$\(|\|\||&&", package) or re.findall(r";|\$\(|\|\||&&", launcher): print("[ATTACK] Possible RCE") return HttpResponseRedirect('/error/') if re.match('^[0-9a-f]{32}$', md5_hash): base_dir = settings.BASE_DIR app_dir = os.path.join( settings.UPLD_DIR, md5_hash + '/') # APP DIRECTORY app_file = md5_hash + '.apk' # NEW FILENAME app_path = app_dir + app_file # APP PATH adb = getADB() if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": proxy_ip = '127.0.0.1' else: proxy_ip = settings.PROXY_IP # Proxy IP start_proxy(settings.PORT, package) # vm needs the connect function try: if not settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": connect() except Exception as exp: data = {'ready': 'no', 'msg': 'Cannot Connect to the VM/Device.', 'error': str(exp)} return HttpResponse(json.dumps(data), content_type='application/json') # Change True to support non-activity components install_and_run(app_path, package, launcher, True) screen_width, screen_width = get_res() data = {'ready': 'yes', 'screen_witdth': screen_width, 'screen_height': screen_width, } return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Setting up Dynamic Analysis Environment") return HttpResponseRedirect('/error/')
def install_and_run(apk_path, package, launcher, is_activity): """Install APK and Run it""" print("\n[INFO] Starting App for Dynamic Analysis") try: adb = getADB() print("\n[INFO] Installing APK") adb_command(["install", "-r", apk_path]) if is_activity: run_app = package + "/" + launcher print("\n[INFO] Launching APK Main Activity") adb_command(["am", "start", "-n", run_app], True) else: print("\n[INFO] App Doesn't have a Main Activity") # Handle Service or Give Choice to Select in Future. print("[INFO] Testing Environment is Ready!") except: PrintException("[ERROR] Starting App for Dynamic Analysis")
def InstallRun(TOOLSDIR, APKPATH, PACKAGE, LAUNCH, isACT): print "\n[INFO] Starting App for Dynamic Analysis" try: adb = getADB(TOOLSDIR) print "\n[INFO] Installing APK" subprocess.call([adb, "-s", getIdentifier(), "install", "-r", APKPATH]) if isACT: runApp = PACKAGE + "/" + LAUNCH print "\n[INFO] Launching APK Main Activity" subprocess.call([adb, "-s", getIdentifier(), "shell", "am", "start", "-n", runApp]) else: print "\n[INFO] App Doesn't have a Main Activity" # Handle Service or Give Choice to Select in Future. pass print "[INFO] Testing Environment is Ready!" except: PrintException("[ERROR] Starting App for Dynamic Analysis")
def adb_command(cmd_list, shell=False, silent=False): emulator = get_identifier() adb = getADB() args = [adb, "-s", emulator] if shell: args += ['shell'] args += cmd_list try: result = subprocess.check_output(args) return result except: if not silent: PrintException("[ERROR] adb_command") return None
def install_and_run(toolsdir, apk_path, package, launcher, is_activity): """Install APK and Run it""" print "\n[INFO] Starting App for Dynamic Analysis" try: adb = getADB(toolsdir) print "\n[INFO] Installing APK" subprocess.call([adb, "-s", get_identifier(), "install", "-r", apk_path]) if is_activity: run_app = package + "/" + launcher print "\n[INFO] Launching APK Main Activity" subprocess.call([adb, "-s", get_identifier(), "shell", "am", "start", "-n", run_app]) else: print "\n[INFO] App Doesn't have a Main Activity" # Handle Service or Give Choice to Select in Future. print "[INFO] Testing Environment is Ready!" except: PrintException("[ERROR] Starting App for Dynamic Analysis")
def ScreenCast(request): print "\n[INFO] Invoking ScreenCast Service in VM/Device" try: global tcp_server_mode data = {} if (request.method == 'POST'): mode = request.POST['mode'] TOOLSDIR = os.path.join( settings.BASE_DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(TOOLSDIR) IP = settings.SCREEN_IP PORT = str(settings.SCREEN_PORT) if mode == "on": args = [adb, "-s", getIdentifier(), "shell", "am", "startservice", "-a", IP + ":" + PORT, "opensecurity.screencast/.StartScreenCast"] data = {'status': 'on'} tcp_server_mode = "on" elif mode == "off": args = [adb, "-s", getIdentifier(), "shell", "am", "force-stop", "opensecurity.screencast"] data = {'status': 'off'} tcp_server_mode = "off" if (mode in ["on", "off"]): try: subprocess.call(args) t = threading.Thread(target=ScreenCastService) t.setDaemon(True) t.start() except: PrintException("[ERROR] Casting Screen") data = {'status': 'error'} return HttpResponse(json.dumps(data), content_type='application/json') else: data = {'status': 'failed'} else: data = {'status': 'failed'} return HttpResponse(json.dumps(data), content_type='application/json') except: PrintException("[ERROR] Casting Screen") return HttpResponseRedirect('/error/')
def clip_dump(request): """Dump Android ClipBoard""" print("\n[INFO] Starting Clipboard Dump Service in VM/Device") try: data = {} if request.method == 'POST': adb = getADB() args = ["am", "startservice", "opensecurity.clipdump/.ClipDumper"] try: adb_command(args, True) data = {'status': 'success'} except: PrintException("[ERROR] Dumping Clipboard") data = {'status': 'error'} else: data = {'status': 'failed'} return HttpResponse(json.dumps(data), content_type='application/json') except: PrintException("[ERROR] Dumping Clipboard") return HttpResponseRedirect('/error/')
def clip_dump(request): """Dump Android ClipBoard""" logger.info("Starting Clipboard Dump Service in VM/Device") try: data = {} if request.method == 'POST': adb = getADB() args = ["am", "startservice", "opensecurity.clipdump/.ClipDumper"] try: adb_command(args, True) data = {'status': 'success'} except: PrintException("Dumping Clipboard") data = {'status': 'error'} else: data = {'status': 'failed'} return HttpResponse(json.dumps(data), content_type='application/json') except: PrintException("Dumping Clipboard") return print_n_send_error_response(request, "Error Dumping Clipboard", True)
def get_res(): """Get Screen Resolution or Device or VM""" print("\n[INFO] Getting Screen Resolution") try: adb = getADB() resp = subprocess.check_output( [adb, "-s", get_identifier(), "shell", "dumpsys", "window"]) resp = resp.decode("utf-8").split("\n") res = "" for line in resp: if "mUnrestrictedScreen" in line: res = line break res = res.split("(0,0)")[1] res = res.strip() res = res.split("x") if len(res) == 2: return res[0], res[1] # width, height return "", "" except: PrintException("[ERROR] Getting Screen Resolution") return "", ""
def connect(): """Connect to VM/Device""" print("\n[INFO] Connecting to VM/Device") adb = getADB() subprocess.call([adb, "kill-server"]) subprocess.call([adb, "start-server"]) print("\n[INFO] ADB Started") wait(5) print("\n[INFO] Connecting to VM/Device") out = subprocess.check_output([adb, "connect", get_identifier()]) if b"unable to connect" in out: raise ValueError("ERROR Connecting to VM/Device. ", out.decode("utf-8").replace("\n","")) try: subprocess.call([adb, "-s", get_identifier(), "wait-for-device"]) print("\n[INFO] Mounting") if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_REAL_DEVICE": adb_command(["su", "-c", "mount", "-o", "rw,remount,rw", "/system"], True) else: adb_command(["su", "-c", "mount", "-o", "rw,remount,rw", "/system"], True) # This may not work for VMs other than the default MobSF VM adb_command(["mount", "-o", "rw,remount", "-t", "rfs", "/dev/block/sda6", "/system"], True) except: PrintException("[ERROR] Connecting to VM/Device")
def Connect(TOOLSDIR): print "\n[INFO] Connecting to VM/Device" try: adb = getADB(TOOLSDIR) subprocess.call([adb, "kill-server"]) subprocess.call([adb, "start-server"]) print "\n[INFO] ADB Started" Wait(5) print "\n[INFO] Connecting to VM/Device" subprocess.call([adb, "connect", getIdentifier()]) subprocess.call([adb, "-s", getIdentifier(), "wait-for-device"]) print "\n[INFO] Mounting" if settings.REAL_DEVICE: subprocess.call([adb, "-s", getIdentifier(), "shell", "su", "-c", "mount", "-o", "rw,remount,rw", "/system"]) else: subprocess.call([adb, "-s", getIdentifier(), "shell", "su", "-c", "mount", "-o", "rw,remount,rw", "/system"]) # This may not work for VMs other than the default MobSF VM subprocess.call([adb, "-s", getIdentifier(), "shell", "mount", "-o", "rw,remount", "-t", "rfs", "/dev/block/sda6", "/system"]) except: PrintException("[ERROR] Connecting to VM/Device")
def Touch(request): print "\n[INFO] Sending Touch Events" try: data = {} if (request.method == 'POST') and (is_number(request.POST['x'])) and (is_number(request.POST['y'])): x_axis = request.POST['x'] y_axis = request.POST['y'] TOOLSDIR = os.path.join( settings.BASE_DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR adb = getADB(TOOLSDIR) args = [adb, "-s", getIdentifier(), "shell", "input", "tap", x_axis, y_axis] data = {'status': 'success'} try: subprocess.call(args) except: data = {'status': 'error'} PrintException("[ERROR] Performing Touch Action") else: data = {'status': 'failed'} return HttpResponse(json.dumps(data), content_type='application/json') except: PrintException("[ERROR] Sending Touch Events") return HttpResponseRedirect('/error/')
def connect(toolsdir): """Connect to VM/Device""" print "\n[INFO] Connecting to VM/Device" try: adb = getADB(toolsdir) subprocess.call([adb, "kill-server"]) subprocess.call([adb, "start-server"]) print "\n[INFO] ADB Started" wait(5) print "\n[INFO] Connecting to VM/Device" subprocess.call([adb, "connect", get_identifier()]) subprocess.call([adb, "-s", get_identifier(), "wait-for-device"]) print "\n[INFO] Mounting" if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_REAL_DEVICE": subprocess.call([adb, "-s", get_identifier(), "shell", "su", "-c", "mount", "-o", "rw,remount,rw", "/system"]) else: subprocess.call([adb, "-s", get_identifier(), "shell", "su", "-c", "mount", "-o", "rw,remount,rw", "/system"]) # This may not work for VMs other than the default MobSF VM subprocess.call([adb, "-s", get_identifier(), "shell", "mount", "-o", "rw,remount", "-t", "rfs", "/dev/block/sda6", "/system"]) except: PrintException("[ERROR] Connecting to VM/Device")
def activity_tester(request): """Activity Tester""" print("\n[INFO] Activity Tester") try: md5_hash = request.POST['md5'] package = request.POST['pkg'] if re.match('^[0-9a-f]{32}$', md5_hash): if re.findall(r";|\$\(|\|\||&&", package): print("[ATTACK] Possible RCE") return HttpResponseRedirect('/error/') if request.method == 'POST': base_dir = settings.BASE_DIR app_dir = os.path.join(settings.UPLD_DIR, md5_hash + '/') screen_dir = os.path.join(app_dir, 'screenshots-apk/') if not os.path.exists(screen_dir): os.makedirs(screen_dir) data = {} adb = getADB() static_android_db = StaticAnalyzerAndroid.objects.filter( MD5=md5_hash) if static_android_db.exists(): print("\n[INFO] Fetching Activity List from DB") activities = python_list(static_android_db[0].ACTIVITIES) if activities: act_no = 0 print("\n[INFO] Starting Activity Tester...") print("\n[INFO] " + str(len(activities)) + " Activities Identified") for line in activities: try: act_no += 1 print("\n[INFO] Launching Activity - " + str(act_no) + ". " + line) adb_command( ["am", "start", "-n", package + "/" + line], True) # AVD is much slower, it should get extra time if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": wait(8) else: wait(4) adb_command( ["screencap", "-p", "/data/local/screen.png"], True) #? get appended from Air :-() if activity names are used adb_command(["pull", "/data/local/screen.png", screen_dir + "act-" + str(act_no) + ".png"]) print("\n[INFO] Activity Screenshot Taken") adb_command( ["am", "force-stop", package], True) print("\n[INFO] Stopping App") except: PrintException("Activity Tester") data = {'acttest': 'done'} else: print("\n[INFO] Activity Tester - No Activity Found!") data = {'acttest': 'noact'} return HttpResponse(json.dumps(data), content_type='application/json') else: print("\n[ERROR] Entry does not exist in DB.") return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Activity Tester") return HttpResponseRedirect('/error/')
def exported_activity_tester(request): """Exported Activity Tester""" logger.info("Exported Activity Tester") try: md5_hash = request.POST['md5'] package = request.POST['pkg'] if re.match('^[0-9a-f]{32}$', md5_hash): if re.findall(r";|\$\(|\|\||&&", package): return print_n_send_error_response(request, "Possible RCE Attack", True) if request.method == 'POST': base_dir = settings.BASE_DIR app_dir = os.path.join(settings.UPLD_DIR, md5_hash + '/') screen_dir = os.path.join(app_dir, 'screenshots-apk/') if not os.path.exists(screen_dir): os.makedirs(screen_dir) data = {} adb = getADB() static_android_db = StaticAnalyzerAndroid.objects.filter( MD5=md5_hash) if static_android_db.exists(): logger.info("Fetching Exported Activity List from DB") exported_act = python_list( static_android_db[0].EXPORTED_ACT) if exported_act: exp_act_no = 0 logger.info("Starting Exported Activity Tester...") logger.info("" + str(len(exported_act)) + " Exported Activities Identified") for line in exported_act: try: exp_act_no += 1 logger.info("Launching Exported Activity - " + str(exp_act_no) + ". " + line) adb_command( ["am", "start", "-n", package + "/" + line], True) # AVD is much slower, it should get extra time if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": wait(8) else: wait(4) adb_command( ["screencap", "-p", "/data/local/screen.png"], True) #? get appended from Air :-() if activity names are used adb_command(["pull", "/data/local/screen.png", screen_dir + "expact-" + str(exp_act_no) + ".png"]) logger.info("Activity Screenshot Taken") adb_command( ["am", "force-stop", package], True) logger.info("Stopping App") except: PrintException( "Exported Activity Tester") data = {'expacttest': 'done'} else: logger.info( "Exported Activity Tester - No Activity Found!") data = {'expacttest': 'noact'} return HttpResponse(json.dumps(data), content_type='application/json') else: return print_n_send_error_response(request, "Entry does not exist in DB", True) else: return print_n_send_error_response(request, "Only POST allowed", True) else: return print_n_send_error_response(request, "Invalid Scan Hash", True) except: PrintException("ERROR] Exported Activity Tester") return print_n_send_error_response(request, "Error Running Exported Activity Tests", True)