Compare commits

..

2 Commits

Author SHA1 Message Date
22946df452 合并Blu3train:Yuris3Engine
修改yuris6 hook为适配英语版yuris
*这破坏了该hook原先对日文版yuris的支持
2024-12-21 23:47:14 +08:00
3b22857d12 update
buildenv, deepl, dac
2024-12-17 10:34:13 -08:00
5 changed files with 399 additions and 58 deletions

View File

@ -8,26 +8,9 @@ macro(msvc_registry_search)
string(REPLACE "/Tools" ";" QT_ROOT "${QT_ROOT}")
list(GET QT_ROOT 0 QT_ROOT)
endif()
file(GLOB QT_VERSIONS "${QT_ROOT}/5.13*")
list(SORT QT_VERSIONS)
# assume the latest version will be last alphabetically
list(REVERSE QT_VERSIONS)
list(GET QT_VERSIONS 0 QT_VERSION)
# fix any double slashes which seem to be common
string(REPLACE "//" "/" QT_VERSION "${QT_VERSION}")
if(MSVC_VERSION GREATER_EQUAL 1920)
set(QT_MSVC 2019)
elseif(MSVC_VERSION GREATER_EQUAL 1910)
set(QT_MSVC 2017)
elseif(MSVC_VERSION GREATER_EQUAL 1900)
set(QT_MSVC 2015)
else()
message(WARNING "Unsupported MSVC toolchain version")
endif()
set(QT_VERSION 5.13.2)
set(QT_MSVC 2019)
if(QT_MSVC)
if(CMAKE_CL_64)
@ -35,17 +18,7 @@ macro(msvc_registry_search)
else()
set(QT_SUFFIX "")
endif()
# MSVC 2015+ is only backwards compatible
if(EXISTS "${QT_VERSION}/msvc${QT_MSVC}${QT_SUFFIX}")
set(Qt5_DIR "${QT_VERSION}/msvc${QT_MSVC}${QT_SUFFIX}/lib/cmake/Qt5")
elseif(QT_MSVC GREATER_EQUAL 2019 AND EXISTS "${QT_VERSION}/msvc2017${QT_SUFFIX}")
set(Qt5_DIR "${QT_VERSION}/msvc2017${QT_SUFFIX}/lib/cmake/Qt5")
elseif(QT_MSVC GREATER_EQUAL 2017 AND EXISTS "${QT_VERSION}/msvc2015${QT_SUFFIX}")
set(Qt5_DIR "${QT_VERSION}/msvc2015${QT_SUFFIX}/lib/cmake/Qt5")
else()
message(WARNING "Required QT5 toolchain is not installed")
endif()
set(Qt5_DIR "${QT_VERSION}/msvc2017${QT_SUFFIX}/lib/cmake/Qt5")
endif()
endif()
endmacro()
@ -55,6 +28,11 @@ macro(find_qt5)
#set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
#add_definitions(-DQT_DEPRECATED_WARNINGS -DQT_DISABLE_DEPRECATED_BEFORE=0x060000)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(Qt5_DIR "C:/Qt/Qt5.13.2/5.13.2/msvc2017_64/lib/cmake/Qt5")
else()
set(Qt5_DIR "C:/Qt/Qt5.13.2/5.13.2/msvc2017/lib/cmake/Qt5")
endif()
find_package(Qt5 COMPONENTS ${ARGN})
if(Qt5_FOUND)

View File

@ -9,43 +9,52 @@ const char* TRANSLATION_PROVIDER = "DeepL Translate";
const char* GET_API_KEY_FROM = "https://www.deepl.com/pro.html#developer";
extern const QStringList languagesTo
{
"Arabic",
"Bulgarian",
"Chinese (Simplified)",
"Czech",
"Danish",
"Dutch",
"English (American)",
"German",
"Greek",
"English (backward compatibility)",
"English (British)",
"English (American)",
"Spanish",
"Estonian",
"Finnish",
"French",
"German",
"Greek",
"Hungarian",
"Indonesian",
"Italian",
"Japanese",
"Latvian",
"Korean",
"Lithuanian",
"Latvian",
"Norwegian Bokmål",
"Dutch",
"Polish",
"Portuguese (Brazil)",
"Portuguese (Portugal)",
"Portuguese (backward compatibility)",
"Portuguese (Brazilian)",
"Portuguese (all Portuguese variants excluding Brazilian Portuguese)",
"Romanian",
"Russian",
"Slovak",
"Slovenian",
"Spanish",
"Swedish",
"Turkish"
"Turkish",
"Ukrainian",
"Chinese (backward compatibility)",
"Chinese (simplified)",
"Chinese (traditional)"
},
languagesFrom
{
"Arabic",
"Bulgarian",
"Chinese",
"Chinese (all Chinese variants)",
"Czech",
"Danish",
"Dutch",
"English",
"English (all English variants)",
"Estonian",
"Finnish",
"French",
@ -55,52 +64,64 @@ languagesFrom
"Indonesian",
"Italian",
"Japanese",
"Korean",
"Latvian",
"Lithuanian",
"Norwegian Bokmål",
"Polish",
"Portuguese",
"Portuguese (all Portuguese variants)",
"Romanian",
"Russian",
"Slovak",
"Slovenian",
"Spanish",
"Swedish",
"Turkish"
"Turkish",
"Ukrainian"
};
extern const std::unordered_map<std::wstring, std::wstring> codes
{
{ { L"Arabic" }, { L"AR" } },
{ { L"Bulgarian" }, { L"BG" } },
{ { L"Chinese" }, { L"ZH" } },
{ { L"Chinese (Simplified)" }, { L"ZH" } },
{ { L"Czech" }, { L"CS" } },
{ { L"Danish" }, { L"DA" } },
{ { L"Dutch" }, { L"NL" } },
{ { L"English" }, { L"EN" } },
{ { L"English (American)" }, { L"EN-US" } },
{ { L"German" }, { L"DE" } },
{ { L"Greek" }, { L"EL" } },
{ { L"English (all English variants)" }, { L"EN" } },
{ { L"English (backward compatibility)" }, { L"EN" } },
{ { L"English (British)" }, { L"EN-GB" } },
{ { L"English (American)" }, { L"EN-US" } },
{ { L"Spanish" }, { L"ES" } },
{ { L"Estonian" }, { L"ET" } },
{ { L"Finnish" }, { L"FI" } },
{ { L"French" }, { L"FR" } },
{ { L"German" }, { L"DE" } },
{ { L"Greek" }, { L"EL" } },
{ { L"Hungarian" }, { L"HU" } },
{ { L"Indonesian" }, { L"ID" } },
{ { L"Italian" }, { L"IT" } },
{ { L"Japanese" }, { L"JA" } },
{ { L"Latvian" }, { L"LV" } },
{ { L"Korean" }, { L"KO" } },
{ { L"Lithuanian" }, { L"LT" } },
{ { L"Latvian" }, { L"LV" } },
{ { L"Norwegian Bokmål" }, { L"NB" } },
{ { L"Dutch" }, { L"NL" } },
{ { L"Polish" }, { L"PL" } },
{ { L"Portuguese" }, { L"PT" } },
{ { L"Portuguese (Brazil)" }, { L"PT-BR" } },
{ { L"Portuguese (Portugal)" }, { L"PT-PT" } },
{ { L"Portuguese (all Portuguese variants)" }, { L"PT" } },
{ { L"Portuguese (backward compatibility)" }, { L"PT" } },
{ { L"Portuguese (Brazilian)" }, { L"PT-BR" } },
{ { L"Portuguese (all Portuguese variants excluding Brazilian Portuguese)" }, { L"PT-PT" } },
{ { L"Romanian" }, { L"RO" } },
{ { L"Russian" }, { L"RU" } },
{ { L"Slovak" }, { L"SK" } },
{ { L"Slovenian" }, { L"SL" } },
{ { L"Spanish" }, { L"ES" } },
{ { L"Swedish" }, { L"SV" } },
{ { L"Turkish" }, { L"TR" } },
{ { L"Ukrainian" }, { L"UK" } },
{ { L"Chinese (all Chinese variants)" }, { L"ZH" } },
{ { L"Chinese (backward compatibility)" }, { L"ZH" } },
{ { L"Chinese (simplified)" }, { L"ZH-HANS" } },
{ { L"Chinese (traditional)" }, { L"ZH-HANT" } },
{ { L"?" }, { L"auto" } }
};
bool translateSelectedOnly = true, useRateLimiter = true, rateLimitSelected = true, useCache = true, useFilter = true;

View File

@ -27,6 +27,7 @@
//#include <boost/foreach.hpp>
#include <cstdio>
#include <string>
#include <sstream>
// jichi 375/2014: Add offset of pusha/pushad
// http://faydoc.tripod.com/cpu/pushad.htm
@ -6351,9 +6352,267 @@ static bool InsertYuris2Hook()
NewHook(hp, "YU-RIS2");
return true;
}
static bool Yuris3Filter(LPVOID data, DWORD* size, HookParam*, BYTE)
{
static wchar_t prev_text;
wchar_t* pText = reinterpret_cast<wchar_t*>(data);
if (prev_text == *pText)
{
prev_text = '\0';
return false;
}
prev_text = *pText;
return true;
}
static bool InsertYuris3Hook()
{
//by Blu3train
HookParam hp = {};
wcsncpy_s(hp.module, L"kernel32.dll", MAX_MODULE_SIZE - 1);
strncpy_s(hp.function, "MultiByteToWideChar", MAX_MODULE_SIZE - 1);
hp.address = 6;
hp.offset = 0xC; //arg3
hp.index = 0;
hp.split = 0x1C;
hp.split_index = 0;
hp.filter_fun = Yuris3Filter;
hp.type = USING_STRING | USING_SPLIT | MODULE_OFFSET | FUNCTION_OFFSET;
hp.length_offset = 0x10 / (short)sizeof(void*); // arg4/arg_sz
ConsoleOutput("vnreng: INSERT YU-RIS 3");
NewHook(hp, "YU-RIS3");
return true;
}
bool InsertYuris4Hook()
{
//by Blu3train
/*
* Sample games:
* https://vndb.org/v6540
*/
bool found = false;
const BYTE pattern[] = {
0x52, // 52 push edx
0x68, 0x00, 0x42, 0x5C, 0x00, // 68 00425C00 push euphoria.exe+1C4200
0xFF, 0x15, 0x90, 0x44, 0x7E, 0x00, // FF 15 90447E00 call dword ptr [euphoria.exe+3E4490]
0x83, 0xC4, 0x0C, // 83 C4 0C add esp,0C
0xEB, 0x5F, // EB 5F jmp euphoria.exe+4F4C5
0xFF, 0x35, 0xA4, 0x19, 0x66, 0x00, // FF 35 A4196600 push [euphoria.exe+2619A4]
0x52 // 52 push edx
};
enum { addr_offset = 12 }; // distance to the beginning of the function, which is 0x83, 0xC4, 0x0C (add esp,0C)
for (auto addr : Util::SearchMemory(pattern, sizeof(pattern), PAGE_EXECUTE, processStartAddress, processStopAddress))
{
HookParam hp = {};
hp.address = addr + addr_offset;
hp.offset = pusha_edx_off - 4;
hp.type = USING_STRING;
ConsoleOutput("Textractor: INSERT YU-RIS 4");
NewHook(hp, "YU-RIS4");
found = true;
}
if (!found) ConsoleOutput("Textractor:YU-RIS 4: pattern not found");
return found;
}
bool InsertYuris5Hook()
{
//by Blu3train
/*
* Sample games:
* https://vndb.org/v4037
*/
const BYTE bytes[] = {
0x33, 0xD2, // xor edx,edx
0x88, 0x14, 0x0F, // mov [edi+ecx],dl
0xA1, XX4, // mov eax,[exe+2DE630]
0x8B, 0x78, 0x3C, // mov edi,[eax+3C]
0x8B, 0x58, 0x5C, // mov ebx,[eax+5C]
0x88, 0x14, 0x3B // mov [ebx+edi],dl
};
enum { addr_offset = 0 }; // distance to the beginning of the function, which is 0x55 (push ebp)
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr)
return false;
HookParam hp = {};
hp.address = addr + addr_offset;
hp.offset = pusha_ecx_off - 4;
hp.type = USING_STRING | NO_CONTEXT;
ConsoleOutput("Textractor: INSERT YU-RIS 5");
NewHook(hp, "YU-RIS5");
return true;
}
static bool Yuris6Filter(LPVOID data, DWORD* size, HookParam*, BYTE)
{
auto text = reinterpret_cast<LPSTR>(data);
auto len = reinterpret_cast<size_t*>(size);
static std::string prevText;
if (prevText.length() == *len && prevText.find(text, 0, *len) != std::string::npos) // Check if the string is present in the previous one
return false;
prevText.assign(text, *len);
// ruby <手水舎/ちょうずや>
if (cpp_strnstr(text, "\x81\x83", *len)) { // \x81\x83 -> ''
StringFilterBetween(text, len, "\x81\x5E", 2, "\x81\x84", 2); // \x81\x5E -> '' , \x81\x84 -> ''
StringFilter(text, len, "\x81\x83", 2); // \x81\x83 -> ''
}
// ruby ≪美桜/姉さん≫
else if (cpp_strnstr(text, "\x81\xE1", *len)) { // \x81\xE1 -> '≪'
StringFilterBetween(text, len, "\x81\x5E", 2, "\x81\xE2", 2); // \x81\x5E -> '' , \x81\xE2 -> '≫'
StringFilter(text, len, "\x81\xE1", 2); // \x81\xE1 -> '≪'
}
CharReplacer(text, len, '=', '-');
StringCharReplacer(text, len, "\xEF\xF0", 2, ' ');
StringFilter(text, len, "\xEF\xF2", 2);
StringFilter(text, len, "\xEF\xF5", 2);
StringFilter(text, len, "\x81\x98", 2);
return true;
}
bool InsertYuris6Hook()
{
//by Blu3train
/*
* Sample games:
* https://vndb.org/v40058
* https://vndb.org/v42883
* https://vndb.org/v44092
* https://vndb.org/v21171
* https://vndb.org/r46910
*/
const BYTE bytes[] = {
0xE9, XX4, // jmp oshitona01.exe+1B629
0xBF, XX4, // mov edi,oshitona01.exe+24EEA0
0x8A, 0x17, // mov dl,[edi]
0x47, // inc edi
0x88, 0x16, // mov [esi],dl
0x46, // inc esi
0x84, 0xD2 // test dl,dl
};
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr)
return false;
HookParam hp = {};
hp.address = addr;
hp.offset = pusha_eax_off - 4;
hp.index = 0x38;
hp.codepage = 65001;
hp.filter_fun = Yuris6Filter;
hp.type = USING_STRING | NO_CONTEXT | DATA_INDIRECT;
ConsoleOutput("Textractor: INSERT YU-RIS 6");
NewHook(hp, "YU-RIS6");
return true;
}
bool InsertYuris7Hook()
{
//by Blu3train
/*
* Sample games:
* https://vndb.org/v45381
* https://vndb.org/v47458
* https://vndb.org/v21144
* https://vndb.org/v18681
*/
const BYTE bytes[] = {
0x03, 0xC1, // add eax,ecx
0x99, // cdq
0xE9, XX4 // jmp nekonin_spin.exe+55753 << hook here
};
enum { addr_offset = sizeof(bytes) - 5 };
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr)
return false;
HookParam hp = {};
hp.address = addr + addr_offset;
hp.offset = pusha_eax_off - 4;
hp.index = 0;
hp.length_offset = 1; // only 1 character
hp.text_fun = [](DWORD esp_base, HookParam*, BYTE, DWORD*, DWORD*, DWORD* len)
{
*len = (retof(esp_base) == 0) ? 2 : 0;
};
hp.type = BIG_ENDIAN;
ConsoleOutput("vnreng: INSERT YU-RIS7");
NewHook(hp, "YU-RIS7");
return true;
}
bool InsertYuris8Hook()
{
//by Blu3train
/*
* Sample games:
* https://vndb.org/v47458
* https://vndb.org/v45381
*/
const BYTE bytes[] = {
0x57, // push edi << hook here
0x56, // push esi
0x55, // push ebp
0x53, // push ebx
0x83, 0xEC, 0x10, // sub esp,10
0x8B, 0x5C, 0x24, 0x24, // mov ebx,[esp+24]
0x8B, 0x15, XX4, // mov edx,[hajiron.exe+47243C]
0x8B, 0x0C, 0x9A, // mov ecx,[edx+ebx*4]
0xC6, 0x41, 0x01, 0x03, // mov byte ptr [ecx+01],03
0x8B, 0xC3, // mov eax,ebx
0xE8,XX4 // call hajiron.exe+54EA4
};
ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range);
if (!addr)
return false;
HookParam hp = {};
hp.address = addr;
hp.offset = pusha_edx_off - 4;
hp.index = 0;
hp.text_fun = [](DWORD esp_base, HookParam*, BYTE, DWORD*, DWORD*, DWORD* len)
{
DWORD textLen = regof(eax, esp_base);
if (textLen > 2)
return;
*len = (regof(edi, esp_base) >= 0xFA && regof(edi, esp_base) <= 0xFE || regof(edi, esp_base) >= 0x1A0 && regof(edi, esp_base) <= 0x1C2) ? textLen : 0;
};
hp.type = USING_STRING;
ConsoleOutput("vnreng: INSERT YU-RIS8");
NewHook(hp, "YU-RIS8");
return true;
}
bool InsertYurisHook()
{ return InsertYuris1Hook() || InsertYuris2Hook(); }
{
bool ok = InsertYuris1Hook();
ok = InsertYuris2Hook() || ok;
ok = InsertYuris3Hook() || ok;
ok = InsertYuris4Hook() || ok;
ok = InsertYuris5Hook() || ok;
ok = InsertYuris6Hook() || ok;
ok = InsertYuris7Hook() || ok;
ok = InsertYuris8Hook() || ok;
return ok;
}
bool InsertCotophaHook1()
{
@ -21026,6 +21285,84 @@ bool InsertTecmoPSPHook()
}
#endif // 0
//for debug
void StringBlockProcessor(char* str, size_t* size, size_t fixlength)
{
size_t original_len = *size;
size_t new_len = 0;
char* new_str = new char[original_len + 1];
size_t i = 0;
while (i < original_len) {
size_t block_end = i + fixlength;
if (block_end > original_len) {
block_end = original_len;
}
size_t block_len = block_end - i;
char* block = str + i;
for (size_t j = 0; j < block_len; ++j) {
if (block[j] != 0) {
new_str[new_len++] = block[j];
}
else {
break;
}
}
i = block_end;
}
new_str[new_len] = '\0';
std::memcpy(str, new_str, new_len + 1);
*size = new_len;
delete[] new_str;
}
bool DACFilter(LPVOID data, DWORD* size, HookParam*, BYTE)
{
auto text = reinterpret_cast<LPSTR>(data);
auto len = reinterpret_cast<size_t*>(size);
StringBlockProcessor(text, len, 0x3f);
return true;
}
bool InsertDACHook()
{
const BYTE bytecodes[] = {
0x0F, 0xBF, 0x56, 0x34, // movsx edx, word ptr ds:[esi+34]
0x83, 0xC2, 0x05, // add edx, 5
0x8B, 0x8E, 0x00, 0x01, 0x00, 0x00, // mov ecx, dword ptr ds:[esi+100]
0x0F, 0xAF, 0xD3 // imul edx, ebx <--
};
ULONG addr = MemDbg::findBytes(bytecodes, sizeof(bytecodes), processStartAddress, processStopAddress);
if (addr == 0) {
ConsoleOutput("vnreng:DAC: pattern not found");
return false;
}
enum { addr_offset = 13 };
HookParam hp = {};
hp.type = USING_STRING; //S
hp.address = addr + addr_offset;
hp.offset = pusha_ecx_off - 4; //-C
hp.index = 0x00;
hp.filter_fun = DACFilter;
hp.length_fun = [](uintptr_t, uintptr_t data)
{
int len = 0x3f;
return len * 4;
};
NewHook(hp, "DAC");
ConsoleOutput("vnreng: INSERT DAC");
return true;
}
/** jichi 7/19/2014 PCSX2
* Tested wit pcsx2-v1.2.1-328-gef0e3fe-windows-x86, built at http://buildbot.orphis.net/pcsx2
*/
@ -21261,7 +21598,6 @@ bool InsertTypeMoonPS2Hook()
ConsoleOutput("vnreng: TypeMoon PS2: leave");
return addr;
}
/** 8/3/2014 jichi
* Tested game: School Rumble <EFBFBD>
*

View File

@ -96,6 +96,7 @@ bool InsertCandyHook(); // SystemC@CandySoft: *.fpk
bool InsertCatSystemHook(); // CatSystem2: *.int
bool InsertCMVSHook(); // CMVS: data/pack/*.cpz; do not support the latest cmvs32.exe and cmvs64.exe
bool InsertCotophaHook(); // Cotopha: *.noa
bool InsertDACHook(); // DAC
bool InsertDebonosuHook(); // Debonosu: bmp.bak and dsetup.dll
bool InsertEaglsHook(); // E.A.G.L.S: EAGLES.dll
bool InsertEMEHook(); // EmonEngine: emecfg.ecf

View File

@ -54,6 +54,11 @@ bool DeterminePCEngine()
return true;
}
if (Util::CheckFile(L"script.dpk")) {
InsertDACHook();
return true;
}
// jichi 5/14/2015: Skip hijacking BALDRSKY ZEROs
//if (Util::CheckFile(L"bsz_Data\\Mono\\mono.dll") || Util::CheckFile(L"bsz2_Data\\Mono\\mono.dll")) {
// ConsoleOutput("vnreng: IGNORE BALDRSKY ZEROs");