Skip to content

Commit

Permalink
Sigscan for frame proc
Browse files Browse the repository at this point in the history
Remove base address
  • Loading branch information
Sirius902 committed Jun 23, 2024
1 parent 8d63d7e commit 4189006
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 36 deletions.
20 changes: 10 additions & 10 deletions config/LuaBackend.toml
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
[kh1]
scripts = [{ path = "scripts/kh1/", relative = true }]
base = 0x3A0606
thread_struct = 0x22B7280
exe = "KINGDOM HEARTS FINAL MIX.exe"
game_docs = "KINGDOM HEARTS HD 1.5+2.5 ReMIX"
# For Steam Version replace with below line
# game_docs = "My Games/KINGDOM HEARTS HD 1.5+2.5 ReMIX"

[kh2]
scripts = [{ path = "scripts/kh2/", relative = true }]
base = 0x56454E
thread_struct = 0x89E9A0
exe = "KINGDOM HEARTS II FINAL MIX.exe"
game_docs = "KINGDOM HEARTS HD 1.5+2.5 ReMIX"
# For Steam Version replace with below line
# game_docs = "My Games/KINGDOM HEARTS HD 1.5+2.5 ReMIX"

[bbs]
scripts = [{ path = "scripts/bbs/", relative = true }]
base = 0x60E334
thread_struct = 0x110B5970
exe = "KINGDOM HEARTS Birth by Sleep FINAL MIX.exe"
game_docs = "KINGDOM HEARTS HD 1.5+2.5 ReMIX"
# For Steam Version replace with below line
# game_docs = "My Games/KINGDOM HEARTS HD 1.5+2.5 ReMIX"

[recom]
scripts = [{ path = "scripts/recom/", relative = true }]
base = 0x4E4660
thread_struct = 0xBF7A80
exe = "KINGDOM HEARTS Re_Chain of Memories.exe"
game_docs = "KINGDOM HEARTS HD 1.5+2.5 ReMIX"
# For Steam Version replace with below line
# game_docs = "My Games/KINGDOM HEARTS HD 1.5+2.5 ReMIX"

[kh3d]
scripts = [{ path = "scripts/kh3d/", relative = true }]
base = 0x770E4A
thread_struct = 0x14DA6F20
exe = "KINGDOM HEARTS Dream Drop Distance.exe"
game_docs = "KINGDOM HEARTS HD 2.8 Final Chapter Prologue"
# For Steam Version replace with below line
# game_docs = "My Games/KINGDOM HEARTS HD 2.8 Final Chapter Prologue"
11 changes: 1 addition & 10 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,12 @@ Config Config::load(const fs::path& path) {

const auto scripts = entry["scripts"].as_array();
const auto base = entry["base"].value<std::uintptr_t>();
const auto threadStruct = entry["thread_struct"].value<std::uintptr_t>();
const auto exe = entry["exe"].value<std::u8string>();
const auto game_docs = entry["game_docs"].value<std::u8string>();

if (!scripts) {
throw std::runtime_error{std::string{k} + ": scripts failed to parse"};
}
if (!base) {
throw std::runtime_error{std::string{k} + ": base failed to parse"};
}
if (!threadStruct) {
throw std::runtime_error{std::string{k} +
": threadStruct failed to parse"};
}
if (!exe) {
throw std::runtime_error{std::string{k} + ": exe failed to parse"};
}
Expand Down Expand Up @@ -61,8 +53,7 @@ Config Config::load(const fs::path& path) {
paths.emplace_back(*str, *relative);
}

config.infos.emplace(*exe, GameInfo{.pointerStructOffset = *threadStruct,
.baseAddress = *base,
config.infos.emplace(*exe, GameInfo{.baseAddress = base.value_or(0),
.scriptPaths = std::move(paths),
.gameDocsPathStr = *game_docs});
}
Expand Down
1 change: 0 additions & 1 deletion src/game_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ struct ScriptPath {
};

struct GameInfo {
std::uintptr_t pointerStructOffset;
std::uintptr_t baseAddress;
std::vector<ScriptPath> scriptPaths;
std::u8string gameDocsPathStr;
Expand Down
101 changes: 86 additions & 15 deletions src/main_dll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,20 +97,92 @@ LONG WINAPI crashDumpHandler(PEXCEPTION_POINTERS exceptionPointers) {
return EXCEPTION_EXECUTE_HANDLER;
}

struct SectionInfo {
std::uintptr_t offset;
std::size_t size;
};

SectionInfo findTextSectionInfo() {
const auto basePtr = std::bit_cast<std::uint8_t*>(moduleAddress);
const auto dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(basePtr);
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
throw std::runtime_error{"DOS header is corrupt"};
}

const auto ntHeaderPtr = basePtr + dosHeader->e_lfanew;
const auto ntHeader = reinterpret_cast<PIMAGE_NT_HEADERS64>(ntHeaderPtr);
if (ntHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
throw new std::runtime_error{"NT64 header is invalid"};
}

std::optional<SectionInfo> textSection;

for (WORD i = 0; i < ntHeader->FileHeader.NumberOfSections; i++) {
const auto sectionHeader = reinterpret_cast<PIMAGE_SECTION_HEADER>(
ntHeaderPtr + sizeof(IMAGE_NT_HEADERS64) +
(i * sizeof(IMAGE_SECTION_HEADER)));

constexpr char textSectionName[] = ".text";
if (std::memcmp(reinterpret_cast<char*>(sectionHeader->Name),
textSectionName, sizeof(textSectionName) - 1) == 0) {
textSection = SectionInfo{
.offset = sectionHeader->VirtualAddress,
.size = sectionHeader->SizeOfRawData,
};
}
}

return textSection.value();
}

std::optional<GameFrameProc*> findFrameProc(const SectionInfo& textInfo) {
constexpr char sig[] = "\x48\x89\x35\xA7\xB6\x69\x00\x48\x8B\xC6";
constexpr char mask[] = "\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF";
static_assert(sizeof(sig) == sizeof(mask));

const char* textStart =
std::bit_cast<const char*>(moduleAddress + textInfo.offset);
const char* textEnd = textStart + textInfo.size;

for (const char* p = textStart; p != textEnd - (sizeof(sig) - 1); p++) {
bool isMatch = true;
for (std::size_t i = 0; i < sizeof(sig) - 1; i++) {
if ((p[i] & mask[i]) != (sig[i] & mask[i])) {
isMatch = false;
break;
}
}

if (!isMatch)
continue;

const auto scanRes = std::bit_cast<std::uintptr_t>(p);
const auto appPtrAddress =
scanRes + 0x7 + *reinterpret_cast<const std::int32_t*>(scanRes + 0x3);
const auto appPtr = *std::bit_cast<void**>(appPtrAddress);

if (appPtr == nullptr)
return std::nullopt;

const auto vtableAddress = *static_cast<std::uintptr_t*>(appPtr);
const auto onFrameEntry = vtableAddress + 4 * sizeof(std::uintptr_t);
return std::bit_cast<GameFrameProc*>(onFrameEntry);
}

return std::nullopt;
}

bool hookGame() {
static_assert(sizeof(std::uint64_t) == sizeof(std::uintptr_t));

constexpr static auto frameProcOffsets =
std::to_array<std::uintptr_t>({0x3E8, 0x0, 0x20});

std::uintptr_t pointerStruct = moduleAddress + gameInfo->pointerStructOffset;
const auto textInfo = findTextSectionInfo();
const auto frameProcPtrOpt = findFrameProc(textInfo);

if (auto ptr = followPointerChain(pointerStruct, frameProcOffsets)) {
frameProcPtr = reinterpret_cast<GameFrameProc*>(*ptr);
} else {
if (!frameProcPtrOpt.has_value()) {
return false;
}

frameProcPtr = frameProcPtrOpt.value();
if (*frameProcPtr == nullptr)
return false;

Expand Down Expand Up @@ -241,17 +313,16 @@ BOOL WINAPI DllMain([[maybe_unused]] HINSTANCE hinstDLL, DWORD fdwReason,
}

extern "C" __declspec(dllexport) HRESULT WINAPI
DirectInput8Create(HINSTANCE hinst, DWORD dwVersion, LPCVOID riidltf,
LPVOID* ppvOut, LPVOID punkOuter) {
DirectInput8Create(HINSTANCE hinst, DWORD dwVersion, LPCVOID riidltf,
LPVOID* ppvOut, LPVOID punkOuter) {
return createProc(hinst, dwVersion, riidltf, ppvOut, punkOuter);
}

extern "C" __declspec(dllexport) BOOL WINAPI
MiniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
MINIDUMP_TYPE DumpType,
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
PMINIDUMP_CALLBACK_INFORMATION CallbackParam) {
extern "C" __declspec(dllexport) BOOL WINAPI MiniDumpWriteDump(
HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE DumpType,
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
PMINIDUMP_CALLBACK_INFORMATION CallbackParam) {
return writeDumpProc(hProcess, ProcessId, hFile, DumpType, ExceptionParam,
UserStreamParam, CallbackParam);
}

0 comments on commit 4189006

Please sign in to comment.