mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-12-27 12:31:50 +00:00
feat: dump iw4 xbox fastfile data
This commit is contained in:
@@ -18,6 +18,7 @@ namespace IW4
|
||||
static constexpr const char* MAGIC_IW4X = "IW4x";
|
||||
static constexpr int ZONE_VERSION = 276;
|
||||
static constexpr int IW4X_ZONE_VERSION = 3;
|
||||
static constexpr int ZONE_VERSION_XENON = 269;
|
||||
|
||||
static_assert(std::char_traits<char>::length(MAGIC_SIGNED_INFINITY_WARD) == sizeof(ZoneHeader::m_magic));
|
||||
static_assert(std::char_traits<char>::length(MAGIC_SIGNED_OAT) == sizeof(ZoneHeader::m_magic));
|
||||
@@ -40,6 +41,20 @@ namespace IW4
|
||||
0x77, 0xCD, 0x62, 0x7D, 0x9D, 0x40, 0x26, 0x44, 0x4B, 0x3B, 0x0A, 0x89, 0x02, 0x03, 0x01, 0x00, 0x01,
|
||||
};
|
||||
|
||||
inline static const uint8_t RSA_PUBLIC_KEY_INFINITY_WARD_XENON[270]{
|
||||
48u, 130u, 1u, 10u, 2u, 130u, 1u, 1u, 0u, 205u, 150u, 80u, 200u, 178u, 78u, 16u, 228u, 121u, 5u, 65u, 110u, 155u, 239u,
|
||||
206u, 81u, 196u, 45u, 158u, 201u, 209u, 132u, 35u, 240u, 172u, 34u, 36u, 24u, 233u, 157u, 40u, 203u, 175u, 180u, 127u, 96u, 179u,
|
||||
103u, 50u, 67u, 252u, 15u, 169u, 112u, 120u, 66u, 204u, 169u, 134u, 64u, 202u, 50u, 202u, 130u, 155u, 12u, 99u, 176u, 81u, 137u,
|
||||
20u, 41u, 234u, 21u, 51u, 63u, 123u, 235u, 102u, 237u, 247u, 22u, 247u, 69u, 6u, 198u, 65u, 98u, 222u, 0u, 117u, 250u, 140u,
|
||||
143u, 229u, 191u, 115u, 203u, 117u, 44u, 68u, 9u, 80u, 216u, 30u, 81u, 226u, 88u, 178u, 86u, 111u, 229u, 245u, 192u, 32u, 79u,
|
||||
95u, 85u, 143u, 141u, 209u, 55u, 204u, 232u, 59u, 9u, 6u, 44u, 93u, 185u, 123u, 142u, 227u, 199u, 131u, 203u, 143u, 64u, 99u,
|
||||
137u, 174u, 107u, 15u, 222u, 56u, 94u, 215u, 244u, 101u, 140u, 48u, 90u, 139u, 158u, 162u, 66u, 3u, 247u, 128u, 171u, 223u, 160u,
|
||||
143u, 149u, 160u, 187u, 182u, 29u, 163u, 189u, 59u, 111u, 66u, 104u, 221u, 66u, 251u, 230u, 50u, 2u, 59u, 8u, 238u, 52u, 60u,
|
||||
143u, 30u, 232u, 89u, 17u, 8u, 9u, 41u, 190u, 105u, 177u, 212u, 85u, 16u, 111u, 243u, 146u, 23u, 9u, 62u, 112u, 160u, 26u,
|
||||
230u, 125u, 109u, 49u, 208u, 248u, 51u, 223u, 240u, 41u, 85u, 98u, 29u, 95u, 62u, 141u, 58u, 29u, 90u, 19u, 176u, 249u, 137u,
|
||||
137u, 145u, 143u, 6u, 186u, 58u, 55u, 22u, 197u, 125u, 137u, 239u, 239u, 99u, 78u, 243u, 137u, 25u, 6u, 137u, 241u, 123u, 220u,
|
||||
245u, 110u, 54u, 10u, 139u, 200u, 196u, 93u, 194u, 125u, 19u, 157u, 2u, 3u, 1u, 0u, 1u};
|
||||
|
||||
static constexpr size_t AUTHED_CHUNK_SIZE = 0x2000;
|
||||
static constexpr unsigned AUTHED_CHUNK_COUNT_PER_GROUP = 256;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "Loading/Processor/ProcessorInflate.h"
|
||||
#include "Loading/Steps/StepAddProcessor.h"
|
||||
#include "Loading/Steps/StepAllocXBlocks.h"
|
||||
#include "Loading/Steps/StepDumpData.h"
|
||||
#include "Loading/Steps/StepLoadHash.h"
|
||||
#include "Loading/Steps/StepLoadSignature.h"
|
||||
#include "Loading/Steps/StepLoadZoneContent.h"
|
||||
@@ -23,14 +24,26 @@
|
||||
#include "Loading/Steps/StepVerifyMagic.h"
|
||||
#include "Loading/Steps/StepVerifySignature.h"
|
||||
#include "Utils/ClassUtils.h"
|
||||
#include "Utils/Endianness.h"
|
||||
#include "Utils/Logging/Log.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
|
||||
using namespace IW4;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
class StepLogPosition final : public ILoadingStep
|
||||
{
|
||||
public:
|
||||
void PerformStep(ZoneLoader& zoneLoader, ILoadingStream& stream) override
|
||||
{
|
||||
con::info("Stream position before dump: 0x{:X}", stream.Pos());
|
||||
}
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -42,9 +55,9 @@ namespace
|
||||
|
||||
std::optional<ZoneLoaderInspectionResultIW4> InspectZoneHeaderIw4(const ZoneHeader& header)
|
||||
{
|
||||
if (header.m_version != ZoneConstants::ZONE_VERSION)
|
||||
return std::nullopt;
|
||||
|
||||
if (endianness::FromLittleEndian(header.m_version) == ZoneConstants::ZONE_VERSION)
|
||||
{
|
||||
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_IW4X, std::char_traits<char>::length(ZoneConstants::MAGIC_IW4X)))
|
||||
{
|
||||
if (*reinterpret_cast<const uint32_t*>(&header.m_magic[std::char_traits<char>::length(ZoneConstants::MAGIC_IW4X)])
|
||||
@@ -101,6 +114,42 @@ namespace
|
||||
.m_is_iw4x = false,
|
||||
};
|
||||
}
|
||||
}
|
||||
else if (endianness::FromBigEndian(header.m_version) == ZoneConstants::ZONE_VERSION_XENON)
|
||||
{
|
||||
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_UNSIGNED, std::char_traits<char>::length(ZoneConstants::MAGIC_UNSIGNED)))
|
||||
{
|
||||
return ZoneLoaderInspectionResultIW4{
|
||||
.m_generic_result =
|
||||
ZoneLoaderInspectionResult{
|
||||
.m_game_id = GameId::IW4,
|
||||
.m_endianness = GameEndianness::BE,
|
||||
.m_word_size = GameWordSize::ARCH_32,
|
||||
.m_platform = GamePlatform::XBOX,
|
||||
.m_is_official = false,
|
||||
.m_is_signed = false,
|
||||
.m_is_encrypted = false,
|
||||
},
|
||||
.m_is_iw4x = false,
|
||||
};
|
||||
}
|
||||
if (!memcmp(header.m_magic, ZoneConstants::MAGIC_SIGNED_INFINITY_WARD, std::char_traits<char>::length(ZoneConstants::MAGIC_SIGNED_INFINITY_WARD)))
|
||||
{
|
||||
return ZoneLoaderInspectionResultIW4{
|
||||
.m_generic_result =
|
||||
ZoneLoaderInspectionResult{
|
||||
.m_game_id = GameId::IW4,
|
||||
.m_endianness = GameEndianness::BE,
|
||||
.m_word_size = GameWordSize::ARCH_32,
|
||||
.m_platform = GamePlatform::XBOX,
|
||||
.m_is_official = true,
|
||||
.m_is_signed = true,
|
||||
.m_is_encrypted = false,
|
||||
},
|
||||
.m_is_iw4x = false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -121,17 +170,28 @@ namespace
|
||||
#undef XBLOCK_DEF
|
||||
}
|
||||
|
||||
std::unique_ptr<cryptography::IPublicKeyAlgorithm> SetupRsa(const bool isOfficial)
|
||||
std::unique_ptr<cryptography::IPublicKeyAlgorithm> SetupRsa(const bool isOfficial, const GamePlatform platform)
|
||||
{
|
||||
if (isOfficial)
|
||||
{
|
||||
auto rsa = cryptography::CreateRsa(cryptography::HashingAlgorithm::RSA_HASH_SHA256, cryptography::RsaPaddingMode::RSA_PADDING_PSS);
|
||||
|
||||
if (platform == GamePlatform::PC)
|
||||
{
|
||||
if (!rsa->SetKey(ZoneConstants::RSA_PUBLIC_KEY_INFINITY_WARD, sizeof(ZoneConstants::RSA_PUBLIC_KEY_INFINITY_WARD)))
|
||||
{
|
||||
con::error("Invalid public key for signature checking");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else if (platform == GamePlatform::XBOX)
|
||||
{
|
||||
if (!rsa->SetKey(ZoneConstants::RSA_PUBLIC_KEY_INFINITY_WARD_XENON, sizeof(ZoneConstants::RSA_PUBLIC_KEY_INFINITY_WARD_XENON)))
|
||||
{
|
||||
con::error("Invalid public key for signature checking");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return rsa;
|
||||
}
|
||||
@@ -151,7 +211,9 @@ namespace
|
||||
return;
|
||||
|
||||
// If file is signed setup a RSA instance.
|
||||
auto rsa = SetupRsa(inspectResult.m_generic_result.m_is_official);
|
||||
auto rsa = SetupRsa(inspectResult.m_generic_result.m_is_official, inspectResult.m_generic_result.m_platform);
|
||||
|
||||
zoneLoader.AddLoadingStep(std::make_unique<StepLogPosition>());
|
||||
|
||||
zoneLoader.AddLoadingStep(step::CreateStepVerifyMagic(ZoneConstants::MAGIC_AUTH_HEADER));
|
||||
zoneLoader.AddLoadingStep(step::CreateStepSkipBytes(4)); // Skip reserved
|
||||
@@ -227,6 +289,11 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(const ZoneH
|
||||
// Skip timestamp
|
||||
zoneLoader->AddLoadingStep(step::CreateStepSkipBytes(8));
|
||||
|
||||
if (inspectResult->m_generic_result.m_platform == GamePlatform::XBOX)
|
||||
{
|
||||
zoneLoader->AddLoadingStep(step::CreateStepSkipBytes(16));
|
||||
}
|
||||
|
||||
// Add steps for loading the auth header which also contain the signature of the zone if it is signed.
|
||||
AddAuthHeaderSteps(*inspectResult, *zoneLoader, fileName);
|
||||
|
||||
@@ -238,6 +305,8 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(const ZoneH
|
||||
zoneLoader->AddLoadingStep(step::CreateStepSkipBytes(1));
|
||||
}
|
||||
|
||||
if (inspectResult->m_generic_result.m_endianness == GameEndianness::LE)
|
||||
{
|
||||
// Start of the XFile struct
|
||||
zoneLoader->AddLoadingStep(step::CreateStepLoadZoneSizes());
|
||||
zoneLoader->AddLoadingStep(step::CreateStepAllocXBlocks());
|
||||
@@ -253,6 +322,18 @@ std::unique_ptr<ZoneLoader> ZoneLoaderFactory::CreateLoaderForHeader(const ZoneH
|
||||
ZoneConstants::INSERT_BLOCK,
|
||||
zonePtr->Memory(),
|
||||
std::move(progressCallback)));
|
||||
}
|
||||
else
|
||||
{
|
||||
fs::path dumpFileNamePath = fs::path(fileName).filename();
|
||||
dumpFileNamePath.replace_extension(".dat");
|
||||
std::string dumpFileName = dumpFileNamePath.string();
|
||||
con::warn("Dumping xbox assets is not supported, making a full fastfile data dump to {}", dumpFileName);
|
||||
|
||||
zoneLoader->AddLoadingStep(std::make_unique<StepLogPosition>());
|
||||
|
||||
zoneLoader->AddLoadingStep(step::CreateStepDumpData(dumpFileName, 0xFFFFFFFF));
|
||||
}
|
||||
|
||||
return zoneLoader;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user