diff --git a/CMakeLists.txt b/CMakeLists.txt index bdc6916..b02c113 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,6 @@ project(unflutter) set(CMAKE_CXX_STANDARD 20) -add_executable(unflutter main.cpp dart/dart.h dart/dart.cpp) +add_executable(unflutter main.cpp dart/Reader.cpp dart/Reader.h dart/Snapshot.cpp dart/Snapshot.h) target_include_directories(unflutter PRIVATE ${CMAKE_SOURCE_DIR}/ThirdParty) \ No newline at end of file diff --git a/dart/Reader.cpp b/dart/Reader.cpp new file mode 100644 index 0000000..df9a7ca --- /dev/null +++ b/dart/Reader.cpp @@ -0,0 +1,84 @@ +// +// Created by selim on 27.11.22. +// + +#include "Reader.h" +#include "elfio/elfio_dump.hpp" + +#include +#include + +namespace Dart { + + Reader::Reader(const fs::path& path) { + if(!fs::exists(path)) { + throw std::runtime_error("File does not exists"); + } + + if(!_elfio.load(path)) { + throw std::runtime_error("Failed to load ELF file"); + } + + auto size = fs::file_size(path); + _file = std::make_unique(size); + + std::ifstream stream(path, std::ios::binary); + stream.read(reinterpret_cast(_file.get()), static_cast(size)); + + if(stream.bad()) { + throw std::runtime_error("Error reading ELF file"); + } + } + + void Reader::dumpInfo() const { + ELFIO::dump::header( std::cout, _elfio ); + ELFIO::dump::section_headers( std::cout, _elfio ); + ELFIO::dump::segment_headers( std::cout, _elfio ); + ELFIO::dump::symbol_tables( std::cout, _elfio ); + ELFIO::dump::notes( std::cout, _elfio ); + ELFIO::dump::modinfo( std::cout, _elfio ); + ELFIO::dump::dynamic_tags( std::cout, _elfio ); + ELFIO::dump::section_datas( std::cout, _elfio ); + ELFIO::dump::segment_datas( std::cout, _elfio ); + } + + const std::byte *Reader::getSnapshotPtr(DartSnapshot snapshot) const { + auto snapshotName = getSnapshotName(snapshot); + + for(const auto& section: _elfio.sections) { + const ELFIO::symbol_section_accessor symbols(_elfio, section.get()); + for(size_t i = 0; i < symbols.get_symbols_num(); ++i) { + std::string name; + Elf64_Addr address; + ELFIO::Elf_Xword size; + ELFIO::Elf_Half section_index; + unsigned char bind, type, other; + symbols.get_symbol(i, name, address, size, bind, type, section_index, other ); + + if(name == snapshotName) { + return _file.get() + address; + } + } + } + + return nullptr; + } + + std::string Reader::getSnapshotName(DartSnapshot snapshot) { + switch (snapshot) { + case DartSnapshot::VM_INSTRUCTIONS: return "_kDartVmSnapshotInstructions"; + case DartSnapshot::VM_DATA: return "_kDartVmSnapshotData"; + case DartSnapshot::ISOLATE_INSTRUCTIONS: return "_kDartIsolateSnapshotInstructions"; + case DartSnapshot::ISOLATE_DATA: return "_kDartIsolateSnapshotData"; + case DartSnapshot::BUILD_ID: return "_kDartSnapshotBuildId"; + } + + return ""; + } + + Snapshot Reader::getSnapshot(DartSnapshot snapshot) const { + auto ptr = getSnapshotPtr(snapshot); + return Snapshot(ptr); + } + +} diff --git a/dart/Reader.h b/dart/Reader.h new file mode 100644 index 0000000..4e72234 --- /dev/null +++ b/dart/Reader.h @@ -0,0 +1,41 @@ +// +// Created by selim on 27.11.22. +// + +#ifndef UNFLUTTER_READER_H +#define UNFLUTTER_READER_H + +#include "elfio/elfio.hpp" +#include "Snapshot.h" +#include + +namespace fs = std::filesystem; + +namespace Dart { + + enum class DartSnapshot { + VM_INSTRUCTIONS, + VM_DATA, + ISOLATE_INSTRUCTIONS, + ISOLATE_DATA, + BUILD_ID + }; + + class Reader { + private: + ELFIO::elfio _elfio; + std::unique_ptr _file; + + private: + static std::string getSnapshotName(DartSnapshot snapshot) ; + + public: + explicit Reader(const fs::path& path); + void dumpInfo() const; + [[nodiscard]] const std::byte* getSnapshotPtr(DartSnapshot snapshot) const; + [[nodiscard]] Snapshot getSnapshot(DartSnapshot snapshot) const; + }; + +} + +#endif //UNFLUTTER_READER_H diff --git a/dart/Snapshot.cpp b/dart/Snapshot.cpp new file mode 100644 index 0000000..c54d3b7 --- /dev/null +++ b/dart/Snapshot.cpp @@ -0,0 +1,75 @@ +// +// Created by selim on 27.11.22. +// + +#include "Snapshot.h" +#include +#include +#include + +namespace Dart { + + Snapshot::Snapshot(const std::byte *data) { + _magic = *(uint32_t*)data; + data += sizeof(_magic); + + if(_magic != MAGIC) { + throw std::runtime_error("Snapshot magic mismatch"); + } + + _size = *(uint64_t*)data; + data += sizeof(_size); + + _kind = *(Kind*)data; + data += sizeof(Kind); + + _versionHash.assign((char*)data, 32); + data += _versionHash.size(); + + auto features = std::string((char*)data); + data += features.size(); + + auto view = features + | std::ranges::views::split(' ') + | std::ranges::views::transform([](auto &&rng) { + return std::string(&*rng.begin(), std::ranges::distance(rng)); + }); + + _features.assign(view.begin(), view.end()); + } + + uint64_t Snapshot::size() const { + return _size; + } + + std::string Snapshot::kindString() const { + switch (_kind) { + case Kind::FULL: return "Full"; + case Kind::FULL_JIT: return "Full JIT"; + case Kind::FULL_AOT: return "Full AOT"; + case Kind::MESSAGE: return "Message"; + case Kind::NONE: return "None"; + case Kind::INVALID: return "Invalid"; + } + + return ""; + } + + std::string Snapshot::versionHash() const { + return _versionHash; + } + + std::string Snapshot::featuresString() const { + std::stringstream ss; + size_t size = _features.size(); + for(size_t i = 0; i < size; ++i) { + ss << _features[i]; + if(i < size - 1) { + ss << ", "; + } + } + + return ss.str(); + } + +} diff --git a/dart/Snapshot.h b/dart/Snapshot.h new file mode 100644 index 0000000..4aa1183 --- /dev/null +++ b/dart/Snapshot.h @@ -0,0 +1,40 @@ +// +// Created by selim on 27.11.22. +// + +#ifndef UNFLUTTER_SNAPSHOT_H +#define UNFLUTTER_SNAPSHOT_H + +#include +#include +#include +#include + +namespace Dart { + + class Snapshot { + public: + enum class Kind: uint64_t { + FULL, FULL_JIT, FULL_AOT, MESSAGE, NONE, INVALID + }; + + static const uint32_t MAGIC = 0xDCDCF5F5; + + private: + uint32_t _magic; + uint64_t _size; + Kind _kind; + std::string _versionHash; + std::vector _features; + + public: + explicit Snapshot(const std::byte* data); + [[nodiscard]] uint64_t size() const; + [[nodiscard]] std::string kindString() const; + [[nodiscard]] std::string versionHash() const; + [[nodiscard]] std::string featuresString() const; + }; + +} + +#endif //UNFLUTTER_SNAPSHOT_H diff --git a/dart/dart.cpp b/dart/dart.cpp deleted file mode 100644 index c310f2b..0000000 --- a/dart/dart.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// -// Created by selim on 26.11.22. -// - -#include "dart.h" - -std::string snapshotKindString(SnapshotKind kind) { - switch (kind) { - case FULL: return "Full"; - case FULL_JIT: return "Full JIT"; - case FULL_AOT: return "Full AOT"; - case MESSAGE: return "Message"; - case NONE: return "None"; - case INVALID: return "Invalid"; - } -} \ No newline at end of file diff --git a/dart/dart.h b/dart/dart.h deleted file mode 100644 index ee12f4e..0000000 --- a/dart/dart.h +++ /dev/null @@ -1,40 +0,0 @@ -// -// Created by selim on 21.11.22. -// - -#ifndef UNFLUTTER_DART_H -#define UNFLUTTER_DART_H - -#include -#include -#include - -const uint32_t DART_MAGIC = 0xDCDCF5F5; - -const char* vmInstructions = "_kDartVmSnapshotInstructions"; -const char* vmData = "_kDartVmSnapshotData"; -const char* isolateInstructions = "_kDartIsolateSnapshotInstructions"; -const char* isolateData = "_kDartIsolateSnapshotData"; -const char* buildId = "_kDartSnapshotBuildId"; - -enum SnapshotKind: uint64_t { - FULL, - FULL_JIT, - FULL_AOT, - MESSAGE, - NONE, - INVALID -}; - -#pragma pack (1) -struct SnapshotHeader { - uint32_t magic; - int64_t size; - SnapshotKind kind; - std::array versionHash; -}; -#pragma pack () - -std::string snapshotKindString(SnapshotKind kind); - -#endif //UNFLUTTER_DART_H diff --git a/main.cpp b/main.cpp index 97add3d..f2d6457 100644 --- a/main.cpp +++ b/main.cpp @@ -1,86 +1,14 @@ -#include "ThirdParty/elfio/elfio.hpp" -#include "dart/dart.h" -#include "elfio/elfio_dump.hpp" - +#include "dart/Reader.h" #include -#include -#include - -void dumpElf(const ELFIO::elfio& reader) { - ELFIO::dump::header( std::cout, reader ); - ELFIO::dump::section_headers( std::cout, reader ); - ELFIO::dump::segment_headers( std::cout, reader ); - ELFIO::dump::symbol_tables( std::cout, reader ); - ELFIO::dump::notes( std::cout, reader ); - ELFIO::dump::modinfo( std::cout, reader ); - ELFIO::dump::dynamic_tags( std::cout, reader ); - ELFIO::dump::section_datas( std::cout, reader ); - ELFIO::dump::segment_datas( std::cout, reader ); -} int main(int argc, char** argv) { - std::string elfPath = "/home/selim/Загрузки/libapp.so"; //argv[1]; - std::cout << "Analyzing file: " << elfPath << std::endl; + Dart::Reader reader("/home/selim/Downloads/libapp.so"); + auto snapshot = reader.getSnapshot(Dart::DartSnapshot::VM_DATA); - ELFIO::elfio reader; - if(!reader.load(elfPath)) { - std::cout << "error loading elf: " << elfPath << std::endl; - return 0; - } - - dumpElf(reader); - - const std::byte* data = nullptr; - const std::byte* text = nullptr; - - for(auto section: reader.sections) { - - } - - ELFIO::Elf_Half sec_num = reader.sections.size(); - for ( int i = 0; i < sec_num; ++i ) { - ELFIO::section* psec = reader.sections[i]; - - if(psec->get_name() == ".rodata") { - data = reinterpret_cast(psec->get_data()); - } - - if(psec->get_name() == ".text") { - text = reinterpret_cast(psec->get_data()); - } - - auto sectionType = psec->get_type(); - if(sectionType == SHT_SYMTAB || sectionType == SHT_DYNSYM) { - const ELFIO::symbol_section_accessor symbols( reader, psec ); - for ( unsigned int j = 0; j < symbols.get_symbols_num(); ++j ) { - std::string name; - Elf64_Addr value; - ELFIO::Elf_Xword size; - unsigned char bind; - unsigned char type; - ELFIO::Elf_Half section_index; - unsigned char other; - symbols.get_symbol( j, name, value, size, bind, - type, section_index, other ); - std::cout << j << " " << name << " " << value << " (section " << section_index << ")" << std::endl; - } - } - } - - std::cout << "====================================================" << std::endl; - std::cout << "===== .rodata ======================================" << std::endl; - std::cout << std::endl; - - auto header = reinterpret_cast(data); - if(header->magic != DART_MAGIC) { - std::cout << "Wrong magic!!!!" << std::endl; - } - - std::cout << "Snapshot kind: " << snapshotKindString(header->kind) << std::endl; - std::cout << "Size: " << header->size << std::endl; - std::cout << std::endl; - - auto ptr = data + header->size + 4; + std::cout << "Snapshot kind: " << snapshot.kindString() << std::endl; + std::cout << "Size: " << snapshot.size() << std::endl; + std::cout << "Version hash: " << snapshot.versionHash() << std::endl; + std::cout << "Features: " << snapshot.featuresString() << std::endl; return 0; }