Skip to content

Commit 4236fd5

Browse files
author
amimo
committed
Android VM may find the user-define native method using short jni name,
so don't compile function if there is a same named native method in the class
1 parent 25377dc commit 4236fd5

File tree

3 files changed

+67
-39
lines changed

3 files changed

+67
-39
lines changed

dcc.py

+53-16
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from androguard.core.bytecodes import apk, dvm
1616
from androguard.util import read
1717
from dex2c.compiler import Dex2C
18-
from dex2c.util import JniLongName
18+
from dex2c.util import JniLongName, get_method_triple, get_access_method
1919

2020
APKTOOL = 'tools/apktool.jar'
2121
SIGNJAR = 'tools/signapk.jar'
@@ -88,11 +88,19 @@ def auto_vm(filename):
8888

8989

9090
class MethodFilter(object):
91-
def __init__(self, configure):
91+
def __init__(self, configure, vm):
9292
self._compile_filters = []
9393
self._keep_filters = []
9494
self._compile_full_match = set()
9595

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):
96104
if not os.path.exists(configure):
97105
return
98106

@@ -111,16 +119,47 @@ def __init__(self, configure):
111119
else:
112120
self._compile_filters.append(re.compile(line))
113121

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:
116155
return True
117156

118157
for rule in self._keep_filters:
119-
if rule.search(func):
158+
if rule.search(full_name):
120159
return False
121160

122161
for rule in self._compile_filters:
123-
if rule.search(func):
162+
if rule.search(full_name):
124163
return True
125164

126165
return False
@@ -222,31 +261,30 @@ def archive_compiled_code(project_dir):
222261
return outfile
223262

224263

225-
def compile_dex(apkfile, filter_func):
264+
def compile_dex(apkfile, filtercfg):
226265
show_logging(level=logging.INFO)
227266

228267
d = auto_vm(apkfile)
229268
dx = analysis.Analysis(d)
230269

270+
method_filter = MethodFilter(filtercfg, d)
271+
231272
compiler = Dex2C(d, dx)
232273

233274
compiled_method_code = {}
234275
errors = []
235276

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)
240279

241-
method_triple = cls_name, name, proto
242280
jni_longname = JniLongName(*method_triple)
243281
full_name = ''.join(method_triple)
244282

245283
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))
247285
continue
248286

249-
if filter_func(full_name):
287+
if method_filter.should_compile(m):
250288
logger.debug("compiling %s" % (full_name))
251289
try:
252290
code = compiler.get_source_method(m)
@@ -270,8 +308,7 @@ def dcc(apkfile, filtercfg, outapk, do_compile=True, project_dir=None, source_ar
270308
logger.error("file %s is not exists", apkfile)
271309
return
272310

273-
method_filter = MethodFilter(filtercfg)
274-
compiled_methods, errors = compile_dex(apkfile, method_filter.should_compile)
311+
compiled_methods, errors = compile_dex(apkfile, filtercfg)
275312

276313
if errors:
277314
logger.warning('================================')

dex2c/compiler.py

+2-23
Original file line numberDiff line numberDiff line change
@@ -550,36 +550,15 @@ class Dex2C:
550550
def __init__(self, vm, vmx):
551551
self.vm = vm
552552
self.vmx = vmx
553-
self.conflict_methods = set()
554-
555-
# don't compile functions that have same parameter but differ return type
556-
candidate_methods = {}
557-
for m in vm.get_methods():
558-
cls_name = m.class_name
559-
method_triple = m.get_triple()
560-
_, name, proto = method_triple
561-
562-
# strip return type
563-
index = proto.find(')')
564-
proto = proto[:index + 1]
565-
method_triple = cls_name, name, proto
566-
567-
if method_triple in candidate_methods:
568-
self.conflict_methods.add(m)
569-
self.conflict_methods.add(candidate_methods[method_triple])
570-
else:
571-
candidate_methods[method_triple] = m
572553

573554
def get_source_method(self, m):
574-
if m in self.conflict_methods:
575-
return None
576-
577555
mx = self.vmx.get_method(m)
578556
z = IrBuilder(mx)
579557
irmethod = z.process()
580558
if irmethod:
581559
return irmethod.get_source()
582-
560+
else:
561+
return None
583562

584563
def get_source_class(self, _class):
585564
c = DvClass(_class, self.vmx)

dex2c/util.py

+12
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,18 @@ def get_params_type(descriptor):
238238
return []
239239

240240

241+
def get_method_triple(method, return_type=True):
242+
method_triple = method.get_triple()
243+
cls_name = method.class_name
244+
_, name, proto = method_triple
245+
if return_type:
246+
return cls_name, name, proto
247+
else:
248+
index = proto.find(')')
249+
proto = proto[:index + 1]
250+
return cls_name, name, proto
251+
252+
241253
def create_png(cls_name, meth_name, graph, dir_name='graphs2'):
242254
m_name = ''.join(x for x in meth_name if x.isalnum())
243255
m_name = m_name.replace('<', '_').replace('>', '_')

0 commit comments

Comments
 (0)