-
Notifications
You must be signed in to change notification settings - Fork 0
/
redroid.py
194 lines (175 loc) · 7.21 KB
/
redroid.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#!/usr/bin/env python3
import os
import sys
import subprocess
# CONFIG
keystorePath = os.path.expanduser("~") + "/android.keystore"
keyName = "debug"
version = "v0.8"
logo = " __ ___ __ __ __ __ \n|__) |__ | \ |__) / \ | | \ \n| \ |___ |__/ | \ \__/ | |__/\n "+version+" - ethaniel.me\n"
branches = list()
selectedBranch = -1
workspaceDir = ""
def writeDat():
global branches, workspaceDir
file = open(workspaceDir + "/redroid.dat", "w")
for i in range(len(branches)):
file.write(branches[i] + "\n")
file.close()
def loadDat():
global branches
file = open(workspaceDir + "/redroid.dat", "r")
branches = [line.strip() for line in file.readlines()]
file.close()
def printHeader():
global branches
subprocess.run(["clear"])
print(logo)
i = 0
for branch in branches:
print("*" if i == selectedBranch else " ", end="")
print(i, " ", branch)
i += 1
print()
def printHelp():
print(
'''Commands:
branch <description> Branches modified.apk with a new description
clear Clears the command line and prints branch list
decompile Decompiles the original.apk of current branch
diff <branch #> Outputs diff of current branch and arg branch
exit Exits the program
help Shows this help dialog
install Install modified.apk to an adb device
recompile Recompiles the branch into modified.apk
remove Deletes the current branch
reset Removes all decompiled/modified source code
show Opens the current branch in a file browser
sign Signs the apk
switch/select <#> Selects branch #'''
)
def poll():
global branches, selectedBranch, keystorePath
command = input("> ")
if command.startswith("help"):
printHelp()
elif command.startswith("switch") or command.startswith("select"):
args = command.split(' ')
if len(args) < 2:
print("Usage: select <branch #>")
elif args[1].isdigit() and int(args[1]) < len(branches):
selectedBranch = int(args[1])
printHeader()
else:
print("Invalid branch #")
elif command == "clear":
printHeader()
elif command == "exit":
return
elif selectedBranch != -1:
moddedPath = workspaceDir + "/" + str(selectedBranch) + "/modified.apk"
if command.startswith("branch"):
args = command.split("branch ")
if len(args) < 2:
print("Usage: branch <description>")
elif (os.path.isfile(moddedPath)):
addBranch(moddedPath, command.lstrip('branch '))
printHeader()
else:
print("Current branch has not been recompiled yet")
elif command == "decompile" or command == "d":
decompile(selectedBranch)
elif command == "reset":
subprocess.run(['rm', '-rf', workspaceDir + "/" + str(selectedBranch) + '/original/'])
elif command == "recompile" or command == "r":
recompile(selectedBranch)
elif command == "remove":
removeBranch(selectedBranch)
printHeader()
elif command.startswith("diff"):
args = command.split(" ")
if (len(args) < 2):
print("Usage: diff <target #>")
elif args[1].isdigit() and int(args[1]) < len(branches):
diffProcess = subprocess.Popen(["diff", "-rq", str(selectedBranch) + "/", str(args[1]) + "/"], stdout=subprocess.PIPE)
for line in iter(diffProcess.stdout.readline, b''):
print(line.decode('utf-8').strip())
else:
print("Invalid branch #")
elif command == "sign":
if (os.path.isfile(moddedPath)):
signProcess = subprocess.Popen(['jarsigner', '-verbose', '-sigalg', 'SHA1withRSA', '-digestalg', 'SHA1', '-keystore', keystorePath, moddedPath, 'debug'], stdout=subprocess.PIPE)
for line in iter(signProcess.stdout.readline, b''):
print(line.decode('utf-8').strip())
else:
print("Current branch has not been recompiled yet")
elif command == "show":
subprocess.run(['nautilus', workspaceDir+"/"+str(selectedBranch)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
elif command == "install":
if (os.path.isfile(workspaceDir + "/" + str(selectedBranch) +"/modified.apk")):
signProcess = subprocess.Popen(['adb', 'install', workspaceDir+'/'+str(selectedBranch)+'/modified.apk'], stdout=subprocess.PIPE)
for line in iter(signProcess.stdout.readline, b''):
print(line.decode('utf-8').strip())
else:
print("Current branch has not been recompiled yet")
else:
print("Invalid command. Select a branch or type help for commands.")
else:
print("Invalid command. Select a branch or type help for commands.")
poll()
def loadWorkSpace():
global branches
if (os.path.isfile("./redroid.dat")):
loadDat()
for i in range(len(branches)):
if not os.path.isdir("./" + str(i)):
print("Corrupted redroid.dat")
return
elif len(sys.argv) == 1:
print("Workspace not detected. Use:")
print(" redroid /path/to/target.apk")
print("to initialize a workspace in the cwd")
return
if len(sys.argv) > 1:
addBranch(sys.argv[1])
printHeader()
poll()
def addBranch(apkPath, desc=""):
global branches, selectedBranch
branchID = len(branches)
os.chdir(workspaceDir)
subprocess.run(["mkdir", str(branchID)])
print("Created Directory")
subprocess.run(["cp", apkPath, str(branchID) + "/original.apk"])
print("Copied APK")
decompile(branchID)
if desc == "":
desc = input("Enter a branch description: ")
branches.append(desc)
writeDat()
selectedBranch = branchID
def removeBranch(branchID):
global selectedBranch
subprocess.run(["rm", "-rf", workspaceDir + "/" + str(branchID)])
branches.pop(branchID)
while branchID < len(branches):
subprocess.run(["mv", workspaceDir + "/" + str(branchID+1), workspaceDir + "/" + str(branchID)])
branchID += 1
writeDat()
selectedBranch = -1
def decompile(branchID):
os.chdir(workspaceDir + "/" + str(branchID))
decompileProcess = subprocess.Popen(["apktool", "d", "original.apk"], stdout=subprocess.PIPE)
for line in iter(decompileProcess.stdout.readline, b""):
print(line.decode("utf-8").strip())
def recompile(branchID):
os.chdir(workspaceDir + "/" + str(branchID))
recompileProcess = subprocess.Popen(["apktool", "b", "original"], stdout=subprocess.PIPE)
for line in iter(recompileProcess.stdout.readline, b""):
print(line.decode("utf-8").strip())
moveProcess = subprocess.Popen(["cp", "./original/dist/original.apk", "./modified.apk"], stdout=subprocess.PIPE)
for line in iter(moveProcess.stdout.readline, b""):
print(line.decode("utf-8").strip())
if __name__ == "__main__":
workspaceDir = os.getcwd()
loadWorkSpace()