From 56048263708f7e08bdccd1bf858183460f8e6599 Mon Sep 17 00:00:00 2001 From: Redbeanw44602 Date: Mon, 24 Feb 2025 21:55:55 +0800 Subject: [PATCH] feat: add blob-extractor. --- BlobExtractor/.clang-format | 45 +++++++++++++++ BlobExtractor/.gitignore | 9 +++ BlobExtractor/README.md | 1 + BlobExtractor/src/main.cpp | 112 ++++++++++++++++++++++++++++++++++++ BlobExtractor/xmake.lua | 14 +++++ 5 files changed, 181 insertions(+) create mode 100644 BlobExtractor/.clang-format create mode 100644 BlobExtractor/.gitignore create mode 100644 BlobExtractor/README.md create mode 100644 BlobExtractor/src/main.cpp create mode 100644 BlobExtractor/xmake.lua diff --git a/BlobExtractor/.clang-format b/BlobExtractor/.clang-format new file mode 100644 index 0000000..d3ead11 --- /dev/null +++ b/BlobExtractor/.clang-format @@ -0,0 +1,45 @@ +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: BlockIndent +AlignArrayOfStructures: Left +AlignConsecutiveDeclarations: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: true + PadOperators: true +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowAllArgumentsOnNextLine: false +AlignOperands: AlignAfterOperator +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AllowShortLambdasOnASingleLine: All +AllowShortBlocksOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: AllIfsAndElse +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakTemplateDeclarations: "Yes" +BinPackArguments: false +BinPackParameters: false +BreakBeforeBraces: Custom +BreakBeforeBinaryOperators: NonAssignment +CommentPragmas: "^ IWYU pragma:" +ConstructorInitializerIndentWidth: 0 +IndentWidth: 4 +Language: Cpp +MaxEmptyLinesToKeep: 2 +PackConstructorInitializers: CurrentLine +PointerAlignment: Left +TabWidth: 4 +UseTab: Never +SortIncludes: CaseSensitive diff --git a/BlobExtractor/.gitignore b/BlobExtractor/.gitignore new file mode 100644 index 0000000..bfbcbbf --- /dev/null +++ b/BlobExtractor/.gitignore @@ -0,0 +1,9 @@ +# VSCode +.vscode + +# XMake +.xmake +build + +# ClangD +.cache diff --git a/BlobExtractor/README.md b/BlobExtractor/README.md new file mode 100644 index 0000000..6daceb5 --- /dev/null +++ b/BlobExtractor/README.md @@ -0,0 +1 @@ +# BlobExtractor diff --git a/BlobExtractor/src/main.cpp b/BlobExtractor/src/main.cpp new file mode 100644 index 0000000..d69192f --- /dev/null +++ b/BlobExtractor/src/main.cpp @@ -0,0 +1,112 @@ +#include +#include +#include +#include +#include + +#define XXH_INLINE_ALL +#include "xxhash.h" + +class File : public std::ifstream { +public: + using std::ifstream::basic_ifstream; + + template + inline T read() { + T value; + std::ifstream::read((char*)&value, sizeof(T)); + return value; + } + + template + inline T read_varint() { + T res = 0; + int shift = 0; + while (true) { + auto byte = std::ifstream::get(); + res |= static_cast(byte & 0x7F) << shift; + if ((byte & 0x80) == 0) break; + shift += 7; + } + return res; + } +}; + +#define HIDWORD(x) (*((int32_t*)&(x) + 1)) + +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); +} + +struct Entry { + std::bitset<64> flags; + uint32_t rva; + uint64_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]; } +}; + +int main(int argc, char** argv) { + File data("bedrock_runtime_data", std::ios::binary); + + uint32_t t_rva{}; + auto record_seed = data.read(); + auto twin_seed = unk_hash(record_seed); + + std::println("Record seed: {:#x}", record_seed); + std::println("Twin seed: {:#x}", twin_seed); + + std::unordered_map map; + + while (data.peek() != EOF) { + Entry entry; + entry.flags = data.read_varint(); + entry.rva = data.read_varint(); + entry.hash = data.read(); + + t_rva += entry.rva; + entry.rva = t_rva; + + map.emplace(entry.hash, entry); + // entry.print_debug_string(); + } + + std::string_view test_query_name = "main"; + auto test_query_hash = + XXH64(test_query_name.data(), test_query_name.size(), twin_seed); + + if (map.contains(test_query_hash)) { + std::println("RVA of main(): {:#x}", map.at(test_query_hash).rva); + } else { + std::println("RVA of main(): INVALID."); + } + + return 0; +} diff --git a/BlobExtractor/xmake.lua b/BlobExtractor/xmake.lua new file mode 100644 index 0000000..b4a07de --- /dev/null +++ b/BlobExtractor/xmake.lua @@ -0,0 +1,14 @@ +add_rules('mode.debug', 'mode.release') + +add_requires('xxhash') + +target('blob-extractor') + set_kind('binary') + add_files('src/**.cpp') + add_includedirs('src') + set_warnings('all') + set_languages('c23', 'c++23') + + if is_mode('debug') then + add_defines('DEBUG') + end