def target(self, queue): # get all decompiled files that contains usage of WebView files = common.text_scan(common.java_files, self.webViewRegex) res = [] count = 0 for f in files: count += 1 pub.sendMessage('progress', bar=self.getName(), percent=round(count * 100 / len(files))) # get decompiled file body fileName = f[1] with open(fileName, 'r') as fi: fileBody = fi.read() # report if file contains any inline calls if PluginUtil.contains(self.inlineRegex, fileBody): PluginUtil.reportIssue(fileName, self.createIssueDetails(fileName), res) break # report if any WebView variables invoke calls for varName in PluginUtil.returnGroupMatches( self.varNameRegex, 2, fileBody): if PluginUtil.contains( r'%s\.addJavascriptInterface\(.*?\)' % varName, fileBody): PluginUtil.reportIssue(fileName, self.createIssueDetails(fileName), res) break queue.put(res)
def target(self, queue): # get all decompiled files that contains usage of TelephonyManager files = common.text_scan(common.java_files, self.telephonyManagerRegex) res = [] count = 0 for f in files: count += 1 pub.sendMessage('progress', bar=self.getName(), percent=round(count * 100 / len(files))) # get decompiled file body fileName = f[1] with open(fileName, 'r') as fi: fileBody = fi.read() # report if file contains inline call if PluginUtil.contains(self.inlineRegex, fileBody): PluginUtil.reportInfo( fileName, self.PhoneIdentifierIssueDetails(fileName), res) break # report if any TelephonyManager variables invokes calls to get phone identifiers for varName in PluginUtil.returnGroupMatches( self.varNameRegex, 2, fileBody): if PluginUtil.contains( r'%s\.(getLine1Number|getDeviceId)\(.*?\)' % varName, fileBody): PluginUtil.reportInfo( fileName, self.PhoneIdentifierIssueDetails(fileName), res) break queue.put(res)
def target(self, queue): results = [] #TODO: add documentation for available API calls. Sample shown below. # Here, we want to scan all decompiled files to see if any file contains the text "API_KEY" possibleFiles = common.text_scan(common.java_files, r'API_KEY') count = 0 for f in possibleFiles: count += 1 # The following call generates the progress bar in the terminal output pub.sendMessage('progress', bar=self.getName(), percent=round(count*100/len(possibleFiles))) # Mostly for logging. This goes in the log file generated under /logs common.logger.debug("Text found, " + str(f)) # This will put individual results of the plugin scan in the HTML report. issue = ReportIssue() issue.setCategory(ExploitType.PLUGIN) issue.setDetails("The string 'API_KEY' appears in the file: %s\n%s" % (f[1], str(f[0]))) issue.setFile(str(f[1])) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) # This puts individual results of the plugin scan in the terminal output. issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData("The string 'API_KEY' appears in the file: %s\n%s" % (f[1], str(f[0]))) results.append(issue) # This is required to send the complete list of results (including the ones to be printed on terminal as well as # issues to be printed in tht HTML report) back to the main thread. queue.put(results)
def target(self, queue): # get all decompiled files that contains usage of TelephonyManager files = common.text_scan(common.java_files, self.telephonyManagerRegex) res = [] count = 0 for f in files: count += 1 pub.sendMessage('progress', bar=self.getName(), percent=round(count * 100 / len(files))) # get decompiled file body fileName = f[1] with open(fileName, 'r') as fi: fileBody = fi.read() # report if file contains inline call if PluginUtil.contains(self.inlineRegex, fileBody): PluginUtil.reportInfo(fileName, self.PhoneIdentifierIssueDetails(fileName), res) break # report if any TelephonyManager variables invokes calls to get phone identifiers for varName in PluginUtil.returnGroupMatches(self.varNameRegex, 2, fileBody): if PluginUtil.contains(r'%s\.(getLine1Number|getDeviceId)\(.*?\)' % varName, fileBody): PluginUtil.reportInfo(fileName, self.PhoneIdentifierIssueDetails(fileName), res) break queue.put(res)
def target(self, queue): # get all decompiled files that contains usage of WebView files = common.text_scan(common.java_files, self.webViewRegex) res = [] count = 0 for f in files: count += 1 pub.sendMessage('progress', bar=self.getName(), percent=round(count * 100 / len(files))) # get decompiled file body fileName = f[1] with open(fileName, 'r') as fi: fileBody = fi.read() # report if file contains any inline calls if PluginUtil.contains(self.inlineRegex, fileBody): PluginUtil.reportIssue(fileName, self.createIssueDetails(fileName), res) break # report if any WebView variables invoke calls for varName in PluginUtil.returnGroupMatches(self.varNameRegex, 2, fileBody): if PluginUtil.contains(r'%s\.addJavascriptInterface\(.*?\)' % varName, fileBody): PluginUtil.reportIssue(fileName, self.createIssueDetails(fileName), res) break queue.put(res)
def find_key_files(results): ''' PackagedPrivateKey ------------------ Summary: Packaged private key Priority: 8 / 10 Severity: Fatal Category: Security In general, you should not package private key files inside your app. ''' if len(common.keyFiles)>0: possibleKeyFiles=common.text_scan(common.keyFiles,r'PRIVATE\sKEY') if len(possibleKeyFiles)>0: for f in possibleKeyFiles: common.logger.debug("It appears there is a private key embedded in your application: " + str(f)) issue = ReportIssue() issue.setCategory(ExploitType.CRYPTO) issue.setDetails("It appears there is a private key embedded in your application in the following file:") issue.setFile(str(f)) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData("It appears there is a private key embedded in your application in the following file:") results.append(issue) return
def find_key_files(results): ''' PackagedPrivateKey ------------------ Summary: Packaged private key Priority: 8 / 10 Severity: Fatal Category: Security In general, you should not package private key files inside your app. ''' if len(common.keyFiles) > 0: possibleKeyFiles = common.text_scan(common.keyFiles, r'PRIVATE\sKEY') if len(possibleKeyFiles) > 0: for f in possibleKeyFiles: common.logger.debug( "It appears there is a private key embedded in your application: " + str(f)) issue = ReportIssue() issue.setCategory(ExploitType.CRYPTO) issue.setDetails( "It appears there is a private key embedded in your application in the following file:" ) issue.setFile(str(f)) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData( "It appears there is a private key embedded in your application in the following file:" ) results.append(issue) return
def target(self, queue): results = [] possibleFiles = common.text_scan(common.java_files, r'API_KEY') count = 0 for f in possibleFiles: count += 1 pub.sendMessage('progress', bar=self.getName(), percent=round(count * 100 / len(possibleFiles))) common.logger.debug("Text found, " + str(f)) issue = ReportIssue() issue.setCategory(ExploitType.PLUGIN) issue.setDetails( "The string 'API_KEY' appears in the file: %s\n%s" % (f[1], str(f[0]))) issue.setFile(str(f[1])) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData("The string 'API_KEY' appears in the file: %s\n%s" % (f[1], str(f[0]))) results.append(issue) queue.put(results)
def target(self, queue): results = [] #TODO: add documentation for available API calls. Sample shown below. # Here, we want to scan all decompiled files to see if any file contains the text "pass" possibleFiles = common.text_scan(common.java_files, r'pass') count = 0 for f in possibleFiles: count += 1 # The following call generates the progress bar in the terminal output pub.sendMessage('progress', bar=self.getName(), percent=round(count*100/len(possibleFiles))) # Mostly for logging. This goes in the log file generated under /logs common.logger.debug("Text found, " + str(f)) issue = ReportIssue() # This will put individual results of the plugin scan in the HTML report. issue.setCategory(ExploitType.PLUGIN) issue.setDetails("The string 'pass' appears in the file: %s\n%s" % (f[1], str(f[0]))) issue.setFile(str(f[1])) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) # This puts individual results of the plugin scan in the terminal output. issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData("The string 'pass' appears in the file: %s\n%s" % (f[1], str(f[0]))) results.append(issue) # This is required to send the complete list of results (including the ones to be printed on terminal as well as # issues to be printed in tht HTML report) back to the main thread. queue.put(results)
def find_intent_files(): """ Find all files declaring or using intents in the application """ common.logger.info("Attempting to trace Intent Sources to Sinks") int_files = [] int_dec_list = [] int_dec_list.append([]) int_rex = r'import\sandroid\.content\.Intent' # This syntax is deprecated int_assign_rex1 = r'Intent\s*[A-Za-z0-9_$]+\s*[=;]\s+getIntent\(' int_assign_rex2 = r'[A-Za-z0-9_$]+\s*[=;]\s*Intent\.parseUri\(' int_assign_rex3 = r'Intent\s*[A-Za-z0-9_$]+\s*[=;]\s*new\s+Intent\(' int_files += common.text_scan(common.java_files, int_rex) for i in int_files: if len(i) > 0: tmp = [i[1]] int_dec_list += common.text_scan(tmp, int_assign_rex1) int_dec_list += common.text_scan(tmp, int_assign_rex2) int_dec_list += common.text_scan(tmp, int_assign_rex3) common.logger.info("Intent Declarations:") int_dec_list = filter(None, int_dec_list) for d in int_dec_list: if len(d) > 0: d[0] = re.sub(r'\s*[=;]\s*new\s*Intent\(.*', '', str(d[0])) d[0] = re.sub(r'(final)?\s*Intent\s+', '', str(d[0])) d[0] = re.sub(r'[=;]\s*getIntent\(.*', '', str(d[0])) d[0] = re.sub(r'\'', '', str(d[0])) d[0] = re.sub(r'\"', '', str(d[0])) d[0] = re.sub(r'\s+', '', str(d[0])) d[0] = re.sub(r'\[', '', str(d[0])) d[0] = re.sub(r'\\\\\t', '', str(d[0])) d[0] = re.sub(r'\\\t', '', str(d[0])) d[0] = re.sub(r'\\t', '', str(d[0])) d[0] = str(d[0]).strip('\t\n\r') common.logger.info(int_dec_list) return
def find_intent_files(): """ Find all files declaring or using intents in the application """ common.logger.info("Attempting to trace Intent Sources to Sinks") int_files = [] int_dec_list = [] int_dec_list.append([]) int_rex = r'import\sandroid\.content\.Intent' #This syntax is deprecated int_assign_rex1 = r'Intent\s*[A-Za-z0-9_$]+\s*[=;]\s+getIntent\(' int_assign_rex2 = r'[A-Za-z0-9_$]+\s*[=;]\s*Intent\.parseUri\(' int_assign_rex3 = r'Intent\s*[A-Za-z0-9_$]+\s*[=;]\s*new\s+Intent\(' int_files += common.text_scan(common.java_files, int_rex) for i in int_files: if len(i) > 0: tmp = [i[1]] int_dec_list += common.text_scan(tmp, int_assign_rex1) int_dec_list += common.text_scan(tmp, int_assign_rex2) int_dec_list += common.text_scan(tmp, int_assign_rex3) common.logger.info("Intent Declarations:") int_dec_list = filter(None, int_dec_list) for d in int_dec_list: if len(d) > 0: d[0] = re.sub(r'\s*[=;]\s*new\s*Intent\(.*', '', str(d[0])) d[0] = re.sub(r'(final)?\s*Intent\s+', '', str(d[0])) d[0] = re.sub(r'[=;]\s*getIntent\(.*', '', str(d[0])) d[0] = re.sub(r'\'', '', str(d[0])) d[0] = re.sub(r'\"', '', str(d[0])) d[0] = re.sub(r'\s+', '', str(d[0])) d[0] = re.sub(r'\[', '', str(d[0])) d[0] = re.sub(r'\\\\\t', '', str(d[0])) d[0] = re.sub(r'\\\t', '', str(d[0])) d[0] = re.sub(r'\\t', '', str(d[0])) d[0] = str(d[0]).strip('\t\n\r') common.logger.info(int_dec_list) return
def find_gradle(): version = 0 files = [] for (dirpath, dirname, filenames) in os.walk(common.sourceDirectory): for filename in filenames: if filename == 'build.gradle': files.append(os.path.join(dirpath, filename)) if len(files) > 0: matches = common.text_scan(files, r'def\s_compileSdkVersion\s*=\s*[0-9]+') # TODO - fix this so we don't have to account for the empty first element # We skip it if there are multiple build.gradle files, since manual input is unavoidable at that point if len(matches) == 2: for m in matches: if len(m) > 0: version = re.compile('\d+') version = version.findall(str(m[0]))[0] return version
def findGradle(): version=0 files=[] for (dirpath,dirname, filenames) in os.walk(common.sourceDirectory): for filename in filenames: if filename=='build.gradle': files.append(os.path.join(dirpath,filename)) if len(files)>0: matches=common.text_scan(files,r'def\s_compileSdkVersion\s*=\s*[0-9]+') #TODO - fix this so we don't have to account for the empty first element #We skip it if there are multiple build.gradle files, since manual input is unavoidable at that point if len(matches)==2: for m in matches: if len(m)>0: version=re.compile('\d+') version=version.findall(str(m[0]))[0] return version
def target(self, queue): results = [] possibleFiles = common.text_scan(common.java_files, r'pass') count = 0 for f in possibleFiles: count += 1 pub.sendMessage('progress', bar=self.getName(), percent=round(count*100/len(possibleFiles))) common.logger.debug("Text found, " + str(f)) issue = ReportIssue() issue.setCategory(ExploitType.PLUGIN) issue.setDetails("The string 'pass' appears in the file: %s\n%s" % (f[1], str(f[0]))) issue.setFile(str(f[1])) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData("The string 'pass' appears in the file: %s\n%s" % (f[1], str(f[0]))) results.append(issue) queue.put(results)
except Exception as e: common.logger.error("Unable to check for exported Preference Activities: " + str(e)) ''' ######################### #Look for TapJacking vulnerabilities #Native protection was added in API v. 9, so previous likely vulnerable if common.minSdkVersion >8: common.logger.debug("Beginning TapJacking testing") findTapJacking.start(common.sourceDirectory) else: common.logger.log(common.VULNERABILITY_LEVEL,"Since the minSdkVersion is less that 9, it is likely this application is vulnerable to TapJacking. QARK made no attempt to confirm, as the protection would have to be custom code, which is difficult for QARK to examine and understand properly. This vulnerability allows a malicious application to lay on top of this app, while letting the key strokes pass through to the application below. This can cause users to take unwanted actions, within the victim application, similar to Clickjacking on websites. Please select the appropriate options in the exploitation menus to verify manually using QARK's exploit APK. Note: The QARK proof-of-concept is transparent, but in real-world attacks, it would likely not be. This is done solely to aid in testing. For more information: https://media.blackhat.com/ad-12/Niemietz/bh-ad-12-androidmarcus_niemietz-WP.pdf") ########### #Look for Content Provider issues if len(common.text_scan(common.java_files,cp_imp_rex)) > 1: common.logger.info("Content Providers appear to be in use, locating...") cp_dec_list=contentProvider.find_content_providers() cp_dec_list=filter(None,cp_dec_list) cp_dec_list=common.dedup(cp_dec_list) common.logger.info("FOUND " + str(len(cp_dec_list)) + " CONTENTPROVIDERS:") for p in cp_dec_list: common.logger.info(str(p)) query_rex=r'\.query\(.*\)' update_rex=r'\.update\(.*\)' delete_rex=r'\.delete\(.*\)' insert_rex=r'\.insert\(.*\)' #TODO - Add SQLi checks #VERY LAME SQL INJECTION DETECTION (GUESSING)
def find_extras(stub_file_name, path): """ Find all extras given a filename """ # TODO - This needs to be gutted and re-writtten extras = [] filename = re.search(r'\w+$', stub_file_name) filename = filename.group() fname = common.grep(path, r'' + str(filename) + '\.java') rextras = [] rextras.append(r'getExtras\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getStringExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getIntExtra\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getIntArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getFloatExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getFloatArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getDoubleExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getDoubleArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getByteExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getByteArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getBundleExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getBooleanExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getBooleanArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharSequenceArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharSequenceArrayListExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharSequenceExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getInterArrayListExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getLongArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getLongExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getParcelableArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getParcelableArrayListExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getParcelableExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getSeriablizableExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getShortArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getShortExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getStringArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getStringArrayListExtra\(\s*[0-9A-Za-z_\"\'.]+') # These are not necessarily Intent extras, but may contain them rextras.append(r'getString\(\s*[0-9A-Za-z_\"\'.]+') # TODO add data types to the extras, so we can provide better suggestions if len(fname) > 0: x_tmp = [] x_tmp.append([]) for r in rextras: x_tmp = common.text_scan(fname, r) for m in x_tmp: if len(m) > 0: i = 0 for l in m: if type(l) is list: sigh = [] for s in l: sigh.append(re.sub(r'.*\(', '', str(s))) sigh[i] = re.sub(r'\).*', '', sigh[i]) sigh[i] = re.sub(r'\s*,.*', '', sigh[i]) extras += sigh i += 1 extras = common.dedup(extras) if len(extras) < 1: common.logger.debug("No extras found in " + str(fname[0]) + " to suggest.\n") common.parsingerrors.add(str(fname[0])) else: # BUG - seems like a flow can come here without the fname; Ex: Flagship S - 4 common.logger.error("Sorry, we could not find a filename while looking for extras\n") # Trying to get rid of empty first element return extras
def find_content_providers(): """ Find all content providers and return the list """ cp_list = common.find_ext('ContentProvider') growing = 1 # TODO - This is ugly and needs to be re-written # The intention here is to loop endlessly until all extensions are found while growing: cp_list_count_old = len(cp_list) cp_list += common.tree(cp_list) if len(cp_list) == cp_list_count_old: growing = 0 cp_list.append(['ContentProvider', '']) cp_decs = [] cp_decs.append([]) for x in cp_list: if len(x) > 0: tmp = r'' + re.escape(str(x[0])) + r'\s\w+[;=]' cp_decs += common.text_scan(common.java_files, tmp) tmp = r'(private .*|protected.*)' + re.escape(str( x[0])) + r'\s\w+;' cp_decs += common.text_scan(common.java_files, tmp) tmp = r'\w+\s[;=]\snew\s' + re.escape(str(x[0])) + r'\(' cp_decs += common.text_scan(common.java_files, tmp) tmp = r'\(.*' + re.escape( str(x[0]) ) + r'\s\w+.*\)' # Need to ensure this is working properly tmp_list2 = [] tmp_list2.append([]) for z in cp_decs: if len(z) > 0: # conditional declarations will cause conditional positives # BUG sometimes Z[0] is a list, rather than just a list element. Need to separate, remove and re-parse if (len(z[0]) > 1 and not isinstance(z[0], str)): for x in z[0]: foo = [x, z[1]] tmp_list2.append(foo) cp_decs.pop() continue else: tmp_list2.append(z) else: tmp_list2.append(z) tmp_list2 = filter(None, tmp_list2) for y in tmp_list2: if len(y) > 0: y[0] = re.sub(r';\\n', '', str(y[0]).strip('[]\'')) y[0] = re.sub(r'\\t*', '', y[0]) y[0] = re.sub(r'\s*private\b', '', y[0]) y[0] = re.sub(r'\s*protected\b', '', y[0]) y[0] = re.sub(r'\s*static\b', '', y[0]) y[0] = re.sub(r'^\s*ContentProvider\b', '', y[0]) y[0] = re.sub(r'\s*[;=]\s*new\sContentProvider\s.*', '', y[0]) y[0] = re.sub(r'\s*[;=]\s*new\s\w+\(.*\)', '', y[0]) y[0] = re.sub(r'^\s*', '', y[0]) y[0] = re.sub(r'\s*$', '', y[0]) y[0] = re.sub(r'^\w+\s', '', y[0]) y[0] = re.sub(r';$', '', y[0]) # remove whitespace y[0] = y[0].strip(' \t\r\n') tmp_list2 = common.dedup(tmp_list2) return tmp_list2
def find_webviews(): """ Finds all webviews in the decompiled source code """ #1. Look for classes that extend WebView #Find classes that extend Web View wv_list=find_ext('WebView') #2. Look for classes that extend classes that extend WebView while len(common.tree(wv_list)) > 1: wv_list+=common.tree(wv_list) wv_list.append(['WebView','']) #3. Cleanup? #4. Look for all declaration of WebViews using normal and extended class names #BUG sometimes multiple declarations are coming back for z[0], need to figure out what is going on there #Currently there may be false negatives #BUG - Need to review this for optional/multiple spaces wv_decs=[] wv_decs.append([]) for x in wv_list: if len(x)>0: tmp=r''+re.escape(str(x[0]))+r'\s\w+[;=]' wv_decs+=common.text_scan(common.java_files,tmp) tmp=r'(private .*|protected.*)'+ re.escape(str(x[0]))+r'\s\w+;' wv_decs+=common.text_scan(common.java_files,tmp) tmp=r'\w+\s[;=]\snew\s'+re.escape(str(x[0]))+r'\(' wv_decs+=common.text_scan(common.java_files,tmp) tmp=r'\(.*'+re.escape(str(x[0]))+r'\s\w+.*\)' # Need to ensure this is working properly tmp_list2=[] tmp_list2.append([]) for z in wv_decs: if len(z)>0: #conditional declarations will cause conditional positives #BUG sometimes Z[0] is a list, rather than just a list element. Need to separate, remove and re-parse if (len(z[0])>1 and not isinstance(z[0],str)): for x in z[0]: foo=[x,z[1]] tmp_list2.append(foo) wv_decs.pop() continue else: tmp_list2.append(z) else: tmp_list2.append(z) tmp_list2=filter(None,tmp_list2) for y in tmp_list2: if len(y)>0: y[0]=re.sub(r';\\n','',str(y[0]).strip('[]\'')) y[0]=re.sub(r'\\t*','',y[0]) y[0]=re.sub(r'\s*private\b','',y[0]) y[0]=re.sub(r'\s*protected\b','',y[0]) y[0]=re.sub(r'\s*static\b','',y[0]) y[0]=re.sub(r'^\s*WebView\b','',y[0]) y[0]=re.sub(r'\s*[;=]\s*new\sWebView\s.*','',y[0]) y[0]=re.sub(r'\s*[;=]\s*new\s\w+\(.*\)','',y[0]) y[0]=re.sub(r'^\s*','',y[0]) y[0]=re.sub(r'\s*$','',y[0]) y[0]=re.sub(r'^\w+\s','',y[0]) y[0]=re.sub(r';$','',y[0]) #remove whitespace y[0]=y[0].strip(' \t\r\n') tmp_list2=common.dedup(tmp_list2) return tmp_list2
def find_webviews(): """ Finds all webviews in the decompiled source code """ #1. Look for classes that extend WebView #Find classes that extend Web View wv_list = find_ext('WebView') #2. Look for classes that extend classes that extend WebView while len(common.tree(wv_list)) > 1: wv_list += common.tree(wv_list) wv_list.append(['WebView', '']) #3. Cleanup? #4. Look for all declaration of WebViews using normal and extended class names #BUG sometimes multiple declarations are coming back for z[0], need to figure out what is going on there #Currently there may be false negatives #BUG - Need to review this for optional/multiple spaces wv_decs = [] wv_decs.append([]) for x in wv_list: if len(x) > 0: tmp = r'' + re.escape(str(x[0])) + r'\s\w+[;=]' wv_decs += common.text_scan(common.java_files, tmp) tmp = r'(private .*|protected.*)' + re.escape(str( x[0])) + r'\s\w+;' wv_decs += common.text_scan(common.java_files, tmp) tmp = r'\w+\s[;=]\snew\s' + re.escape(str(x[0])) + r'\(' wv_decs += common.text_scan(common.java_files, tmp) tmp = r'\(.*' + re.escape( str(x[0]) ) + r'\s\w+.*\)' # Need to ensure this is working properly tmp_list2 = [] tmp_list2.append([]) for z in wv_decs: if len(z) > 0: #conditional declarations will cause conditional positives #BUG sometimes Z[0] is a list, rather than just a list element. Need to separate, remove and re-parse if (len(z[0]) > 1 and not isinstance(z[0], str)): for x in z[0]: foo = [x, z[1]] tmp_list2.append(foo) wv_decs.pop() continue else: tmp_list2.append(z) else: tmp_list2.append(z) tmp_list2 = filter(None, tmp_list2) for y in tmp_list2: if len(y) > 0: y[0] = re.sub(r';\\n', '', str(y[0]).strip('[]\'')) y[0] = re.sub(r'\\t*', '', y[0]) y[0] = re.sub(r'\s*private\b', '', y[0]) y[0] = re.sub(r'\s*protected\b', '', y[0]) y[0] = re.sub(r'\s*static\b', '', y[0]) y[0] = re.sub(r'^\s*WebView\b', '', y[0]) y[0] = re.sub(r'\s*[;=]\s*new\sWebView\s.*', '', y[0]) y[0] = re.sub(r'\s*[;=]\s*new\s\w+\(.*\)', '', y[0]) y[0] = re.sub(r'^\s*', '', y[0]) y[0] = re.sub(r'\s*$', '', y[0]) y[0] = re.sub(r'^\w+\s', '', y[0]) y[0] = re.sub(r';$', '', y[0]) #remove whitespace y[0] = y[0].strip(' \t\r\n') tmp_list2 = common.dedup(tmp_list2) return tmp_list2
def find_extras(stub_file_name,path): """ Find all extras given a filename """ #TODO - This needs to be gutted and re-writtten extras=[] filename=re.search(r'\w+$',stub_file_name) filename=filename.group() fname=common.grep(path,r''+str(filename)+'\.java') rextras=[] rextras.append(r'getExtras\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getStringExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getIntExtra\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getIntArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getFloatExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getFloatArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getDoubleExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getDoubleArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getByteExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getByteArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getBundleExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getBooleanExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getBooleanArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharSequenceArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharSequenceArrayListExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getCharSequenceExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getInterArrayListExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getLongArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getLongExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getParcelableArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getParcelableArrayListExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getParcelableExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getSeriablizableExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getShortArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getShortExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getStringArrayExtra\(\s*[0-9A-Za-z_\"\'.]+') rextras.append(r'getStringArrayListExtra\(\s*[0-9A-Za-z_\"\'.]+') #These are not necessarily Intent extras, but may contain them rextras.append(r'getString\(\s*[0-9A-Za-z_\"\'.]+') #TODO add data types to the extras, so we can provide better suggestions if len(fname)>0: x_tmp=[] x_tmp.append([]) for r in rextras: x_tmp=common.text_scan(fname,r) for m in x_tmp: if len(m)>0: i=0 for l in m: if type(l) is list: sigh=[] for s in l: sigh.append(re.sub(r'.*\(','',str(s))) sigh[i]=re.sub(r'\).*','',sigh[i]) sigh[i]=re.sub(r'\s*,.*','',sigh[i]) extras+=sigh i+=1 extras=common.dedup(extras) if len(extras)<1: common.logger.debug("No extras found in " + str(fname[0]) + " to suggest.\n") common.parsingerrors.add(str(fname[0])) else: #BUG - seems like a flow can come here without the fname; Ex: Flagship S - 4 common.logger.error("Sorry, we could not find a filename while looking for extras\n") #Trying to get rid of empty first element return extras
def find_content_providers(): """ Find all content providers and return the list """ cp_list = common.find_ext('ContentProvider') growing = 1 # TODO - This is ugly and needs to be re-written # The intention here is to loop endlessly until all extensions are found while growing: cp_list_count_old = len(cp_list) cp_list += common.tree(cp_list) if len(cp_list) == cp_list_count_old: growing = 0 cp_list.append(['ContentProvider', '']) cp_decs = [] cp_decs.append([]) for x in cp_list: if len(x) > 0: tmp = r'' + re.escape(str(x[0])) + r'\s\w+[;=]' cp_decs += common.text_scan(common.java_files, tmp) tmp = r'(private .*|protected.*)' + re.escape(str(x[0])) + r'\s\w+;' cp_decs += common.text_scan(common.java_files, tmp) tmp = r'\w+\s[;=]\snew\s' + re.escape(str(x[0])) + r'\(' cp_decs += common.text_scan(common.java_files, tmp) tmp = r'\(.*' + re.escape(str(x[0])) + r'\s\w+.*\)' # Need to ensure this is working properly tmp_list2 = [] tmp_list2.append([]) for z in cp_decs: if len(z) > 0: # conditional declarations will cause conditional positives # BUG sometimes Z[0] is a list, rather than just a list element. Need to separate, remove and re-parse if (len(z[0]) > 1 and not isinstance(z[0], str)): for x in z[0]: foo = [x, z[1]] tmp_list2.append(foo) cp_decs.pop() continue else: tmp_list2.append(z) else: tmp_list2.append(z) tmp_list2 = filter(None, tmp_list2) for y in tmp_list2: if len(y) > 0: y[0] = re.sub(r';\\n', '', str(y[0]).strip('[]\'')) y[0] = re.sub(r'\\t*', '', y[0]) y[0] = re.sub(r'\s*private\b', '', y[0]) y[0] = re.sub(r'\s*protected\b', '', y[0]) y[0] = re.sub(r'\s*static\b', '', y[0]) y[0] = re.sub(r'^\s*ContentProvider\b', '', y[0]) y[0] = re.sub(r'\s*[;=]\s*new\sContentProvider\s.*', '', y[0]) y[0] = re.sub(r'\s*[;=]\s*new\s\w+\(.*\)', '', y[0]) y[0] = re.sub(r'^\s*', '', y[0]) y[0] = re.sub(r'\s*$', '', y[0]) y[0] = re.sub(r'^\w+\s', '', y[0]) y[0] = re.sub(r';$', '', y[0]) # remove whitespace y[0] = y[0].strip(' \t\r\n') tmp_list2 = common.dedup(tmp_list2) return tmp_list2