From b595b9857bbc93c4845ea95cd8234dbadc0e8262 Mon Sep 17 00:00:00 2001 From: pancake Date: Sun, 26 May 2024 00:08:13 +0200 Subject: [PATCH 1/7] Initial support for radare2 --- blutter/src/DartDumper.cpp | 51 +++++++++++++++++++++++++++++++++++++- blutter/src/DartDumper.h | 1 + blutter/src/main.cpp | 3 ++- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/blutter/src/DartDumper.cpp b/blutter/src/DartDumper.cpp index 7323cb2..ebae1e9 100644 --- a/blutter/src/DartDumper.cpp +++ b/blutter/src/DartDumper.cpp @@ -82,6 +82,55 @@ static std::string getFunctionName4Ida(const DartFunction& dartFn, const std::st return prefix + fnName; } +void DartDumper::Dump4Radare2(std::filesystem::path outDir) +{ + std::filesystem::create_directory(outDir); + std::ofstream of((outDir / "addNames.r2").string()); + of << "# create flags for libraries, classes and methods\n"; + + of << std::format("f app.base = {:#x}\n", app.base()); + of << std::format("f app.heap_base = {:#x}\n", app.heap_base()); + + bool show_library = true; + bool show_class = true; + for (auto lib : app.libs) { + std::string lib_prefix = lib->GetName(); + + std::replace(lib_prefix.begin(), lib_prefix.end(), '$', '_'); + std::replace(lib_prefix.begin(), lib_prefix.end(), '&', '_'); + for (auto cls : lib->classes) { + std::string cls_prefix = cls->Name(); + std::replace(cls_prefix.begin(), cls_prefix.end(), '$', '_'); + std::replace(cls_prefix.begin(), cls_prefix.end(), '&', '_'); + for (auto dartFn : cls->Functions()) { + const auto ep = dartFn->Address(); + auto name = getFunctionName4Ida(*dartFn, cls_prefix); + std::replace(name.begin(), name.end(), '$', '_'); + std::replace(name.begin(), name.end(), '&', '_'); + if (show_library) { + of << std::format("CC Library({:#x}) = {} @ {}\n", lib->id, lib_prefix, ep); + of << std::format("f lib.{}={:#x} # {:#x}\n", lib_prefix, ep, lib->id); + show_library = false; + } + if (show_class) { + of << std::format("CC Class({:#x}) = {} @ {}\n", cls->Id(), cls_prefix, ep); + of << std::format("f class.{}.{}={:#x} # {:#x}\n", lib_prefix, cls_prefix, ep, cls->Id()); + show_class = false; + } + of << std::format("f method.{}.{}.{}={:#x}\n", lib_prefix, cls_prefix, name.c_str(), ep); + if (dartFn->HasMorphicCode()) { + of << std::format("f method.{}.{}.{}.miss={:#x}\n", lib_prefix, cls_prefix, name.c_str(), + dartFn->PayloadAddress()); + of << std::format("f method.{}.{}.{}.check={:#x}\n", lib_prefix, cls_prefix, name.c_str(), + dartFn->MonomorphicAddress()); + } + } + show_class = true; + } + show_library = true; + } +} + void DartDumper::Dump4Ida(std::filesystem::path outDir) { std::filesystem::create_directory(outDir); @@ -842,4 +891,4 @@ void DartDumper::DumpObjects(const char* filename) of << dumpInstance(obj, simpleForm, nestedObj, 0); of << "\n\n"; } -} \ No newline at end of file +} diff --git a/blutter/src/DartDumper.h b/blutter/src/DartDumper.h index e1d2107..76ecaf2 100644 --- a/blutter/src/DartDumper.h +++ b/blutter/src/DartDumper.h @@ -8,6 +8,7 @@ class DartDumper DartDumper(DartApp& app) : app(app) {}; void Dump4Ida(std::filesystem::path outDir); + void Dump4Radare2(std::filesystem::path outDir); std::vector> DumpStructHeaderFile(std::string outFile); diff --git a/blutter/src/main.cpp b/blutter/src/main.cpp index 6aa46fd..98b7cae 100644 --- a/blutter/src/main.cpp +++ b/blutter/src/main.cpp @@ -52,6 +52,7 @@ int main(int argc, char** argv) #endif dumper.DumpCode((outDir / "asm").string().c_str()); dumper.Dump4Ida(outDir / "ida_script"); + dumper.Dump4Radare2(outDir / "r2_script"); std::cout << "Generating Frida script\n"; FridaWriter fwriter{ app }; @@ -78,4 +79,4 @@ int main(int argc, char** argv) } return 0; -} \ No newline at end of file +} From 28ded8b287692ae3898b6faee7016621a2592d07 Mon Sep 17 00:00:00 2001 From: pancake Date: Wed, 19 Jun 2024 17:50:36 +0200 Subject: [PATCH 2/7] Avoid using - and + in flagnames --- blutter/src/DartDumper.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/blutter/src/DartDumper.cpp b/blutter/src/DartDumper.cpp index ebae1e9..0431395 100644 --- a/blutter/src/DartDumper.cpp +++ b/blutter/src/DartDumper.cpp @@ -98,15 +98,21 @@ void DartDumper::Dump4Radare2(std::filesystem::path outDir) std::replace(lib_prefix.begin(), lib_prefix.end(), '$', '_'); std::replace(lib_prefix.begin(), lib_prefix.end(), '&', '_'); + std::replace(lib_prefix.begin(), lib_prefix.end(), '-', '_'); + std::replace(lib_prefix.begin(), lib_prefix.end(), '+', '_'); for (auto cls : lib->classes) { std::string cls_prefix = cls->Name(); std::replace(cls_prefix.begin(), cls_prefix.end(), '$', '_'); std::replace(cls_prefix.begin(), cls_prefix.end(), '&', '_'); + std::replace(cls_prefix.begin(), cls_prefix.end(), '-', '_'); + std::replace(cls_prefix.begin(), cls_prefix.end(), '+', '_'); for (auto dartFn : cls->Functions()) { const auto ep = dartFn->Address(); auto name = getFunctionName4Ida(*dartFn, cls_prefix); std::replace(name.begin(), name.end(), '$', '_'); std::replace(name.begin(), name.end(), '&', '_'); + std::replace(name.begin(), name.end(), '-', '_'); + std::replace(name.begin(), name.end(), '+', '_'); if (show_library) { of << std::format("CC Library({:#x}) = {} @ {}\n", lib->id, lib_prefix, ep); of << std::format("f lib.{}={:#x} # {:#x}\n", lib_prefix, ep, lib->id); From 85d8e029cba3e9a70a207dc5a2b8368f3b948044 Mon Sep 17 00:00:00 2001 From: pancake Date: Wed, 18 Sep 2024 14:04:12 +0200 Subject: [PATCH 3/7] Register flags for the constant pool --- blutter/src/DartDumper.cpp | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/blutter/src/DartDumper.cpp b/blutter/src/DartDumper.cpp index 0431395..f6200de 100644 --- a/blutter/src/DartDumper.cpp +++ b/blutter/src/DartDumper.cpp @@ -82,6 +82,40 @@ static std::string getFunctionName4Ida(const DartFunction& dartFn, const std::st return prefix + fnName; } +static bool is_valid_char(const char ch) { + if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || isdigit(ch)) { + return true; + } + switch (ch) { + case '(': + case ')': + case '[': + case ']': + case '<': + case '+': + case '-': + case '>': + case '$': + case '%': + case '@': + case '.': + case ',': + case ':': + case '_': + return true; + default: + return false; + } +} + +static void filterString(std::string &str) { + for (char& ch : str) { + if (!is_valid_char(ch)) { + ch = '_'; + } + } +} + void DartDumper::Dump4Radare2(std::filesystem::path outDir) { std::filesystem::create_directory(outDir); @@ -135,6 +169,16 @@ void DartDumper::Dump4Radare2(std::filesystem::path outDir) } show_library = true; } + of << "f pptr=x27\n"; // TODO: hardcoded value + auto comments = DumpStructHeaderFile((outDir / "r2_dart_struct.h").string()); + for (const auto& [offset, comment] : comments) { + if (comment.find("String:") != -1) { + std::string flagFromComment = comment; + filterString(flagFromComment); + of << "f pp." << flagFromComment << "=pptr+" << offset << "\n"; + of << "'@0x0+" << offset << "'CC " << comment << "\n"; + } + } } void DartDumper::Dump4Ida(std::filesystem::path outDir) From b30d7ed6b04209db45b298ca72cf4639c36db417 Mon Sep 17 00:00:00 2001 From: Axelle Date: Fri, 26 Jul 2024 09:40:46 +0200 Subject: [PATCH 4/7] fixes the issue where some Dart functions were missing in the Radare2 addNames.r2 script see merge request #67 --- blutter/src/DartDumper.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/blutter/src/DartDumper.cpp b/blutter/src/DartDumper.cpp index f6200de..f659247 100644 --- a/blutter/src/DartDumper.cpp +++ b/blutter/src/DartDumper.cpp @@ -87,19 +87,7 @@ static bool is_valid_char(const char ch) { return true; } switch (ch) { - case '(': - case ')': - case '[': - case ']': - case '<': - case '+': - case '-': - case '>': - case '$': - case '%': - case '@': case '.': - case ',': case ':': case '_': return true; @@ -169,6 +157,21 @@ void DartDumper::Dump4Radare2(std::filesystem::path outDir) } show_library = true; } + for (auto& item : app.stubs) { + auto stub = item.second; + const auto ep = stub->Address(); + std::string name = stub->FullName(); + std::replace(name.begin(), name.end(), '<', '_'); + std::replace(name.begin(), name.end(), '>', '_'); + std::replace(name.begin(), name.end(), ',', '_'); + std::replace(name.begin(), name.end(), ' ', '_'); + std::replace(name.begin(), name.end(), '$', '_'); + std::replace(name.begin(), name.end(), '&', '_'); + std::replace(name.begin(), name.end(), '-', '_'); + std::replace(name.begin(), name.end(), '+', '_'); + of << std::format("f method.stub.{}={:#x}\n", name.c_str(), ep); + } + of << "f pptr=x27\n"; // TODO: hardcoded value auto comments = DumpStructHeaderFile((outDir / "r2_dart_struct.h").string()); for (const auto& [offset, comment] : comments) { From afe91055b8b8f8f949141726fee9e530272654dc Mon Sep 17 00:00:00 2001 From: cryptax Date: Fri, 9 Aug 2024 11:40:49 +0200 Subject: [PATCH 5/7] some methods have the same name. To differentiate them, adding the offset in the name --- blutter/src/DartDumper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blutter/src/DartDumper.cpp b/blutter/src/DartDumper.cpp index f659247..d7f661a 100644 --- a/blutter/src/DartDumper.cpp +++ b/blutter/src/DartDumper.cpp @@ -145,7 +145,7 @@ void DartDumper::Dump4Radare2(std::filesystem::path outDir) of << std::format("f class.{}.{}={:#x} # {:#x}\n", lib_prefix, cls_prefix, ep, cls->Id()); show_class = false; } - of << std::format("f method.{}.{}.{}={:#x}\n", lib_prefix, cls_prefix, name.c_str(), ep); + of << std::format("f method.{}.{}.{}_{:x}={:#x}\n", lib_prefix, cls_prefix, name.c_str(), ep, ep); if (dartFn->HasMorphicCode()) { of << std::format("f method.{}.{}.{}.miss={:#x}\n", lib_prefix, cls_prefix, name.c_str(), dartFn->PayloadAddress()); @@ -169,7 +169,7 @@ void DartDumper::Dump4Radare2(std::filesystem::path outDir) std::replace(name.begin(), name.end(), '&', '_'); std::replace(name.begin(), name.end(), '-', '_'); std::replace(name.begin(), name.end(), '+', '_'); - of << std::format("f method.stub.{}={:#x}\n", name.c_str(), ep); + of << std::format("f method.stub.{}_{:x}={:#x}\n", name.c_str(), ep, ep); } of << "f pptr=x27\n"; // TODO: hardcoded value From 340df50bbe32f376edf32109a34d6fba428ce1ae Mon Sep 17 00:00:00 2001 From: cryptax Date: Fri, 9 Aug 2024 12:09:26 +0200 Subject: [PATCH 6/7] fixing names with ? --- blutter/src/DartDumper.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/blutter/src/DartDumper.cpp b/blutter/src/DartDumper.cpp index d7f661a..366d013 100644 --- a/blutter/src/DartDumper.cpp +++ b/blutter/src/DartDumper.cpp @@ -135,6 +135,7 @@ void DartDumper::Dump4Radare2(std::filesystem::path outDir) std::replace(name.begin(), name.end(), '&', '_'); std::replace(name.begin(), name.end(), '-', '_'); std::replace(name.begin(), name.end(), '+', '_'); + std::replace(name.begin(), name.end(), '?', '_'); if (show_library) { of << std::format("CC Library({:#x}) = {} @ {}\n", lib->id, lib_prefix, ep); of << std::format("f lib.{}={:#x} # {:#x}\n", lib_prefix, ep, lib->id); @@ -169,6 +170,7 @@ void DartDumper::Dump4Radare2(std::filesystem::path outDir) std::replace(name.begin(), name.end(), '&', '_'); std::replace(name.begin(), name.end(), '-', '_'); std::replace(name.begin(), name.end(), '+', '_'); + std::replace(name.begin(), name.end(), '?', '_'); of << std::format("f method.stub.{}_{:x}={:#x}\n", name.c_str(), ep, ep); } From 241bd25a1dbb00d190cffb3bb040d474ebfc64c9 Mon Sep 17 00:00:00 2001 From: pancake Date: Sat, 21 Sep 2024 19:22:04 +0200 Subject: [PATCH 7/7] Clean code, require latest r2 from git and add class+method info --- blutter/src/DartDumper.cpp | 62 +++++++++++++++----------------------- 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/blutter/src/DartDumper.cpp b/blutter/src/DartDumper.cpp index 366d013..c2db1e9 100644 --- a/blutter/src/DartDumper.cpp +++ b/blutter/src/DartDumper.cpp @@ -110,6 +110,7 @@ void DartDumper::Dump4Radare2(std::filesystem::path outDir) std::ofstream of((outDir / "addNames.r2").string()); of << "# create flags for libraries, classes and methods\n"; + of << "e emu.str=true\n"; of << std::format("f app.base = {:#x}\n", app.base()); of << std::format("f app.heap_base = {:#x}\n", app.heap_base()); @@ -117,41 +118,33 @@ void DartDumper::Dump4Radare2(std::filesystem::path outDir) bool show_class = true; for (auto lib : app.libs) { std::string lib_prefix = lib->GetName(); - - std::replace(lib_prefix.begin(), lib_prefix.end(), '$', '_'); - std::replace(lib_prefix.begin(), lib_prefix.end(), '&', '_'); - std::replace(lib_prefix.begin(), lib_prefix.end(), '-', '_'); - std::replace(lib_prefix.begin(), lib_prefix.end(), '+', '_'); + filterString(lib_prefix); for (auto cls : lib->classes) { std::string cls_prefix = cls->Name(); - std::replace(cls_prefix.begin(), cls_prefix.end(), '$', '_'); - std::replace(cls_prefix.begin(), cls_prefix.end(), '&', '_'); - std::replace(cls_prefix.begin(), cls_prefix.end(), '-', '_'); - std::replace(cls_prefix.begin(), cls_prefix.end(), '+', '_'); + filterString(cls_prefix); for (auto dartFn : cls->Functions()) { const auto ep = dartFn->Address(); - auto name = getFunctionName4Ida(*dartFn, cls_prefix); - std::replace(name.begin(), name.end(), '$', '_'); - std::replace(name.begin(), name.end(), '&', '_'); - std::replace(name.begin(), name.end(), '-', '_'); - std::replace(name.begin(), name.end(), '+', '_'); - std::replace(name.begin(), name.end(), '?', '_'); + std::string name = getFunctionName4Ida(*dartFn, cls_prefix); + filterString(name); if (show_library) { - of << std::format("CC Library({:#x}) = {} @ {}\n", lib->id, lib_prefix, ep); - of << std::format("f lib.{}={:#x} # {:#x}\n", lib_prefix, ep, lib->id); + of << std::format("'@{:#x}'CC Library({:#x}) = {}\n", ep, lib->id, lib->GetName()); + of << std::format("'@{:#x}'f lib.{}\n", ep, lib_prefix); show_library = false; } if (show_class) { - of << std::format("CC Class({:#x}) = {} @ {}\n", cls->Id(), cls_prefix, ep); - of << std::format("f class.{}.{}={:#x} # {:#x}\n", lib_prefix, cls_prefix, ep, cls->Id()); + of << std::format("'@{:#x}'CC Class({:#x}) = {}\n", ep, cls->Id(), cls->Name()); + of << std::format("'@{:#x}'f class.{}.{}\n", ep, lib_prefix, cls_prefix); show_class = false; } - of << std::format("f method.{}.{}.{}_{:x}={:#x}\n", lib_prefix, cls_prefix, name.c_str(), ep, ep); + of << std::format("'@{:#x}'f method.{}.{}.{}\n", ep, lib_prefix, cls_prefix, name); + of << std::format("'@{:#x}'ic+{}.{}\n", ep, cls_prefix, name); if (dartFn->HasMorphicCode()) { - of << std::format("f method.{}.{}.{}.miss={:#x}\n", lib_prefix, cls_prefix, name.c_str(), - dartFn->PayloadAddress()); - of << std::format("f method.{}.{}.{}.check={:#x}\n", lib_prefix, cls_prefix, name.c_str(), - dartFn->MonomorphicAddress()); + of << std::format("'@{:#x}'f method.{}.{}.{}.miss\n", + dartFn->PayloadAddress(), + lib_prefix, cls_prefix, name); + of << std::format("'@{:#x}'f method.{}.{}.{}.check\n", + dartFn->MonomorphicAddress(), + lib_prefix, cls_prefix, name); } } show_class = true; @@ -162,26 +155,19 @@ void DartDumper::Dump4Radare2(std::filesystem::path outDir) auto stub = item.second; const auto ep = stub->Address(); std::string name = stub->FullName(); - std::replace(name.begin(), name.end(), '<', '_'); - std::replace(name.begin(), name.end(), '>', '_'); - std::replace(name.begin(), name.end(), ',', '_'); - std::replace(name.begin(), name.end(), ' ', '_'); - std::replace(name.begin(), name.end(), '$', '_'); - std::replace(name.begin(), name.end(), '&', '_'); - std::replace(name.begin(), name.end(), '-', '_'); - std::replace(name.begin(), name.end(), '+', '_'); - std::replace(name.begin(), name.end(), '?', '_'); - of << std::format("f method.stub.{}_{:x}={:#x}\n", name.c_str(), ep, ep); + std::string flagName = name; + filterString(flagName); + of << std::format("'@{:#x}'f method.stub.{}\n", ep, flagName); } - - of << "f pptr=x27\n"; // TODO: hardcoded value + of << "dr x27=`e anal.gp`\n"; + of << "'f PP=x27\n"; auto comments = DumpStructHeaderFile((outDir / "r2_dart_struct.h").string()); for (const auto& [offset, comment] : comments) { if (comment.find("String:") != -1) { std::string flagFromComment = comment; filterString(flagFromComment); - of << "f pp." << flagFromComment << "=pptr+" << offset << "\n"; - of << "'@0x0+" << offset << "'CC " << comment << "\n"; + of << "f pp." << flagFromComment << "=PP+" << offset << "\n"; + of << "'@PP+" << offset << "'CC " << comment << "\n"; } } }