This commit is contained in:
恍兮惚兮 2024-08-12 16:46:39 +08:00
parent 406438bb42
commit d31698c5d1
2 changed files with 277 additions and 217 deletions

View File

@ -1,4 +1,4 @@
#include"Candy.h" #include "Candy.h"
/******************************************************************************************** /********************************************************************************************
CandySoft hook: CandySoft hook:
@ -17,20 +17,21 @@ CandySoft hook:
But the original <EFBFBD>is quite different. I handle this case separately. But the original <EFBFBD>is quite different. I handle this case separately.
********************************************************************************************/ ********************************************************************************************/
namespace{ namespace
//https://vndb.org/v23666 {
// https://vndb.org/v23666
//(18禁ゲーム) [180928] [INTERHEART glossy] はらかつ3 ~子作りビジネス廃業の危機!?~ (iso+mds+rr3) //(18禁ゲーム) [180928] [INTERHEART glossy] はらかつ3 ~子作りビジネス廃業の危機!?~ (iso+mds+rr3)
//https://vndb.org/v47957 // https://vndb.org/v47957
//[240222][1261652][DESSERT Soft] 二股野郎とパパ活姉妹 パッケージ版 (mdf+mds) //[240222][1261652][DESSERT Soft] 二股野郎とパパ活姉妹 パッケージ版 (mdf+mds)
//https://vndb.org/v20368 // https://vndb.org/v20368
//[170224] [Sweet HEART] アイドル★クリニック 恋の薬でHな処方 (iso+mds+rr3) //[170224] [Sweet HEART] アイドル★クリニック 恋の薬でHな処方 (iso+mds+rr3)
bool filter(LPVOID data, size_t* size, HookParam*) bool filter(LPVOID data, size_t *size, HookParam *)
{ {
StringFilter((char*)data,size,"$L",2); StringFilter((char *)data, size, "$L", 2);
StringFilter((char*)data,size,"$M",2); StringFilter((char *)data, size, "$M", 2);
StringFilter((char*)data,size,"$S",2); StringFilter((char *)data, size, "$S", 2);
StringFilterBetween((char*)data,size,"[",1,"]",1); StringFilterBetween((char *)data, size, "[", 1, "]", 1);
StringFilterBetween((char*)data,size,"&",1,";",1); StringFilterBetween((char *)data, size, "&", 1, ";", 1);
return true; return true;
// else // else
// { // {
@ -77,91 +78,102 @@ namespace{
} }
uintptr_t hh() uintptr_t hh()
{ {
//void __usercall sub_425580(char *a1@<edx>, int a2@<ecx>, int a3) // void __usercall sub_425580(char *a1@<edx>, int a2@<ecx>, int a3)
BYTE bytes[]={ BYTE bytes[] = {
0x3c,0x24, //clang-format off
0x75,XX, 0x3c, 0x24,
0x80,0x7e,0x01,0x00, 0x75, XX,
0x74,XX, 0x80, 0x7e, 0x01, 0x00,
0x83,XX,0x02, 0x74, XX,
0x83,XX,0x02, 0x83, XX, 0x02,
0x83, XX, 0x02,
//clang-format on
}; };
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress); auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (!addr) return 0; if (!addr)
addr=findfuncstart(addr,0x400); return 0;
addr = findfuncstart(addr, 0x400);
return addr; return addr;
} }
} }
namespace { // unnamed Candy namespace
{ // unnamed Candy
// jichi 8/23/2013: split into two different engines // jichi 8/23/2013: split into two different engines
//if (_wcsicmp(processName, L"systemc.exe")==0) // if (_wcsicmp(processName, L"systemc.exe")==0)
// Process name is "SystemC.exe" // Process name is "SystemC.exe"
bool InsertCandyHook1() bool InsertCandyHook1()
{ {
for (DWORD i = processStartAddress + 0x1000; i < processStopAddress - 4; i++) for (DWORD i = processStartAddress + 0x1000; i < processStopAddress - 4; i++)
if ((*(DWORD *)i&0xffffff) == 0x24f980) // cmp cl,24 if ((*(DWORD *)i & 0xffffff) == 0x24f980) // cmp cl,24
for (DWORD j = i, k = i - 0x100; j > k; j--) for (DWORD j = i, k = i - 0x100; j > k; j--)
if (*(DWORD *)j == 0xc0330a8a) { // mov cl,[edx]; xor eax,eax if (*(DWORD *)j == 0xc0330a8a)
{ // mov cl,[edx]; xor eax,eax
HookParam hp; HookParam hp;
hp.address = j; hp.address = j;
hp.offset=get_reg(regs::edx); hp.offset = get_reg(regs::edx);
hp.type = USING_STRING; hp.type = USING_STRING;
ConsoleOutput("INSERT SystemC#1"); ConsoleOutput("INSERT SystemC#1");
//RegisterEngineType(ENGINE_CANDY); // RegisterEngineType(ENGINE_CANDY);
return NewHook(hp, "SystemC"); return NewHook(hp, "SystemC");
} }
ConsoleOutput("CandyHook1: failed"); ConsoleOutput("CandyHook1: failed");
return false; return false;
} }
uintptr_t __InsertCandyHook2() uintptr_t __InsertCandyHook2()
{ {
for (DWORD i = processStartAddress + 0x1000; i < processStopAddress - 4 ;i++) for (DWORD i = processStartAddress + 0x1000; i < processStopAddress - 4; i++)
if (*(WORD *)i == 0x5b3c || // cmp al,0x5b if (*(WORD *)i == 0x5b3c || // cmp al,0x5b
(*(DWORD *)i & 0xfff8fc) == 0x5bf880) // cmp reg,0x5B (*(DWORD *)i & 0xfff8fc) == 0x5bf880) // cmp reg,0x5B
for (DWORD j = i, k = i - 0x100; j > k; j--) for (DWORD j = i, k = i - 0x100; j > k; j--)
if ((*(DWORD *)j & 0xffff) == 0x8b55) { // push ebp, mov ebp,esp, sub esp,* if ((*(DWORD *)j & 0xffff) == 0x8b55)
{ // push ebp, mov ebp,esp, sub esp,*
return j; return j;
} }
return 0; return 0;
} }
// jichi 8/23/2013: Process name is NOT "SystemC.exe" // jichi 8/23/2013: Process name is NOT "SystemC.exe"
bool InsertCandyHook2() bool InsertCandyHook2()
{ {
auto addr1=hh();//新版本的candy但是有时会和旧版在同一个地址。当是同一个地址时避让5个字节 auto addr1 = hh(); // 新版本的candy但是有时会和旧版在同一个地址。当是同一个地址时避让5个字节
auto addr2=__InsertCandyHook2(); auto addr2 = __InsertCandyHook2();
HookParam hp; HookParam hp;
hp.type=USING_STRING; hp.type = USING_STRING;
hp.filter_fun=filter; hp.filter_fun = filter;
if(addr2==0&&addr1==0)return false; if (addr2 == 0 && addr1 == 0)
else if(addr2==0&&addr1!=0){ return false;
hp.address=addr1; else if (addr2 == 0 && addr1 != 0)
hp.offset=get_reg(regs::edx); {
hp.address = addr1;
hp.offset = get_reg(regs::edx);
return NewHook(hp, "SystemC"); return NewHook(hp, "SystemC");
} }
else if(addr2!=0&&addr1==0){ else if (addr2 != 0 && addr1 == 0)
hp.address=addr2; {
hp.offset=get_stack(1); // jichi: text in arg1 hp.address = addr2;
hp.offset = get_stack(1); // jichi: text in arg1
return NewHook(hp, "SystemC"); return NewHook(hp, "SystemC");
} }
else{ else
if(addr1==addr2){ {
addr1+=5; if (addr1 == addr2)
{
addr1 += 5;
} }
hp.address=addr1; hp.address = addr1;
hp.offset=get_reg(regs::edx); hp.offset = get_reg(regs::edx);
auto succ=NewHook(hp, "SystemC"); auto succ = NewHook(hp, "SystemC");
hp.address=addr2; hp.address = addr2;
hp.offset=get_stack(1); hp.offset = get_stack(1);
succ|=NewHook(hp, "SystemC"); succ |= NewHook(hp, "SystemC");
return succ; return succ;
} }
} }
/** jichi 10/2/2013: CHECKPOINT /** jichi 10/2/2013: CHECKPOINT
* *
* [5/31/2013] Hもお勉強も<EFBFBD><EFBFBD> * [5/31/2013] Hもお勉強も<EFBFBD><EFBFBD>
* base = 0xf20000 * base = 0xf20000
@ -172,54 +184,58 @@ bool InsertCandyHook2()
* - off: 4294967288 = 0xfffffff8 = -8 * - off: 4294967288 = 0xfffffff8 = -8
* - type: 1089 = 0x441 * - type: 1089 = 0x441
*/ */
//bool InsertCandyHook3() // bool InsertCandyHook3()
//{ //{
// return false; // CHECKPOINT // return false; // CHECKPOINT
// const BYTE ins[] = { // const BYTE ins[] = {
// 0x83,0xc4, 0x0c, // add esp,0xc ; hook here // 0x83,0xc4, 0x0c, // add esp,0xc ; hook here
// 0x0f,0xb6,0xc0, // movzx eax,al // 0x0f,0xb6,0xc0, // movzx eax,al
// 0x85,0xc0, // test eax,eax // 0x85,0xc0, // test eax,eax
// 0x75, 0x0e // jnz XXOO ; it must be 0xe, or there will be duplication // 0x75, 0x0e // jnz XXOO ; it must be 0xe, or there will be duplication
// }; // };
// enum { addr_offset = 0 }; // enum { addr_offset = 0 };
// ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR); // ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
// ULONG reladdr = SearchPattern(processStartAddress, range, ins, sizeof(ins)); // ULONG reladdr = SearchPattern(processStartAddress, range, ins, sizeof(ins));
// reladdr = 0x104a48; // reladdr = 0x104a48;
// GROWL_DWORD(processStartAddress); // GROWL_DWORD(processStartAddress);
// //GROWL_DWORD3(reladdr, processStartAddress, range); // //GROWL_DWORD3(reladdr, processStartAddress, range);
// if (!reladdr) // if (!reladdr)
// return false; // return false;
// //
// HookParam hp; // HookParam hp;
// hp.address = processStartAddress + reladdr + addr_offset; // hp.address = processStartAddress + reladdr + addr_offset;
// hp.offset=get_reg(regs::eax); // hp.offset=get_reg(regs::eax);
// hp.type = USING_STRING|NO_CONTEXT; // hp.type = USING_STRING|NO_CONTEXT;
// NewHook(hp, "Candy"); // NewHook(hp, "Candy");
// return true; // return true;
//} // }
} // unnamed Candy } // unnamed Candy
namespace{ namespace
bool candy3(){ {
//お母さんは俺専用!~あなたの初めてを…母さんが貰ってア・ゲ・ル~ bool candy3()
//茉莉子さん家の性事情 ~伯母さんは僕のモノ~ {
// お母さんは俺専用!~あなたの初めてを…母さんが貰ってア・ゲ・ル~
// 茉莉子さん家の性事情 ~伯母さんは僕のモノ~
const BYTE bytes[] = { const BYTE bytes[] = {
0x24, //XX||XX2 0x24, // XX||XX2
0x75 0x75};
}; for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE))
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE)){ {
ConsoleOutput("%x",addr); ConsoleOutput("%x", addr);
if((*(BYTE*)(addr-1) ==0x3c)||((*(BYTE*)(addr-2) ==0x83)&&(*(BYTE*)(addr-1) ==0xf9))){ if ((*(BYTE *)(addr - 1) == 0x3c) || ((*(BYTE *)(addr - 2) == 0x83) && (*(BYTE *)(addr - 1) == 0xf9)))
addr=MemDbg::findEnclosingAlignedFunction(addr); {
if(addr==0)continue; addr = MemDbg::findEnclosingAlignedFunction(addr);
ConsoleOutput("!%x",addr); if (addr == 0)
continue;
ConsoleOutput("!%x", addr);
HookParam hp; HookParam hp;
hp.type = USING_STRING; hp.type = USING_STRING;
if(*(BYTE*)addr==0x55) if (*(BYTE *)addr == 0x55)
hp.offset=get_stack(1); hp.offset = get_stack(1);
else if(*(BYTE*)addr==0x56) else if (*(BYTE *)addr == 0x56)
hp.offset=get_reg(regs::eax); hp.offset = get_reg(regs::eax);
else else
continue; continue;
hp.address = addr; hp.address = addr;
@ -228,9 +244,9 @@ bool candy3(){
} }
} }
return false; return false;
} }
bool InsertCandyHook3() bool InsertCandyHook3()
{ {
/* /*
* Sample games: * Sample games:
@ -252,57 +268,98 @@ bool InsertCandyHook3()
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR); ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range); ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr) return false; if (!addr)
return false;
HookParam hp; HookParam hp;
hp.address = addr + 1; hp.address = addr + 1;
hp.offset=get_stack(4); hp.offset = get_stack(4);
hp.type = USING_STRING | CODEC_UTF16; hp.type = USING_STRING | CODEC_UTF16;
ConsoleOutput("INSERT SystemC#3"); ConsoleOutput("INSERT SystemC#3");
return NewHook(hp, "SystemC#3"); return NewHook(hp, "SystemC#3");
} }
} }
// jichi 10/2/2013: Add new candy hook // jichi 10/2/2013: Add new candy hook
bool InsertCandyHook() bool InsertCandyHook()
{ {
PcHooks::hookOtherPcFunctions();
//if (0 == _wcsicmp(processName, L"systemc.exe")) // if (0 == _wcsicmp(processName, L"systemc.exe"))
if (Util::CheckFile(L"SystemC.exe")) if (Util::CheckFile(L"SystemC.exe"))
return InsertCandyHook1()||candy3(); return InsertCandyHook1() || candy3();
else{ else
//return InsertCandyHook2(); {
// return InsertCandyHook2();
bool b2 = InsertCandyHook2(); bool b2 = InsertCandyHook2();
b2 |= InsertCandyHook3(); b2 |= InsertCandyHook3();
return b2; return b2;
} }
} }
namespace
{
bool willowsoft()
{
const BYTE bytes[] = {
// https://vndb.org/v5761
// まません
bool Candy::attach_function() { 0xA1, XX4,
0x89, 0x45, 0xF8,
0x83, 0x7D, 0xF8, 0x10,
0x74, XX,
0x83, 0x7D, 0xF8, 0x18,
0x74, XX,
0x83, 0x7D, 0xF8, 0x20,
0x74, XX};
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if (addr == 0)
return false;
addr = MemDbg::findEnclosingAlignedFunction(addr, 0x20);
if (addr == 0)
return false;
HookParam hp;
hp.type = USING_STRING;
hp.offset = get_stack(2);
hp.type = USING_STRING;
hp.address = addr;
return NewHook(hp, "WillowSoft");
}
}
bool Candy::attach_function()
{
return InsertCandyHook(); auto b1 = InsertCandyHook();
if (b1)
PcHooks::hookOtherPcFunctions();
else
{
b1 = b1 || willowsoft();
if (!b1)
PcHooks::hookOtherPcFunctions();
}
return b1;
} }
bool WillowSoft::attach_function()
bool WillowSoft::attach_function(){ {
//お母さんがいっぱい!!限定ママBOX // お母さんがいっぱい!!限定ママBOX
const BYTE bytes[] = { const BYTE bytes[] = {
0xF7 ,0xC2 ,0x00 ,0x00 ,0xFF ,0x00, 0xF7, 0xC2, 0x00, 0x00, 0xFF, 0x00,
XX2, XX2,
0xF7 ,0xC2 ,0x00 ,0x00 ,0x00 ,0xFF , 0xF7, 0xC2, 0x00, 0x00, 0x00, 0xFF,
XX2 XX2};
}; auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
auto addr=MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress); if (addr == 0)
if(addr==0)return false; return false;
addr=MemDbg::findEnclosingAlignedFunction(addr); addr = MemDbg::findEnclosingAlignedFunction(addr);
if(addr==0)return false; if (addr == 0)
return false;
HookParam hp; HookParam hp;
hp.type = USING_STRING; hp.type = USING_STRING;
hp.offset=get_stack(2); hp.offset = get_stack(2);
hp.type |= DATA_INDIRECT; hp.type |= DATA_INDIRECT;
hp.index = 0; hp.index = 0;
hp.address = addr; hp.address = addr;
return NewHook(hp, "WillowSoft"); return NewHook(hp, "WillowSoft");
} }

View File

@ -1,24 +1,27 @@
class Candy:public ENGINE{ class Candy : public ENGINE
public: {
Candy(){ public:
Candy()
{
check_by=CHECK_BY::FILE_ANY; check_by = CHECK_BY::FILE_ANY;
check_by_target=check_by_list{L"*.fpk",L"data\\*.fpk"}; check_by_target = check_by_list{L"*.fpk", L"data\\*.fpk"};
is_engine_certain=false; is_engine_certain = false;
}; };
bool attach_function(); bool attach_function();
}; };
class WillowSoft : public ENGINE
{
public:
WillowSoft()
{
class WillowSoft:public ENGINE{ check_by = CHECK_BY::FILE;
public: check_by_target = L"Selene.dll";
WillowSoft(){ is_engine_certain = false;
check_by=CHECK_BY::FILE;
check_by_target=L"Selene.dll";
is_engine_certain=false;
}; };
bool attach_function(); bool attach_function();
}; };