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,29 +1,34 @@
#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; {
*len=stack->ARG3; *data = stack->ARG2;
*split=stack->ARG1; *len = stack->ARG3;
*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); {
strReplace(s,"%N","\n"); auto s = std::string((char *)data, *len);
//sub_140096E80 strReplace(s, "%N", "\n");
// sub_140096E80
//%I %B %C %R( %Z %% //%I %B %C %R( %Z %%
return write_string_overwrite(data,len,s); return write_string_overwrite(data, len, s);
}; };
return NewHook(hp,"strncat"); return NewHook(hp, "strncat");
} }
} }
bool _5pb::attach_function() { bool _5pb::attach_function()
//CHAOS;HEAD_NOAH {
bool b3=hookmages::MAGES(); // CHAOS;HEAD_NOAH
return b3||_strncat(); bool b3 = hookmages::MAGES();
return b3 || _strncat();
} }

View File

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

View File

@ -1,80 +1,97 @@
#include"AGES7.h" #include "AGES7.h"
namespace{ namespace
//Muv-Luv Alternative - Total Eclipse {
//https://vndb.org/v7052 // Muv-Luv Alternative - Total Eclipse
bool _1(){ // https://vndb.org/v7052
//HSN65001#-44@234699:te-win64vc14-release.exe bool _1()
BYTE b1[]={ {
0x48,XX2,0xb0,0xfe,0xff,0xff, // HSN65001#-44@234699:te-win64vc14-release.exe
0x4c,XX2,0xb8,0x01,0x00,0x00, BYTE b1[] = {
//clang-format off
0x48, XX2, 0xb0, 0xfe, 0xff, 0xff,
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.type=USING_STRING|CODEC_UTF8|NO_CONTEXT; hp.address = addr;
hp.offset=get_reg(regs::rbx); hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
succ|=NewHook(hp,"Ages7_3"); hp.offset = get_reg(regs::rbx);
succ |= NewHook(hp, "Ages7_3");
} }
return succ; return succ;
} }
bool _2(){ bool _2()
//HSN65001#-44@2346AC:te-win64vc14-release.exe {
BYTE b1[]={ // HSN65001#-44@2346AC:te-win64vc14-release.exe
0x48,XX2,0x10, BYTE b1[] = {
0x48,XX2,0xb0,0x01,0x00,0x00, //clang-format off
XX2,0xc0,0x08,0x00,0x00 0x48, XX2, 0x10,
0x48, XX2, 0xb0, 0x01, 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.type=USING_STRING|CODEC_UTF8|NO_CONTEXT; hp.address = addr;
hp.offset=get_reg(regs::rbx); hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
suc|=NewHook(hp,"Ages7_3"); hp.offset = get_reg(regs::rbx);
suc |= NewHook(hp, "Ages7_3");
} }
return suc; return suc;
} }
bool _3(){ bool _3()
//HSN65001#-14@3D9814:te-win64vc14-release.exe {
BYTE b1[]={ // HSN65001#-14@3D9814:te-win64vc14-release.exe
0x48,0x8b,0x1b, BYTE b1[] = {
0x48,0x8b,0x01, //clang-format off
0x48,0x8b,0xd3, 0x48, 0x8b, 0x1b,
0xff,0x10, 0x48, 0x8b, 0x01,
0x48,0x8b,0x45,0xc8, 0x48, 0x8b, 0xd3,
0x48,0x8b,0x4d,0xc0, 0xff, 0x10,
0x48,0x2b,0xc1, 0x48, 0x8b, 0x45, 0xc8,
0x48,0xc1,0xf8,0x03, 0x48, 0x8b, 0x4d, 0xc0,
0x48,0x85,0xc0, 0x48, 0x2b, 0xc1,
0x48, 0xc1, 0xf8, 0x03,
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(); {
_=_2()||_; auto _ = _1();
_=_3()||_; _ = _2() || _;
_ = _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: {
AGES7(){ public:
AGES7()
check_by=CHECK_BY::FILE_ALL; {
check_by_target=check_by_list{L"obb\\pack.bin",L"erc_nospfx.dll"};
check_by = CHECK_BY::FILE_ALL;
check_by_target = check_by_list{L"obb\\pack.bin", L"erc_nospfx.dll"};
}; };
bool attach_function(); bool attach_function();
}; };

View File

@ -54,8 +54,8 @@ bool Artemis64()
bool Artemis64x() bool Artemis64x()
{ {
//https://vndb.org/v50832 // https://vndb.org/v50832
//きら☆かの 体验版 // きら☆かの 体验版
/* /*
__int64 __fastcall sub_1401B13F0(__int64 a1, unsigned __int64 a2, char **a3) __int64 __fastcall sub_1401B13F0(__int64 a1, unsigned __int64 a2, char **a3)

View File

@ -1,11 +1,13 @@
class Artemis:public ENGINE{ class Artemis : public ENGINE
public: {
Artemis(){ public:
Artemis()
check_by=CHECK_BY::FILE; {
check_by_target=L"*.pfs";
check_by = CHECK_BY::FILE;
check_by_target = L"*.pfs";
}; };
bool attach_function(); bool attach_function();
}; };

View File

@ -1,57 +1,68 @@
#include"CMVS.h" #include "CMVS.h"
namespace{ namespace
bool EMbed(){ {
//有多个,但是只有最后一个是有效的 bool EMbed()
const uint8_t bytes[] = { {
0xB8,0x42,0x81,0x00,0x00, // 有多个,但是只有最后一个是有效的
0x66,XX2,0x74,XX, const uint8_t bytes[] = {
0xB8,0x76,0x81,0x00,0x00, //clang-format off
0x66,XX2,0x74,XX, 0xB8, 0x42, 0x81, 0x00, 0x00,
0xB8,0x78,0x81,0x00,0x00, 0x66, XX2, 0x74, XX,
0x66,XX2,0x74,XX, 0xB8, 0x76, 0x81, 0x00, 0x00,
}; 0x66, XX2, 0x74, XX,
bool res=false; 0xB8, 0x78, 0x81, 0x00, 0x00,
auto addr=processStartAddress; 0x66, XX2, 0x74, XX,
//clang-format on
std::vector<uintptr_t>already; };
bool res = false;
while(addr){ auto addr = processStartAddress;
addr = MemDbg::findBytes(bytes,sizeof(bytes),addr+1,processStopAddress);
if(addr==0)continue; std::vector<uintptr_t> already;
while (addr)
{
addr = MemDbg::findBytes(bytes, sizeof(bytes), addr + 1, processStopAddress);
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())
{
HookParam hp;
hp.address = already.back();
hp.offset = get_reg(regs::rdx);
hp.type = EMBED_ABLE | USING_STRING | EMBED_BEFORE_SIMPLE | EMBED_AFTER_NEW | EMBED_DYNA_SJIS;
hp.hook_font = F_GetGlyphOutlineA;
res |= NewHook(hp, "EmbedCMVS");
}
return res;
} }
if(already.size()){
bool CMVSh()
{
DWORD align = 0xCCCCCCCC;
auto addr = MemDbg::findCallerAddress((uintptr_t)::GetGlyphOutlineA, align, processStartAddress, processStopAddress);
if (!addr)
return false;
HookParam hp; HookParam hp;
hp.address = already.back() ; hp.address = addr + 4;
hp.offset=get_reg(regs::rdx); hp.offset = get_reg(regs::r8);
hp.type = CODEC_ANSI_BE;
hp.type=EMBED_ABLE|USING_STRING|EMBED_BEFORE_SIMPLE|EMBED_AFTER_NEW|EMBED_DYNA_SJIS;
hp.hook_font=F_GetGlyphOutlineA; return NewHook(hp, "CMVS");
res|=NewHook(hp, "EmbedCMVS");
} }
return res;
} }
bool CMVS::attach_function()
bool CMVSh() { {
bool b1 = CMVSh();
DWORD align = 0xCCCCCCCC; bool b2 = EMbed();
auto addr = MemDbg::findCallerAddress((uintptr_t)::GetGlyphOutlineA, align, processStartAddress, processStopAddress); return b1 || b2;
if (!addr) return false;
HookParam hp;
hp.address = addr+4;
hp.offset=get_reg(regs::r8);
hp.type = CODEC_ANSI_BE;
return NewHook(hp, "CMVS");
}
}
bool CMVS::attach_function(){
bool b1=CMVSh();
bool b2=EMbed();
return b1||b2;
} }

View File

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

View File

@ -1,26 +1,29 @@
#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;
myhp.type = USING_STRING | CODEC_UTF16 | NO_CONTEXT; // /HQ 不使用上下文区分 把所有线程的文本都提取 myhp.type = USING_STRING | CODEC_UTF16 | NO_CONTEXT; // /HQ 不使用上下文区分 把所有线程的文本都提取
//myhp.padding = 0xc;//[esp+4]+padding // myhp.padding = 0xc;//[esp+4]+padding
// data_offset // data_offset
myhp.offset=get_reg(regs::rax); myhp.offset = get_reg(regs::rax);
myhp.text_fun = [](hook_stack* stack, HookParam *hp, uintptr_t* data, uintptr_t* split, size_t* count) myhp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *count)
{ {
*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))
*count=len*2; return;
*count = len * 2;
}; };
char nameForUser[HOOK_NAME_SIZE] = "RichTextLabel_add_text"; char nameForUser[HOOK_NAME_SIZE] = "RichTextLabel_add_text";
ConsoleOutput("Insert: Godot_add_text_X64 Hook "); ConsoleOutput("Insert: Godot_add_text_X64 Hook ");
return NewHook(myhp, nameForUser); return NewHook(myhp, nameForUser);
} }
@ -28,27 +31,29 @@ 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:
* https://vndb.org/r109138 * https://vndb.org/r109138
*/ */
const BYTE bytes[] = { const BYTE bytes[] = {
0x48, 0x8B, 0x94, 0x24, XX4, // mov rdx,[rsp+000001C0] <- hook here 0x48, 0x8B, 0x94, 0x24, XX4, // mov rdx,[rsp+000001C0] <- hook here
0x4C, 0x89, 0xE1, // mov rcx,r12 0x4C, 0x89, 0xE1, // mov rcx,r12
0xE8, XX4, // call NULL-Windows.exe+D150 0xE8, XX4, // call NULL-Windows.exe+D150
0x49, 0x8B, 0x06, // mov rax,[r14] 0x49, 0x8B, 0x06, // mov rax,[r14]
0x48, 0x85, 0xC0, // test rax,rax 0x48, 0x85, 0xC0, // test rax,rax
0x0F, 0x85, XX4 // jne NULL-Windows.exe+A359D4 0x0F, 0x85, XX4 // jne NULL-Windows.exe+A359D4
}; };
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);
hp.type = USING_STRING | CODEC_UTF16; hp.type = USING_STRING | CODEC_UTF16;
ConsoleOutput("INSERT Godot2_x64 Hook "); ConsoleOutput("INSERT Godot2_x64 Hook ");
return NewHook(hp, "Godot2_x64"); return NewHook(hp, "Godot2_x64");
@ -57,8 +62,9 @@ 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(); {
_=InsertGodotHook2_X64()||_; auto _ = InsertGodotHook_X64();
_ = InsertGodotHook2_X64() || _;
return _; return _;
} }

View File

@ -1,11 +1,13 @@
class Godot:public ENGINE{ class Godot : public ENGINE
public: {
Godot(){ public:
Godot()
check_by=CHECK_BY::FILE; {
check_by_target=L"*.pck";
}; check_by = CHECK_BY::FILE;
bool attach_function(); check_by_target = L"*.pck";
};
bool attach_function();
}; };

View File

@ -1,38 +1,42 @@
#include"Kincaid.h" #include "Kincaid.h"
namespace{ namespace
bool _1(){ {
// .text:0000000140230D80 mov rsi, rax bool _1()
// .text:0000000140230D83 mov edx, 1 {
// .text:0000000140230D88 mov rcx, rdi // .text:0000000140230D80 mov rsi, rax
// .text:0000000140230D8B call sub_1402B35B0 // .text:0000000140230D83 mov edx, 1
// .text:0000000140230D90 lea ebx, [rax-1] // .text:0000000140230D88 mov rcx, rdi
// .text:0000000140230D93 mov edx, 2 // .text:0000000140230D8B call sub_1402B35B0
// .text:0000000140230D98 mov rcx, rdi // .text:0000000140230D90 lea ebx, [rax-1]
// .text:0000000140230D9B call sub_1402B35B0 // .text:0000000140230D93 mov edx, 2
BYTE b1[]={ // .text:0000000140230D98 mov rcx, rdi
0x48,0x8b,0xf0, // .text:0000000140230D9B call sub_1402B35B0
0xba,0x01,0x00,0x00,0x00, BYTE b1[] = {
0x48,0x8b,0xcf, 0x48, 0x8b, 0xf0,
0xe8,XX4, 0xba, 0x01, 0x00, 0x00, 0x00,
0x8d,0x58,0xff, 0x48, 0x8b, 0xcf,
0xba,0x02,0x00,0x00,0x00, 0xe8, XX4,
0x48,0x8b,0xcf, 0x8d, 0x58, 0xff,
0xe8,XX4 0xba, 0x02, 0x00, 0x00, 0x00,
}; 0x48, 0x8b, 0xcf,
auto addr=MemDbg::findBytes(b1,sizeof(b1),processStartAddress,processStopAddress); 0xe8, XX4};
if(addr==0)return false; auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress);
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; {
if(stack->retaddr==(DWORD)-1) *data = stack->rax;
*len=strlen((char*)*data); if (stack->retaddr == (DWORD)-1)
*len = strlen((char *)*data);
}; };
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: {
Kincaid(){ public:
Kincaid()
check_by=CHECK_BY::CUSTOM; {
check_by_target=[](){
return Util::SearchResourceString(L"Cookiedraggy")|| Util::SearchResourceString(L"The Adventures of Kincaid");
};
check_by = CHECK_BY::CUSTOM;
check_by_target = []()
{
return Util::SearchResourceString(L"Cookiedraggy") || Util::SearchResourceString(L"The Adventures of Kincaid");
};
}; };
bool attach_function(); bool attach_function();
}; };

View File

@ -1,68 +1,70 @@
#include"KiriKiri.h" #include "KiriKiri.h"
bool InsertKiriKiriZHook() bool InsertKiriKiriZHook()
{ {
/*
* Sample games:
* RJ351843
*/
const BYTE bytes[] = {
0xCC, // int 3
0x4C, 0x89, 0x44, 0x24, 0x18, // mov [rsp+18],r8 <- hook here
0x48, 0x89, 0x54, 0x24, 0x10, // mov [rsp+10],rdx
0x53, // push rbx
0x56, // push rsi
0x57, // push rdi
0x41, 0x54, // push r12
0x41, 0x55, // push r13
0x41, 0x56, // push r14
0x41, 0x57, // push r15
0x48, 0x83, 0xEC, 0x40, // sub rsp,40
0x48, 0xC7, 0x44, 0x24, 0x30, 0xFE, 0xFF, 0xFF, 0xFF // mov qword ptr [rsp+30],FFFFFFFFFFFFFFFE
};
ULONG64 range = min(processStopAddress - processStartAddress, X64_MAX_REL_ADDR); /*
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range)) { * Sample games:
HookParam hp; * RJ351843
hp.address = addr + 1; */
hp.offset=get_reg(regs::rcx); const BYTE bytes[] = {
hp.index = 0x18; 0xCC, // int 3
hp.type = CODEC_UTF16 | DATA_INDIRECT; 0x4C, 0x89, 0x44, 0x24, 0x18, // mov [rsp+18],r8 <- hook here
return NewHook(hp, "KiriKiriZ"); 0x48, 0x89, 0x54, 0x24, 0x10, // mov [rsp+10],rdx
} 0x53, // push rbx
return false; 0x56, // push rsi
0x57, // push rdi
0x41, 0x54, // push r12
0x41, 0x55, // push r13
0x41, 0x56, // push r14
0x41, 0x57, // push r15
0x48, 0x83, 0xEC, 0x40, // sub rsp,40
0x48, 0xC7, 0x44, 0x24, 0x30, 0xFE, 0xFF, 0xFF, 0xFF // mov qword ptr [rsp+30],FFFFFFFFFFFFFFFE
};
ULONG64 range = min(processStopAddress - processStartAddress, X64_MAX_REL_ADDR);
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range))
{
HookParam hp;
hp.address = addr + 1;
hp.offset = get_reg(regs::rcx);
hp.index = 0x18;
hp.type = CODEC_UTF16 | DATA_INDIRECT;
return NewHook(hp, "KiriKiriZ");
} }
return false;
}
bool Insertkrkrz64Hook() bool Insertkrkrz64Hook()
{ {
const BYTE BYTES[] = { const BYTE BYTES[] = {
0x41,0x0F,0xB7,0x44,0x24,0x04, 0x41, 0x0F, 0xB7, 0x44, 0x24, 0x04,
0x89,0x43,0x20, 0x89, 0x43, 0x20,
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)
addr += 4; continue;
HookParam hp; addr += 4;
hp.address = addr; HookParam hp;
hp.type = CODEC_UTF16| DATA_INDIRECT; hp.address = addr;
hp.offset=get_reg(regs::rcx); hp.type = CODEC_UTF16 | DATA_INDIRECT;
hp.index = 0x18; hp.offset = get_reg(regs::rcx);
ConsoleOutput("krkrz64 %p %x", addr); hp.index = 0x18;
return NewHook(hp, "krkrz64"); ConsoleOutput("krkrz64 %p %x", addr);
} return NewHook(hp, "krkrz64");
}
ConsoleOutput("krkrz64 failed"); ConsoleOutput("krkrz64 failed");
return false; return false;
}
bool KiriKiri::attach_function()
{
return Insertkrkrz64Hook() || InsertKiriKiriZHook();
} }
bool KiriKiri::attach_function() {
return Insertkrkrz64Hook()||InsertKiriKiriZHook();
}

View File

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

View File

@ -1,13 +1,14 @@
class LightVN:public ENGINE{ class LightVN : public ENGINE
public: {
LightVN(){ public:
LightVN()
check_by=CHECK_BY::FILE_ANY; {
is_engine_certain=false;
check_by_target=check_by_list{L"Data/Scripts/title.txt",L"Data/data*.vndat",L"Scripts/000_title.txt"}; check_by = CHECK_BY::FILE_ANY;
}; is_engine_certain = false;
bool attach_function(); check_by_target = check_by_list{L"Data/Scripts/title.txt", L"Data/data*.vndat", L"Scripts/000_title.txt"};
};
bool attach_function();
}; };

View File

@ -1,5 +1,5 @@
#include"PPSSPP.h" #include "PPSSPP.h"
#include"ppsspp/psputils.hpp" #include "ppsspp/psputils.hpp"
bool PPSSPPengine::attach_function() bool PPSSPPengine::attach_function()
{ {

View File

@ -1,12 +1,14 @@
class PPSSPPengine:public ENGINE{ class PPSSPPengine : public ENGINE
public: {
PPSSPPengine(){ public:
PPSSPPengine()
check_by=CHECK_BY::FILE; {
is_engine_certain=false;
check_by_target=L"PPSSPP*.exe"; check_by = CHECK_BY::FILE;
}; is_engine_certain = false;
bool attach_function(); check_by_target = L"PPSSPP*.exe";
};
bool attach_function();
}; };

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"); {
if(msvcrt==0)return 0; auto msvcrt = GetModuleHandle(L"msvcrt.dll");
auto _strdup=GetProcAddress(msvcrt,"_strdup"); if (msvcrt == 0)
if(_strdup==0)return 0; return 0;
auto _strdup = GetProcAddress(msvcrt, "_strdup");
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,11 +1,13 @@
class Suika2:public ENGINE{ class Suika2 : public ENGINE
public: {
Suika2(){ public:
is_engine_certain=false; Suika2()
check_by=CHECK_BY::FILE_ANY; {
check_by_target=check_by_list{L"suika.exe",L"conf/config.txt"}; is_engine_certain = false;
check_by = CHECK_BY::FILE_ANY;
check_by_target = check_by_list{L"suika.exe", L"conf/config.txt"};
}; };
bool attach_function(); bool attach_function();
}; };

View File

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

View File

@ -1,13 +1,14 @@
class TYPEMOON:public ENGINE{ class TYPEMOON : public ENGINE
public: {
TYPEMOON(){ public:
TYPEMOON()
check_by=CHECK_BY::FILE; {
is_engine_certain=false;
check_by_target=L"data*.hfa"; check_by = CHECK_BY::FILE;
}; is_engine_certain = false;
bool attach_function(); check_by_target = L"data*.hfa";
};
bool attach_function();
}; };

View File

@ -1,5 +1,5 @@
#include"V8.h" #include "V8.h"
#include"v8/v8.h" #include "v8/v8.h"
#if 0 #if 0
// Artikash 6/23/2019: V8 (JavaScript runtime) has rcx = string** at v8::String::Write // Artikash 6/23/2019: V8 (JavaScript runtime) has rcx = string** at v8::String::Write
// sample game https://www.freem.ne.jp/dl/win/18963 // sample game https://www.freem.ne.jp/dl/win/18963
@ -113,7 +113,7 @@ namespace{
} }
return save; return save;
} }
#if 0 #if 0
std::vector<HookParam> v8hook1(HMODULE module) { std::vector<HookParam> v8hook1(HMODULE module) {
const BYTE BYTES[] = { const BYTE BYTES[] = {
@ -155,7 +155,7 @@ namespace{
} }
return save; return save;
} }
#endif #endif
bool innerHTML(HMODULE module) { bool innerHTML(HMODULE module) {
//花葬 //花葬
//result = sub_142DF3CA0(a2, v5, 1u, (__int64)"innerHTML", a3); //result = sub_142DF3CA0(a2, v5, 1u, (__int64)"innerHTML", a3);
@ -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: {
V8(){ public:
check_by=CHECK_BY::CUSTOM; V8()
check_by_target=[this](){return attach_function_();}; {
check_by = CHECK_BY::CUSTOM;
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

@ -1,21 +1,22 @@
#include"YOX.h" #include "YOX.h"
bool YOX::attach_function() 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;
hp.offset = get_stack(26); hp.offset = get_stack(26);
ConsoleOutput("yox64 %p", addr); ConsoleOutput("yox64 %p", addr);
return NewHook(hp, "yox64"); return NewHook(hp, "yox64");
} }
ConsoleOutput("yox64 failed"); ConsoleOutput("yox64 failed");
return false; return false;
} }

View File

@ -1,13 +1,14 @@
class YOX:public ENGINE{ class YOX : public ENGINE
public: {
YOX(){ public:
YOX()
check_by=CHECK_BY::FILE; {
is_engine_certain=false;
check_by_target=L"base/*.dat"; check_by = CHECK_BY::FILE;
}; is_engine_certain = false;
bool attach_function(); check_by_target = L"base/*.dat";
};
bool attach_function();
}; };

View File

@ -1,49 +1,50 @@
#include "livecaptions.h" #include "livecaptions.h"
bool livecaptions::attach_function() bool livecaptions::attach_function()
{ {
// .text:0000000180001C98 push rbx
// .text:0000000180001C9A sub rsp, 20h
// .text:0000000180001C9E mov rbx, rcx
// .text:0000000180001CA1 call memmove_0
// .text:0000000180001CA6 mov rax, rbx
// .text:0000000180001CA9 add rsp, 20h
// .text:0000000180001CAD pop rbx
// .text:0000000180001CAE retn
HookParam hp;
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){
BYTE sig[]={
0x40,0x53,0x48,0x83,0xEC,0x20,0x48,0x8B,0xD9,
0xE8,XX4
};
auto a1=stack->retaddr-sizeof(sig);
if((stack->retaddr>(uintptr_t)GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll")))
if(memcmp((void*)a1,&sig,sizeof(sig)-4)==0){
static std::set<uintptr_t>once;
if(once.find(stack->retaddr)!=once.end())return;
once.insert(stack->retaddr);
// hp->text_fun=nullptr;
// hp->type=HOOK_EMPTY;
HookParam hpinternal; // .text:0000000180001C98 push rbx
hpinternal.address =a1;// 0xE551+(uintptr_t)GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll"); // .text:0000000180001C9A sub rsp, 20h
hpinternal.type = USING_STRING | CODEC_UTF8|FULL_STRING; // .text:0000000180001C9E mov rbx, rcx
hpinternal.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len) // .text:0000000180001CA1 call memmove_0
// .text:0000000180001CA6 mov rax, rbx
// .text:0000000180001CA9 add rsp, 20h
// .text:0000000180001CAD pop rbx
// .text:0000000180001CAE retn
HookParam hp;
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)
{
BYTE sig[] = {
0x40, 0x53, 0x48, 0x83, 0xEC, 0x20, 0x48, 0x8B, 0xD9,
0xE8, XX4};
auto a1 = stack->retaddr - sizeof(sig);
if ((stack->retaddr > (uintptr_t)GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll")))
if (memcmp((void *)a1, &sig, sizeof(sig) - 4) == 0)
{ {
auto ptr = stack->rdx; static std::set<uintptr_t> once;
auto size = stack->r8; if (once.find(stack->retaddr) != once.end())
if (size == strnlen((char *)ptr, TEXT_BUFFER_SIZE) )//否则有短acsii return;
once.insert(stack->retaddr);
// hp->text_fun=nullptr;
// hp->type=HOOK_EMPTY;
HookParam hpinternal;
hpinternal.address = a1; // 0xE551+(uintptr_t)GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll");
hpinternal.type = USING_STRING | CODEC_UTF8 | FULL_STRING;
hpinternal.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{ {
*data = ptr; auto ptr = stack->rdx;
*len = size; auto size = stack->r8;
} if (size == strnlen((char *)ptr, TEXT_BUFFER_SIZE)) // 否则有短acsii
}; {
NewHook(hpinternal, "std::_Char_traits<char,int>::copy(void *, const void *, size_t)"); *data = ptr;
} *len = size;
}
};
NewHook(hpinternal, "std::_Char_traits<char,int>::copy(void *, const void *, size_t)");
}
}; };
return NewHook(hp,"vcruntime140_app:memmove"); return NewHook(hp, "vcruntime140_app:memmove");
} }

View File

@ -9,7 +9,7 @@ public:
check_by = CHECK_BY::CUSTOM; check_by = CHECK_BY::CUSTOM;
check_by_target = []() check_by_target = []()
{ {
return GetModuleHandle(L"vcruntime140_app.dll")&&GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll"); return GetModuleHandle(L"vcruntime140_app.dll") && GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll");
}; };
}; };
bool attach_function(); bool attach_function();

View File

@ -1,13 +1,14 @@
class lucasystem:public ENGINE{ class lucasystem : public ENGINE
public: {
lucasystem(){ public:
lucasystem()
check_by=CHECK_BY::FILE; {
is_engine_certain=false;
check_by_target=L"files/*.PAK"; check_by = CHECK_BY::FILE;
}; is_engine_certain = false;
bool attach_function(); check_by_target = L"files/*.PAK";
};
bool attach_function();
}; };

View File

@ -1,82 +1,90 @@
#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,
0x73,0x05, 0x73, 0x05,
0x49,0x8B,0xCC 0x49, 0x8B, 0xCC
/* /*
_BYTE *__fastcall sub_18005B290( _BYTE *__fastcall sub_18005B290(
_WORD *a1, _WORD *a1,
int a2, int a2,
__int64 a3, __int64 a3,
_DWORD *a4, _DWORD *a4,
__int64 (__fastcall *a5)(__int64, __int64), __int64 (__fastcall *a5)(__int64, __int64),
__int64 a6, __int64 a6,
__int64 a7) __int64 a7)
if ( (_DWORD)v26 ) if ( (_DWORD)v26 )
{
if ( (unsigned int)v26 >= 0x80 )
{ {
if ( (unsigned int)v26 >= 0x800 ) if ( (unsigned int)v26 >= 0x80 )
{ {
if ( (unsigned int)v26 >= 0x10000 ) if ( (unsigned int)v26 >= 0x800 )
{ {
if ( (unsigned int)v26 >= 0x200000 ) if ( (unsigned int)v26 >= 0x10000 )
{ {
if ( (unsigned int)v26 >= 0x4000000 ) if ( (unsigned int)v26 >= 0x200000 )
{ {
v17 = 6i64; if ( (unsigned int)v26 >= 0x4000000 )
if ( (unsigned int)v26 >= 0x80000000 ) {
*/ v17 = 6i64;
if ( (unsigned int)v26 >= 0x80000000 )
*/
}; };
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}; {
addr=reverseFindBytes(align,sizeof(align),addr-0x100,addr); const BYTE align[] = {0xCC, 0xCC, 0xCC, 0xCC};
if(addr==0)continue; addr = reverseFindBytes(align, sizeof(align), addr - 0x100, addr);
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); {
if(str.find(L"OnShowComplete")!=str.npos){ std::wstring str = std::wstring((LPWSTR)data, *len / 2);
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;
std::regex_search(str, match,reg1 ); std::regex_search(str, match, reg1);
auto result1= match[1].str(); auto result1 = match[1].str();
std::regex_search(str, match,std::wregex(L" Text:(.*?)Next:(.*?)") ); std::regex_search(str, match, std::wregex(L" Text:(.*?)Next:(.*?)"));
result1= match[1].str(); result1 = match[1].str();
write_string_overwrite(data,len,result1); write_string_overwrite(data, len, result1);
} }
return true; return true;
}; };
suc|=NewHook(hp, "monobdwgcdll"); suc |= NewHook(hp, "monobdwgcdll");
} }
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,10 +1,12 @@
class mono:public ENGINE{ class mono : public ENGINE
public: {
mono(){ public:
mono()
check_by=CHECK_BY::ALL_TRUE; {
check_by = CHECK_BY::ALL_TRUE;
}; };
bool attach_function(); bool attach_function();
}; };

View File

@ -1,12 +1,16 @@
#include"pchooks.h" #include "pchooks.h"
bool pchooks::attach_function() { bool pchooks::attach_function()
for (std::wstring DXVersion : { L"d3dx9", L"d3dx10" }) {
if (HMODULE module = GetModuleHandleW(DXVersion.c_str())) PcHooks::hookD3DXFunctions(module); for (std::wstring DXVersion : {L"d3dx9", L"d3dx10"})
else for (int i = 0; i < 50; ++i) if (HMODULE module = GetModuleHandleW(DXVersion.c_str()))
if (HMODULE module = GetModuleHandleW((DXVersion + L"_" + std::to_wstring(i)).c_str())) PcHooks::hookD3DXFunctions(module); 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();
return true; return true;
} }

View File

@ -1,11 +1,13 @@
class pchooks:public ENGINE{ class pchooks : public ENGINE
public: {
pchooks(){ public:
pchooks()
check_by=CHECK_BY::ALL_TRUE; {
dontstop=true;
}; check_by = CHECK_BY::ALL_TRUE;
bool attach_function(); dontstop = true;
};
bool attach_function();
}; };

View File

@ -1,6 +1,7 @@
#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;
uintptr_t getDoJitAddress_() { uintptr_t getDoJitAddress_() {
@ -113,10 +114,11 @@ namespace{
return DoJitPtr+6; return DoJitPtr+6;
} }
#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)
{ {
@ -138,130 +140,147 @@ 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)
auto addr=MemDbg::findleaaddr(logstrptr, processStartAddress, processStopAddress); return 0;
ConsoleOutput("%p",addr); auto addr = MemDbg::findleaaddr(logstrptr, processStartAddress, processStopAddress);
if(addr==0)return 0; ConsoleOutput("%p", addr);
//ff cc cc cc,find不到。。 if (addr == 0)
BYTE start[]={XX,0xCC,0xCC,0xCC}; return 0;
addr=reverseFindBytes(start,sizeof(start),addr-0x200,addr,4,true); // ff cc cc cc,find不到。。
ConsoleOutput("%p",addr); BYTE start[] = {XX, 0xCC, 0xCC, 0xCC};
addr = reverseFindBytes(start, sizeof(start), addr - 0x200, addr, 4, true);
ConsoleOutput("%p", addr);
return addr; return addr;
} }
struct emfuncinfo{ struct emfuncinfo
uint64_t type;
int argidx;int padding;
void* hookfunc;
void* filterfun;
const char* _id;
};
std::unordered_map<uintptr_t,emfuncinfo>emfunctionhooks;
bool checkiscurrentgame(const emfuncinfo& em){
auto wininfos=get_proc_windows();
for(auto&& info:wininfos){
if(info.title.find(acastw(em._id))!=info.title.npos)return true;
}
return false;
}
static std::set<std::pair<uintptr_t,uintptr_t>> timeoutbreaks;
void dohookemaddr(uintptr_t em_address,uintptr_t ret){
jitaddraddr(em_address,ret,JITTYPE::RPCS3);
if(emfunctionhooks.find(em_address)==emfunctionhooks.end())return;
if(!(checkiscurrentgame(emfunctionhooks.at(em_address))))return;
timeoutbreaks.insert(std::make_pair(em_address,ret));
auto op=emfunctionhooks.at(em_address);
HookParam hpinternal;
hpinternal.address=ret;
hpinternal.emu_addr=em_address;//用于生成hcode
hpinternal.type=USING_STRING|NO_CONTEXT|BREAK_POINT|op.type;
hpinternal.text_fun=(decltype(hpinternal.text_fun))op.hookfunc;
hpinternal.filter_fun=(decltype(hpinternal.filter_fun))op.filterfun;
hpinternal.argidx=op.argidx;
hpinternal.padding=op.padding;
hpinternal.jittype=JITTYPE::RPCS3;
NewHook(hpinternal,op._id);
}
bool unsafeinithooks(){
//rpcs0.0.30不知道为什么ppu_register_function_at不全。不过看代码得到映射表了直接弄吧。
//rpcs3/Emu/Cell/PPUThread.cpp
// Get pointer to executable cache
/*
static inline u8* ppu_ptr(u32 addr)
{ {
return vm::g_exec_addr + u64{addr} * 2; uint64_t type;
} int argidx;
*/ int padding;
HookParam hp; void *hookfunc;
hp.type=DIRECT_READ; void *filterfun;
hp.address=0x500000000; const char *_id;
hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len) };
{ std::unordered_map<uintptr_t, emfuncinfo> emfunctionhooks;
for(auto [addr,info]:emfunctionhooks){
auto table=addr*2+0x500000000; bool checkiscurrentgame(const emfuncinfo &em)
if(IsBadReadPtr((void*)table,sizeof(uintptr_t)))continue; {
auto funcaddr=*(uintptr_t*)table; auto wininfos = get_proc_windows();
funcaddr&=0x0000ffffffffffff; for (auto &&info : wininfos)
if(!funcaddr)continue; {
auto p=std::make_pair(addr,funcaddr); if (info.title.find(acastw(em._id)) != info.title.npos)
if(timeoutbreaks.find(p)!=timeoutbreaks.end())continue; return true;
dohookemaddr(addr,funcaddr);
delayinsertNewHook(addr);
} }
}; return false;
return NewHook(hp,"g_exec_addr"); }
} static std::set<std::pair<uintptr_t, uintptr_t>> timeoutbreaks;
void dohookemaddr(uintptr_t em_address, uintptr_t ret)
{
jitaddraddr(em_address, ret, JITTYPE::RPCS3);
if (emfunctionhooks.find(em_address) == emfunctionhooks.end())
return;
if (!(checkiscurrentgame(emfunctionhooks.at(em_address))))
return;
timeoutbreaks.insert(std::make_pair(em_address, ret));
auto op = emfunctionhooks.at(em_address);
HookParam hpinternal;
hpinternal.address = ret;
hpinternal.emu_addr = em_address; // 用于生成hcode
hpinternal.type = USING_STRING | NO_CONTEXT | BREAK_POINT | op.type;
hpinternal.text_fun = (decltype(hpinternal.text_fun))op.hookfunc;
hpinternal.filter_fun = (decltype(hpinternal.filter_fun))op.filterfun;
hpinternal.argidx = op.argidx;
hpinternal.padding = op.padding;
hpinternal.jittype = JITTYPE::RPCS3;
NewHook(hpinternal, op._id);
}
bool unsafeinithooks()
{
// rpcs0.0.30不知道为什么ppu_register_function_at不全。不过看代码得到映射表了直接弄吧。
// rpcs3/Emu/Cell/PPUThread.cpp
// Get pointer to executable cache
/*
static inline u8* ppu_ptr(u32 addr)
{
return vm::g_exec_addr + u64{addr} * 2;
}
*/
HookParam hp;
hp.type = DIRECT_READ;
hp.address = 0x500000000;
hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
for (auto [addr, info] : emfunctionhooks)
{
auto table = addr * 2 + 0x500000000;
if (IsBadReadPtr((void *)table, sizeof(uintptr_t)))
continue;
auto funcaddr = *(uintptr_t *)table;
funcaddr &= 0x0000ffffffffffff;
if (!funcaddr)
continue;
auto p = std::make_pair(addr, funcaddr);
if (timeoutbreaks.find(p) != timeoutbreaks.end())
continue;
dohookemaddr(addr, funcaddr);
delayinsertNewHook(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)
dohookemaddr(em_address,entrypoint); return;
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)
{
auto s = std::string((char *)data, *len);
std::regex pattern("\\[[^\\]]+.");
s = std::regex_replace(s, pattern, "");
s = std::regex_replace(s, std::regex("\\\\k|\\\\x|%C|%B"), "");
s = std::regex_replace(s, std::regex("\\%\\d+\\#[0-9a-fA-F]*\\;"), "");
s = std::regex_replace(s, std::regex("\\n+"), " ");
return write_string_overwrite(data, len, s);
}
auto _ = []()
{
emfunctionhooks = {
//'&' -Sora no Mukou de Sakimasu you ni-
{0x46328, {CODEC_UTF8, 1, 0, 0, FBLJM61131, "BLJM61131"}},
// Dunamis15
{0x42c90, {CODEC_UTF8, 1, 0, 0, FBLJM61131, "BLJM60347"}},
bool FBLJM61131(void* data, size_t* len, HookParam* hp){ };
auto s = std::string((char*)data,*len); return 1;
std::regex pattern("\\[[^\\]]+."); }();
s = std::regex_replace(s, pattern, "");
s = std::regex_replace(s, std::regex("\\\\k|\\\\x|%C|%B"), "");
s = std::regex_replace(s, std::regex("\\%\\d+\\#[0-9a-fA-F]*\\;"), "");
s = std::regex_replace(s, std::regex("\\n+"), " ");
return write_string_overwrite(data,len,s);
}
auto _=[](){
emfunctionhooks={
//'&' -Sora no Mukou de Sakimasu you ni-
{0x46328,{CODEC_UTF8,1,0,0,FBLJM61131,"BLJM61131"}},
//Dunamis15
{0x42c90,{CODEC_UTF8,1,0,0,FBLJM61131,"BLJM60347"}},
};
return 1;
}();
} }

View File

@ -1,13 +1,14 @@
class rpcs3:public ENGINE{ class rpcs3 : public ENGINE
public: {
rpcs3(){ public:
rpcs3()
check_by=CHECK_BY::FILE; {
is_engine_certain=false;
check_by_target=L"rpcs3.exe"; check_by = CHECK_BY::FILE;
}; is_engine_certain = false;
bool attach_function(); check_by_target = L"rpcs3.exe";
};
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
@ -19,346 +22,544 @@ namespace{
return symbols[0]; return symbols[0];
} }
*/ */
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; {
int argidx;int padding; uint64_t type;
void* hookfunc; int argidx;
void* filterfun; int padding;
const char* _id; void *hookfunc;
}; void *filterfun;
std::unordered_map<uintptr_t,emfuncinfo>emfunctionhooks; const char *_id;
};
std::unordered_map<uintptr_t, emfuncinfo> emfunctionhooks;
bool checkiscurrentgame(const emfuncinfo& em){ bool checkiscurrentgame(const emfuncinfo &em)
auto wininfos=get_proc_windows(); {
for(auto&& info:wininfos){ auto wininfos = get_proc_windows();
if(info.title.find(acastw(em._id))!=info.title.npos)return true; for (auto &&info : wininfos)
{
if (info.title.find(acastw(em._id)) != info.title.npos)
return true;
}
return false;
} }
return false;
}
} }
bool vita3k::attach_function() 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)
ConsoleOutput("DoJitPtr %p",DoJitPtr); return false;
spDefault.jittype=JITTYPE::VITA3K; ConsoleOutput("DoJitPtr %p", DoJitPtr);
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 entrypoint = *argidx(stack,idxEntrypoint+1); // r9 auto descriptor = *argidx(stack, idxDescriptor + 1); // r8
auto em_address = *(uint32_t*)descriptor; auto entrypoint = *argidx(stack, idxEntrypoint + 1); // r9
if(!entrypoint)return; auto em_address = *(uint32_t *)descriptor;
// ConsoleOutput("%p",em_address); if (!entrypoint)
jitaddraddr(em_address,entrypoint,JITTYPE::VITA3K); return;
[&](){ // ConsoleOutput("%p",em_address);
if(emfunctionhooks.find(em_address)==emfunctionhooks.end())return; jitaddraddr(em_address, entrypoint, JITTYPE::VITA3K);
auto op=emfunctionhooks.at(em_address); [&]()
if(!(checkiscurrentgame(op)))return; {
if (emfunctionhooks.find(em_address) == emfunctionhooks.end())
HookParam hpinternal; return;
hpinternal.address=entrypoint; auto op = emfunctionhooks.at(em_address);
hpinternal.emu_addr=em_address;//用于生成hcode if (!(checkiscurrentgame(op)))
hpinternal.type=USING_STRING|NO_CONTEXT|BREAK_POINT|op.type; return;
hpinternal.text_fun=(decltype(hpinternal.text_fun))op.hookfunc;
hpinternal.filter_fun=(decltype(hpinternal.filter_fun))op.filterfun; HookParam hpinternal;
hpinternal.argidx=op.argidx; hpinternal.address = entrypoint;
hpinternal.padding=op.padding; hpinternal.emu_addr = em_address; // 用于生成hcode
hpinternal.jittype=JITTYPE::VITA3K; hpinternal.type = USING_STRING | NO_CONTEXT | BREAK_POINT | op.type;
NewHook(hpinternal,op._id); hpinternal.text_fun = (decltype(hpinternal.text_fun))op.hookfunc;
}(); hpinternal.filter_fun = (decltype(hpinternal.filter_fun))op.filterfun;
delayinsertNewHook(em_address); hpinternal.argidx = op.argidx;
hpinternal.padding = op.padding;
hpinternal.jittype = JITTYPE::VITA3K;
NewHook(hpinternal, op._id);
}();
delayinsertNewHook(em_address);
}; };
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); {
s = std::regex_replace(s, std::regex("<br>"), ""); auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("%CF11F"), ""); s = std::regex_replace(s, std::regex("<br>"), "");
s = std::regex_replace(s, std::regex("%CFFFF"), ""); s = std::regex_replace(s, std::regex("%CF11F"), "");
s = std::regex_replace(s, std::regex("%K%P"), ""); s = std::regex_replace(s, std::regex("%CFFFF"), "");
s = std::regex_replace(s, std::regex("%K%N"), ""); s = std::regex_replace(s, std::regex("%K%P"), "");
s = std::regex_replace(s, std::regex("\n"), ""); s = std::regex_replace(s, std::regex("%K%N"), "");
return write_string_overwrite(data,len,s); s = std::regex_replace(s, std::regex("\n"), "");
} return write_string_overwrite(data, len, s);
template<int idx> }
bool FPCSG01282(void* data, size_t* len, HookParam* hp){ template <int idx>
auto s = std::string((char*)data,*len); bool FPCSG01282(void *data, size_t *len, HookParam *hp)
s = std::regex_replace(s, std::regex("(\\n)+"), " "); {
s = std::regex_replace(s, std::regex("\\d$|^@[a-z]+|#.*?#|\\$"), ""); auto s = std::string((char *)data, *len);
static std::string last; s = std::regex_replace(s, std::regex("(\\n)+"), " ");
if(last==s)return false; s = std::regex_replace(s, std::regex("\\d$|^@[a-z]+|#.*?#|\\$"), "");
last=s; static std::string last;
return write_string_overwrite(data,len,s); if (last == s)
} return false;
last = s;
template<int index> return write_string_overwrite(data, len, s);
void ReadU16TextAndLenDW(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
auto address=VITA3K::emu_arg(stack)[index];
*len=(*(DWORD*)(address+0x8))*2;
*data=address+0xC;
}
bool FPCSG00410(void* data, size_t* len, HookParam* hp){
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("#Pos\\[[\\s\\S]*?\\]"), "");
s = std::regex_replace(s, std::regex("#n"), " ");
// .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\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);
}
bool FPCSG00448(void* data, size_t* len, HookParam* hp){
auto s = std::string((char*)data,*len);
s = std::regex_replace(s, std::regex("[\\s]"), "");
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("#Pos[\\s\\S]*?\\]"), "");
return write_string_overwrite(data,len,s);
}
bool FPCSG01008(void* data, size_t* len, HookParam* hp){
auto s = std::string((char*)data,*len);
s = std::regex_replace(s, std::regex("#Ruby\\[([^,]+)\\.([^\\]]+)\\]."), "$1");
s = std::regex_replace(s, std::regex("(#n)+"), " ");
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
return write_string_overwrite(data,len,s);
}
void TPCSG00903(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
auto address=VITA3K::emu_arg(stack)[0];
*len=(*(DWORD*)(address+0x14));
*data=address+0x1C;
}
bool FPCSG00903(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 FPCSG00839(void* data, size_t* len, HookParam* hp){
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"\\\\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"\\\\n"), L"");
static std::wstring last;
if(last.find(s)!=last.npos)return false;
last=s;
return write_string_overwrite(data,len,s);
}
bool FPCSG00751(void* data, size_t* len, HookParam* hp){
auto s = std::string((char*)data,*len);
s = std::regex_replace(s, std::regex("[\\s]"), "");
s = std::regex_replace(s, std::regex("@[a-z]"), "");
//s = std::regex_replace(s, std::regex(""), "");
strReplace(s,"\x81\x90","");
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);
s = std::regex_replace(s, std::wregex(L"<br>"), L"");
return write_string_overwrite(data,len,s);
}
bool FPCSG00696(void* data, size_t* len, HookParam* hp){
auto s = std::string((char*)data,*len);
//.replace(/㌔/g, '⁉')
//.replace(/㍉/g, '!!')
strReplace(s,"\x87\x60","");
strReplace(s,"\x87\x5f","");
return write_string_overwrite(data,len,s);
}
bool FPCSG00389(void* data, size_t* len, HookParam* hp){
auto s = std::string((char*)data,*len);
s = std::regex_replace(s, std::regex("[\\s]"), "");
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("#Pos\\[[\\s\\S]*?\\]"), "");
return write_string_overwrite(data,len,s);
}
bool FPCSG00216(void* data, size_t* len, HookParam* hp){
auto s = std::string((char*)data,*len);
s = std::regex_replace(s, std::regex("[\\s]"), "");
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("#Pos\\[[\\s\\S]*?\\]"), "");
return write_string_overwrite(data,len,s);
}
bool FPCSG00405(void* data, size_t* len, HookParam* hp){
auto s = std::string((char*)data,*len);
s = std::regex_replace(s, std::regex("[\\s]"), "");
return write_string_overwrite(data,len,s);
}
bool PCSG00776(void* data, size_t* len, HookParam* hp){
auto s = std::string((char*)data,*len);
auto ws=StringToWideString(s,932).value();
strReplace(ws,L"\x02",L"");
Trim(ws);
return write_string_overwrite(data,len,WideStringToString(ws));
}
void PCSG00911(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
auto address = VITA3K::emu_arg(stack)[1];
std::string final_string = "";
BYTE pattern[] = {0x47,0xff,0xff};
auto results = MemDbg::findBytes(pattern,sizeof(pattern),address,address+0x50);
if (!results) return;
address = results+5;
while (true) {
std::string text= (char*)address;
final_string += text;
address = address+(text.size() + 1);
auto bytes=(BYTE*)address;
if (!(bytes[0] == 0x48 && bytes[1] == 0xFF && bytes[2] == 0xFF)) break;
address = address+(3);
bytes=(BYTE*)address;
if (!(bytes[0] == 0x47 && bytes[1] == 0xFF && bytes[2] == 0xFF)) break;
address = address+(5);
} }
write_string_new(data,len,final_string);
}
void TPCSG00291(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
auto a2= VITA3K::emu_arg(stack)[0];
auto vm = *(DWORD*)(a2+(0x28)); template <int index>
vm=*(DWORD*)VITA3K::emu_addr(stack,vm); void ReadU16TextAndLenDW(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
vm=*(DWORD*)VITA3K::emu_addr(stack,vm+8); {
uintptr_t address=VITA3K::emu_addr(stack,vm); auto address = VITA3K::emu_arg(stack)[index];
auto len1=*(DWORD*)(address+4); *len = (*(DWORD *)(address + 0x8)) * 2;
auto p=address+0x20; *data = address + 0xC;
if(len1>4 && *(WORD*)(p+2)==0){ }
auto p1=*(DWORD*)(address+8);
vm=*(DWORD*)VITA3K::emu_addr(stack,vm);
vm=*(DWORD*)VITA3K::emu_addr(stack,vm+0xC);
p=VITA3K::emu_addr(stack,vm);
}
static int fm=0;
static std::string pre;
auto b=fm;
auto s=[](uintptr_t address){
auto frist = *(WORD*)address;
auto lo = frist & 0xFF; // uppercase: 41->5A
auto hi = frist >> 8;
if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */) {
return std::string();
}
std::string s ;int i = 0;WORD c;
char buf[3]={0};
while ((c = *(WORD*)(address+i)) != 0) {
// reverse endian: ShiftJIS BE => LE
buf[0] = c >> 8;
buf[1] = c & 0xFF;
if (c == 0x815e /* */) { bool FPCSG00410(void *data, size_t *len, HookParam *hp)
s += ' '; // single line {
} auto s = std::string((char *)data, *len);
else if (buf[0] == 0) { s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
//// UTF16 LE turned BE: 5700=>0057, 3100, 3500 s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), "");
//// 4e00 6d00=>PLAYER s = std::regex_replace(s, std::regex("#n"), " ");
// do nothing // .replaceAll("④", "!?").replaceAll("②", "!!").replaceAll("⑥", "。").replaceAll("⑪", "【")
if (buf[1] == 0x4e) { // .replaceAll("⑫", "】").replaceAll("⑤", "、").replaceAll("①", "・・・")
s += "PLAYER"; strReplace(s, "\x87\x43", "!?");
fm++; strReplace(s, "\x87\x41", "!!");
} strReplace(s, "\x87\x45", "\x81\x42");
} strReplace(s, "\x87\x4a", "\x81\x79");
else { strReplace(s, "\x87\x4b", "\x81\x7a");
s+=buf; strReplace(s, "\x87\x44", "\x81\x41");
} strReplace(s, "\x87\x40", "\x81\x45\x81\x45\x81\x45");
i += 2; return write_string_overwrite(data, len, s);
} }
return s; bool FPCSG00448(void *data, size_t *len, HookParam *hp)
}(p); {
if(b>0){ auto s = std::string((char *)data, *len);
fm--; s = std::regex_replace(s, std::regex("[\\s]"), "");
return; s = std::regex_replace(s, std::regex("(#n)+"), "");
} s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
if(s==pre)return ; s = std::regex_replace(s, std::regex("#Pos[\\s\\S]*?\\]"), "");
pre=s; return write_string_overwrite(data, len, s);
write_string_new(data,len,s); }
} bool FPCSG01008(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("#Ruby\\[([^,]+)\\.([^\\]]+)\\]."), "$1");
s = std::regex_replace(s, std::regex("(#n)+"), " ");
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
return write_string_overwrite(data, len, s);
}
void TPCSG00903(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
auto address = VITA3K::emu_arg(stack)[0];
*len = (*(DWORD *)(address + 0x14));
*data = address + 0x1C;
}
bool FPCSG00903(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 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);
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"#[0-9a-fA-F]+;([^%#]+)(%r)?"), L"$1");
s = std::regex_replace(s, std::wregex(L"\\\\n"), L"");
static std::wstring last;
if (last.find(s) != last.npos)
return false;
last = s;
return write_string_overwrite(data, len, s);
}
bool FPCSG00751(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("[\\s]"), "");
s = std::regex_replace(s, std::regex("@[a-z]"), "");
// s = std::regex_replace(s, std::regex(""), "");
strReplace(s, "\x81\x90", "");
return write_string_overwrite(data, len, s);
}
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);
s = std::regex_replace(s, std::wregex(L"<br>"), L"");
return write_string_overwrite(data, len, s);
}
bool FPCSG00696(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
//.replace(/㌔/g, '⁉')
//.replace(/㍉/g, '!!')
strReplace(s, "\x87\x60", "");
strReplace(s, "\x87\x5f", "");
return write_string_overwrite(data, len, s);
}
bool FPCSG00389(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("[\\s]"), "");
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("#Pos\\[[\\s\\S]*?\\]"), "");
return write_string_overwrite(data, len, s);
}
bool FPCSG00216(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("[\\s]"), "");
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("#Pos\\[[\\s\\S]*?\\]"), "");
return write_string_overwrite(data, len, s);
}
bool FPCSG00405(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("[\\s]"), "");
return write_string_overwrite(data, len, s);
}
bool PCSG00776(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
auto ws = StringToWideString(s, 932).value();
strReplace(ws, L"\x02", L"");
Trim(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)
{
auto address = VITA3K::emu_arg(stack)[1];
std::string final_string = "";
BYTE pattern[] = {0x47, 0xff, 0xff};
auto results = MemDbg::findBytes(pattern, sizeof(pattern), address, address + 0x50);
if (!results)
return;
auto _=[](){ address = results + 5;
emfunctionhooks={
//Tsuihou Senkyo
{0x8002e176,{0,0,0,0,FPCSG01023,"PCSG01023"}},//dialogue+name,sjis
//死神と少女 Shinigami to Shoujo
{0x800204ba,{0,2,0,0,FPCSG01282<0>,"PCSG01282"}},//dialogueNVL,sjis
{0x8000f00e,{0,1,0,0,FPCSG01282<1>,"PCSG01282"}},//dialogue main
{0x80011f1a,{0,0,0,0,FPCSG01282<2>,"PCSG01282"}},//Name
{0x8001ebac,{0,1,0,0,FPCSG01282<3>,"PCSG01282"}},//choices
//神凪ノ杜 Kannagi no Mori Satsukiame Tsuzuri
{0x828bb50c,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<0>,0,"PCSG01268"}},//dialogue
{0x828ba9b6,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<0>,0,"PCSG01268"}},//name
{0x8060D376,{CODEC_UTF8,0,0,0,0,"PCSG01268"}},//vita3k v0.2.0 can't find 0x828bb50c && 0x828ba9b6, unknown reason.
//Sanzen Sekai Yuugi ~MultiUniverse Myself~
{0x8005ae24,{0,0,0,0,0,"PCSG01194"}},//dialouge+name,sjis,need remap jis char,to complex
// Marginal #4 Road to Galaxy
{0x8002ff90,{CODEC_UTF8,0,0,0,FPCSG01008,"PCSG01008"}},//text
//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
//New Game! The Challenge Stage!
{0x8012674c,{CODEC_UTF8,0,0,TPCSG00903,FPCSG00903,"PCSG00903"}},
//Kenka Banchou Otome
{0x80009722,{CODEC_UTF16,0,0,0,FPCSG00839,"PCSG00839"}},
//Arcana famiglia -La storia della Arcana Famiglia-
{0x80070e30,{0,2,0,0,FPCSG00751,"PCSG00751"}},//all,sjis
{0x80070cdc,{0,1,0,0,FPCSG00751,"PCSG00751"}},//text
//もし、この世界に神様がいるとするならば。 Moshi, Kono Sekai ni Kami-sama ga Iru to Suru Naraba.
{0x80c1f270,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<0>,FPCSG00706,"PCSG00706"}},//dialogue
{0x80d48bfc,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<1>,FPCSG00706,"PCSG00706"}},//Dictionary1
{0x80d48c20,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<0>,FPCSG00706,"PCSG00706"}},//Dictionary2
//Angelique Retour
{0x8008bd1a,{0,1,0,0,FPCSG00696,"PCSG00696"}},//text1,sjis
{0x8008cd48,{0,0,0,0,FPCSG00696,"PCSG00696"}},//text2
{0x8008f75a,{0,0,0,0,FPCSG00696,"PCSG00696"}},//choice
//Tsuki ni Yorisou Otome no Sahou
{0x8002aefa,{0,2,0,0,0,"PCSG00648"}},//dialogue,sjis
//MARGINAL#4 IDOL OF SUPERNOVA
{0x800718f8,{0,0,0,0,FPCSG00448,"PCSG00448"}},//dialogue,sjis
//Nekketsu Inou Bukatsu-tan Trigger Kiss
{0x8004e44a,{0,0,0,0,FPCSG00410,"PCSG00410"}},//dialogue,sjis
//バイナリースター Binary Star
{0x80058608,{0,1,0,0,FPCSG00389,"PCSG00389"}},//dialogue,sjis
{0x80021292,{0,0,0,0,FPCSG00389,"PCSG00389"}},//name
//Amagami
{0x80070658,{0,0,0,TPCSG00291,0,"PCSG00291"}},
//Rui wa Tomo o Yobu
{0x81003db0,{CODEC_UTF8,1,0,0,FPCSG00839,"PCSG00216"}},//dialogue
//Reine des Fleurs
{0x8001bff2,{0,0,0,0,FPCSG00405,"PCSG00405"}},//dialogue,sjis
//Muv-Luv
{0x80118f10,{0,5,0,0,PCSG00776,"PCSG00776"}},//dialogue, choices
{0x80126e7e,{0,0,0,0,PCSG00776,"PCSG00776"}},//dialogue
//Re:Birthday Song ~Koi o Utau Shinigami~
{0x80033af6,{0,0,2,0,0,"PCSG00911"}},//dialogue
//Un:Birthday Song ~Ai o Utau Shinigami~
{0x80038538,{0,0,0,PCSG00911,0,"PCSG00911"}},
{0x80004b52,{0,3,5,0,0,"PCSG00911"}},
}; while (true)
return 1; {
}(); std::string text = (char *)address;
final_string += text;
address = address + (text.size() + 1);
auto bytes = (BYTE *)address;
if (!(bytes[0] == 0x48 && bytes[1] == 0xFF && bytes[2] == 0xFF))
break;
address = address + (3);
bytes = (BYTE *)address;
if (!(bytes[0] == 0x47 && bytes[1] == 0xFF && bytes[2] == 0xFF))
break;
address = address + (5);
}
write_string_new(data, len, final_string);
}
void TPCSG00291(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
auto a2 = VITA3K::emu_arg(stack)[0];
auto vm = *(DWORD *)(a2 + (0x28));
vm = *(DWORD *)VITA3K::emu_addr(stack, vm);
vm = *(DWORD *)VITA3K::emu_addr(stack, vm + 8);
uintptr_t address = VITA3K::emu_addr(stack, vm);
auto len1 = *(DWORD *)(address + 4);
auto p = address + 0x20;
if (len1 > 4 && *(WORD *)(p + 2) == 0)
{
auto p1 = *(DWORD *)(address + 8);
vm = *(DWORD *)VITA3K::emu_addr(stack, vm);
vm = *(DWORD *)VITA3K::emu_addr(stack, vm + 0xC);
p = VITA3K::emu_addr(stack, vm);
}
static int fm = 0;
static std::string pre;
auto b = fm;
auto s = [](uintptr_t address)
{
auto frist = *(WORD *)address;
auto lo = frist & 0xFF; // uppercase: 41->5A
auto hi = frist >> 8;
if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */)
{
return std::string();
}
std::string s;
int i = 0;
WORD c;
char buf[3] = {0};
while ((c = *(WORD *)(address + i)) != 0)
{
// reverse endian: ShiftJIS BE => LE
buf[0] = c >> 8;
buf[1] = c & 0xFF;
if (c == 0x815e /* */)
{
s += ' '; // single line
}
else if (buf[0] == 0)
{
//// UTF16 LE turned BE: 5700=>0057, 3100, 3500
//// 4e00 6d00=>PLAYER
// do nothing
if (buf[1] == 0x4e)
{
s += "PLAYER";
fm++;
}
}
else
{
s += buf;
}
i += 2;
}
return s;
}(p);
if (b > 0)
{
fm--;
return;
}
if (s == pre)
return;
pre = s;
write_string_new(data, len, s);
}
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 = {
// Tsuihou Senkyo
{0x8002e176, {0, 0, 0, 0, FPCSG01023, "PCSG01023"}}, // dialogue+name,sjis
// 死神と少女 Shinigami to Shoujo
{0x800204ba, {0, 2, 0, 0, FPCSG01282<0>, "PCSG01282"}}, // dialogueNVL,sjis
{0x8000f00e, {0, 1, 0, 0, FPCSG01282<1>, "PCSG01282"}}, // dialogue main
{0x80011f1a, {0, 0, 0, 0, FPCSG01282<2>, "PCSG01282"}}, // Name
{0x8001ebac, {0, 1, 0, 0, FPCSG01282<3>, "PCSG01282"}}, // choices
// 神凪ノ杜 Kannagi no Mori Satsukiame Tsuzuri
{0x828bb50c, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<0>, 0, "PCSG01268"}}, // dialogue
{0x828ba9b6, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<0>, 0, "PCSG01268"}}, // name
{0x8060D376, {CODEC_UTF8, 0, 0, 0, 0, "PCSG01268"}}, // vita3k v0.2.0 can't find 0x828bb50c && 0x828ba9b6, unknown reason.
// Sanzen Sekai Yuugi ~MultiUniverse Myself~
{0x8005ae24, {0, 0, 0, 0, 0, "PCSG01194"}}, // dialouge+name,sjis,need remap jis char,to complex
// Marginal #4 Road to Galaxy
{0x8002ff90, {CODEC_UTF8, 0, 0, 0, FPCSG01008, "PCSG01008"}}, // text
// BLACK WOLVES SAGA -Weiβ und Schwarz-
{0x800581a2, {CODEC_UTF8, 0, 0, 0, FPCSG01008, "PCSG00935"}}, // text
// New Game! The Challenge Stage!
{0x8012674c, {CODEC_UTF8, 0, 0, TPCSG00903, FPCSG00903, "PCSG00903"}},
// Kenka Banchou Otome
{0x80009722, {CODEC_UTF16, 0, 0, 0, FPCSG00839, "PCSG00839"}},
// Arcana famiglia -La storia della Arcana Famiglia-
{0x80070e30, {0, 2, 0, 0, FPCSG00751, "PCSG00751"}}, // all,sjis
{0x80070cdc, {0, 1, 0, 0, FPCSG00751, "PCSG00751"}}, // text
// もし、この世界に神様がいるとするならば。 Moshi, Kono Sekai ni Kami-sama ga Iru to Suru Naraba.
{0x80c1f270, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<0>, FPCSG00706, "PCSG00706"}}, // dialogue
{0x80d48bfc, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<1>, FPCSG00706, "PCSG00706"}}, // Dictionary1
{0x80d48c20, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<0>, FPCSG00706, "PCSG00706"}}, // Dictionary2
// Angelique Retour
{0x8008bd1a, {0, 1, 0, 0, FPCSG00696, "PCSG00696"}}, // text1,sjis
{0x8008cd48, {0, 0, 0, 0, FPCSG00696, "PCSG00696"}}, // text2
{0x8008f75a, {0, 0, 0, 0, FPCSG00696, "PCSG00696"}}, // choice
// Tsuki ni Yorisou Otome no Sahou
{0x8002aefa, {0, 2, 0, 0, 0, "PCSG00648"}}, // dialogue,sjis
// MARGINAL#4 IDOL OF SUPERNOVA
{0x800718f8, {0, 0, 0, 0, FPCSG00448, "PCSG00448"}}, // dialogue,sjis
// Nekketsu Inou Bukatsu-tan Trigger Kiss
{0x8004e44a, {0, 0, 0, 0, FPCSG00410, "PCSG00410"}}, // dialogue,sjis
// バイナリースター Binary Star
{0x80058606, {0, 1, 0xd, 0, FPCSG00389, "PCSG00389"}}, // dialogue,sjis
// Amagami
{0x80070658, {0, 0, 0, TPCSG00291, 0, "PCSG00291"}},
// Rui wa Tomo o Yobu
{0x81003db0, {CODEC_UTF8, 1, 0, 0, FPCSG00839, "PCSG00216"}}, // dialogue
// Reine des Fleurs
{0x8001bff2, {0, 0, 0, 0, FPCSG00405, "PCSG00405"}}, // dialogue,sjis
// Muv-Luv
{0x80118f10, {0, 5, 0, 0, PCSG00776, "PCSG00776"}}, // dialogue, choices
{0x80126e7e, {0, 0, 0, 0, PCSG00776, "PCSG00776"}}, // dialogue
// Re:Birthday Song ~Koi o Utau Shinigami~
{0x80033af6, {0, 0, 2, 0, 0, "PCSG00911"}}, // dialogue
// Un:Birthday Song ~Ai o Utau Shinigami~
{0x80038538, {0, 0, 0, PCSG00912, 0, "PCSG00912"}},
{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;
}();
} }

View File

@ -1,13 +1,14 @@
class vita3k:public ENGINE{ class vita3k : public ENGINE
public: {
vita3k(){ public:
vita3k()
check_by=CHECK_BY::FILE; {
is_engine_certain=false;
check_by_target=L"Vita3K.exe"; check_by = CHECK_BY::FILE;
}; is_engine_certain = false;
bool attach_function(); check_by_target = L"Vita3K.exe";
};
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,329 +1,377 @@
#include<queue> #include <queue>
#include"emujitarg.hpp" #include "emujitarg.hpp"
namespace ppsspp{ namespace ppsspp
bool ULJS00403_filter(void* data, size_t* len, HookParam* hp){ {
std::string result = std::string((char*)data,*len); bool ULJS00403_filter(void *data, size_t *len, HookParam *hp)
std::regex newlinePattern(R"((\\n)+)"); {
result = std::regex_replace(result, newlinePattern, " "); std::string result = std::string((char *)data, *len);
std::regex pattern(R"((\\d$|^\@[a-z]+|#.*?#|\$))"); std::regex newlinePattern(R"((\\n)+)");
result = std::regex_replace(result, pattern, ""); result = std::regex_replace(result, newlinePattern, " ");
return write_string_overwrite(data,len,result); std::regex pattern(R"((\\d$|^\@[a-z]+|#.*?#|\$))");
} result = std::regex_replace(result, pattern, "");
return write_string_overwrite(data, len, result);
void ULJS00339(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
auto a2= PPSSPP::emu_arg(stack)[0];
auto vm = *(DWORD*)(a2+(0x28));
vm=*(DWORD*)PPSSPP::emu_addr(stack,vm);
vm=*(DWORD*)PPSSPP::emu_addr(stack,vm+8);
uintptr_t address=PPSSPP::emu_addr(stack,vm);
auto len1=*(DWORD*)(address+4);
auto p=address+0x20;
if(len1>4 && *(WORD*)(p+2)==0){
auto p1=*(DWORD*)(address+8);
vm=*(DWORD*)PPSSPP::emu_addr(stack,vm);
vm=*(DWORD*)PPSSPP::emu_addr(stack,vm+0xC);
p=PPSSPP::emu_addr(stack,vm);
} }
static int fm=0;
static std::string pre;
auto b=fm;
auto s=[](uintptr_t address){
auto frist = *(WORD*)address;
auto lo = frist & 0xFF; // uppercase: 41->5A
auto hi = frist >> 8;
if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */) {
return std::string();
}
std::string s ;int i = 0;WORD c;
char buf[3]={0};
while ((c = *(WORD*)(address+i)) != 0) {
// reverse endian: ShiftJIS BE => LE
buf[0] = c >> 8;
buf[1] = c & 0xFF;
if (c == 0x815e /* */) { void ULJS00339(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
s += ' '; // single line {
auto a2 = PPSSPP::emu_arg(stack)[0];
auto vm = *(DWORD *)(a2 + (0x28));
vm = *(DWORD *)PPSSPP::emu_addr(stack, vm);
vm = *(DWORD *)PPSSPP::emu_addr(stack, vm + 8);
uintptr_t address = PPSSPP::emu_addr(stack, vm);
auto len1 = *(DWORD *)(address + 4);
auto p = address + 0x20;
if (len1 > 4 && *(WORD *)(p + 2) == 0)
{
auto p1 = *(DWORD *)(address + 8);
vm = *(DWORD *)PPSSPP::emu_addr(stack, vm);
vm = *(DWORD *)PPSSPP::emu_addr(stack, vm + 0xC);
p = PPSSPP::emu_addr(stack, vm);
}
static int fm = 0;
static std::string pre;
auto b = fm;
auto s = [](uintptr_t address)
{
auto frist = *(WORD *)address;
auto lo = frist & 0xFF; // uppercase: 41->5A
auto hi = frist >> 8;
if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */)
{
return std::string();
} }
else if (buf[0] == 0) { std::string s;
//// UTF16 LE turned BE: 5700=>0057, 3100, 3500 int i = 0;
//// 4e00 6d00=>PLAYER WORD c;
// do nothing char buf[3] = {0};
if (buf[1] == 0x4e) { while ((c = *(WORD *)(address + i)) != 0)
s += "PLAYER"; {
fm++; // reverse endian: ShiftJIS BE => LE
buf[0] = c >> 8;
buf[1] = c & 0xFF;
if (c == 0x815e /* */)
{
s += ' '; // single line
}
else if (buf[0] == 0)
{
//// UTF16 LE turned BE: 5700=>0057, 3100, 3500
//// 4e00 6d00=>PLAYER
// do nothing
if (buf[1] == 0x4e)
{
s += "PLAYER";
fm++;
}
}
else
{
s += buf;
}
i += 2;
}
return s;
}(p);
if (b > 0)
{
fm--;
return;
}
if (s == pre)
return;
pre = s;
write_string_new(data, len, s);
}
bool NPJH50909_filter(void *data, size_t *len, HookParam *hp)
{
std::string result = std::string((char *)data, *len);
auto ws = StringToWideString(result, 932).value();
// Remove single line markers
ws = std::regex_replace(ws, std::wregex(L"(\\%N)+"), L" ");
// Remove scale marker
ws = std::regex_replace(ws, std::wregex(L"\\%\\@\\%\\d+"), L"");
// Reformat name
std::wsmatch match;
if (std::regex_search(ws, match, std::wregex(L"(^[^「]+)「")))
{
std::wstring name = match[1].str();
ws = std::regex_replace(ws, std::wregex(L"^[^「]+"), L"");
ws = name + L"\n" + ws;
}
return write_string_overwrite(data, len, WideStringToString(ws, 932));
}
bool ULJM06119_filter(void *data, size_t *len, HookParam *hp)
{
std::string s = std::string((char *)data, *len);
std::regex pattern(R"(/\[[^\]]+./g)");
s = std::regex_replace(s, pattern, "");
std::regex tagPattern(R"(/\\k|\\x|%C|%B)");
s = std::regex_replace(s, tagPattern, "");
std::regex colorPattern(R"(/\%\d+\#[0-9a-fA-F]*\;)");
s = std::regex_replace(s, colorPattern, "");
std::regex newlinePattern(R"(/\n+)");
s = std::regex_replace(s, newlinePattern, " ");
return write_string_overwrite(data, len, s);
}
bool ULJM06036_filter(void *data, size_t *len, HookParam *hp)
{
std::wstring result = std::wstring((wchar_t *)data, *len / 2);
std::wregex pattern(LR"(<R([^\/]+).([^>]+).>)");
result = std::regex_replace(result, pattern, L"$2");
std::wregex tagPattern(LR"(<[A-Z]+>)");
result = std::regex_replace(result, tagPattern, L"");
return write_string_overwrite(data, len, result);
}
namespace Corda
{
std::string readBinaryString(uintptr_t address, bool *haveName)
{
*haveName = false;
if ((*(WORD *)address & 0xF0FF) == 0x801b)
{
*haveName = true;
address = address + 2; // (1)
}
std::string s;
int i = 0;
uint8_t c;
while ((c = *(uint8_t *)(address + i)) != 0)
{
if (c == 0x1b)
{
if (*haveName)
return s; // (1) skip junk after name
c = *(uint8_t *)(address + (i + 1));
if (c == 0x7f)
i += 5;
else
i += 2;
}
else if (c == 0x0a)
{
s += '\n';
i += 1;
}
else if (c == 0x20)
{
s += ' ';
i += 1;
}
else
{
auto len = 1 + (IsDBCSLeadByteEx(932, *(BYTE *)(address + i)));
s += std::string((char *)(address + i), len);
i += len; // encoder.encode(c).byteLength;
} }
} }
else { return s;
s+=buf;
}
i += 2;
} }
return s;
}(p);
if(b>0){
fm--;
return;
} }
if(s==pre)return ;
pre=s;
write_string_new(data,len,s);
}
void ULJM05428(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
auto address = PPSSPP::emu_arg(stack)[1];
bool haveNamve;
auto s = Corda::readBinaryString(address, &haveNamve);
*split = haveNamve;
write_string_new(data, len, s);
}
bool NPJH50909_filter(void* data, size_t* len, HookParam* hp){ void ULJM05054(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
std::string result = std::string((char*)data,*len); {
auto ws=StringToWideString(result,932).value(); if (hp->emu_addr != 0x886162c)
// Remove single line markers {
ws = std::regex_replace(ws, std::wregex(L"(\\%N)+"), L" "); auto addr = PPSSPP::emu_arg(stack)[0] + 0x3c;
*data = addr;
// Remove scale marker *len = strlen((char *)addr);
ws = std::regex_replace(ws, std::wregex(L"\\%\\@\\%\\d+"), L""); return;
// Reformat name
std::wsmatch match;
if (std::regex_search(ws, match, std::wregex(L"(^[^「]+)「"))) {
std::wstring name = match[1].str();
ws = std::regex_replace(ws, std::wregex(L"^[^「]+"), L"");
ws = name + L"\n" + ws;
}
return write_string_overwrite(data,len,WideStringToString(ws,932));
}
bool ULJM06119_filter(void* data, size_t* len, HookParam* hp){
std::string s = std::string((char*)data,*len);
std::regex pattern(R"(/\[[^\]]+./g)");
s = std::regex_replace(s, pattern, "");
std::regex tagPattern(R"(/\\k|\\x|%C|%B)");
s = std::regex_replace(s, tagPattern, "");
std::regex colorPattern(R"(/\%\d+\#[0-9a-fA-F]*\;)");
s = std::regex_replace(s, colorPattern, "");
std::regex newlinePattern(R"(/\n+)");
s = std::regex_replace(s, newlinePattern, " ");
return write_string_overwrite(data,len,s);
}
bool ULJM06036_filter(void* data, size_t* len, HookParam* hp){
std::wstring result = std::wstring((wchar_t*)data,*len/2);
std::wregex pattern(LR"(<R([^\/]+).([^>]+).>)");
result = std::regex_replace(result, pattern, L"$2");
std::wregex tagPattern(LR"(<[A-Z]+>)");
result = std::regex_replace(result, tagPattern, L"");
return write_string_overwrite(data,len,result);
}
namespace Corda{
std::string readBinaryString(uintptr_t address,bool* haveName){
* haveName=false;
if ((*(WORD*)address & 0xF0FF) == 0x801b) {
*haveName = true;
address = address+2; // (1)
}
std::string s;int i=0;uint8_t c;
while ((c = *(uint8_t*)(address+i)) != 0) {
if (c == 0x1b) {
if (*haveName)
return s; // (1) skip junk after name
c = *(uint8_t*)(address+(i + 1));
if (c == 0x7f)
i += 5;
else
i += 2;
}
else if (c == 0x0a) {
s += '\n';
i += 1;
}
else if (c == 0x20) {
s += ' ';
i += 1;
}
else {
auto len=1+(IsDBCSLeadByteEx(932,*(BYTE*)(address+i)));
s += std::string((char*)(address+i),len);
i += len;//encoder.encode(c).byteLength;
}
} }
return s; auto address = PPSSPP::emu_arg(stack)[1];
bool haveNamve;
auto s = Corda::readBinaryString(address, &haveNamve);
*split = haveNamve;
write_string_new(data, len, s);
} }
}
void ULJM05428(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ bool ULJM05943F(void *data, size_t *len, HookParam *hp)
auto address= PPSSPP::emu_arg(stack)[1]; {
bool haveNamve; auto s = std::string((char *)data, *len);
auto s=Corda::readBinaryString(address,&haveNamve); std::regex pattern1("#n+");
*split=haveNamve; std::string replacement1 = " ";
write_string_new(data,len,s); std::string result1 = std::regex_replace(s, pattern1, replacement1);
} std::regex pattern2("#[A-Za-z]+\\[(\\d*\\.)?\\d+\\]+");
std::string replacement2 = "";
std::string result2 = std::regex_replace(result1, pattern2, replacement2);
return write_string_overwrite(data, len, result2);
}
void ULJM05054(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ bool FULJM05603(LPVOID data, size_t *size, HookParam *)
if (hp->emu_addr != 0x886162c) { {
auto addr=PPSSPP::emu_arg(stack)[0]+0x3c; auto text = reinterpret_cast<LPSTR>(data);
*data=addr;*len=strlen((char*)addr); auto len = reinterpret_cast<size_t *>(size);
return;
}
auto address= PPSSPP::emu_arg(stack)[1];
bool haveNamve;
auto s=Corda::readBinaryString(address,&haveNamve);
*split=haveNamve;
write_string_new(data,len,s);
}
StringCharReplacer(text, len, "%N", 2, ' ');
StringFilter(text, len, "%K", 2);
StringFilter(text, len, "%P", 2);
bool ULJM05943F(void* data, size_t* len, HookParam* hp){ return true;
auto s = std::string((char*)data,*len); }
std::regex pattern1("#n+"); namespace NPJH50530
std::string replacement1 = " "; {
std::string result1 = std::regex_replace(s, pattern1, replacement1); std::string current;
std::regex pattern2("#[A-Za-z]+\\[(\\d*\\.)?\\d+\\]+"); bool T(LPVOID data, size_t *size, HookParam *)
std::string replacement2 = ""; {
std::string result2 = std::regex_replace(result1, pattern2, replacement2); current = std::string((char *)data, *size);
return write_string_overwrite(data,len,result2); return true;
} }
bool N(LPVOID data, size_t *size, HookParam *)
bool FULJM05603(LPVOID data, size_t* size, HookParam*) {
{ auto current1 = std::string((char *)data, *size);
auto text = reinterpret_cast<LPSTR>(data); return current != current1;
auto len = reinterpret_cast<size_t*>(size);
StringCharReplacer(text, len, "%N", 2, ' ');
StringFilter(text, len, "%K", 2);
StringFilter(text, len, "%P", 2);
return true;
}
namespace NPJH50530{
std::string current;
bool T(LPVOID data, size_t* size, HookParam*)
{
current=std::string((char*)data,*size);
return true;
}
bool N(LPVOID data, size_t* size, HookParam*)
{
auto current1=std::string((char*)data,*size);
return current!=current1;
}
}
bool FULJM05889(LPVOID data, size_t* size, HookParam*)
{
auto text = reinterpret_cast<LPSTR>(data);
auto len = reinterpret_cast<size_t*>(size);
for(size_t i=0;i<*len;){
if(IsDBCSLeadByteEx(932,(text[i]))){
i+=2;
continue;
} }
if(text[i]=='^')
text[i]='\n';
i+=1;
} }
return true; 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 *)
{
auto text = reinterpret_cast<LPSTR>(data);
auto len = reinterpret_cast<size_t *>(size);
for (size_t i = 0; i < *len;)
{
if (IsDBCSLeadByteEx(932, (text[i])))
{
i += 2;
continue;
}
if (text[i] == '^')
text[i] = '\n';
bool NPJH50619F(void* data, size_t* len, HookParam* hp){ i += 1;
auto s = std::string((char*)data,*len); }
std::regex pattern1("[\\r\\n]+"); return true;
std::string replacement1 = ""; }
std::string result1 = std::regex_replace(s, pattern1, replacement1);
std::regex pattern2("^(.*?)\\)+");
std::string replacement2 = "";
std::string result2 = std::regex_replace(result1, pattern2, replacement2);
std::regex pattern3("#ECL+");
std::string replacement3 = "";
std::string result3 = std::regex_replace(result2, pattern3, replacement3);
std::regex pattern4("(#.+?\\))+");
std::string replacement4 = "";
std::string result4 = std::regex_replace(result3, pattern4, replacement4);
return write_string_overwrite(data,len,result4);
}
bool NPJH50619F(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
std::regex pattern1("[\\r\\n]+");
std::string replacement1 = "";
std::string result1 = std::regex_replace(s, pattern1, replacement1);
std::regex pattern2("^(.*?)\\)+");
std::string replacement2 = "";
std::string result2 = std::regex_replace(result1, pattern2, replacement2);
std::regex pattern3("#ECL+");
std::string replacement3 = "";
std::string result3 = std::regex_replace(result2, pattern3, replacement3);
std::regex pattern4("(#.+?\\))+");
std::string replacement4 = "";
std::string result4 = std::regex_replace(result3, pattern4, replacement4);
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::string replacement2 = "";
std::string result2 = std::regex_replace(s, pattern2, replacement2);
std::regex pattern3("#FAMILY"); std::regex pattern2("#RUBS(#[A-Z0-9]+)*[^#]+");
std::string replacement3 = "$FAMILY"; std::string replacement2 = "";
std::string result3 = std::regex_replace(result2, pattern3, replacement3); std::string result2 = std::regex_replace(s, pattern2, replacement2);
std::regex pattern4("#GIVE"); std::regex pattern3("#FAMILY");
std::string replacement4 = "$GIVE"; std::string replacement3 = "$FAMILY";
std::string result4 = std::regex_replace(result3, pattern4, replacement4); std::string result3 = std::regex_replace(result2, pattern3, replacement3);
std::regex pattern5("(#[A-Z0-9\\-]+)+"); std::regex pattern4("#GIVE");
std::string replacement5 = ""; std::string replacement4 = "$GIVE";
std::string result5 = std::regex_replace(result4, pattern5, replacement5); std::string result4 = std::regex_replace(result3, pattern4, replacement4);
std::regex pattern6("\\n+"); std::regex pattern5("(#[A-Z0-9\\-]+)+");
std::string replacement6 = " "; std::string replacement5 = "";
std::string result6 = std::regex_replace(result5, pattern6, replacement6); std::string result5 = std::regex_replace(result4, pattern5, replacement5);
return write_string_overwrite(data,len,result6); std::regex pattern6("\\n+");
} std::string replacement6 = " ";
std::string result6 = std::regex_replace(result5, pattern6, replacement6);
return write_string_overwrite(data, len, result6);
}
void QNPJH50909(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
uintptr_t addr = PPSSPP::emu_addr(stack, 0x08975110);
*data = addr + 0x20;
*len = *(DWORD *)(addr + 0x14) * 2;
if (0x6e87 == *(WORD *)*data)
*len = 0;
if (0x000a == *(WORD *)*data)
*len = 0;
}
std::unordered_map<uintptr_t, emfuncinfo> emfunctionhooks = {
// Shinigami to Shoujo
{0x883bf34, {0, 1, 0, 0, ULJS00403_filter, "ULJS00403"}},
// Amagami
{0x0886775c, {0, 0, 0, ULJS00339, 0, "ULJS00339"}}, // String.length()
// Sekai de Ichiban Dame na Koi
{0x8814adc, {0, 0, 0, 0, NPJH50909_filter, "ULJM05878"}}, // name + dialouge
{0x8850b2c, {0, 0, 0, 0, NPJH50909_filter, "ULJM05878"}}, // onscreen toast
// Dunamis15
{0x0891D72C, {CODEC_UTF8, 0, 0, 0, ULJM06119_filter, "ULJM06119"}},
// Princess Evangile Portable
{0x88506d0, {CODEC_UTF16, 2, 0, 0, ULJM06036_filter, "ULJM06036"}}, // [0x88506d0(2)...0x088507C0(?)] // name text text (line doubled)
// Kin'iro no Corda 2f
{0x89b59dc, {0, 0, 0, ULJM05428, 0, "ULJM05428"}},
// Kin'iro no Corda
{0x886162c, {0, 0, 0, ULJM05054, 0, "ULJM05054"}}, // dialogue: 0x886162c (x1), 0x889d5fc-0x889d520(a2) fullLine
{0x8899e90, {0, 0, 0, ULJM05054, 0, "ULJM05054"}}, // name 0x88da57c, 0x8899ca4 (x0, oneTime), 0x8899e90
// Sol Trigger
{0x8952cfc, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // dialog
{0x884aad4, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // description
{0x882e1b0, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // system
{0x88bb108, {CODEC_UTF8, 2, 0, 0, NPJH50619F, "NPJH50619"}}, // battle tutorial
{0x89526a0, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // battle info
{0x88bcef8, {CODEC_UTF8, 1, 0, 0, NPJH50619F, "NPJH50619"}}, // battle talk
// Fate/EXTRA CCC
{0x8958490, {0, 0, 0, 0, NPJH50505F, "NPJH50505"}},
// Kamigami no Asobi InFinite
{0x088630f8, {0, 0, 0, QNPJH50909, 0, "NPJH50909"}}, // text, choice (debounce trailing 400ms), TODO: better hook
{0x0887813c, {0, 3, 4, 0, 0, "NPJH50909"}}, // Question YN
// Gekka Ryouran Romance
{0x88eeba4, {0, 0, 0, 0, ULJM05943F, "ULJM05943"}}, // a0 - monologue text
{0x8875e0c, {0, 1, 6, 0, ULJM05943F, "ULJM05943"}}, // a1 - dialogue text
// My Merry May with be
{0x886F014, {0, 3, 0, 0, FULJM05603, "ULJM05603"}},
// Corpse Party -The Anthology- Sachiko no Ren'ai Yuugi ♥ Hysteric Birthday 2U - Regular Edition
{0x88517C8, {0, 1, 0, 0, FULJM05603, "ULJM06114"}},
// Himawari_no_Kyoukai_to_Nagai_Natsuyasumi_Extra_Vacation_JPN_PSP-MOEMOE
{0x881c444, {FULL_STRING, 0, 0, 0, 0, "ULJM06321"}}, // name+text,sjit,FULL_STRING to split name and text
// ましろ色シンフォニー *mutsu-no-hana
{0x8868AB8, {0, 0, 0, 0, FULJM05889, "ULJM05889"}},
// シャイニング・ブレイド
{0x8AA3B70, {0, 0xC, 0, 0, NPJH50530::T, "NPJH50530"}}, // text only
{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"}},
};
void QNPJH50909(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
uintptr_t addr = PPSSPP::emu_addr(stack,0x08975110);
*data=addr+0x20;
*len=*(DWORD*)(addr+0x14)*2;
if(0x6e87==*(WORD*)*data)*len=0;
if(0x000a==*(WORD*)*data)*len=0;
}
std::unordered_map<uintptr_t,emfuncinfo>emfunctionhooks= {
//Shinigami to Shoujo
{0x883bf34,{0,1,0,0,ULJS00403_filter,"ULJS00403"}},
//Amagami
{0x0886775c,{0,0,0,ULJS00339,0,"ULJS00339"}},// String.length()
//Sekai de Ichiban Dame na Koi
{0x8814adc,{0,0,0,0,NPJH50909_filter,"ULJM05878"}},// name + dialouge
{0x8850b2c,{0,0,0,0,NPJH50909_filter,"ULJM05878"}},// onscreen toast
//Dunamis15
{0x0891D72C,{CODEC_UTF8,0,0,0,ULJM06119_filter,"ULJM06119"}},
//Princess Evangile Portable
{0x88506d0,{CODEC_UTF16,2,0,0,ULJM06036_filter,"ULJM06036"}},// [0x88506d0(2)...0x088507C0(?)] // name text text (line doubled)
//Kin'iro no Corda 2f
{0x89b59dc,{0,0,0,ULJM05428,0,"ULJM05428"}},
//Kin'iro no Corda
{0x886162c,{0,0,0,ULJM05054,0,"ULJM05054"}},// dialogue: 0x886162c (x1), 0x889d5fc-0x889d520(a2) fullLine
{0x8899e90,{0,0,0,ULJM05054,0,"ULJM05054"}},// name 0x88da57c, 0x8899ca4 (x0, oneTime), 0x8899e90
//Sol Trigger
{0x8952cfc,{CODEC_UTF8,0,0,0,NPJH50619F,"NPJH50619"}},//dialog
{0x884aad4,{CODEC_UTF8,0,0,0,NPJH50619F,"NPJH50619"}},//description
{0x882e1b0,{CODEC_UTF8,0,0,0,NPJH50619F,"NPJH50619"}},//system
{0x88bb108,{CODEC_UTF8,2,0,0,NPJH50619F,"NPJH50619"}},//battle tutorial
{0x89526a0,{CODEC_UTF8,0,0,0,NPJH50619F,"NPJH50619"}},//battle info
{0x88bcef8,{CODEC_UTF8,1,0,0,NPJH50619F,"NPJH50619"}},//battle talk
//Fate/EXTRA CCC
{0x8958490,{0,0,0,0,NPJH50505F,"NPJH50505"}},
//Kamigami no Asobi InFinite
{0x088630f8,{0,0,0,QNPJH50909,0,"NPJH50909"}}, // text, choice (debounce trailing 400ms), TODO: better hook
{0x0887813c,{0,3,4,0,0,"NPJH50909"}}, // Question YN
//Gekka Ryouran Romance
{0x88eeba4,{0,0,0,0,ULJM05943F,"ULJM05943"}},// a0 - monologue text
{0x8875e0c,{0,1,6,0,ULJM05943F,"ULJM05943"}},// a1 - dialogue text
//My Merry May with be
{0x886F014,{0,3,0,0,FULJM05603,"ULJM05603"}},
//Corpse Party -The Anthology- Sachiko no Ren'ai Yuugi ♥ Hysteric Birthday 2U - Regular Edition
{0x88517C8,{0,1,0,0,FULJM05603,"ULJM06114"}},
//Himawari_no_Kyoukai_to_Nagai_Natsuyasumi_Extra_Vacation_JPN_PSP-MOEMOE
{0x881c444,{FULL_STRING,0,0,0,0,"ULJM06321"}},//name+text,sjit,FULL_STRING to split name and text
//ましろ色シンフォニー *mutsu-no-hana
{0x8868AB8,{0,0,0,0,FULJM05889,"ULJM05889"}},
//シャイニング・ブレイド
{0x8AA3B70,{0,0xC,0,0,NPJH50530::T,"NPJH50530"}},//text only
{0x884DB44,{0,1,0,0,NPJH50530::N,"NPJH50530"}},//text+name
};
} }

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

@ -464,7 +464,7 @@ std::array<InfoForExtension, 20> Pluginmanager::GetSentenceInfo(TextThread &thre
static DWORD SelectedProcessId; static DWORD SelectedProcessId;
auto currthread = (TextThread *)host->currentselect; auto currthread = (TextThread *)host->currentselect;
SelectedProcessId = (currthread != 0) ? currthread->tp.processId : 0; SelectedProcessId = (currthread != 0) ? currthread->tp.processId : 0;
DWORD (*GetSelectedProcessId) DWORD(*GetSelectedProcessId)
() = [] () = []
{ return SelectedProcessId; }; { return SelectedProcessId; };

View File

@ -35,7 +35,7 @@ struct plugindata
VisSetting_t VisSetting; VisSetting_t VisSetting;
HMODULE hmodule; HMODULE hmodule;
void clear(); void clear();
plugindata(){}; plugindata() {};
plugindata(const std::wstring &, Pluginmanager *, bool, HMODULE); plugindata(const std::wstring &, Pluginmanager *, bool, HMODULE);
bool valid(); bool valid();
void initstatus(const pluginitem &); void initstatus(const pluginitem &);

View File

@ -2,15 +2,14 @@
#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);
_setmode(_fileno(stdin), _O_U16TEXT); _setmode(_fileno(stdin), _O_U16TEXT);
wprintf_s(L"Usage: {'attach'|'detach'|hookcode} -Pprocessid\n"); wprintf_s(L"Usage: {'attach'|'detach'|hookcode} -Pprocessid\n");
fflush(stdout); fflush(stdout);
Host::Start([](auto) {}, [](auto) {}, [](auto&) {}, [](auto&) {}, [](TextThread& thread, std::wstring& output) Host::Start([](auto) {}, [](auto) {}, [](auto &) {}, [](auto &) {}, [](TextThread &thread, std::wstring &output)
{ {
wprintf_s(L"[%I64X:%I32X:%I64X:%I64X:%I64X:%s:%s] %s\n", wprintf_s(L"[%I64X:%I32X:%I64X:%I64X:%I64X:%s:%s] %s\n",
thread.handle, thread.handle,
thread.tp.processId, thread.tp.processId,
@ -22,53 +21,67 @@ 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]"))) {
hooks->push_back(std::wstring(hp.hookcode) + L"=>" + text + L"\n"); if (std::regex_search(text, std::wregex(L"[\u3000-\ua000]")))
{
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();
FILE* out = fopen("hook.txt", "a+,ccs=UTF-8"); FILE* out = fopen("hook.txt", "a+,ccs=UTF-8");
@ -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

@ -1,20 +1,19 @@
#include "host.h" #include "host.h"
typedef LONG NTSTATUS; typedef LONG NTSTATUS;
#include"yapi.hpp" #include "yapi.hpp"
#include"Lang/Lang.h" #include "Lang/Lang.h"
namespace 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))
{
{ embedsharedmem = (EmbedSharedMem *)MapViewOfFile(mappedFile2, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, sizeof(EmbedSharedMem));
embedsharedmem=(EmbedSharedMem*)MapViewOfFile(mappedFile2, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(EmbedSharedMem)); // 放到构造表里就不行,不知道为何。
//放到构造表里就不行,不知道为何。
} }
~ProcessRecord() ~ProcessRecord()
@ -27,18 +26,17 @@ 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)
{ {
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;
@ -51,13 +49,16 @@ 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::HookInsertHandler HookInsert=0; Host::ConsoleHandler OnWarning = 0;
Host::EmbedCallback embedcallback=0; Host::HookInsertHandler HookInsert = 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);
@ -76,14 +77,14 @@ namespace
void CreatePipe(int pid) void CreatePipe(int pid)
{ {
HANDLE HANDLE
hookPipe = CreateNamedPipeW((std::wstring(HOOK_PIPE)+std::to_wstring(pid)).c_str(), PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, 0, PIPE_BUFFER_SIZE, MAXDWORD, &allAccess), hookPipe = CreateNamedPipeW((std::wstring(HOOK_PIPE) + std::to_wstring(pid)).c_str(), PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, 0, PIPE_BUFFER_SIZE, MAXDWORD, &allAccess),
hostPipe = CreateNamedPipeW((std::wstring(HOST_PIPE)+std::to_wstring(pid)).c_str(), PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, 0, MAXDWORD, &allAccess); hostPipe = CreateNamedPipeW((std::wstring(HOST_PIPE) + std::to_wstring(pid)).c_str(), PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, 0, MAXDWORD, &allAccess);
HANDLE pipeAvailableEvent = CreateEventW(&allAccess, FALSE, FALSE, (std::wstring(PIPE_AVAILABLE_EVENT)+std::to_wstring(pid)).c_str()); HANDLE pipeAvailableEvent = CreateEventW(&allAccess, FALSE, FALSE, (std::wstring(PIPE_AVAILABLE_EVENT) + std::to_wstring(pid)).c_str());
Host::AddConsoleOutput((std::wstring(PIPE_AVAILABLE_EVENT)+std::to_wstring(pid))); Host::AddConsoleOutput((std::wstring(PIPE_AVAILABLE_EVENT) + std::to_wstring(pid)));
SetEvent(pipeAvailableEvent); SetEvent(pipeAvailableEvent);
std::thread([hookPipe,hostPipe,pipeAvailableEvent] std::thread([hookPipe, hostPipe, pipeAvailableEvent]
{ {
ConnectNamedPipe(hookPipe, nullptr); ConnectNamedPipe(hookPipe, nullptr);
CloseHandle(pipeAvailableEvent); CloseHandle(pipeAvailableEvent);
BYTE buffer[PIPE_BUFFER_SIZE] = {}; BYTE buffer[PIPE_BUFFER_SIZE] = {};
@ -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();
} }
} }
@ -189,156 +196,200 @@ namespace Host
std::mutex threadmutex; std::mutex threadmutex;
std::mutex outputmutex; std::mutex outputmutex;
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;
IsWow64Process(process, &invalidProcess); IsWow64Process(process, &invalidProcess);
if (invalidProcess) return AddConsoleOutput(NEED_32_BIT); if (invalidProcess) return AddConsoleOutput(NEED_32_BIT);
#endif #endif
bool succ=false; bool succ = false;
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);
if (AutoHandle<> thread = CreateRemoteThread(process, nullptr, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, remoteData, 0, nullptr))
{ {
WriteProcessMemory(process, remoteData, location.c_str(), (location.size() + 1) * sizeof(wchar_t), nullptr); WaitForSingleObject(thread, INFINITE);
if (AutoHandle<> thread = CreateRemoteThread(process, nullptr, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, remoteData, 0, nullptr)){ succ = true;
WaitForSingleObject(thread, INFINITE);
succ=true;
}
else if (GetLastError() == ERROR_ACCESS_DENIED){
AddConsoleOutput(NEED_64_BIT); // https://stackoverflow.com/questions/16091141/createremotethread-access-denied
succ=false;
}
VirtualFreeEx(process, remoteData, 0, MEM_RELEASE);
} }
return succ; else if (GetLastError() == ERROR_ACCESS_DENIED)
{
AddConsoleOutput(NEED_64_BIT); // https://stackoverflow.com/questions/16091141/createremotethread-access-denied
succ = false;
}
VirtualFreeEx(process, remoteData, 0, MEM_RELEASE);
}
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
return false; injectedDll = LoadLibraryW(location.c_str());
if (injectedDll)
return true;
return false;
} }
bool CheckProcess(DWORD processId){ bool CheckProcess(DWORD processId)
if (processId == GetCurrentProcessId()) return false; {
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)
bool proc64=Is64BitProcess(process); return false;
auto dllname=proc64?LUNA_HOOK_DLL_64:LUNA_HOOK_DLL_32; bool proc64 = Is64BitProcess(process);
std::wstring location =locationX.size()?(locationX+L"\\"+dllname): std::filesystem::path(getModuleFilename().value()).replace_filename(dllname); 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);
AddConsoleOutput(location); AddConsoleOutput(location);
if(proc64==x64){ if (proc64 == x64)
return (SafeInject(process,location)); {
return (SafeInject(process, location));
}
else
{
return (UnSafeInject(process, location));
} }
else{
return (UnSafeInject(process,location));
}
} }
bool CreatePipeAndCheck(DWORD processId){ bool CreatePipeAndCheck(DWORD processId)
{
CreatePipe(processId); CreatePipe(processId);
return CheckProcess(processId); return CheckProcess(processId);
} }
void InjectProcess(DWORD processId,const std::wstring locationX) void InjectProcess(DWORD processId, const std::wstring locationX)
{ {
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));
} }
TextThread& GetThread(ThreadParam tp) TextThread &GetThread(ThreadParam tp)
{ {
return textThreadsByParams->at(tp); return textThreadsByParams->at(tp);
} }
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)
return nullptr; if (thread.handle == handle)
return &thread;
return nullptr;
} }
EmbedSharedMem* GetEmbedSharedMem(DWORD processId){ EmbedSharedMem *GetEmbedSharedMem(DWORD processId)
auto &prs=processRecordsByIds.Acquire().contents; {
if(prs.find(processId)==prs.end())return 0; auto &prs = processRecordsByIds.Acquire().contents;
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)
{ {
if(OnConsole) if (OnConsole)
OnConsole(std::move(text)); OnConsole(std::move(text));
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

@ -3,15 +3,15 @@
#include "textthread.h" #include "textthread.h"
namespace Host namespace Host
{ {
using ConsoleHandler =std::function<void(const std::wstring&)>; using ConsoleHandler = std::function<void(const std::wstring &)>;
using ProcessEventHandler = std::function<void(DWORD)>; using ProcessEventHandler = std::function<void(DWORD)>;
using ThreadEventHandler = std::function<void(TextThread&)>; using ThreadEventHandler = std::function<void(TextThread &)>;
using HookEventHandler = std::function<void(const HookParam&,const std::wstring& text)>; using HookEventHandler = std::function<void(const HookParam &, const std::wstring &text)>;
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);
void DetachProcess(DWORD processId); void DetachProcess(DWORD processId);
@ -19,13 +19,14 @@ namespace Host
void InsertHook(DWORD processId, HookParam hp); void InsertHook(DWORD processId, HookParam hp);
void RemoveHook(DWORD processId, uint64_t address); void RemoveHook(DWORD processId, uint64_t address);
void FindHooks(DWORD processId, SearchParam sp, HookEventHandler HookFound = {}); void FindHooks(DWORD processId, SearchParam sp, HookEventHandler HookFound = {});
EmbedSharedMem* GetEmbedSharedMem(DWORD pid); EmbedSharedMem *GetEmbedSharedMem(DWORD pid);
TextThread* GetThread(int64_t handle); TextThread *GetThread(int64_t handle);
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;
constexpr ThreadParam console{ 0, 0, 0, 0 }; constexpr ThreadParam console{0, 0, 0, 0};
} }

View File

@ -1,27 +1,28 @@
#include "textthread.h" #include "textthread.h"
#include "host.h" #include "host.h"
#include"Lang/Lang.h" #include "Lang/Lang.h"
// return true if repetition found (see https://github.com/Artikash/Textractor/issues/40) // return true if repetition found (see https://github.com/Artikash/Textractor/issues/40)
static bool RemoveRepetition(std::wstring& text) static bool RemoveRepetition(std::wstring &text)
{ {
wchar_t* end = text.data() + text.size(); wchar_t *end = text.data() + text.size();
for (int length = text.size() / 3; length > 6; --length) for (int length = text.size() / 3; length > 6; --length)
if (memcmp(end - length * 3, end - length * 2, length * sizeof(wchar_t)) == 0 && memcmp(end - length * 3, end - length * 1, length * sizeof(wchar_t)) == 0) if (memcmp(end - length * 3, end - length * 2, length * sizeof(wchar_t)) == 0 && memcmp(end - length * 3, end - length * 1, length * sizeof(wchar_t)) == 0)
return RemoveRepetition(text = std::wstring(end - length, length)), true; return RemoveRepetition(text = std::wstring(end - length, length)), true;
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()
@ -34,9 +35,10 @@ void TextThread::AddSentence(std::wstring sentence)
queuedSentences->emplace_back(std::move(sentence)); queuedSentences->emplace_back(std::move(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];
@ -56,19 +58,23 @@ void TextThread::Push(BYTE* data, int length)
length = 0; length = 0;
} }
} }
auto converted = commonparsestring(data,length,&hp,Host::defaultCodepage); auto converted = commonparsestring(data, length, &hp, Host::defaultCodepage);
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());
@ -84,7 +90,7 @@ void TextThread::Push(BYTE* data, int length)
} }
} }
void TextThread::Push(const wchar_t* data) void TextThread::Push(const wchar_t *data)
{ {
std::scoped_lock lock(bufferMutex); std::scoped_lock lock(bufferMutex);
// not sure if this should filter repetition // not sure if this should filter repetition
@ -96,21 +102,24 @@ 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;
queuedSentences->swap(sentences); queuedSentences->swap(sentences);
int totalSize = 0; int totalSize = 0;
for (auto& sentence : sentences) for (auto &sentence : sentences)
{ {
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,14 +1,13 @@
#pragma once #pragma once
class TextThread class TextThread
{ {
public: public:
using OutputCallback = std::function<bool(TextThread&, std::wstring&)>; using OutputCallback = std::function<bool(TextThread &, std::wstring &)>;
inline static OutputCallback Output; inline static OutputCallback Output;
inline static bool filterRepetition = false; inline static bool filterRepetition = false;
inline static int flushDelay = 100; inline static int flushDelay = 100;
inline static int maxBufferSize = 3000; inline static int maxBufferSize = 3000;
inline static int maxHistorySize = 10'000'000; inline static int maxHistorySize = 10'000'000;
@ -17,8 +16,8 @@ public:
void Start(); void Start();
void Stop(); void Stop();
void AddSentence(std::wstring sentence); void AddSentence(std::wstring sentence);
void Push(BYTE* data, int length); void Push(BYTE *data, int length);
void Push(const wchar_t* data); void Push(const wchar_t *data);
Synchronized<std::wstring> storage; Synchronized<std::wstring> storage;
const int64_t handle; const int64_t handle;
@ -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
{ {