2323 remove_dup_list ,
2424)
2525
26- R2Cache = namedtuple ("r2_cache" , "address dexindex is_imported" )
26+ R2Cache = namedtuple ("r2_cache" , "address is_imported" )
2727
2828PRIMITIVE_TYPE_MAPPING = {
2929 "void" : "V" ,
3737 "double" : "D" ,
3838}
3939
40- # R2_ESCAPE_CHAR_LIST = ["<", ">", "$"]
4140R2_ESCAPE_CHAR_LIST = ["$" ]
4241
4342
@@ -78,15 +77,19 @@ def __init__(
7877 self ._number_of_dex = len (self ._dex_list )
7978
8079 @functools .lru_cache
81- def _get_r2 (self , index ):
80+ def _get_r2 (self ):
8281 """
8382 Return a R2 object that opens the specified Dex file.
8483
8584 :param index: an index indicating which Dex file should the returned
8685 object open
8786 :return: a R2 object opening the specified Dex file
8887 """
89- r2 = r2pipe .open (self ._dex_list [index ])
88+ if self .ret_type == "DEX" :
89+ r2 = r2pipe .open (self ._dex_list [0 ])
90+ elif self .ret_type == "APK" :
91+ r2 = r2pipe .open (f"apk://{ self .apk_filepath } " )
92+
9093 r2 .cmd ("aa" )
9194 return r2
9295
@@ -125,7 +128,6 @@ def _convert_type_to_type_signature(self, raw_type: str):
125128 raw_type = raw_type .replace ("_" , "$" )
126129 return "L" + raw_type + ";"
127130
128- # return "Ljava/lang/" + raw_type + ";"
129131 return raw_type + ";"
130132
131133 @staticmethod
@@ -142,7 +144,7 @@ def _escape_str_in_r2_manner(raw_str: str):
142144 raw_str = raw_str .replace (c , "_" )
143145 return raw_str
144146
145- def _parse_method_from_isj_obj (self , json_obj , dexindex ):
147+ def _parse_method_from_isj_obj (self , json_obj ):
146148 """
147149 Parse a JSON object provided by the R2 command `isj` or `is.j` into
148150 an instance of MethodObject.
@@ -188,13 +190,13 @@ def _parse_method_from_isj_obj(self, json_obj, dexindex):
188190 class_name = class_name ,
189191 name = method_name ,
190192 descriptor = descriptor ,
191- cache = R2Cache (json_obj ["vaddr" ], dexindex , is_imported ),
193+ cache = R2Cache (json_obj ["vaddr" ], is_imported ),
192194 )
193195
194196 return method
195197
196198 @functools .lru_cache
197- def _get_methods_classified (self , dexindex ):
199+ def _get_methods_classified (self ):
198200 """
199201 Parse all methods in the specified Dex and convert them into a
200202 dictionary. The dictionary takes their belonging classes as the keys.
@@ -205,12 +207,12 @@ def _get_methods_classified(self, dexindex):
205207 :return: a dictionary taking a class name as the key and a list of
206208 MethodObject as the corresponding value.
207209 """
208- r2 = self ._get_r2 (dexindex )
210+ r2 = self ._get_r2 ()
209211
210212 method_json_list = r2 .cmdj ("isj" )
211213 method_dict = defaultdict (list )
212214 for json_obj in method_json_list :
213- method = self ._parse_method_from_isj_obj (json_obj , dexindex )
215+ method = self ._parse_method_from_isj_obj (json_obj )
214216
215217 if method :
216218 method_dict [method .class_name ].append (method )
@@ -306,7 +308,7 @@ def all_methods(self) -> Set[MethodObject]:
306308 """
307309 method_set = set ()
308310 for dex_index in range (self ._number_of_dex ):
309- for method_list in self ._get_methods_classified (dex_index ).values ():
311+ for method_list in self ._get_methods_classified ().values ():
310312 method_set .update (method_list )
311313
312314 return method_set
@@ -354,13 +356,13 @@ def method_filter(method):
354356
355357 if class_name != ".*" :
356358 for dex_index in dex_list :
357- method_dict = self ._get_methods_classified (dex_index )
359+ method_dict = self ._get_methods_classified ()
358360 filtered_methods += list (
359361 filter (method_filter , method_dict [class_name ])
360362 )
361363 else :
362364 for dex_index in dex_list :
363- method_dict = self ._get_methods_classified (dex_index )
365+ method_dict = self ._get_methods_classified ()
364366 for key_name in method_dict :
365367 filtered_methods += list (
366368 filter (method_filter , method_dict [key_name ])
@@ -380,10 +382,9 @@ def upperfunc(self, method_object: MethodObject) -> Set[MethodObject]:
380382 """
381383 cache = method_object .cache
382384
383- r2 = self ._get_r2 (cache .dexindex )
384-
385- xrefs = r2 .cmdj (f"axtj @ { cache .address } " )
385+ r2 = self ._get_r2 ()
386386
387+ xrefs = r2 .cmdj (f"axlj @ { cache .address } " )
387388 upperfunc_set = set ()
388389 for xref in xrefs :
389390 if xref ["type" ] != "CALL" :
@@ -421,8 +422,7 @@ def lowerfunc(
421422 """
422423 cache = method_object .cache
423424
424- r2 = self ._get_r2 (cache .dexindex )
425-
425+ r2 = self ._get_r2 ()
426426 instruct_flow = r2 .cmdj (f"pdfj @ { cache .address } " )["ops" ]
427427
428428 lowerfunc_list = []
@@ -462,7 +462,7 @@ def get_method_bytecode(
462462 cache = method_object .cache
463463 if not cache .is_imported :
464464
465- r2 = self ._get_r2 (cache . dexindex )
465+ r2 = self ._get_r2 ()
466466
467467 instruct_flow = r2 .cmdj (f"pdfj @ { cache .address } " )["ops" ]
468468 if instruct_flow :
@@ -480,13 +480,12 @@ def get_strings(self) -> Set[str]:
480480 :return: a set of strings
481481 """
482482 strings = set ()
483- for dex_index in range (self ._number_of_dex ):
484- r2 = self ._get_r2 (dex_index )
483+ r2 = self ._get_r2 ()
485484
486- string_detail_list = r2 .cmdj ("izzj" )
487- strings .update (
488- [string_detail ["string" ] for string_detail in string_detail_list ]
489- )
485+ string_detail_list = r2 .cmdj ("izzj" )
486+ strings .update (
487+ [string_detail ["string" ] for string_detail in string_detail_list ]
488+ )
490489
491490 return strings
492491
@@ -536,7 +535,7 @@ def convert_bytecode_to_list(bytecode):
536535 if cache .is_imported :
537536 return {}
538537
539- r2 = self ._get_r2 (cache . dexindex )
538+ r2 = self ._get_r2 ()
540539
541540 instruction_flow = r2 .cmdj (f"pdfj @ { cache .address } " )["ops" ]
542541
@@ -587,18 +586,16 @@ def superclass_relationships(self) -> Dict[str, Set[str]]:
587586 """
588587 hierarchy_dict = defaultdict (set )
589588
590- for dex_index in range (self ._number_of_dex ):
591-
592- r2 = self ._get_r2 (dex_index )
589+ r2 = self ._get_r2 ()
593590
594- class_info_list = r2 .cmdj ("icj" )
595- for class_info in class_info_list :
596- class_name = class_info ["classname" ]
597- class_name = self ._convert_type_to_type_signature (class_name )
598- super_classes = class_info ["super" ]
591+ class_info_list = r2 .cmdj ("icj" )
592+ for class_info in class_info_list :
593+ class_name = class_info ["classname" ]
594+ class_name = self ._convert_type_to_type_signature (class_name )
595+ super_classes = class_info ["super" ]
599596
600- for super_class in super_classes :
601- hierarchy_dict [class_name ].add (super_class )
597+ for super_class in super_classes :
598+ hierarchy_dict [class_name ].add (super_class )
602599
603600 return hierarchy_dict
604601
@@ -616,16 +613,14 @@ def subclass_relationships(self) -> Dict[str, Set[str]]:
616613 """
617614 hierarchy_dict = defaultdict (set )
618615
619- for dex_index in range ( self ._number_of_dex ):
616+ r2 = self ._get_r2 ()
620617
621- r2 = self ._get_r2 (dex_index )
618+ class_info_list = r2 .cmdj ("icj" )
619+ for class_info in class_info_list :
620+ class_name = class_info ["classname" ]
621+ super_class = class_info ["super" ]
622622
623- class_info_list = r2 .cmdj ("icj" )
624- for class_info in class_info_list :
625- class_name = class_info ["classname" ]
626- super_class = class_info ["super" ]
627-
628- hierarchy_dict [super_class ].add (class_name )
623+ hierarchy_dict [super_class ].add (class_name )
629624
630625 return hierarchy_dict
631626
@@ -636,14 +631,12 @@ def _get_method_by_address(self, address: int) -> MethodObject:
636631 :param address: an address used to find the corresponding method
637632 :return: the MethodObject of the method in the given address
638633 """
639- dexindex = 0
640-
641- r2 = self ._get_r2 (dexindex )
634+ r2 = self ._get_r2 ()
642635 json_data = r2 .cmdj (f"is.j @ { address } " )
643636 json_data = json_data .get ("symbols" )
644637
645638 if json_data :
646- return self ._parse_method_from_isj_obj (json_data , dexindex )
639+ return self ._parse_method_from_isj_obj (json_data )
647640 else :
648641 return None
649642
@@ -654,9 +647,7 @@ def _get_string_by_address(self, address: str) -> str:
654647 :param address: an address used to find the corresponding method
655648 :return: the content in the given address
656649 """
657- dexindex = 0
658-
659- r2 = self ._get_r2 (dexindex )
650+ r2 = self ._get_r2 ()
660651 content = r2 .cmd (f"pr @ { int (address , 16 )} " )
661652 return content
662653
0 commit comments