mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-11-28 00:04:03 +08:00
370 lines
14 KiB
C++
370 lines
14 KiB
C++
|
#include"Ryokucha.h"
|
|||
|
#include"ntxpundef.h"
|
|||
|
static void SpecialHookRyokucha(hook_stack* stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t*len)
|
|||
|
{
|
|||
|
for (DWORD i = 1; i < 5; i++) {
|
|||
|
DWORD j = stack->stack[i];
|
|||
|
if ((j >> 16) == 0 && (j >> 8)) {
|
|||
|
hp->offset = i << 2;
|
|||
|
*data = j;
|
|||
|
*len = 2;
|
|||
|
//hp->type &= ~EXTERN_HOOK;
|
|||
|
hp->text_fun = nullptr;
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
*len = 0;
|
|||
|
}
|
|||
|
bool InsertRyokuchaDynamicHook(LPVOID addr, uintptr_t frame, uintptr_t stack)
|
|||
|
{
|
|||
|
if (addr != ::GetGlyphOutlineA)
|
|||
|
return false;
|
|||
|
|
|||
|
auto tib = (NT_TIB*)__readfsdword(0);
|
|||
|
auto exception = tib->ExceptionList;
|
|||
|
for (int i = 0; i < 1; i++) {
|
|||
|
exception = exception->Next;
|
|||
|
}
|
|||
|
auto handler=(DWORD)exception->Handler;
|
|||
|
auto ptr=*(DWORD*)((DWORD)exception+0xC);
|
|||
|
auto insert_addr=ptr+*(DWORD*)(ptr-4);
|
|||
|
auto flag=(*(DWORD*)(insert_addr+3)==handler);
|
|||
|
|
|||
|
if (flag) {
|
|||
|
HookParam hp;
|
|||
|
hp.address = insert_addr;
|
|||
|
hp.text_fun = SpecialHookRyokucha;
|
|||
|
hp.type = CODEC_ANSI_BE|USING_CHAR;
|
|||
|
ConsoleOutput("INSERT StudioRyokucha");
|
|||
|
return NewHook(hp, "StudioRyokucha");
|
|||
|
}
|
|||
|
//else ConsoleOutput("Unknown Ryokucha engine.");
|
|||
|
ConsoleOutput("StudioRyokucha: failed");
|
|||
|
return true;
|
|||
|
}
|
|||
|
void InsertRyokuchaHook()
|
|||
|
{
|
|||
|
//ConsoleOutput("Probably Ryokucha. Wait for text.");
|
|||
|
trigger_fun = InsertRyokuchaDynamicHook;
|
|||
|
ConsoleOutput("TRIGGER Ryokucha");
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* jichi 1/10/2014: Rai7 puk
|
|||
|
* See: http://www.hongfire.com/forum/showthread.php/421909-%E3%80%90Space-Warfare-Sim%E3%80%91Rai-7-PUK/page10
|
|||
|
* See: www.hongfire.com/forum/showthread.php/421909-%E3%80%90Space-Warfare-Sim%E3%80%91Rai-7-PUK/page19
|
|||
|
*
|
|||
|
* Version: R7P3-13v2(131220).rar, pass: sstm http://pan.baidu.com/share/home?uk=3727185265#category/type=0
|
|||
|
* /HS0@409524
|
|||
|
*/
|
|||
|
//bool InsertRai7Hook()
|
|||
|
//{
|
|||
|
//}
|
|||
|
|
|||
|
/**
|
|||
|
* jichi 10/1/2013: sol-fa-soft
|
|||
|
* See (tryguy): http://www.hongfire.com/forum/printthread.php?t=36807&pp=10&page=639
|
|||
|
*
|
|||
|
* @tryguy
|
|||
|
* [sol-fa-soft]
|
|||
|
* 17 スク水不要<EFBFBD> /HA4@4AD140
|
|||
|
* 18 ななちも<EFBFBD>とぁ<EFBFBD>しょ: /HA4@5104A0
|
|||
|
* 19 発惁<EFBFBD>んこぁ<EFBFBD><EFBFBD> /HA4@51D720
|
|||
|
* 20 わたし<EFBFBD>たまごさ<EFBFBD> /HA4@4968E0
|
|||
|
* 21 修学旡<EFBFBD>夜更かし<EFBFBD> /HA4@49DC00
|
|||
|
* 22 おぼえたてキヂ<EFBFBD>: /HA4@49DDB0
|
|||
|
* 23 ちっさい巫女さんSOS: /HA4@4B4AA0
|
|||
|
* 24 はじめてのお<EFBFBD>ろやさん: /HA4@4B5600
|
|||
|
* 25 はきわすれ愛好<EFBFBD> /HA4@57E360
|
|||
|
* 26 朝っぱらから発惮<EFBFBD><EFBFBD> /HA4@57E360
|
|||
|
* 27 となり<EFBFBD>ヴァンパイア: /HA4@5593B0
|
|||
|
* 28 麦わら帽子と水辺の妖精: /HA4@5593B0
|
|||
|
* 29 海と温泉と夏休み: /HA4@6DE8E0
|
|||
|
* 30 駏<EFBFBD>子屋さん繁盛<EFBFBD> /HA4@6DEC90
|
|||
|
* 31 浴衣の下<EFBFBD>… <EFBFBD>神社で発見<EFBFBD>ノ<EFBFBD>パン少女 /HA4@6DEC90
|
|||
|
* 32 プ<EFBFBD>ルのじか<EFBFBD>スク水不要<EFBFBD>: /HA4@62AE10
|
|||
|
* 33 妹のお泊まり<EFBFBD> /HA4@6087A0
|
|||
|
* 34 薝<EFBFBD>少女: /HA4@6087A0
|
|||
|
* 35 あや<EFBFBD>Princess Intermezzo: /HA4@609BF0
|
|||
|
*
|
|||
|
* SG01 男湯<EFBFBD>: /HA4@6087A0
|
|||
|
*
|
|||
|
* c71 真<EFBFBD>の大晦日CD: /HA4@516b50
|
|||
|
* c78 sol-fa-soft真夏<EFBFBD>お気楽CD: /HA4@6DEC90
|
|||
|
*
|
|||
|
* Example: 35 あや<EFBFBD>Princess Intermezzo: /HA4@609BF0
|
|||
|
* - addr: 6331376 = 0x609bf0
|
|||
|
* - length_offset: 1
|
|||
|
* - off: 4
|
|||
|
* - type: 4
|
|||
|
*
|
|||
|
* ASCII: あや<EFBFBD> addr_offset = -50
|
|||
|
* Function starts
|
|||
|
* 00609bef /> cc int3
|
|||
|
* 00609bf0 /> 55 push ebp
|
|||
|
* 00609bf1 |. 8bec mov ebp,esp
|
|||
|
* 00609bf3 |. 64:a1 00000000 mov eax,dword ptr fs:[0]
|
|||
|
* 00609bf9 |. 6a ff push -0x1
|
|||
|
* 00609bfb |. 68 e1266300 push あや<EFBFBD>006326e1
|
|||
|
* 00609c00 |. 50 push eax
|
|||
|
* 00609c01 |. 64:8925 000000>mov dword ptr fs:[0],esp
|
|||
|
* 00609c08 |. 81ec 80000000 sub esp,0x80
|
|||
|
* 00609c0e |. 53 push ebx
|
|||
|
* 00609c0f |. 8b5d 08 mov ebx,dword ptr ss:[ebp+0x8]
|
|||
|
* 00609c12 |. 57 push edi
|
|||
|
* 00609c13 |. 8bf9 mov edi,ecx
|
|||
|
* 00609c15 |. 8b07 mov eax,dword ptr ds:[edi]
|
|||
|
* 00609c17 |. 83f8 02 cmp eax,0x2
|
|||
|
* 00609c1a |. 75 1f jnz short あや<EFBFBD>00609c3b
|
|||
|
* 00609c1c |. 3b5f 40 cmp ebx,dword ptr ds:[edi+0x40]
|
|||
|
* 00609c1f |. 75 1a jnz short あや<EFBFBD>00609c3b
|
|||
|
* 00609c21 |. 837f 44 00 cmp dword ptr ds:[edi+0x44],0x0
|
|||
|
* 00609c25 |. 74 14 je short あや<EFBFBD>00609c3b
|
|||
|
* 00609c27 |. 5f pop edi
|
|||
|
* 00609c28 |. b0 01 mov al,0x1
|
|||
|
* 00609c2a |. 5b pop ebx
|
|||
|
* 00609c2b |. 8b4d f4 mov ecx,dword ptr ss:[ebp-0xc]
|
|||
|
* 00609c2e |. 64:890d 000000>mov dword ptr fs:[0],ecx
|
|||
|
* 00609c35 |. 8be5 mov esp,ebp
|
|||
|
* 00609c37 |. 5d pop ebp
|
|||
|
* 00609c38 |. c2 0400 retn 0x4
|
|||
|
* Function stops
|
|||
|
*
|
|||
|
* WideChar: こいな<EFBFBD>小田舎で初恋x中出しセクシャルライ<EFBFBD>, addr_offset = -53
|
|||
|
* 0040653a cc int3
|
|||
|
* 0040653b cc int3
|
|||
|
* 0040653c cc int3
|
|||
|
* 0040653d cc int3
|
|||
|
* 0040653e cc int3
|
|||
|
* 0040653f cc int3
|
|||
|
* 00406540 > 55 push ebp
|
|||
|
* 00406541 . 8bec mov ebp,esp
|
|||
|
* 00406543 . 64:a1 00000000 mov eax,dword ptr fs:[0]
|
|||
|
* 00406549 . 6a ff push -0x1
|
|||
|
* 0040654b . 68 f1584300 push erondo01.004358f1
|
|||
|
* 00406550 . 50 push eax
|
|||
|
* 00406551 . 64:8925 000000>mov dword ptr fs:[0],esp
|
|||
|
* 00406558 . 83ec 6c sub esp,0x6c
|
|||
|
* 0040655b . 53 push ebx
|
|||
|
* 0040655c . 8bd9 mov ebx,ecx
|
|||
|
* 0040655e . 57 push edi
|
|||
|
* 0040655f . 8b03 mov eax,dword ptr ds:[ebx]
|
|||
|
* 00406561 . 8b7d 08 mov edi,dword ptr ss:[ebp+0x8]
|
|||
|
* 00406564 . 83f8 02 cmp eax,0x2
|
|||
|
* 00406567 . 75 1f jnz short erondo01.00406588
|
|||
|
* 00406569 . 3b7b 3c cmp edi,dword ptr ds:[ebx+0x3c]
|
|||
|
* 0040656c . 75 1a jnz short erondo01.00406588
|
|||
|
* 0040656e . 837b 40 00 cmp dword ptr ds:[ebx+0x40],0x0
|
|||
|
* 00406572 . 74 14 je short erondo01.00406588
|
|||
|
* 00406574 . 5f pop edi
|
|||
|
* 00406575 . b0 01 mov al,0x1
|
|||
|
* 00406577 . 5b pop ebx
|
|||
|
* 00406578 . 8b4d f4 mov ecx,dword ptr ss:[ebp-0xc]
|
|||
|
* 0040657b . 64:890d 000000>mov dword ptr fs:[0],ecx
|
|||
|
* 00406582 . 8be5 mov esp,ebp
|
|||
|
* 00406584 . 5d pop ebp
|
|||
|
* 00406585 . c2 0400 retn 0x4
|
|||
|
*
|
|||
|
* WideChar: 祝福<EFBFBD>鐘<EFBFBD>音は、桜色の風と共に, addr_offset = -50,
|
|||
|
* FIXME: how to know if it is UTF16? This game has /H code, though:
|
|||
|
*
|
|||
|
* /HA-4@94D62:shukufuku_main.exe
|
|||
|
*
|
|||
|
* 011d619e cc int3
|
|||
|
* 011d619f cc int3
|
|||
|
* 011d61a0 55 push ebp
|
|||
|
* 011d61a1 8bec mov ebp,esp
|
|||
|
* 011d61a3 64:a1 00000000 mov eax,dword ptr fs:[0]
|
|||
|
* 011d61a9 6a ff push -0x1
|
|||
|
* 011d61ab 68 d1811f01 push .011f81d1
|
|||
|
* 011d61b0 50 push eax
|
|||
|
* 011d61b1 64:8925 00000000 mov dword ptr fs:[0],esp
|
|||
|
* 011d61b8 81ec 80000000 sub esp,0x80
|
|||
|
* 011d61be 53 push ebx
|
|||
|
* 011d61bf 8b5d 08 mov ebx,dword ptr ss:[ebp+0x8]
|
|||
|
* 011d61c2 57 push edi
|
|||
|
* 011d61c3 8bf9 mov edi,ecx
|
|||
|
* 011d61c5 8b07 mov eax,dword ptr ds:[edi]
|
|||
|
* 011d61c7 83f8 02 cmp eax,0x2
|
|||
|
* 011d61ca 75 1f jnz short .011d61eb
|
|||
|
* 011d61cc 3b5f 40 cmp ebx,dword ptr ds:[edi+0x40]
|
|||
|
* 011d61cf 75 1a jnz short .011d61eb
|
|||
|
* 011d61d1 837f 44 00 cmp dword ptr ds:[edi+0x44],0x0
|
|||
|
* 011d61d5 74 14 je short .011d61eb
|
|||
|
* 011d61d7 5f pop edi
|
|||
|
* 011d61d8 b0 01 mov al,0x1
|
|||
|
* 011d61da 5b pop ebx
|
|||
|
* 011d61db 8b4d f4 mov ecx,dword ptr ss:[ebp-0xc]
|
|||
|
* 011d61de 64:890d 00000000 mov dword ptr fs:[0],ecx
|
|||
|
* 011d61e5 8be5 mov esp,ebp
|
|||
|
* 011d61e7 5d pop ebp
|
|||
|
* 011d61e8 c2 0400 retn 0x4
|
|||
|
*/
|
|||
|
bool InsertScenarioPlayerHook()
|
|||
|
{
|
|||
|
PcHooks::hookOtherPcFunctions();
|
|||
|
//const BYTE bytes[] = {
|
|||
|
// 0x53, // 00609c0e |. 53 push ebx
|
|||
|
// 0x8b,0x5d,0x08, // 00609c0f |. 8b5d 08 mov ebx,dword ptr ss:[ebp+0x8]
|
|||
|
// 0x57, // 00609c12 |. 57 push edi
|
|||
|
// 0x8b,0xf9, // 00609c13 |. 8bf9 mov edi,ecx
|
|||
|
// 0x8b,0x07, // 00609c15 |. 8b07 mov eax,dword ptr ds:[edi]
|
|||
|
// 0x83,0xf8, 0x02, // 00609c17 |. 83f8 02 cmp eax,0x2
|
|||
|
// 0x75, 0x1f, // 00609c1a |. 75 1f jnz short あや<E38182>00609c3b
|
|||
|
// 0x3b,0x5f, 0x40, // 00609c1c |. 3b5f 40 cmp ebx,dword ptr ds:[edi+0x40]
|
|||
|
// 0x75, 0x1a, // 00609c1f |. 75 1a jnz short あや<E38182>00609c3b
|
|||
|
// 0x83,0x7f, 0x44, 0x00, // 00609c21 |. 837f 44 00 cmp dword ptr ds:[edi+0x44],0x0
|
|||
|
// 0x74, 0x14, // 00609c25 |. 74 14 je short あや<E38182>00609c3b
|
|||
|
//};
|
|||
|
//enum { addr_offset = 0x00609bf0 - 0x00609c0e }; // distance to the beginning of the function
|
|||
|
|
|||
|
const BYTE bytes[] = {
|
|||
|
0x74, 0x14, // 00609c25 |. 74 14 je short あや<E38182>00609c3b
|
|||
|
0x5f, // 00609c27 |. 5f pop edi
|
|||
|
0xb0, 0x01, // 00609c28 |. b0 01 mov al,0x1
|
|||
|
0x5b, // 00609c2a |. 5b pop ebx
|
|||
|
0x8b,0x4d, 0xf4 // 00609c2b |. 8b4d f4 mov ecx,dword ptr ss:[ebp-0xc]
|
|||
|
};
|
|||
|
enum { // distance to the beginning of the function
|
|||
|
addr_offset_A = 0x00609bf0 - 0x00609c25 // -53
|
|||
|
, addr_offset_W = 0x00406540 - 0x00406572 // -50
|
|||
|
};
|
|||
|
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
|||
|
ULONG start = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
|
|||
|
if (!start) {
|
|||
|
ConsoleOutput("ScenarioPlayer: pattern not found");
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
DWORD addr = MemDbg::findEnclosingAlignedFunction(start, 80); // range is around 50, use 80
|
|||
|
|
|||
|
enum : BYTE { push_ebp = 0x55 }; // 011d4c80 /$ 55 push ebp
|
|||
|
if (!addr || *(BYTE *)addr != push_ebp) {
|
|||
|
ConsoleOutput("ScenarioPlayer: pattern found but the function offset is invalid");
|
|||
|
return false;
|
|||
|
}
|
|||
|
auto succ=false;
|
|||
|
HookParam hp;
|
|||
|
hp.address = addr;
|
|||
|
hp.offset=get_stack(1);
|
|||
|
if (
|
|||
|
(addr - start == addr_offset_W)||
|
|||
|
(
|
|||
|
(Util::FindImportEntry(processStartAddress,(DWORD)GetGlyphOutlineA)==0)&&
|
|||
|
(Util::FindImportEntry(processStartAddress,(DWORD)TextOutA)==0)&&
|
|||
|
(Util::FindImportEntry(processStartAddress,(DWORD)ExtTextOutA)==0)&&
|
|||
|
(Util::FindImportEntry(processStartAddress,(DWORD)GetTextExtentPoint32A)==0)
|
|||
|
//祝福の鐘の音は、桜色の風と共に
|
|||
|
)
|
|||
|
) {
|
|||
|
// Artikash 8/18/2018: can't figure out how to tell apart which hook is needed, so alert user
|
|||
|
// (The method used to tell the hooks apart previously fails on https://vndb.org/v19713)
|
|||
|
|
|||
|
hp.type = CODEC_UTF16;
|
|||
|
ConsoleOutput("INSERT ScenarioPlayerW");
|
|||
|
succ=NewHook(hp, "ScenarioPlayerW");
|
|||
|
} else {
|
|||
|
hp.type = CODEC_ANSI_BE; // 4
|
|||
|
ConsoleOutput("INSERT ScenarioPlayerA");
|
|||
|
succ=NewHook(hp, "ScenarioPlayerA");
|
|||
|
}
|
|||
|
ConsoleOutput("Text encoding might be wrong: try changing it if this hook finds garbage!");
|
|||
|
return succ;
|
|||
|
}
|
|||
|
|
|||
|
bool InsertScenarioPlayerHookx() {
|
|||
|
//夏彩恋呗
|
|||
|
//为避免和engine中的冲突,进行一次xref
|
|||
|
const BYTE bytes[] = {
|
|||
|
0xC1,0xE8,0x02,0x25,0x01,0xFF,0xFF,0xFF,0x89,0x45,XX
|
|||
|
};
|
|||
|
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
|||
|
ConsoleOutput("%p", addr);
|
|||
|
if (addr == 0)return false;
|
|||
|
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
|||
|
ConsoleOutput("%p", addr);
|
|||
|
if (addr == 0)return false;
|
|||
|
auto addrs = findxref_reverse_checkcallop(addr, addr - 0x1000, addr, 0xe9);
|
|||
|
if (addrs.size() != 1)return false;
|
|||
|
addr = addrs[0];
|
|||
|
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
|||
|
if (addr == 0)return false;
|
|||
|
HookParam hp;
|
|||
|
hp.address = addr;
|
|||
|
hp.offset=get_stack(1);
|
|||
|
hp.type = CODEC_UTF16;
|
|||
|
return NewHook(hp, "sutajioryokutyaW");
|
|||
|
}
|
|||
|
namespace{
|
|||
|
bool Iyashikei(){
|
|||
|
//癒し系ソープ嬢ヒロさん
|
|||
|
const BYTE bytes[] = {
|
|||
|
0x6A,0xFF,
|
|||
|
0x68,XX4,
|
|||
|
0x64,0xA1,0x00,0x00,0x00,0x00,
|
|||
|
0x50,
|
|||
|
0x83,0xEC,0x08,
|
|||
|
0x56,
|
|||
|
0xA1,0x08,0x6E,0x6B,0x00,
|
|||
|
0x33,0xC4,
|
|||
|
0x50,
|
|||
|
0x8D,0x44,0x24,XX,
|
|||
|
0x64,0xA3,0x00,0x00,0x00,0x00,
|
|||
|
0x8B,0xF1,
|
|||
|
0x8B,0x44,0x24,XX,
|
|||
|
0x50,
|
|||
|
0x8D,0x4C,0x24,XX,
|
|||
|
0x51,
|
|||
|
0x8B,0xCE,
|
|||
|
0xE8,XX4
|
|||
|
};
|
|||
|
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
|||
|
if(addr==0)return false;
|
|||
|
HookParam hp;
|
|||
|
hp.address = addr;
|
|||
|
hp.offset=get_stack(1);
|
|||
|
hp.type = CODEC_ANSI_BE;
|
|||
|
return NewHook(hp, "Iyashikei");
|
|||
|
}
|
|||
|
}
|
|||
|
bool InsertScenarioPlayerHook_all(){
|
|||
|
bool b1= InsertScenarioPlayerHook();
|
|||
|
bool b2=InsertScenarioPlayerHookx();
|
|||
|
return b1||b2||Iyashikei();
|
|||
|
}
|
|||
|
bool Ryokucha::attach_function() {
|
|||
|
InsertRyokuchaHook();
|
|||
|
|
|||
|
if (Util::CheckFile(L"*.iar") && Util::CheckFile(L"*.sec5")) // jichi 9/27/2014: For new Ryokucha games
|
|||
|
InsertScenarioPlayerHook_all();
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
bool ScenarioPlayer_last::attach_function() {
|
|||
|
|
|||
|
return InsertScenarioPlayerHook_all();
|
|||
|
}
|
|||
|
bool Ryokucha2::attach_function() {
|
|||
|
//夏日
|
|||
|
const BYTE bytes[] = {
|
|||
|
0x8b,XX2,0x2b,0xd1,0xc1,0xfa,0x02,0x3b,0xd0,0x76
|
|||
|
};
|
|||
|
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
|||
|
ConsoleOutput("%p", addr);
|
|||
|
if (addr == 0)return false;
|
|||
|
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
|||
|
ConsoleOutput("%p", addr);
|
|||
|
if (addr == 0)return false;
|
|||
|
|
|||
|
HookParam hp;
|
|||
|
hp.address = addr;
|
|||
|
hp.offset =get_stack(6);
|
|||
|
hp.type = USING_STRING;
|
|||
|
hp.filter_fun = [](void* data, size_t* len, HookParam* hp) {
|
|||
|
std::string s = std::string(reinterpret_cast<char*>(data), *len);
|
|||
|
if (s[0] == '#')return false;
|
|||
|
return true;
|
|||
|
};
|
|||
|
return NewHook(hp, "sutajioryokutya");
|
|||
|
}
|