Skip to content

Commit

Permalink
Checksum games .text section if we don't recognize the timestamp
Browse files Browse the repository at this point in the history
  • Loading branch information
emoose committed Oct 8, 2021
1 parent c48833d commit 6eb5bf2
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 14 deletions.
38 changes: 38 additions & 0 deletions src/Utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,41 @@ HWND FindMainWindow(DWORD process_id)
EnumWindows(enum_windows_callback, (LPARAM)&data);
return data.window_handle;
}

// https://rosettacode.org/wiki/CRC-32#Implementation_2
uint32_t
rc_crc32(uint32_t crc, const char* buf, size_t len)
{
static uint32_t table[256];
static int have_table = 0;
uint32_t rem;
uint8_t octet;
int i, j;
const char* p, * q;

/* This check is not thread safe; there is no mutex. */
if (have_table == 0) {
/* Calculate CRC table. */
for (i = 0; i < 256; i++) {
rem = i; /* remainder from polynomial division */
for (j = 0; j < 8; j++) {
if (rem & 1) {
rem >>= 1;
rem ^= 0xedb88320;
}
else
rem >>= 1;
}
table[i] = rem;
}
have_table = 1;
}

crc = ~crc;
q = buf + len;
for (p = buf; p < q; p++) {
octet = *p; /* Cast to unsigned octet. */
crc = (crc >> 8) ^ table[(crc & 0xff) ^ octet];
}
return ~crc;
}
40 changes: 30 additions & 10 deletions src/dllmain.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#include "pch.h"

#define SDK_VERSION "0.1.26"
#define SDK_VERSION "0.1.26a"

const uint32_t Addr_Timestamp = 0x1E0;
const uint32_t Value_Timestamp = 1626315361; // 2021/07/15 02:16:01
const uint32_t Value_Timestamp_patch1 = 1629818287; // 2021/08/24 15:18:07 (no code changes?)

const uint32_t Game_TextSectionChecksum = 0x13ce422f; // patch0 & patch1 share this

const uint32_t Addr_ProcessEvent = 0x14CBA50;
const uint32_t Addr_GUObjectArray = 0x44DC350;
const uint32_t Addr_Names = 0x4C6DE10;
Expand Down Expand Up @@ -165,6 +167,8 @@ void UAchCharacterBuildComponent__SetCulling_Hook(UAchCharacterBuildComponent* t
UAchCharacterBuildComponent__SetCulling_Orig(thisptr, Options.CharaDisableCull ? false : bCulling);
}

// Ran by DllMain, before the games code itself has ran (or any wrappers like SteamStub etc)
// Not recommended to put anything that writes to game EXE here, since it might be writing over still-encrypted data
bool InitGame()
{
printf("\nArise-SDK " SDK_VERSION " - https://github.com/emoose/Arise-SDK\n");
Expand All @@ -178,14 +182,6 @@ bool InitGame()
}
mBaseAddress = reinterpret_cast<uintptr_t>(GameHModule);

// Check that this is the EXE we were built against...
uint32_t timestamp = *reinterpret_cast<uint32_t*>(mBaseAddress + Addr_Timestamp);
if (timestamp != Value_Timestamp && timestamp != Value_Timestamp_patch1)
{
MessageBoxA(0, "Unsupported 'Tales of Arise.exe' version, aborting Arise-SDK load...", "Arise-SDK", 0);
return false;
}

// Get folder path of currently running EXE
GetModuleFileName(GameHModule, IniPath, 4096);
int len = wcslen(IniPath);
Expand Down Expand Up @@ -551,10 +547,34 @@ void RefreshEngineSettings_Hook()
RefreshEngineSettings_Orig();
}


// InitPlugin is ran sometime after steamstub decrypted the exe - usually within the first frame or so of the game
// Some parts of the game might already be inited by this time though, requiring a different method of handling them
void InitPlugin()
{
inited = false;

// Check that this is the EXE we were built against...
uint32_t timestamp = *reinterpret_cast<uint32_t*>(mBaseAddress + Addr_Timestamp);
if (timestamp != Value_Timestamp && timestamp != Value_Timestamp_patch1)
{
// Not a known EXE timestamp, we'll checksum the .text section since some patches are known to just update timestamps...
bool isKnown = false;
int textSize = 0;
void* textSection = ModuleGetSection((void*)mBaseAddress, ".text", &textSize);
if (textSection)
{
auto checksum = rc_crc32(0, (char*)textSection, textSize);
isKnown = checksum == Game_TextSectionChecksum;
}

if (!isKnown)
{
MessageBoxA(0, "Unsupported 'Tales of Arise.exe' version, aborting Arise-SDK load...", "Arise-SDK", 0);
return;
}
}


PostProc_Init();

UObject::ProcessEventPtr = reinterpret_cast<ProcessEventFn>(mBaseAddress + Addr_ProcessEvent);
Expand Down
2 changes: 2 additions & 0 deletions src/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ extern uintptr_t mBaseAddress;
void InitPlugin();

// proxy.cpp
void* ModuleGetSection(void* Module, const char* SectionName, int* OutSectionSize);
void Proxy_InitSteamStub();

// UE4Hook.cpp
Expand All @@ -60,6 +61,7 @@ bool DirExists(const WCHAR* DirPath);
HWND FindMainWindow(DWORD process_id);
bool INI_GetBool(const WCHAR* IniPath, const WCHAR* Section, const WCHAR* Key, bool DefaultValue);
float INI_GetFloat(const WCHAR* IniPath, const WCHAR* Section, const WCHAR* Key, float DefaultValue);
uint32_t rc_crc32(uint32_t crc, const char* buf, size_t len);

// PostProcOverrides.cpp
void PostProc_AddCVars(IConsoleManager* ConsoleManager);
Expand Down
33 changes: 33 additions & 0 deletions src/proxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,39 @@ void* ModuleDirectoryEntryData(void* Module, int DirectoryEntry, int* EntrySize
return base + entryAddr;
}

void* ModuleGetSection(void* Module, const char* SectionName, int* OutSectionSize)
{
BYTE* base = reinterpret_cast<BYTE*>(Module);
IMAGE_DOS_HEADER* dosHeader = reinterpret_cast<IMAGE_DOS_HEADER*>(base);
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
return nullptr; // invalid header :(

IMAGE_NT_HEADERS* ntHeader = reinterpret_cast<IMAGE_NT_HEADERS*>(base + dosHeader->e_lfanew);
if (ntHeader->Signature != IMAGE_NT_SIGNATURE)
return nullptr;

IMAGE_SECTION_HEADER* sections = reinterpret_cast<IMAGE_SECTION_HEADER*>(&ntHeader[1]);

IMAGE_SECTION_HEADER* foundSection = nullptr;
for (int i = 0; i < ntHeader->FileHeader.NumberOfSections; i++)
{
IMAGE_SECTION_HEADER* section = &sections[i];
if (!strncmp((const char*)section->Name, SectionName, 8))
{
foundSection = section;
break;
}
}

if (!foundSection)
return nullptr;

if (OutSectionSize)
*OutSectionSize = foundSection->Misc.VirtualSize;

return base + foundSection->VirtualAddress;
}

FARPROC* GetIATPointer(void* Module, const char* LibraryName, const char* ImportName)
{
auto* base = (BYTE*)Module;
Expand Down
8 changes: 4 additions & 4 deletions src/resource.rc
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ END
//

VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,1,26,0
PRODUCTVERSION 0,1,26,0
FILEVERSION 0,1,26,1
PRODUCTVERSION 0,1,26,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
Expand All @@ -68,12 +68,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "emoose"
VALUE "FileDescription", "Arise-SDK - improvement extension for Tales of Arise"
VALUE "FileVersion", "0.1.26.0"
VALUE "FileVersion", "0.1.26.1"
VALUE "InternalName", "Arise-SDK.dll"
VALUE "LegalCopyright", "emoose - 2021"
VALUE "OriginalFilename", "Arise-SDK.dll"
VALUE "ProductName", "Arise-SDK"
VALUE "ProductVersion", "0.1.26.0"
VALUE "ProductVersion", "0.1.26.1"
END
END
BLOCK "VarFileInfo"
Expand Down

0 comments on commit 6eb5bf2

Please sign in to comment.