This commit is contained in:
恍兮惚兮 2024-08-15 04:50:33 +08:00
parent 3cc416c29f
commit 05c65a095e
2 changed files with 813 additions and 747 deletions

View File

@ -39,7 +39,8 @@
* *
* Again, drop the N to split dialogue and menu text into separate threads. * Again, drop the N to split dialogue and menu text into separate threads.
*/ */
namespace { // WolfRPG namespace
{ // WolfRPG
// jichi 10/13/2013: restored // jichi 10/13/2013: restored
bool InsertOldWolfHook() bool InsertOldWolfHook()
{ {
@ -47,16 +48,22 @@ bool InsertOldWolfHook()
// Step 1: find the address of GetTextMetricsA // Step 1: find the address of GetTextMetricsA
// Step 2: find where this function is called // Step 2: find where this function is called
// Step 3: search "sub esp, XX" after where it is called // Step 3: search "sub esp, XX" after where it is called
enum { sub_esp = 0xec81 }; // jichi: caller pattern: sub esp = 0x81,0xec enum
{
sub_esp = 0xec81
}; // jichi: caller pattern: sub esp = 0x81,0xec
if (DWORD c1 = Util::FindCallAndEntryAbs((DWORD)GetTextMetricsA, processStopAddress - processStartAddress, processStartAddress, sub_esp)) if (DWORD c1 = Util::FindCallAndEntryAbs((DWORD)GetTextMetricsA, processStopAddress - processStartAddress, processStartAddress, sub_esp))
if (DWORD c2 = Util::FindCallOrJmpRel(c1, processStopAddress - processStartAddress, processStartAddress, 0)) { if (DWORD c2 = Util::FindCallOrJmpRel(c1, processStopAddress - processStartAddress, processStartAddress, 0))
union { {
union
{
DWORD i; DWORD i;
WORD *k; WORD *k;
}; };
DWORD j; DWORD j;
for (i = c2 - 0x100, j = c2 - 0x400; i > j; i--) for (i = c2 - 0x100, j = c2 - 0x400; i > j; i--)
if (*k == 0xec83) { // jichi 10/12/2013: 83 EC XX sub esp, XX See: http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20120312.txt if (*k == 0xec83)
{ // jichi 10/12/2013: 83 EC XX sub esp, XX See: http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20120312.txt
HookParam hp; HookParam hp;
hp.address = i; hp.address = i;
hp.offset = get_reg(regs::ecx); hp.offset = get_reg(regs::ecx);
@ -79,7 +86,8 @@ bool InsertWolf3Hook()
const BYTE bytes[] = {0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x45, 0x94, 0x83, 0xE0, 0x01}; const BYTE bytes[] = {0xC7, 0x45, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x45, 0x94, 0x83, 0xE0, 0x01};
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) { if (!addr)
{
ConsoleOutput("WolfRPG: pattern3 not found"); ConsoleOutput("WolfRPG: pattern3 not found");
return false; return false;
} }
@ -99,11 +107,13 @@ bool InsertWolf3Hook()
return NewHook(myhp, nameForUser); return NewHook(myhp, nameForUser);
} }
bool InsertWolf4Hook() { bool InsertWolf4Hook()
{
const BYTE bytes[] = {0xC6, 0x45, 0xFC, 0x29, 0x8B, 0x8D, 0xE0, 0xEF, 0xFF, 0xFF, 0xE8, XX4, 0x50, 0x8B, 0x4D, 0xE8, 0x2B, 0x4D, 0xEC}; const BYTE bytes[] = {0xC6, 0x45, 0xFC, 0x29, 0x8B, 0x8D, 0xE0, 0xEF, 0xFF, 0xFF, 0xE8, XX4, 0x50, 0x8B, 0x4D, 0xE8, 0x2B, 0x4D, 0xEC};
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) { if (!addr)
{
ConsoleOutput("WolfRPG: pattern4 not found"); ConsoleOutput("WolfRPG: pattern4 not found");
return false; return false;
} }
@ -123,8 +133,6 @@ bool InsertWolf4Hook() {
return NewHook(myhp, nameForUser); return NewHook(myhp, nameForUser);
} }
} // WolfRPG namespace } // WolfRPG namespace
bool InsertWolfHook() bool InsertWolfHook()
@ -132,21 +140,23 @@ bool InsertWolfHook()
// return InsertOldWolfHook(), InsertWolf2Hook(), InsertWolf3Hook(), InsertWolf4Hook(); // return InsertOldWolfHook(), InsertWolf2Hook(), InsertWolf3Hook(), InsertWolf4Hook();
return InsertOldWolfHook(), InsertWolf3Hook(), InsertWolf4Hook(); return InsertOldWolfHook(), InsertWolf3Hook(), InsertWolf4Hook();
} }
namespace{ namespace
{
bool commonfilter(void* data, size_t* len, HookParam* hp){ bool commonfilter(void *data, size_t *len, HookParam *hp)
{
auto str = std::string(reinterpret_cast<LPSTR>(data), *len); auto str = std::string(reinterpret_cast<LPSTR>(data), *len);
bool checkchaos = WideStringToString(StringToWideString(str)) != str; bool checkchaos = WideStringToString(StringToWideString(str)) != str;
if(checkchaos)return false; if (checkchaos)
return false;
bool check1 = str.find("/") != str.npos || str.find("\\") != str.npos; bool check1 = str.find("/") != str.npos || str.find("\\") != str.npos;
auto hashsuffix=[str](){ auto hashsuffix = [str]()
{
auto filterpath = { auto filterpath = {
".png", ".jpg", ".bmp", ".png", ".jpg", ".bmp",
".mp3", ".ogg", ".mp3", ".ogg",
".webm", ".mp4", ".webm", ".mp4",
".otf",".mps" ".otf", ".mps"};
};
for (auto _ : filterpath) for (auto _ : filterpath)
if (str.find(_) != str.npos) if (str.find(_) != str.npos)
return true; return true;
@ -154,10 +164,12 @@ namespace{
}; };
bool check2 = hashsuffix(); bool check2 = hashsuffix();
bool check3 = all_ascii((const char *)data, *len); bool check3 = all_ascii((const char *)data, *len);
if(check1&&(check2||check3))return false; if (check1 && (check2 || check3))
return false;
return true; return true;
} }
bool hook5_1(DWORD addr_1){ bool hook5_1(DWORD addr_1)
{
// RJ338582 // RJ338582
// 妹せいかつ ファンタジー1.4.5 // 妹せいかつ ファンタジー1.4.5
const BYTE bytes[] = { const BYTE bytes[] = {
@ -168,13 +180,14 @@ namespace{
0x6a, 0x00, 0x6a, 0x00,
0xFF, 0x77, 0x10, 0xFF, 0x77, 0x10,
0xFF, 0x77, 0x18, 0xFF, 0x77, 0x18,
0xE8 0xE8};
};
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress); auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if(addr==0)return false; if (addr == 0)
return false;
auto off = (*((DWORD *)(sizeof(bytes) + addr))); auto off = (*((DWORD *)(sizeof(bytes) + addr)));
auto _calladdr = addr + sizeof(bytes) + 4 + off; auto _calladdr = addr + sizeof(bytes) + 4 + off;
if(addr_1!=_calladdr)return false; if (addr_1 != _calladdr)
return false;
HookParam hp; HookParam hp;
hp.address = addr + sizeof(bytes) - 1; hp.address = addr + sizeof(bytes) - 1;
@ -183,7 +196,8 @@ namespace{
hp.filter_fun = commonfilter; hp.filter_fun = commonfilter;
return NewHook(hp, "Wolf5_1"); return NewHook(hp, "Wolf5_1");
} }
bool hook5(){ bool hook5()
{
//[220901][あせろら] 寝取られ新妻モニカツンデレな奥さんのHなお仕事 //[220901][あせろら] 寝取られ新妻モニカツンデレな奥さんのHなお仕事
const BYTE bytes[] = { const BYTE bytes[] = {
0x80, 0x38, 0x40, 0x80, 0x38, 0x40,
@ -191,14 +205,16 @@ namespace{
0x57, 0x57,
0x68, XX4, 0x68, XX4,
0x8d, XX2, 0x8d, XX2,
0xe8 0xe8};
};
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress); auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
if(addr==0)return false; if (addr == 0)
return false;
addr = MemDbg::findEnclosingAlignedFunction(addr); addr = MemDbg::findEnclosingAlignedFunction(addr);
if(addr==0)return false; if (addr == 0)
if(hook5_1(addr))return true; return false;
if (hook5_1(addr))
return true;
HookParam hp; HookParam hp;
hp.address = addr; hp.address = addr;
hp.offset = get_stack(8); hp.offset = get_stack(8);
@ -206,18 +222,20 @@ namespace{
hp.filter_fun = commonfilter; hp.filter_fun = commonfilter;
return NewHook(hp, "Wolf5"); return NewHook(hp, "Wolf5");
} }
bool hook6(){ bool hook6()
{
//[220901][あせろら] 寝取られ新妻モニカツンデレな奥さんのHなお仕事 //[220901][あせろら] 寝取られ新妻モニカツンデレな奥さんのHなお仕事
const BYTE bytes[] = { const BYTE bytes[] = {
0xB8, 0x00, 0x00, 0x00, 0x80, 0xB8, 0x00, 0x00, 0x00, 0x80,
0x83,0xC0,0x23 0x83, 0xC0, 0x23};
};
bool ok = false; bool ok = false;
auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStopAddress); auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStopAddress);
for (auto addr : addrs) { for (auto addr : addrs)
{
addr = MemDbg::findEnclosingAlignedFunction(addr); addr = MemDbg::findEnclosingAlignedFunction(addr);
if(addr==0)continue; if (addr == 0)
continue;
HookParam hp; HookParam hp;
hp.address = (DWORD)addr; hp.address = (DWORD)addr;
hp.offset = get_stack(3); hp.offset = get_stack(3);
@ -228,19 +246,22 @@ namespace{
return ok; return ok;
} }
bool hook56(){ bool hook56()
{
bool _1 = hook5(); bool _1 = hook5();
bool _2 = hook6(); bool _2 = hook6();
return _1 || _2; return _1 || _2;
} }
} }
namespace
{ // unnamed
namespace { // unnamed namespace ScenarioHook
{
namespace ScenarioHook { namespace Private
{
namespace Private {
struct TextListElement // ecx, this structure saved a list of element struct TextListElement // ecx, this structure saved a list of element
{ {
@ -253,12 +274,13 @@ namespace Private {
capacity; // 0xe8, capacity of the data including \0 capacity; // 0xe8, capacity of the data including \0
bool isScenarioText() const bool isScenarioText() const
{ return flag1 == 0 && flag2 == 0 && flag3 == 0 && flag4 == 0; } {
return flag1 == 0 && flag2 == 0 && flag3 == 0 && flag4 == 0;
}
bool isValid() const bool isValid() const
{ {
return size > 0 && size <= capacity return size > 0 && size <= capacity && Engine::isAddressReadable(text, capacity) && size == ::strlen(text);
&& Engine::isAddressReadable(text, capacity) && size == ::strlen(text);
} }
}; };
@ -274,18 +296,23 @@ namespace Private {
{ {
// enum { DataQueueCapacity = 30 }; // enum { DataQueueCapacity = 30 };
auto self = (TextListElement *)s->ecx; // ecx is actually a list of element auto self = (TextListElement *)s->ecx; // ecx is actually a list of element
if (self->isValid()) { if (self->isValid())
{
char *text = ltrim(self->text); char *text = ltrim(self->text);
if (*text) { if (*text)
{
std::string data = text; std::string data = text;
if (dataSet_.find(data)==dataSet_.end()) { if (dataSet_.find(data) == dataSet_.end())
{
auto role = text == self->text && self->isScenarioText() ? Engine::ScenarioRole : Engine::OtherRole; auto role = text == self->text && self->isScenarioText() ? Engine::ScenarioRole : Engine::OtherRole;
auto split = s->stack[0]; // retaddr auto split = s->stack[0]; // retaddr
// auto sig = Engine::hashThreadSignature(role, split); // auto sig = Engine::hashThreadSignature(role, split);
enum { SendAllowed = true }; enum
{
SendAllowed = true
};
bool timeout; bool timeout;
int prefixSize = text - self->text, int prefixSize = text - self->text,
capacity = self->capacity - prefixSize; capacity = self->capacity - prefixSize;
@ -304,21 +331,28 @@ namespace Private {
} }
return 0; return 0;
} }
void hookafter2(hook_stack*s,void* data1, size_t len){ void hookafter2(hook_stack *s, void *data1, size_t len)
{
auto newData = std::string((char *)data1, len); auto newData = std::string((char *)data1, len);
auto self = (TextListElement *)s->ecx; // ecx is actually a list of element auto self = (TextListElement *)s->ecx; // ecx is actually a list of element
if (self->isValid()) { if (self->isValid())
{
char *text = ltrim(self->text); char *text = ltrim(self->text);
if (*text) { if (*text)
{
std::string data = text; std::string data = text;
if (dataSet_.find(data)==dataSet_.end()) { if (dataSet_.find(data) == dataSet_.end())
{
auto role = text == self->text && self->isScenarioText() ? Engine::ScenarioRole : Engine::OtherRole; auto role = text == self->text && self->isScenarioText() ? Engine::ScenarioRole : Engine::OtherRole;
auto split = s->stack[0]; // retaddr auto split = s->stack[0]; // retaddr
// auto sig = Engine::hashThreadSignature(role, split); // auto sig = Engine::hashThreadSignature(role, split);
enum { SendAllowed = true }; enum
{
SendAllowed = true
};
bool timeout; bool timeout;
int prefixSize = text - self->text, int prefixSize = text - self->text,
capacity = self->capacity - prefixSize; capacity = self->capacity - prefixSize;
@ -831,7 +865,8 @@ bool attach(ULONG startAddress, ULONG stopAddress) // attach other text
// addr = MemDbg::findNearCallAddress(addr, startAddress, stopAddress); // addr = MemDbg::findNearCallAddress(addr, startAddress, stopAddress);
// if (!addr) // if (!addr)
// return false; // return false;
if(addr==0)return 0; if (addr == 0)
return 0;
HookParam hp; HookParam hp;
hp.address = addr; hp.address = addr;
hp.offset = get_reg(regs::ecx); hp.offset = get_reg(regs::ecx);
@ -843,12 +878,41 @@ bool attach(ULONG startAddress, ULONG stopAddress) // attach other text
return NewHook(hp, "EmbedWolf"); return NewHook(hp, "EmbedWolf");
} }
} // namespace ScenarioHook } // namespace ScenarioHook
} // unnamed namespace } // unnamed namespace
namespace
bool Wolf::attach_function() { {
auto _=ScenarioHook::attach(processStartAddress,processStopAddress); bool wolf7()
return InsertWolfHook()||hook56()||_; {
BYTE sig[] = {
0x52,
0x8b, 0x4d, 0xf4,
0xe8, XX4,
0x03, 0x45, 0x08,
0x03, 0x45, 0x0c,
0x50,
0x8b, 0x4d, 0xf4,
0xe8, XX4,
0x03, 0x45, 0x08,
0x03, 0x45, 0x14,
0x50,
0xe8, XX4,
0x83, 0xc4, 0x0c,
0x8b, 0x45, 0x14};
auto addr = MemDbg::findBytes(sig, sizeof(sig), processStartAddress, processStopAddress);
if (!addr)
return false;
addr += 31;
HookParam hp;
hp.address = addr;
hp.offset = get_stack(1);
hp.type = USING_STRING | NO_CONTEXT;
return NewHook(hp, "Wolf7");
}
}
bool Wolf::attach_function()
{
auto _ = ScenarioHook::attach(processStartAddress, processStopAddress);
return InsertWolfHook() || hook56() || _ || wolf7();
} }

View File

@ -1,9 +1,11 @@
class Wolf:public ENGINE{ class Wolf : public ENGINE
{
public: public:
Wolf(){ Wolf()
{
is_engine_certain = false;
check_by = CHECK_BY::FILE_ANY; check_by = CHECK_BY::FILE_ANY;
check_by_target = check_by_list{L"data.wolf", L"data\\*.wolf", L"data\\basicdata\\cdatabase.dat"}; check_by_target = check_by_list{L"data.wolf", L"data\\*.wolf", L"data\\basicdata\\cdatabase.dat"};
}; };