Skip to content

Commit

Permalink
Merge branch 'th19'
Browse files Browse the repository at this point in the history
  • Loading branch information
32th-System committed Jan 14, 2024
2 parents f6bd267 + c96ad7d commit ff44cb8
Show file tree
Hide file tree
Showing 17 changed files with 1,181 additions and 51 deletions.
20 changes: 20 additions & 0 deletions thprac/src/thprac/thprac_games.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@
struct IDirect3DDevice8;

namespace THPrac {

struct Float2 {
float x;
float y;
};

struct Float3 {
float x;
float y;
float z;
};

struct Timer {
int32_t previous;
int32_t current;
Expand All @@ -17,6 +29,14 @@ struct Timer {
uint32_t control;
};

struct Timer19 {
int32_t previous;
int32_t current;
float current_f;
uint32_t scale_table_index;
uint32_t flags;
};

template<typename T>
struct ThList {
T* entry;
Expand Down
5 changes: 5 additions & 0 deletions thprac/src/thprac/thprac_games_def.json
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,11 @@
"TH18.5 弹幕狂们的黑市 ~ 100th Black Market.",
"TH18.5 100th Black Market",
"TH18.5 バレットフィリア達の闇市場 〜 100th Black Market."
],
"TH19_TITLE": [
"TH19 东方兽王园 〜 Unfinished Dream of All Living Ghost.",
"TH19 Unfinished Dream of All Living Ghost",
"TH19 東方獣王園 〜 Unfinished Dream of All Living Ghost."
]
},

Expand Down
29 changes: 14 additions & 15 deletions thprac/src/thprac/thprac_hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ namespace THPrac {
#define XIP_TYPE DWORD
#endif

uintptr_t ingame_image_base = 0;

struct VEHHookCtx {
uint8_t* m_Src = nullptr;
CallbackFunc* m_Dest = nullptr;
Expand Down Expand Up @@ -102,7 +104,7 @@ __declspec(noinline) LONG CALLBACK VEHHandler(EXCEPTION_POINTERS* ExceptionInfo)

DWORD ExceptionCode = ExceptionInfo->ExceptionRecord->ExceptionCode;
if (ExceptionCode == EXCEPTION_BREAKPOINT) {
auto ctx = VEHHookLookUp(ExceptionInfo->ContextRecord->XIP);
auto ctx = VEHHookLookUp(ExceptionInfo->ContextRecord->XIP - ingame_image_base);
if (ctx != g_VEHHookVector->end()) {
InvokeCallback(*ctx, ExceptionInfo->ContextRecord);
return EXCEPTION_CONTINUE_EXECUTION;
Expand Down Expand Up @@ -139,8 +141,7 @@ void VEHHookEnable(void* target)
if (ctx->isActivate)
return;

VEHWriteByte(ctx->m_Src, 0xCC, &ctx->m_StorageByte);
FlushInstructionCache(GetCurrentProcess(), ctx->m_Src, 1);
VEHWriteByte((void*)(ingame_image_base + (uintptr_t)ctx->m_Src), 0xCC, &ctx->m_StorageByte);

ctx->isActivate = true;
}
Expand All @@ -151,7 +152,7 @@ void VEHHookDisable(void* target)
if (!ctx->isActivate)
return;

VEHWriteByte(ctx->m_Src, ctx->m_StorageByte);
VEHWriteByte((void*)(ingame_image_base + (uintptr_t)ctx->m_Src), ctx->m_StorageByte);
FlushInstructionCache(GetCurrentProcess(), ctx->m_Src, 1);

ctx->isActivate = false;
Expand Down Expand Up @@ -229,10 +230,10 @@ bool HookCtx::Setup(void* target, CallbackFunc* detour)
return false;
}

LPVOID buffer = AllocateBuffer(target);
LPVOID buffer = AllocateBuffer((LPVOID)((uintptr_t)target + ingame_image_base));
if (buffer) {
TRAMPOLINE ct;
ct.pTarget = target;
ct.pTarget = (LPVOID)((uintptr_t)target + ingame_image_base);
ct.pDetour = (void*)detour;
ct.pTrampoline = buffer;
if (CreateTrampolineFunctionEx(&ct, 1, FALSE)) {
Expand Down Expand Up @@ -262,7 +263,7 @@ bool HookCtx::Setup(void* target, const char* patch, size_t patch_size)
if (!buffer)
return false;
memcpy(buffer, patch, patch_size);
memcpy((void*)((size_t)buffer + patch_size), target, patch_size);
memcpy((void*)((size_t)buffer + patch_size), (void*)((uintptr_t)target + ingame_image_base), patch_size);

mTarget = target;
mIsPatch = true;
Expand All @@ -279,10 +280,9 @@ bool HookCtx::Enable()

if (mIsPatch) {
DWORD oldProtect;
VirtualProtect(mTarget, mPatchSize, PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy(mTarget, mPatch, mPatchSize);
FlushInstructionCache(GetCurrentProcess(), mTarget, mPatchSize);
VirtualProtect(mTarget, mPatchSize, oldProtect, &oldProtect);
VirtualProtect((LPVOID)((uintptr_t)mTarget + ingame_image_base), mPatchSize, PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy((void*)((uintptr_t)mTarget + ingame_image_base), mPatch, mPatchSize);
VirtualProtect((LPVOID)((uintptr_t)mTarget + ingame_image_base), mPatchSize, oldProtect, &oldProtect);
} else {
VEHHookEnable(mTarget);
}
Expand All @@ -297,10 +297,9 @@ bool HookCtx::Disable()

if (mIsPatch) {
DWORD oldProtect;
VirtualProtect(mTarget, mPatchSize, PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy(mTarget, (void*)((size_t)mPatch + mPatchSize), mPatchSize);
FlushInstructionCache(GetCurrentProcess(), mTarget, mPatchSize);
VirtualProtect(mTarget, mPatchSize, oldProtect, &oldProtect);
VirtualProtect((LPVOID)((uintptr_t)mTarget + ingame_image_base), mPatchSize, PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy((void*)((uintptr_t)mTarget + ingame_image_base), (void*)((size_t)mPatch + mPatchSize), mPatchSize);
VirtualProtect((LPVOID)((uintptr_t)mTarget + ingame_image_base), mPatchSize, oldProtect, &oldProtect);
} else {
VEHHookDisable(mTarget);
}
Expand Down
25 changes: 25 additions & 0 deletions thprac/src/thprac/thprac_hook.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <vector>

namespace THPrac {
extern uintptr_t ingame_image_base;
#define RVA(a) ((uintptr_t)a + ingame_image_base)
typedef void __stdcall CallbackFunc(PCONTEXT);
class HookCtx {
public:
Expand Down Expand Up @@ -159,6 +161,29 @@ static inline R asm_call(Args... args) {
}
}

template <uintptr_t addr, CallType type, typename R = void, typename... Args>
static inline R asm_call_rel(Args... args)
{
uintptr_t _addr = RVA(addr);
if constexpr (type == Cdecl) {
auto* func = (R(__cdecl*)(Args...))_addr;
return func(args...);
} else if constexpr (type == Stdcall) {
auto* func = (R(__stdcall*)(Args...))_addr;
return func(args...);
} else if constexpr (type == Fastcall) {
auto* func = (R(__fastcall*)(Args...))_addr;
return func(args...);
} else if constexpr (type == Vectorcall) {
auto* func = (R(__vectorcall*)(Args...))_addr;
return func(args...);
} else if constexpr (type == Thiscall) {
auto* func = (R(__thiscall*)(Args...))_addr;
return func(args...);
}
}


inline void PushHelper32(CONTEXT* pCtx, DWORD value)
{
pCtx->Esp -= 4;
Expand Down
2 changes: 1 addition & 1 deletion thprac/src/thprac/thprac_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ void RemoteInit()
{
if (((int)&__ImageBase) != ((int)GetModuleHandleW(nullptr))) {
ExeSig exeSig;
if (GetExeInfoEx((size_t)GetCurrentProcess(), exeSig)) {
if (GetExeInfoEx((size_t)GetCurrentProcess(), (uintptr_t)GetModuleHandleW(NULL), exeSig)) {
for (auto& gameDef : gGameDefs) {
if (gameDef.catagory != CAT_MAIN && gameDef.catagory != CAT_SPINOFF_STG) {
continue;
Expand Down
36 changes: 23 additions & 13 deletions thprac/src/thprac/thprac_launcher_games.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,22 +99,22 @@ bool GetExeInfo(void* exeBuffer, size_t exeSize, ExeSig& exeSigOut)

return true;
}
bool GetExeInfoEx(size_t process, ExeSig& exeSigOut)
bool GetExeInfoEx(uintptr_t hProcess, uintptr_t base, ExeSig& exeSigOut)
{
HANDLE hProc = (HANDLE)process;
DWORD bytesRead;
HANDLE hProc = (HANDLE)hProcess;

IMAGE_DOS_HEADER dosHeader;
if (!ReadProcessMemory(hProc, (void*)0x400000, &dosHeader, sizeof(IMAGE_DOS_HEADER), &bytesRead)) {
if (!ReadProcessMemory(hProc, (void*)base, &dosHeader, sizeof(IMAGE_DOS_HEADER), &bytesRead)) {
return false;
}
IMAGE_NT_HEADERS ntHeader;
if (!ReadProcessMemory(hProc, (void*)(0x400000 + dosHeader.e_lfanew), &ntHeader, sizeof(IMAGE_NT_HEADERS), &bytesRead)) {
if (!ReadProcessMemory(hProc, (void*)(base + dosHeader.e_lfanew), &ntHeader, sizeof(IMAGE_NT_HEADERS), &bytesRead)) {
return false;
}

exeSigOut.timeStamp = ntHeader.FileHeader.TimeDateStamp;
PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)((ULONG_PTR)(0x400000 + dosHeader.e_lfanew) + ((LONG)(LONG_PTR) & (((IMAGE_NT_HEADERS*)0)->OptionalHeader)) + ntHeader.FileHeader.SizeOfOptionalHeader);
PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)((ULONG_PTR)(base + dosHeader.e_lfanew) + ((LONG)(LONG_PTR) & (((IMAGE_NT_HEADERS*)0)->OptionalHeader)) + ntHeader.FileHeader.SizeOfOptionalHeader);
for (int i = 0; i < ntHeader.FileHeader.NumberOfSections; i++, pSection++) {
IMAGE_SECTION_HEADER section;
if (!ReadProcessMemory(hProc, (void*)(pSection), &section, sizeof(IMAGE_SECTION_HEADER), &bytesRead)) {
Expand Down Expand Up @@ -1524,7 +1524,7 @@ class THGameGui {

return THPrac::LoadSelf(process, extraData, extraSize);
}
static bool WINAPI CheckProcessOmni(PROCESSENTRY32W& proc)
static bool WINAPI CheckProcessOmni(PROCESSENTRY32W& proc, uintptr_t& base)
{
if (wcscmp(L"東方紅魔郷.exe", proc.szExeFile)) {
if (proc.szExeFile[0] != L't' || proc.szExeFile[1] != L'h')
Expand All @@ -1543,23 +1543,29 @@ class THGameGui {
if (!hProc)
return false;

base = GetGameModuleBase(hProc);
if (!base) {
return false;
}

// Check THPrac signature
DWORD sigAddr = 0;
DWORD sigCheck = 0;
DWORD bytesReadRPM;
ReadProcessMemory(hProc, (void*)0x40003c, &sigAddr, 4, &bytesReadRPM);

ReadProcessMemory(hProc, (void*)(base + 0x3c), &sigAddr, 4, &bytesReadRPM);
if (bytesReadRPM != 4 || !sigAddr) {
CloseHandle(hProc);
return false;
}
ReadProcessMemory(hProc, (void*)(0x400000 + sigAddr - 4), &sigCheck, 4, &bytesReadRPM);
ReadProcessMemory(hProc, (void*)(base + sigAddr - 4), &sigCheck, 4, &bytesReadRPM);
if (bytesReadRPM != 4 || sigCheck) {
CloseHandle(hProc);
return false;
}

ExeSig sig;
if (GetExeInfoEx((size_t)hProc, sig)) {
if (GetExeInfoEx((size_t)hProc, base, sig)) {
for (auto& gameDef : gGameDefs) {
if (gameDef.catagory != CAT_MAIN && gameDef.catagory != CAT_SPINOFF_STG) {
continue;
Expand All @@ -1573,7 +1579,7 @@ class THGameGui {
CloseHandle(hProc);
return false;
}
static DWORD WINAPI CheckProcess(DWORD process, std::wstring& exePath)
static DWORD WINAPI CheckProcess(DWORD process, std::wstring& exePath, uintptr_t& base)
{
// TODO: THPRAC SIG CHECK & EXE TIME STAMP CHECK
int result = 0;
Expand All @@ -1596,6 +1602,7 @@ class THGameGui {
modulePath = GetUnifiedPath(std::wstring(me32.szExePath));
if (exePathU16 == modulePath) {
result = 1;
base = (uintptr_t)me32.modBaseAddr;
break;
}
}
Expand Down Expand Up @@ -1646,14 +1653,15 @@ class THGameGui {
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (Process32FirstW(snapshot, &procEntry)) {
do {
bool test = isOmni ? CheckProcessOmni(procEntry) : CheckProcess(procEntry.th32ProcessID, exePath);
uintptr_t base;
bool test = isOmni ? CheckProcessOmni(procEntry, base) : CheckProcess(procEntry.th32ProcessID, exePath, base);
if (test) {
auto hProc = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
FALSE,
procEntry.th32ProcessID);
if (hProc) {
auto result = (WriteTHPracSig(hProc) && LocalApplyTHPrac(hProc));
auto result = (WriteTHPracSig(hProc, base) && LocalApplyTHPrac(hProc));
CloseHandle(hProc);
return result ? 1 : 0;
}
Expand Down Expand Up @@ -1721,6 +1729,8 @@ class THGameGui {
startup_info.cb = sizeof(STARTUPINFOW);
CreateProcessW(currentInstPath.c_str(), nullptr, nullptr, nullptr, false, CREATE_SUSPENDED, nullptr, currentInstDir.c_str(), &startup_info, &proc_info);

uintptr_t base = GetGameModuleBase(proc_info.hProcess);

if (currentInst.useVpatch) {
auto exeName = GetNameFromFullPath(currentInstPath);
if (exeName == L"東方紅魔郷.exe") {
Expand All @@ -1734,7 +1744,7 @@ class THGameGui {
}
}
if (currentInst.useTHPrac) {
result = (WriteTHPracSig(proc_info.hProcess) && LocalApplyTHPrac(proc_info.hProcess));
result = (WriteTHPracSig(proc_info.hProcess, base) && LocalApplyTHPrac(proc_info.hProcess));
}

if (!result) {
Expand Down
2 changes: 1 addition & 1 deletion thprac/src/thprac/thprac_launcher_games.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
namespace THPrac {

bool GetExeInfo(void* exeBuffer, size_t exeSize, ExeSig& exeSigOut);
bool GetExeInfoEx(size_t process, ExeSig& exeSigOut);
bool GetExeInfoEx(uintptr_t hProcess, uintptr_t base, ExeSig& exeSigOut);

bool LauncherGamesGuiUpd();
void LauncherGamesGuiSwitch(const char* idStr);
Expand Down
13 changes: 13 additions & 0 deletions thprac/src/thprac/thprac_launcher_games_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ extern void TH165Init();
extern void TH17Init();
extern void TH18Init();
extern void TH185Init();
extern void TH19Init();

static THKnownGame gKnownGames[] {
{ "th06",
Expand Down Expand Up @@ -509,6 +510,18 @@ static THGameSig gGameDefs[] {
0xcd13, 0xc4ab, 0x44a4, 0x04c4, 0xa2be },
{ 0xeff8426f, 0xa6522a33,
0xdc04050e, 0xc99233fe } } },
{ "th19",
L"2400340",
TH19_TITLE,
CAT_MAIN,
nullptr,
L"%APPDATA%\\ShanghaiAlice\\th19",
TH19Init,
{ 1690598468, 1433600,
{ 0xdfa9, 0x4247, 0xaa43, 0xba3e, 0xbaba,
0x0e2e, 0x1d90, 0xb748, 0x8d5c, 0x1fbb },
{ 0x1ef2d050, 0xbddd8da2,
0x56cedb87, 0xe674cd2c } } },
};

#pragma region Game Roll Def
Expand Down
8 changes: 6 additions & 2 deletions thprac/src/thprac/thprac_locale_def.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace THPrac {

const char* th_glossary_str[3][897]
const char* th_glossary_str[3][898]
{
{
"",
Expand Down Expand Up @@ -515,6 +515,7 @@ const char* th_glossary_str[3][897]
"...并写入replay中",
"牙冷却",
"0CD",
"TH19 东方兽王园 〜 Unfinished Dream of All Living Ghost.",
"中止",
"以管理员身份启动thprac",
"启动游戏后:",
Expand Down Expand Up @@ -1414,6 +1415,7 @@ const char* th_glossary_str[3][897]
"...and write into the replay",
"Fang CD",
"0CD",
"TH19 Unfinished Dream of All Living Ghost",
"Abort",
"Launch thprac with admin rights",
"After launching game:",
Expand Down Expand Up @@ -2313,6 +2315,7 @@ const char* th_glossary_str[3][897]
"...そしてリプレイに書き込みます ",
"牙CD",
"0CD",
"TH19 東方獣王園 〜 Unfinished Dream of All Living Ghost.",
"中止",
"管理者権限でthpracを起動する",
"ゲーム起動後:",
Expand Down Expand Up @@ -19963,7 +19966,7 @@ const th_sections_t th_sections_cbt[1][2][1]

}

const wchar_t __thprac_loc_range_zh[3141] {
const wchar_t __thprac_loc_range_zh[3143] {
0x0020, 0x00FF,
0x2014, 0x2014,
0x201c, 0x201c,
Expand All @@ -19973,6 +19976,7 @@ const wchar_t __thprac_loc_range_zh[3141] {
0x3002, 0x3002,
0x300c, 0x300c,
0x300d, 0x300d,
0x301c, 0x301c,
0x4e00, 0x4e00,
0x4e03, 0x4e03,
0x4e07, 0x4e07,
Expand Down
Loading

0 comments on commit ff44cb8

Please sign in to comment.