From df5fd8b05b2a40838c10103959e2032aa9035dc8 Mon Sep 17 00:00:00 2001 From: Lucas Peter Date: Thu, 26 Sep 2024 17:52:10 +0200 Subject: [PATCH] Tried with Unreal base approach --- Source/SkyPortal/Private/SkyPortalIO.cpp | 79 ++++++++++++++++--- .../SkyPortal/Private/SkyPortalSubsystem.cpp | 1 + Source/SkyPortal/Public/SkyPortalFigure.h | 10 ++- Source/SkyPortal/Public/SkyPortalIO.h | 7 +- 4 files changed, 81 insertions(+), 16 deletions(-) diff --git a/Source/SkyPortal/Private/SkyPortalIO.cpp b/Source/SkyPortal/Private/SkyPortalIO.cpp index 9248806..ae6d88a 100644 --- a/Source/SkyPortal/Private/SkyPortalIO.cpp +++ b/Source/SkyPortal/Private/SkyPortalIO.cpp @@ -1,4 +1,9 @@ #include "SkyPortalIO.h" +#include "Misc/AES.h" +#include "Misc/ArchiveMD5.h" +#include "Misc/ScopeLock.h" +#include "HAL/UnrealMemory.h" + DEFINE_LOG_CATEGORY(LogHIDApi); DEFINE_LOG_CATEGORY(LogSkyportalIO); @@ -161,9 +166,20 @@ uint8* USkyPortalIO::Read() return output; } -TArray USkyPortalIO::QueryBlock(uint8 characterIndex, uint8 block) +uint8* USkyPortalIO::QueryBlock(uint8 FigureIndex, uint8 BlockIndex) { - return TArray(); + FWriteBlock command; + memset(command.data, 0, write_buf_size); //maybe not needed here + command.data[1] = 'Q'; + command.data[2] = FigureIndex; // Figure index (0x00-0x0F) + command.data[3] = BlockIndex; + unsigned char* output; + do { + Write(&command); + output = Read(); + } while (output[0] != 'Q' || (output[1] % 0x10 != FigureIndex && output[1] != 0x01) || output[2] != BlockIndex); + + return output; } void USkyPortalIO::Close() { @@ -272,21 +288,59 @@ FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) FigureData FigureData; FigureData.dataError = false; // Initialize error flag - FWriteBlock command; + // Loop over all 64 blocks for (uint8 BlockIndex = 0; BlockIndex < FIGURE_TOTAL_BLOCKS; ++BlockIndex) { - memset(command.data, 0, write_buf_size); //maybe not needed here - command.data[1] = 'Q'; - command.data[2] = FigureIndex; // Figure index (0x00-0x0F) - command.data[3] = BlockIndex; - uint8* output; - do { - Write(&command); - output = Read(); - } while (output[0] != 'Q'); + // Query the block from the portal + uint8* output = QueryBlock(FigureIndex, BlockIndex); + // Copy 16 bytes from the output, starting at the third byte + FMemory::Memcpy(FigureData.data, output + 3, FIGURE_BLOCK_SIZE); + + // Block 1 is sometimes a duplicate of block 0 + if (BlockIndex == 1) + { + if (FMemory::Memcmp(FigureData.data, FigureData.data[0], FIGURE_BLOCK_SIZE) == 0) + { + --BlockIndex; // Decrement index to reprocess + continue; + } + } + + if (((BlockIndex + 1) % 4 == 0) || BlockIndex < 8) + { + // Direct copy from data to decryptedData for certain blocks + FMemory::Memcpy(FigureData.decryptedData[BlockIndex], FigureData.data[BlockIndex], FIGURE_BLOCK_SIZE); + + } + else { + /***** MD5 Hash Calculation *****/ + // Prepare the hash input buffer + uint8 hashIn[0x56]; + FMemory::Memcpy(hashIn, FigureData.data[0], 16); + FMemory::Memcpy(hashIn + 0x10, FigureData.data[1], 16); + hashIn[0x20] = BlockIndex; + // Append the 35-byte constant + FMemory::Memcpy(hashIn + 0x21, HASH_CONST, sizeof(HASH_CONST)); + + // Compute the MD5 hash + FMD5 MD5; + MD5.Update(hashIn, sizeof(hashIn)); + uint8 key[16]; // MD5 produces 16 bytes + MD5.Final(key); + + // AES-128 ECB decryption + + FAES::FAESKey AesKey; + FMemory::Memcpy(AesKey.Key, key, 16); + + //TODO: FAES implementation in Unreal is AES-256. We need AES-128 + //FAES::DecryptData(FigureData.decryptedData[BlockIndex], FigureData.data[BlockIndex], 16, AesKey); + } + + /* if (output[1] == (0x10 + 'Q')) // Successful query { // Extract the 16 bytes of block data @@ -312,6 +366,7 @@ FigureData USkyPortalIO::ReadFigureBlocks(uint8 FigureIndex) // Copy block data into FigureData //memcpy(FigureData.blockdata[BlockIndex], &res.buf[4], FIGURE_BLOCK_SIZE); + */ } // Some verifications should happen. Like if dataError is set. diff --git a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp index 9d9ae34..0e057d9 100644 --- a/Source/SkyPortal/Private/SkyPortalSubsystem.cpp +++ b/Source/SkyPortal/Private/SkyPortalSubsystem.cpp @@ -118,6 +118,7 @@ SKYPORTAL_API bool USkyPortalSubsystem::RestartRunner() StatusCheckerThread = FRunnableThread::Create(StatusChecker, TEXT("PortalStatusCheckerThread"), 0, TPri_AboveNormal); UE_LOG(LogTemp, Log, TEXT("SkyPortalSubsystem Initialized")); + return true; } diff --git a/Source/SkyPortal/Public/SkyPortalFigure.h b/Source/SkyPortal/Public/SkyPortalFigure.h index b597203..a697300 100644 --- a/Source/SkyPortal/Public/SkyPortalFigure.h +++ b/Source/SkyPortal/Public/SkyPortalFigure.h @@ -2,6 +2,12 @@ #include "CoreMinimal.h" //#include "SkyPortalFigure.generated.h" +//Copyright (C) 2010 Activision.All Rights Reserved. +static const uint8 HASH_CONST[] = { + 0x20, 0x43, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x43, 0x29, 0x20, 0x32, // Copyright (C) 2 + 0x30, 0x31, 0x30, 0x20, 0x41, 0x63, 0x74, 0x69, 0x76, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x2E, 0x20, // 010 Activision. + 0x41, 0x6C, 0x6C, 0x20, 0x52, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x52, 0x65, 0x73, 0x65, 0x72, // All Rights Reser + 0x76, 0x65, 0x64, 0x2E, 0x20 }; // ved. #define FIGURE_TOTAL_BLOCKS 64 #define FIGURE_BLOCK_SIZE 16 @@ -53,8 +59,8 @@ public: UFUNCTION(BlueprintCallable, BlueprintPure, meta = (Category = "SkyPortal|Figure")) uint32 GetFigureIdByIndex(uint32 index); - UFUNCTION() - TArray QueryBlock(uint8 characterIndex, uint8 block = 0x00); + //UFUNCTION() + //TArray QueryBlock(uint8 characterIndex, uint8 block = 0x00); void ReadData(uint8 index); void ClearData(); diff --git a/Source/SkyPortal/Public/SkyPortalIO.h b/Source/SkyPortal/Public/SkyPortalIO.h index c94683d..ea9ed3d 100644 --- a/Source/SkyPortal/Public/SkyPortalIO.h +++ b/Source/SkyPortal/Public/SkyPortalIO.h @@ -72,8 +72,11 @@ public: */ uint8* Read(); - UFUNCTION() - TArray QueryBlock(uint8 characterIndex, uint8 block = 0x00); + + /*Trying to read a figure + * @return + */ + unsigned char* QueryBlock(uint8 characterIndex, uint8 block = 0x00); FigureData ReadFigureBlocks(uint8 FigureIndex);