Add reader and snapshot classes

This commit is contained in:
Selim Mustafaev 2022-11-27 23:59:00 +03:00
parent 9cc38354d7
commit 2a6e45b05d
8 changed files with 248 additions and 136 deletions

View File

@ -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)

84
dart/Reader.cpp Normal file
View File

@ -0,0 +1,84 @@
//
// Created by selim on 27.11.22.
//
#include "Reader.h"
#include "elfio/elfio_dump.hpp"
#include <fstream>
#include <elf.h>
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<std::byte[]>(size);
std::ifstream stream(path, std::ios::binary);
stream.read(reinterpret_cast<char*>(_file.get()), static_cast<std::streamsize>(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);
}
}

41
dart/Reader.h Normal file
View File

@ -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 <filesystem>
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<std::byte[]> _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

75
dart/Snapshot.cpp Normal file
View File

@ -0,0 +1,75 @@
//
// Created by selim on 27.11.22.
//
#include "Snapshot.h"
#include <stdexcept>
#include <ranges>
#include <sstream>
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();
}
}

40
dart/Snapshot.h Normal file
View File

@ -0,0 +1,40 @@
//
// Created by selim on 27.11.22.
//
#ifndef UNFLUTTER_SNAPSHOT_H
#define UNFLUTTER_SNAPSHOT_H
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>
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<std::string> _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

View File

@ -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";
}
}

View File

@ -1,40 +0,0 @@
//
// Created by selim on 21.11.22.
//
#ifndef UNFLUTTER_DART_H
#define UNFLUTTER_DART_H
#include <cstdint>
#include <array>
#include <string>
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<char8_t, 32> versionHash;
};
#pragma pack ()
std::string snapshotKindString(SnapshotKind kind);
#endif //UNFLUTTER_DART_H

View File

@ -1,86 +1,14 @@
#include "ThirdParty/elfio/elfio.hpp"
#include "dart/dart.h"
#include "elfio/elfio_dump.hpp"
#include "dart/Reader.h"
#include <iostream>
#include <cstddef>
#include <elf.h>
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<const std::byte*>(psec->get_data());
}
if(psec->get_name() == ".text") {
text = reinterpret_cast<const std::byte*>(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<const SnapshotHeader*>(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;
}