-
Notifications
You must be signed in to change notification settings - Fork 12
/
ClassNameDeobfuscator.py
93 lines (70 loc) · 3.28 KB
/
ClassNameDeobfuscator.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
import argparse
import os
__author__ = 'HamiltonianPath'
def parse_args():
parser = argparse.ArgumentParser(description='Execute in the smali directory of a disassembled APK')
parser.add_argument('namespace', type=str, help='base namespace to begin deobfuscating classes')
parser.add_argument('-o', dest='outfile', default=None, metavar='output.txt', type=str, help='output filename to save deobfusacted class mapping')
return parser.parse_args()
class SmaliFile:
"""A class to represent a Smali file."""
raw_lines = [] # A list of all lines in the Smali file.
def __init__(self, filepath=None):
if filepath:
self.readsmalifile(filepath)
def readsmalifile(self, filepath):
f = open(filepath, 'r')
self.raw_lines = f.readlines()
class ClassNameDeobfuscator():
def __init__(self, namespace, outfilepath):
self.namespace = namespace
self.outfilepath = outfilepath
self.outfile = None
if self.outfilepath:
self.outfile = open(self.outfilepath, 'w')
def out(self, message):
if self.outfile:
self.outfile.write(message + '\n')
else:
print(message)
def namespace_to_path(self, namespace):
return namespace.replace('.', os.path.sep)
def path_to_namespace(self, path):
return path.replace(os.path.sep, '.')
def ensure_namespace_dir_exists(self, namespace_dir):
return os.path.isdir(namespace_dir)
def parse_classname_from_source_line(self, source_line):
try:
return source_line.split(' ')[1].strip().strip('"')
except IndexError:
return 'ERROR_WHILE_DEOBFUSCATING_CLASS_NAME'
def deobfuscate_smali_file_class(self, namespace_path, filename):
filepath = os.path.join(namespace_path, filename)
smali_file = SmaliFile(filepath)
for line in smali_file.raw_lines:
if line.startswith('.source'):
return self.parse_classname_from_source_line(line)
def walk_namespace_dir(self, namespace_dir):
self.out(' [*] Deobfuscating class names from namespace {0}...'.format(self.path_to_namespace(namespace_dir)))
for dirpath, dirnames, filenames in os.walk(namespace_dir):
namespace = self.path_to_namespace(dirpath)
for file in filenames:
if file.endswith('smali'):
obfuscated_full_namesapce = '{0}.{1}'.format(namespace, file)
deobfuscated_name = self.deobfuscate_smali_file_class(dirpath, file)
deobfuscated_full_namepsace = '{0}.{1}'.format(namespace, deobfuscated_name)
self.out('{0} => {1}'.format(obfuscated_full_namesapce, deobfuscated_full_namepsace))
def execute(self):
namespace_dir = self.namespace_to_path(self.namespace)
if not self.ensure_namespace_dir_exists(namespace_dir):
self.out(' [E] Could not find directory {0} for given namespace {1}'.format(namespace_dir, self.namespace))
return
self.walk_namespace_dir(namespace_dir)
if self.outfile:
self.outfile.close()
def main():
args = parse_args()
deobfuscator = ClassNameDeobfuscator(args.namespace, args.outfile)
deobfuscator.execute()
if __name__ == '__main__':
main()