恍兮惚兮 edc5efec99 format
2024-11-02 15:49:09 +08:00

265 lines
8.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Atelier.h"
/********************************************************************************************
AtelierKaguya hook:
Game folder contains message.dat. Used by AtelierKaguya games.
Usually has font caching issue with TextOutA.
Game engine uses EBP to set up stack frame so we can easily trace back.
Keep step out until it's in main game module. We notice that either register or
stack contains string pointer before call instruction. But it's not quite stable.
In-depth analysis of the called function indicates that there's a loop traverses
the string one character by one. We can set a hook there.
This search process is too complex so I just make use of some characteristic
instruction(add esi,0x40) to locate the right point.
********************************************************************************************/
bool InsertAtelierHook()
{
PcHooks::hookOtherPcFunctions(); // lstrlenA gives good hook too
// SafeFillRange(processName, &base, &size);
// size=size-base;
// DWORD sig = 0x40c683; // add esi,0x40
// i=processStartAddress+SearchPattern(processStartAddress,processStopAddress-processStartAddress,&sig,3);
DWORD i;
for (i = processStartAddress; i < processStopAddress - 4; i++)
{
DWORD sig = *(DWORD *)i & 0xffffff;
if (0x40c683 == sig) // add esi,0x40
break;
}
if (i < processStopAddress - 4)
for (DWORD j = i - 0x200; i > j; i--)
if (*(DWORD *)i == 0xff6acccc)
{ // find the function entry
HookParam hp;
hp.address = i + 2;
hp.offset = get_stack(2);
hp.split = get_reg(regs::esp);
hp.type = USING_SPLIT;
ConsoleOutput("INSERT Aterlier KAGUYA");
// RegisterEngineType(ENGINE_ATELIER);
return NewHook(hp, "Atelier KAGUYA");
}
ConsoleOutput("Aterlier: failed");
return false;
// ConsoleOutput("Unknown Atelier KAGUYA engine.");
}
bool InsertAtelierKaguya2Hook()
{
/*
* Sample games:
* https://vndb.org/v22713
* https://vndb.org/v31685
* https://vndb.org/v37081
*/
const BYTE bytes[] = {
0x51, // push ecx << hook here
0x50, // push eax
0xE8, XX4, // call Start.exe+114307
0x83, 0xC4, 0x08, // add esp,08
0x85, 0xC0, // test eax,eax
0x78, 0xA1 // js Start.exe+48947
};
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr)
{
ConsoleOutput("Atelier KAGUYA2: pattern not found");
return false;
}
HookParam hp;
hp.address = addr;
hp.offset = get_reg(regs::eax);
hp.type = USING_STRING | EMBED_AFTER_OVERWRITE | EMBED_BEFORE_SIMPLE | EMBED_ABLE | EMBED_DYNA_SJIS;
hp.hook_font = F_TextOutA;
hp.filter_fun = NewLineCharToSpaceFilterA;
ConsoleOutput("INSERT Atelier KAGUYA2");
return NewHook(hp, "Atelier KAGUYA2");
}
bool InsertAtelierKaguya3Hook()
{
/*
* Sample games:
* https://vndb.org/v10082
*/
const BYTE bytes[] = {
0x55, // push ebp << hook here
0x8B, 0xEC, // mov ebp,esp
0x6A, 0xFF, // push -01
0x68, 0x80, 0xB9, 0x4D, 0x00, // push Start.exe+DB980
0x64, 0xA1, XX4, // mov eax,fs:[00000000]
0x50, // push eax
0x51, // push ecx
0x81, 0xEC, 0xAC, 0x00, 0x00, 0x00 // sub esp,000000AC
};
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr)
{
ConsoleOutput("Atelier KAGUYA3: pattern not found");
return false;
}
HookParam hp;
hp.address = addr;
hp.offset = get_reg(regs::eax);
hp.type = USING_STRING;
hp.filter_fun = NewLineCharToSpaceFilterA;
ConsoleOutput("INSERT Atelier KAGUYA3");
return NewHook(hp, "Atelier KAGUYA3");
}
bool InsertAtelierKaguya4Hook()
{
/*
* Sample games:
* https://vndb.org/v14705
*/
const BYTE bytes[] = {
0xE8, 0x90, 0xA8, 0xFF, 0xFF, // call Start.exe+18380
0x89, 0x45, 0xF8, // mov [ebp-08],eax
0x8B, 0x4D, 0x10, // mov ecx,[ebp+10]
0x51, // push ecx
0x8B, 0x55, 0x0C, // mov edx,[ebp+0C]
0x52, // push edx
0x8B, 0x45, 0x08, // mov eax,[ebp+08]
0x50 // push eax << hook here
};
enum
{
addr_offset = sizeof(bytes) - 1
};
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr)
{
ConsoleOutput("Atelier KAGUYA4: pattern not found");
return false;
}
HookParam hp;
hp.address = addr + addr_offset;
hp.offset = get_reg(regs::eax);
hp.type = USING_STRING;
hp.filter_fun = NewLineCharToSpaceFilterA;
ConsoleOutput("INSERT Atelier KAGUYA4");
return NewHook(hp, "Atelier KAGUYA4");
}
bool InsertAtelierKaguya5Hook()
{
/*
* Sample games:
* https://vndb.org/v11224
*/
const BYTE bytes[] = {
0xC2, 0x04, 0x00, // ret 0004
0x55, // push ebp << hook here
0x8B, 0xEC, // mov ebp,esp
0x6A, 0xFF, // push -01
0x68, XX4, // push Start.exe+DA680
0x64, 0xA1, 0x00, 0x00, 0x00, 0x00, // mov eax,fs:[00000000]
0x50, // push eax
0x51, // push ecx
};
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr)
{
ConsoleOutput("Atelier KAGUYA5: pattern not found");
return false;
}
HookParam hp;
hp.address = addr + 3;
hp.offset = get_reg(regs::eax);
hp.type = USING_STRING;
hp.filter_fun = NewLineCharToSpaceFilterA;
ConsoleOutput("INSERT Atelier KAGUYA5");
return NewHook(hp, "Atelier KAGUYA5");
}
bool InsertAtelierKaguyaX()
{
// エロティ課 誘惑研修はじまるよ~ しごいちゃうから覚悟なさい!
const BYTE bytes[] = {
0x3D, 0xF0, 0x41, 0x00, 0x00,
0x75};
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr)
return false;
addr = findfuncstart(addr, 0x1000);
if (!addr)
return false;
HookParam hp;
hp.address = addr;
hp.offset = get_stack(1);
hp.type = USING_STRING;
return NewHook(hp, "Atelier KAGUYA3");
}
bool Atelier::attach_function()
{
return InsertAtelierHook() || InsertAtelierKaguya2Hook() || InsertAtelierKaguyaX() || InsertAtelierKaguya3Hook() || InsertAtelierKaguya4Hook() || InsertAtelierKaguya5Hook();
}
bool Atelier2attach_function()
{
// https://vndb.org/v304
// ダンジョンクルセイダーズTALES OF DEMON EATER
const BYTE bytes[] = {
0x83, 0xFE, 0x34,
0xF6, XX,
0x88, XX, 0x24, 0x29,
0x7D};
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr)
return false;
HookParam hp;
hp.address = addr + sizeof(bytes) - 1;
hp.offset = get_stack(10);
hp.type = USING_CHAR | NO_CONTEXT;
// NO_CONTEXT:
// 牝奴隷 ~犯された放課後~
// https://vndb.org/v4351会把每行单独分开。
return NewHook(hp, "Atelier KAGUYA3");
}
bool Atelier2attach_function2()
{
// https://vndb.org/v7264
// 禁断の病棟 特殊精神科医 遊佐惣介の診察記録
auto addr = MemDbg::findCallerAddressAfterInt3((ULONG)TextOutA, processStartAddress, processStopAddress);
if (addr == 0)
return 0;
HookParam hp;
hp.address = addr;
hp.offset = get_stack(3);
hp.type = USING_STRING | DATA_INDIRECT;
return NewHook(hp, "Atelier KAGUYA");
}
bool Atelier2::attach_function()
{
return Atelier2attach_function() || Atelier2attach_function2();
}