mirror of
https://github.com/HIllya51/LunaHook.git
synced 2025-01-12 21:04:00 +08:00
wolf
This commit is contained in:
parent
3cc416c29f
commit
05c65a095e
@ -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();
|
||||||
}
|
}
|
@ -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"};
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user