This commit is contained in:
恍兮惚兮 2024-08-12 00:52:28 +08:00
parent 621fd866e6
commit 406438bb42
3 changed files with 1418 additions and 1337 deletions

View File

@ -1,16 +1,20 @@
#include"RPGMakerRGSS3.h"
namespace { // unnamed
#include "RPGMakerRGSS3.h"
namespace
{ // unnamed
namespace RGSS3 {
namespace RGSS3
{
namespace Private {
std::vector<std::wstring> glob(const std::wstring& relpath)
namespace Private
{
std::vector<std::wstring> glob(const std::wstring &relpath)
{
std::wstring path = std::wstring(MAX_PATH, 0);
GetModuleFileNameW(nullptr, &path[0], MAX_PATH);
size_t i = relpath.rfind(L'/');
if (i != std::wstring::npos) {
if (i != std::wstring::npos)
{
std::wstring dir_path = path + L"/" + relpath.substr(0, i);
WIN32_FIND_DATAW find_data;
HANDLE hFind = FindFirstFileW((dir_path + L"/*").c_str(), &find_data);
@ -18,9 +22,11 @@ namespace Private {
return {};
std::vector<std::wstring> results;
do {
do
{
if ((find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
PathMatchSpecW(find_data.cFileName, relpath.substr(i + 1).c_str())) {
PathMatchSpecW(find_data.cFileName, relpath.substr(i + 1).c_str()))
{
results.push_back(dir_path + L"/" + find_data.cFileName);
}
} while (FindNextFileW(hFind, &find_data));
@ -28,14 +34,16 @@ namespace Private {
return results;
}
else {
else
{
WIN32_FIND_DATAW find_data;
HANDLE hFind = FindFirstFileW(relpath.c_str(), &find_data);
if (hFind == INVALID_HANDLE_VALUE)
return {};
std::vector<std::wstring> results;
do {
do
{
if (!(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
results.push_back(find_data.cFileName);
} while (FindNextFileW(hFind, &find_data));
@ -46,27 +54,29 @@ namespace Private {
}
std::wstring getDllModuleName()
{
for (const auto &dll: glob(L"System/RGSS3*.dll"))
for (const auto &dll : glob(L"System/RGSS3*.dll"))
if (::GetModuleHandleW((LPCWSTR)dll.c_str()))
return dll;
return {};
}
} // namespace Private
} // namespace Private
bool getMemoryRange(ULONG *startAddress, ULONG *stopAddress)
{
bool getMemoryRange(ULONG *startAddress, ULONG *stopAddress)
{
std::wstring module = Private::getDllModuleName();
if (module.empty())
return false;
auto [_1,_2]=Util::QueryModuleLimits(GetModuleHandle(module.c_str()));
*startAddress=_1;*stopAddress=_2;
auto [_1, _2] = Util::QueryModuleLimits(GetModuleHandle(module.c_str()));
*startAddress = _1;
*stopAddress = _2;
return 1;
}
}
namespace ScenarioHook {
namespace ScenarioHook
{
/**
/**
* Sample game:
* - Mogeko Castle with RGSS 3.01
* - with RGSS 3.02
@ -504,11 +514,12 @@ namespace ScenarioHook {
* 10180BAA CC INT3
* 10180BAB CC INT3
*/
namespace Private {
namespace Private
{
//enum { MaxTextSize = 0x1000 };
//char oldText_[MaxTextSize + 1]; // 1 extra 0 that is always 0
//size_t oldSize_;
// enum { MaxTextSize = 0x1000 };
// char oldText_[MaxTextSize + 1]; // 1 extra 0 that is always 0
// size_t oldSize_;
struct HookArgument
{
@ -519,44 +530,47 @@ namespace Private {
bool isValid() const
{
return Engine::isAddressReadable(type) && *type
&& size && size < 1500
&& Engine::isAddressWritable(text, size + 1) && *text
&& text[size] == 0 && ::strlen(text) == size // validate size
return Engine::isAddressReadable(type) && *type && size && size < 1500 && Engine::isAddressWritable(text, size + 1) && *text && text[size] == 0 && ::strlen(text) == size // validate size
//&& !::strchr(text, '/')
&& !all_ascii(text);
}
//int size() const { return (*type >> 0xe) & 0x1f; }
// int size() const { return (*type >> 0xe) & 0x1f; }
};
inline bool _trims(const wchar_t &ch)
{ return ch <= 127 ||std::isspace(ch,std::locale("ja_JP.SJIS")); }
{
return ch <= 127 || std::isspace(ch, std::locale("ja_JP.SJIS"));
}
std::wstring trim(const std::wstring& text, std::wstring* prefix = nullptr, std::wstring* suffix = nullptr)
std::wstring trim(const std::wstring &text, std::wstring *prefix = nullptr, std::wstring *suffix = nullptr)
{
if (text.empty() ||
!_trims(text[0]) && !_trims(text[text.size() - 1]))
return text;
std::wstring ret = text;
if (_trims(ret[0])) {
if (_trims(ret[0]))
{
int pos = 1;
for (; pos < ret.size() && _trims(ret[pos]); pos++);
for (; pos < ret.size() && _trims(ret[pos]); pos++)
;
if (prefix)
*prefix = ret.substr(0,pos);
*prefix = ret.substr(0, pos);
ret = ret.substr(pos);
}
if (!ret.empty() && _trims(ret[ret.size() - 1])) {
if (!ret.empty() && _trims(ret[ret.size() - 1]))
{
int pos = ret.size() - 2;
for (; pos >= 0 && _trims(ret[pos]); pos--);
for (; pos >= 0 && _trims(ret[pos]); pos--)
;
if (suffix)
*suffix = ret.substr(pos + 1);
ret = ret.substr(0,pos + 1);
ret = ret.substr(0, pos + 1);
}
return ret;
}
//bool textsContains(const QSet<QString> &texts, const QString &text)
// bool textsContains(const QSet<QString> &texts, const QString &text)
//{
// if (texts.contains(text))
// return true;
@ -565,19 +579,21 @@ namespace Private {
// if (texts.contains(it))
// return true;
// return false;
//}
// }
int guessTextRole(const std::wstring &text)
{
enum { MaxNameSize = 100 };
enum : wchar_t {
w_square_open = 0x3010 /* 【 */
, w_square_close = 0x3011 /* 】 */
enum
{
MaxNameSize = 100
};
if (text.size() > 2
&& text.size() < MaxNameSize
&& text[0] == w_square_open
&& text[text.size() - 1] == w_square_close)
enum : wchar_t
{
w_square_open = 0x3010 /* 【 */
,
w_square_close = 0x3011 /* 】 */
};
if (text.size() > 2 && text.size() < MaxNameSize && text[0] == w_square_open && text[text.size() - 1] == w_square_close)
return Engine::NameRole;
return Engine::ScenarioRole;
}
@ -587,36 +603,43 @@ namespace Private {
LPCSTR oldText_;
size_t oldSize_;
std::unordered_set<std::wstring> texts_;
void hookafter2(hook_stack*s,void* data1, size_t len){
void hookafter2(hook_stack *s, void *data1, size_t len)
{
enum { RecentTextCapacity = 4 };
enum
{
RecentTextCapacity = 4
};
static std::vector<std::wstring> recentTexts_; // used to eliminate recent duplicates
auto arg = (HookArgument *)s->stack[0]; // arg1
if (arg && arg->isValid()) { // && (quint8)arg->text[0] > 127) { // skip translate text beginning with ascii character
std::wstring oldText =StringToWideString(std::string(arg->text, arg->size),CP_UTF8).value(),// QString::fromUtf8(arg->text, arg->size),
if (arg && arg->isValid())
{ // && (quint8)arg->text[0] > 127) { // skip translate text beginning with ascii character
std::wstring oldText = StringToWideString(std::string(arg->text, arg->size), CP_UTF8).value(), // QString::fromUtf8(arg->text, arg->size),
prefix,
suffix,
trimmedText = trim(oldText, &prefix, &suffix);
if (!trimmedText.empty() && (texts_.find(trimmedText)==texts_.end())) { // skip text beginning with ascii character
if (!trimmedText.empty() && (texts_.find(trimmedText) == texts_.end()))
{ // skip text beginning with ascii character
//ULONG split = arg->unknown2[0]; // always 2
//ULONG split = s->stack[0]; // return address
std::wstring newText =std::wstring((wchar_t*)data1,len/2);
// ULONG split = arg->unknown2[0]; // always 2
// ULONG split = s->stack[0]; // return address
std::wstring newText = std::wstring((wchar_t *)data1, len / 2);
if (newText != trimmedText) {
if (newText != trimmedText)
{
texts_.insert(newText);
texts_.insert(trim(newText)); // in case there are leading/trailing English letters in the translation
if (!prefix.empty())
newText.insert(0,prefix);
newText.insert(0, prefix);
if (!suffix.empty())
newText.append(suffix);
//texts_.insert(newText);
// texts_.insert(newText);
data_ = WideStringToString(newText, CP_UTF8);// newText.toUtf8();
data_ = WideStringToString(newText, CP_UTF8); // newText.toUtf8();
arg_ = arg;
oldSize_ = arg->size;
@ -629,46 +652,53 @@ namespace Private {
}
}
}
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 { RecentTextCapacity = 4 };
enum
{
RecentTextCapacity = 4
};
static std::vector<std::wstring> recentTexts_; // used to eliminate recent duplicates
auto arg = (HookArgument *)s->stack[0]; // arg1
if (arg && arg->isValid()) { // && (quint8)arg->text[0] > 127) { // skip translate text beginning with ascii character
std::wstring oldText =StringToWideString(std::string(arg->text, arg->size),CP_UTF8).value(),// QString::fromUtf8(arg->text, arg->size),
if (arg && arg->isValid())
{ // && (quint8)arg->text[0] > 127) { // skip translate text beginning with ascii character
std::wstring oldText = StringToWideString(std::string(arg->text, arg->size), CP_UTF8).value(), // QString::fromUtf8(arg->text, arg->size),
prefix,
suffix,
trimmedText = trim(oldText, &prefix, &suffix);
if (!trimmedText.empty() && (texts_.find(trimmedText)==texts_.end())) { // skip text beginning with ascii character
if (!trimmedText.empty() && (texts_.find(trimmedText) == texts_.end()))
{ // skip text beginning with ascii character
const bool sendAllowed = (std::find(recentTexts_.begin(),recentTexts_.end(),oldText)==recentTexts_.end());
if (sendAllowed) {
const bool sendAllowed = (std::find(recentTexts_.begin(), recentTexts_.end(), oldText) == recentTexts_.end());
if (sendAllowed)
{
recentTexts_.push_back(oldText);
if (recentTexts_.size() > RecentTextCapacity)
recentTexts_.erase(recentTexts_.begin());
}
//ULONG split = arg->unknown2[0]; // always 2
//ULONG split = s->stack[0]; // return address
// ULONG split = arg->unknown2[0]; // always 2
// ULONG split = s->stack[0]; // return address
std::wstring newText;
write_string_overwrite(data1,len1,trimmedText);
write_string_overwrite(data1, len1, trimmedText);
return 1;
if (newText != trimmedText) {
if (newText != trimmedText)
{
texts_.insert(newText);
texts_.insert(trim(newText)); // in case there are leading/trailing English letters in the translation
if (!prefix.empty())
newText.insert(0,prefix);
newText.insert(0, prefix);
if (!suffix.empty())
newText.append(suffix);
//texts_.insert(newText);
// texts_.insert(newText);
data_ = WideStringToString(newText, CP_UTF8);// newText.toUtf8();
data_ = WideStringToString(newText, CP_UTF8); // newText.toUtf8();
arg_ = arg;
oldSize_ = arg->size;
@ -683,9 +713,10 @@ namespace Private {
return 0;
}
bool hookAfter(hook_stack*s,void* data1, size_t* len1,uintptr_t*role)
bool hookAfter(hook_stack *s, void *data1, size_t *len1, uintptr_t *role)
{
if (arg_)
{
if (arg_) {
arg_->size = oldSize_;
arg_->text = oldText_;
//::strcpy(arg_->text, oldText_);
@ -693,16 +724,16 @@ namespace Private {
}
return 0;
}
} // namespace Private
} // namespace Private
bool attach(ULONG startAddress, ULONG stopAddress) // attach scenario
{
bool attach(ULONG startAddress, ULONG stopAddress) // attach scenario
{
const uint8_t bytes[] = {
0x8b,0x54,0x24, 0x24, // 1004155c 8b5424 24 mov edx,dword ptr ss:[esp+0x24]
0x8b,0x02, // 10041560 8b02 mov eax,dword ptr ds:[edx]
0x8b,0xc8, // 10041562 8bc8 mov ecx,eax
0x83,0xc4, 0x0c, // 10041564 83c4 0c add esp,0xc
0x81,0xe1, 0x00,0x20,0x00,0x00 // 10041567 81e1 00200000 and ecx,0x2000
0x8b, 0x54, 0x24, 0x24, // 1004155c 8b5424 24 mov edx,dword ptr ss:[esp+0x24]
0x8b, 0x02, // 10041560 8b02 mov eax,dword ptr ds:[edx]
0x8b, 0xc8, // 10041562 8bc8 mov ecx,eax
0x83, 0xc4, 0x0c, // 10041564 83c4 0c add esp,0xc
0x81, 0xe1, 0x00, 0x20, 0x00, 0x00 // 10041567 81e1 00200000 and ecx,0x2000
};
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress);
if (!addr)
@ -710,33 +741,35 @@ bool attach(ULONG startAddress, ULONG stopAddress) // attach scenario
addr = MemDbg::findEnclosingAlignedFunction(addr);
if (!addr)
return false;
//addr = MemDbg::findPushAddress(addr, startAddress, stopAddress);
//addr = 0x10041557;
//addr = 0x100414a0;
//addr = 0x10056BC0;
//addr = 0x1002e5e1;
// addr = MemDbg::findPushAddress(addr, startAddress, stopAddress);
// addr = 0x10041557;
// addr = 0x100414a0;
// addr = 0x10056BC0;
// addr = 0x1002e5e1;
addr = MemDbg::findNearCallAddress(addr, startAddress, stopAddress);
if (!addr)
return false;
//return winhook::hook_both(addr, Private::hookBefore, Private::hookAfter);
// return winhook::hook_both(addr, Private::hookBefore, Private::hookAfter);
HookParam hp;
hp.address=addr;
hp.hook_before=Private::hookBefore;
hp.hook_after=Private::hookafter2;
hp.type=USING_STRING|CODEC_UTF16|EMBED_ABLE;
hp.hook_font=F_GetGlyphOutlineW;
auto succ=NewHook(hp,"EmbedRGSS3");
hp.address=addr+5;
hp.hook_before=Private::hookAfter;
hp.type=HOOK_EMPTY|EMBED_ABLE;
succ|=NewHook(hp,"EmbedRGSS3");
hp.address = addr;
hp.hook_before = Private::hookBefore;
hp.hook_after = Private::hookafter2;
hp.type = USING_STRING | CODEC_UTF16 | EMBED_ABLE;
hp.hook_font = F_GetGlyphOutlineW;
auto succ = NewHook(hp, "EmbedRGSS3");
hp.address = addr + 5;
hp.hook_before = Private::hookAfter;
hp.type = HOOK_EMPTY | EMBED_ABLE;
succ |= NewHook(hp, "EmbedRGSS3");
return succ;
}
} // namespace ScenarioHook
}
} // namespace ScenarioHook
namespace ChoiceHook {
namespace ChoiceHook
{
namespace Private {
namespace Private
{
struct HookArgument
{
@ -747,22 +780,21 @@ namespace Private {
bool isValid() const
{
return text
&& Engine::isAddressReadable(text) && *text
&& Engine::isAddressWritable(text, ::strlen(text));
return text && Engine::isAddressReadable(text) && *text && Engine::isAddressWritable(text, ::strlen(text));
}
//int size() const { return (*type >> 0xe) & 0x1f; }
// int size() const { return (*type >> 0xe) & 0x1f; }
};
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)
{
* role = Engine::OtherRole ;
*role = Engine::OtherRole;
auto arg = (HookArgument *)s->stack[2]; // arg2
if (arg->isValid()) {
auto oldText =StringToWideString(std::string(arg->text),CP_UTF8).value();
if (arg->isValid())
{
auto oldText = StringToWideString(std::string(arg->text), CP_UTF8).value();
auto split = s->stack[0]; // return address
write_string_overwrite(data1,len1,oldText);
write_string_overwrite(data1, len1, oldText);
return 1;
// std::wstring newText = EngineController::instance()->dispatchTextWSTD(oldText, role, sig);
// if (newText != oldText) {
@ -773,25 +805,28 @@ namespace Private {
}
return 0;
}
void hookafter2(hook_stack*s,void* data1, size_t len){
void hookafter2(hook_stack *s, void *data1, size_t len)
{
{
auto arg = (HookArgument *)s->stack[2]; // arg2
if (arg->isValid()) {
auto oldText =StringToWideString(std::string(arg->text),CP_UTF8).value();
if (arg->isValid())
{
auto oldText = StringToWideString(std::string(arg->text), CP_UTF8).value();
auto split = s->stack[0]; // return address
std::wstring old=oldText;
std::wstring old = oldText;
std::wstring newText =std::wstring((wchar_t*)data1,len/2);
if (newText != oldText) {
std::wstring newText = std::wstring((wchar_t *)data1, len / 2);
if (newText != oldText)
{
if (newText.size() < oldText.size())
::memset(arg->text, 0, ::strlen(arg->text));
::strcpy(arg->text, WideStringToString(newText, CP_UTF8).c_str());// newText.toUtf8());
::strcpy(arg->text, WideStringToString(newText, CP_UTF8).c_str()); // newText.toUtf8());
}
}
}
} // namespace Private
} // namespace Private
/**
/**
* Sample game: Mogeko Castle
*
* One of the caller of the three GetGlyphOutlineW
@ -870,77 +905,87 @@ namespace Private {
* 100075ED C3 RETN
* 100075EE CC INT3
*/
ULONG functionAddress; // the function address being hooked
bool attach(ULONG startAddress, ULONG stopAddress) // attach other text
{
ULONG functionAddress; // the function address being hooked
bool attach(ULONG startAddress, ULONG stopAddress) // attach other text
{
const uint8_t bytes[] = {
0x89,0x45, 0xfc, // 100075b5 8945 fc mov dword ptr ss:[ebp-0x4],eax
0x8b,0x4d, 0xfc, // 100075b8 8b4d fc mov ecx,dword ptr ss:[ebp-0x4]
0x8b,0x51, 0x10, // 100075bb 8b51 10 mov edx,dword ptr ds:[ecx+0x10]
0x89,0x55, 0xe8, // 100075be 8955 e8 mov dword ptr ss:[ebp-0x18],edx
0x8b,0x45, 0xe8 // 100075c1 8b45 e8 mov eax,dword ptr ss:[ebp-0x18]
0x89, 0x45, 0xfc, // 100075b5 8945 fc mov dword ptr ss:[ebp-0x4],eax
0x8b, 0x4d, 0xfc, // 100075b8 8b4d fc mov ecx,dword ptr ss:[ebp-0x4]
0x8b, 0x51, 0x10, // 100075bb 8b51 10 mov edx,dword ptr ds:[ecx+0x10]
0x89, 0x55, 0xe8, // 100075be 8955 e8 mov dword ptr ss:[ebp-0x18],edx
0x8b, 0x45, 0xe8 // 100075c1 8b45 e8 mov eax,dword ptr ss:[ebp-0x18]
};
if (ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), startAddress, stopAddress))
if (addr = MemDbg::findEnclosingAlignedFunction(addr)){
if (addr = MemDbg::findEnclosingAlignedFunction(addr))
{
HookParam hp;
hp.address=addr;
hp.hook_before=Private::hookBefore;
hp.hook_after=Private::hookafter2;
hp.type=USING_STRING|CODEC_UTF16|EMBED_ABLE;
hp.hook_font=F_GetGlyphOutlineW;
hp.address = addr;
hp.hook_before = Private::hookBefore;
hp.hook_after = Private::hookafter2;
hp.type = USING_STRING | CODEC_UTF16 | EMBED_ABLE;
hp.hook_font = F_GetGlyphOutlineW;
functionAddress = addr;
return NewHook(hp,"EmbedRGSS3Choice");
return NewHook(hp, "EmbedRGSS3Choice");
}
return false;
}
}
} // namespace ChoiceHook
} // namespace ChoiceHook
}
namespace OtherHook {
namespace Private {
bool hookBefore(hook_stack*s,void* data1, size_t* len1,uintptr_t*role)
}
namespace OtherHook
{
{* role = Engine::OtherRole ;};
namespace Private
{
bool hookBefore(hook_stack *s, void *data1, size_t *len1, uintptr_t *role)
{
{
*role = Engine::OtherRole;
};
auto retaddr = s->stack[0];
if (retaddr > ChoiceHook::Private::functionAddress && retaddr - ChoiceHook::Private::functionAddress < 0xff)
return 0; // skip translate already-hooked function
auto text = (LPWSTR)s->stack[1]; // arg1
if (text && *text) {
if (text && *text)
{
std::wstring oldText(text);
if (oldText.size() > 1) {
write_string_overwrite(data1,len1,oldText);
if (oldText.size() > 1)
{
write_string_overwrite(data1, len1, oldText);
return 1;
}
}
return 0;
}
void hookafter2(hook_stack*s,void* data1, size_t len){
void hookafter2(hook_stack *s, void *data1, size_t len)
{
{
auto retaddr = s->stack[0];
if (retaddr > ChoiceHook::Private::functionAddress && retaddr - ChoiceHook::Private::functionAddress < 0xff)
return ; // skip translate already-hooked function
return; // skip translate already-hooked function
auto text = (LPWSTR)s->stack[1]; // arg1
if (text && *text) {
if (text && *text)
{
std::wstring oldText(text);
if (oldText.size() > 1) {
if (oldText.size() > 1)
{
std::wstring newText =std::wstring((wchar_t*)data1,len/2); ;
std::wstring newText = std::wstring((wchar_t *)data1, len / 2);
;
if (newText != oldText)
::wcscpy(text, (LPCWSTR)newText.c_str());
}
}
}
} // namespace Private
} // namespace Private
/**
/**
* Sample game: Mogeko Castle
*
* There are three GetGlyphIndicesW.
@ -1328,24 +1373,25 @@ namespace Private {
* 1000C69C CC INT3
* 1000C69D CC INT3
*/
ULONG functionAddress; // the beginning of the function being hooked
bool attach(ULONG startAddress, ULONG stopAddress) // attach other text
{
ULONG functionAddress; // the beginning of the function being hooked
bool attach(ULONG startAddress, ULONG stopAddress) // attach other text
{
ULONG addr = MemDbg::findCallerAddressAfterInt3((ULONG)::GetGlyphOutlineW, startAddress, stopAddress);
if(addr==0)return 0;
if (addr == 0)
return 0;
HookParam hp;
hp.address=addr;
hp.hook_before=Private::hookBefore;
hp.hook_after=Private::hookafter2;
hp.type=USING_STRING|CODEC_UTF16|EMBED_ABLE;
hp.hook_font=F_GetGlyphOutlineW;
hp.address = addr;
hp.hook_before = Private::hookBefore;
hp.hook_after = Private::hookafter2;
hp.type = USING_STRING | CODEC_UTF16 | EMBED_ABLE;
hp.hook_font = F_GetGlyphOutlineW;
return NewHook(hp,"EmbedRGSS3Other");
}
}
} // namespace OtherHook
return NewHook(hp, "EmbedRGSS3Other");
}
}
} // namespace OtherHook
} // namespace RGSS3Hook
} // namespace RGSS3Hook
#if 0
@ -1391,10 +1437,10 @@ bool attach()
#endif // 0
} // unnamed namespace
bool RPGMakerRGSS3::attach_function() {
bool RPGMakerRGSS3::attach_function()
{
ULONG startAddress, stopAddress;
if (!RGSS3::getMemoryRange(&startAddress, &stopAddress))
return false;
@ -1406,3 +1452,23 @@ bool RPGMakerRGSS3::attach_function() {
return true;
}
bool RPGMakerRGSS300::attach_function()
{
trigger_fun = [](LPVOID addr1, hook_stack *stack)
{
if (addr1 != GetGlyphOutlineW)
return false;
auto addr = stack->retaddr;
addr = MemDbg::findEnclosingAlignedFunction(addr);
if (addr == 0)
return false;
HookParam hp;
hp.address = addr;
hp.type = USING_STRING | CODEC_UTF16;
hp.offset = get_stack(1);
NewHook(hp, "RGSS300.dll");
return true;
};
return GetModuleHandle(L"RGSS300.dll");
}

View File

@ -1,12 +1,26 @@
class RPGMakerRGSS3:public ENGINE{
public:
RPGMakerRGSS3(){
class RPGMakerRGSS3 : public ENGINE
{
public:
RPGMakerRGSS3()
{
check_by=CHECK_BY::FILE_ALL;
check_by_target=check_by_list{L"*.rgss3a",L"System/RGSS3*.dll"};
is_engine_certain=false;
check_by = CHECK_BY::FILE_ALL;
check_by_target = check_by_list{L"*.rgss3a", L"System/RGSS3*.dll"};
is_engine_certain = false;
};
bool attach_function();
};
class RPGMakerRGSS300 : public ENGINE
{
public:
RPGMakerRGSS300()
{
check_by = CHECK_BY::FILE_ALL;
check_by_target = check_by_list{L"System/RGSS300.dll"};
is_engine_certain = false;
};
bool attach_function();
};

View File

@ -392,5 +392,6 @@ std::vector<ENGINE *> check_engines()
//
//
new DISCOVERY,
new RPGMakerRGSS300,
};
}