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

Commit

Permalink
Merge pull request #9 from orf/patch-1
Browse files Browse the repository at this point in the history
Big refactorings
  • Loading branch information
TheZ3ro committed May 25, 2017
2 parents 3c251e7 + 4b8457e commit 3f2e412
Showing 1 changed file with 177 additions and 156 deletions.
333 changes: 177 additions & 156 deletions apk2java.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,188 +5,209 @@
import sys, os, string
import urllib.request
import zipfile
from subprocess import call
import subprocess
from optparse import OptionParser

apk_file=''
apk_folder=''
project_name=''
sign_file=''
cwd=os.path.dirname(os.path.abspath(__file__))
home=os.path.dirname(os.path.realpath(sys.argv[0]))
outdir=os.path.dirname(os.path.realpath(sys.argv[1]))
external="https://github.com/TheZ3ro/apk2java-linux/releases/download/tool/tool.zip"

def call(cmd, **kwargs):
print('Running: {0}'.format(' '.join(cmd)))
return subprocess.call(cmd, **kwargs)


apk_file = ''
apk_folder = ''
project_name = ''
sign_file = ''
cwd = os.path.dirname(os.path.abspath(__file__))
home = os.path.dirname(os.path.realpath(sys.argv[0]))
outdir = os.path.dirname(os.path.realpath(sys.argv[1]))
external = "https://github.com/TheZ3ro/apk2java-linux/releases/download/tool/tool.zip"


def check_home(path):
return os.path.isdir(path+"/tool")
return os.path.isdir(path + "/tool")


def getunzipped(theurl, thedir, report):
if not os.path.exists(thedir):
os.mkdir(thedir)
print ("Downloading external tool... -> "+thedir+"/tool/")
name = os.path.join(thedir, 'temp.zip')
try:
name, hdrs = urllib.request.urlretrieve(theurl, name, report)
except IOError as e:
print ("Can't retrieve %r to %r: %s" % (theurl, thedir, e))
return
try:
z = zipfile.ZipFile(name)
except zipfile.error as e:
print ("Bad zipfile (from %r): %s" % (theurl, e))
return
for n in z.namelist():
(dirname, filename) = os.path.split(n)
perm = ((z.getinfo(n).external_attr >> 16) & 0x0777)
if filename == '':
# directory
newdir = thedir + '/' + dirname
if not os.path.exists(newdir):
os.mkdir(newdir)
else:
# file
fd = os.open(thedir+"/"+n, os.O_CREAT | os.O_WRONLY, perm)
os.write(fd, z.read(n))
os.close(fd)
z.close()
os.unlink(name)
print ("")
if not os.path.exists(thedir):
os.mkdir(thedir)
print("Downloading external tool... -> " + thedir + "/tool/")
name = os.path.join(thedir, 'temp.zip')
try:
name, hdrs = urllib.request.urlretrieve(theurl, name, report)
except IOError as e:
print("Can't retrieve %r to %r: %s" % (theurl, thedir, e))
return
try:
z = zipfile.ZipFile(name)
except zipfile.error as e:
print("Bad zipfile (from %r): %s" % (theurl, e))
return
for n in z.namelist():
(dirname, filename) = os.path.split(n)
perm = ((z.getinfo(n).external_attr >> 16) & 0x0777)
if filename == '':
# directory
newdir = thedir + '/' + dirname
if not os.path.exists(newdir):
os.mkdir(newdir)
else:
# file
fd = os.open(thedir + "/" + n, os.O_CREAT | os.O_WRONLY, perm)
os.write(fd, z.read(n))
os.close(fd)
z.close()
os.unlink(name)
print("")


def report(blocknr, blocksize, size):
current = blocknr*blocksize
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))
current = blocknr * blocksize
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))


def print_header(text):
block = "*********************************************"
print(block)
print('**' + text.center(len(block) - 4) + '**')
print(block)


def apktool(smali):
print ("*********************************************")
print ("** Extract, fix resource files **")
print ("*********************************************")
if apk_file != '':
if smali == True:
call(home+'/tool/apktool_200rc3.jar d '+apk_file+' -o '+outdir+project_name+' -f',shell=True)
else:
call(home+'/tool/apktool_200rc3.jar d '+apk_file+' -o '+outdir+project_name+' -sf',shell=True)
os.system('mv %s %s' % (outdir+project_name+'/classes.dex', outdir+project_name+'/original/'))
print ('Done')
print_header('Extract, fix resource files')
if apk_file != '':
cmd = [home + '/tool/apktool_200rc3.jar', 'd', apk_file, '-o', outdir + project_name, '-f']

if smali:
cmd[-1] = '-sf'

call(cmd)
call(['mv', outdir + project_name + '/classes.dex', outdir + project_name + '/original/'])
print('Done')


def dex2jar():
print ("*********************************************")
print ("** Convert 'apk' to 'jar' **")
print ("*********************************************")
if apk_file != '':
call(home+'/tool/dex2jar-0.0.9.15/d2j-dex2jar.sh -f -o '+outdir+project_name+'.jar '+apk_file, shell=True)
call(home+'/tool/dex2jar-0.0.9.15/d2j-asm-verify.sh '+outdir+project_name+'.jar',shell=True)
print ('Done')
print_header("Convert 'apk' to 'jar'")
if apk_file != '':
call([home + '/tool/dex2jar-0.0.9.15/d2j-dex2jar.sh', '-f', '-o', outdir + project_name + '.jar', apk_file])
call([home + '/tool/dex2jar-0.0.9.15/d2j-asm-verify.sh', outdir + project_name + '.jar'])
print('Done')


def procyon():
print ("*********************************************")
print ("** Decompiling class files **")
print ("*********************************************")
if apk_file != '':
call(home+'/tool/procyon-decompiler-0528.jar -jar '+outdir+project_name+'.jar -o '+outdir+project_name+'/src/',shell=True)
print ('Done')
print_header('Decompiling class files')
if apk_file != '':
call([home + '/tool/procyon-decompiler-0528.jar', '-jar', outdir + project_name + '.jar',
'-o', outdir + project_name + '/src/'])
print('Done')


def apktool_build():
print ("*********************************************")
print ("** Building apk from smali **")
print ("*********************************************")
if apk_folder != '':
call(home+'/tool/apktool_200rc3.jar b '+apk_folder+' -o '+outdir+project_name+'-rebuild.apk',shell=True)
global sign_file
sign_file = outdir+project_name+'-rebuild.apk'
print ('Done')
print_header('Building apk from smali')
if apk_folder != '':
call([home + '/tool/apktool_200rc3.jar', 'b', apk_folder, '-o', outdir + project_name + '-rebuild.apk'])
global sign_file
sign_file = outdir + project_name + '-rebuild.apk'
print('Done')


def jar2jasmin():
print ("*********************************************")
print ("** Convert 'jar' to 'jasmin' **")
print ("*********************************************")
if apk_file != '':
call(home+'/tool/dex2jar-0.0.9.15/d2j-jar2jasmin.sh -f -o '+outdir+project_name+'/jasmin '+outdir+project_name+'.jar',shell=True)
print ('Done')
print_header("Convert 'jar' to 'jasmin'")
if apk_file != '':
call([home + '/tool/dex2jar-0.0.9.15/d2j-jar2jasmin.sh', '-f', '-o', outdir + project_name + '/jasmin',
outdir + project_name + '.jar'])
print('Done')


def jasmin_build():
print ("*********************************************")
print ("** Build apk from jasmin **")
print ("*********************************************")
if apk_folder != '':
call(home+'/tool/dex2jar-0.0.9.15/d2j-jasmin2jar.sh -f -o '+outdir+project_name+'-new.jar '+outdir+project_name+'/jasmin',shell=True)
call(home+'/tool/dex2jar-0.0.9.15/d2j-asm-verify.sh '+outdir+project_name+'-new.jar',shell=True)
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)
call('zip -r '+outdir+project_name+'-new.apk -j '+outdir+project_name+'/classes.dex',shell=True)
global sign_file
sign_file = outdir+project_name+'-new.apk'
print ('Done')
print_header('Build apk from jasmin')
if apk_folder != '':
call([home + '/tool/dex2jar-0.0.9.15/d2j-jasmin2jar.sh', '-f', '-o', outdir + project_name + '-new.jar',
outdir + project_name + '/jasmin'])
call([home + '/tool/dex2jar-0.0.9.15/d2j-asm-verify.sh', outdir + project_name + '-new.jar'])
call([home + '/tool/dex2jar-0.0.9.15/d2j-jar2dex.sh', '-f', '-o', outdir + project_name + '/classes.dex',
outdir + project_name + '-new.jar'])
call(['zip', '-r ' + outdir + project_name + '-new.apk', '-j', outdir + project_name + '/classes.dex'])
global sign_file
sign_file = outdir + project_name + '-new.apk'
print('Done')


def sign():
print ("*********************************************")
print ("** Sign apk **")
print ("*********************************************")
call(home+'/tool/dex2jar-0.0.9.15/d2j-apk-sign.sh -f -o '+outdir+project_name+'-signed.apk '+sign_file,shell=True)
print ('Done')
print_header('Sign apk')
call([home + '/tool/dex2jar-0.0.9.15/d2j-apk-sign.sh', '-f', '-o', outdir + project_name + '-signed.apk',
sign_file])
print('Done')


def main():
global apk_folder,apk_file,project_name,home,outdir
usage = "usage: %prog action file [options]"
parser = OptionParser(usage=usage)
parser.add_option("--java",action="store_true", dest="java", default=True, help="select java source format [DEFAULT]")
parser.add_option("--smali",action="store_true", dest="smali", default=False, help="select smali source format")
parser.add_option("--jasmin",action="store_true", dest="jasmin", default=False, help="select jasmin source format")
parser.add_option("--no-source",action="store_true", dest="nosc", default=False, help="no source code generation")
parser.add_option("-o", dest="outdir", default=cwd+"/", help="specify the output directory "
+"(if not specified the decomipled version will be store in a folder in the script directory)")
(options, args) = parser.parse_args()

if home == cwd+"/apk2java":
if check_home(home) == False:
getunzipped(external, home, report)
else:
if check_home(home) == False:
if check_home(cwd+"/apk2java") == False:
getunzipped(external, cwd+"/apk2java", report)
home = cwd+"/apk2java"
else:
home = cwd+"/apk2java"
outdir = options.outdir

if (options.smali+options.jasmin+options.nosc) > 1:
print ("[ ERROR ] You can only select 1 source format --[smali/jasmin/java/no-source]")
exit(1)
if len(args)==2:
if args[0] == 'd':
if os.path.isfile(args[1]) and os.path.splitext(args[1])[-1].lower() == '.apk':
apk_file = args[1]
project_name = os.path.splitext(os.path.basename(args[1]))[0].lower()
if not os.path.exists(outdir):
os.makedirs(outdir)
call("cp "+apk_file+" "+outdir+project_name+"-new.apk",shell=True)
if options.jasmin == True:
dex2jar()
jar2jasmin()
else:
apktool(options.smali)
if options.smali == False and options.nosc == False:
dex2jar()
procyon()
call("cp "+tmp+project_name+"/ ./ -R",shell=True)
else:
print ("[ ERROR ] You must select a valid APK file!")
global apk_folder, apk_file, project_name, home, outdir
usage = "usage: %prog action file [options]"
parser = OptionParser(usage=usage)
parser.add_option("--java", action="store_true", dest="java", default=True,
help="select java source format [DEFAULT]")
parser.add_option("--smali", action="store_true", dest="smali", default=False, help="select smali source format")
parser.add_option("--jasmin", action="store_true", dest="jasmin", default=False, help="select jasmin source format")
parser.add_option("--no-source", action="store_true", dest="nosc", default=False, help="no source code generation")
parser.add_option("-o", dest="outdir", default=cwd + "/", help="specify the output directory "
+ "(if not specified the decomipled version will be store in a folder in the script directory)")
(options, args) = parser.parse_args()

if home == cwd + "/apk2java":
if check_home(home) == False:
getunzipped(external, home, report)
else:
if check_home(home) == False:
if check_home(cwd + "/apk2java") == False:
getunzipped(external, cwd + "/apk2java", report)
home = cwd + "/apk2java"
else:
home = cwd + "/apk2java"
outdir = options.outdir

if (options.smali + options.jasmin + options.nosc) > 1:
print("[ ERROR ] You can only select 1 source format --[smali/jasmin/java/no-source]")
exit(1)
elif args[0] == 'b':
if os.path.isdir(args[1]):
apk_folder = args[1]
project_name = os.path.basename(os.path.dirname(args[1]).lower())
if options.jasmin == True:
jasmin_build()
elif options.smali == True:
apktool_build()
if len(args) == 2:
if args[0] == 'd':
if os.path.isfile(args[1]) and os.path.splitext(args[1])[-1].lower() == '.apk':
apk_file = args[1]
project_name = os.path.splitext(os.path.basename(args[1]))[0].lower()
if not os.path.exists(outdir):
os.makedirs(outdir)

call(["cp", apk_file, outdir + project_name + "-new.apk"])
if options.jasmin == True:
dex2jar()
jar2jasmin()
else:
apktool(options.smali)
if options.smali == False and options.nosc == False:
dex2jar()
procyon()
call(["cp", tmp + project_name + "/", "./", "-R"])
else:
print("[ ERROR ] You must select a valid APK file!")
exit(1)
elif args[0] == 'b':
if os.path.isdir(args[1]):
apk_folder = args[1]
project_name = os.path.basename(os.path.dirname(args[1]).lower())
if options.jasmin == True:
jasmin_build()
elif options.smali == True:
apktool_build()
else:
print("[ ERROR ] Can't build apk with that source format. Only Jasmin or Smali supported")
sign()
call(["cp", sign_file, "./", ])
else:
print ("[ ERROR ] Can't build apk with that source format. Only Jasmin or Smali supported")
sign()
call("cp "+sign_file+" ./",shell=True)
parser.error("action can be only 'b' (build) or 'd' (decompile)")
else:
parser.error("action can be only 'b' (build) or 'd' (decompile)")
else:
parser.print_help()
parser.print_help()


# Script start Here
if __name__=="__main__":
main()
if __name__ == "__main__":
main()

0 comments on commit 3f2e412

Please sign in to comment.