Skip to content

Commit 5ce6e39

Browse files
authored
Add analysis library for radare2 v5.8.8 (#495)
1 parent 5912933 commit 5ce6e39

File tree

9 files changed

+826
-55
lines changed

9 files changed

+826
-55
lines changed

.github/workflows/pytest.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
- name: Install dependencies
2727
run: |
2828
python -m pip install --upgrade pip
29-
python -m pip install pytest rzpipe meson==0.62.0 ninja coverage ciphey frida objection
29+
python -m pip install pytest rzpipe meson==0.62.0 ninja coverage ciphey frida objection r2pipe==1.8.0
3030
3131
# Install graphviz & ninja
3232
sudo apt-get -y install graphviz ninja-build
@@ -39,6 +39,14 @@ jobs:
3939
sudo ninja -C build install
4040
sudo ldconfig -v
4141
cd -
42+
43+
# Install Radare2 (5.8.8)
44+
sudo apt install -y musl-tools
45+
sudo git clone https://github.com/radareorg/radare2 /opt/radare2/
46+
cd /opt/radare2/
47+
sudo git checkout 5.8.8
48+
sudo sys/install.sh
49+
cd -
4250

4351
# Install click >= 8.0.0 for CLI supports
4452
python -m pip install click==8.0.3

Pipfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ rzpipe = "<=0.1.2"
2525
objection = "<=1.11.0"
2626
frida = "<=15.2.2"
2727
ciphey = ">=5.0.0,<=5.14.0"
28+
r2pipe = "==1.8.0"
2829

2930
[requires]
3031
python_version = "3.8"

quark/cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@
133133
"--core-library",
134134
"core_library",
135135
help="Specify the core library used to analyze an APK",
136-
type=click.Choice(("androguard", "rizin"), case_sensitive=False),
136+
type=click.Choice(("androguard", "rizin", "radare2"), case_sensitive=False),
137137
required=False,
138138
default="androguard",
139139
)

quark/core/axmlreader/__init__.py

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import pkg_resources
1010
import rzpipe
11+
import r2pipe
1112

1213
# Resource Types Definition
1314
# Please reference to
@@ -84,7 +85,7 @@ class AxmlReader(object):
8485
A Class that parses the Android XML file
8586
"""
8687

87-
def __init__(self, file_path, structure_path=None):
88+
def __init__(self, file_path, core_library="rizin", structure_path=None):
8889
if structure_path is None:
8990
structure_path = pkg_resources.resource_filename(
9091
"quark.core.axmlreader", "axml_definition"
@@ -96,10 +97,13 @@ def __init__(self, file_path, structure_path=None):
9697
f" of Rizin in {structure_path}"
9798
)
9899

99-
self._rz = rzpipe.open(file_path)
100-
self._rz.cmd(f"pfo {structure_path}")
100+
if core_library == "rizin":
101+
self._core = rzpipe.open(file_path)
102+
else:
103+
self._core = r2pipe.open(file_path)
104+
self._core.cmd(f"pfo {structure_path}")
101105

102-
self._file_size = int(self._rz.cmd("i~size[1]"), 16)
106+
self._file_size = int(self._core.cmd("i~size[1]"), 16)
103107
self._ptr = 0
104108

105109
self._cache = {}
@@ -110,7 +114,7 @@ def __init__(self, file_path, structure_path=None):
110114
raise AxmlException("Filesize exceeds theoretical lower bound.")
111115

112116
# File Header
113-
header = self._rz.cmdj("pfj axml_ResChunk_header @ 0x0")
117+
header = self._core.cmdj("pfj axml_ResChunk_header @ 0x0")
114118

115119
self._data_type = header[0]["value"]
116120
self._axml_size = header[2]["value"]
@@ -133,7 +137,7 @@ def __init__(self, file_path, structure_path=None):
133137
return
134138

135139
# String Pool
136-
string_pool_header = self._rz.cmdj("pfj axml_ResStringPool_header @ 8")
140+
string_pool_header = self._core.cmdj("pfj axml_ResStringPool_header @ 8")
137141

138142
string_pool_size = string_pool_header[0]["value"][2]["value"]
139143

@@ -163,18 +167,18 @@ def __init__(self, file_path, structure_path=None):
163167
self._stringCount = string_pool_header[1]["value"]
164168
stringStart = string_pool_header[4]["value"]
165169

166-
self._rz.cmd(f"f string_pool_header @ 0x8 ")
170+
self._core.cmd(f"f string_pool_header @ 0x8 ")
167171
string_pool_index = header_size + self._ptr
168-
self._rz.cmd(f"f string_pool_index @ { string_pool_index }")
172+
self._core.cmd(f"f string_pool_index @ { string_pool_index }")
169173
string_pool_data = stringStart + self._ptr
170-
self._rz.cmd(f"f string_pool_data @ { string_pool_data }")
174+
self._core.cmd(f"f string_pool_data @ { string_pool_data }")
171175

172176
self._ptr += string_pool_size
173177
if self._ptr >= self._axml_size:
174178
return
175179

176180
# Resource Map (Optional)
177-
header = self._rz.cmdj(f"pfj axml_ResChunk_header @ {self._ptr}")
181+
header = self._core.cmdj(f"pfj axml_ResChunk_header @ {self._ptr}")
178182

179183
header_type = header[0]["value"]
180184
if header_type == RES_XML_RESOURCE_MAP_TYPE:
@@ -201,7 +205,7 @@ def __iter__(self) -> Iterator[ResChunkHeader]:
201205
:yield: header of a resource chunk defined in the binary
202206
"""
203207
while self._axml_size - self._ptr >= 16:
204-
header = self._rz.cmdj(f"pfj axml_ResXMLTree_node @ {self._ptr}")
208+
header = self._core.cmdj(f"pfj axml_ResXMLTree_node @ {self._ptr}")
205209

206210
node_type = header[0]["value"][0]["value"]
207211
header_size = header[0]["value"][1]["value"]
@@ -224,7 +228,7 @@ def __iter__(self) -> Iterator[ResChunkHeader]:
224228
chunk = {"Address": self._ptr, "Type": node_type}
225229

226230
if node_type == RES_XML_START_ELEMENT_TYPE:
227-
ext = self._rz.cmdj(
231+
ext = self._core.cmdj(
228232
f"pfj axml_ResXMLTree_attrExt @ { ext_ptr }"
229233
)
230234

@@ -235,7 +239,7 @@ def __iter__(self) -> Iterator[ResChunkHeader]:
235239
# node['AttrCount'] = ext[4]['value']
236240

237241
elif node_type == RES_XML_END_ELEMENT_TYPE:
238-
ext = self._rz.cmdj(
242+
ext = self._core.cmdj(
239243
f"pfj axml_ResXMLTree_endElementExt @ { ext_ptr }"
240244
)
241245

@@ -246,15 +250,15 @@ def __iter__(self) -> Iterator[ResChunkHeader]:
246250
RES_XML_START_NAMESPACE_TYPE,
247251
RES_XML_END_NAMESPACE_TYPE,
248252
]:
249-
ext = self._rz.cmdj(
253+
ext = self._core.cmdj(
250254
f"pfj axml_ResXMLTree_namespaceExt @ { ext_ptr }"
251255
)
252256

253257
chunk["Prefix"] = ext[0]["value"][0]["value"]
254258
chunk["Uri"] = ext[1]["value"][0]["value"]
255259

256260
elif node_type == RES_XML_CDATA_TYPE:
257-
ext = self._rz.cmdj(
261+
ext = self._core.cmdj(
258262
f"pfj axml_ResXMLTree_cdataExt @ { ext_ptr }"
259263
)
260264

@@ -281,7 +285,7 @@ def get_string(self, index):
281285
if index < 0 or index >= self._stringCount:
282286
return None
283287

284-
return self._rz.cmdj(
288+
return self._core.cmdj(
285289
f"pfj Z @ string_pool_data + `pfv n4 "
286290
f"@ string_pool_index+ {index}*4` + 2"
287291
)[0]["string"]
@@ -296,14 +300,14 @@ def get_attributes(self, chunk: ResChunkHeader) -> List[ResValue]:
296300
return None
297301
extAddress = int(chunk["Address"]) + 16
298302

299-
attrExt = self._rz.cmdj(f"pfj axml_ResXMLTree_attrExt @ {extAddress}")
303+
attrExt = self._core.cmdj(f"pfj axml_ResXMLTree_attrExt @ {extAddress}")
300304

301305
attrAddress = extAddress + attrExt[2]["value"]
302306
attributeSize = attrExt[3]["value"]
303307
attributeCount = attrExt[4]["value"]
304308
attributes = []
305309
for _ in range(attributeCount):
306-
attr = self._rz.cmdj(
310+
attr = self._core.cmdj(
307311
f"pfj axml_ResXMLTree_attribute @ {attrAddress}"
308312
)
309313

@@ -402,6 +406,6 @@ def get_xml_tree(self) -> XMLElementTree:
402406

403407
def __del__(self):
404408
try:
405-
self._rz.quit()
409+
self._core.quit()
406410
except BaseException:
407411
pass

quark/core/quark.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from quark.core.analysis import QuarkAnalysis
1515
from quark.core.apkinfo import AndroguardImp
1616
from quark.core.rzapkinfo import RizinImp
17+
from quark.core.r2apkinfo import R2Imp
1718
from quark.evaluator.pyeval import PyEval
1819
from quark.utils import tools
1920
from quark.utils.colors import (
@@ -49,6 +50,8 @@ def __init__(self, apk, core_library="androguard"):
4950
core_library = core_library.lower()
5051
if core_library == "rizin":
5152
self.apkinfo = RizinImp(apk)
53+
elif core_library == "radare2":
54+
self.apkinfo = R2Imp(apk)
5255
elif core_library == "androguard":
5356
self.apkinfo = AndroguardImp(apk)
5457
else:

0 commit comments

Comments
 (0)