Skip to content
This repository was archived by the owner on Aug 31, 2023. It is now read-only.

Commit 3f2e412

Browse files
authored
Merge pull request #9 from orf/patch-1
Big refactorings
2 parents 3c251e7 + 4b8457e commit 3f2e412

1 file changed

Lines changed: 177 additions & 156 deletions

File tree

apk2java.py

Lines changed: 177 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -5,188 +5,209 @@
55
import sys, os, string
66
import urllib.request
77
import zipfile
8-
from subprocess import call
8+
import subprocess
99
from optparse import OptionParser
1010

11-
apk_file=''
12-
apk_folder=''
13-
project_name=''
14-
sign_file=''
15-
cwd=os.path.dirname(os.path.abspath(__file__))
16-
home=os.path.dirname(os.path.realpath(sys.argv[0]))
17-
outdir=os.path.dirname(os.path.realpath(sys.argv[1]))
18-
external="https://github.com/TheZ3ro/apk2java-linux/releases/download/tool/tool.zip"
11+
12+
def call(cmd, **kwargs):
13+
print('Running: {0}'.format(' '.join(cmd)))
14+
return subprocess.call(cmd, **kwargs)
15+
16+
17+
apk_file = ''
18+
apk_folder = ''
19+
project_name = ''
20+
sign_file = ''
21+
cwd = os.path.dirname(os.path.abspath(__file__))
22+
home = os.path.dirname(os.path.realpath(sys.argv[0]))
23+
outdir = os.path.dirname(os.path.realpath(sys.argv[1]))
24+
external = "https://github.com/TheZ3ro/apk2java-linux/releases/download/tool/tool.zip"
25+
1926

2027
def check_home(path):
21-
return os.path.isdir(path+"/tool")
28+
return os.path.isdir(path + "/tool")
29+
2230

2331
def getunzipped(theurl, thedir, report):
24-
if not os.path.exists(thedir):
25-
os.mkdir(thedir)
26-
print ("Downloading external tool... -> "+thedir+"/tool/")
27-
name = os.path.join(thedir, 'temp.zip')
28-
try:
29-
name, hdrs = urllib.request.urlretrieve(theurl, name, report)
30-
except IOError as e:
31-
print ("Can't retrieve %r to %r: %s" % (theurl, thedir, e))
32-
return
33-
try:
34-
z = zipfile.ZipFile(name)
35-
except zipfile.error as e:
36-
print ("Bad zipfile (from %r): %s" % (theurl, e))
37-
return
38-
for n in z.namelist():
39-
(dirname, filename) = os.path.split(n)
40-
perm = ((z.getinfo(n).external_attr >> 16) & 0x0777)
41-
if filename == '':
42-
# directory
43-
newdir = thedir + '/' + dirname
44-
if not os.path.exists(newdir):
45-
os.mkdir(newdir)
46-
else:
47-
# file
48-
fd = os.open(thedir+"/"+n, os.O_CREAT | os.O_WRONLY, perm)
49-
os.write(fd, z.read(n))
50-
os.close(fd)
51-
z.close()
52-
os.unlink(name)
53-
print ("")
32+
if not os.path.exists(thedir):
33+
os.mkdir(thedir)
34+
print("Downloading external tool... -> " + thedir + "/tool/")
35+
name = os.path.join(thedir, 'temp.zip')
36+
try:
37+
name, hdrs = urllib.request.urlretrieve(theurl, name, report)
38+
except IOError as e:
39+
print("Can't retrieve %r to %r: %s" % (theurl, thedir, e))
40+
return
41+
try:
42+
z = zipfile.ZipFile(name)
43+
except zipfile.error as e:
44+
print("Bad zipfile (from %r): %s" % (theurl, e))
45+
return
46+
for n in z.namelist():
47+
(dirname, filename) = os.path.split(n)
48+
perm = ((z.getinfo(n).external_attr >> 16) & 0x0777)
49+
if filename == '':
50+
# directory
51+
newdir = thedir + '/' + dirname
52+
if not os.path.exists(newdir):
53+
os.mkdir(newdir)
54+
else:
55+
# file
56+
fd = os.open(thedir + "/" + n, os.O_CREAT | os.O_WRONLY, perm)
57+
os.write(fd, z.read(n))
58+
os.close(fd)
59+
z.close()
60+
os.unlink(name)
61+
print("")
62+
5463

5564
def report(blocknr, blocksize, size):
56-
current = blocknr*blocksize
57-
sys.stdout.write("\rProgress: {0:.2f}%".format(100.0*current/size)+" - {0:.1f} MB".format(current/1024/1024)+"/{0:.1f} MB".format(size/1024/1024))
65+
current = blocknr * blocksize
66+
sys.stdout.write("\rProgress: {0:.2f}%".format(100.0 * current / size) + " - {0:.1f} MB".format(
67+
current / 1024 / 1024) + "/{0:.1f} MB".format(size / 1024 / 1024))
68+
69+
70+
def print_header(text):
71+
block = "*********************************************"
72+
print(block)
73+
print('**' + text.center(len(block) - 4) + '**')
74+
print(block)
75+
5876

5977
def apktool(smali):
60-
print ("*********************************************")
61-
print ("** Extract, fix resource files **")
62-
print ("*********************************************")
63-
if apk_file != '':
64-
if smali == True:
65-
call(home+'/tool/apktool_200rc3.jar d '+apk_file+' -o '+outdir+project_name+' -f',shell=True)
66-
else:
67-
call(home+'/tool/apktool_200rc3.jar d '+apk_file+' -o '+outdir+project_name+' -sf',shell=True)
68-
os.system('mv %s %s' % (outdir+project_name+'/classes.dex', outdir+project_name+'/original/'))
69-
print ('Done')
78+
print_header('Extract, fix resource files')
79+
if apk_file != '':
80+
cmd = [home + '/tool/apktool_200rc3.jar', 'd', apk_file, '-o', outdir + project_name, '-f']
81+
82+
if smali:
83+
cmd[-1] = '-sf'
84+
85+
call(cmd)
86+
call(['mv', outdir + project_name + '/classes.dex', outdir + project_name + '/original/'])
87+
print('Done')
88+
7089

7190
def dex2jar():
72-
print ("*********************************************")
73-
print ("** Convert 'apk' to 'jar' **")
74-
print ("*********************************************")
75-
if apk_file != '':
76-
call(home+'/tool/dex2jar-0.0.9.15/d2j-dex2jar.sh -f -o '+outdir+project_name+'.jar '+apk_file, shell=True)
77-
call(home+'/tool/dex2jar-0.0.9.15/d2j-asm-verify.sh '+outdir+project_name+'.jar',shell=True)
78-
print ('Done')
91+
print_header("Convert 'apk' to 'jar'")
92+
if apk_file != '':
93+
call([home + '/tool/dex2jar-0.0.9.15/d2j-dex2jar.sh', '-f', '-o', outdir + project_name + '.jar', apk_file])
94+
call([home + '/tool/dex2jar-0.0.9.15/d2j-asm-verify.sh', outdir + project_name + '.jar'])
95+
print('Done')
96+
7997

8098
def procyon():
81-
print ("*********************************************")
82-
print ("** Decompiling class files **")
83-
print ("*********************************************")
84-
if apk_file != '':
85-
call(home+'/tool/procyon-decompiler-0528.jar -jar '+outdir+project_name+'.jar -o '+outdir+project_name+'/src/',shell=True)
86-
print ('Done')
99+
print_header('Decompiling class files')
100+
if apk_file != '':
101+
call([home + '/tool/procyon-decompiler-0528.jar', '-jar', outdir + project_name + '.jar',
102+
'-o', outdir + project_name + '/src/'])
103+
print('Done')
104+
87105

88106
def apktool_build():
89-
print ("*********************************************")
90-
print ("** Building apk from smali **")
91-
print ("*********************************************")
92-
if apk_folder != '':
93-
call(home+'/tool/apktool_200rc3.jar b '+apk_folder+' -o '+outdir+project_name+'-rebuild.apk',shell=True)
94-
global sign_file
95-
sign_file = outdir+project_name+'-rebuild.apk'
96-
print ('Done')
107+
print_header('Building apk from smali')
108+
if apk_folder != '':
109+
call([home + '/tool/apktool_200rc3.jar', 'b', apk_folder, '-o', outdir + project_name + '-rebuild.apk'])
110+
global sign_file
111+
sign_file = outdir + project_name + '-rebuild.apk'
112+
print('Done')
113+
97114

98115
def jar2jasmin():
99-
print ("*********************************************")
100-
print ("** Convert 'jar' to 'jasmin' **")
101-
print ("*********************************************")
102-
if apk_file != '':
103-
call(home+'/tool/dex2jar-0.0.9.15/d2j-jar2jasmin.sh -f -o '+outdir+project_name+'/jasmin '+outdir+project_name+'.jar',shell=True)
104-
print ('Done')
116+
print_header("Convert 'jar' to 'jasmin'")
117+
if apk_file != '':
118+
call([home + '/tool/dex2jar-0.0.9.15/d2j-jar2jasmin.sh', '-f', '-o', outdir + project_name + '/jasmin',
119+
outdir + project_name + '.jar'])
120+
print('Done')
121+
105122

106123
def jasmin_build():
107-
print ("*********************************************")
108-
print ("** Build apk from jasmin **")
109-
print ("*********************************************")
110-
if apk_folder != '':
111-
call(home+'/tool/dex2jar-0.0.9.15/d2j-jasmin2jar.sh -f -o '+outdir+project_name+'-new.jar '+outdir+project_name+'/jasmin',shell=True)
112-
call(home+'/tool/dex2jar-0.0.9.15/d2j-asm-verify.sh '+outdir+project_name+'-new.jar',shell=True)
113-
call(home+'/tool/dex2jar-0.0.9.15/d2j-jar2dex.sh -f -o '+outdir+project_name+'/classes.dex '+outdir+project_name+'-new.jar',shell=True)
114-
call('zip -r '+outdir+project_name+'-new.apk -j '+outdir+project_name+'/classes.dex',shell=True)
115-
global sign_file
116-
sign_file = outdir+project_name+'-new.apk'
117-
print ('Done')
124+
print_header('Build apk from jasmin')
125+
if apk_folder != '':
126+
call([home + '/tool/dex2jar-0.0.9.15/d2j-jasmin2jar.sh', '-f', '-o', outdir + project_name + '-new.jar',
127+
outdir + project_name + '/jasmin'])
128+
call([home + '/tool/dex2jar-0.0.9.15/d2j-asm-verify.sh', outdir + project_name + '-new.jar'])
129+
call([home + '/tool/dex2jar-0.0.9.15/d2j-jar2dex.sh', '-f', '-o', outdir + project_name + '/classes.dex',
130+
outdir + project_name + '-new.jar'])
131+
call(['zip', '-r ' + outdir + project_name + '-new.apk', '-j', outdir + project_name + '/classes.dex'])
132+
global sign_file
133+
sign_file = outdir + project_name + '-new.apk'
134+
print('Done')
135+
118136

119137
def sign():
120-
print ("*********************************************")
121-
print ("** Sign apk **")
122-
print ("*********************************************")
123-
call(home+'/tool/dex2jar-0.0.9.15/d2j-apk-sign.sh -f -o '+outdir+project_name+'-signed.apk '+sign_file,shell=True)
124-
print ('Done')
138+
print_header('Sign apk')
139+
call([home + '/tool/dex2jar-0.0.9.15/d2j-apk-sign.sh', '-f', '-o', outdir + project_name + '-signed.apk',
140+
sign_file])
141+
print('Done')
142+
125143

126144
def main():
127-
global apk_folder,apk_file,project_name,home,outdir
128-
usage = "usage: %prog action file [options]"
129-
parser = OptionParser(usage=usage)
130-
parser.add_option("--java",action="store_true", dest="java", default=True, help="select java source format [DEFAULT]")
131-
parser.add_option("--smali",action="store_true", dest="smali", default=False, help="select smali source format")
132-
parser.add_option("--jasmin",action="store_true", dest="jasmin", default=False, help="select jasmin source format")
133-
parser.add_option("--no-source",action="store_true", dest="nosc", default=False, help="no source code generation")
134-
parser.add_option("-o", dest="outdir", default=cwd+"/", help="specify the output directory "
135-
+"(if not specified the decomipled version will be store in a folder in the script directory)")
136-
(options, args) = parser.parse_args()
137-
138-
if home == cwd+"/apk2java":
139-
if check_home(home) == False:
140-
getunzipped(external, home, report)
141-
else:
142-
if check_home(home) == False:
143-
if check_home(cwd+"/apk2java") == False:
144-
getunzipped(external, cwd+"/apk2java", report)
145-
home = cwd+"/apk2java"
146-
else:
147-
home = cwd+"/apk2java"
148-
outdir = options.outdir
149-
150-
if (options.smali+options.jasmin+options.nosc) > 1:
151-
print ("[ ERROR ] You can only select 1 source format --[smali/jasmin/java/no-source]")
152-
exit(1)
153-
if len(args)==2:
154-
if args[0] == 'd':
155-
if os.path.isfile(args[1]) and os.path.splitext(args[1])[-1].lower() == '.apk':
156-
apk_file = args[1]
157-
project_name = os.path.splitext(os.path.basename(args[1]))[0].lower()
158-
if not os.path.exists(outdir):
159-
os.makedirs(outdir)
160-
call("cp "+apk_file+" "+outdir+project_name+"-new.apk",shell=True)
161-
if options.jasmin == True:
162-
dex2jar()
163-
jar2jasmin()
164-
else:
165-
apktool(options.smali)
166-
if options.smali == False and options.nosc == False:
167-
dex2jar()
168-
procyon()
169-
call("cp "+tmp+project_name+"/ ./ -R",shell=True)
170-
else:
171-
print ("[ ERROR ] You must select a valid APK file!")
145+
global apk_folder, apk_file, project_name, home, outdir
146+
usage = "usage: %prog action file [options]"
147+
parser = OptionParser(usage=usage)
148+
parser.add_option("--java", action="store_true", dest="java", default=True,
149+
help="select java source format [DEFAULT]")
150+
parser.add_option("--smali", action="store_true", dest="smali", default=False, help="select smali source format")
151+
parser.add_option("--jasmin", action="store_true", dest="jasmin", default=False, help="select jasmin source format")
152+
parser.add_option("--no-source", action="store_true", dest="nosc", default=False, help="no source code generation")
153+
parser.add_option("-o", dest="outdir", default=cwd + "/", help="specify the output directory "
154+
+ "(if not specified the decomipled version will be store in a folder in the script directory)")
155+
(options, args) = parser.parse_args()
156+
157+
if home == cwd + "/apk2java":
158+
if check_home(home) == False:
159+
getunzipped(external, home, report)
160+
else:
161+
if check_home(home) == False:
162+
if check_home(cwd + "/apk2java") == False:
163+
getunzipped(external, cwd + "/apk2java", report)
164+
home = cwd + "/apk2java"
165+
else:
166+
home = cwd + "/apk2java"
167+
outdir = options.outdir
168+
169+
if (options.smali + options.jasmin + options.nosc) > 1:
170+
print("[ ERROR ] You can only select 1 source format --[smali/jasmin/java/no-source]")
172171
exit(1)
173-
elif args[0] == 'b':
174-
if os.path.isdir(args[1]):
175-
apk_folder = args[1]
176-
project_name = os.path.basename(os.path.dirname(args[1]).lower())
177-
if options.jasmin == True:
178-
jasmin_build()
179-
elif options.smali == True:
180-
apktool_build()
172+
if len(args) == 2:
173+
if args[0] == 'd':
174+
if os.path.isfile(args[1]) and os.path.splitext(args[1])[-1].lower() == '.apk':
175+
apk_file = args[1]
176+
project_name = os.path.splitext(os.path.basename(args[1]))[0].lower()
177+
if not os.path.exists(outdir):
178+
os.makedirs(outdir)
179+
180+
call(["cp", apk_file, outdir + project_name + "-new.apk"])
181+
if options.jasmin == True:
182+
dex2jar()
183+
jar2jasmin()
184+
else:
185+
apktool(options.smali)
186+
if options.smali == False and options.nosc == False:
187+
dex2jar()
188+
procyon()
189+
call(["cp", tmp + project_name + "/", "./", "-R"])
190+
else:
191+
print("[ ERROR ] You must select a valid APK file!")
192+
exit(1)
193+
elif args[0] == 'b':
194+
if os.path.isdir(args[1]):
195+
apk_folder = args[1]
196+
project_name = os.path.basename(os.path.dirname(args[1]).lower())
197+
if options.jasmin == True:
198+
jasmin_build()
199+
elif options.smali == True:
200+
apktool_build()
201+
else:
202+
print("[ ERROR ] Can't build apk with that source format. Only Jasmin or Smali supported")
203+
sign()
204+
call(["cp", sign_file, "./", ])
181205
else:
182-
print ("[ ERROR ] Can't build apk with that source format. Only Jasmin or Smali supported")
183-
sign()
184-
call("cp "+sign_file+" ./",shell=True)
206+
parser.error("action can be only 'b' (build) or 'd' (decompile)")
185207
else:
186-
parser.error("action can be only 'b' (build) or 'd' (decompile)")
187-
else:
188-
parser.print_help()
208+
parser.print_help()
209+
189210

190211
# Script start Here
191-
if __name__=="__main__":
192-
main()
212+
if __name__ == "__main__":
213+
main()

0 commit comments

Comments
 (0)