1
+ import argparse
2
+ import os
3
+ from SmaliFile import SmaliFile
4
+
5
+ __author__ = 'HamiltonianPath'
6
+
7
+
8
+ def parse_args ():
9
+ parser = argparse .ArgumentParser (description = 'Execute in the smali directory of a disassembled APK' )
10
+ parser .add_argument ('namespace' , type = str , help = 'base namespace to begin deobfuscating classes' )
11
+ parser .add_argument ('-o' , dest = 'outfile' , default = None , metavar = 'output.txt' , type = str , help = 'output filename to save deobfusacted class mapping' )
12
+ return parser .parse_args ()
13
+
14
+
15
+ class ClassNameDeobfuscator ():
16
+ def __init__ (self , namespace , outfilepath ):
17
+ self .namespace = namespace
18
+ self .outfilepath = outfilepath
19
+ self .outfile = None
20
+ if self .outfilepath :
21
+ self .outfile = open (self .outfilepath , 'w' )
22
+
23
+ def out (self , message ):
24
+ if self .outfile :
25
+ self .outfile .write (message + '\n ' )
26
+ else :
27
+ print (message )
28
+
29
+ def namespace_to_path (self , namespace ):
30
+ return namespace .replace ('.' , os .path .sep )
31
+
32
+ def path_to_namespace (self , path ):
33
+ return path .replace (os .path .sep , '.' )
34
+
35
+ def ensure_namespace_dir_exists (self , namespace_dir ):
36
+ return os .path .isdir (namespace_dir )
37
+
38
+ def parse_classname_from_source_line (self , source_line ):
39
+ try :
40
+ return source_line .split (' ' )[1 ].strip ().strip ('"' )
41
+ except IndexError :
42
+ return 'ERROR_WHILE_DEOBFUSCATING_CLASS_NAME'
43
+
44
+ def deobfuscate_smali_file_class (self , namespace_path , filename ):
45
+ filepath = os .path .join (namespace_path , filename )
46
+ smali_file = SmaliFile (filepath )
47
+ for line in smali_file .raw_lines :
48
+ if line .startswith ('.source' ):
49
+ return self .parse_classname_from_source_line (line )
50
+
51
+ def walk_namespace_dir (self , namespace_dir ):
52
+ self .out (' [*] Deobfuscating class names from namespace {0}...' .format (self .path_to_namespace (namespace_dir )))
53
+ for dirpath , dirnames , filenames in os .walk (namespace_dir ):
54
+ namespace = self .path_to_namespace (dirpath )
55
+ for file in filenames :
56
+ if file .endswith ('smali' ):
57
+ obfuscated_full_namesapce = '{0}.{1}' .format (namespace , file )
58
+ deobfuscated_name = self .deobfuscate_smali_file_class (dirpath , file )
59
+ deobfuscated_full_namepsace = '{0}.{1}' .format (namespace , deobfuscated_name )
60
+ self .out ('{0} => {1}' .format (obfuscated_full_namesapce , deobfuscated_full_namepsace ))
61
+
62
+ def execute (self ):
63
+ namespace_dir = self .namespace_to_path (self .namespace )
64
+ if not self .ensure_namespace_dir_exists (namespace_dir ):
65
+ self .out (' [E] Could not find directory {0} for given namespace {1}' .format (namespace_dir , self .namespace ))
66
+ return
67
+
68
+ self .walk_namespace_dir (namespace_dir )
69
+
70
+ if self .outfile :
71
+ self .outfile .close ()
72
+
73
+
74
+ def main ():
75
+ args = parse_args ()
76
+ deobfuscator = ClassNameDeobfuscator (args .namespace , args .outfile )
77
+ deobfuscator .execute ()
78
+
79
+ if __name__ == '__main__' :
80
+ main ()
0 commit comments