feat: add built-in magicblob parser support.

This commit is contained in:
2025-03-01 00:43:39 +08:00
parent 7de3b20a6c
commit 761f3a6d7f
3 changed files with 116 additions and 0 deletions

View File

@@ -0,0 +1,70 @@
#include "magic_blob.h"
#define XXH_INLINE_ALL
#include "xxhash.h"
#ifndef HIDWORD
#define HIDWORD(x) (*((int32_t*)&(x) + 1))
#endif
// copy from ida F5.
constexpr uint64_t unk_hash(uint64_t a1) {
unsigned int v1; // eax
int v2; // edx
int64_t v3; // rdx
v1 = ((33
* ((4097 * HIDWORD(a1) + 2127912214)
^ ((unsigned int)(4097 * HIDWORD(a1) + 2127912214) >> 19)
^ 0xC761C23C)
+ 374761393)
<< 9)
^ (33
* ((4097 * HIDWORD(a1) + 2127912214)
^ ((unsigned int)(4097 * HIDWORD(a1) + 2127912214) >> 19)
^ 0xC761C23C)
- 369570787);
v2 = 33
* ((4097 * a1 + 2127912214)
^ ((unsigned int)(4097 * a1 + 2127912214) >> 19) ^ 0xC761C23C);
v3 = (((v2 + 374761393) << 9) ^ (v2 - 369570787))
+ 8 * (((v2 + 374761393) << 9) ^ (unsigned int)(v2 - 369570787))
- 42973499;
return (v3 ^ (((unsigned int)v3 ^ 0xB55A4F090000uLL) >> 16))
| ((((v1 + 8 * v1 - 42973499) & 0xFFFF0000)
^ (((v1 + 8 * v1 - 42973499) ^ 0xFFFFFFFFB55A4F09uLL) << 16))
<< 16);
}
namespace di::data_format {
void MagicBlob::read(const fs::path& path) {
StreamedIO::read(path);
m_stored_seed = eat<uint64_t>();
m_query_seed = unk_hash(m_stored_seed);
rva_t n_rva{};
while (next() != EOF) {
auto flags = eat_varint<uint64_t>();
auto rva = eat_varint<rva_t>();
auto hash = eat<hash_t>();
// see comments in magic_entry.h
n_rva += rva;
rva = n_rva;
m_entities.emplace(hash, std::make_unique<MagicEntry>(flags, rva));
}
}
MagicEntry const* MagicBlob::query(std::string_view symbol) const {
auto query_hash = XXH64(symbol.data(), symbol.size(), m_query_seed);
if (m_entities.contains(query_hash)) {
return m_entities.at(query_hash).get();
}
return nullptr;
}
} // namespace di::data_format

View File

@@ -0,0 +1,25 @@
#pragma once
#include "data_format/io/streamed_io.h"
#include "data_format/type/magic_entry.h"
namespace di::data_format {
class MagicBlob : public StreamedIO {
public:
void read(const fs::path& path) override;
constexpr size_t count() const { return m_entities.size(); }
MagicEntry const* query(std::string_view symbol) const;
private:
std::unordered_map<hash_t, std::unique_ptr<MagicEntry>> m_entities;
// MagicBlob uses a custom algorithm to transform the stored seed. When
// querying, you should use m_query_seed.
uint64_t m_stored_seed{};
uint64_t m_query_seed{};
};
} // namespace di::data_format

View File

@@ -0,0 +1,21 @@
#pragma once
namespace di {
struct MagicEntry {
std::bitset<64> flags;
// What is stored in the original format is not the RVA itself, but the
// difference with the previous entry (in MagicBlob, RVA is sorted from
// small to large)
// But here, we still store the "real" RVA.
rva_t rva;
// Do not put the original hash in the entry yet.
// hash_t hash;
constexpr bool is_function() { return flags[0]; }
constexpr bool _unk2() { return flags[1]; }
constexpr bool is_verbose() { return flags[2]; }
constexpr bool _unk4() { return flags[3]; }
};
} // namespace di