import os
import re
import random
import sys
_classMap = {}
_fileClassMap = {}
_reservedClassSet = set()
_re_className = re.compile('L[a-zA-Z_0-9/\$]+;')
def getFilenameSuffix(filename):
i = filename.rfind('.')
if i > 0:
return filename[i:]
return ''
def convertClassName(cls, sourceName):
segs = cls[1:-1].split('/')
baseName = segs[-1]
if '$' in baseName:
baseName = sourceName + '$' + baseName.split('$', 1)[1]
else:
baseName = sourceName
segs[-1] = baseName
return 'L'+ '/'.join(segs) + ';'
def getFileNameFromClass(cls, suffix = '.smali'):
segs = cls[1:-1].split('/')
return segs[-1] + suffix
def readClassSourceName(smalifd):
smalifd.seek(0, os.SEEK_CUR)
cls, source = None, None
for line in smalifd:
if len(line.strip('\r\n')) == 0:
break
segs = line.split(' ')
if segs[0] == '.class':
cls = segs[-1].strip('\r\n')
elif segs[0] == '.source':
s = segs[-1].strip('\r\n"')
return cls, source
def findClassName(smalifile):
cls, source = None, None
for line in open(smalifile, 'r'):
if len(line.strip('\r\n')) == 0:
break
segs = line.split(' ')
if segs[0] == '.class':
cls = segs[-1].strip('\r\n')
elif segs[0] == '.source':
s = segs[-1].strip('\r\n"')
if s.endswith('.java'):
source = s[:-5]
if source is not None:
newCls = convertClassName(cls, source)
if newCls != cls:
_classMap[cls] = newCls
_fileClassMap[smalifile] = cls
_reservedClassSet.add(cls.lower())
def clsrepl(matchobj):
cls = matchobj.group(0)
if cls in _classMap:
return _classMap[cls]
return cls
def updateSmaliContent(smalifile):
content = open(smalifile, 'rb').read()
open(smalifile, 'wb').write(_re_className.sub(clsrepl, content))
def renameSmaliFile(smalifile):
if smalifile in _fileClassMap:
newCls = _classMap[_fileClassMap[smalifile]]
newPath = os.path.join(os.path.dirname(smalifile), getFileNameFromClass(newCls))
try:
os.rename(smalifile, newPath)
except Exception as e:
print smalifile, ' -> ', newPath
print e
raise e
def handleWalkError(err):
print 'Error When Access ', err.filename
print err
def processSmali(smali_root):
smali_root = os.path.abspath(smali_root)
for root, dirs, files in os.walk(smali_root, onerror=handleWalkError):
if not files:
continue
for f in files:
if f.endswith('.smali'):
findClassName(os.path.join(root, f))
for k in _classMap.keys():
newCls = _classMap[k]
if newCls.lower() in _reservedClassSet and '$' not in k:
newCls = newCls[:-1] + '$' + k[1:-1].split('/')[-1] + ';'
while newCls.lower() in _reservedClassSet:
newCls = newCls[:-1] + str(random.randint(0, 9)) + ';'
_classMap[k] = newCls
_reservedClassSet.add(newCls.lower())
for root, dirs, files in os.walk(smali_root, onerror=handleWalkError):
if not files:
continue
for f in files:
if f.endswith('.smali'):
fpath = os.path.join(root, f)
updateSmaliContent(fpath)
renameSmaliFile(fpath)
if __name__ == '__main__':
if len(sys.argv) == 1:
print 'Please provide root directory for smali'
sys.exit(2)
smali_root = sys.argv[1]
print 'Begine to process *.smali under ', smali_root
processSmali(smali_root)
print 'Done'