1+ #!/usr/bin/env python2
2+ # -*- coding: utf-8 -*-
3+ #
4+
5+ import sys , os , string
6+ import urllib
7+ import zipfile
8+ from subprocess import call
9+ from optparse import OptionParser
10+
11+ apk_file = ''
12+ apk_folder = ''
13+ project_name = ''
14+ sign_file = ''
15+ home = os .path .dirname (os .path .realpath (sys .argv [0 ]))
16+ tmp = '/tmp/apk2java/'
17+ external = "https://github.com/TheZ3ro/apk2java-linux/archive/master.zip"
18+
19+ def check_home (path ):
20+ return os .path .isdir (path + "/tool" )
21+
22+ def getunzipped (theurl , thedir , report ):
23+ print "Downloading external tool..."
24+ name = os .path .join (thedir , 'temp.zip' )
25+ try :
26+ name , hdrs = urllib .urlretrieve (theurl , name , report )
27+ except IOError , e :
28+ print "Can't retrieve %r to %r: %s" % (theurl , thedir , e )
29+ return
30+ try :
31+ z = zipfile .ZipFile (name )
32+ except zipfile .error , e :
33+ print "Bad zipfile (from %r): %s" % (theurl , e )
34+ return
35+ for n in z .namelist ():
36+ (dirname , filename ) = os .path .split (n )
37+ if filename == '' :
38+ # directory
39+ newdir = thedir + '/' + dirname
40+ if not os .path .exists (newdir ):
41+ os .mkdir (newdir )
42+ else :
43+ # file
44+ fd = open (thedir + "/" + n , 'w' )
45+ fd .write (z .read (n ))
46+ fd .close ()
47+ z .close ()
48+ os .unlink (name )
49+
50+ def report (blocknr , blocksize , size ):
51+ current = blocknr * blocksize
52+ sys .stdout .write ("\r Progress: {0:.2f}%" .format (100.0 * current / size ))
53+
54+ def apktool (smali ):
55+ print "*********************************************"
56+ print "** Extract, fix resource files **"
57+ print "*********************************************"
58+ if apk_file != '' :
59+ if smali == True :
60+ call (home + '/tool/apktool_200rc3.jar d ' + apk_file + ' -o ' + tmp + project_name + ' -f' ,shell = True )
61+ else :
62+ call (home + '/tool/apktool_200rc3.jar d ' + apk_file + ' -o ' + tmp + project_name + ' -sf' ,shell = True )
63+ os .system ('mv %s %s' % (tmp + project_name + '/classes.dex' , tmp + project_name + '/original/' ))
64+ print 'Done'
65+
66+ def dex2jar ():
67+ print "*********************************************"
68+ print "** Convert 'apk' to 'jar' **"
69+ print "*********************************************"
70+ if apk_file != '' :
71+ call (home + '/tool/dex2jar-0.0.9.15/d2j-dex2jar.sh -f -o ' + tmp + project_name + '.jar ' + apk_file , shell = True )
72+ call (home + '/tool/dex2jar-0.0.9.15/d2j-asm-verify.sh ' + tmp + project_name + '.jar' ,shell = True )
73+ print 'Done'
74+
75+ def procyon ():
76+ print "*********************************************"
77+ print "** Decompiling class files **"
78+ print "*********************************************"
79+ if apk_file != '' :
80+ call (home + '/tool/procyon-decompiler-0528.jar -jar ' + tmp + project_name + '.jar -o ' + tmp + project_name + '/src/' ,shell = True )
81+ print 'Done'
82+
83+ def apktool_build ():
84+ print "*********************************************"
85+ print "** Building apk from smali **"
86+ print "*********************************************"
87+ if apk_folder != '' :
88+ call (home + '/tool/apktool_200rc3.jar b ' + apk_folder + ' -o ' + tmp + project_name + '-rebuild.apk' ,shell = True )
89+ global sign_file
90+ sign_file = tmp + project_name + '-rebuild.apk'
91+ print 'Done'
92+
93+ def jar2jasmin ():
94+ print "*********************************************"
95+ print "** Convert 'jar' to 'jasmin' **"
96+ print "*********************************************"
97+ if apk_file != '' :
98+ call (home + '/tool/dex2jar-0.0.9.15/d2j-jar2jasmin.sh -f -o ' + tmp + project_name + '/jasmin ' + tmp + project_name + '.jar' ,shell = True )
99+ print 'Done'
100+
101+ def jasmin_build ():
102+ print "*********************************************"
103+ print "** Build apk from jasmin **"
104+ print "*********************************************"
105+ if apk_folder != '' :
106+ call (home + '/tool/dex2jar-0.0.9.15/d2j-jasmin2jar.sh -f -o ' + tmp + project_name + '-new.jar ' + tmp + project_name + '/jasmin' ,shell = True )
107+ call (home + '/tool/dex2jar-0.0.9.15/d2j-asm-verify.sh ' + tmp + project_name + '-new.jar' ,shell = True )
108+ call (home + '/tool/dex2jar-0.0.9.15/d2j-jar2dex.sh -f -o ' + tmp + project_name + '/classes.dex ' + tmp + project_name + '-new.jar' ,shell = True )
109+ call ('zip -r ' + tmp + project_name + '-new.apk -j ' + tmp + project_name + '/classes.dex' ,shell = True )
110+ global sign_file
111+ sign_file = tmp + project_name + '-new.apk'
112+ print 'Done'
113+
114+ def sign ():
115+ print "*********************************************"
116+ print "** Sign apk **"
117+ print "*********************************************"
118+ call (home + '/tool/dex2jar-0.0.9.15/d2j-apk-sign.sh -f -o ' + tmp + project_name + '-signed.apk ' + sign_file ,shell = True )
119+
120+ def main ():
121+ global apk_folder ,apk_file ,project_name ,home
122+ usage = "usage: %prog action file [options]"
123+ parser = OptionParser (usage = usage )
124+ parser .add_option ("--java" ,action = "store_true" , dest = "java" , default = True , help = "select java source format [DEFAULT]" )
125+ parser .add_option ("--smali" ,action = "store_true" , dest = "smali" , default = False , help = "select smali source format" )
126+ parser .add_option ("--jasmin" ,action = "store_true" , dest = "jasmin" , default = False , help = "select jasmin source format" )
127+ parser .add_option ("--no-source" ,action = "store_true" , dest = "nosc" , default = False , help = "no source code generation" )
128+ (options , args ) = parser .parse_args ()
129+
130+ if home == "/opt/apk2java" :
131+ if check_home (home ) == False :
132+ getunzipped (external , home , report )
133+ else :
134+ if check_home (home ) == False and check_home ("/opt/apk2java" ) == False :
135+ getunzipped (external , "/opt/apk2java" , report )
136+ home = "/opt/apk2java"
137+
138+ exit (0 )
139+
140+ if (options .smali + options .jasmin + options .nosc ) > 1 :
141+ print "[ ERROR ] You can only select 1 source format --[smali/jasmin/java/no-source]"
142+ exit (1 )
143+ if len (args )== 2 :
144+ if args [0 ] == 'd' :
145+ if os .path .isfile (args [1 ]) and os .path .splitext (args [1 ])[- 1 ].lower () == '.apk' :
146+ apk_file = args [1 ]
147+ project_name = os .path .splitext (os .path .basename (args [1 ]))[0 ].lower ()
148+ call ("cp " + apk_file + " " + tmp + project_name + "-new.apk" ,shell = True )
149+ if options .jasmin == True :
150+ dex2jar ()
151+ jar2jasmin ()
152+ else :
153+ apktool (options .smali )
154+ if options .smali == False and options .nosc == False :
155+ dex2jar ()
156+ procyon ()
157+ else :
158+ print "[ ERROR ] You must select a valid APK file!"
159+ exit (1 )
160+ elif args [0 ] == 'b' :
161+ if os .path .isdir (args [1 ]):
162+ apk_folder = args [1 ]
163+ project_name = os .path .basename (os .path .dirname (args [1 ]).lower ())
164+ print project_name
165+ if options .jasmin == True :
166+ jasmin_build ()
167+ elif options .smali == True :
168+ apktool_build ()
169+ else :
170+ print "[ ERROR ] Can't build apk with that source format. Only Jasmin or Smali supported"
171+ sign ()
172+ else :
173+ parser .error ("action can be only 'b' (build) or 'd' (decompile)" )
174+ else :
175+ parser .print_help ()
176+
177+ # Script start Here
178+ if __name__ == "__main__" :
179+ main ()
180+
0 commit comments