From 2eb76beb1ab97c23efda1841ac90a04fc84fc159 Mon Sep 17 00:00:00 2001 From: HappyTanuki Date: Wed, 22 Apr 2026 17:19:26 +0000 Subject: [PATCH] payload analysis --- .clang-format | 8 ++++ CMakeLists.txt | 17 ++++---- include/objects.h | 57 +++++++++++++++++++++++++++ include/pch.h | 4 +- include/util/file.h | 6 +++ src/main.cc | 29 ++++++-------- src/objects.cc | 95 +++++++++++++++++++++++++++++++++++++++++++++ src/util/file.cc | 34 ++++++++++++++++ test/CMakeLists.txt | 2 +- 9 files changed, 223 insertions(+), 29 deletions(-) create mode 100644 .clang-format create mode 100644 include/objects.h create mode 100644 include/util/file.h create mode 100644 src/objects.cc create mode 100644 src/util/file.cc diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..3749ae7 --- /dev/null +++ b/.clang-format @@ -0,0 +1,8 @@ +# Google C/C++ Code Style Settings + +Language: Cpp +BasedOnStyle: Google +Standard: c++20 +IndentWidth: 2 +UseTab: Never +ColumnLimit: 80 \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index b97549d..fa5812d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,20 +44,19 @@ FetchContent_Declare( FetchContent_MakeAvailable(Encryption) # ============================================================ -# Target – Networking +# Target – Test # ============================================================ file(GLOB_RECURSE SOURCES "src/*.cc") -if (CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "DLL$") - add_executable(${SUB_PROJECT_NAME} ${SOURCES}) -else () - add_executable(${SUB_PROJECT_NAME} ${SOURCES}) -endif () +add_library(${SUB_PROJECT_NAME}_lib INTERFACE) -target_link_libraries(${SUB_PROJECT_NAME} PUBLIC ${ROOT_PROJECT_NAME}::Common) -target_link_libraries(${SUB_PROJECT_NAME} PUBLIC ${ROOT_PROJECT_NAME}::Encryption) +target_link_libraries(${SUB_PROJECT_NAME}_lib INTERFACE ${ROOT_PROJECT_NAME}::Common) +target_link_libraries(${SUB_PROJECT_NAME}_lib INTERFACE ${ROOT_PROJECT_NAME}::Encryption) -target_include_directories(${SUB_PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_include_directories(${SUB_PROJECT_NAME}_lib INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) + +add_executable(${SUB_PROJECT_NAME} ${SOURCES}) +target_link_libraries(${SUB_PROJECT_NAME} PUBLIC ${SUB_PROJECT_NAME}_lib) # ============================================================ # Compiler Options diff --git a/include/objects.h b/include/objects.h new file mode 100644 index 0000000..e369c07 --- /dev/null +++ b/include/objects.h @@ -0,0 +1,57 @@ +#pragma once +#include +#include +#include +#include + +template +struct ObjectInfo { + std::size_t GetSize() const { return sizeof(T); } + T data; +}; + +template <> +struct ObjectInfo { + std::size_t GetSize() const { return data.size(); } + std::size_t SetSize(std::size_t size) { + data.resize(size); + return data.size(); + } + + std::string data; +}; + +template <> +struct ObjectInfo> { + std::size_t GetSize() const { return data.size(); } + std::size_t SetSize(std::size_t size) { + data.resize(size); + return data.size(); + } + + std::vector data; +}; + +struct OLEObjectHeader { + ObjectInfo OLEVersion; + ObjectInfo FormatID; + ObjectInfo ClassName; + ObjectInfo TopicName; + ObjectInfo ItemName; +}; + +struct EmbededObject { + OLEObjectHeader Header; + ObjectInfo> NativeData; +}; + +struct LinkedObject {}; + +struct OLEObject { + OLEObjectHeader Header; + + std::unique_ptr EObject = nullptr; + std::unique_ptr LOobject = nullptr; +}; + +OLEObject OLEObjectParser(std::span data); \ No newline at end of file diff --git a/include/pch.h b/include/pch.h index 7b9637e..6b4761a 100644 --- a/include/pch.h +++ b/include/pch.h @@ -1 +1,3 @@ -#pragma once \ No newline at end of file +#pragma once + +#include // IWYU pragma: export diff --git a/include/util/file.h b/include/util/file.h new file mode 100644 index 0000000..5532a7e --- /dev/null +++ b/include/util/file.h @@ -0,0 +1,6 @@ +#pragma once +#include + +std::string ReadEntireFileIntoString(std::filesystem::path path); +void WriteStringToFile(std::filesystem::path path, + std::vector data); \ No newline at end of file diff --git a/src/main.cc b/src/main.cc index 84b5ed2..80cba5b 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,26 +1,19 @@ #include "encryption/util/helper.h" -#include -#include +#include "objects.h" +#include "util/file.h" int main() { - std::ifstream payload1_file("./payload1.txt"); - if (!payload1_file) { - std::cout << "파일 열기 실패\n"; - return 1; - } - payload1_file.seekg(0, std::ios::end); + std::string payload1_hex = ReadEntireFileIntoString("./payload1.txt"); + std::string payload2_hex = ReadEntireFileIntoString("./payload2.txt"); - // 현재 위치 = 파일 크기 - std::streampos size = payload1_file.tellg(); + auto payload1 = bedrock::util::HexStrToBytes(payload1_hex); + auto payload2 = bedrock::util::HexStrToBytes(payload2_hex); - std::string payload1; - payload1.resize(size); - payload1_file >> payload1; - // payload1_file.read(payload1.data(), size); + // OLEObject obj1 = OLEObjectParser(payload1); + OLEObject obj2 = OLEObjectParser(payload2); - std::cout << "red: " << payload1 << std::endl; - - auto bytes = bedrock::util::HexStrToBytes(payload1); + WriteStringToFile("./payload1.bin", payload1); + WriteStringToFile("./payload2.bin", payload2); return 0; -} \ No newline at end of file +} diff --git a/src/objects.cc b/src/objects.cc new file mode 100644 index 0000000..8ac21c3 --- /dev/null +++ b/src/objects.cc @@ -0,0 +1,95 @@ +#include "objects.h" + +#include +#include + +static void OLEObjectHeaderParser(OLEObjectHeader& object, + std::span data, + std::size_t& read_offset) { + const std::uint8_t* data_ptr = data.data(); + std::uint32_t size = 0; + + // OLE vsersion data must be ignored + std::memcpy(&object.OLEVersion.data, data_ptr + read_offset, + object.OLEVersion.GetSize()); + read_offset += 4; + std::memcpy(&object.FormatID.data, data_ptr + read_offset, + object.FormatID.GetSize()); + read_offset += 4; + + // Read LengthPrefixedAnsiString (ClassName) + std::memcpy(&size, data_ptr + read_offset, 4); + read_offset += 4; + object.ClassName.SetSize(size); + std::memcpy(object.ClassName.data.data(), data_ptr + read_offset, + object.ClassName.GetSize()); + read_offset += object.ClassName.GetSize(); + + // Read LengthPrefixedAnsiString (TopicName) + std::memcpy(&size, data_ptr + read_offset, 4); + read_offset += 4; + object.TopicName.SetSize(size); + std::memcpy(object.TopicName.data.data(), data_ptr + read_offset, + object.TopicName.GetSize()); + read_offset += object.TopicName.GetSize(); + + // Read LengthPrefixedAnsiString (ItemName) + std::memcpy(&size, data_ptr + read_offset, 4); + read_offset += 4; + object.ItemName.SetSize(size); + std::memcpy(object.ItemName.data.data(), data_ptr + read_offset, + object.ItemName.GetSize()); + read_offset += object.ItemName.GetSize(); + + return; +} + +static void OLEObjectLinkedObjectParser(OLEObject& object, + std::span data, + std::size_t& read_offset) { + // Not Implemented + return; +} + +static void OLEObjectEnbeddedObjectParser(OLEObject& object, + std::span data, + std::size_t& read_offset) { + object.EObject = std::make_unique(); + const std::uint8_t* data_ptr = data.data(); + std::uint32_t size = 0; + + // Intentionally ignore 2nd header parsing (which is NOT in spec) + // OLEObjectHeaderParser(object.EObject->Header, data, read_offset); + + // Read NativeDataSize + std::memcpy(&size, data_ptr + read_offset, 4); + read_offset += 4; + object.EObject->NativeData.SetSize(size); + std::memcpy(object.EObject->NativeData.data.data(), data_ptr + read_offset, + object.EObject->NativeData.GetSize()); + read_offset += object.EObject->NativeData.GetSize(); + + return; +} + +// Please refer to MS-OLEDS spec and MS-CFB spec +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-oleds/85583d21-c1cf-4afe-a35f-d6701c5fbb6f +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cfb/53989ce4-7b05-4f8d-829b-d08d6148375b +OLEObject OLEObjectParser(std::span data) { + OLEObject object; + + std::size_t read_offset = 0; + + OLEObjectHeaderParser(object.Header, data, read_offset); + + if (object.Header.FormatID.data == 0x00000001) { + OLEObjectLinkedObjectParser(object, data, read_offset); + } else if (object.Header.FormatID.data == 0x00000002) { + OLEObjectEnbeddedObjectParser(object, data, read_offset); + } else { + // invalid object + return {}; + } + + return object; +} diff --git a/src/util/file.cc b/src/util/file.cc new file mode 100644 index 0000000..5898554 --- /dev/null +++ b/src/util/file.cc @@ -0,0 +1,34 @@ +#include "util/file.h" + +#include + +std::string ReadEntireFileIntoString(std::filesystem::path path) { + std::ifstream file(path); + if (!file) { + return {}; + } + + file.seekg(0, std::ios::end); + // 현재 위치 = 파일 크기 + std::size_t size = static_cast(file.tellg()); + file.seekg(0, std::ios::beg); + + std::string contents; + contents.resize(size); + file.read(contents.data(), static_cast(size)); + + return contents; +} + +void WriteStringToFile(std::filesystem::path path, + std::vector data) { + std::ofstream file(path, std::ios::binary); + if (!file) { + return; + } + + file.write(reinterpret_cast(data.data()), + static_cast(data.size())); + + return; +} \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bb9954f..8f53a18 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -3,7 +3,7 @@ file(GLOB TEST_SOURCES "*.cc") foreach(test_src ${TEST_SOURCES}) get_filename_component(test_name ${test_src} NAME_WE) add_executable(${test_name} ${test_src}) - target_link_libraries(${test_name} PRIVATE ${PROJECT_NAME}) + target_link_libraries(${test_name} PRIVATE ${PROJECT_NAME}_lib) if(NOT WIN32) target_compile_options(${test_name} PRIVATE -fno-exceptions -march=native -maes -msse2 -msse3 -mssse3 -msse4.1 -msse4.2) endif()