[ZoneBuilder] Better FastFile obfuscation

This commit is contained in:
momo5502 2017-04-27 22:03:05 +02:00
parent 745f27429a
commit 3e20ca366a
5 changed files with 107 additions and 1 deletions

View File

@ -9,6 +9,8 @@ namespace Components
bool FastFiles::IsIW4xZone = false; bool FastFiles::IsIW4xZone = false;
bool FastFiles::StreamRead = false; bool FastFiles::StreamRead = false;
char FastFiles::LastByteRead = 0;
unsigned int FastFiles::CurrentZone; unsigned int FastFiles::CurrentZone;
unsigned int FastFiles::MaxZones; unsigned int FastFiles::MaxZones;
@ -332,6 +334,7 @@ namespace Components
void FastFiles::ReadHeaderStub(unsigned int* header, int size) void FastFiles::ReadHeaderStub(unsigned int* header, int size)
{ {
FastFiles::IsIW4xZone = false; FastFiles::IsIW4xZone = false;
FastFiles::LastByteRead = 0;
Game::DB_ReadXFileUncompressed(header, size); Game::DB_ReadXFileUncompressed(header, size);
if (header[0] == XFILE_HEADER_IW4X) if (header[0] == XFILE_HEADER_IW4X)
@ -439,6 +442,36 @@ namespace Components
Utils::Hook::Call<void(Game::XZoneInfo*, unsigned int)>(0x5BBAC0)(zoneInfo, zoneCount); Utils::Hook::Call<void(Game::XZoneInfo*, unsigned int)>(0x5BBAC0)(zoneInfo, zoneCount);
} }
__declspec(naked) void FastFiles::ReadXFile(void* /*buffer*/, int /*size*/)
{
__asm
{
mov eax, [esp + 4]
mov ecx, [esp + 8]
push 445468h
retn
}
}
void FastFiles::ReadXFileStub(char* buffer, int size)
{
FastFiles::ReadXFile(buffer, size);
if(FastFiles::IsIW4xZone)
{
for(int i = 0; i < size; ++i)
{
buffer[i] ^= FastFiles::LastByteRead;
Utils::RotLeft(buffer[i], 4);
buffer[i] ^= -1;
Utils::RotRight(buffer[i], 6);
FastFiles::LastByteRead = buffer[i];
}
}
}
#ifdef DEBUG #ifdef DEBUG
void FastFiles::LogStreamRead(int len) void FastFiles::LogStreamRead(int len)
{ {
@ -466,6 +499,9 @@ namespace Components
// Allow loading IW4x zones // Allow loading IW4x zones
Utils::Hook(0x4157B8, FastFiles::ReadHeaderStub, HOOK_CALL).install()->quick(); Utils::Hook(0x4157B8, FastFiles::ReadHeaderStub, HOOK_CALL).install()->quick();
// Obfuscate zone data
Utils::Hook(Game::DB_ReadXFile, FastFiles::ReadXFileStub, HOOK_JUMP).install()->quick();
// Allow custom zone loading // Allow custom zone loading
if (!ZoneBuilder::IsEnabled()) if (!ZoneBuilder::IsEnabled())
{ {

View File

@ -41,6 +41,8 @@ namespace Components
static bool IsIW4xZone; static bool IsIW4xZone;
static bool StreamRead; static bool StreamRead;
static char LastByteRead;
static Key CurrentKey; static Key CurrentKey;
static symmetric_CTR CurrentCTR; static symmetric_CTR CurrentCTR;
static std::vector<std::string> ZonePaths; static std::vector<std::string> ZonePaths;
@ -62,6 +64,9 @@ namespace Components
static void LoadZonesStub(Game::XZoneInfo *zoneInfo, unsigned int zoneCount); static void LoadZonesStub(Game::XZoneInfo *zoneInfo, unsigned int zoneCount);
static void ReadXFile(void* buffer, int size);
static void ReadXFileStub(char* buffer, int size);
#ifdef DEBUG #ifdef DEBUG
static void LogStreamRead(int len); static void LogStreamRead(int len);
#endif #endif

View File

@ -445,6 +445,18 @@ namespace Components
#ifndef DEBUG #ifndef DEBUG
// Insert a random byte, this will destroy the whole alignment and result in a crash, if not handled // Insert a random byte, this will destroy the whole alignment and result in a crash, if not handled
zoneBuffer.insert(zoneBuffer.begin(), static_cast<char>(Utils::Cryptography::Rand::GenerateInt())); zoneBuffer.insert(zoneBuffer.begin(), static_cast<char>(Utils::Cryptography::Rand::GenerateInt()));
char lastByte = 0;
for(unsigned int i = 0; i < zoneBuffer.size(); ++i )
{
char oldLastByte = lastByte;
lastByte = zoneBuffer[i];
Utils::RotLeft(zoneBuffer[i], 6);
zoneBuffer[i] ^= -1;
Utils::RotRight(zoneBuffer[i], 4);
zoneBuffer[i] ^= oldLastByte;
}
#endif #endif
zoneBuffer = Utils::Compression::ZLib::Compress(zoneBuffer); zoneBuffer = Utils::Compression::ZLib::Compress(zoneBuffer);
@ -988,4 +1000,37 @@ namespace Components
assert(ZoneBuilder::MemAllocator.empty()); assert(ZoneBuilder::MemAllocator.empty());
ZoneBuilder::CommonAssets.clear(); ZoneBuilder::CommonAssets.clear();
} }
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
bool ZoneBuilder::unitTest()
{
printf("Testing circular bit shifting (left)...");
unsigned int integer = 0x80000000;
Utils::RotLeft(integer, 1);
if(integer != 1)
{
printf("Error\n");
printf("Bit shifting failed: %X\n", integer);
return false;
}
printf("Success\n");
printf("Testing circular bit shifting (right)...");
unsigned char byte = 0b00000011;
Utils::RotRight(byte, 2);
if (byte != 0b11000000)
{
printf("Error\n");
printf("Bit shifting failed %X\n", byte & 0xFF);
return false;
}
printf("Success\n");
return true;
}
#endif
} }

View File

@ -4,7 +4,7 @@
#define XFILE_VERSION 276 #define XFILE_VERSION 276
#define XFILE_HEADER_IW4X 0x78345749 // 'IW4x' #define XFILE_HEADER_IW4X 0x78345749 // 'IW4x'
#define XFILE_VERSION_IW4X 1 #define XFILE_VERSION_IW4X 2
namespace Components namespace Components
{ {
@ -97,6 +97,7 @@ namespace Components
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "ZoneBuilder"; }; const char* getName() override { return "ZoneBuilder"; };
bool unitTest() override;
#endif #endif
static bool IsEnabled(); static bool IsEnabled();

View File

@ -15,6 +15,25 @@ namespace Utils
bool HasIntercection(unsigned int base1, unsigned int len1, unsigned int base2, unsigned int len2); bool HasIntercection(unsigned int base1, unsigned int len1, unsigned int base2, unsigned int len2);
template <typename T> inline void RotLeft(T& object, size_t bits)
{
bits %= sizeof(T) * 8;
T sign = 1;
sign = sign << (sizeof(T) * 8 - 1);
bool negative = (object & sign) != 0;
object &= ~sign;
object = (object << bits) | (object >> (sizeof(T) * 8 - bits));
object |= T(negative) << ((sizeof(T) * 8 - 1 + bits) % (sizeof(T) * 8));
}
template <typename T> inline void RotRight(T& object, size_t bits)
{
bits %= (sizeof(T) * 8);
RotLeft<T>(object, ((sizeof(T) * 8) - bits));
}
template <typename T> inline void Merge(std::vector<T>* target, T* source, size_t length) template <typename T> inline void Merge(std::vector<T>* target, T* source, size_t length)
{ {
if (source) if (source)