Compare commits

...

10 Commits

Author SHA1 Message Date
4420fee251 Adding some more parsing 2022-12-01 01:25:48 +03:00
24917a40ab Filled ClassId enum 2022-11-30 00:06:19 +03:00
59e8789455 Merge branch 'master' of https://bitbucket.org/green-caterpillar/unflutter 2022-11-29 23:36:44 +03:00
fdaf533bca Removing hardcoded elf path 2022-11-29 23:25:28 +03:00
Selim Mustafaev
cfd527fb54 Adding ClassId enum 2022-11-29 20:01:13 +03:00
Selim Mustafaev
5ec1117337 Fix building on macOS.
Adding LEB128 reader class.
2022-11-28 20:46:19 +03:00
2a6e45b05d Add reader and snapshot classes 2022-11-27 23:59:00 +03:00
9cc38354d7 last changes 2022-11-27 12:49:38 +03:00
328703ac5f dump elf info 2022-11-27 01:18:03 +03:00
cabd4abe7f packing header struct 2022-11-26 11:20:01 +03:00
11 changed files with 557 additions and 70 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
.idea/
cmake-build-debug/

View File

@ -3,6 +3,6 @@ project(unflutter)
set(CMAKE_CXX_STANDARD 20)
add_executable(unflutter main.cpp dart/dart.h)
add_executable(unflutter main.cpp dart/Reader.cpp dart/Reader.h dart/Snapshot.cpp dart/Snapshot.h dart/Leb128Int.cpp dart/Leb128Int.h dart/ClassId.h)
target_include_directories(unflutter PRIVATE ${CMAKE_SOURCE_DIR}/ThirdParty)

170
dart/ClassId.h Normal file
View File

@ -0,0 +1,170 @@
//
// Created by Selim Mustafaev on 29.11.2022.
//
#ifndef UNFLUTTER_CLASSID_H
#define UNFLUTTER_CLASSID_H
namespace Dart {
enum class ClassId: uint64_t {
Illegal = 0,
NativePointer = 1,
FreeListElement = 2,
ForwardingCorpse = 3,
Object = 4,
Class = 5,
PatchClass = 6,
Function = 7,
TypeParameters = 8,
ClosureData = 9,
FfiTrampolineData = 10,
Field = 11,
Script = 12,
Library = 13,
Namespace = 14,
KernelProgramInfo = 15,
WeakSerializationReference = 16,
Code = 17,
Instructions = 18,
InstructionsSection = 19,
InstructionsTable = 20,
ObjectPool = 21,
PcDescriptors = 22,
CodeSourceMap = 23,
CompressedStackMaps = 24,
LocalVarDescriptors = 25,
ExceptionHandlers = 26,
Context = 27,
ContextScope = 28,
Sentinel = 29,
SingleTargetCache = 30,
UnlinkedCall = 31,
MonomorphicSmiableCall = 32,
CallSiteData = 33,
ICData = 34,
MegamorphicCache = 35,
SubtypeTestCache = 36,
LoadingUnit = 37,
Error = 38,
ApiError = 39,
LanguageError = 40,
UnhandledException = 41,
UnwindError = 42,
Instance = 43,
LibraryPrefix = 44,
TypeArguments = 45,
AbstractType = 46,
Type = 47,
FunctionType = 48,
TypeRef = 49,
TypeParameter = 50,
Closure = 51,
Number = 52,
Integer = 53,
Smi = 54,
Mint = 55,
Double = 56,
Bool = 57,
Float32x4 = 58,
Int32x4 = 59,
Float64x2 = 60,
TypedDataBase = 61,
TypedData = 62,
ExternalTypedData = 63,
TypedDataView = 64,
Pointer = 65,
DynamicLibrary = 66,
Capability = 67,
ReceivePort = 68,
SendPort = 69,
StackTrace = 70,
RegExp = 71,
WeakProperty = 72,
MirrorReference = 73,
FutureOr = 74,
UserTag = 75,
TransferableTypedData = 76,
LinkedHashMap = 77,
ImmutableLinkedHashMap = 78,
LinkedHashSet = 79,
ImmutableLinkedHashSet = 80,
Array = 81,
ImmutableArray = 82,
GrowableObjectArray = 83,
String = 84,
OneByteString = 85,
TwoByteString = 86,
ExternalOneByteString = 87,
ExternalTwoByteString = 88,
kFfiNativeFunctionCid = 89,
FfiInt8 = 90,
FfiInt16 = 91,
FfiInt32 = 92,
FfiInt64 = 93,
FfiUint8 = 94,
FfiUint16 = 95,
FfiUint32 = 96,
FfiUint64 = 97,
FfiIntPtr = 98,
FfiFloat = 99,
FfiDouble = 100,
FfiVoid = 101,
FfiHandle = 102,
FfiBool = 103,
FfiNativeType = 104,
FfiStruct = 105,
TypedDataInt8Array = 106,
TypedDataInt8ArrayView = 107,
ExternalTypedDataInt8Array = 108,
TypedDataUint8Array = 109,
TypedDataUint8ArrayView = 110,
ExternalTypedDataUint8Array = 111,
TypedDataUint8ClampedArray = 112,
TypedDataUint8ClampedArrayView = 113,
ExternalTypedDataUint8ClampedArray = 114,
TypedDataInt16Array = 115,
TypedDataInt16ArrayView = 116,
ExternalTypedDataInt16Array = 117,
TypedDataUint16Array = 118,
TypedDataUint16ArrayView = 119,
ExternalTypedDataUint16Array = 120,
TypedDataInt32Array = 121,
TypedDataInt32ArrayView = 122,
ExternalTypedDataInt32Array = 123,
TypedDataUint32Array = 124,
TypedDataUint32ArrayView = 125,
ExternalTypedDataUint32Array = 126,
TypedDataInt64Array = 127,
TypedDataInt64ArrayView = 128,
ExternalTypedDataInt64Array = 129,
TypedDataUint64Array = 130,
TypedDataUint64ArrayView = 131,
ExternalTypedDataUint64Array = 132,
TypedDataFloat32Array = 133,
TypedDataFloat32ArrayView = 134,
ExternalTypedDataFloat32Array = 135,
TypedDataFloat64Array = 136,
TypedDataFloat64ArrayView = 137,
ExternalTypedDataFloat64Array = 138,
TypedDataFloat32x4Array = 139,
TypedDataFloat32x4ArrayView = 140,
ExternalTypedDataFloat32x4Array = 141,
TypedDataInt32x4Array = 142,
TypedDataInt32x4ArrayView = 143,
ExternalTypedDataInt32x4Array = 144,
TypedDataFloat64x2Array = 145,
TypedDataFloat64x2ArrayView = 146,
ExternalTypedDataFloat64x2Array = 147,
ByteDataView = 148,
ByteBuffer = 149,
Null = 150,
Dynamic = 151,
Void = 152,
Never = 153,
NumPredefined = 154
};
}
#endif //UNFLUTTER_CLASSID_H

36
dart/Leb128Int.cpp Normal file
View File

@ -0,0 +1,36 @@
//
// Created by Selim Mustafaev on 28.11.2022.
//
#include "Leb128Int.h"
namespace Dart {
Leb128Int::Leb128Int(): _value(0), _size(0) {
}
Dart::Leb128Int::Leb128Int(const std::byte* ptr): _value(0), _size(0) {
size_t bitShift = 0;
auto data = reinterpret_cast<const uint8_t*>(ptr);
while (*data < 0x80) {
_value |= (*data << bitShift);
bitShift += 7;
data++;
_size++;
}
_value |= ((*data & 0x7f) << bitShift);
_size++;
}
uint64_t Leb128Int::value() const {
return _value;
}
size_t Leb128Int::size() const {
return _size;
}
}

28
dart/Leb128Int.h Normal file
View File

@ -0,0 +1,28 @@
//
// Created by Selim Mustafaev on 28.11.2022.
//
#ifndef UNFLUTTER_LEB128INT_H
#define UNFLUTTER_LEB128INT_H
#include <cstdint>
#include <cstdio>
#include <cstddef>
namespace Dart {
class Leb128Int {
private:
uint64_t _value;
size_t _size;
public:
Leb128Int();
explicit Leb128Int(const std::byte* ptr);
[[nodiscard]] uint64_t value() const;
[[nodiscard]] size_t size() const;
};
}
#endif //UNFLUTTER_LEB128INT_H

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 "elfio/elf_types.hpp"
#include <fstream>
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;
ELFIO::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

129
dart/Snapshot.cpp Normal file
View File

@ -0,0 +1,129 @@
//
// Created by selim on 27.11.22.
//
#include "Snapshot.h"
#include "ClassId.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() + 1;
_features = split(features);
_baseObjectsCount = Leb128Int(data);
data += _baseObjectsCount.size();
_allObjectsCount = Leb128Int(data);
data += _allObjectsCount.size();
_clustersCount = Leb128Int(data);
data += _clustersCount.size();
_fieldTableLength = Leb128Int(data);
data += _fieldTableLength.size();
_instructionsTableLength = Leb128Int(data);
data += _instructionsTableLength.size();
uint64_t cidAndCanonical = *(uint64_t*)data;
uint64_t cid = (cidAndCanonical >> 1) & 0xFFFFFFFF;
bool canonical = cidAndCanonical & 1;
// If non-predefined (instance) cid
if (cid >= (uint64_t)ClassId::NumPredefined || cid == (uint64_t)ClassId::Instance) {
}
auto nextInt = Leb128Int(data);
auto val = nextInt.value();
auto size = nextInt.size();
}
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::FULL_CORE: return "Full core";
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();
}
std::vector<std::string> Snapshot::split(const std::string &str) {
std::vector<std::string> result;
std::stringstream ss(str);
std::string item;
while (std::getline (ss, item, ' ')) {
result.push_back (item);
}
return result;
}
uint64_t Snapshot::baseObjectsCount() const {
return _baseObjectsCount.value();
}
uint64_t Snapshot::allObjectsCount() const {
return _allObjectsCount.value();
}
uint64_t Snapshot::clustersCount() const {
return _clustersCount.value();
}
uint64_t Snapshot::fieldTableLength() const {
return _fieldTableLength.value();
}
uint64_t Snapshot::instructionsTableLength() const {
return _instructionsTableLength.value();
}
}

55
dart/Snapshot.h Normal file
View File

@ -0,0 +1,55 @@
//
// Created by selim on 27.11.22.
//
#ifndef UNFLUTTER_SNAPSHOT_H
#define UNFLUTTER_SNAPSHOT_H
#include "Leb128Int.h"
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>
namespace Dart {
class Snapshot {
public:
enum class Kind: uint64_t {
FULL, FULL_CORE, FULL_JIT, FULL_AOT, 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;
Leb128Int _baseObjectsCount;
Leb128Int _allObjectsCount;
Leb128Int _clustersCount;
Leb128Int _fieldTableLength;
Leb128Int _instructionsTableLength;
private:
static std::vector<std::string> split(const std::string &str);
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;
[[nodiscard]] uint64_t baseObjectsCount() const;
[[nodiscard]] uint64_t allObjectsCount() const;
[[nodiscard]] uint64_t clustersCount() const;
[[nodiscard]] uint64_t fieldTableLength() const;
[[nodiscard]] uint64_t instructionsTableLength() const;
};
}
#endif //UNFLUTTER_SNAPSHOT_H

View File

@ -1,30 +0,0 @@
//
// Created by selim on 21.11.22.
//
#ifndef UNFLUTTER_DART_H
#define UNFLUTTER_DART_H
#include <cstdint>
#include <array>
const int32_t DART_MAGIC = 0xdcdcf5f5;
enum class SnaphotKind: uint64_t {
FULL,
FULL_JIT,
FULL_AOT,
MESSAGE,
NONE,
INVALID
};
struct SnapshotHeader {
uint32_t magic;
uint32_t size;
uint32_t size2;
SnaphotKind kind;
std::array<char8_t, 32> versionHash;
};
#endif //UNFLUTTER_DART_H

View File

@ -1,46 +1,19 @@
#include "ThirdParty/elfio/elfio.hpp"
#include "dart/dart.h"
#include "dart/Reader.h"
#include <iostream>
int main(int argc, char** argv) {
std::string elfPath = "/home/selim/Downloads/libapp.so"; //argv[1];
std::cout << "Analyzing file: " << elfPath << std::endl;
Dart::Reader reader(argv[1]);
auto snapshot = reader.getSnapshot(Dart::DartSnapshot::ISOLATE_DATA);
ELFIO::elfio reader;
if(!reader.load(elfPath)) {
std::cout << "error loading elf: " << elfPath << std::endl;
return 0;
}
const void* data = nullptr;
const void* text = nullptr;
ELFIO::Elf_Half sec_num = reader.sections.size();
std::cout << "Number of sections: " << sec_num << std::endl;
for ( int i = 0; i < sec_num; ++i ) {
const ELFIO::section* psec = reader.sections[i];
std::cout << " [" << i << "] "
<< psec->get_name()
<< "\t"
<< psec->get_size()
<< std::endl;
if(psec->get_name() == ".rodata") {
data = psec->get_data();
}
if(psec->get_name() == ".text") {
text = psec->get_data();
}
}
auto header = reinterpret_cast<const SnapshotHeader*>(data);
if(header->magic != DART_MAGIC) {
std::cout << "Wrong magic!!!!" << std::endl;
}
auto sizer = __builtin_bswap32(header->size);
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;
std::cout << "Base objects: " << snapshot.baseObjectsCount() << std::endl;
std::cout << "All objects: " << snapshot.allObjectsCount() << std::endl;
std::cout << "Clusters: " << snapshot.clustersCount() << std::endl;
std::cout << "Field table length: " << snapshot.fieldTableLength() << std::endl;
std::cout << "Instructions table length: " << snapshot.instructionsTableLength() << std::endl;
return 0;
}