This commit is contained in:
恍兮惚兮 2024-10-03 14:53:59 +08:00
parent 1016b82df0
commit 163835bec9
61 changed files with 4928 additions and 3780 deletions

View File

@ -61,7 +61,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/version)
include(generate_product_version) include(generate_product_version)
set(VERSION_MAJOR 3) set(VERSION_MAJOR 3)
set(VERSION_MINOR 13) set(VERSION_MINOR 14)
set(VERSION_PATCH 0) set(VERSION_PATCH 0)
set(VERSION_REVISION 0) set(VERSION_REVISION 0)

View File

@ -1,6 +1,6 @@
include_directories(. util engines) include_directories(. util engines)
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8) if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
set(enginessrc MKXPZ Ryujinx livecaptions Kincaid vita3k rpcs3 yuzusuyu TYPEMOON ENTERGRAM AGES7 mono Godot 5pb lucasystem LightVN V8 pchooks Artemis KiriKiri YOX PPSSPP CMVS Suika2 ) set(enginessrc MKXPZ Ryujinx livecaptions Kincaid vita3k rpcs3 yuzu TYPEMOON ENTERGRAM AGES7 mono Godot 5pb lucasystem LightVN V8 pchooks Artemis KiriKiri YOX PPSSPP CMVS Suika2 )
set(enginepath "engine64") set(enginepath "engine64")
set(collector "enginecollection64.cpp") set(collector "enginecollection64.cpp")
else() else()

View File

@ -1,18 +1,22 @@
#include "5pb.h" #include "5pb.h"
#include "mages/mages.h" #include "mages/mages.h"
namespace{ namespace
{
// https://vndb.org/v46553 // https://vndb.org/v46553
// 新宿葬命 // 新宿葬命
bool _strncat(){ bool _strncat()
{
HookParam hp; HookParam hp;
hp.address = (uintptr_t)GetProcAddress(GetModuleHandleA("ucrtbase.dll"), "strncat"); hp.address = (uintptr_t)GetProcAddress(GetModuleHandleA("ucrtbase.dll"), "strncat");
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT; hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
*data = stack->ARG2; *data = stack->ARG2;
*len = stack->ARG3; *len = stack->ARG3;
*split = stack->ARG1; *split = stack->ARG1;
}; };
hp.filter_fun=[](void* data, size_t* len, HookParam* hp){ hp.filter_fun = [](void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
strReplace(s, "%N", "\n"); strReplace(s, "%N", "\n");
// sub_140096E80 // sub_140096E80
@ -22,7 +26,8 @@ namespace{
return NewHook(hp, "strncat"); return NewHook(hp, "strncat");
} }
} }
bool _5pb::attach_function() { bool _5pb::attach_function()
{
// CHAOS;HEAD_NOAH // CHAOS;HEAD_NOAH
bool b3 = hookmages::MAGES(); bool b3 = hookmages::MAGES();
return b3 || _strncat(); return b3 || _strncat();

View File

@ -1,13 +1,13 @@
class _5pb:public ENGINE{ class _5pb : public ENGINE
{
public: public:
_5pb(){ _5pb()
{
is_engine_certain = false; is_engine_certain = false;
check_by = CHECK_BY::FILE_ANY; check_by = CHECK_BY::FILE_ANY;
check_by_target = check_by_list{L"data\\*.cpk", L"*.cpk"}; check_by_target = check_by_list{L"data\\*.cpk", L"*.cpk"};
}; };
bool attach_function(); bool attach_function();
}; };

View File

@ -1,22 +1,28 @@
#include "AGES7.h" #include "AGES7.h"
namespace{ namespace
{
// Muv-Luv Alternative - Total Eclipse // Muv-Luv Alternative - Total Eclipse
// https://vndb.org/v7052 // https://vndb.org/v7052
bool _1(){ bool _1()
{
// HSN65001#-44@234699:te-win64vc14-release.exe // HSN65001#-44@234699:te-win64vc14-release.exe
BYTE b1[] = { BYTE b1[] = {
//clang-format off
0x48, XX2, 0xb0, 0xfe, 0xff, 0xff, 0x48, XX2, 0xb0, 0xfe, 0xff, 0xff,
0x4c, XX2, 0xb8, 0x01, 0x00, 0x00, 0x4c, XX2, 0xb8, 0x01, 0x00, 0x00,
//clang-format on
}; };
auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress); auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress);
if(addr==0)return false; if (addr == 0)
return false;
HookParam hp; HookParam hp;
hp.address = addr; hp.address = addr;
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT; hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
hp.offset = get_reg(regs::rdi); hp.offset = get_reg(regs::rdi);
auto succ = NewHook(hp, "Ages7_1"); auto succ = NewHook(hp, "Ages7_1");
if(addr=MemDbg::findEnclosingAlignedFunction(addr)){ if (addr = MemDbg::findEnclosingAlignedFunction(addr))
{
hp.address = addr; hp.address = addr;
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT; hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
hp.offset = get_reg(regs::rbx); hp.offset = get_reg(regs::rbx);
@ -24,22 +30,27 @@ namespace{
} }
return succ; return succ;
} }
bool _2(){ bool _2()
{
// HSN65001#-44@2346AC:te-win64vc14-release.exe // HSN65001#-44@2346AC:te-win64vc14-release.exe
BYTE b1[] = { BYTE b1[] = {
//clang-format off
0x48, XX2, 0x10, 0x48, XX2, 0x10,
0x48, XX2, 0xb0, 0x01, 0x00, 0x00, 0x48, XX2, 0xb0, 0x01, 0x00, 0x00,
XX2, 0xc0, 0x08, 0x00, 0x00 XX2, 0xc0, 0x08, 0x00, 0x00
//clang-format on
}; };
auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress); auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress);
if(addr==0)return false; if (addr == 0)
return false;
HookParam hp; HookParam hp;
hp.address = addr; hp.address = addr;
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT; hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
hp.offset = get_reg(regs::rdi); hp.offset = get_reg(regs::rdi);
auto suc = NewHook(hp, "Ages7_2"); auto suc = NewHook(hp, "Ages7_2");
if(addr=MemDbg::findEnclosingAlignedFunction(addr)){ if (addr = MemDbg::findEnclosingAlignedFunction(addr))
{
hp.address = addr; hp.address = addr;
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT; hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
hp.offset = get_reg(regs::rbx); hp.offset = get_reg(regs::rbx);
@ -47,9 +58,11 @@ namespace{
} }
return suc; return suc;
} }
bool _3(){ bool _3()
{
// HSN65001#-14@3D9814:te-win64vc14-release.exe // HSN65001#-14@3D9814:te-win64vc14-release.exe
BYTE b1[] = { BYTE b1[] = {
//clang-format off
0x48, 0x8b, 0x1b, 0x48, 0x8b, 0x1b,
0x48, 0x8b, 0x01, 0x48, 0x8b, 0x01,
0x48, 0x8b, 0xd3, 0x48, 0x8b, 0xd3,
@ -59,22 +72,26 @@ namespace{
0x48, 0x2b, 0xc1, 0x48, 0x2b, 0xc1,
0x48, 0xc1, 0xf8, 0x03, 0x48, 0xc1, 0xf8, 0x03,
0x48, 0x85, 0xc0, 0x48, 0x85, 0xc0,
//clang-format on
}; };
auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress); auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress);
if(addr==0)return false; if (addr == 0)
return false;
HookParam hp; HookParam hp;
hp.address = addr + 3; hp.address = addr + 3;
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT; hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
hp.offset = get_reg(regs::rbx); hp.offset = get_reg(regs::rbx);
return NewHook(hp, "Ages7_4"); return NewHook(hp, "Ages7_4");
} }
bool all(){ bool all()
{
auto _ = _1(); auto _ = _1();
_ = _2() || _; _ = _2() || _;
_ = _3() || _; _ = _3() || _;
return _; return _;
} }
} }
bool AGES7::attach_function(){ bool AGES7::attach_function()
{
return all(); return all();
} }

View File

@ -1,12 +1,13 @@
class AGES7:public ENGINE{ class AGES7 : public ENGINE
{
public: public:
AGES7(){ AGES7()
{
check_by = CHECK_BY::FILE_ALL; check_by = CHECK_BY::FILE_ALL;
check_by_target = check_by_list{L"obb\\pack.bin", L"erc_nospfx.dll"}; check_by_target = check_by_list{L"obb\\pack.bin", L"erc_nospfx.dll"};
}; };
bool attach_function(); bool attach_function();
}; };

View File

@ -1,8 +1,10 @@
class Artemis:public ENGINE{ class Artemis : public ENGINE
{
public: public:
Artemis(){ Artemis()
{
check_by = CHECK_BY::FILE; check_by = CHECK_BY::FILE;
check_by_target = L"*.pfs"; check_by_target = L"*.pfs";

View File

@ -1,30 +1,38 @@
#include "CMVS.h" #include "CMVS.h"
namespace{ namespace
bool EMbed(){ {
bool EMbed()
{
// 有多个,但是只有最后一个是有效的 // 有多个,但是只有最后一个是有效的
const uint8_t bytes[] = { const uint8_t bytes[] = {
//clang-format off
0xB8, 0x42, 0x81, 0x00, 0x00, 0xB8, 0x42, 0x81, 0x00, 0x00,
0x66, XX2, 0x74, XX, 0x66, XX2, 0x74, XX,
0xB8, 0x76, 0x81, 0x00, 0x00, 0xB8, 0x76, 0x81, 0x00, 0x00,
0x66, XX2, 0x74, XX, 0x66, XX2, 0x74, XX,
0xB8, 0x78, 0x81, 0x00, 0x00, 0xB8, 0x78, 0x81, 0x00, 0x00,
0x66, XX2, 0x74, XX, 0x66, XX2, 0x74, XX,
//clang-format on
}; };
bool res = false; bool res = false;
auto addr = processStartAddress; auto addr = processStartAddress;
std::vector<uintptr_t> already; std::vector<uintptr_t> already;
while(addr){ while (addr)
{
addr = MemDbg::findBytes(bytes, sizeof(bytes), addr + 1, processStopAddress); addr = MemDbg::findBytes(bytes, sizeof(bytes), addr + 1, processStopAddress);
if(addr==0)continue; if (addr == 0)
continue;
auto f = MemDbg::findEnclosingAlignedFunction(addr); auto f = MemDbg::findEnclosingAlignedFunction(addr);
if(f==0)continue; if (f == 0)
if(std::find(already.begin(),already.end(),f)!=already.end())continue; continue;
if (std::find(already.begin(), already.end(), f) != already.end())
continue;
already.push_back(f); already.push_back(f);
} }
if(already.size()){ if (already.size())
{
HookParam hp; HookParam hp;
hp.address = already.back(); hp.address = already.back();
hp.offset = get_reg(regs::rdx); hp.offset = get_reg(regs::rdx);
@ -36,11 +44,13 @@ bool EMbed(){
return res; return res;
} }
bool CMVSh() { bool CMVSh()
{
DWORD align = 0xCCCCCCCC; DWORD align = 0xCCCCCCCC;
auto addr = MemDbg::findCallerAddress((uintptr_t)::GetGlyphOutlineA, align, processStartAddress, processStopAddress); auto addr = MemDbg::findCallerAddress((uintptr_t)::GetGlyphOutlineA, align, processStartAddress, processStopAddress);
if (!addr) return false; if (!addr)
return false;
HookParam hp; HookParam hp;
hp.address = addr + 4; hp.address = addr + 4;
@ -50,7 +60,8 @@ bool CMVSh() {
return NewHook(hp, "CMVS"); return NewHook(hp, "CMVS");
} }
} }
bool CMVS::attach_function(){ bool CMVS::attach_function()
{
bool b1 = CMVSh(); bool b1 = CMVSh();
bool b2 = EMbed(); bool b2 = EMbed();
return b1 || b2; return b1 || b2;

View File

@ -1,13 +1,14 @@
class CMVS:public ENGINE{ class CMVS : public ENGINE
{
public: public:
CMVS(){ CMVS()
{
check_by = CHECK_BY::FILE; check_by = CHECK_BY::FILE;
check_by_target = L"data\\pack\\*.cpz"; check_by_target = L"data\\pack\\*.cpz";
// jichi 8/19/2013: DO NOT WORK for games like「ハピメア」 // jichi 8/19/2013: DO NOT WORK for games like「ハピメア」
// if (wcsstr(str,L"cmvs32") || wcsstr(str,L"cmvs64")) { // if (wcsstr(str,L"cmvs32") || wcsstr(str,L"cmvs64")) {
// InsertCMVSHook(); // InsertCMVSHook();

View File

@ -1,10 +1,12 @@
#include "Godot.h" #include "Godot.h"
bool InsertGodotHook_X64() { bool InsertGodotHook_X64()
{
const BYTE bytes[] = {0x8B, 0x40, 0xFC, 0x83, 0xF8, 0x01, 0x83, 0xD0, 0xFF, 0x41, 0x39, 0xC6}; const BYTE bytes[] = {0x8B, 0x40, 0xFC, 0x83, 0xF8, 0x01, 0x83, 0xD0, 0xFF, 0x41, 0x39, 0xC6};
ULONG64 range = min(processStopAddress - processStartAddress, MAX_REL_ADDR); ULONG64 range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range)) { for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range))
{
HookParam myhp; HookParam myhp;
myhp.address = addr; myhp.address = addr;
@ -16,7 +18,8 @@ bool InsertGodotHook_X64() {
{ {
*data = (stack->rax); *data = (stack->rax);
int len = *(int *)(*data - 4); int len = *(int *)(*data - 4);
if(len!=wcslen((wchar_t*)*data))return; if (len != wcslen((wchar_t *)*data))
return;
*count = len * 2; *count = len * 2;
}; };
char nameForUser[HOOK_NAME_SIZE] = "RichTextLabel_add_text"; char nameForUser[HOOK_NAME_SIZE] = "RichTextLabel_add_text";
@ -28,7 +31,8 @@ bool InsertGodotHook_X64() {
ConsoleOutput("Godot_x64: pattern not found"); ConsoleOutput("Godot_x64: pattern not found");
return false; return false;
} }
bool InsertGodotHook2_X64() { bool InsertGodotHook2_X64()
{
/* /*
* Sample games: * Sample games:
@ -45,7 +49,8 @@ bool InsertGodotHook2_X64() {
}; };
ULONG64 range = min(processStopAddress - processStartAddress, X64_MAX_REL_ADDR); ULONG64 range = min(processStopAddress - processStartAddress, X64_MAX_REL_ADDR);
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range)) { for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range))
{
HookParam hp; HookParam hp;
hp.address = addr; hp.address = addr;
hp.offset = get_reg(regs::rcx); hp.offset = get_reg(regs::rcx);
@ -57,7 +62,8 @@ bool InsertGodotHook2_X64() {
ConsoleOutput("Godot2_x64: pattern not found"); ConsoleOutput("Godot2_x64: pattern not found");
return false; return false;
} }
bool Godot::attach_function(){ bool Godot::attach_function()
{
auto _ = InsertGodotHook_X64(); auto _ = InsertGodotHook_X64();
_ = InsertGodotHook2_X64() || _; _ = InsertGodotHook2_X64() || _;
return _; return _;

View File

@ -1,8 +1,10 @@
class Godot:public ENGINE{ class Godot : public ENGINE
{
public: public:
Godot(){ Godot()
{
check_by = CHECK_BY::FILE; check_by = CHECK_BY::FILE;
check_by_target = L"*.pck"; check_by_target = L"*.pck";

View File

@ -1,6 +1,8 @@
#include "Kincaid.h" #include "Kincaid.h"
namespace{ namespace
bool _1(){ {
bool _1()
{
// .text:0000000140230D80 mov rsi, rax // .text:0000000140230D80 mov rsi, rax
// .text:0000000140230D83 mov edx, 1 // .text:0000000140230D83 mov edx, 1
// .text:0000000140230D88 mov rcx, rdi // .text:0000000140230D88 mov rcx, rdi
@ -17,15 +19,16 @@ namespace{
0x8d, 0x58, 0xff, 0x8d, 0x58, 0xff,
0xba, 0x02, 0x00, 0x00, 0x00, 0xba, 0x02, 0x00, 0x00, 0x00,
0x48, 0x8b, 0xcf, 0x48, 0x8b, 0xcf,
0xe8,XX4 0xe8, XX4};
};
auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress); auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress);
if(addr==0)return false; if (addr == 0)
return false;
HookParam hp; HookParam hp;
hp.address = addr; hp.address = addr;
hp.type = USING_STRING | CODEC_UTF8; hp.type = USING_STRING | CODEC_UTF8;
hp.offset = get_reg(regs::rax); hp.offset = get_reg(regs::rax);
hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
*data = stack->rax; *data = stack->rax;
if (stack->retaddr == (DWORD)-1) if (stack->retaddr == (DWORD)-1)
*len = strlen((char *)*data); *len = strlen((char *)*data);
@ -33,6 +36,7 @@ namespace{
return NewHook(hp, "Kincaid"); return NewHook(hp, "Kincaid");
} }
} }
bool Kincaid::attach_function(){ bool Kincaid::attach_function()
{
return _1(); return _1();
} }

View File

@ -26,15 +26,17 @@
// } // }
// } // }
class Kincaid:public ENGINE{ class Kincaid : public ENGINE
{
public: public:
Kincaid(){ Kincaid()
{
check_by = CHECK_BY::CUSTOM; check_by = CHECK_BY::CUSTOM;
check_by_target=[](){ check_by_target = []()
{
return Util::SearchResourceString(L"Cookiedraggy") || Util::SearchResourceString(L"The Adventures of Kincaid"); return Util::SearchResourceString(L"Cookiedraggy") || Util::SearchResourceString(L"The Adventures of Kincaid");
}; };
}; };
bool attach_function(); bool attach_function();
}; };

View File

@ -22,7 +22,8 @@ bool InsertKiriKiriZHook()
}; };
ULONG64 range = min(processStopAddress - processStartAddress, X64_MAX_REL_ADDR); ULONG64 range = min(processStopAddress - processStartAddress, X64_MAX_REL_ADDR);
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range)) { for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range))
{
HookParam hp; HookParam hp;
hp.address = addr + 1; hp.address = addr + 1;
hp.offset = get_reg(regs::rcx); hp.offset = get_reg(regs::rcx);
@ -40,15 +41,16 @@ bool Insertkrkrz64Hook()
0x41, 0x0F, 0xB7, 0x44, 0x24, 0x06, 0x41, 0x0F, 0xB7, 0x44, 0x24, 0x06,
0x89, 0x43, 0x24, 0x89, 0x43, 0x24,
0x41, 0x0F, 0xBF, 0x44, 0x24, 0x0C, 0x41, 0x0F, 0xBF, 0x44, 0x24, 0x0C,
0x89,0x43,0x14 0x89, 0x43, 0x14};
};
auto addrs = Util::SearchMemory(BYTES, sizeof(BYTES), PAGE_EXECUTE_READ, processStartAddress, processStopAddress); auto addrs = Util::SearchMemory(BYTES, sizeof(BYTES), PAGE_EXECUTE_READ, processStartAddress, processStopAddress);
ConsoleOutput("%p %p", processStartAddress, processStopAddress); ConsoleOutput("%p %p", processStartAddress, processStopAddress);
for (auto addr : addrs) { for (auto addr : addrs)
{
ConsoleOutput("krkrz64 %p", addr); ConsoleOutput("krkrz64 %p", addr);
const BYTE funcstart[] = {0xcc, 0xcc, 0xcc, 0xcc}; const BYTE funcstart[] = {0xcc, 0xcc, 0xcc, 0xcc};
addr = reverseFindBytes(funcstart, sizeof(funcstart), addr - 0x1000, addr); addr = reverseFindBytes(funcstart, sizeof(funcstart), addr - 0x1000, addr);
if (addr == 0)continue; if (addr == 0)
continue;
addr += 4; addr += 4;
HookParam hp; HookParam hp;
hp.address = addr; hp.address = addr;
@ -62,7 +64,7 @@ bool Insertkrkrz64Hook()
ConsoleOutput("krkrz64 failed"); ConsoleOutput("krkrz64 failed");
return false; return false;
} }
bool KiriKiri::attach_function() { bool KiriKiri::attach_function()
{
return Insertkrkrz64Hook() || InsertKiriKiriZHook(); return Insertkrkrz64Hook() || InsertKiriKiriZHook();
} }

View File

@ -1,15 +1,17 @@
class KiriKiri:public ENGINE{ class KiriKiri : public ENGINE
{
public: public:
KiriKiri(){ KiriKiri()
{
check_by = CHECK_BY::CUSTOM; check_by = CHECK_BY::CUSTOM;
is_engine_certain = false; is_engine_certain = false;
check_by_target=[](){ check_by_target = []()
{
return Util::CheckFile(L"*.xp3") || Util::SearchResourceString(L"TVP(KIRIKIRI)"); return Util::CheckFile(L"*.xp3") || Util::SearchResourceString(L"TVP(KIRIKIRI)");
}; };
}; };
bool attach_function(); bool attach_function();
}; };

View File

@ -1,8 +1,10 @@
class LightVN:public ENGINE{ class LightVN : public ENGINE
{
public: public:
LightVN(){ LightVN()
{
check_by = CHECK_BY::FILE_ANY; check_by = CHECK_BY::FILE_ANY;
is_engine_certain = false; is_engine_certain = false;
@ -10,4 +12,3 @@ class LightVN:public ENGINE{
}; };
bool attach_function(); bool attach_function();
}; };

View File

@ -1,8 +1,10 @@
class PPSSPPengine:public ENGINE{ class PPSSPPengine : public ENGINE
{
public: public:
PPSSPPengine(){ PPSSPPengine()
{
check_by = CHECK_BY::FILE; check_by = CHECK_BY::FILE;
is_engine_certain = false; is_engine_certain = false;

View File

@ -44,6 +44,8 @@ namespace
} }
bool Ryujinx::attach_function() bool Ryujinx::attach_function()
{ {
WarningOutput("not support ryuujinx, please use yuzu/sudachi instead.");
return true;
auto invokeCompileMethodHelper = processStartAddress + 0x84CC0; auto invokeCompileMethodHelper = processStartAddress + 0x84CC0;
getMethodNameFromMetadata = (decltype(getMethodNameFromMetadata))(processStartAddress + 0x7AED0); getMethodNameFromMetadata = (decltype(getMethodNameFromMetadata))(processStartAddress + 0x7AED0);
HookParam hp; HookParam hp;

View File

@ -1,18 +1,21 @@
#include "Suika2.h" #include "Suika2.h"
bool Suika2_msvcrt() { bool Suika2_msvcrt()
{
auto msvcrt = GetModuleHandle(L"msvcrt.dll"); auto msvcrt = GetModuleHandle(L"msvcrt.dll");
if(msvcrt==0)return 0; if (msvcrt == 0)
return 0;
auto _strdup = GetProcAddress(msvcrt, "_strdup"); auto _strdup = GetProcAddress(msvcrt, "_strdup");
if(_strdup==0)return 0; if (_strdup == 0)
return 0;
HookParam hp; HookParam hp;
hp.address = (uintptr_t)_strdup; hp.address = (uintptr_t)_strdup;
hp.type = USING_STRING | CODEC_UTF8; hp.type = USING_STRING | CODEC_UTF8;
hp.offset = get_reg(regs::rcx); hp.offset = get_reg(regs::rcx);
return NewHook(hp, "Suika2_msvcrt"); return NewHook(hp, "Suika2_msvcrt");
} }
bool Suika2::attach_function() { bool Suika2::attach_function()
{
auto _1 = Suika2_msvcrt(); auto _1 = Suika2_msvcrt();
return _1; return _1;
} }

View File

@ -1,8 +1,10 @@
class Suika2:public ENGINE{ class Suika2 : public ENGINE
{
public: public:
Suika2(){ Suika2()
{
is_engine_certain = false; is_engine_certain = false;
check_by = CHECK_BY::FILE_ANY; check_by = CHECK_BY::FILE_ANY;
check_by_target = check_by_list{L"suika.exe", L"conf/config.txt"}; check_by_target = check_by_list{L"suika.exe", L"conf/config.txt"};

View File

@ -1,17 +1,21 @@
#include "TYPEMOON.h" #include "TYPEMOON.h"
namespace{ namespace
bool _h() { {
bool _h()
{
// TYPE-MOON 魔法使いの夜 多国語版 中文-英文-日文 // TYPE-MOON 魔法使いの夜 多国語版 中文-英文-日文
BYTE bytes[] = { BYTE bytes[] = {
0xBA, 0x08, 0xFF, 0x00, 0x00, 0xBA, 0x08, 0xFF, 0x00, 0x00,
0x41, 0xB8, 0x1C, 0x20, 0x00, 0x00, 0x41, 0xB8, 0x1C, 0x20, 0x00, 0x00,
0x66,0x90 0x66, 0x90};
};
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress); auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
ConsoleOutput("%p", addr); ConsoleOutput("%p", addr);
if(addr==0)return false; if (addr == 0)
addr=MemDbg::findEnclosingAlignedFunction(addr);ConsoleOutput("%p",addr); return false;
if(addr==0)return false; addr = MemDbg::findEnclosingAlignedFunction(addr);
ConsoleOutput("%p", addr);
if (addr == 0)
return false;
HookParam hp; HookParam hp;
hp.address = addr; hp.address = addr;
hp.type = CODEC_UTF16 | USING_STRING | EMBED_ABLE | EMBED_AFTER_NEW | EMBED_BEFORE_SIMPLE; hp.type = CODEC_UTF16 | USING_STRING | EMBED_ABLE | EMBED_AFTER_NEW | EMBED_BEFORE_SIMPLE;
@ -19,7 +23,7 @@ bool _h() {
return NewHook(hp, "typemoon"); return NewHook(hp, "typemoon");
} }
} }
bool TYPEMOON::attach_function() { bool TYPEMOON::attach_function()
{
return _h(); return _h();
} }

View File

@ -1,8 +1,10 @@
class TYPEMOON:public ENGINE{ class TYPEMOON : public ENGINE
{
public: public:
TYPEMOON(){ TYPEMOON()
{
check_by = CHECK_BY::FILE; check_by = CHECK_BY::FILE;
is_engine_certain = false; is_engine_certain = false;
@ -10,4 +12,3 @@ class TYPEMOON:public ENGINE{
}; };
bool attach_function(); bool attach_function();
}; };

View File

@ -208,8 +208,8 @@ namespace{
} }
#endif #endif
bool V8::attach_function_() { bool V8::attach_function_()
{
return tryhookv8(); return tryhookv8();
} }

View File

@ -1,12 +1,14 @@
class V8:public ENGINE{ class V8 : public ENGINE
{
public: public:
V8(){ V8()
{
check_by = CHECK_BY::CUSTOM; check_by = CHECK_BY::CUSTOM;
check_by_target=[this](){return attach_function_();}; check_by_target = [this]()
{ return attach_function_(); };
}; };
bool attach_function_(); bool attach_function_();
bool attach_function() { return true; } bool attach_function() { return true; }
}; };

View File

@ -3,12 +3,13 @@ bool YOX::attach_function()
{ {
const BYTE BYTES[] = { const BYTE BYTES[] = {
0x48, 0x8B, 0x0F, 0x48, 0x8B, 0x0F,
0x48,0x8d,0x54,0x24,0x50 0x48, 0x8d, 0x54, 0x24, 0x50};
};
auto addrs = Util::SearchMemory(BYTES, sizeof(BYTES), PAGE_EXECUTE_READ, processStartAddress, processStopAddress); auto addrs = Util::SearchMemory(BYTES, sizeof(BYTES), PAGE_EXECUTE_READ, processStartAddress, processStopAddress);
ConsoleOutput("%p %p", processStartAddress, processStopAddress); ConsoleOutput("%p %p", processStartAddress, processStopAddress);
for (auto addr : addrs) { for (auto addr : addrs)
if (addr == 0)continue; {
if (addr == 0)
continue;
HookParam hp; HookParam hp;
hp.address = addr; hp.address = addr;
hp.type = USING_STRING; hp.type = USING_STRING;

View File

@ -1,8 +1,10 @@
class YOX:public ENGINE{ class YOX : public ENGINE
{
public: public:
YOX(){ YOX()
{
check_by = CHECK_BY::FILE; check_by = CHECK_BY::FILE;
is_engine_certain = false; is_engine_certain = false;
@ -10,4 +12,3 @@ class YOX:public ENGINE{
}; };
bool attach_function(); bool attach_function();
}; };

View File

@ -1,6 +1,5 @@
#include "livecaptions.h" #include "livecaptions.h"
bool livecaptions::attach_function() bool livecaptions::attach_function()
{ {
@ -14,16 +13,18 @@ bool livecaptions::attach_function()
// .text:0000000180001CAE retn // .text:0000000180001CAE retn
HookParam hp; HookParam hp;
hp.address = (uintptr_t)GetProcAddress(GetModuleHandle(L"vcruntime140_app.dll"), "memmove"); hp.address = (uintptr_t)GetProcAddress(GetModuleHandle(L"vcruntime140_app.dll"), "memmove");
hp.text_fun=[](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len){ hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
BYTE sig[] = { BYTE sig[] = {
0x40, 0x53, 0x48, 0x83, 0xEC, 0x20, 0x48, 0x8B, 0xD9, 0x40, 0x53, 0x48, 0x83, 0xEC, 0x20, 0x48, 0x8B, 0xD9,
0xE8,XX4 0xE8, XX4};
};
auto a1 = stack->retaddr - sizeof(sig); auto a1 = stack->retaddr - sizeof(sig);
if ((stack->retaddr > (uintptr_t)GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll"))) if ((stack->retaddr > (uintptr_t)GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll")))
if(memcmp((void*)a1,&sig,sizeof(sig)-4)==0){ if (memcmp((void *)a1, &sig, sizeof(sig) - 4) == 0)
{
static std::set<uintptr_t> once; static std::set<uintptr_t> once;
if(once.find(stack->retaddr)!=once.end())return; if (once.find(stack->retaddr) != once.end())
return;
once.insert(stack->retaddr); once.insert(stack->retaddr);
// hp->text_fun=nullptr; // hp->text_fun=nullptr;
// hp->type=HOOK_EMPTY; // hp->type=HOOK_EMPTY;

View File

@ -1,8 +1,10 @@
class lucasystem:public ENGINE{ class lucasystem : public ENGINE
{
public: public:
lucasystem(){ lucasystem()
{
check_by = CHECK_BY::FILE; check_by = CHECK_BY::FILE;
is_engine_certain = false; is_engine_certain = false;
@ -10,4 +12,3 @@ class lucasystem:public ENGINE{
}; };
bool attach_function(); bool attach_function();
}; };

View File

@ -1,11 +1,14 @@
#include "mono.h" #include "mono.h"
#include "mono/monocommon.hpp" #include "mono/monocommon.hpp"
namespace{ namespace
bool monobdwgc() { {
bool monobdwgc()
{
HMODULE module = GetModuleHandleW(L"mono-2.0-bdwgc.dll"); HMODULE module = GetModuleHandleW(L"mono-2.0-bdwgc.dll");
if (module == 0)return false; if (module == 0)
return false;
auto [minAddress, maxAddress] = Util::QueryModuleLimits(module); auto [minAddress, maxAddress] = Util::QueryModuleLimits(module);
BYTE bytes[] = { BYTE bytes[] = {
0x81, 0xF9, 0x80, 0x00, 0x00, 0x00, 0x81, 0xF9, 0x80, 0x00, 0x00, 0x00,
@ -39,26 +42,30 @@ _BYTE *__fastcall sub_18005B290(
}; };
auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, minAddress, maxAddress); auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, minAddress, maxAddress);
auto suc = false; auto suc = false;
for (auto addr : addrs) { for (auto addr : addrs)
{
const BYTE align[] = {0xCC, 0xCC, 0xCC, 0xCC}; const BYTE align[] = {0xCC, 0xCC, 0xCC, 0xCC};
addr = reverseFindBytes(align, sizeof(align), addr - 0x100, addr); addr = reverseFindBytes(align, sizeof(align), addr - 0x100, addr);
if(addr==0)continue; if (addr == 0)
continue;
ConsoleOutput("monobdwgcdll %p", addr); ConsoleOutput("monobdwgcdll %p", addr);
HookParam hp; HookParam hp;
hp.address = addr + 4; hp.address = addr + 4;
hp.offset = get_reg(regs::rcx); hp.offset = get_reg(regs::rcx);
hp.type = CODEC_UTF16 | USING_STRING; hp.type = CODEC_UTF16 | USING_STRING;
hp.text_fun=[](auto, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ hp.text_fun = [](auto, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
std::wstring str = std::wstring((LPWSTR)*data); std::wstring str = std::wstring((LPWSTR)*data);
*split = str.find(L"OnShowComplete") != str.npos; *split = str.find(L"OnShowComplete") != str.npos;
*len = wcslen((wchar_t *)*data) * 2; *len = wcslen((wchar_t *)*data) * 2;
}; };
hp.filter_fun=[](void* data, size_t* len, HookParam* hp){ hp.filter_fun = [](void *data, size_t *len, HookParam *hp)
{
std::wstring str = std::wstring((LPWSTR)data, *len / 2); std::wstring str = std::wstring((LPWSTR)data, *len / 2);
if(str.find(L"OnShowComplete")!=str.npos){ if (str.find(L"OnShowComplete") != str.npos)
{
str = std::regex_replace(str, std::wregex(L"\n"), L""); str = std::regex_replace(str, std::wregex(L"\n"), L"");
std::wregex reg1(L"\\((.*?)\\)"); std::wregex reg1(L"\\((.*?)\\)");
std::wsmatch match; std::wsmatch match;
@ -76,7 +83,8 @@ _BYTE *__fastcall sub_18005B290(
return suc; return suc;
} }
} }
bool mono::attach_function(){ bool mono::attach_function()
{
bool common = monocommon::hook_mono_il2cpp(); bool common = monocommon::hook_mono_il2cpp();
return common; return common;
} }

View File

@ -1,8 +1,10 @@
class mono:public ENGINE{ class mono : public ENGINE
{
public: public:
mono(){ mono()
{
check_by = CHECK_BY::ALL_TRUE; check_by = CHECK_BY::ALL_TRUE;
}; };

View File

@ -1,10 +1,14 @@
#include "pchooks.h" #include "pchooks.h"
bool pchooks::attach_function() { bool pchooks::attach_function()
{
for (std::wstring DXVersion : {L"d3dx9", L"d3dx10"}) for (std::wstring DXVersion : {L"d3dx9", L"d3dx10"})
if (HMODULE module = GetModuleHandleW(DXVersion.c_str())) PcHooks::hookD3DXFunctions(module); if (HMODULE module = GetModuleHandleW(DXVersion.c_str()))
else for (int i = 0; i < 50; ++i) PcHooks::hookD3DXFunctions(module);
if (HMODULE module = GetModuleHandleW((DXVersion + L"_" + std::to_wstring(i)).c_str())) PcHooks::hookD3DXFunctions(module); else
for (int i = 0; i < 50; ++i)
if (HMODULE module = GetModuleHandleW((DXVersion + L"_" + std::to_wstring(i)).c_str()))
PcHooks::hookD3DXFunctions(module);
PcHooks::hookGDIFunctions(); PcHooks::hookGDIFunctions();
PcHooks::hookGDIPlusFunctions(); PcHooks::hookGDIPlusFunctions();

View File

@ -1,8 +1,10 @@
class pchooks:public ENGINE{ class pchooks : public ENGINE
{
public: public:
pchooks(){ pchooks()
{
check_by = CHECK_BY::ALL_TRUE; check_by = CHECK_BY::ALL_TRUE;
dontstop = true; dontstop = true;

View File

@ -1,5 +1,6 @@
#include"rpcs3.h" #include "rpcs3.h"
namespace{ namespace
{
#if 0 // only support0.0.20-0.0.27 #if 0 // only support0.0.20-0.0.27
int emoffset; int emoffset;
int jitoffset; int jitoffset;
@ -115,7 +116,8 @@ namespace{
} }
#endif #endif
uintptr_t getDoJitAddress() { uintptr_t getDoJitAddress()
{
// rpcs3/Emu/Cell/PPUThread.cpp // rpcs3/Emu/Cell/PPUThread.cpp
/* /*
extern void ppu_register_function_at(u32 addr, u32 size, ppu_intrp_func_t ptr = nullptr) extern void ppu_register_function_at(u32 addr, u32 size, ppu_intrp_func_t ptr = nullptr)
@ -141,40 +143,49 @@ namespace{
char log[] = "ppu_register_function_at(0x%x): empty range"; char log[] = "ppu_register_function_at(0x%x): empty range";
auto logstrptr = MemDbg::findBytes(log, sizeof(log), processStartAddress, processStopAddress); auto logstrptr = MemDbg::findBytes(log, sizeof(log), processStartAddress, processStopAddress);
ConsoleOutput("%p", logstrptr); ConsoleOutput("%p", logstrptr);
if(logstrptr==0)return 0; if (logstrptr == 0)
return 0;
auto addr = MemDbg::findleaaddr(logstrptr, processStartAddress, processStopAddress); auto addr = MemDbg::findleaaddr(logstrptr, processStartAddress, processStopAddress);
ConsoleOutput("%p", addr); ConsoleOutput("%p", addr);
if(addr==0)return 0; if (addr == 0)
return 0;
// ff cc cc cc,find不到。。 // ff cc cc cc,find不到。。
BYTE start[] = {XX, 0xCC, 0xCC, 0xCC}; BYTE start[] = {XX, 0xCC, 0xCC, 0xCC};
addr = reverseFindBytes(start, sizeof(start), addr - 0x200, addr, 4, true); addr = reverseFindBytes(start, sizeof(start), addr - 0x200, addr, 4, true);
ConsoleOutput("%p", addr); ConsoleOutput("%p", addr);
return addr; return addr;
} }
struct emfuncinfo{ struct emfuncinfo
{
uint64_t type; uint64_t type;
int argidx;int padding; int argidx;
int padding;
void *hookfunc; void *hookfunc;
void *filterfun; void *filterfun;
const char *_id; const char *_id;
}; };
std::unordered_map<uintptr_t, emfuncinfo> emfunctionhooks; std::unordered_map<uintptr_t, emfuncinfo> emfunctionhooks;
bool checkiscurrentgame(const emfuncinfo& em){ bool checkiscurrentgame(const emfuncinfo &em)
{
auto wininfos = get_proc_windows(); auto wininfos = get_proc_windows();
for(auto&& info:wininfos){ for (auto &&info : wininfos)
if(info.title.find(acastw(em._id))!=info.title.npos)return true; {
if (info.title.find(acastw(em._id)) != info.title.npos)
return true;
} }
return false; return false;
} }
static std::set<std::pair<uintptr_t, uintptr_t>> timeoutbreaks; static std::set<std::pair<uintptr_t, uintptr_t>> timeoutbreaks;
void dohookemaddr(uintptr_t em_address,uintptr_t ret){ void dohookemaddr(uintptr_t em_address, uintptr_t ret)
{
jitaddraddr(em_address, ret, JITTYPE::RPCS3); jitaddraddr(em_address, ret, JITTYPE::RPCS3);
if(emfunctionhooks.find(em_address)==emfunctionhooks.end())return; if (emfunctionhooks.find(em_address) == emfunctionhooks.end())
if(!(checkiscurrentgame(emfunctionhooks.at(em_address))))return; return;
if (!(checkiscurrentgame(emfunctionhooks.at(em_address))))
return;
timeoutbreaks.insert(std::make_pair(em_address, ret)); timeoutbreaks.insert(std::make_pair(em_address, ret));
auto op = emfunctionhooks.at(em_address); auto op = emfunctionhooks.at(em_address);
HookParam hpinternal; HookParam hpinternal;
@ -189,7 +200,8 @@ void dohookemaddr(uintptr_t em_address,uintptr_t ret){
NewHook(hpinternal, op._id); NewHook(hpinternal, op._id);
} }
bool unsafeinithooks(){ bool unsafeinithooks()
{
// rpcs0.0.30不知道为什么ppu_register_function_at不全。不过看代码得到映射表了直接弄吧。 // rpcs0.0.30不知道为什么ppu_register_function_at不全。不过看代码得到映射表了直接弄吧。
// rpcs3/Emu/Cell/PPUThread.cpp // rpcs3/Emu/Cell/PPUThread.cpp
// Get pointer to executable cache // Get pointer to executable cache
@ -204,48 +216,54 @@ bool unsafeinithooks(){
hp.address = 0x500000000; hp.address = 0x500000000;
hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{ {
for(auto [addr,info]:emfunctionhooks){ for (auto [addr, info] : emfunctionhooks)
{
auto table = addr * 2 + 0x500000000; auto table = addr * 2 + 0x500000000;
if(IsBadReadPtr((void*)table,sizeof(uintptr_t)))continue; if (IsBadReadPtr((void *)table, sizeof(uintptr_t)))
continue;
auto funcaddr = *(uintptr_t *)table; auto funcaddr = *(uintptr_t *)table;
funcaddr &= 0x0000ffffffffffff; funcaddr &= 0x0000ffffffffffff;
if(!funcaddr)continue; if (!funcaddr)
continue;
auto p = std::make_pair(addr, funcaddr); auto p = std::make_pair(addr, funcaddr);
if(timeoutbreaks.find(p)!=timeoutbreaks.end())continue; if (timeoutbreaks.find(p) != timeoutbreaks.end())
continue;
dohookemaddr(addr, funcaddr); dohookemaddr(addr, funcaddr);
delayinsertNewHook(addr); delayinsertNewHook(addr);
} }
}; };
return NewHook(hp, "g_exec_addr"); return NewHook(hp, "g_exec_addr");
} }
} }
bool rpcs3::attach_function() bool rpcs3::attach_function()
{ {
ConsoleOutput("[Compatibility] RPCS3"); ConsoleOutput("[Compatibility] RPCS3");
auto DoJitPtr = getDoJitAddress(); auto DoJitPtr = getDoJitAddress();
if(DoJitPtr==0)return false; if (DoJitPtr == 0)
return false;
unsafeinithooks(); unsafeinithooks();
spDefault.jittype = JITTYPE::RPCS3; spDefault.jittype = JITTYPE::RPCS3;
spDefault.minAddress = 0; spDefault.minAddress = 0;
spDefault.maxAddress = -1; spDefault.maxAddress = -1;
HookParam hp; HookParam hp;
hp.address = DoJitPtr; hp.address = DoJitPtr;
hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
auto em_address = stack->rcx; // *(uint32_t*)*(uintptr_t*)(stack->base+emoffset); auto em_address = stack->rcx; // *(uint32_t*)*(uintptr_t*)(stack->base+emoffset);
auto entrypoint = stack->r8; //*(uintptr_t*)*(uintptr_t*)(stack->base+jitoffset)-0x0008000000000000; auto entrypoint = stack->r8; //*(uintptr_t*)*(uintptr_t*)(stack->base+jitoffset)-0x0008000000000000;
if(!em_address||!entrypoint)return; if (!em_address || !entrypoint)
return;
dohookemaddr(em_address, entrypoint); dohookemaddr(em_address, entrypoint);
delayinsertNewHook(em_address); delayinsertNewHook(em_address);
}; };
return NewHook(hp, "vita3kjit"); return NewHook(hp, "vita3kjit");
} }
namespace
{
namespace{ bool FBLJM61131(void *data, size_t *len, HookParam *hp)
{
bool FBLJM61131(void* data, size_t* len, HookParam* hp){
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
std::regex pattern("\\[[^\\]]+."); std::regex pattern("\\[[^\\]]+.");
s = std::regex_replace(s, pattern, ""); s = std::regex_replace(s, pattern, "");
@ -254,7 +272,8 @@ bool FBLJM61131(void* data, size_t* len, HookParam* hp){
s = std::regex_replace(s, std::regex("\\n+"), " "); s = std::regex_replace(s, std::regex("\\n+"), " ");
return write_string_overwrite(data, len, s); return write_string_overwrite(data, len, s);
} }
auto _=[](){ auto _ = []()
{
emfunctionhooks = { emfunctionhooks = {
//'&' -Sora no Mukou de Sakimasu you ni- //'&' -Sora no Mukou de Sakimasu you ni-
{0x46328, {CODEC_UTF8, 1, 0, 0, FBLJM61131, "BLJM61131"}}, {0x46328, {CODEC_UTF8, 1, 0, 0, FBLJM61131, "BLJM61131"}},

View File

@ -1,8 +1,10 @@
class rpcs3:public ENGINE{ class rpcs3 : public ENGINE
{
public: public:
rpcs3(){ rpcs3()
{
check_by = CHECK_BY::FILE; check_by = CHECK_BY::FILE;
is_engine_certain = false; is_engine_certain = false;
@ -10,4 +12,3 @@ class rpcs3:public ENGINE{
}; };
bool attach_function(); bool attach_function();
}; };

View File

@ -1,12 +1,15 @@
#include"vita3k.h" #include "vita3k.h"
namespace{ namespace
{
auto isVirtual = true; auto isVirtual = true;
auto idxDescriptor = isVirtual == true ? 2 : 1; auto idxDescriptor = isVirtual == true ? 2 : 1;
auto idxEntrypoint = idxDescriptor + 1; auto idxEntrypoint = idxDescriptor + 1;
uintptr_t getDoJitAddress() { uintptr_t getDoJitAddress()
{
auto RegisterBlockSig1 = "40 55 53 56 57 41 54 41 56 41 57 48 8D 6C 24 E9 48 81 EC 90 00 00 00 48 8B ?? ?? ?? ?? ?? 48 33 C4 48 89 45 07 4D 8B F1 49 8B F0 48 8B FA 48 8B D9 4C 8B 7D 77 48 8B 01 48 8D 55 C7 FF 50 10"; auto RegisterBlockSig1 = "40 55 53 56 57 41 54 41 56 41 57 48 8D 6C 24 E9 48 81 EC 90 00 00 00 48 8B ?? ?? ?? ?? ?? 48 33 C4 48 89 45 07 4D 8B F1 49 8B F0 48 8B FA 48 8B D9 4C 8B 7D 77 48 8B 01 48 8D 55 C7 FF 50 10";
auto first = find_pattern(RegisterBlockSig1, processStartAddress, processStopAddress); auto first = find_pattern(RegisterBlockSig1, processStartAddress, processStopAddress);
if (first) return first; if (first)
return first;
/* /*
// DebugSymbol: RegisterBlock // DebugSymbol: RegisterBlock
// ?RegisterBlock@EmitX64@X64@Backend@Dynarmic@@IEAA?AUBlockDescriptor@1234@AEBVLocationDescriptor@IR@4@PEBX_K@Z <- new // ?RegisterBlock@EmitX64@X64@Backend@Dynarmic@@IEAA?AUBlockDescriptor@1234@AEBVLocationDescriptor@IR@4@PEBX_K@Z <- new
@ -21,26 +24,32 @@ namespace{
*/ */
auto PatchBlockSig1 = "4C 8B DC 49 89 5B 10 49 89 6B 18 56 57 41 54 41 56 41 57"; // "4C 8B DC 49 89 5B ?? 49 89 6B ?? 56 57 41 54 41 56 41 57"; auto PatchBlockSig1 = "4C 8B DC 49 89 5B 10 49 89 6B 18 56 57 41 54 41 56 41 57"; // "4C 8B DC 49 89 5B ?? 49 89 6B ?? 56 57 41 54 41 56 41 57";
first = find_pattern(PatchBlockSig1, processStartAddress, processStopAddress); first = find_pattern(PatchBlockSig1, processStartAddress, processStopAddress);
if (first) { if (first)
{
idxDescriptor = 1; idxDescriptor = 1;
idxEntrypoint = 2; idxEntrypoint = 2;
return first; return first;
} }
return 0; return 0;
} }
struct emfuncinfo{ struct emfuncinfo
{
uint64_t type; uint64_t type;
int argidx;int padding; int argidx;
int padding;
void *hookfunc; void *hookfunc;
void *filterfun; void *filterfun;
const char *_id; const char *_id;
}; };
std::unordered_map<uintptr_t, emfuncinfo> emfunctionhooks; std::unordered_map<uintptr_t, emfuncinfo> emfunctionhooks;
bool checkiscurrentgame(const emfuncinfo& em){ bool checkiscurrentgame(const emfuncinfo &em)
{
auto wininfos = get_proc_windows(); auto wininfos = get_proc_windows();
for(auto&& info:wininfos){ for (auto &&info : wininfos)
if(info.title.find(acastw(em._id))!=info.title.npos)return true; {
if (info.title.find(acastw(em._id)) != info.title.npos)
return true;
} }
return false; return false;
} }
@ -50,24 +59,30 @@ bool vita3k::attach_function()
{ {
ConsoleOutput("[Compatibility] Vita3k 0.1.9 3520+"); ConsoleOutput("[Compatibility] Vita3k 0.1.9 3520+");
auto DoJitPtr = getDoJitAddress(); auto DoJitPtr = getDoJitAddress();
if(DoJitPtr==0)return false; if (DoJitPtr == 0)
return false;
ConsoleOutput("DoJitPtr %p", DoJitPtr); ConsoleOutput("DoJitPtr %p", DoJitPtr);
spDefault.jittype = JITTYPE::VITA3K; spDefault.jittype = JITTYPE::VITA3K;
spDefault.minAddress = 0; spDefault.minAddress = 0;
spDefault.maxAddress = -1; spDefault.maxAddress = -1;
HookParam hp; HookParam hp;
hp.address = DoJitPtr; hp.address = DoJitPtr;
hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
auto descriptor = *argidx(stack, idxDescriptor + 1); // r8 auto descriptor = *argidx(stack, idxDescriptor + 1); // r8
auto entrypoint = *argidx(stack, idxEntrypoint + 1); // r9 auto entrypoint = *argidx(stack, idxEntrypoint + 1); // r9
auto em_address = *(uint32_t *)descriptor; auto em_address = *(uint32_t *)descriptor;
if(!entrypoint)return; if (!entrypoint)
return;
// ConsoleOutput("%p",em_address); // ConsoleOutput("%p",em_address);
jitaddraddr(em_address, entrypoint, JITTYPE::VITA3K); jitaddraddr(em_address, entrypoint, JITTYPE::VITA3K);
[&](){ [&]()
if(emfunctionhooks.find(em_address)==emfunctionhooks.end())return; {
if (emfunctionhooks.find(em_address) == emfunctionhooks.end())
return;
auto op = emfunctionhooks.at(em_address); auto op = emfunctionhooks.at(em_address);
if(!(checkiscurrentgame(op)))return; if (!(checkiscurrentgame(op)))
return;
HookParam hpinternal; HookParam hpinternal;
hpinternal.address = entrypoint; hpinternal.address = entrypoint;
@ -85,9 +100,10 @@ bool vita3k::attach_function()
return NewHook(hp, "vita3kjit"); return NewHook(hp, "vita3kjit");
} }
namespace
namespace{ {
bool FPCSG01023(void* data, size_t* len, HookParam* hp){ bool FPCSG01023(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("<br>"), ""); s = std::regex_replace(s, std::regex("<br>"), "");
s = std::regex_replace(s, std::regex("%CF11F"), ""); s = std::regex_replace(s, std::regex("%CF11F"), "");
@ -98,35 +114,45 @@ bool FPCSG01023(void* data, size_t* len, HookParam* hp){
return write_string_overwrite(data, len, s); return write_string_overwrite(data, len, s);
} }
template <int idx> template <int idx>
bool FPCSG01282(void* data, size_t* len, HookParam* hp){ bool FPCSG01282(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("(\\n)+"), " "); s = std::regex_replace(s, std::regex("(\\n)+"), " ");
s = std::regex_replace(s, std::regex("\\d$|^@[a-z]+|#.*?#|\\$"), ""); s = std::regex_replace(s, std::regex("\\d$|^@[a-z]+|#.*?#|\\$"), "");
static std::string last; static std::string last;
if(last==s)return false; if (last == s)
return false;
last = s; last = s;
return write_string_overwrite(data, len, s); return write_string_overwrite(data, len, s);
} }
template <int index> template <int index>
void ReadU16TextAndLenDW(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ void ReadU16TextAndLenDW(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
auto address = VITA3K::emu_arg(stack)[index]; auto address = VITA3K::emu_arg(stack)[index];
*len = (*(DWORD *)(address + 0x8)) * 2; *len = (*(DWORD *)(address + 0x8)) * 2;
*data = address + 0xC; *data = address + 0xC;
} }
bool FPCSG00410(void* data, size_t* len, HookParam* hp){ bool FPCSG00410(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), ""); s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), "");
s = std::regex_replace(s, std::regex("#n"), " "); s = std::regex_replace(s, std::regex("#n"), " ");
// .replaceAll("④", "!?").replaceAll("②", "!!").replaceAll("⑥", "。").replaceAll("⑪", "【") // .replaceAll("④", "!?").replaceAll("②", "!!").replaceAll("⑥", "。").replaceAll("⑪", "【")
// .replaceAll("⑫", "】").replaceAll("⑤", "、").replaceAll("①", "・・・") // .replaceAll("⑫", "】").replaceAll("⑤", "、").replaceAll("①", "・・・")
strReplace(s,"\x87\x43","!?");strReplace(s,"\x87\x41","!!");strReplace(s,"\x87\x45","\x81\x42");strReplace(s,"\x87\x4a","\x81\x79"); strReplace(s, "\x87\x43", "!?");
strReplace(s,"\x87\x4b","\x81\x7a");strReplace(s,"\x87\x44","\x81\x41");strReplace(s,"\x87\x40","\x81\x45\x81\x45\x81\x45"); strReplace(s, "\x87\x41", "!!");
strReplace(s, "\x87\x45", "\x81\x42");
strReplace(s, "\x87\x4a", "\x81\x79");
strReplace(s, "\x87\x4b", "\x81\x7a");
strReplace(s, "\x87\x44", "\x81\x41");
strReplace(s, "\x87\x40", "\x81\x45\x81\x45\x81\x45");
return write_string_overwrite(data, len, s); return write_string_overwrite(data, len, s);
} }
bool FPCSG00448(void* data, size_t* len, HookParam* hp){ bool FPCSG00448(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("[\\s]"), ""); s = std::regex_replace(s, std::regex("[\\s]"), "");
s = std::regex_replace(s, std::regex("(#n)+"), ""); s = std::regex_replace(s, std::regex("(#n)+"), "");
@ -134,35 +160,48 @@ bool FPCSG00448(void* data, size_t* len, HookParam* hp){
s = std::regex_replace(s, std::regex("#Pos[\\s\\S]*?\\]"), ""); s = std::regex_replace(s, std::regex("#Pos[\\s\\S]*?\\]"), "");
return write_string_overwrite(data, len, s); return write_string_overwrite(data, len, s);
} }
bool FPCSG01008(void* data, size_t* len, HookParam* hp){ bool FPCSG01008(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("#Ruby\\[([^,]+)\\.([^\\]]+)\\]."), "$1"); s = std::regex_replace(s, std::regex("#Ruby\\[([^,]+)\\.([^\\]]+)\\]."), "$1");
s = std::regex_replace(s, std::regex("(#n)+"), " "); s = std::regex_replace(s, std::regex("(#n)+"), " ");
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), ""); s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
return write_string_overwrite(data, len, s); return write_string_overwrite(data, len, s);
} }
void TPCSG00903(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ void TPCSG00903(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
auto address = VITA3K::emu_arg(stack)[0]; auto address = VITA3K::emu_arg(stack)[0];
*len = (*(DWORD *)(address + 0x14)); *len = (*(DWORD *)(address + 0x14));
*data = address + 0x1C; *data = address + 0x1C;
} }
bool FPCSG00903(void* data, size_t* len, HookParam* hp){ bool FPCSG00903(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("\\\\n"), " "); s = std::regex_replace(s, std::regex("\\\\n"), " ");
return write_string_overwrite(data, len, s); return write_string_overwrite(data, len, s);
} }
bool FPCSG00839(void* data, size_t* len, HookParam* hp){ bool FPCSG01180(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex(R"(\\n)"), " ");
s = std::regex_replace(s, std::regex(R"(,.*$)"), " ");
return write_string_overwrite(data, len, s);
}
bool FPCSG00839(void *data, size_t *len, HookParam *hp)
{
auto s = std::wstring((wchar_t *)data, *len / 2); auto s = std::wstring((wchar_t *)data, *len / 2);
s = std::regex_replace(s, std::wregex(L"\\[[^\\]]+."), L""); s = std::regex_replace(s, std::wregex(L"\\[[^\\]]+."), L"");
s = std::regex_replace(s, std::wregex(L"\\\\k|\\\\x|%C|%B|%p-1;"), L""); s = std::regex_replace(s, std::wregex(L"\\\\k|\\\\x|%C|%B|%p-1;"), L"");
s = std::regex_replace(s, std::wregex(L"#[0-9a-fA-F]+;([^%#]+)(%r)?"), L"$1"); s = std::regex_replace(s, std::wregex(L"#[0-9a-fA-F]+;([^%#]+)(%r)?"), L"$1");
s = std::regex_replace(s, std::wregex(L"\\\\n"), L""); s = std::regex_replace(s, std::wregex(L"\\\\n"), L"");
static std::wstring last; static std::wstring last;
if(last.find(s)!=last.npos)return false; if (last.find(s) != last.npos)
return false;
last = s; last = s;
return write_string_overwrite(data, len, s); return write_string_overwrite(data, len, s);
} }
bool FPCSG00751(void* data, size_t* len, HookParam* hp){ bool FPCSG00751(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("[\\s]"), ""); s = std::regex_replace(s, std::regex("[\\s]"), "");
s = std::regex_replace(s, std::regex("@[a-z]"), ""); s = std::regex_replace(s, std::regex("@[a-z]"), "");
@ -170,12 +209,28 @@ bool FPCSG00751(void* data, size_t* len, HookParam* hp){
strReplace(s, "\x81\x90", ""); strReplace(s, "\x81\x90", "");
return write_string_overwrite(data, len, s); return write_string_overwrite(data, len, s);
} }
bool FPCSG00706(void* data, size_t* len, HookParam* hp){ bool FPCSG00401(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex(R"([\s])"), "");
s = std::regex_replace(s, std::regex(R"(\c)"), "");
s = std::regex_replace(s, std::regex(R"(\\n)"), "");
return write_string_overwrite(data, len, s);
}
bool FPCSG00912(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("%N"), "");
return write_string_overwrite(data, len, s);
}
bool FPCSG00706(void *data, size_t *len, HookParam *hp)
{
auto s = std::wstring((wchar_t *)data, *len / 2); auto s = std::wstring((wchar_t *)data, *len / 2);
s = std::regex_replace(s, std::wregex(L"<br>"), L""); s = std::regex_replace(s, std::wregex(L"<br>"), L"");
return write_string_overwrite(data, len, s); return write_string_overwrite(data, len, s);
} }
bool FPCSG00696(void* data, size_t* len, HookParam* hp){ bool FPCSG00696(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
//.replace(/㌔/g, '⁉') //.replace(/㌔/g, '⁉')
//.replace(/㍉/g, '!!') //.replace(/㍉/g, '!!')
@ -183,7 +238,8 @@ bool FPCSG00696(void* data, size_t* len, HookParam* hp){
strReplace(s, "\x87\x5f", ""); strReplace(s, "\x87\x5f", "");
return write_string_overwrite(data, len, s); return write_string_overwrite(data, len, s);
} }
bool FPCSG00389(void* data, size_t* len, HookParam* hp){ bool FPCSG00389(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("[\\s]"), ""); s = std::regex_replace(s, std::regex("[\\s]"), "");
s = std::regex_replace(s, std::regex("(#n)+"), ""); s = std::regex_replace(s, std::regex("(#n)+"), "");
@ -191,7 +247,8 @@ bool FPCSG00389(void* data, size_t* len, HookParam* hp){
s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), ""); s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), "");
return write_string_overwrite(data, len, s); return write_string_overwrite(data, len, s);
} }
bool FPCSG00216(void* data, size_t* len, HookParam* hp){ bool FPCSG00216(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("[\\s]"), ""); s = std::regex_replace(s, std::regex("[\\s]"), "");
s = std::regex_replace(s, std::regex("(#n)+"), ""); s = std::regex_replace(s, std::regex("(#n)+"), "");
@ -199,46 +256,52 @@ bool FPCSG00216(void* data, size_t* len, HookParam* hp){
s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), ""); s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), "");
return write_string_overwrite(data, len, s); return write_string_overwrite(data, len, s);
} }
bool FPCSG00405(void* data, size_t* len, HookParam* hp){ bool FPCSG00405(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("[\\s]"), ""); s = std::regex_replace(s, std::regex("[\\s]"), "");
return write_string_overwrite(data, len, s); return write_string_overwrite(data, len, s);
} }
bool PCSG00776(void* data, size_t* len, HookParam* hp){ bool PCSG00776(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
auto ws = StringToWideString(s, 932).value(); auto ws = StringToWideString(s, 932).value();
strReplace(ws, L"\x02", L""); strReplace(ws, L"\x02", L"");
Trim(ws); Trim(ws);
return write_string_overwrite(data, len, WideStringToString(ws)); return write_string_overwrite(data, len, WideStringToString(ws));
} }
void PCSG00912(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
void PCSG00911(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ {
auto address = VITA3K::emu_arg(stack)[1]; auto address = VITA3K::emu_arg(stack)[1];
std::string final_string = ""; std::string final_string = "";
BYTE pattern[] = {0x47, 0xff, 0xff}; BYTE pattern[] = {0x47, 0xff, 0xff};
auto results = MemDbg::findBytes(pattern, sizeof(pattern), address, address + 0x50); auto results = MemDbg::findBytes(pattern, sizeof(pattern), address, address + 0x50);
if (!results) return; if (!results)
return;
address = results + 5; address = results + 5;
while (true) { while (true)
{
std::string text = (char *)address; std::string text = (char *)address;
final_string += text; final_string += text;
address = address + (text.size() + 1); address = address + (text.size() + 1);
auto bytes = (BYTE *)address; auto bytes = (BYTE *)address;
if (!(bytes[0] == 0x48 && bytes[1] == 0xFF && bytes[2] == 0xFF)) break; if (!(bytes[0] == 0x48 && bytes[1] == 0xFF && bytes[2] == 0xFF))
break;
address = address + (3); address = address + (3);
bytes = (BYTE *)address; bytes = (BYTE *)address;
if (!(bytes[0] == 0x47 && bytes[1] == 0xFF && bytes[2] == 0xFF)) break; if (!(bytes[0] == 0x47 && bytes[1] == 0xFF && bytes[2] == 0xFF))
break;
address = address + (5); address = address + (5);
} }
write_string_new(data, len, final_string); write_string_new(data, len, final_string);
} }
void TPCSG00291(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ void TPCSG00291(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
auto a2 = VITA3K::emu_arg(stack)[0]; auto a2 = VITA3K::emu_arg(stack)[0];
auto vm = *(DWORD *)(a2 + (0x28)); auto vm = *(DWORD *)(a2 + (0x28));
@ -247,7 +310,8 @@ void TPCSG00291(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* sp
uintptr_t address = VITA3K::emu_addr(stack, vm); uintptr_t address = VITA3K::emu_addr(stack, vm);
auto len1 = *(DWORD *)(address + 4); auto len1 = *(DWORD *)(address + 4);
auto p = address + 0x20; auto p = address + 0x20;
if(len1>4 && *(WORD*)(p+2)==0){ if (len1 > 4 && *(WORD *)(p + 2) == 0)
{
auto p1 = *(DWORD *)(address + 8); auto p1 = *(DWORD *)(address + 8);
vm = *(DWORD *)VITA3K::emu_addr(stack, vm); vm = *(DWORD *)VITA3K::emu_addr(stack, vm);
vm = *(DWORD *)VITA3K::emu_addr(stack, vm + 0xC); vm = *(DWORD *)VITA3K::emu_addr(stack, vm + 0xC);
@ -256,49 +320,142 @@ void TPCSG00291(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* sp
static int fm = 0; static int fm = 0;
static std::string pre; static std::string pre;
auto b = fm; auto b = fm;
auto s=[](uintptr_t address){ auto s = [](uintptr_t address)
{
auto frist = *(WORD *)address; auto frist = *(WORD *)address;
auto lo = frist & 0xFF; // uppercase: 41->5A auto lo = frist & 0xFF; // uppercase: 41->5A
auto hi = frist >> 8; auto hi = frist >> 8;
if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */) { if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */)
{
return std::string(); return std::string();
} }
std::string s ;int i = 0;WORD c; std::string s;
int i = 0;
WORD c;
char buf[3] = {0}; char buf[3] = {0};
while ((c = *(WORD*)(address+i)) != 0) { while ((c = *(WORD *)(address + i)) != 0)
{
// reverse endian: ShiftJIS BE => LE // reverse endian: ShiftJIS BE => LE
buf[0] = c >> 8; buf[0] = c >> 8;
buf[1] = c & 0xFF; buf[1] = c & 0xFF;
if (c == 0x815e /* */) { if (c == 0x815e /* */)
{
s += ' '; // single line s += ' '; // single line
} }
else if (buf[0] == 0) { else if (buf[0] == 0)
{
//// UTF16 LE turned BE: 5700=>0057, 3100, 3500 //// UTF16 LE turned BE: 5700=>0057, 3100, 3500
//// 4e00 6d00=>PLAYER //// 4e00 6d00=>PLAYER
// do nothing // do nothing
if (buf[1] == 0x4e) { if (buf[1] == 0x4e)
{
s += "PLAYER"; s += "PLAYER";
fm++; fm++;
} }
} }
else { else
{
s += buf; s += buf;
} }
i += 2; i += 2;
} }
return s; return s;
}(p); }(p);
if(b>0){ if (b > 0)
{
fm--; fm--;
return; return;
} }
if(s==pre)return ; if (s == pre)
return;
pre = s; pre = s;
write_string_new(data, len, s); write_string_new(data, len, s);
} }
auto _=[](){ bool FPCSG00468(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex(R"(\\n\u3000*|\\k)"), "");
s = std::regex_replace(s, std::regex(R"(\[|\*[^\]]+])"), "");
s = std::regex_replace(s, std::regex(u8"×"), "");
return write_string_overwrite(data, len, s);
}
bool FPCSG00808(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex(R"(^\s+|\s+$)"), "");
s = std::regex_replace(s, std::regex(R"(\s*(#n)*\s*)"), "");
s = std::regex_replace(s, std::regex(R"(#\w+(\[.+?\])?)"), "");
return write_string_overwrite(data, len, s);
}
bool FPCSG00855(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex(R"(#n\u3000*)"), "");
s = std::regex_replace(s, std::regex(R"(#\w.+?])"), "");
return write_string_overwrite(data, len, s);
}
template <int idx>
bool FPCSG00855_2(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
static std::string last;
if (last == s)
return false;
last = s;
strReplace(s, u8"Χ", u8"");
strReplace(s, u8"Δ", u8"");
strReplace(s, u8"Λ", u8"");
strReplace(s, u8"", u8"");
strReplace(s, u8"", u8"");
strReplace(s, u8"", u8"");
strReplace(s, u8"", u8"");
strReplace(s, u8"", u8"");
strReplace(s, u8"", u8"");
strReplace(s, u8"П", u8"");
strReplace(s, u8"Ц", u8"");
if (write_string_overwrite(data, len, s))
return FPCSG00855(data, len, hp);
else
return false;
}
bool FPCSG00477(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
auto ws = StringToWideString(s, 932).value();
ws = std::regex_replace(ws, std::wregex(LR"(#n\u3000*)"), L"");
ws = std::regex_replace(ws, std::wregex(LR"(#\w.+?])"), L"");
s = WideStringToString(ws, 932);
return write_string_overwrite(data, len, s);
}
bool FPCSG00852(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
auto ws = StringToWideString(s, 932).value();
ws = std::regex_replace(ws, std::wregex(LR"(\^)"), L"");
s = WideStringToString(ws, 932);
return write_string_overwrite(data, len, s);
}
bool FPCSG01066(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex(R"(\n\u3000*)"), "");
return write_string_overwrite(data, len, s);
}
bool FPCSG01075(void *data, size_t *len, HookParam *hp)
{
if (!FPCSG00808(data, len, hp))
return false;
auto s = std::string((char *)data, *len);
static std::string last;
if (last == s)
return false;
last = s;
return true;
}
auto _ = []()
{
emfunctionhooks = { emfunctionhooks = {
// Tsuihou Senkyo // Tsuihou Senkyo
{0x8002e176, {0, 0, 0, 0, FPCSG01023, "PCSG01023"}}, // dialogue+name,sjis {0x8002e176, {0, 0, 0, 0, FPCSG01023, "PCSG01023"}}, // dialogue+name,sjis
@ -316,8 +473,6 @@ auto _=[](){
// Marginal #4 Road to Galaxy // Marginal #4 Road to Galaxy
{0x8002ff90, {CODEC_UTF8, 0, 0, 0, FPCSG01008, "PCSG01008"}}, // text {0x8002ff90, {CODEC_UTF8, 0, 0, 0, FPCSG01008, "PCSG01008"}}, // text
// BLACK WOLVES SAGA -Weiβ und Schwarz- // BLACK WOLVES SAGA -Weiβ und Schwarz-
// {0x8004ed22,{CODEC_UTF8,0,0,0,FPCSG01008,"PCSG00935"}},//name
// {0x8006d202,{CODEC_UTF8,1,2,0,FPCSG01008,"PCSG00935"}},//text
{0x800581a2, {CODEC_UTF8, 0, 0, 0, FPCSG01008, "PCSG00935"}}, // text {0x800581a2, {CODEC_UTF8, 0, 0, 0, FPCSG01008, "PCSG00935"}}, // text
// New Game! The Challenge Stage! // New Game! The Challenge Stage!
{0x8012674c, {CODEC_UTF8, 0, 0, TPCSG00903, FPCSG00903, "PCSG00903"}}, {0x8012674c, {CODEC_UTF8, 0, 0, TPCSG00903, FPCSG00903, "PCSG00903"}},
@ -341,8 +496,7 @@ auto _=[](){
// Nekketsu Inou Bukatsu-tan Trigger Kiss // Nekketsu Inou Bukatsu-tan Trigger Kiss
{0x8004e44a, {0, 0, 0, 0, FPCSG00410, "PCSG00410"}}, // dialogue,sjis {0x8004e44a, {0, 0, 0, 0, FPCSG00410, "PCSG00410"}}, // dialogue,sjis
// バイナリースター Binary Star // バイナリースター Binary Star
{0x80058608,{0,1,0,0,FPCSG00389,"PCSG00389"}},//dialogue,sjis {0x80058606, {0, 1, 0xd, 0, FPCSG00389, "PCSG00389"}}, // dialogue,sjis
{0x80021292,{0,0,0,0,FPCSG00389,"PCSG00389"}},//name
// Amagami // Amagami
{0x80070658, {0, 0, 0, TPCSG00291, 0, "PCSG00291"}}, {0x80070658, {0, 0, 0, TPCSG00291, 0, "PCSG00291"}},
// Rui wa Tomo o Yobu // Rui wa Tomo o Yobu
@ -355,9 +509,56 @@ auto _=[](){
// Re:Birthday Song ~Koi o Utau Shinigami~ // Re:Birthday Song ~Koi o Utau Shinigami~
{0x80033af6, {0, 0, 2, 0, 0, "PCSG00911"}}, // dialogue {0x80033af6, {0, 0, 2, 0, 0, "PCSG00911"}}, // dialogue
// Un:Birthday Song ~Ai o Utau Shinigami~ // Un:Birthday Song ~Ai o Utau Shinigami~
{0x80038538,{0,0,0,PCSG00911,0,"PCSG00911"}}, {0x80038538, {0, 0, 0, PCSG00912, 0, "PCSG00912"}},
{0x80004b52,{0,3,5,0,0,"PCSG00911"}}, {0x80033d66, {0, 3, 4, 0, FPCSG00912, "PCSG00912"}},
// Sora*yume
{0x8000bad4, {0, 1, 0, 0, FPCSG00401, "PCSG00401"}},
// Tengai ni Mau, Iki na Hana
{0x8006808e, {CODEC_UTF8, 0, 0, 0, FPCSG01180, "PCSG01180"}},
{0x80089408, {CODEC_UTF8, 0, 0, 0, FPCSG01180, "PCSG01180"}},
// Kokuchou no Psychedelica (黒蝶のサイケデリカ)
{0x80043538, {CODEC_UTF8, 1, 0, 0, FPCSG00468, "PCSG00468"}},
// Haitaka no Psychedelica (灰鷹のサイケデリカ)
{0x80022c06, {CODEC_UTF8, 4, 0, 0, FPCSG00468, "PCSG00812"}},
// Yuukyuu no Tierblade -Lost Chronicle- (悠久のティアブレイド -Lost Chronicle-)
{0x8003542a, {CODEC_UTF8, 10, 0, 0, FPCSG00808, "PCSG00808"}},
{0x8002a95a, {CODEC_UTF8, 6, 0, 0, FPCSG00808, "PCSG00808"}},
{0x801a98aa, {CODEC_UTF8, 9, 0, 0, FPCSG00808, "PCSG00808"}},
{0x801a42bc, {CODEC_UTF8, 9, 0, 0, FPCSG00808, "PCSG00808"}},
{0x801a42d0, {CODEC_UTF8, 7, 0, 0, FPCSG00808, "PCSG00808"}},
// Yuukyuu no Tierblade -Fragments of Memory- (悠久のティアブレイド -Fragments of Memory-)
{0x80035f44, {CODEC_UTF8, 10, 0, 0, FPCSG01075, "PCSG01075"}},
{0x8000d868, {CODEC_UTF8, 9, 0, 0, FPCSG01075, "PCSG01075"}},
{0x8004598e, {CODEC_UTF8, 0, 0, 0, FPCSG01075, "PCSG01075"}},
{0x801b1d16, {CODEC_UTF8, 9, 0, 0, FPCSG01075, "PCSG01075"}},
{0x801ac31e, {CODEC_UTF8, 9, 0, 0, FPCSG01075, "PCSG01075"}},
{0x801ac33a, {CODEC_UTF8, 7, 0, 0, FPCSG01075, "PCSG01075"}},
{0x801b879a, {CODEC_UTF8, 5, 0, 0, FPCSG01075, "PCSG01075"}},
{0x8009f570, {CODEC_UTF8, 5, 0, 0, FPCSG01075, "PCSG01075"}},
// Magic Kyun! Renaissance (マジきゅんっ!ルネッサンス)
{0x8008375a, {0, 1, 0, 0, FPCSG00852, "PCSG00852"}},
{0x8001c194, {0, 1, 0, 0, FPCSG00852, "PCSG00852"}},
// Chouchou Jiken Lovesodic / Chouchou Jiken Rhapsodic (蝶々事件ラブソディック)
{0x8008dea2, {CODEC_UTF8, 4, 0, 0, FPCSG01066, "PCSG01066"}},
{0x8008eb38, {CODEC_UTF8, 0, 0, 0, FPCSG01066, "PCSG01066"}},
// Hyakka Yakou (百華夜光)
{0x80032b30, {0, 8, 0, 0, 0, "PCSG00477"}},
{0x80019c5a, {0, 5, 0, 0, 0, "PCSG00477"}},
{0x80031a46, {0, 6, 0, 0, 0, "PCSG00477"}},
{0x8003a49a, {0, 0, 0, 0, FPCSG00477, "PCSG00477"}},
{0x80182532, {0, 7, 0, 0, FPCSG00477, "PCSG00477"}},
{0x8017d1da, {0, 5, 0, 0, 0, "PCSG00477"}},
{0x8017d478, {0, 4, 0, 0, 0, "PCSG00477"}},
{0x8017a6aa, {0, 6, 0, 0, 0, "PCSG00477"}},
// Hana Oboro ~Sengoku-den Ranki~ (花朧 ~戦国伝乱奇~)
{0x80037600, {CODEC_UTF8, 6, 0, 0, FPCSG00855, "PCSG00855"}},
{0x80036580, {CODEC_UTF8, 6, 0, 0, FPCSG00855, "PCSG00855"}},
{0x801a2ada, {CODEC_UTF8, 0, 0, 0, FPCSG00855_2<0>, "PCSG00855"}},
{0x801a2ba8, {CODEC_UTF8, 0, 0, 0, FPCSG00855_2<1>, "PCSG00855"}},
{0x801a2d9e, {CODEC_UTF8, 0, 0, 0, FPCSG00855_2<2>, "PCSG00855"}},
{0x801a2e68, {CODEC_UTF8, 0, 0, 0, FPCSG00855_2<3>, "PCSG00855"}},
}; };
return 1; return 1;
}(); }();

View File

@ -1,8 +1,10 @@
class vita3k:public ENGINE{ class vita3k : public ENGINE
{
public: public:
vita3k(){ vita3k()
{
check_by = CHECK_BY::FILE; check_by = CHECK_BY::FILE;
is_engine_certain = false; is_engine_certain = false;
@ -10,4 +12,3 @@ class vita3k:public ENGINE{
}; };
bool attach_function(); bool attach_function();
}; };

2904
LunaHook/engine64/yuzu.cpp Normal file

File diff suppressed because it is too large Load Diff

17
LunaHook/engine64/yuzu.h Normal file
View File

@ -0,0 +1,17 @@
class yuzu : public ENGINE
{
public:
yuzu()
{
is_engine_certain = false;
check_by = CHECK_BY::CUSTOM;
check_by_target = []()
{
return (wcscmp(processName_lower, L"suyu.exe") == 0 || wcscmp(processName_lower, L"yuzu.exe") == 0 || wcscmp(processName_lower, L"sudachi.exe") == 0);
};
};
bool attach_function();
};

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +0,0 @@
class yuzusuyu:public ENGINE{
public:
yuzusuyu(){
is_engine_certain=false;
check_by=CHECK_BY::CUSTOM;
check_by_target=[](){
return (wcscmp(processName_lower, L"suyu.exe")==0 || wcscmp(processName_lower, L"yuzu.exe")==0|| wcscmp(processName_lower, L"sudachi.exe")==0);
};
};
bool attach_function();
};

View File

@ -16,7 +16,7 @@
#include "engine64/TYPEMOON.h" #include "engine64/TYPEMOON.h"
#include "engine64/Kincaid.h" #include "engine64/Kincaid.h"
#include "engine64/LightVN.h" #include "engine64/LightVN.h"
#include "engine64/yuzusuyu.h" #include "engine64/yuzu.h"
#include "engine64/Ryujinx.h" #include "engine64/Ryujinx.h"
#include "engine64/vita3k.h" #include "engine64/vita3k.h"
#include "engine64/rpcs3.h" #include "engine64/rpcs3.h"
@ -42,7 +42,7 @@ std::vector<ENGINE *> check_engines()
new _5pb, new _5pb,
new TYPEMOON, new TYPEMOON,
new ENTERGRAM, new ENTERGRAM,
new yuzusuyu, new yuzu,
new PPSSPPengine, new PPSSPPengine,
new vita3k, new vita3k,
new rpcs3, new rpcs3,

View File

@ -1,8 +1,10 @@
#include <queue> #include <queue>
#include "emujitarg.hpp" #include "emujitarg.hpp"
namespace ppsspp{ namespace ppsspp
bool ULJS00403_filter(void* data, size_t* len, HookParam* hp){ {
bool ULJS00403_filter(void *data, size_t *len, HookParam *hp)
{
std::string result = std::string((char *)data, *len); std::string result = std::string((char *)data, *len);
std::regex newlinePattern(R"((\\n)+)"); std::regex newlinePattern(R"((\\n)+)");
result = std::regex_replace(result, newlinePattern, " "); result = std::regex_replace(result, newlinePattern, " ");
@ -11,8 +13,8 @@ bool ULJS00403_filter(void* data, size_t* len, HookParam* hp){
return write_string_overwrite(data, len, result); return write_string_overwrite(data, len, result);
} }
void ULJS00339(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
void ULJS00339(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ {
auto a2 = PPSSPP::emu_arg(stack)[0]; auto a2 = PPSSPP::emu_arg(stack)[0];
auto vm = *(DWORD *)(a2 + (0x28)); auto vm = *(DWORD *)(a2 + (0x28));
@ -21,7 +23,8 @@ void ULJS00339(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* spl
uintptr_t address = PPSSPP::emu_addr(stack, vm); uintptr_t address = PPSSPP::emu_addr(stack, vm);
auto len1 = *(DWORD *)(address + 4); auto len1 = *(DWORD *)(address + 4);
auto p = address + 0x20; auto p = address + 0x20;
if(len1>4 && *(WORD*)(p+2)==0){ if (len1 > 4 && *(WORD *)(p + 2) == 0)
{
auto p1 = *(DWORD *)(address + 8); auto p1 = *(DWORD *)(address + 8);
vm = *(DWORD *)PPSSPP::emu_addr(stack, vm); vm = *(DWORD *)PPSSPP::emu_addr(stack, vm);
vm = *(DWORD *)PPSSPP::emu_addr(stack, vm + 0xC); vm = *(DWORD *)PPSSPP::emu_addr(stack, vm + 0xC);
@ -30,50 +33,61 @@ void ULJS00339(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* spl
static int fm = 0; static int fm = 0;
static std::string pre; static std::string pre;
auto b = fm; auto b = fm;
auto s=[](uintptr_t address){ auto s = [](uintptr_t address)
{
auto frist = *(WORD *)address; auto frist = *(WORD *)address;
auto lo = frist & 0xFF; // uppercase: 41->5A auto lo = frist & 0xFF; // uppercase: 41->5A
auto hi = frist >> 8; auto hi = frist >> 8;
if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */) { if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */)
{
return std::string(); return std::string();
} }
std::string s ;int i = 0;WORD c; std::string s;
int i = 0;
WORD c;
char buf[3] = {0}; char buf[3] = {0};
while ((c = *(WORD*)(address+i)) != 0) { while ((c = *(WORD *)(address + i)) != 0)
{
// reverse endian: ShiftJIS BE => LE // reverse endian: ShiftJIS BE => LE
buf[0] = c >> 8; buf[0] = c >> 8;
buf[1] = c & 0xFF; buf[1] = c & 0xFF;
if (c == 0x815e /* */) { if (c == 0x815e /* */)
{
s += ' '; // single line s += ' '; // single line
} }
else if (buf[0] == 0) { else if (buf[0] == 0)
{
//// UTF16 LE turned BE: 5700=>0057, 3100, 3500 //// UTF16 LE turned BE: 5700=>0057, 3100, 3500
//// 4e00 6d00=>PLAYER //// 4e00 6d00=>PLAYER
// do nothing // do nothing
if (buf[1] == 0x4e) { if (buf[1] == 0x4e)
{
s += "PLAYER"; s += "PLAYER";
fm++; fm++;
} }
} }
else { else
{
s += buf; s += buf;
} }
i += 2; i += 2;
} }
return s; return s;
}(p); }(p);
if(b>0){ if (b > 0)
{
fm--; fm--;
return; return;
} }
if(s==pre)return ; if (s == pre)
return;
pre = s; pre = s;
write_string_new(data, len, s); write_string_new(data, len, s);
} }
bool NPJH50909_filter(void *data, size_t *len, HookParam *hp)
bool NPJH50909_filter(void* data, size_t* len, HookParam* hp){ {
std::string result = std::string((char *)data, *len); std::string result = std::string((char *)data, *len);
auto ws = StringToWideString(result, 932).value(); auto ws = StringToWideString(result, 932).value();
// Remove single line markers // Remove single line markers
@ -84,7 +98,8 @@ bool NPJH50909_filter(void* data, size_t* len, HookParam* hp){
// Reformat name // Reformat name
std::wsmatch match; std::wsmatch match;
if (std::regex_search(ws, match, std::wregex(L"(^[^「]+)「"))) { if (std::regex_search(ws, match, std::wregex(L"(^[^「]+)「")))
{
std::wstring name = match[1].str(); std::wstring name = match[1].str();
ws = std::regex_replace(ws, std::wregex(L"^[^「]+"), L""); ws = std::regex_replace(ws, std::wregex(L"^[^「]+"), L"");
ws = name + L"\n" + ws; ws = name + L"\n" + ws;
@ -92,7 +107,8 @@ bool NPJH50909_filter(void* data, size_t* len, HookParam* hp){
return write_string_overwrite(data, len, WideStringToString(ws, 932)); return write_string_overwrite(data, len, WideStringToString(ws, 932));
} }
bool ULJM06119_filter(void* data, size_t* len, HookParam* hp){ bool ULJM06119_filter(void *data, size_t *len, HookParam *hp)
{
std::string s = std::string((char *)data, *len); std::string s = std::string((char *)data, *len);
std::regex pattern(R"(/\[[^\]]+./g)"); std::regex pattern(R"(/\[[^\]]+./g)");
@ -109,7 +125,8 @@ bool ULJM06119_filter(void* data, size_t* len, HookParam* hp){
return write_string_overwrite(data, len, s); return write_string_overwrite(data, len, s);
} }
bool ULJM06036_filter(void* data, size_t* len, HookParam* hp){ bool ULJM06036_filter(void *data, size_t *len, HookParam *hp)
{
std::wstring result = std::wstring((wchar_t *)data, *len / 2); std::wstring result = std::wstring((wchar_t *)data, *len / 2);
std::wregex pattern(LR"(<R([^\/]+).([^>]+).>)"); std::wregex pattern(LR"(<R([^\/]+).([^>]+).>)");
result = std::regex_replace(result, pattern, L"$2"); result = std::regex_replace(result, pattern, L"$2");
@ -118,16 +135,23 @@ bool ULJM06036_filter(void* data, size_t* len, HookParam* hp){
return write_string_overwrite(data, len, result); return write_string_overwrite(data, len, result);
} }
namespace Corda{ namespace Corda
std::string readBinaryString(uintptr_t address,bool* haveName){ {
std::string readBinaryString(uintptr_t address, bool *haveName)
{
*haveName = false; *haveName = false;
if ((*(WORD*)address & 0xF0FF) == 0x801b) { if ((*(WORD *)address & 0xF0FF) == 0x801b)
{
*haveName = true; *haveName = true;
address = address + 2; // (1) address = address + 2; // (1)
} }
std::string s;int i=0;uint8_t c; std::string s;
while ((c = *(uint8_t*)(address+i)) != 0) { int i = 0;
if (c == 0x1b) { uint8_t c;
while ((c = *(uint8_t *)(address + i)) != 0)
{
if (c == 0x1b)
{
if (*haveName) if (*haveName)
return s; // (1) skip junk after name return s; // (1) skip junk after name
@ -137,15 +161,18 @@ namespace Corda{
else else
i += 2; i += 2;
} }
else if (c == 0x0a) { else if (c == 0x0a)
{
s += '\n'; s += '\n';
i += 1; i += 1;
} }
else if (c == 0x20) { else if (c == 0x20)
{
s += ' '; s += ' ';
i += 1; i += 1;
} }
else { else
{
auto len = 1 + (IsDBCSLeadByteEx(932, *(BYTE *)(address + i))); auto len = 1 + (IsDBCSLeadByteEx(932, *(BYTE *)(address + i)));
s += std::string((char *)(address + i), len); s += std::string((char *)(address + i), len);
i += len; // encoder.encode(c).byteLength; i += len; // encoder.encode(c).byteLength;
@ -155,7 +182,8 @@ namespace Corda{
} }
} }
void ULJM05428(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ void ULJM05428(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
auto address = PPSSPP::emu_arg(stack)[1]; auto address = PPSSPP::emu_arg(stack)[1];
bool haveNamve; bool haveNamve;
auto s = Corda::readBinaryString(address, &haveNamve); auto s = Corda::readBinaryString(address, &haveNamve);
@ -163,10 +191,13 @@ void ULJM05428(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* spl
write_string_new(data, len, s); write_string_new(data, len, s);
} }
void ULJM05054(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ void ULJM05054(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
if (hp->emu_addr != 0x886162c) { {
if (hp->emu_addr != 0x886162c)
{
auto addr = PPSSPP::emu_arg(stack)[0] + 0x3c; auto addr = PPSSPP::emu_arg(stack)[0] + 0x3c;
*data=addr;*len=strlen((char*)addr); *data = addr;
*len = strlen((char *)addr);
return; return;
} }
auto address = PPSSPP::emu_arg(stack)[1]; auto address = PPSSPP::emu_arg(stack)[1];
@ -176,8 +207,8 @@ void ULJM05054(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* spl
write_string_new(data, len, s); write_string_new(data, len, s);
} }
bool ULJM05943F(void *data, size_t *len, HookParam *hp)
bool ULJM05943F(void* data, size_t* len, HookParam* hp){ {
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
std::regex pattern1("#n+"); std::regex pattern1("#n+");
std::string replacement1 = " "; std::string replacement1 = " ";
@ -199,7 +230,8 @@ bool FULJM05603(LPVOID data, size_t* size, HookParam*)
return true; return true;
} }
namespace NPJH50530{ namespace NPJH50530
{
std::string current; std::string current;
bool T(LPVOID data, size_t *size, HookParam *) bool T(LPVOID data, size_t *size, HookParam *)
{ {
@ -212,12 +244,20 @@ bool N(LPVOID data, size_t* size, HookParam*)
return current != current1; return current != current1;
} }
} }
bool FNPJH50243(LPVOID data, size_t *size, HookParam *)
{
auto s = std::wstring((wchar_t *)data, *size / 2);
s = std::regex_replace(s, std::wregex(LR"(<(.*?)\|(.*?)>)"), L"$1");
return write_string_overwrite(data, size, s);
}
bool FULJM05889(LPVOID data, size_t *size, HookParam *) bool FULJM05889(LPVOID data, size_t *size, HookParam *)
{ {
auto text = reinterpret_cast<LPSTR>(data); auto text = reinterpret_cast<LPSTR>(data);
auto len = reinterpret_cast<size_t *>(size); auto len = reinterpret_cast<size_t *>(size);
for(size_t i=0;i<*len;){ for (size_t i = 0; i < *len;)
if(IsDBCSLeadByteEx(932,(text[i]))){ {
if (IsDBCSLeadByteEx(932, (text[i])))
{
i += 2; i += 2;
continue; continue;
} }
@ -229,7 +269,8 @@ bool FULJM05889(LPVOID data, size_t* size, HookParam*)
return true; return true;
} }
bool NPJH50619F(void* data, size_t* len, HookParam* hp){ bool NPJH50619F(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
std::regex pattern1("[\\r\\n]+"); std::regex pattern1("[\\r\\n]+");
std::string replacement1 = ""; std::string replacement1 = "";
@ -246,8 +287,8 @@ bool NPJH50619F(void* data, size_t* len, HookParam* hp){
return write_string_overwrite(data, len, result4); return write_string_overwrite(data, len, result4);
} }
bool NPJH50505F(void *data, size_t *len, HookParam *hp)
bool NPJH50505F(void* data, size_t* len, HookParam* hp){ {
auto s = std::string((char *)data, *len); auto s = std::string((char *)data, *len);
std::regex pattern2("#RUBS(#[A-Z0-9]+)*[^#]+"); std::regex pattern2("#RUBS(#[A-Z0-9]+)*[^#]+");
@ -273,13 +314,16 @@ bool NPJH50505F(void* data, size_t* len, HookParam* hp){
return write_string_overwrite(data, len, result6); return write_string_overwrite(data, len, result6);
} }
void QNPJH50909(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ void QNPJH50909(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
uintptr_t addr = PPSSPP::emu_addr(stack, 0x08975110); uintptr_t addr = PPSSPP::emu_addr(stack, 0x08975110);
*data = addr + 0x20; *data = addr + 0x20;
*len = *(DWORD *)(addr + 0x14) * 2; *len = *(DWORD *)(addr + 0x14) * 2;
if(0x6e87==*(WORD*)*data)*len=0; if (0x6e87 == *(WORD *)*data)
if(0x000a==*(WORD*)*data)*len=0; *len = 0;
if (0x000a == *(WORD *)*data)
*len = 0;
} }
std::unordered_map<uintptr_t, emfuncinfo> emfunctionhooks = { std::unordered_map<uintptr_t, emfuncinfo> emfunctionhooks = {
// Shinigami to Shoujo // Shinigami to Shoujo
@ -324,6 +368,10 @@ std::unordered_map<uintptr_t,emfuncinfo>emfunctionhooks= {
// シャイニング・ブレイド // シャイニング・ブレイド
{0x8AA3B70, {0, 0xC, 0, 0, NPJH50530::T, "NPJH50530"}}, // text only {0x8AA3B70, {0, 0xC, 0, 0, NPJH50530::T, "NPJH50530"}}, // text only
{0x884DB44, {0, 1, 0, 0, NPJH50530::N, "NPJH50530"}}, // text+name {0x884DB44, {0, 1, 0, 0, NPJH50530::N, "NPJH50530"}}, // text+name
// ティアーズ・トゥ・ティアラ 外伝 アヴァロンの謎
{0x890A4BC, {CODEC_UTF16, 1, 0, 0, FNPJH50243, "NPJH50243"}},
// 薔薇ノ木ニ薔薇ノ花咲ク
{0x881E560, {0, 1, 0, 0, 0, "ULJM05802"}},
}; };
} }

View File

@ -222,7 +222,6 @@ void SafeSendJitVeh(hook_stack *stack, uintptr_t address, uintptr_t em_addr, JIT
} }
} }
std::unordered_map<uintptr_t, uint64_t> addresscalledtime; std::unordered_map<uintptr_t, uint64_t> addresscalledtime;
bool safeautoleaveveh = false;
bool SendJitVeh(PCONTEXT context, uintptr_t address, uintptr_t em_addr, JITTYPE jittype) bool SendJitVeh(PCONTEXT context, uintptr_t address, uintptr_t em_addr, JITTYPE jittype)
{ {
if (safeautoleaveveh) if (safeautoleaveveh)
@ -295,7 +294,7 @@ void SearchForHooks_Return()
if (!records[i].em_addr) if (!records[i].em_addr)
continue; continue;
hp.emu_addr = records[i].em_addr; hp.emu_addr = records[i].em_addr;
hp.type = CODEC_UTF16 | USING_STRING | BREAK_POINT; hp.type = CODEC_UTF16 | USING_STRING | BREAK_POINT | NO_CONTEXT;
hp.argidx = records[i].argidx; hp.argidx = records[i].argidx;
} }
NotifyHookFound(hp, (wchar_t *)records[i].text); NotifyHookFound(hp, (wchar_t *)records[i].text);

View File

@ -101,6 +101,15 @@ void ConsoleOutput(LPCSTR text, ...)
vsnprintf(buffer.message, MESSAGE_SIZE, text, args); vsnprintf(buffer.message, MESSAGE_SIZE, text, args);
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr); WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
} }
void WarningOutput(LPCSTR text, ...)
{
WarningNotif buffer;
va_list args;
va_start(args, text);
vsnprintf(buffer.message, MESSAGE_SIZE, text, args);
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
}
Synchronized<std::unordered_map<uintptr_t, std::wstring>> modulecache; Synchronized<std::unordered_map<uintptr_t, std::wstring>> modulecache;
std::wstring &querymodule(uintptr_t addr) std::wstring &querymodule(uintptr_t addr)
{ {

View File

@ -6,6 +6,7 @@
void TextOutput(const ThreadParam &tp, const HookParam &hp, TextOutput_T(*buffer), int len); void TextOutput(const ThreadParam &tp, const HookParam &hp, TextOutput_T(*buffer), int len);
void ConsoleOutput(LPCSTR text, ...); void ConsoleOutput(LPCSTR text, ...);
void WarningOutput(LPCSTR text, ...);
void NotifyHookFound(HookParam hp, wchar_t *text); void NotifyHookFound(HookParam hp, wchar_t *text);
void NotifyHookRemove(uint64_t addr, LPCSTR name); void NotifyHookRemove(uint64_t addr, LPCSTR name);
bool NewHook(HookParam hp, LPCSTR name); bool NewHook(HookParam hp, LPCSTR name);
@ -27,6 +28,6 @@ void context_set(hook_stack *, PCONTEXT);
inline std::map<uintptr_t, std::pair<std::string, HookParam>> delayinserthook; inline std::map<uintptr_t, std::pair<std::string, HookParam>> delayinserthook;
void delayinsertadd(HookParam, std::string); void delayinsertadd(HookParam, std::string);
void delayinsertNewHook(uintptr_t); void delayinsertNewHook(uintptr_t);
inline bool safeautoleaveveh = false;
inline bool dont_detach = false; inline bool dont_detach = false;
inline bool host_connected = false; inline bool host_connected = false;

View File

@ -127,7 +127,13 @@ bool TextHook::Insert(HookParam hp)
if (hp.type & DIRECT_READ) if (hp.type & DIRECT_READ)
return InsertReadCode(); return InsertReadCode();
if (hp.type & BREAK_POINT) if (hp.type & BREAK_POINT)
return InsertBreakPoint(); {
if (InsertBreakPoint())
return true;
if (safeautoleaveveh)
return InsertBreakPoint(); // 搜索特殊码后不会释放导致virtualprotect查询失败重试。
return false;
}
return InsertHookCode(); return InsertHookCode();
} }
uintptr_t win64find0000(uintptr_t addr) uintptr_t win64find0000(uintptr_t addr)

View File

@ -292,12 +292,16 @@ LunaHost::LunaHost()
hooksearchwindow->show(); hooksearchwindow->show();
}; };
Host::Start( Host::StartEx(
std::bind(&LunaHost::on_proc_connect, this, std::placeholders::_1), std::bind(&LunaHost::on_proc_connect, this, std::placeholders::_1),
std::bind(&LunaHost::on_proc_disconnect, this, std::placeholders::_1), std::bind(&LunaHost::on_proc_disconnect, this, std::placeholders::_1),
std::bind(&LunaHost::on_thread_create, this, std::placeholders::_1), std::bind(&LunaHost::on_thread_create, this, std::placeholders::_1),
std::bind(&LunaHost::on_thread_delete, this, std::placeholders::_1), std::bind(&LunaHost::on_thread_delete, this, std::placeholders::_1),
std::bind(&LunaHost::on_text_recv, this, std::placeholders::_1, std::placeholders::_2)); std::bind(&LunaHost::on_text_recv, this, std::placeholders::_1, std::placeholders::_2),
{},
{},
{},
std::bind(&LunaHost::on_warning, this, std::placeholders::_1));
mainlayout = new gridlayout(); mainlayout = new gridlayout();
mainlayout->addcontrol(g_selectprocessbutton, 0, 0); mainlayout->addcontrol(g_selectprocessbutton, 0, 0);
@ -448,6 +452,10 @@ bool LunaHost::on_text_recv(TextThread &thread, std::wstring &output)
} }
return true; return true;
} }
void LunaHost::on_warning(const std::wstring &warning)
{
MessageBoxW(winId, warning.c_str(), L"warning", 0);
}
void LunaHost::on_thread_create(TextThread &thread) void LunaHost::on_thread_create(TextThread &thread)
{ {
wchar_t buff[65535]; wchar_t buff[65535];

View File

@ -116,6 +116,7 @@ class LunaHost : public mainwindow
void on_thread_delete(TextThread &thread); void on_thread_delete(TextThread &thread);
void on_proc_connect(DWORD pid); void on_proc_connect(DWORD pid);
void on_proc_disconnect(DWORD pid); void on_proc_disconnect(DWORD pid);
void on_warning(const std::wstring &);
void showtext(const std::wstring &text, bool clear); void showtext(const std::wstring &text, bool clear);
void updatelisttext(const std::wstring &text, LONG_PTR data); void updatelisttext(const std::wstring &text, LONG_PTR data);

View File

@ -2,7 +2,6 @@
#include <io.h> #include <io.h>
#include <fcntl.h> #include <fcntl.h>
int main() int main()
{ {
_setmode(_fileno(stdout), _O_U16TEXT); _setmode(_fileno(stdout), _O_U16TEXT);
@ -22,51 +21,65 @@ int main()
output.c_str() output.c_str()
); );
fflush(stdout); fflush(stdout);
return false; return false; });
});
wchar_t input[500] = {}; wchar_t input[500] = {};
SearchParam sp = {}; SearchParam sp = {};
sp.codepage = Host::defaultCodepage; sp.codepage = Host::defaultCodepage;
sp.length = 0; sp.length = 0;
while (fgetws(input, 500, stdin)) while (fgetws(input, 500, stdin))
{ {
if(wcslen(input)<=1)continue;//\r\n第二行会直接只有一个\n if (wcslen(input) <= 1)
continue; //\r\n第二行会直接只有一个\n
wchar_t command[500] = {}; wchar_t command[500] = {};
DWORD processId = 0; DWORD processId = 0;
int split; int split;
for (split = wcslen(input) - 1; split >= 1; split--) { for (split = wcslen(input) - 1; split >= 1; split--)
if (input[split] == L'P' && input[split-1]=='-') { {
if (input[split] == L'P' && input[split - 1] == '-')
{
processId = _wtoi(input + split + 1); processId = _wtoi(input + split + 1);
break; break;
} }
} }
if (split == 1)continue;// ExitProcess(0); if (split == 1)
continue; // ExitProcess(0);
split -= 2; split -= 2;
while (split > 0 && input[split] == L' ')split -= 1; while (split > 0 && input[split] == L' ')
if (split == 0)continue;//ExitProcess(0); split -= 1;
if (split == 0)
continue; // ExitProcess(0);
input[split + 1] = 0; input[split + 1] = 0;
wcscpy(command, input); wcscpy(command, input);
// if (swscanf(input, L"%500s -P%d", command, &processId) != 2) ExitProcess(0); // if (swscanf(input, L"%500s -P%d", command, &processId) != 2) ExitProcess(0);
if (_wcsicmp(command, L"attach") == 0) Host::InjectProcess(processId); if (_wcsicmp(command, L"attach") == 0)
else if (_wcsicmp(command, L"detach") == 0) { Host::DetachProcess(processId); } Host::InjectProcess(processId);
else if (_wcsicmp(command, L"find") == 0) { else if (_wcsicmp(command, L"detach") == 0)
{
Host::DetachProcess(processId);
}
else if (_wcsicmp(command, L"find") == 0)
{
std::shared_ptr<std::vector<std::wstring>> hooks = std::make_shared<std::vector<std::wstring>>(); std::shared_ptr<std::vector<std::wstring>> hooks = std::make_shared<std::vector<std::wstring>>();
try try
{ {
Host::FindHooks(processId, sp, Host::FindHooks(processId, sp,
[hooks](HookParam hp, std::wstring text) { [hooks](HookParam hp, std::wstring text)
{
// if (std::regex_search(text, std::wregex(L"[\u3000-\ua000]"))) { // if (std::regex_search(text, std::wregex(L"[\u3000-\ua000]"))) {
if (std::regex_search(text, std::wregex(L"[\u3000-\ua000]"))) { if (std::regex_search(text, std::wregex(L"[\u3000-\ua000]")))
{
hooks->push_back(std::wstring(hp.hookcode) + L"=>" + text + L"\n"); hooks->push_back(std::wstring(hp.hookcode) + L"=>" + text + L"\n");
// *hooks << sanitize(S(HookCode::Generate(hp) + L" => " + text)); // *hooks << sanitize(S(HookCode::Generate(hp) + L" => " + text));
} }
}); });
} }
catch (wchar_t c) { std::wcout << c; } catch (wchar_t c)
{
std::wcout << c;
}
std::thread([hooks] std::thread([hooks]
{ {
for (int lastSize = 0; hooks->size() == 0 || hooks->size() != lastSize; Sleep(2000)) lastSize = hooks->size(); for (int lastSize = 0; hooks->size() == 0 || hooks->size() != lastSize; Sleep(2000)) lastSize = hooks->size();
@ -76,34 +89,40 @@ int main()
fwrite(hook.c_str(), wcslen(hook.c_str()) * sizeof(wchar_t), 1, out); fwrite(hook.c_str(), wcslen(hook.c_str()) * sizeof(wchar_t), 1, out);
} }
fclose(out); fclose(out); })
}).detach(); .detach();
} }
else { else
if (command[0] == L'-') { {
if (command[0] == L'-')
{
try try
{ {
unsigned long long address; unsigned long long address;
swscanf_s(command, L"-%llu", &address); swscanf_s(command, L"-%llu", &address);
Host::RemoveHook(processId, address); Host::RemoveHook(processId, address);
} }
catch (std::out_of_range) {} catch (std::out_of_range)
{
} }
else if (command[0] == L'=') { }
else if (command[0] == L'=')
{
int codepage; int codepage;
swscanf_s(command, L"=%d", &codepage); swscanf_s(command, L"=%d", &codepage);
Host::defaultCodepage = codepage; Host::defaultCodepage = codepage;
} }
else if (command[0] == L'+') { else if (command[0] == L'+')
{
int flushDelay; int flushDelay;
swscanf_s(command, L"+%d", &flushDelay); swscanf_s(command, L"+%d", &flushDelay);
TextThread::flushDelay = flushDelay; TextThread::flushDelay = flushDelay;
} }
else if (auto hp = HookCode::Parse(command)) Host::InsertHook(processId, hp.value()); else if (auto hp = HookCode::Parse(command))
else ExitProcess(0); Host::InsertHook(processId, hp.value());
else
ExitProcess(0);
} }
} }
ExitProcess(0); ExitProcess(0);

View File

@ -26,7 +26,7 @@ typedef void (*EmbedCallback)(const wchar_t *, ThreadParam);
wchar_t hookcode[HOOKCODE_LEN]; \ wchar_t hookcode[HOOKCODE_LEN]; \
wcscpy_s(hookcode, HOOKCODE_LEN, thread.hp.hookcode); \ wcscpy_s(hookcode, HOOKCODE_LEN, thread.hp.hookcode); \
strcpy_s(name, HOOK_NAME_SIZE, thread.hp.name); strcpy_s(name, HOOK_NAME_SIZE, thread.hp.name);
C_LUNA_API void Luna_Start(ProcessEvent Connect, ProcessEvent Disconnect, ThreadEvent Create, ThreadEvent Destroy, OutputCallback Output, ConsoleHandler console, HookInsertHandler hookinsert, EmbedCallback embed) C_LUNA_API void Luna_Start(ProcessEvent Connect, ProcessEvent Disconnect, ThreadEvent Create, ThreadEvent Destroy, OutputCallback Output, ConsoleHandler console, HookInsertHandler hookinsert, EmbedCallback embed, ConsoleHandler Warning)
{ {
Host::StartEx( Host::StartEx(
Connect, Connect,
@ -56,6 +56,10 @@ C_LUNA_API void Luna_Start(ProcessEvent Connect, ProcessEvent Disconnect, Thread
[=](const std::wstring &output, const ThreadParam &tp) [=](const std::wstring &output, const ThreadParam &tp)
{ {
embed(output.c_str(), tp); embed(output.c_str(), tp);
},
[=](const std::wstring &output)
{
Warning(output.c_str());
}); });
} }
C_LUNA_API void Luna_Inject(DWORD pid, LPCWSTR basepath) C_LUNA_API void Luna_Inject(DWORD pid, LPCWSTR basepath)

View File

@ -7,8 +7,7 @@ namespace
class ProcessRecord class ProcessRecord
{ {
public: public:
ProcessRecord(DWORD processId, HANDLE pipe) : ProcessRecord(DWORD processId, HANDLE pipe) : pipe(pipe),
pipe(pipe),
mappedFile2(OpenFileMappingW(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, (EMBED_SHARED_MEM + std::to_wstring(processId)).c_str())), mappedFile2(OpenFileMappingW(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, (EMBED_SHARED_MEM + std::to_wstring(processId)).c_str())),
viewMutex(ITH_HOOKMAN_MUTEX_ + std::to_wstring(processId)) viewMutex(ITH_HOOKMAN_MUTEX_ + std::to_wstring(processId))
@ -27,9 +26,8 @@ namespace
{ {
static_assert(sizeof(data) < PIPE_BUFFER_SIZE); static_assert(sizeof(data) < PIPE_BUFFER_SIZE);
std::thread([=] std::thread([=]
{ { WriteFile(pipe, &data, sizeof(data), DUMMY, nullptr); })
WriteFile(pipe, &data, sizeof(data), DUMMY, nullptr); .detach();
}).detach();
} }
Host::HookEventHandler OnHookFound = [](HookParam hp, std::wstring text) Host::HookEventHandler OnHookFound = [](HookParam hp, std::wstring text)
@ -37,8 +35,8 @@ namespace
Host::AddConsoleOutput(std::wstring(hp.hookcode) + L": " + text); Host::AddConsoleOutput(std::wstring(hp.hookcode) + L": " + text);
}; };
EmbedSharedMem *embedsharedmem; EmbedSharedMem *embedsharedmem;
private: private:
HANDLE pipe; HANDLE pipe;
AutoHandle<> mappedFile2; AutoHandle<> mappedFile2;
@ -52,12 +50,15 @@ namespace
Host::ProcessEventHandler OnConnect, OnDisconnect; Host::ProcessEventHandler OnConnect, OnDisconnect;
Host::ThreadEventHandler OnCreate, OnDestroy; Host::ThreadEventHandler OnCreate, OnDestroy;
Host::ConsoleHandler OnConsole = 0; Host::ConsoleHandler OnConsole = 0;
Host::ConsoleHandler OnWarning = 0;
Host::HookInsertHandler HookInsert = 0; Host::HookInsertHandler HookInsert = 0;
Host::EmbedCallback embedcallback = 0; Host::EmbedCallback embedcallback = 0;
void RemoveThreads(std::function<bool(ThreadParam)> removeIf) void RemoveThreads(std::function<bool(ThreadParam)> removeIf)
{ {
std::vector<TextThread *> threadsToRemove; std::vector<TextThread *> threadsToRemove;
for (auto& [tp, thread] : textThreadsByParams.Acquire().contents) if (removeIf(tp)) threadsToRemove.push_back(&thread); for (auto &[tp, thread] : textThreadsByParams.Acquire().contents)
if (removeIf(tp))
threadsToRemove.push_back(&thread);
for (auto thread : threadsToRemove) for (auto thread : threadsToRemove)
{ {
OnDestroy(*thread); OnDestroy(*thread);
@ -141,6 +142,12 @@ namespace
Host::AddConsoleOutput(StringToWideString(info.message)); Host::AddConsoleOutput(StringToWideString(info.message));
} }
break; break;
case HOST_NOTIFICATION_WARNING:
{
auto info = *(WarningNotif*)buffer;
Host::Warning(StringToWideString(info.message));
}
break;
default: default:
{ {
auto data=(TextOutput_T*)buffer; auto data=(TextOutput_T*)buffer;
@ -179,8 +186,8 @@ namespace
RemoveThreads([&](ThreadParam tp) { return tp.processId == processId; }); RemoveThreads([&](ThreadParam tp) { return tp.processId == processId; });
OnDisconnect(processId); OnDisconnect(processId);
Host::AddConsoleOutput(FormatString(PROC_DISCONN,processId)); Host::AddConsoleOutput(FormatString(PROC_DISCONN,processId));
processRecordsByIds->erase(processId); processRecordsByIds->erase(processId); })
}).detach(); .detach();
} }
} }
@ -191,34 +198,47 @@ namespace Host
std::mutex procmutex; std::mutex procmutex;
void Start(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output, bool createconsole) void Start(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output, bool createconsole)
{ {
OnConnect = [=](auto &&...args){std::lock_guard _(procmutex);Connect(std::forward<decltype(args)>(args)...);}; OnConnect = [=](auto &&...args)
OnDisconnect = [=](auto &&...args){std::lock_guard _(procmutex);Disconnect(std::forward<decltype(args)>(args)...);}; {std::lock_guard _(procmutex);Connect(std::forward<decltype(args)>(args)...); };
OnCreate = [=](TextThread& thread) {{std::lock_guard _(threadmutex); Create(thread);} thread.Start(); }; OnDisconnect = [=](auto &&...args)
OnDestroy = [=](TextThread& thread) {thread.Stop(); {std::lock_guard _(threadmutex); Destroy(thread);} }; {std::lock_guard _(procmutex);Disconnect(std::forward<decltype(args)>(args)...); };
TextThread::Output = [=](auto &&...args){std::lock_guard _(outputmutex);return Output(std::forward<decltype(args)>(args)...);}; OnCreate = [=](TextThread &thread)
{{std::lock_guard _(threadmutex); Create(thread);} thread.Start(); };
OnDestroy = [=](TextThread &thread)
{thread.Stop(); {std::lock_guard _(threadmutex); Destroy(thread);} };
TextThread::Output = [=](auto &&...args)
{std::lock_guard _(outputmutex);return Output(std::forward<decltype(args)>(args)...); };
if(createconsole){ if (createconsole)
{
OnCreate(textThreadsByParams->try_emplace(console, console, HookParam{}, CONSOLE).first->second); OnCreate(textThreadsByParams->try_emplace(console, console, HookParam{}, CONSOLE).first->second);
Host::AddConsoleOutput(ProjectHomePage); Host::AddConsoleOutput(ProjectHomePage);
} }
// CreatePipe(); // CreatePipe();
} }
void StartEx(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output,ConsoleHandler console,HookInsertHandler hookinsert,EmbedCallback embed){ void StartEx(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output, std::optional<ConsoleHandler> console, std::optional<HookInsertHandler> hookinsert, std::optional<EmbedCallback> embed, std::optional<ConsoleHandler> warning)
Start(Connect,Disconnect,Create,Destroy,Output,false); {
Start(Connect, Disconnect, Create, Destroy, Output, !console.has_value());
OnConsole=[=](auto &&...args){std::lock_guard _(outputmutex);console(std::forward<decltype(args)>(args)...);}; if (warning.has_value())
HookInsert=[=](auto &&...args){std::lock_guard _(threadmutex);hookinsert(std::forward<decltype(args)>(args)...);}; OnWarning = warning.value();
embedcallback=[=](auto &&...args){std::lock_guard _(outputmutex);embed(std::forward<decltype(args)>(args)...);}; if (console.has_value())
OnConsole = [=](auto &&...args)
{std::lock_guard _(outputmutex);console.value()(std::forward<decltype(args)>(args)...); };
if (hookinsert.has_value())
HookInsert = [=](auto &&...args)
{std::lock_guard _(threadmutex);hookinsert.value()(std::forward<decltype(args)>(args)...); };
if (embed.has_value())
embedcallback = [=](auto &&...args)
{std::lock_guard _(outputmutex);embed.value()(std::forward<decltype(args)>(args)...); };
} }
constexpr auto PROCESS_INJECT_ACCESS=( constexpr auto PROCESS_INJECT_ACCESS = (PROCESS_CREATE_THREAD |
PROCESS_CREATE_THREAD |
PROCESS_QUERY_INFORMATION | PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION | PROCESS_VM_OPERATION |
PROCESS_VM_WRITE | PROCESS_VM_WRITE |
PROCESS_VM_READ); PROCESS_VM_READ);
bool SafeInject(HANDLE process,const std::wstring &location){ bool SafeInject(HANDLE process, const std::wstring &location)
{
// #ifdef _WIN64 // #ifdef _WIN64
#if 0 #if 0
BOOL invalidProcess = FALSE; BOOL invalidProcess = FALSE;
@ -229,51 +249,66 @@ namespace Host
if (LPVOID remoteData = VirtualAllocEx(process, nullptr, (location.size() + 1) * sizeof(wchar_t), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)) if (LPVOID remoteData = VirtualAllocEx(process, nullptr, (location.size() + 1) * sizeof(wchar_t), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))
{ {
WriteProcessMemory(process, remoteData, location.c_str(), (location.size() + 1) * sizeof(wchar_t), nullptr); WriteProcessMemory(process, remoteData, location.c_str(), (location.size() + 1) * sizeof(wchar_t), nullptr);
if (AutoHandle<> thread = CreateRemoteThread(process, nullptr, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, remoteData, 0, nullptr)){ if (AutoHandle<> thread = CreateRemoteThread(process, nullptr, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, remoteData, 0, nullptr))
{
WaitForSingleObject(thread, INFINITE); WaitForSingleObject(thread, INFINITE);
succ = true; succ = true;
} }
else if (GetLastError() == ERROR_ACCESS_DENIED){ else if (GetLastError() == ERROR_ACCESS_DENIED)
{
AddConsoleOutput(NEED_64_BIT); // https://stackoverflow.com/questions/16091141/createremotethread-access-denied AddConsoleOutput(NEED_64_BIT); // https://stackoverflow.com/questions/16091141/createremotethread-access-denied
succ = false; succ = false;
} }
VirtualFreeEx(process, remoteData, 0, MEM_RELEASE); VirtualFreeEx(process, remoteData, 0, MEM_RELEASE);
} }
return succ; return succ;
} }
bool UnSafeInject(HANDLE process,const std::wstring &location){ bool UnSafeInject(HANDLE process, const std::wstring &location)
{
DWORD64 injectedDll; DWORD64 injectedDll;
yapi::YAPICall LoadLibraryW(process, _T("kernel32.dll"), "LoadLibraryW"); yapi::YAPICall LoadLibraryW(process, _T("kernel32.dll"), "LoadLibraryW");
if(x64)injectedDll = LoadLibraryW.Dw64()(location.c_str()); if (x64)
else injectedDll = LoadLibraryW(location.c_str()); injectedDll = LoadLibraryW.Dw64()(location.c_str());
if(injectedDll)return true; else
injectedDll = LoadLibraryW(location.c_str());
if (injectedDll)
return true;
return false;
}
bool CheckProcess(DWORD processId)
{
if (processId == GetCurrentProcessId())
return false; return false;
}
bool CheckProcess(DWORD processId){
if (processId == GetCurrentProcessId()) return false;
WinMutex(ITH_HOOKMAN_MUTEX_ + std::to_wstring(processId)); WinMutex(ITH_HOOKMAN_MUTEX_ + std::to_wstring(processId));
if (GetLastError() == ERROR_ALREADY_EXISTS){AddConsoleOutput(ALREADY_INJECTED); return false;} if (GetLastError() == ERROR_ALREADY_EXISTS)
{
AddConsoleOutput(ALREADY_INJECTED);
return false;
}
return true; return true;
} }
bool InjectDll(DWORD processId,const std::wstring locationX){ bool InjectDll(DWORD processId, const std::wstring locationX)
{
AutoHandle<> process = OpenProcess(PROCESS_INJECT_ACCESS, FALSE, processId); AutoHandle<> process = OpenProcess(PROCESS_INJECT_ACCESS, FALSE, processId);
if(!process)return false; if (!process)
return false;
bool proc64 = Is64BitProcess(process); bool proc64 = Is64BitProcess(process);
auto dllname = proc64 ? LUNA_HOOK_DLL_64 : LUNA_HOOK_DLL_32; auto dllname = proc64 ? LUNA_HOOK_DLL_64 : LUNA_HOOK_DLL_32;
std::wstring location = locationX.size() ? (locationX + L"\\" + dllname) : std::filesystem::path(getModuleFilename().value()).replace_filename(dllname); std::wstring location = locationX.size() ? (locationX + L"\\" + dllname) : std::filesystem::path(getModuleFilename().value()).replace_filename(dllname);
AddConsoleOutput(location); AddConsoleOutput(location);
if(proc64==x64){ if (proc64 == x64)
{
return (SafeInject(process, location)); return (SafeInject(process, location));
} }
else{ else
{
return (UnSafeInject(process, location)); return (UnSafeInject(process, location));
} }
} }
bool CreatePipeAndCheck(DWORD processId){ bool CreatePipeAndCheck(DWORD processId)
{
CreatePipe(processId); CreatePipe(processId);
return CheckProcess(processId); return CheckProcess(processId);
} }
@ -281,41 +316,47 @@ namespace Host
{ {
auto check = CreatePipeAndCheck(processId); auto check = CreatePipeAndCheck(processId);
if(check==false)return; if (check == false)
return;
std::thread([=] std::thread([=]
{ {
if(InjectDll(processId,locationX))return ; if(InjectDll(processId,locationX))return ;
AddConsoleOutput(INJECT_FAILED); AddConsoleOutput(INJECT_FAILED); })
}).detach(); .detach();
} }
void DetachProcess(DWORD processId) void DetachProcess(DWORD processId)
{ {
auto &prs = processRecordsByIds.Acquire().contents; auto &prs = processRecordsByIds.Acquire().contents;
if(prs.find(processId)==prs.end())return; if (prs.find(processId) == prs.end())
return;
prs.at(processId).Send(HOST_COMMAND_DETACH); prs.at(processId).Send(HOST_COMMAND_DETACH);
} }
void InsertHook(DWORD processId, HookParam hp) void InsertHook(DWORD processId, HookParam hp)
{ {
auto &prs = processRecordsByIds.Acquire().contents; auto &prs = processRecordsByIds.Acquire().contents;
if(prs.find(processId)==prs.end())return; if (prs.find(processId) == prs.end())
return;
prs.at(processId).Send(InsertHookCmd(hp)); prs.at(processId).Send(InsertHookCmd(hp));
} }
void RemoveHook(DWORD processId, uint64_t address) void RemoveHook(DWORD processId, uint64_t address)
{ {
auto &prs = processRecordsByIds.Acquire().contents; auto &prs = processRecordsByIds.Acquire().contents;
if(prs.find(processId)==prs.end())return; if (prs.find(processId) == prs.end())
return;
prs.at(processId).Send(RemoveHookCmd(address)); prs.at(processId).Send(RemoveHookCmd(address));
} }
void FindHooks(DWORD processId, SearchParam sp, HookEventHandler HookFound) void FindHooks(DWORD processId, SearchParam sp, HookEventHandler HookFound)
{ {
auto &prs = processRecordsByIds.Acquire().contents; auto &prs = processRecordsByIds.Acquire().contents;
if(prs.find(processId)==prs.end())return; if (prs.find(processId) == prs.end())
if (HookFound) prs.at(processId).OnHookFound = HookFound; return;
if (HookFound)
prs.at(processId).OnHookFound = HookFound;
prs.at(processId).Send(FindHookCmd(sp)); prs.at(processId).Send(FindHookCmd(sp));
} }
@ -326,12 +367,16 @@ namespace Host
TextThread *GetThread(int64_t handle) TextThread *GetThread(int64_t handle)
{ {
for (auto& [tp, thread] : textThreadsByParams.Acquire().contents) if (thread.handle == handle) return &thread; for (auto &[tp, thread] : textThreadsByParams.Acquire().contents)
if (thread.handle == handle)
return &thread;
return nullptr; return nullptr;
} }
EmbedSharedMem* GetEmbedSharedMem(DWORD processId){ EmbedSharedMem *GetEmbedSharedMem(DWORD processId)
{
auto &prs = processRecordsByIds.Acquire().contents; auto &prs = processRecordsByIds.Acquire().contents;
if(prs.find(processId)==prs.end())return 0; if (prs.find(processId) == prs.end())
return 0;
return prs.at(processId).embedsharedmem; return prs.at(processId).embedsharedmem;
} }
void AddConsoleOutput(std::wstring text) void AddConsoleOutput(std::wstring text)
@ -341,4 +386,10 @@ namespace Host
else else
GetThread(console).AddSentence(std::move(text)); GetThread(console).AddSentence(std::move(text));
} }
void Warning(std::wstring text)
{
if (OnWarning)
OnWarning(text);
AddConsoleOutput(L"[Warning] " + text);
}
} }

View File

@ -10,7 +10,7 @@ namespace Host
using HookInsertHandler = std::function<void(uint64_t, const std::wstring &)>; using HookInsertHandler = std::function<void(uint64_t, const std::wstring &)>;
using EmbedCallback = std::function<void(const std::wstring &, const ThreadParam &)>; using EmbedCallback = std::function<void(const std::wstring &, const ThreadParam &)>;
void Start(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output, bool createconsole = true); void Start(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output, bool createconsole = true);
void StartEx(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output,ConsoleHandler console,HookInsertHandler hookinsert,EmbedCallback embed); void StartEx(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output, std::optional<ConsoleHandler> console, std::optional<HookInsertHandler> hookinsert, std::optional<EmbedCallback> embed, std::optional<ConsoleHandler> warning);
void InjectProcess(DWORD processId, const std::wstring locationX = L""); void InjectProcess(DWORD processId, const std::wstring locationX = L"");
bool CreatePipeAndCheck(DWORD processId); bool CreatePipeAndCheck(DWORD processId);
@ -24,6 +24,7 @@ namespace Host
TextThread &GetThread(ThreadParam tp); TextThread &GetThread(ThreadParam tp);
void AddConsoleOutput(std::wstring text); void AddConsoleOutput(std::wstring text);
void Warning(std::wstring text);
inline int defaultCodepage = SHIFT_JIS; inline int defaultCodepage = SHIFT_JIS;

View File

@ -12,16 +12,17 @@ static bool RemoveRepetition(std::wstring& text)
return false; return false;
} }
TextThread::TextThread(ThreadParam tp, HookParam hp, std::optional<std::wstring> name) : TextThread::TextThread(ThreadParam tp, HookParam hp, std::optional<std::wstring> name) : handle(threadCounter++),
handle(threadCounter++),
name(name.value_or(StringToWideString(hp.name))), name(name.value_or(StringToWideString(hp.name))),
tp(tp), tp(tp),
hp(hp) hp(hp)
{} {
}
void TextThread::Start() void TextThread::Start()
{ {
CreateTimerQueueTimer(&timer, NULL, [](void* This, auto) { ((TextThread*)This)->Flush(); }, this, 10, 10, WT_EXECUTELONGFUNCTION); CreateTimerQueueTimer(&timer, NULL, [](void *This, auto)
{ ((TextThread *)This)->Flush(); }, this, 10, 10, WT_EXECUTELONGFUNCTION);
} }
void TextThread::Stop() void TextThread::Stop()
@ -36,7 +37,8 @@ void TextThread::AddSentence(std::wstring sentence)
void TextThread::Push(BYTE *data, int length) void TextThread::Push(BYTE *data, int length)
{ {
if (length < 0) return; if (length < 0)
return;
std::scoped_lock lock(bufferMutex); std::scoped_lock lock(bufferMutex);
BYTE doubleByteChar[2]; BYTE doubleByteChar[2];
@ -60,15 +62,19 @@ void TextThread::Push(BYTE* data, int length)
if (converted) if (converted)
{ {
buffer.append(converted.value()); buffer.append(converted.value());
if (hp.type & FULL_STRING && converted.value().size()>1) buffer.push_back(L'\n'); if (hp.type & FULL_STRING && converted.value().size() > 1)
buffer.push_back(L'\n');
} }
else Host::AddConsoleOutput(INVALID_CODEPAGE); else
Host::AddConsoleOutput(INVALID_CODEPAGE);
lastPushTime = GetTickCount64(); lastPushTime = GetTickCount64();
if (filterRepetition) if (filterRepetition)
{ {
if (std::all_of(buffer.begin(), buffer.end(), [&](wchar_t ch) { return repeatingChars.find(ch) != repeatingChars.end(); })) buffer.clear(); if (std::all_of(buffer.begin(), buffer.end(), [&](wchar_t ch)
{ return repeatingChars.find(ch) != repeatingChars.end(); }))
buffer.clear();
if (RemoveRepetition(buffer)) // sentence repetition detected, which means the entire sentence has already been received if (RemoveRepetition(buffer)) // sentence repetition detected, which means the entire sentence has already been received
{ {
repeatingChars = std::unordered_set(buffer.begin(), buffer.end()); repeatingChars = std::unordered_set(buffer.begin(), buffer.end());
@ -96,7 +102,8 @@ void TextThread::Flush()
{ {
{ {
auto storage = this->storage.Acquire(); auto storage = this->storage.Acquire();
if (storage->size() > maxHistorySize) storage->erase(0, storage->size() - maxHistorySize); // https://github.com/Artikash/Textractor/issues/127#issuecomment-486882983 if (storage->size() > maxHistorySize)
storage->erase(0, storage->size() - maxHistorySize); // https://github.com/Artikash/Textractor/issues/127#issuecomment-486882983
} }
std::vector<std::wstring> sentences; std::vector<std::wstring> sentences;
@ -106,11 +113,13 @@ void TextThread::Flush()
{ {
totalSize += sentence.size(); totalSize += sentence.size();
sentence.erase(std::remove(sentence.begin(), sentence.end(), 0), sentence.end()); sentence.erase(std::remove(sentence.begin(), sentence.end(), 0), sentence.end());
if (Output(*this, sentence)) storage->append(sentence+L"\n"); if (Output(*this, sentence))
storage->append(sentence + L"\n");
} }
std::scoped_lock lock(bufferMutex); std::scoped_lock lock(bufferMutex);
if (buffer.empty()) return; if (buffer.empty())
return;
if (buffer.size() > maxBufferSize || GetTickCount64() - lastPushTime > flushDelay) if (buffer.size() > maxBufferSize || GetTickCount64() - lastPushTime > flushDelay)
{ {
AddSentence(std::move(buffer)); AddSentence(std::move(buffer));

View File

@ -1,6 +1,5 @@
#pragma once #pragma once
class TextThread class TextThread
{ {
public: public:
@ -37,6 +36,9 @@ private:
std::mutex bufferMutex; std::mutex bufferMutex;
DWORD64 lastPushTime = 0; DWORD64 lastPushTime = 0;
Synchronized<std::vector<std::wstring>> queuedSentences; Synchronized<std::vector<std::wstring>> queuedSentences;
struct TimerDeleter { void operator()(HANDLE h) { DeleteTimerQueueTimer(NULL, h, INVALID_HANDLE_VALUE); } }; struct TimerDeleter
{
void operator()(HANDLE h) { DeleteTimerQueueTimer(NULL, h, INVALID_HANDLE_VALUE); }
};
AutoHandle<TimerDeleter> timer = NULL; AutoHandle<TimerDeleter> timer = NULL;
}; };

View File

@ -38,7 +38,8 @@ enum HostNotificationType
HOST_NOTIFICATION_FOUND_HOOK, HOST_NOTIFICATION_FOUND_HOOK,
HOST_NOTIFICATION_RMVHOOK, HOST_NOTIFICATION_RMVHOOK,
HOST_NOTIFICATION_INSERTING_HOOK, HOST_NOTIFICATION_INSERTING_HOOK,
HOST_SETTEXTTHREADTYPE HOST_SETTEXTTHREADTYPE,
HOST_NOTIFICATION_WARNING
}; };
#define NEXT_MASK(x) \ #define NEXT_MASK(x) \
DUMMY1_##x, \ DUMMY1_##x, \

View File

@ -183,6 +183,12 @@ struct ConsoleOutputNotif // From dll
HostNotificationType command = HOST_NOTIFICATION_TEXT; HostNotificationType command = HOST_NOTIFICATION_TEXT;
char message[MESSAGE_SIZE] = {}; char message[MESSAGE_SIZE] = {};
}; };
struct WarningNotif // From dll
{
WarningNotif(std::string message = "") { strncpy_s(this->message, message.c_str(), MESSAGE_SIZE - 1); }
HostNotificationType command = HOST_NOTIFICATION_WARNING;
char message[MESSAGE_SIZE] = {};
};
struct HookFoundNotif // From dll struct HookFoundNotif // From dll
{ {