Skip to content

Commit 5a2025a

Browse files
haeter525sidra-asa
authored andcommitted
Update docstrings for rzapkinfo.py
1 parent 20df14f commit 5a2025a

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

@@ -273,6 +327,12 @@ def activities(self) -> List[XMLElement]:
273327

274328
@property
275329
def android_apis(self) -> Set[MethodObject]:
330+
"""
331+
Inherited from baseapkinfo.py.
332+
Return all Android native APIs used by the sample.
333+
334+
:return: a set of MethodObjects
335+
"""
276336
return {
277337
method
278338
for method in self.all_methods
@@ -281,10 +341,27 @@ def android_apis(self) -> Set[MethodObject]:
281341

282342
@property
283343
def custom_methods(self) -> Set[MethodObject]:
284-
return {method for method in self.all_methods if not method.cache.is_imported}
344+
"""_
345+
Inherited from baseapkinfo.py.
346+
Return all custom methods declared by the sample.
347+
348+
:return: a set of MethodObjects
349+
"""
350+
return {
351+
method
352+
for method in self.all_methods
353+
if not method.cache.is_imported
354+
}
285355

286356
@functools.cached_property
287357
def all_methods(self) -> Set[MethodObject]:
358+
"""_
359+
Inherited from baseapkinfo.py.
360+
Return all methods including Android native APIs and custom methods
361+
declared in the sample.
362+
363+
:return: a set of MethodObjects
364+
"""
288365
method_set = set()
289366
for dex_index in range(self._number_of_dex):
290367
for method_list in self._get_methods_classified(dex_index).values():
@@ -298,6 +375,18 @@ def find_method(
298375
method_name: Optional[str] = ".*",
299376
descriptor: Optional[str] = ".*",
300377
) -> List[MethodObject]:
378+
"""
379+
Inherited from baseapkinfo.py.
380+
Find a method with the given class name, method name, and descriptor.
381+
382+
:param class_name: the class name of the target method. Defaults to
383+
".*"
384+
:param method_name: the method name of the target method. Defaults to
385+
".*"
386+
:param descriptor: the descriptor of the target method. Defaults to
387+
".*"
388+
:return: a list of the target MethodObject
389+
"""
301390
if not class_name:
302391
class_name = ".*"
303392

@@ -339,6 +428,14 @@ def method_filter(method):
339428

340429
@functools.lru_cache
341430
def upperfunc(self, method_object: MethodObject) -> Set[MethodObject]:
431+
"""
432+
Inherited from baseapkinfo.py.
433+
Find the xrefs from the specified method.
434+
435+
:param method_object: a target method which the returned methods
436+
should call
437+
:return: a set of MethodObjects
438+
"""
342439
cache = method_object.cache
343440

344441
r2 = self._get_rz(cache.dexindex)
@@ -368,7 +465,18 @@ def upperfunc(self, method_object: MethodObject) -> Set[MethodObject]:
368465
return upperfunc_set
369466

370467
@functools.lru_cache
371-
def lowerfunc(self, method_object: MethodObject) -> Set[MethodObject]:
468+
def lowerfunc(
469+
self, method_object: MethodObject
470+
) -> Set[Tuple[MethodObject, int]]:
471+
"""
472+
Inherited from baseapkinfo.py.
473+
Find the xrefs to the specified method.
474+
475+
:param method_object: a target method used to find what methods it
476+
calls
477+
:return: a set of tuples consisting of the called method and the
478+
offset of the invocation
479+
"""
372480
cache = method_object.cache
373481

374482
rz = self._get_rz(cache.dexindex)
@@ -401,6 +509,14 @@ def lowerfunc(self, method_object: MethodObject) -> Set[MethodObject]:
401509
def get_method_bytecode(
402510
self, method_object: MethodObject
403511
) -> Generator[BytecodeObject, None, None]:
512+
"""
513+
Inherited from baseapkinfo.py.
514+
Return the bytecodes of the specified method.
515+
516+
:param method_object: a target method to get the corresponding
517+
bytecodes
518+
:yield: a generator of BytecodeObjects
519+
"""
404520
cache = method_object.cache
405521

406522
if not cache.is_imported:
@@ -414,6 +530,12 @@ def get_method_bytecode(
414530
yield self._parse_smali(ins["disasm"])
415531

416532
def get_strings(self) -> Set[str]:
533+
"""
534+
Inherited from baseapkinfo.py.
535+
Return all strings in the sample.
536+
537+
:return: a set of strings
538+
"""
417539
strings = set()
418540
for dex_index in range(self._number_of_dex):
419541
rz = self._get_rz(dex_index)
@@ -431,6 +553,19 @@ def get_wrapper_smali(
431553
first_method: MethodObject,
432554
second_method: MethodObject,
433555
) -> Dict[str, Union[BytecodeObject, str]]:
556+
"""
557+
Inherited from baseapkinfo.py.
558+
Find the invocations that call two specified methods, first_method
559+
and second_method, respectively. Then, return a dictionary storing
560+
the corresponding bytecodes and hex values.
561+
562+
:param parent_method: a parent method to scan
563+
:param first_method: the first method called by the parent method
564+
:param second_method: the second method called by the parent method
565+
:return: a dictionary storing the corresponding bytecodes and hex
566+
values.
567+
"""
568+
434569
def convert_bytecode_to_list(bytecode):
435570
return [bytecode.mnemonic] + bytecode.registers + [bytecode.parameter]
436571

@@ -494,6 +629,15 @@ def convert_bytecode_to_list(bytecode):
494629

495630
@functools.cached_property
496631
def superclass_relationships(self) -> Dict[str, Set[str]]:
632+
"""
633+
Inherited from baseapkinfo.py.
634+
Return a dictionary holding the inheritance relationship of classes in
635+
the sample. The dictionary takes a class name as the key and the
636+
corresponding superclass as the value.
637+
638+
:return: a dictionary taking a class name as the key and the
639+
corresponding superclass as the value.
640+
"""
497641
hierarchy_dict = defaultdict(set)
498642

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

512656
@functools.cached_property
513657
def subclass_relationships(self) -> Dict[str, Set[str]]:
658+
"""
659+
Inherited from baseapkinfo.py.
660+
Return a dictionary holding the inheritance relationship of classes in
661+
the sample. Return a dictionary holding the inheritance relationship
662+
of classes in the sample. The dictionary takes a class name as the key
663+
and the corresponding subclasses as the value.
664+
665+
:return: a dictionary taking a class name as the key and the
666+
corresponding subclasses as the value.
667+
"""
514668
hierarchy_dict = defaultdict(set)
515669

516670
for dex_index in range(self._number_of_dex):
@@ -527,6 +681,12 @@ def subclass_relationships(self) -> Dict[str, Set[str]]:
527681
return hierarchy_dict
528682

529683
def _get_method_by_address(self, address: int) -> MethodObject:
684+
"""
685+
Find a method via a specified address.
686+
687+
:param address: an address used to find the corresponding method
688+
:return: the MethodObject of the method in the given address
689+
"""
530690
dexindex = 0
531691

532692
rz = self._get_rz(dexindex)
@@ -558,6 +718,14 @@ def _parse_parameter(mnemonic: str, parameter: str) -> Any:
558718

559719
@staticmethod
560720
def _parse_smali(smali: str) -> BytecodeObject:
721+
"""
722+
Convert a Smali code provided by the Rizin command `pdfj` into a
723+
BytecodeObject.
724+
725+
:param smali: a Smali code provided by the Rizin command `pdfj`
726+
:raises ValueError: if the Smali code follows an unknown format
727+
:return: a BytecodeObject
728+
"""
561729
if smali == "":
562730
raise ValueError("Argument cannot be empty.")
563731

0 commit comments

Comments
 (0)