Add reader and snapshot classes
This commit is contained in:
parent
9cc38354d7
commit
2a6e45b05d
@ -3,6 +3,6 @@ project(unflutter)
|
|||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
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)
|
target_include_directories(unflutter PRIVATE ${CMAKE_SOURCE_DIR}/ThirdParty)
|
||||||
84
dart/Reader.cpp
Normal file
84
dart/Reader.cpp
Normal 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
41
dart/Reader.h
Normal 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
75
dart/Snapshot.cpp
Normal 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
40
dart/Snapshot.h
Normal 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
|
||||||
@ -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";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
40
dart/dart.h
40
dart/dart.h
@ -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
|
|
||||||
86
main.cpp
86
main.cpp
@ -1,86 +1,14 @@
|
|||||||
#include "ThirdParty/elfio/elfio.hpp"
|
#include "dart/Reader.h"
|
||||||
#include "dart/dart.h"
|
|
||||||
#include "elfio/elfio_dump.hpp"
|
|
||||||
|
|
||||||
#include <iostream>
|
#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) {
|
int main(int argc, char** argv) {
|
||||||
std::string elfPath = "/home/selim/Загрузки/libapp.so"; //argv[1];
|
Dart::Reader reader("/home/selim/Downloads/libapp.so");
|
||||||
std::cout << "Analyzing file: " << elfPath << std::endl;
|
auto snapshot = reader.getSnapshot(Dart::DartSnapshot::VM_DATA);
|
||||||
|
|
||||||
ELFIO::elfio reader;
|
std::cout << "Snapshot kind: " << snapshot.kindString() << std::endl;
|
||||||
if(!reader.load(elfPath)) {
|
std::cout << "Size: " << snapshot.size() << std::endl;
|
||||||
std::cout << "error loading elf: " << elfPath << std::endl;
|
std::cout << "Version hash: " << snapshot.versionHash() << std::endl;
|
||||||
return 0;
|
std::cout << "Features: " << snapshot.featuresString() << std::endl;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user