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
@ -1,4 +1,4 @@
|
|||||||
#include"Wolf.h"
|
#include "Wolf.h"
|
||||||
/**
|
/**
|
||||||
* jichi 10/12/2014
|
* jichi 10/12/2014
|
||||||
* P.S.: Another approach
|
* P.S.: Another approach
|
||||||
@ -39,56 +39,64 @@
|
|||||||
*
|
*
|
||||||
* 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
|
||||||
// jichi 10/13/2013: restored
|
{ // WolfRPG
|
||||||
bool InsertOldWolfHook()
|
// jichi 10/13/2013: restored
|
||||||
{
|
bool InsertOldWolfHook()
|
||||||
|
{
|
||||||
// jichi 10/12/2013:
|
// jichi 10/12/2013:
|
||||||
// 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);
|
||||||
hp.split = get_reg(regs::esp);
|
hp.split = get_reg(regs::esp);
|
||||||
hp.type = DATA_INDIRECT|USING_SPLIT;
|
hp.type = DATA_INDIRECT | USING_SPLIT;
|
||||||
//GROWL_DWORD(hp.address); // jichi 6/5/2014: 淫乱勀<E4B9B1><E58B80>フィのRPG = 0x50a400
|
// GROWL_DWORD(hp.address); // jichi 6/5/2014: 淫乱勀<E4B9B1><E58B80>フィのRPG = 0x50a400
|
||||||
ConsoleOutput("INSERT WolfRPG");
|
ConsoleOutput("INSERT WolfRPG");
|
||||||
return NewHook(hp, "WolfRPG");
|
return NewHook(hp, "WolfRPG");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//ConsoleOutput("Unknown WolfRPG engine.");
|
// ConsoleOutput("Unknown WolfRPG engine.");
|
||||||
ConsoleOutput("WolfRPG: failed");
|
ConsoleOutput("WolfRPG: failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//example-game:妹!せいかつ~ファンタジー~ by:iov
|
// example-game:妹!せいかつ~ファンタジー~ by:iov
|
||||||
bool InsertWolf3Hook()
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
HookParam myhp;
|
HookParam myhp;
|
||||||
myhp.address = addr+41;
|
myhp.address = addr + 41;
|
||||||
|
|
||||||
myhp.type = USING_STRING | NO_CONTEXT;
|
myhp.type = USING_STRING | NO_CONTEXT;
|
||||||
myhp.offset=get_reg(regs::eax);
|
myhp.offset = get_reg(regs::eax);
|
||||||
myhp.type |= DATA_INDIRECT;
|
myhp.type |= DATA_INDIRECT;
|
||||||
|
|
||||||
myhp.index = 4;
|
myhp.index = 4;
|
||||||
@ -97,13 +105,15 @@ bool InsertWolf3Hook()
|
|||||||
|
|
||||||
ConsoleOutput("Insert: WolfRPG_String_Copy Hook");
|
ConsoleOutput("Insert: WolfRPG_String_Copy Hook");
|
||||||
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;
|
||||||
}
|
}
|
||||||
@ -112,7 +122,7 @@ bool InsertWolf4Hook() {
|
|||||||
myhp.address = addr + 16;
|
myhp.address = addr + 16;
|
||||||
|
|
||||||
myhp.type = USING_STRING | NO_CONTEXT;
|
myhp.type = USING_STRING | NO_CONTEXT;
|
||||||
myhp.offset=get_reg(regs::eax);
|
myhp.offset = get_reg(regs::eax);
|
||||||
// myhp.type |= DATA_INDIRECT;
|
// myhp.type |= DATA_INDIRECT;
|
||||||
|
|
||||||
// myhp.index = 4;
|
// myhp.index = 4;
|
||||||
@ -121,9 +131,7 @@ bool InsertWolf4Hook() {
|
|||||||
|
|
||||||
ConsoleOutput("Insert: WolfRPG4 Hook");
|
ConsoleOutput("Insert: WolfRPG4 Hook");
|
||||||
return NewHook(myhp, nameForUser);
|
return NewHook(myhp, nameForUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // WolfRPG namespace
|
} // WolfRPG namespace
|
||||||
|
|
||||||
@ -132,115 +140,128 @@ 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);
|
{
|
||||||
bool checkchaos=WideStringToString(StringToWideString(str))!=str;
|
auto str = std::string(reinterpret_cast<LPSTR>(data), *len);
|
||||||
if(checkchaos)return false;
|
bool checkchaos = WideStringToString(StringToWideString(str)) != str;
|
||||||
bool check1= str.find("/")!=str.npos||str.find("\\")!=str.npos;
|
if (checkchaos)
|
||||||
auto hashsuffix=[str](){
|
return false;
|
||||||
|
bool check1 = str.find("/") != str.npos || str.find("\\") != str.npos;
|
||||||
auto filterpath={
|
auto hashsuffix = [str]()
|
||||||
".png",".jpg",".bmp",
|
{
|
||||||
".mp3",".ogg",
|
auto filterpath = {
|
||||||
".webm",".mp4",
|
".png", ".jpg", ".bmp",
|
||||||
".otf",".mps"
|
".mp3", ".ogg",
|
||||||
};
|
".webm", ".mp4",
|
||||||
for(auto _ :filterpath)
|
".otf", ".mps"};
|
||||||
if(str.find(_)!=str.npos)
|
for (auto _ : filterpath)
|
||||||
|
if (str.find(_) != str.npos)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
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
|
{
|
||||||
//妹!せいかつ ~ファンタジー~1.4.5
|
// RJ338582
|
||||||
|
// 妹!せいかつ ~ファンタジー~1.4.5
|
||||||
const BYTE bytes[] = {
|
const BYTE bytes[] = {
|
||||||
0x6a,0x01,
|
0x6a, 0x01,
|
||||||
0x68,XX4,
|
0x68, XX4,
|
||||||
0x68,XX4,
|
0x68, XX4,
|
||||||
0x6a,0x01,
|
0x6a, 0x01,
|
||||||
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)
|
||||||
auto off=(*((DWORD*)(sizeof(bytes)+addr)));
|
return false;
|
||||||
auto _calladdr=addr+sizeof(bytes)+4+off;
|
auto off = (*((DWORD *)(sizeof(bytes) + addr)));
|
||||||
if(addr_1!=_calladdr)return false;
|
auto _calladdr = addr + sizeof(bytes) + 4 + off;
|
||||||
|
if (addr_1 != _calladdr)
|
||||||
|
return false;
|
||||||
|
|
||||||
HookParam hp;
|
HookParam hp;
|
||||||
hp.address = addr+sizeof(bytes)-1;
|
hp.address = addr + sizeof(bytes) - 1;
|
||||||
hp.offset =get_stack(7);
|
hp.offset = get_stack(7);
|
||||||
hp.type =USING_STRING|CODEC_UTF8|EMBED_ABLE|EMBED_AFTER_OVERWRITE|EMBED_BEFORE_SIMPLE;
|
hp.type = USING_STRING | CODEC_UTF8 | EMBED_ABLE | EMBED_AFTER_OVERWRITE | EMBED_BEFORE_SIMPLE;
|
||||||
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,
|
||||||
0x0f,0x85,XX4,
|
0x0f, 0x85, XX4,
|
||||||
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)
|
||||||
addr=MemDbg::findEnclosingAlignedFunction(addr);
|
return false;
|
||||||
|
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);
|
||||||
hp.type =USING_STRING|CODEC_UTF8|EMBED_ABLE|EMBED_AFTER_OVERWRITE|EMBED_BEFORE_SIMPLE;
|
hp.type = USING_STRING | CODEC_UTF8 | EMBED_ABLE | EMBED_AFTER_OVERWRITE | EMBED_BEFORE_SIMPLE;
|
||||||
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);
|
||||||
hp.type =USING_STRING|CODEC_UTF8;
|
hp.type = USING_STRING | CODEC_UTF8;
|
||||||
hp.filter_fun=commonfilter;
|
hp.filter_fun = commonfilter;
|
||||||
ok|=NewHook(hp, "Wolf6");
|
ok |= NewHook(hp, "Wolf6");
|
||||||
}
|
}
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
bool hook56(){
|
bool hook56()
|
||||||
bool _1=hook5();
|
{
|
||||||
bool _2=hook6();
|
bool _1 = hook5();
|
||||||
return _1||_2;
|
bool _2 = hook6();
|
||||||
|
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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -270,26 +292,31 @@ namespace Private {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
std::unordered_set<std::string> dataSet_;
|
std::unordered_set<std::string> dataSet_;
|
||||||
bool hookBefore(hook_stack*s,void* data1, size_t* len1,uintptr_t*role)
|
bool hookBefore(hook_stack *s, void *data1, size_t *len1, uintptr_t *role)
|
||||||
{
|
{
|
||||||
//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;
|
||||||
return write_string_overwrite(data1,len1,data);
|
return write_string_overwrite(data1, len1, data);
|
||||||
|
|
||||||
// data = EngineController::instance()->dispatchTextASTD(data, role, sig, capacity, SendAllowed, &timeout);
|
// data = EngineController::instance()->dispatchTextASTD(data, role, sig, capacity, SendAllowed, &timeout);
|
||||||
// if (timeout)
|
// if (timeout)
|
||||||
@ -304,26 +331,33 @@ 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;
|
||||||
|
|
||||||
data=newData;
|
data = newData;
|
||||||
dataSet_.insert(data);
|
dataSet_.insert(data);
|
||||||
|
|
||||||
::memcpy(text, data.c_str(), min(data.size() + 1, capacity));
|
::memcpy(text, data.c_str(), min(data.size() + 1, capacity));
|
||||||
@ -332,9 +366,9 @@ namespace Private {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace Private
|
} // namespace Private
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sample game: DRAGON SLAVE
|
* Sample game: DRAGON SLAVE
|
||||||
*
|
*
|
||||||
* This function is very long and contains many CharNextA.
|
* This function is very long and contains many CharNextA.
|
||||||
@ -825,30 +859,60 @@ namespace Private {
|
|||||||
* 00471898 CC INT3
|
* 00471898 CC INT3
|
||||||
* 00471899 CC INT3
|
* 00471899 CC INT3
|
||||||
*/
|
*/
|
||||||
bool attach(ULONG startAddress, ULONG stopAddress) // attach other text
|
bool attach(ULONG startAddress, ULONG stopAddress) // attach other text
|
||||||
{
|
{
|
||||||
ULONG addr = MemDbg::findCallerAddressAfterInt3((ULONG)::CharNextA, startAddress, stopAddress);
|
ULONG addr = MemDbg::findCallerAddressAfterInt3((ULONG)::CharNextA, startAddress, stopAddress);
|
||||||
//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);
|
||||||
hp.index = 4;
|
hp.index = 4;
|
||||||
hp.hook_before=Private::hookBefore;
|
hp.hook_before = Private::hookBefore;
|
||||||
hp.hook_after=Private::hookafter2;
|
hp.hook_after = Private::hookafter2;
|
||||||
hp.type=USING_STRING|DATA_INDIRECT|EMBED_ABLE|EMBED_DYNA_SJIS;
|
hp.type = USING_STRING | DATA_INDIRECT | EMBED_ABLE | EMBED_DYNA_SJIS;
|
||||||
hp.hook_font=F_GetGlyphOutlineA;
|
hp.hook_font = F_GetGlyphOutlineA;
|
||||||
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,11 +1,13 @@
|
|||||||
|
|
||||||
|
|
||||||
class Wolf:public ENGINE{
|
class Wolf : public ENGINE
|
||||||
public:
|
{
|
||||||
Wolf(){
|
public:
|
||||||
|
Wolf()
|
||||||
check_by=CHECK_BY::FILE_ANY;
|
{
|
||||||
check_by_target=check_by_list{L"data.wolf",L"data\\*.wolf",L"data\\basicdata\\cdatabase.dat"};
|
is_engine_certain = false;
|
||||||
|
check_by = CHECK_BY::FILE_ANY;
|
||||||
|
check_by_target = check_by_list{L"data.wolf", L"data\\*.wolf", L"data\\basicdata\\cdatabase.dat"};
|
||||||
};
|
};
|
||||||
bool attach_function();
|
bool attach_function();
|
||||||
};
|
};
|
Loading…
x
Reference in New Issue
Block a user