#!/usr/bin/python # -*- coding: utf-8 -*- import os, sys, time, threading, shlex import urllib, urllib2 from datetime import datetime from optparse import OptionParser #from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice from xml.dom import minidom from os.path import join, isdir, isfile, getsize from subprocess import Popen, PIPE import random DEVCONFIG = 'devconfig.txt' APPDUMP = 'appdump' SODUMP = 'sodump' STRDUMP = 'strdump' SLEEPTIME = 2 SMLSLEEP = 4 BIGSLEEP = 12 #since attack 3 requires 8s DATAOUT = 'dataOut' dexdump = '/home/dao/software/android-sdk-linux_x86/build-tools/28.0.3/dexdump' dex2jar="/home/dao/software/dex2jar/dex2jar-2.1/d2j-dex2jar.sh" backdroid="../bin/backdroid.sh" """ from http://stackoverflow.com/questions/1191374/subprocess-with-timeout """ class MyCmd(object): def __init__(self, cmd): self.cmd = cmd self.process = None def run(self, timeout=60): def target(): self.process = Popen(self.cmd, shell=True) (out, err) = self.process.communicate() thread = threading.Thread(target=target) thread.start() thread.join(timeout) if thread.is_alive(): print 'Terminating: %s' % self.cmd self.process.terminate() thread.join() """ IN: /dir1/dir2/dir3/xxx.apk OUT: /dir1/dir2/dir3/xxx """ def getApkPrefix(apkpath): return apkpath[0:-4] """ .FileBrowser --> com.dropbox.android.FileBrowser App --> org.mozilla.firefox.App """ def translateName(component, package): if component.startswith('.'): return '%s%s' % (package, component) else: if '.' in component: return component else: return '%s.%s' % (package, component) """ get package name for an apk """ def getPackageName(apk): # aapt to get package p1 = Popen(['aapt', 'dump', 'badging', apk], stdout=PIPE) p2 = Popen(['sed', '-n', "s/package.*name='\\([^']*\\).*/\\1/p"], stdin=p1.stdout, stdout=PIPE) (out, err) = p2.communicate() package = out.rstrip('\n') return package def grepSoFile(sopath): os.system('strings %s > %s' % (sopath, STRDUMP)) cmd = 'grep "^socket$" %s' % STRDUMP process = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) (out1, err1) = process.communicate() cmd = 'grep "^bind$" %s' % STRDUMP process = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) (out2, err2) = process.communicate() cmd = 'grep "^listen$" %s' % STRDUMP process = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) (out3, err3) = process.communicate() cmd = 'grep "^accept$" %s' % STRDUMP process = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) (out4, err4) = process.communicate() if out1 != '' and out2 != '' and out3 != '' and out4 != '': return os.path.basename(sopath) else: return '' """ com.facebook.orca-49249863-v104.0.0.13.69_unzip$ ls *.dex classes2.dex classes4.dex classes6.dex classes.dex classes3.dex classes5.dex classes7.dex """ def tranDex2Dump(appunzip, applog): appdex = '%s/classes.dex' % appunzip os.system('%s -d %s > %s' % (dexdump, appdex, applog)) # Further check starting from classes2.dex i = 2 isMore = 0 while True: appdex = '%s/classes%d.dex' % (appunzip, i) templog = '_dexdump%d.log' % i #Just save in the cmd dir if os.path.exists(appdex) == True: os.system('%s -d %s > %s' % (dexdump, appdex, templog)) os.system('cat %s >> %s' % (templog, applog)) os.system('rm %s' % templog) isMore = 1 else: break i = i + 1 return isMore def myExit(code): print '[Main] Start exiting...' sys.exit(code) def flush(): sys.stdout.flush() """ ============== main entry ============== """ # parse param usage = "usage: python %prog -a apkdir -f listfile -w NO" parser = OptionParser(usage=usage) parser.add_option('-a', '--apk', action='store', type='string', dest='apk', help='The dir of apk files.') parser.add_option('-f', '--listfile', action='store', type='string', dest='listfile', help='The list of apk files.') parser.add_option('-w', '--whether', action='store', type='string', dest='whether', help='Whether to remove temp files.') (options, args) = parser.parse_args() if (not options.apk) and (not options.listfile): parser.error('-a (apkdir) or -f (listfile) is mandatory') if options.apk: APPDIR = options.apk if APPDIR.endswith('/'): APPDIR = APPDIR[:-1] if options.listfile: APPDUMP = options.listfile ISREMOVE = True # by default, we remove temp files if options.whether: whether = options.whether if whether == 'NO' or whether == 'no' or whether == 'No': ISREMOVE = False # read app list applist = [] print '[Main] Read app list...' flush() if options.apk: os.system('ls %s/*.apk > %s' % (APPDIR, APPDUMP)) f = open(APPDUMP, 'r') for line in f: app = line.rstrip('\n') #'appset/org.tint-10-v1.8.apk' #the full path depends on the value of appset applist.append(app) if f: f.close() # http://stackoverflow.com/a/415525/197165 curtime = time.strftime("%Y-%m-%d %H:%M:%S") print 'Current Time: ', curtime flush() # loop app list i = 0 for app in applist: apkprefix = getApkPrefix(app) appunzip = '%s_unzip' % apkprefix appdex = '%s/classes.dex' % appunzip applib = '%s/lib/armeabi' % appunzip appjar = '%s_dex2jar.jar' % apkprefix applog = '%s_dexdump.log' % apkprefix manifest = '%s/AndroidManifest.xml' % appunzip start_all = datetime.now() # unzip if not os.path.exists(appunzip): cmd = 'unzip -n -q %s -d %s' % (app, appunzip) process = Popen(cmd, shell=True, stderr=PIPE) (out, err) = process.communicate() if not os.path.exists(manifest): print 'unzip error: %s' % app flush() # Also need to remove if os.path.exists(appunzip): os.system('rm -rf %s' % appunzip) continue # dexdump muldex = 0 if os.path.exists(applog) == False: muldex = tranDex2Dump(appunzip, applog) # print i = i + 1 package = getPackageName(app) print '[%d] App: %s' % (i, package) flush() # grep dex resdex = 0 cmd = 'cat %s | grep -e "Ljavax/crypto/Cipher;.getInstance:(Ljava/lang/String;)Ljavax/crypto/Cipher;" -e "Lorg/apache/http/conn/ssl/SSLSocketFactory;.setHostnameVerifier:(Lorg/apache/http/conn/ssl/X509HostnameVerifier;)V" -e "Ljavax/net/ssl/HttpsURLConnection;.setHostnameVerifier:(Ljavax/net/ssl/HostnameVerifier;)V"' % applog process = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) (out, err) = process.communicate() #TODO error handling if out != '': resdex = 1 # only at this time, we do dex2jar if not os.path.exists(appjar): os.system('%s -f -o %s %s' % (dex2jar, appjar, app)) # analyze parameters and conditions when resdex == 1 start_back = datetime.now() if resdex and os.path.exists(appjar) and os.path.exists(applog): os.system('%s %s %s' % (backdroid, apkprefix, package)) end_time = datetime.now() elapsed_all = end_time - start_all elapsed_all_s = elapsed_all.total_seconds() elapsed_back = end_time - start_back elapsed_back_s = elapsed_back.total_seconds() # output print '[UseTime] %s\t%d\t%d' % \ (package, elapsed_all_s, elapsed_back_s) print '[GrepPort] %s\t%d\t%d' % (package, resdex, muldex) flush() # rm temp files, *_dex2jar.jar has not much space if ISREMOVE: if os.path.exists(applog): os.system('rm %s' % applog) if os.path.exists(appunzip): os.system('rm -rf %s' % appunzip) curtime = time.strftime("%Y-%m-%d %H:%M:%S") print 'Current Time: ', curtime flush() if (not options.listfile) and options.apk: os.system('rm %s' % APPDUMP) os.system('rm %s' % SODUMP) os.system('rm %s' % STRDUMP) # exit myExit(0)