mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-11-27 15:54:03 +08:00
275 lines
8.7 KiB
C++
275 lines
8.7 KiB
C++
#include "Reallive.h"
|
||
|
||
/********************************************************************************************
|
||
Reallive hook:
|
||
Process name is reallive.exe or reallive*.exe.
|
||
|
||
Technique to find Reallive hook is quite different from 2 above.
|
||
Usually Reallive engine has a font caching issue. This time we wait
|
||
until the first call to GetGlyphOutlineA. Reallive engine usually set
|
||
up stack frames so we can just refer to EBP to find function entry.
|
||
|
||
********************************************************************************************/
|
||
/** jichi 5/13/2015
|
||
* RealLive does not work for 水着少女と媚薬アイス from 裸足少女
|
||
* 012da80f cc int3
|
||
* 012da810 55 push ebp ; jichi: change to hook here
|
||
* 012da811 8bec mov ebp,esp
|
||
* 012da813 83ec 10 sub esp,0x10 ; jichi: hook here by default
|
||
* 012da816 53 push ebx
|
||
* 012da817 56 push esi
|
||
* 012da818 57 push edi
|
||
* 012da819 8b7d 18 mov edi,dword ptr ss:[ebp+0x18]
|
||
* 012da81c 81ff 5c810000 cmp edi,0x815c
|
||
* 012da822 75 0a jnz short reallive.012da82e
|
||
* 012da824 c745 18 9f840000 mov dword ptr ss:[ebp+0x18],0x849f
|
||
* 012da82b 8b7d 18 mov edi,dword ptr ss:[ebp+0x18]
|
||
* 012da82e b8 9041e301 mov eax,reallive.01e34190
|
||
* 012da833 b9 18a49001 mov ecx,reallive.0190a418
|
||
* 012da838 e8 a38d0000 call reallive.012e35e0
|
||
* 012da83d 85c0 test eax,eax
|
||
* 012da83f 74 14 je short reallive.012da855
|
||
* 012da841 e8 6addffff call reallive.012d85b0
|
||
* 012da846 ba 9041e301 mov edx,reallive.01e34190
|
||
* 012da84b b8 18a49001 mov eax,reallive.0190a418
|
||
* 012da850 e8 ab7c0000 call reallive.012e2500
|
||
* 012da855 8d45 f0 lea eax,dword ptr ss:[ebp-0x10]
|
||
* 012da858 50 push eax
|
||
* 012da859 8d4d f4 lea ecx,dword ptr ss:[ebp-0xc]
|
||
* 012da85c 51 push ecx
|
||
* 012da85d 8d55 fc lea edx,dword ptr ss:[ebp-0x4]
|
||
* 012da860 52 push edx
|
||
* 012da861 8d45 f8 lea eax,dword ptr ss:[ebp-0x8]
|
||
* 012da864 50 push eax
|
||
* 012da865 8bc7 mov eax,edi
|
||
* 012da867 e8 54dfffff call reallive.012d87c0
|
||
* 012da86c 8bf0 mov esi,eax
|
||
* 012da86e 83c4 10 add esp,0x10
|
||
* 012da871 85f6 test esi,esi
|
||
* 012da873 75 4b jnz short reallive.012da8c0
|
||
* 012da875 8d4d f4 lea ecx,dword ptr ss:[ebp-0xc]
|
||
* 012da878 51 push ecx
|
||
* 012da879 57 push edi
|
||
* 012da87a 8d4d f0 lea ecx,dword ptr ss:[ebp-0x10]
|
||
* 012da87d e8 cef0ffff call reallive.012d9950
|
||
* 012da882 8bf0 mov esi,eax
|
||
* 012da884 83c4 08 add esp,0x8
|
||
* 012da887 85f6 test esi,esi
|
||
*/
|
||
static bool InsertRealliveDynamicHook(LPVOID addr, hook_stack *stack)
|
||
{
|
||
if (addr != ::GetGlyphOutlineA)
|
||
return false;
|
||
// jichi 5/13/2015: Find the enclosing caller of GetGlyphOutlineA
|
||
if (DWORD i = stack->ebp)
|
||
{
|
||
i = *(DWORD *)(i + 4);
|
||
for (DWORD j = i; j > i - 0x100; j--)
|
||
if (*(WORD *)j == 0xec83)
|
||
{ // jichi 7/26/2014: function starts
|
||
// 012da80f cc int3
|
||
// 012da810 55 push ebp ; jichi: change to hook here
|
||
// 012da811 8bec mov ebp,esp
|
||
// 012da813 83ec 10 sub esp,0x10 ; jichi: hook here by default
|
||
if (*(DWORD *)(j - 3) == 0x83ec8b55)
|
||
j -= 3;
|
||
|
||
HookParam hp;
|
||
hp.address = j;
|
||
hp.offset = get_stack(5);
|
||
hp.split = get_reg(regs::esp);
|
||
hp.type = CODEC_ANSI_BE | USING_SPLIT;
|
||
// GROWL_DWORD(hp.address);
|
||
|
||
// RegisterEngineType(ENGINE_REALLIVE);
|
||
ConsoleOutput("RealLive: disable GDI hooks");
|
||
|
||
return NewHook(hp, "RealLive");
|
||
}
|
||
}
|
||
return true; // jichi 12/25/2013: return true
|
||
}
|
||
void InsertRealliveHook()
|
||
{
|
||
// ConsoleOutput("Probably Reallive. Wait for text.");
|
||
ConsoleOutput("TRIGGER Reallive");
|
||
trigger_fun = InsertRealliveDynamicHook;
|
||
}
|
||
|
||
bool RlBabelFilter(LPVOID data, size_t *size, HookParam *)
|
||
{
|
||
auto text = reinterpret_cast<LPSTR>(data);
|
||
auto len = reinterpret_cast<size_t *>(size);
|
||
|
||
if (text[0] == '\x01')
|
||
{
|
||
StringFilterBetween(text, len, "\x01", 1, "\x02", 1); // remove names
|
||
}
|
||
|
||
CharReplacer(text, len, '\x08', '"');
|
||
CharReplacer(text, len, '\x09', '\'');
|
||
CharReplacer(text, len, '\x0A', '\'');
|
||
CharFilter(text, len, '\x1F'); // remove color
|
||
StringReplacer(text, len, "\x89\x85", 2, "\x81\x63", 2); // "\x89\x85"-> shift-JIS"…"
|
||
StringReplacer(text, len, "\x89\x97", 2, "--", 2);
|
||
|
||
return true;
|
||
}
|
||
|
||
bool InsertRlBabelHook()
|
||
{
|
||
|
||
/*
|
||
* Sample games:
|
||
* https://vndb.org/r78318
|
||
*/
|
||
const BYTE bytes[] = {
|
||
0xCC, // int 3
|
||
0x55, // push ebp <- hook here
|
||
0x8B, 0xEC, // mov ebp,esp
|
||
0x83, 0xEC, 0x20, // sub esp,20
|
||
0xC7, 0x45, 0xFC, XX4 // mov [ebp-04],rlBabel.DLL+16804
|
||
};
|
||
|
||
HMODULE module = GetModuleHandleW(L"rlBabel.dll");
|
||
if (!module)
|
||
return false;
|
||
auto [minAddress, maxAddress] = Util::QueryModuleLimits(module);
|
||
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), minAddress, maxAddress);
|
||
if (!addr)
|
||
return false;
|
||
|
||
HookParam hp;
|
||
hp.address = addr + 1;
|
||
hp.offset = get_reg(regs::eax);
|
||
hp.type = USING_STRING;
|
||
hp.filter_fun = RlBabelFilter;
|
||
ConsoleOutput("INSERT RealLive Babel");
|
||
return NewHook(hp, "RealLive Babel");
|
||
}
|
||
namespace
|
||
{
|
||
bool clannad_en_steam()
|
||
{
|
||
// if ( v12 == 33116 || v12 == 33951 || v12 == 33962 )
|
||
BYTE sig[] = {
|
||
0x81, 0xFE, 0x5C, 0x81, 0x00, 0x00,
|
||
0x74, 0x10,
|
||
0x81, 0xFE, 0x9F, 0x84, 0x00, 0x00,
|
||
0x74, 0x08,
|
||
0x81, 0xFE, 0xAA, 0x84, 0x00, 0x00,
|
||
0x75, XX};
|
||
ULONG addr = MemDbg::findBytes(sig, sizeof(sig), processStartAddress, processStopAddress);
|
||
if (!addr)
|
||
return false;
|
||
|
||
HookParam hp;
|
||
hp.address = addr;
|
||
hp.offset = get_reg(regs::esi);
|
||
hp.type = USING_CHAR | CODEC_ANSI_LE;
|
||
return NewHook(hp, "RealLiveX");
|
||
}
|
||
}
|
||
namespace
|
||
{
|
||
// https://vndb.org/r1944
|
||
bool veryold()
|
||
{
|
||
HookParam hp;
|
||
hp.address = (DWORD)GetProcAddress(GetModuleHandleA("gdi32.dll"), "GetGlyphOutline");
|
||
hp.type = HOOK_RETURN;
|
||
hp.text_fun = [](hook_stack *stack, HookParam *hps, uintptr_t *data, uintptr_t *split, size_t *len)
|
||
{
|
||
hps->type = HOOK_EMPTY;
|
||
auto addr = findfuncstart(hps->address);
|
||
if (!addr)
|
||
return;
|
||
auto addrs = findxref_reverse_checkcallop(addr, processStartAddress, processStopAddress, 0xe8);
|
||
if (addrs.size() != 1)
|
||
return;
|
||
addr = addrs[0];
|
||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||
if (!addr)
|
||
return;
|
||
HookParam hp;
|
||
hp.address = addr;
|
||
hp.offset = get_stack(5);
|
||
hp.type = USING_CHAR | CODEC_ANSI_BE;
|
||
NewHook(hp, "RealLiveOld");
|
||
};
|
||
return NewHook(hp, "GetGlyphOutline");
|
||
}
|
||
}
|
||
bool Reallive::attach_function()
|
||
{
|
||
InsertRealliveHook();
|
||
InsertRlBabelHook() || clannad_en_steam() || veryold();
|
||
return true;
|
||
}
|
||
|
||
bool avg3216dattach_function()
|
||
{
|
||
BYTE pattern1[] = {
|
||
//clang-format off
|
||
0x3c, 0x81, XX2,
|
||
0x3c, 0x9f, XX2,
|
||
0x3c, 0xe0, XX2,
|
||
0x3c, 0xfc, XX2,
|
||
//clang-format on
|
||
};
|
||
BYTE pattern2[] = {
|
||
0x8b, 0x75, 0x08,
|
||
0x8a, 0x06,
|
||
0x3c, 0x81,
|
||
0x75, XX,
|
||
0x80, 0x7e, 0x01, 0x7a};
|
||
auto addr = MemDbg::findBytes(pattern2, sizeof(pattern2), processStartAddress, processStopAddress);
|
||
if (addr == 0)
|
||
return false;
|
||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||
if (addr == 0)
|
||
return false;
|
||
auto check = MemDbg::findBytes(pattern1, sizeof(pattern1), addr, addr + 0x200);
|
||
if (check == 0)
|
||
return false;
|
||
HookParam hp;
|
||
hp.address = addr;
|
||
hp.offset = get_stack(1);
|
||
hp.type = NO_CONTEXT | DATA_INDIRECT;
|
||
// GROWL_DWORD(hp.address);
|
||
return NewHook(hp, "avg3216d");
|
||
}
|
||
|
||
bool avg3216dattach_function2()
|
||
{
|
||
// https://vndb.org/v12860
|
||
// effect~悪魔の仔~
|
||
BYTE pattern2[] = {
|
||
//clang-format off
|
||
0x80, 0xf9, 0x81,
|
||
0x72, 0x05,
|
||
0x80, 0xf9, 0x9f,
|
||
0x76, XX, // 76 17
|
||
0x80, 0xf9, 0xe0,
|
||
0x72, 0x05,
|
||
0x80, 0xf9, 0xfc,
|
||
0x76, 0x0d,
|
||
//clang-format on
|
||
};
|
||
auto addr = MemDbg::findBytes(pattern2, sizeof(pattern2), processStartAddress, processStopAddress);
|
||
if (addr == 0)
|
||
return false;
|
||
addr = findfuncstart(addr, 0x200, true);
|
||
if (addr == 0)
|
||
return false;
|
||
HookParam hp;
|
||
hp.address = addr;
|
||
hp.offset = get_stack(1);
|
||
hp.type = USING_STRING;
|
||
// GROWL_DWORD(hp.address);
|
||
return NewHook(hp, "avg3217d");
|
||
}
|
||
bool avg3216d::attach_function()
|
||
{
|
||
return avg3216dattach_function() || avg3216dattach_function2();
|
||
} |