Skip to content

Commit 502afd1

Browse files
authored
Merge pull request #12 from AbhiTheModder/main
code cleanup, revert comment and add new flag
2 parents 8990db3 + 89a3f73 commit 502afd1

File tree

4 files changed

+120
-61
lines changed

4 files changed

+120
-61
lines changed

blutter.py

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,14 @@ def __init__(
3131
rebuild_blutter: bool,
3232
create_vs_sln: bool,
3333
no_analysis: bool,
34+
ida_fcn: bool,
3435
):
3536
self.libapp_path = libapp_path
3637
self.dart_info = dart_info
3738
self.outdir = outdir
3839
self.rebuild_blutter = rebuild_blutter
3940
self.create_vs_sln = create_vs_sln
41+
self.ida_fcn = ida_fcn
4042

4143
vers = dart_info.version.split(".", 2)
4244
if int(vers[0]) == 2 and int(vers[1]) < 15:
@@ -51,6 +53,8 @@ def __init__(
5153
self.name_suffix += "_no-compressed-ptrs"
5254
if no_analysis:
5355
self.name_suffix += "_no-analysis"
56+
if ida_fcn:
57+
self.name_suffix += "_ida-fcn"
5458
# derive blutter executable filename
5559
self.blutter_name = f"blutter_{dart_info.lib_name}{self.name_suffix}"
5660
self.blutter_file = os.path.join(BIN_DIR, self.blutter_name) + (
@@ -90,7 +94,7 @@ def extract_libs_from_apk(apk_file: str, out_dir: str):
9094
return app_file, flutter_file
9195

9296

93-
def find_compat_macro(dart_version: str, no_analysis: bool):
97+
def find_compat_macro(dart_version: str, no_analysis: bool, ida_fcn: bool):
9498
macros = []
9599
include_path = os.path.join(PKG_INC_DIR, f"dartvm{dart_version}")
96100
vm_path = os.path.join(include_path, "vm")
@@ -139,19 +143,25 @@ def find_compat_macro(dart_version: str, no_analysis: bool):
139143
if no_analysis:
140144
macros.append("-DNO_CODE_ANALYSIS=1")
141145

142-
if dart_version >= "3.5.0":
143-
# [vm] marking_stack_block_offset() changes in Dart Stable 3.5.0
144-
# https://github.com/worawit/blutter/issues/96#issue-2470674670
145-
macros.append("-DOLD_MARKING_STACK_BLOCK=1")
146-
146+
if ida_fcn:
147+
macros.append("-DIDA_FCN=1")
148+
149+
d_v = float('.'.join(dart_version.split('.')[:2]))
150+
if d_v >= float(3.5) :
151+
with open(os.path.join(vm_path, "compiler", "runtime_api.h"), "rb") as f:
152+
mm = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
153+
if not mm.find(b" old_marking_stack_block_offset") == -1:
154+
# [vm] marking_stack_block_offset() changes since Dart Stable 3.5.0
155+
# https://github.com/worawit/blutter/issues/96#issue-2470674670
156+
macros.append("-DOLD_MARKING_STACK_BLOCK=1")
147157
return macros
148158

149159

150160
def cmake_blutter(input: BlutterInput):
151161
blutter_dir = os.path.join(SCRIPT_DIR, "blutter")
152162
builddir = os.path.join(BUILD_DIR, input.blutter_name)
153163

154-
macros = find_compat_macro(input.dart_info.version, input.no_analysis)
164+
macros = find_compat_macro(input.dart_info.version, input.no_analysis, input.ida_fcn)
155165

156166
my_env = None
157167
if platform.system() == "Darwin":
@@ -222,7 +232,7 @@ def build_and_run(input: BlutterInput):
222232

223233
# creating Visual Studio solution overrides building
224234
if input.create_vs_sln:
225-
macros = find_compat_macro(dart_version, no_analysis)
235+
macros = find_compat_macro(input.dart_info.version, input.no_analysis, input.ida_fcn)
226236
blutter_dir = os.path.join(SCRIPT_DIR, "blutter")
227237
dbg_output_path = os.path.abspath(os.path.join(input.outdir, "out"))
228238
dbg_cmd_args = f"-i {input.libapp_path} -o {dbg_output_path}"
@@ -269,11 +279,12 @@ def main_no_flutter(
269279
rebuild_blutter: bool,
270280
create_vs_sln: bool,
271281
no_analysis: bool,
282+
ida_fcn: bool,
272283
):
273284
version, os_name, arch = dart_version.split("_")
274285
dart_info = DartLibInfo(version, os_name, arch)
275286
input = BlutterInput(
276-
libapp_path, dart_info, outdir, rebuild_blutter, create_vs_sln, no_analysis
287+
libapp_path, dart_info, outdir, rebuild_blutter, create_vs_sln, no_analysis, ida_fcn
277288
)
278289
build_and_run(input)
279290

@@ -285,10 +296,11 @@ def main2(
285296
rebuild_blutter: bool,
286297
create_vs_sln: bool,
287298
no_analysis: bool,
299+
ida_fcn: bool,
288300
):
289301
dart_info = get_dart_lib_info(libapp_path, libflutter_path)
290302
input = BlutterInput(
291-
libapp_path, dart_info, outdir, rebuild_blutter, create_vs_sln, no_analysis
303+
libapp_path, dart_info, outdir, rebuild_blutter, create_vs_sln, no_analysis, ida_fcn
292304
)
293305
build_and_run(input)
294306

@@ -299,6 +311,7 @@ def main(
299311
rebuild_blutter: bool,
300312
create_vs_sln: bool,
301313
no_analysis: bool,
314+
ida_fcn: bool,
302315
):
303316
if indir.endswith(".apk"):
304317
with tempfile.TemporaryDirectory() as tmp_dir:
@@ -310,6 +323,7 @@ def main(
310323
rebuild_blutter,
311324
create_vs_sln,
312325
no_analysis,
326+
ida_fcn,
313327
)
314328
else:
315329
libapp_file, libflutter_file = find_lib_files(indir)
@@ -321,6 +335,7 @@ def main(
321335
rebuild_blutter,
322336
create_vs_sln,
323337
no_analysis,
338+
ida_fcn,
324339
)
325340

326341

@@ -386,13 +401,25 @@ def check_for_updates_and_pull():
386401
"--dart-version",
387402
help='Run without libflutter (indir become libapp.so) by specify dart version such as "3.4.2_android_arm64"',
388403
)
404+
parser.add_argument(
405+
"--nu",
406+
action="store_false",
407+
default=True,
408+
help="Don't check for updates",
409+
)
410+
parser.add_argument(
411+
"--ida-fcn",
412+
action="store_true",
413+
default=False,
414+
help="Generate IDA function names script, Doesn't Generates Thread and Object Pool structs comments",
415+
)
389416
args = parser.parse_args()
390417

391-
# Check for updates and pull them if necessary
392-
check_for_updates_and_pull()
418+
if args.nu:
419+
check_for_updates_and_pull()
393420

394421
if args.dart_version is None:
395-
main(args.indir, args.outdir, args.rebuild, args.vs_sln, args.no_analysis)
422+
main(args.indir, args.outdir, args.rebuild, args.vs_sln, args.no_analysis, args.ida_fcn)
396423
else:
397424
main_no_flutter(
398425
args.indir,
@@ -401,4 +428,5 @@ def check_for_updates_and_pull():
401428
args.rebuild,
402429
args.vs_sln,
403430
args.no_analysis,
431+
args.ida_fcn,
404432
)

blutter/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ endif()
106106
if (OLD_MARKING_STACK_BLOCK)
107107
set(defines ${defines} OLD_MARKING_STACK_BLOCK)
108108
endif()
109+
if (IDA_FCN)
110+
set(defines ${defines} IDA_FCN)
111+
endif()
109112
target_compile_definitions(${BINNAME} PRIVATE ${defines})
110113

111114
target_compile_options(${BINNAME} PRIVATE ${cc_opts})

blutter/src/DartDumper.cpp

Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -132,51 +132,45 @@ void DartDumper::Dump4Radare2(std::filesystem::path outDir)
132132
std::filesystem::create_directory(outDir);
133133
std::ofstream of((outDir / "addNames.r2").string());
134134
of << "# create flags for libraries, classes and methods\n";
135-
136-
// app base & heap base address values changes on every run i.e, setting flag names for them is of no use
137135

138-
// of << fmt::format("f app.base = {:#x}\n", app.base());
139-
// of << fmt::format("f app.heap_base = {:#x}\n", app.heap_base());
136+
of << "e emu.str=true\n";
137+
// app base & heap base address values changes on every run i.e, setting flag names for them is of no use
138+
// but since right now r2 bases it to address 0 let's leave it as it is
139+
// https://github.com/worawit/blutter/pull/104#discussion_r1769637361
140+
of << fmt::format("f app.base = {:#x}\n", app.base());
141+
of << fmt::format("f app.heap_base = {:#x}\n", app.heap_base());
140142

141143
bool show_library = true;
142144
bool show_class = true;
143145
for (auto lib : app.libs) {
144146
std::string lib_prefix = lib->GetName();
145-
146-
std::replace(lib_prefix.begin(), lib_prefix.end(), '$', '_');
147-
std::replace(lib_prefix.begin(), lib_prefix.end(), '&', '_');
148-
std::replace(lib_prefix.begin(), lib_prefix.end(), '-', '_');
149-
std::replace(lib_prefix.begin(), lib_prefix.end(), '+', '_');
147+
filterString(lib_prefix);
150148
for (auto cls : lib->classes) {
151149
std::string cls_prefix = cls->Name();
152-
std::replace(cls_prefix.begin(), cls_prefix.end(), '$', '_');
153-
std::replace(cls_prefix.begin(), cls_prefix.end(), '&', '_');
154-
std::replace(cls_prefix.begin(), cls_prefix.end(), '-', '_');
155-
std::replace(cls_prefix.begin(), cls_prefix.end(), '+', '_');
150+
filterString(cls_prefix);
156151
for (auto dartFn : cls->Functions()) {
157152
const auto ep = dartFn->Address();
158-
auto name = getFunctionName4Ida(*dartFn, cls_prefix);
159-
std::replace(name.begin(), name.end(), '$', '_');
160-
std::replace(name.begin(), name.end(), '&', '_');
161-
std::replace(name.begin(), name.end(), '-', '_');
162-
std::replace(name.begin(), name.end(), '+', '_');
163-
std::replace(name.begin(), name.end(), '?', '_');
153+
std::string name = getFunctionName4Ida(*dartFn, cls_prefix);
154+
filterString(name);
164155
if (show_library) {
165-
of << fmt::format("CC Library({:#x}) = {} @ {}\n", lib->id, lib_prefix, ep);
166-
of << fmt::format("f lib.{}={:#x} # {:#x}\n", lib_prefix, ep, lib->id);
156+
of << fmt::format("'@{:#x}'CC Library({:#x}) = {}\n", ep, lib->id, lib->GetName());
157+
of << fmt::format("'@{:#x}'f lib.{}\n", ep, lib_prefix);
167158
show_library = false;
168159
}
169160
if (show_class) {
170-
of << fmt::format("CC Class({:#x}) = {} @ {}\n", cls->Id(), cls_prefix, ep);
171-
of << fmt::format("f class.{}.{}={:#x} # {:#x}\n", lib_prefix, cls_prefix, ep, cls->Id());
161+
of << fmt::format("'@{:#x}'CC Class({:#x}) = {}\n", ep, cls->Id(), cls->Name());
162+
of << fmt::format("'@{:#x}'f class.{}.{}\n", ep, lib_prefix, cls_prefix);
172163
show_class = false;
173164
}
174-
of << fmt::format("f method.{}.{}.{}_{:x}={:#x}\n", lib_prefix, cls_prefix, name.c_str(), ep, ep);
165+
of << fmt::format("'@{:#x}'f method.{}.{}.{}\n", ep, lib_prefix, cls_prefix, name);
166+
of << fmt::format("'@{:#x}'ic+{}.{}\n", ep, cls_prefix, name);
175167
if (dartFn->HasMorphicCode()) {
176-
of << fmt::format("f method.{}.{}.{}.miss={:#x}\n", lib_prefix, cls_prefix, name.c_str(),
177-
dartFn->PayloadAddress());
178-
of << fmt::format("f method.{}.{}.{}.check={:#x}\n", lib_prefix, cls_prefix, name.c_str(),
179-
dartFn->MonomorphicAddress());
168+
of << fmt::format("'@{:#x}'f method.{}.{}.{}.miss\n",
169+
dartFn->PayloadAddress(),
170+
lib_prefix, cls_prefix, name);
171+
of << fmt::format("'@{:#x}'f method.{}.{}.{}.check\n",
172+
dartFn->MonomorphicAddress(),
173+
lib_prefix, cls_prefix, name);
180174
}
181175
}
182176
show_class = true;
@@ -187,28 +181,19 @@ void DartDumper::Dump4Radare2(std::filesystem::path outDir)
187181
auto stub = item.second;
188182
const auto ep = stub->Address();
189183
std::string name = stub->FullName();
190-
std::replace(name.begin(), name.end(), '<', '_');
191-
std::replace(name.begin(), name.end(), '>', '_');
192-
std::replace(name.begin(), name.end(), ',', '_');
193-
std::replace(name.begin(), name.end(), ' ', '_');
194-
std::replace(name.begin(), name.end(), '$', '_');
195-
std::replace(name.begin(), name.end(), '&', '_');
196-
std::replace(name.begin(), name.end(), '-', '_');
197-
std::replace(name.begin(), name.end(), '+', '_');
198-
std::replace(name.begin(), name.end(), '?', '_');
199-
std::replace(name.begin(), name.end(), '(', '_'); // https://github.com/AbhiTheModder/blutter-termux/issues/6
200-
std::replace(name.begin(), name.end(), ')', '_');
201-
of << fmt::format("f method.stub.{}_{:x}={:#x}\n", name.c_str(), ep, ep);
184+
std::string flagName = name;
185+
filterString(flagName);
186+
of << fmt::format("'@{:#x}'f method.stub.{}\n", ep, flagName);
202187
}
203-
204-
of << "f pptr=x27\n"; // TODO: hardcoded value
188+
of << "dr x27=`e anal.gp`\n";
189+
of << "'f PP=x27\n";
205190
auto comments = DumpStructHeaderFile((outDir / "r2_dart_struct.h").string());
206191
for (const auto& [offset, comment] : comments) {
207192
if (comment.find("String:") != -1) {
208193
std::string flagFromComment = comment;
209194
filterString(flagFromComment);
210-
of << "f pp." << flagFromComment << "=pptr+" << offset << "\n";
211-
of << "'@0x0+" << offset << "'CC " << comment << "\n";
195+
of << "f pp." << flagFromComment << "=PP+" << offset << "\n";
196+
of << "'@PP+" << offset << "'CC " << comment << "\n";
212197
}
213198
}
214199
}
@@ -219,6 +204,7 @@ void DartDumper::Dump4Ida(std::filesystem::path outDir)
219204
std::ofstream of((outDir / "addNames.py").string());
220205
of << "import ida_funcs\n";
221206
of << "import idaapi\n\n";
207+
of << "print(\"[+] Adding Function names...\")\n\n";
222208

223209
for (auto lib : app.libs) {
224210
std::string lib_prefix = lib->GetName();
@@ -250,8 +236,9 @@ void DartDumper::Dump4Ida(std::filesystem::path outDir)
250236
continue;
251237
of << fmt::format("ida_funcs.add_func({:#x}, {:#x})\n", ep, ep + stub->Size());
252238
}
239+
of << "print(\"[+] Done!\")\n";
253240

254-
241+
#ifndef IDA_FCN
255242
// Note: create struct with a lot of member by ida script is very slow
256243
// use header file then adding comment is much faster
257244
auto comments = DumpStructHeaderFile((outDir / "ida_dart_struct.h").string());
@@ -271,13 +258,27 @@ def create_Dart_structs():
271258
for (const auto& [offset, comment] : comments) {
272259
of << "\tida_struct.set_member_cmt(ida_struct.get_member(struc, " << offset << "), '''" << comment << "''', True)\n";
273260
}
261+
#else
262+
auto comments = DumpStructHeaderFile((outDir / "ida_dart_struct.h").string());
263+
of << R"CBLOCK(
264+
import os
265+
def create_Dart_structs():
266+
sid1 = idc.get_struc_id("DartThread")
267+
if sid1 != idc.BADADDR:
268+
return sid1, idc.get_struc_id("DartObjectPool")
269+
hdr_file = os.path.join(os.path.dirname(__file__), 'ida_dart_struct.h')
270+
idaapi.idc_parse_types(hdr_file, idc.PT_FILE)
271+
sid1 = idc.import_type(-1, "DartThread")
272+
sid2 = idc.import_type(-1, "DartObjectPool")
273+
)CBLOCK";
274+
#endif
274275
of << "\treturn sid1, sid2\n";
275276
of << "thrs, pps = create_Dart_structs()\n";
276277

277-
of << "print('Applying Thread and Object Pool struct')\n";
278+
of << "print('[+] Applying Thread and Object Pool struct')\n";
278279
applyStruct4Ida(of);
279280

280-
of << "print('Script finished!')\n";
281+
of << "print('[+] Script finished!')\n";
281282
}
282283

283284
std::vector<std::pair<intptr_t, std::string>> DartDumper::DumpStructHeaderFile(std::string outFile)

dartvm_fetch_build.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@ def load_source(modname, filename):
3232
"""
3333

3434

35+
dart_versions = {
36+
"3.4": ["3.4.0", "3.4.1", "3.4.2", "3.4.3", "3.4.4"],
37+
"3.3": ["3.3.0", "3.3.1", "3.3.2", "3.3.3", "3.3.4"],
38+
"3.5": ["3.5.0", "3.5.1", "3.5.2", "3.5.3"],
39+
"3.0_aa": ["3.0.0", "3.0.1", "3.0.2"],
40+
"3.0_90": ["3.0.3", "3.0.4", "3.0.5", "3.0.6", "3.0.7"],
41+
"3.1": ["3.1.0", "3.1.1", "3.1.2", "3.1.3", "3.1.4", "3.1.5"],
42+
"3.2": ["3.2.0", "3.2.1", "3.2.2", "3.2.3", "3.2.4", "3.2.5", "3.2.6"],
43+
}
44+
45+
3546
class DartLibInfo:
3647
def __init__(
3748
self,
@@ -41,7 +52,6 @@ def __init__(
4152
has_compressed_ptrs: bool = None,
4253
snapshot_hash: str = None,
4354
):
44-
self.version = version
4555
self.os_name = os_name
4656
self.arch = arch
4757
self.snapshot_hash = snapshot_hash
@@ -51,6 +61,23 @@ def __init__(
5161
self.has_compressed_ptrs = os_name != "ios"
5262
else:
5363
self.has_compressed_ptrs = has_compressed_ptrs
64+
65+
if os.path.exists(os.path.join(SCRIPT_DIR, "bin")):
66+
file_name_version = []
67+
suffixes = ["", "_no-analysis", "_ida-fcn", "_no-analysis_ida-fcn", "_no-compressed-ptrs", "_no-compressed-ptrs_no-analysis", "_no-compressed-ptrs_no-analysis_ida-fcn", "_no-compressed-ptrs_ida-fcn"]
68+
for file in os.listdir(os.path.join(SCRIPT_DIR, "bin")):
69+
for suffix in suffixes:
70+
if file.startswith("blutter_dartvm") and file.endswith(f"{os_name}_{arch}{suffix}"):
71+
file_name_version.append(file.split("_")[1].replace('dartvm', ''))
72+
73+
for key, versions in dart_versions.items():
74+
if version in versions and any(v in versions for v in file_name_version):
75+
matched_version = next(v for v in file_name_version if v in versions)
76+
self.lib_name = f"dartvm{matched_version}_{os_name}_{arch}"
77+
self.version = matched_version
78+
return
79+
80+
self.version = version
5481
self.lib_name = f"dartvm{version}_{os_name}_{arch}"
5582

5683

0 commit comments

Comments
 (0)