Exemplo n.º 1
0
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
Exemplo n.º 2
0
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
Exemplo n.º 3
0
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
Exemplo n.º 4
0
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
Exemplo n.º 5
0
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
Exemplo n.º 6
0
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
Exemplo n.º 7
0
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
Exemplo n.º 8
0
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_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
Exemplo n.º 10
0
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
Exemplo n.º 11
0
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