15
15
from androguard .core .bytecodes import apk , dvm
16
16
from androguard .util import read
17
17
from dex2c .compiler import Dex2C
18
- from dex2c .util import JniLongName
18
+ from dex2c .util import JniLongName , get_method_triple , get_access_method
19
19
20
20
APKTOOL = 'tools/apktool.jar'
21
21
SIGNJAR = 'tools/signapk.jar'
@@ -88,11 +88,19 @@ def auto_vm(filename):
88
88
89
89
90
90
class MethodFilter (object ):
91
- def __init__ (self , configure ):
91
+ def __init__ (self , configure , vm ):
92
92
self ._compile_filters = []
93
93
self ._keep_filters = []
94
94
self ._compile_full_match = set ()
95
95
96
+ self .conflict_methods = set ()
97
+ self .native_methods = set ()
98
+
99
+ self ._load_filter_configure (configure )
100
+ self ._init_conflict_methods (vm )
101
+ self ._init_native_methods (vm )
102
+
103
+ def _load_filter_configure (self , configure ):
96
104
if not os .path .exists (configure ):
97
105
return
98
106
@@ -111,16 +119,47 @@ def __init__(self, configure):
111
119
else :
112
120
self ._compile_filters .append (re .compile (line ))
113
121
114
- def should_compile (self , func ):
115
- if func in self ._compile_full_match :
122
+ def _init_conflict_methods (self , vm ):
123
+ all_methods = {}
124
+ for m in vm .get_methods ():
125
+ method_triple = get_method_triple (m , return_type = False )
126
+ if method_triple in all_methods :
127
+ self .conflict_methods .add (m )
128
+ self .conflict_methods .add (all_methods [method_triple ])
129
+ else :
130
+ all_methods [method_triple ] = m
131
+
132
+ def _init_native_methods (self , vm ):
133
+ for m in vm .get_methods ():
134
+ cls_name , name , _ = get_method_triple (m )
135
+
136
+ access = get_access_method (m .get_access_flags ())
137
+ if 'native' in access :
138
+ self .native_methods .add ((cls_name , name ))
139
+
140
+ def should_compile (self , method ):
141
+ # don't compile functions that have same parameter but differ return type
142
+ if method in self .conflict_methods :
143
+ return False
144
+
145
+ method_triple = get_method_triple (method )
146
+ cls_name , name , _ = method_triple
147
+
148
+ # Android VM may find the wrong method using short jni name
149
+ # don't compile function if there is a same named native method
150
+ if (cls_name , name ) in self .native_methods :
151
+ return False
152
+
153
+ full_name = '' .join (method_triple )
154
+ if full_name in self ._compile_full_match :
116
155
return True
117
156
118
157
for rule in self ._keep_filters :
119
- if rule .search (func ):
158
+ if rule .search (full_name ):
120
159
return False
121
160
122
161
for rule in self ._compile_filters :
123
- if rule .search (func ):
162
+ if rule .search (full_name ):
124
163
return True
125
164
126
165
return False
@@ -222,31 +261,30 @@ def archive_compiled_code(project_dir):
222
261
return outfile
223
262
224
263
225
- def compile_dex (apkfile , filter_func ):
264
+ def compile_dex (apkfile , filtercfg ):
226
265
show_logging (level = logging .INFO )
227
266
228
267
d = auto_vm (apkfile )
229
268
dx = analysis .Analysis (d )
230
269
270
+ method_filter = MethodFilter (filtercfg , d )
271
+
231
272
compiler = Dex2C (d , dx )
232
273
233
274
compiled_method_code = {}
234
275
errors = []
235
276
236
- for m in d .get_methods ()[:]:
237
- cls_name = m .class_name
238
- method_triple = m .get_triple ()
239
- _ , name , proto = method_triple
277
+ for m in d .get_methods ():
278
+ method_triple = get_method_triple (m )
240
279
241
- method_triple = cls_name , name , proto
242
280
jni_longname = JniLongName (* method_triple )
243
281
full_name = '' .join (method_triple )
244
282
245
283
if len (jni_longname ) > 220 :
246
- logger .warning ("name to long %s(> 220) %s" % (jni_longname , full_name ))
284
+ logger .debug ("name to long %s(> 220) %s" % (jni_longname , full_name ))
247
285
continue
248
286
249
- if filter_func ( full_name ):
287
+ if method_filter . should_compile ( m ):
250
288
logger .debug ("compiling %s" % (full_name ))
251
289
try :
252
290
code = compiler .get_source_method (m )
@@ -270,8 +308,7 @@ def dcc(apkfile, filtercfg, outapk, do_compile=True, project_dir=None, source_ar
270
308
logger .error ("file %s is not exists" , apkfile )
271
309
return
272
310
273
- method_filter = MethodFilter (filtercfg )
274
- compiled_methods , errors = compile_dex (apkfile , method_filter .should_compile )
311
+ compiled_methods , errors = compile_dex (apkfile , filtercfg )
275
312
276
313
if errors :
277
314
logger .warning ('================================' )
0 commit comments