Skip to content

Commit f0938f0

Browse files
haeter525sidra-asa
authored andcommitted
Update docstrings for rzapkinfo.py
1 parent 189fd7b commit f0938f0

File tree

1 file changed

+171
-3
lines changed

1 file changed

+171
-3
lines changed

quark/core/rzapkinfo.py

Lines changed: 171 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import zipfile
1111
from collections import defaultdict, namedtuple
1212
from os import PathLike
13-
from typing import Any, Dict, Generator, List, Optional, Set, Union
13+
from typing import Dict, Generator, List, Optional, Set, Tuple, Union
1414

1515
import rzpipe
1616

@@ -78,11 +78,31 @@ def __init__(
7878

7979
@functools.lru_cache
8080
def _get_rz(self, index):
81+
"""
82+
Return a Rizin object that opens the specified Dex file.
83+
84+
:param index: an index indicating which Dex file should the returned
85+
object open
86+
:return: a Rizin object opening the specified Dex file
87+
"""
8188
rz = rzpipe.open(self._dex_list[index])
8289
rz.cmd("aa")
8390
return rz
8491

8592
def _convert_type_to_type_signature(self, raw_type: str):
93+
"""
94+
Convert a Java type in the format of the Java language into the
95+
one in the format of the Java VM type signature.
96+
97+
For example,
98+
+ `int` will be converted into the Java VM type signature `I`.
99+
+ `long` will be converted into the Java VM type signature `L`.
100+
+ `String...` will be converted into the Java VM type signature
101+
`[Ljava/lang/String;`.
102+
103+
:param raw_type: a type in the format of the Java language
104+
:return: a type in the format of the Java VM type signature
105+
"""
86106
if not raw_type:
87107
return raw_type
88108

@@ -108,11 +128,29 @@ def _convert_type_to_type_signature(self, raw_type: str):
108128

109129
@staticmethod
110130
def _escape_str_in_rizin_manner(raw_str: str):
131+
"""
132+
Convert characters with special meanings in Rizin into `_`.
133+
For now, these characters are `<`, `>` and `$`.
134+
135+
:param raw_str: a string that may consist of characters with special
136+
meanings.
137+
:return: a new string contains no characters with special meanings.
138+
"""
111139
for c in RIZIN_ESCAPE_CHAR_LIST:
112140
raw_str = raw_str.replace(c, "_")
113141
return raw_str
114142

115143
def _parse_method_from_isj_obj(self, json_obj, dexindex):
144+
"""
145+
Parse a JSON object provided by the Rizin command `isj` or `is.j` into
146+
an instance of MethodObject.
147+
148+
:param json_obj: a JSON object provided by the Rizin command `isj` or
149+
`is.j`
150+
:param dexindex: an index indicating from which Dex file the JSON
151+
object is generated
152+
:return: an instance of MethodObject
153+
"""
116154
if json_obj.get("type") not in ["FUNC", "METH"]:
117155
return None
118156

@@ -215,6 +253,16 @@ def _parse_method_from_isj_obj(self, json_obj, dexindex):
215253

216254
@functools.lru_cache
217255
def _get_methods_classified(self, dexindex):
256+
"""
257+
Parse all methods in the specified Dex and convert them into a
258+
dictionary. The dictionary takes their belonging classes as the keys.
259+
Then, it categorizes them into lists.
260+
261+
:param dexindex: an index indicating which Dex file should this method
262+
parse
263+
:return: a dictionary taking a class name as the key and a list of
264+
MethodObject as the corresponding value.
265+
"""
218266
rz = self._get_rz(dexindex)
219267

220268
method_json_list = rz.cmdj("isj")
@@ -233,6 +281,12 @@ def _get_methods_classified(self, dexindex):
233281

234282
@functools.cached_property
235283
def permissions(self) -> List[str]:
284+
"""
285+
Inherited from baseapkinfo.py.
286+
Return the permissions used by the sample.
287+
288+
:return: a list of permissions.
289+
"""
236290
axml = AxmlReader(self._manifest)
237291
permission_list = set()
238292

@@ -285,6 +339,12 @@ def receivers(self) -> List[XMLElement]:
285339

286340
@property
287341
def android_apis(self) -> Set[MethodObject]:
342+
"""
343+
Inherited from baseapkinfo.py.
344+
Return all Android native APIs used by the sample.
345+
346+
:return: a set of MethodObjects
347+
"""
288348
return {
289349
method
290350
for method in self.all_methods
@@ -293,10 +353,27 @@ def android_apis(self) -> Set[MethodObject]:
293353

294354
@property
295355
def custom_methods(self) -> Set[MethodObject]:
296-
return {method for method in self.all_methods if not method.cache.is_imported}
356+
"""_
357+
Inherited from baseapkinfo.py.
358+
Return all custom methods declared by the sample.
359+
360+
:return: a set of MethodObjects
361+
"""
362+
return {
363+
method
364+
for method in self.all_methods
365+
if not method.cache.is_imported
366+
}
297367

298368
@functools.cached_property
299369
def all_methods(self) -> Set[MethodObject]:
370+
"""_
371+
Inherited from baseapkinfo.py.
372+
Return all methods including Android native APIs and custom methods
373+
declared in the sample.
374+
375+
:return: a set of MethodObjects
376+
"""
300377
method_set = set()
301378
for dex_index in range(self._number_of_dex):
302379
for method_list in self._get_methods_classified(dex_index).values():
@@ -310,6 +387,18 @@ def find_method(
310387
method_name: Optional[str] = ".*",
311388
descriptor: Optional[str] = ".*",
312389
) -> List[MethodObject]:
390+
"""
391+
Inherited from baseapkinfo.py.
392+
Find a method with the given class name, method name, and descriptor.
393+
394+
:param class_name: the class name of the target method. Defaults to
395+
".*"
396+
:param method_name: the method name of the target method. Defaults to
397+
".*"
398+
:param descriptor: the descriptor of the target method. Defaults to
399+
".*"
400+
:return: a MethodObject of the target method
401+
"""
313402
if not class_name:
314403
class_name = ".*"
315404

@@ -351,6 +440,14 @@ def method_filter(method):
351440

352441
@functools.lru_cache
353442
def upperfunc(self, method_object: MethodObject) -> Set[MethodObject]:
443+
"""
444+
Inherited from baseapkinfo.py.
445+
Find the xrefs from the specified method.
446+
447+
:param method_object: a target method which the returned methods
448+
should call
449+
:return: a set of MethodObjects
450+
"""
354451
cache = method_object.cache
355452

356453
r2 = self._get_rz(cache.dexindex)
@@ -380,7 +477,18 @@ def upperfunc(self, method_object: MethodObject) -> Set[MethodObject]:
380477
return upperfunc_set
381478

382479
@functools.lru_cache
383-
def lowerfunc(self, method_object: MethodObject) -> Set[MethodObject]:
480+
def lowerfunc(
481+
self, method_object: MethodObject
482+
) -> Set[Tuple[MethodObject, int]]:
483+
"""
484+
Inherited from baseapkinfo.py.
485+
Find the xrefs to the specified method.
486+
487+
:param method_object: a target method used to find what methods it
488+
calls
489+
:return: a set of tuples consisting of the called method and the
490+
offset of the invocation
491+
"""
384492
cache = method_object.cache
385493

386494
rz = self._get_rz(cache.dexindex)
@@ -413,6 +521,14 @@ def lowerfunc(self, method_object: MethodObject) -> Set[MethodObject]:
413521
def get_method_bytecode(
414522
self, method_object: MethodObject
415523
) -> Generator[BytecodeObject, None, None]:
524+
"""
525+
Inherited from baseapkinfo.py.
526+
Return the bytecodes of the specified method.
527+
528+
:param method_object: a target method to get the corresponding
529+
bytecodes
530+
:yield: a generator of BytecodeObjects
531+
"""
416532
cache = method_object.cache
417533

418534
if not cache.is_imported:
@@ -426,6 +542,12 @@ def get_method_bytecode(
426542
yield self._parse_smali(ins["disasm"])
427543

428544
def get_strings(self) -> Set[str]:
545+
"""
546+
Inherited from baseapkinfo.py.
547+
Return all strings in the sample.
548+
549+
:return: a set of strings
550+
"""
429551
strings = set()
430552
for dex_index in range(self._number_of_dex):
431553
rz = self._get_rz(dex_index)
@@ -443,6 +565,19 @@ def get_wrapper_smali(
443565
first_method: MethodObject,
444566
second_method: MethodObject,
445567
) -> Dict[str, Union[BytecodeObject, str]]:
568+
"""
569+
Inherited from baseapkinfo.py.
570+
Find the invocations that call two specified methods, first_method
571+
and second_method, respectively. Then, return a dictionary storing
572+
the corresponding bytecodes and hex values.
573+
574+
:param parent_method: a parent method to scan
575+
:param first_method: the first method called by the parent method
576+
:param second_method: the second method called by the parent method
577+
:return: a dictionary storing the corresponding bytecodes and hex
578+
values.
579+
"""
580+
446581
def convert_bytecode_to_list(bytecode):
447582
return [bytecode.mnemonic] + bytecode.registers + [bytecode.parameter]
448583

@@ -506,6 +641,15 @@ def convert_bytecode_to_list(bytecode):
506641

507642
@functools.cached_property
508643
def superclass_relationships(self) -> Dict[str, Set[str]]:
644+
"""
645+
Inherited from baseapkinfo.py.
646+
Return a dictionary holding the inheritance relationship of classes in
647+
the sample. The dictionary takes a class name as the key and the
648+
corresponding superclass as the value.
649+
650+
:return: a dictionary taking a class name as the key and the
651+
corresponding superclass as the value.
652+
"""
509653
hierarchy_dict = defaultdict(set)
510654

511655
for dex_index in range(self._number_of_dex):
@@ -523,6 +667,16 @@ def superclass_relationships(self) -> Dict[str, Set[str]]:
523667

524668
@functools.cached_property
525669
def subclass_relationships(self) -> Dict[str, Set[str]]:
670+
"""
671+
Inherited from baseapkinfo.py.
672+
Return a dictionary holding the inheritance relationship of classes in
673+
the sample. Return a dictionary holding the inheritance relationship
674+
of classes in the sample. The dictionary takes a class name as the key
675+
and the corresponding subclasses as the value.
676+
677+
:return: a dictionary taking a class name as the key and the
678+
corresponding subclasses as the value.
679+
"""
526680
hierarchy_dict = defaultdict(set)
527681

528682
for dex_index in range(self._number_of_dex):
@@ -539,6 +693,12 @@ def subclass_relationships(self) -> Dict[str, Set[str]]:
539693
return hierarchy_dict
540694

541695
def _get_method_by_address(self, address: int) -> MethodObject:
696+
"""
697+
Find a method via a specified address.
698+
699+
:param address: an address used to find the corresponding method
700+
:return: the MethodObject of the method in the given address
701+
"""
542702
dexindex = 0
543703

544704
rz = self._get_rz(dexindex)
@@ -570,6 +730,14 @@ def _parse_parameter(mnemonic: str, parameter: str) -> Any:
570730

571731
@staticmethod
572732
def _parse_smali(smali: str) -> BytecodeObject:
733+
"""
734+
Convert a Smali code provided by the Rizin command `pdfj` into a
735+
BytecodeObject.
736+
737+
:param smali: a Smali code provided by the Rizin command `pdfj`
738+
:raises ValueError: if the Smali code follows an unknown format
739+
:return: a BytecodeObject
740+
"""
573741
if smali == "":
574742
raise ValueError("Argument cannot be empty.")
575743

0 commit comments

Comments
 (0)