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)
set(VERSION_MAJOR 3)
set(VERSION_MINOR 13)
set(VERSION_MINOR 14)
set(VERSION_PATCH 0)
set(VERSION_REVISION 0)

View File

@ -1,6 +1,6 @@
include_directories(. util engines)
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(collector "enginecollection64.cpp")
else()

View File

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

View File

@ -1,13 +1,13 @@
class _5pb:public ENGINE{
public:
_5pb(){
is_engine_certain=false;
check_by=CHECK_BY::FILE_ANY;
check_by_target=check_by_list{ L"data\\*.cpk",L"*.cpk"};
class _5pb : public ENGINE
{
public:
_5pb()
{
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"
namespace{
//Muv-Luv Alternative - Total Eclipse
//https://vndb.org/v7052
bool _1(){
//HSN65001#-44@234699:te-win64vc14-release.exe
BYTE b1[]={
0x48,XX2,0xb0,0xfe,0xff,0xff,
0x4c,XX2,0xb8,0x01,0x00,0x00,
#include "AGES7.h"
namespace
{
// Muv-Luv Alternative - Total Eclipse
// https://vndb.org/v7052
bool _1()
{
// HSN65001#-44@234699:te-win64vc14-release.exe
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);
if(addr==0)return false;
auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress);
if (addr == 0)
return false;
HookParam hp;
hp.address=addr;
hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT;
hp.offset=get_reg(regs::rdi);
auto succ=NewHook(hp,"Ages7_1");
if(addr=MemDbg::findEnclosingAlignedFunction(addr)){
hp.address=addr;
hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT;
hp.offset=get_reg(regs::rbx);
succ|=NewHook(hp,"Ages7_3");
hp.address = addr;
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
hp.offset = get_reg(regs::rdi);
auto succ = NewHook(hp, "Ages7_1");
if (addr = MemDbg::findEnclosingAlignedFunction(addr))
{
hp.address = addr;
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
hp.offset = get_reg(regs::rbx);
succ |= NewHook(hp, "Ages7_3");
}
return succ;
}
bool _2(){
//HSN65001#-44@2346AC:te-win64vc14-release.exe
BYTE b1[]={
0x48,XX2,0x10,
0x48,XX2,0xb0,0x01,0x00,0x00,
XX2,0xc0,0x08,0x00,0x00
bool _2()
{
// HSN65001#-44@2346AC:te-win64vc14-release.exe
BYTE b1[] = {
//clang-format off
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);
if(addr==0)return false;
auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress);
if (addr == 0)
return false;
HookParam hp;
hp.address=addr;
hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT;
hp.offset=get_reg(regs::rdi);
auto suc=NewHook(hp,"Ages7_2");
if(addr=MemDbg::findEnclosingAlignedFunction(addr)){
hp.address=addr;
hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT;
hp.offset=get_reg(regs::rbx);
suc|=NewHook(hp,"Ages7_3");
hp.address = addr;
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
hp.offset = get_reg(regs::rdi);
auto suc = NewHook(hp, "Ages7_2");
if (addr = MemDbg::findEnclosingAlignedFunction(addr))
{
hp.address = addr;
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
hp.offset = get_reg(regs::rbx);
suc |= NewHook(hp, "Ages7_3");
}
return suc;
}
bool _3(){
//HSN65001#-14@3D9814:te-win64vc14-release.exe
BYTE b1[]={
0x48,0x8b,0x1b,
0x48,0x8b,0x01,
0x48,0x8b,0xd3,
0xff,0x10,
0x48,0x8b,0x45,0xc8,
0x48,0x8b,0x4d,0xc0,
0x48,0x2b,0xc1,
0x48,0xc1,0xf8,0x03,
0x48,0x85,0xc0,
}
bool _3()
{
// HSN65001#-14@3D9814:te-win64vc14-release.exe
BYTE b1[] = {
//clang-format off
0x48, 0x8b, 0x1b,
0x48, 0x8b, 0x01,
0x48, 0x8b, 0xd3,
0xff, 0x10,
0x48, 0x8b, 0x45, 0xc8,
0x48, 0x8b, 0x4d, 0xc0,
0x48, 0x2b, 0xc1,
0x48, 0xc1, 0xf8, 0x03,
0x48, 0x85, 0xc0,
//clang-format on
};
auto addr=MemDbg::findBytes(b1,sizeof(b1),processStartAddress,processStopAddress);
if(addr==0)return false;
auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress);
if (addr == 0)
return false;
HookParam hp;
hp.address=addr+3;
hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT;
hp.offset=get_reg(regs::rbx);
return NewHook(hp,"Ages7_4");
}
bool all(){
auto _=_1();
_=_2()||_;
_=_3()||_;
hp.address = addr + 3;
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
hp.offset = get_reg(regs::rbx);
return NewHook(hp, "Ages7_4");
}
bool all()
{
auto _ = _1();
_ = _2() || _;
_ = _3() || _;
return _;
}
}
bool AGES7::attach_function(){
bool AGES7::attach_function()
{
return all();
}

View File

@ -1,12 +1,13 @@
class AGES7:public ENGINE{
public:
AGES7(){
check_by=CHECK_BY::FILE_ALL;
check_by_target=check_by_list{L"obb\\pack.bin",L"erc_nospfx.dll"};
class AGES7 : public ENGINE
{
public:
AGES7()
{
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()
{
//https://vndb.org/v50832
//きら☆かの 体验版
// https://vndb.org/v50832
// きら☆かの 体验版
/*
__int64 __fastcall sub_1401B13F0(__int64 a1, unsigned __int64 a2, char **a3)

View File

@ -1,11 +1,13 @@
class Artemis:public ENGINE{
public:
Artemis(){
check_by=CHECK_BY::FILE;
check_by_target=L"*.pfs";
class Artemis : public ENGINE
{
public:
Artemis()
{
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"
namespace{
bool EMbed(){
//有多个,但是只有最后一个是有效的
const uint8_t bytes[] = {
0xB8,0x42,0x81,0x00,0x00,
0x66,XX2,0x74,XX,
0xB8,0x76,0x81,0x00,0x00,
0x66,XX2,0x74,XX,
0xB8,0x78,0x81,0x00,0x00,
0x66,XX2,0x74,XX,
};
bool res=false;
auto addr=processStartAddress;
std::vector<uintptr_t>already;
while(addr){
addr = MemDbg::findBytes(bytes,sizeof(bytes),addr+1,processStopAddress);
if(addr==0)continue;
#include "CMVS.h"
namespace
{
bool EMbed()
{
// 有多个,但是只有最后一个是有效的
const uint8_t bytes[] = {
//clang-format off
0xB8, 0x42, 0x81, 0x00, 0x00,
0x66, XX2, 0x74, XX,
0xB8, 0x76, 0x81, 0x00, 0x00,
0x66, XX2, 0x74, XX,
0xB8, 0x78, 0x81, 0x00, 0x00,
0x66, XX2, 0x74, XX,
//clang-format on
};
bool res = false;
auto addr = processStartAddress;
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);
if(f==0)continue;
if(std::find(already.begin(),already.end(),f)!=already.end())continue;
if (f == 0)
continue;
if (std::find(already.begin(), already.end(), f) != already.end())
continue;
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;
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");
hp.address = addr + 4;
hp.offset = get_reg(regs::r8);
hp.type = CODEC_ANSI_BE;
return NewHook(hp, "CMVS");
}
return res;
}
bool CMVSh() {
DWORD align = 0xCCCCCCCC;
auto addr = MemDbg::findCallerAddress((uintptr_t)::GetGlyphOutlineA, align, processStartAddress, processStopAddress);
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;
bool CMVS::attach_function()
{
bool b1 = CMVSh();
bool b2 = EMbed();
return b1 || b2;
}

View File

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

View File

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

View File

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

View File

@ -1,38 +1,42 @@
#include"Kincaid.h"
namespace{
bool _1(){
// .text:0000000140230D80 mov rsi, rax
// .text:0000000140230D83 mov edx, 1
// .text:0000000140230D88 mov rcx, rdi
// .text:0000000140230D8B call sub_1402B35B0
// .text:0000000140230D90 lea ebx, [rax-1]
// .text:0000000140230D93 mov edx, 2
// .text:0000000140230D98 mov rcx, rdi
// .text:0000000140230D9B call sub_1402B35B0
BYTE b1[]={
0x48,0x8b,0xf0,
0xba,0x01,0x00,0x00,0x00,
0x48,0x8b,0xcf,
0xe8,XX4,
0x8d,0x58,0xff,
0xba,0x02,0x00,0x00,0x00,
0x48,0x8b,0xcf,
0xe8,XX4
};
auto addr=MemDbg::findBytes(b1,sizeof(b1),processStartAddress,processStopAddress);
if(addr==0)return false;
#include "Kincaid.h"
namespace
{
bool _1()
{
// .text:0000000140230D80 mov rsi, rax
// .text:0000000140230D83 mov edx, 1
// .text:0000000140230D88 mov rcx, rdi
// .text:0000000140230D8B call sub_1402B35B0
// .text:0000000140230D90 lea ebx, [rax-1]
// .text:0000000140230D93 mov edx, 2
// .text:0000000140230D98 mov rcx, rdi
// .text:0000000140230D9B call sub_1402B35B0
BYTE b1[] = {
0x48, 0x8b, 0xf0,
0xba, 0x01, 0x00, 0x00, 0x00,
0x48, 0x8b, 0xcf,
0xe8, XX4,
0x8d, 0x58, 0xff,
0xba, 0x02, 0x00, 0x00, 0x00,
0x48, 0x8b, 0xcf,
0xe8, XX4};
auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress);
if (addr == 0)
return false;
HookParam hp;
hp.address=addr;
hp.type=USING_STRING|CODEC_UTF8;
hp.offset=get_reg(regs::rax);
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)
*len=strlen((char*)*data);
hp.address = addr;
hp.type = USING_STRING | CODEC_UTF8;
hp.offset = get_reg(regs::rax);
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)
*len = strlen((char *)*data);
};
return NewHook(hp,"Kincaid");
return NewHook(hp, "Kincaid");
}
}
bool Kincaid::attach_function(){
bool Kincaid::attach_function()
{
return _1();
}

View File

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

View File

@ -1,68 +1,70 @@
#include"KiriKiri.h"
#include "KiriKiri.h"
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)) {
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;
/*
* 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))
{
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()
{
const BYTE BYTES[] = {
0x41,0x0F,0xB7,0x44,0x24,0x04,
0x89,0x43,0x20,
0x41,0x0F,0xB7,0x44,0x24,0x06,
0x89,0x43,0x24,
0x41,0x0F,0xBF,0x44,0x24,0x0C,
0x89,0x43,0x14
};
auto addrs = Util::SearchMemory(BYTES, sizeof(BYTES), PAGE_EXECUTE_READ, processStartAddress, processStopAddress);
ConsoleOutput("%p %p", processStartAddress, processStopAddress);
for (auto addr : addrs) {
ConsoleOutput("krkrz64 %p", addr);
const BYTE funcstart[] = { 0xcc,0xcc,0xcc,0xcc };
addr = reverseFindBytes(funcstart, sizeof(funcstart), addr - 0x1000, addr);
if (addr == 0)continue;
addr += 4;
HookParam hp;
hp.address = addr;
hp.type = CODEC_UTF16| DATA_INDIRECT;
hp.offset=get_reg(regs::rcx);
hp.index = 0x18;
ConsoleOutput("krkrz64 %p %x", addr);
return NewHook(hp, "krkrz64");
}
const BYTE BYTES[] = {
0x41, 0x0F, 0xB7, 0x44, 0x24, 0x04,
0x89, 0x43, 0x20,
0x41, 0x0F, 0xB7, 0x44, 0x24, 0x06,
0x89, 0x43, 0x24,
0x41, 0x0F, 0xBF, 0x44, 0x24, 0x0C,
0x89, 0x43, 0x14};
auto addrs = Util::SearchMemory(BYTES, sizeof(BYTES), PAGE_EXECUTE_READ, processStartAddress, processStopAddress);
ConsoleOutput("%p %p", processStartAddress, processStopAddress);
for (auto addr : addrs)
{
ConsoleOutput("krkrz64 %p", addr);
const BYTE funcstart[] = {0xcc, 0xcc, 0xcc, 0xcc};
addr = reverseFindBytes(funcstart, sizeof(funcstart), addr - 0x1000, addr);
if (addr == 0)
continue;
addr += 4;
HookParam hp;
hp.address = addr;
hp.type = CODEC_UTF16 | DATA_INDIRECT;
hp.offset = get_reg(regs::rcx);
hp.index = 0x18;
ConsoleOutput("krkrz64 %p %x", addr);
return NewHook(hp, "krkrz64");
}
ConsoleOutput("krkrz64 failed");
return false;
ConsoleOutput("krkrz64 failed");
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{
public:
KiriKiri(){
check_by=CHECK_BY::CUSTOM;
is_engine_certain=false;
check_by_target=[](){
return Util::CheckFile(L"*.xp3") || Util::SearchResourceString(L"TVP(KIRIKIRI)");
class KiriKiri : public ENGINE
{
public:
KiriKiri()
{
check_by = CHECK_BY::CUSTOM;
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{
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"};
};
bool attach_function();
class LightVN : public ENGINE
{
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"};
};
bool attach_function();
};

View File

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

View File

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

View File

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

View File

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

View File

@ -1,11 +1,13 @@
class Suika2:public ENGINE{
public:
Suika2(){
is_engine_certain=false;
check_by=CHECK_BY::FILE_ANY;
check_by_target=check_by_list{L"suika.exe",L"conf/config.txt"};
class Suika2 : public ENGINE
{
public:
Suika2()
{
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"
namespace{
bool _h() {
//TYPE-MOON 魔法使いの夜 多国語版 中文-英文-日文
BYTE bytes[]={
0xBA,0x08,0xFF,0x00,0x00,
0x41,0xB8,0x1C,0x20,0x00,0x00,
0x66,0x90
};
auto addr=MemDbg::findBytes(bytes,sizeof(bytes),processStartAddress, processStopAddress);
ConsoleOutput("%p",addr);
if(addr==0)return false;
addr=MemDbg::findEnclosingAlignedFunction(addr);ConsoleOutput("%p",addr);
if(addr==0)return false;
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");
#include "TYPEMOON.h"
namespace
{
bool _h()
{
// TYPE-MOON 魔法使いの夜 多国語版 中文-英文-日文
BYTE bytes[] = {
0xBA, 0x08, 0xFF, 0x00, 0x00,
0x41, 0xB8, 0x1C, 0x20, 0x00, 0x00,
0x66, 0x90};
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
ConsoleOutput("%p", addr);
if (addr == 0)
return false;
addr = MemDbg::findEnclosingAlignedFunction(addr);
ConsoleOutput("%p", addr);
if (addr == 0)
return false;
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();
}
}

View File

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

View File

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

View File

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

View File

@ -1,21 +1,22 @@
#include"YOX.h"
#include "YOX.h"
bool YOX::attach_function()
{
const BYTE BYTES[] = {
0x48,0x8B,0x0F,
0x48,0x8d,0x54,0x24,0x50
};
0x48, 0x8B, 0x0F,
0x48, 0x8d, 0x54, 0x24, 0x50};
auto addrs = Util::SearchMemory(BYTES, sizeof(BYTES), PAGE_EXECUTE_READ, processStartAddress, processStopAddress);
ConsoleOutput("%p %p", processStartAddress, processStopAddress);
for (auto addr : addrs) {
if (addr == 0)continue;
for (auto addr : addrs)
{
if (addr == 0)
continue;
HookParam hp;
hp.address = addr;
hp.type = USING_STRING ;
hp.type = USING_STRING;
hp.offset = get_stack(26);
ConsoleOutput("yox64 %p", addr);
return NewHook(hp, "yox64");
}
ConsoleOutput("yox64 failed");
return false;
}
}

View File

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

View File

@ -1,49 +1,50 @@
#include "livecaptions.h"
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;
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)
// .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)
{
auto ptr = stack->rdx;
auto size = stack->r8;
if (size == strnlen((char *)ptr, TEXT_BUFFER_SIZE) )//否则有短acsii
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;
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;
*len = size;
}
};
NewHook(hpinternal, "std::_Char_traits<char,int>::copy(void *, const void *, size_t)");
}
auto ptr = stack->rdx;
auto size = stack->r8;
if (size == strnlen((char *)ptr, TEXT_BUFFER_SIZE)) // 否则有短acsii
{
*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_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();

View File

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

View File

@ -1,82 +1,90 @@
#include"mono.h"
#include"mono/monocommon.hpp"
namespace{
bool monobdwgc() {
#include "mono.h"
#include "mono/monocommon.hpp"
namespace
{
bool monobdwgc()
{
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);
BYTE bytes[] = {
0x81,0xF9,0x80,0x00,0x00,0x00,
0x73,0x05,
0x49,0x8B,0xCC
/*
_BYTE *__fastcall sub_18005B290(
_WORD *a1,
int a2,
__int64 a3,
_DWORD *a4,
__int64 (__fastcall *a5)(__int64, __int64),
__int64 a6,
__int64 a7)
0x81, 0xF9, 0x80, 0x00, 0x00, 0x00,
0x73, 0x05,
0x49, 0x8B, 0xCC
/*
_BYTE *__fastcall sub_18005B290(
_WORD *a1,
int a2,
__int64 a3,
_DWORD *a4,
__int64 (__fastcall *a5)(__int64, __int64),
__int64 a6,
__int64 a7)
if ( (_DWORD)v26 )
{
if ( (unsigned int)v26 >= 0x80 )
if ( (_DWORD)v26 )
{
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 >= 0x80000000 )
*/
if ( (unsigned int)v26 >= 0x4000000 )
{
v17 = 6i64;
if ( (unsigned int)v26 >= 0x80000000 )
*/
};
auto addrs =Util::SearchMemory(bytes, sizeof(bytes),PAGE_EXECUTE, minAddress, maxAddress);
auto suc=false;
for (auto addr : addrs) {
const BYTE align[]={0xCC,0xCC,0xCC,0xCC};
addr=reverseFindBytes(align,sizeof(align),addr-0x100,addr);
if(addr==0)continue;
auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, minAddress, maxAddress);
auto suc = false;
for (auto addr : addrs)
{
const BYTE align[] = {0xCC, 0xCC, 0xCC, 0xCC};
addr = reverseFindBytes(align, sizeof(align), addr - 0x100, addr);
if (addr == 0)
continue;
ConsoleOutput("monobdwgcdll %p", addr);
HookParam hp;
hp.address = addr+4;
hp.offset=get_reg(regs::rcx);
hp.type = CODEC_UTF16|USING_STRING;
hp.text_fun=[](auto, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
std::wstring str = std::wstring((LPWSTR)*data );
*split=str.find(L"OnShowComplete")!=str.npos;
*len = wcslen((wchar_t*)*data) * 2 ;
hp.address = addr + 4;
hp.offset = get_reg(regs::rcx);
hp.type = CODEC_UTF16 | USING_STRING;
hp.text_fun = [](auto, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
std::wstring str = std::wstring((LPWSTR)*data);
*split = str.find(L"OnShowComplete") != str.npos;
*len = wcslen((wchar_t *)*data) * 2;
};
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){
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)
{
str = std::regex_replace(str, std::wregex(L"\n"), L"");
std::wregex reg1(L"\\((.*?)\\)");
std::wsmatch match;
std::regex_search(str, match,reg1 );
auto result1= match[1].str();
std::regex_search(str, match,std::wregex(L" Text:(.*?)Next:(.*?)") );
result1= match[1].str();
write_string_overwrite(data,len,result1);
std::wsmatch match;
std::regex_search(str, match, reg1);
auto result1 = match[1].str();
std::regex_search(str, match, std::wregex(L" Text:(.*?)Next:(.*?)"));
result1 = match[1].str();
write_string_overwrite(data, len, result1);
}
return true;
};
suc|=NewHook(hp, "monobdwgcdll");
suc |= NewHook(hp, "monobdwgcdll");
}
return suc;
}
}
}
bool mono::attach_function(){
bool common=monocommon::hook_mono_il2cpp();
bool mono::attach_function()
{
bool common = monocommon::hook_mono_il2cpp();
return common;
}

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
#include"rpcs3.h"
namespace{
#if 0 //only support0.0.20-0.0.27
#include "rpcs3.h"
namespace
{
#if 0 // only support0.0.20-0.0.27
int emoffset;
int jitoffset;
uintptr_t getDoJitAddress_() {
@ -113,10 +114,11 @@ namespace{
return DoJitPtr+6;
}
#endif
uintptr_t getDoJitAddress() {
//rpcs3/Emu/Cell/PPUThread.cpp
#endif
uintptr_t getDoJitAddress()
{
// rpcs3/Emu/Cell/PPUThread.cpp
/*
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";
auto logstrptr=MemDbg::findBytes(log,sizeof(log),processStartAddress,processStopAddress);
ConsoleOutput("%p",logstrptr);
if(logstrptr==0)return 0;
auto addr=MemDbg::findleaaddr(logstrptr, processStartAddress, processStopAddress);
ConsoleOutput("%p",addr);
if(addr==0)return 0;
//ff cc cc cc,find不到。。
BYTE start[]={XX,0xCC,0xCC,0xCC};
addr=reverseFindBytes(start,sizeof(start),addr-0x200,addr,4,true);
ConsoleOutput("%p",addr);
char log[] = "ppu_register_function_at(0x%x): empty range";
auto logstrptr = MemDbg::findBytes(log, sizeof(log), processStartAddress, processStopAddress);
ConsoleOutput("%p", logstrptr);
if (logstrptr == 0)
return 0;
auto addr = MemDbg::findleaaddr(logstrptr, processStartAddress, processStopAddress);
ConsoleOutput("%p", addr);
if (addr == 0)
return 0;
// ff cc cc cc,find不到。。
BYTE start[] = {XX, 0xCC, 0xCC, 0xCC};
addr = reverseFindBytes(start, sizeof(start), addr - 0x200, addr, 4, true);
ConsoleOutput("%p", addr);
return addr;
}
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)
struct emfuncinfo
{
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);
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 NewHook(hp,"g_exec_addr");
}
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;
}
*/
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()
{
ConsoleOutput("[Compatibility] RPCS3");
auto DoJitPtr=getDoJitAddress();
if(DoJitPtr==0)return false;
ConsoleOutput("[Compatibility] RPCS3");
auto DoJitPtr = getDoJitAddress();
if (DoJitPtr == 0)
return false;
unsafeinithooks();
spDefault.jittype=JITTYPE::RPCS3;
spDefault.jittype = JITTYPE::RPCS3;
spDefault.minAddress = 0;
spDefault.maxAddress = -1;
HookParam hp;
hp.address=DoJitPtr;
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 entrypoint=stack->r8;//*(uintptr_t*)*(uintptr_t*)(stack->base+jitoffset)-0x0008000000000000;
if(!em_address||!entrypoint)return;
dohookemaddr(em_address,entrypoint);
hp.address = DoJitPtr;
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 entrypoint = stack->r8; //*(uintptr_t*)*(uintptr_t*)(stack->base+jitoffset)-0x0008000000000000;
if (!em_address || !entrypoint)
return;
dohookemaddr(em_address, entrypoint);
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);
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;
}();
};
return 1;
}();
}

View File

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

View File

@ -1,12 +1,15 @@
#include"vita3k.h"
namespace{
#include "vita3k.h"
namespace
{
auto isVirtual = true;
auto idxDescriptor = isVirtual == true ? 2 : 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 first=find_pattern(RegisterBlockSig1,processStartAddress,processStopAddress);
if (first) return first;
auto first = find_pattern(RegisterBlockSig1, processStartAddress, processStopAddress);
if (first)
return first;
/*
// DebugSymbol: RegisterBlock
// ?RegisterBlock@EmitX64@X64@Backend@Dynarmic@@IEAA?AUBlockDescriptor@1234@AEBVLocationDescriptor@IR@4@PEBX_K@Z <- new
@ -19,346 +22,544 @@ namespace{
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";
first = find_pattern(PatchBlockSig1,processStartAddress,processStopAddress);
if (first) {
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);
if (first)
{
idxDescriptor = 1;
idxEntrypoint = 2;
return first;
}
return 0;
}
struct emfuncinfo{
uint64_t type;
int argidx;int padding;
void* hookfunc;
void* filterfun;
const char* _id;
};
std::unordered_map<uintptr_t,emfuncinfo>emfunctionhooks;
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;
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;
}
return false;
}
}
bool vita3k::attach_function()
{
ConsoleOutput("[Compatibility] Vita3k 0.1.9 3520+");
auto DoJitPtr=getDoJitAddress();
if(DoJitPtr==0)return false;
ConsoleOutput("DoJitPtr %p",DoJitPtr);
spDefault.jittype=JITTYPE::VITA3K;
ConsoleOutput("[Compatibility] Vita3k 0.1.9 3520+");
auto DoJitPtr = getDoJitAddress();
if (DoJitPtr == 0)
return false;
ConsoleOutput("DoJitPtr %p", DoJitPtr);
spDefault.jittype = JITTYPE::VITA3K;
spDefault.minAddress = 0;
spDefault.maxAddress = -1;
HookParam hp;
hp.address=DoJitPtr;
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 em_address = *(uint32_t*)descriptor;
if(!entrypoint)return;
// ConsoleOutput("%p",em_address);
jitaddraddr(em_address,entrypoint,JITTYPE::VITA3K);
[&](){
if(emfunctionhooks.find(em_address)==emfunctionhooks.end())return;
auto op=emfunctionhooks.at(em_address);
if(!(checkiscurrentgame(op)))return;
HookParam hpinternal;
hpinternal.address=entrypoint;
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::VITA3K;
NewHook(hpinternal,op._id);
}();
delayinsertNewHook(em_address);
hp.address = DoJitPtr;
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 em_address = *(uint32_t *)descriptor;
if (!entrypoint)
return;
// ConsoleOutput("%p",em_address);
jitaddraddr(em_address, entrypoint, JITTYPE::VITA3K);
[&]()
{
if (emfunctionhooks.find(em_address) == emfunctionhooks.end())
return;
auto op = emfunctionhooks.at(em_address);
if (!(checkiscurrentgame(op)))
return;
HookParam hpinternal;
hpinternal.address = entrypoint;
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::VITA3K;
NewHook(hpinternal, op._id);
}();
delayinsertNewHook(em_address);
};
return NewHook(hp,"vita3kjit");
return NewHook(hp, "vita3kjit");
}
namespace{
bool FPCSG01023(void* data, size_t* len, HookParam* hp){
auto s = std::string((char*)data,*len);
s = std::regex_replace(s, std::regex("<br>"), "");
s = std::regex_replace(s, std::regex("%CF11F"), "");
s = std::regex_replace(s, std::regex("%CFFFF"), "");
s = std::regex_replace(s, std::regex("%K%P"), "");
s = std::regex_replace(s, std::regex("%K%N"), "");
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){
auto s = std::string((char*)data,*len);
s = std::regex_replace(s, std::regex("(\\n)+"), " ");
s = std::regex_replace(s, std::regex("\\d$|^@[a-z]+|#.*?#|\\$"), "");
static std::string last;
if(last==s)return false;
last=s;
return write_string_overwrite(data,len,s);
}
template<int index>
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);
namespace
{
bool FPCSG01023(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("<br>"), "");
s = std::regex_replace(s, std::regex("%CF11F"), "");
s = std::regex_replace(s, std::regex("%CFFFF"), "");
s = std::regex_replace(s, std::regex("%K%P"), "");
s = std::regex_replace(s, std::regex("%K%N"), "");
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)
{
auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("(\\n)+"), " ");
s = std::regex_replace(s, std::regex("\\d$|^@[a-z]+|#.*?#|\\$"), "");
static std::string last;
if (last == s)
return false;
last = s;
return write_string_overwrite(data, len, s);
}
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;
template <int index>
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;
}
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 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 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 _=[](){
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"}},
address = results + 5;
};
return 1;
}();
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));
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{
public:
vita3k(){
check_by=CHECK_BY::FILE;
is_engine_certain=false;
check_by_target=L"Vita3K.exe";
};
bool attach_function();
class vita3k : public ENGINE
{
public:
vita3k()
{
check_by = CHECK_BY::FILE;
is_engine_certain = false;
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/Kincaid.h"
#include "engine64/LightVN.h"
#include "engine64/yuzusuyu.h"
#include "engine64/yuzu.h"
#include "engine64/Ryujinx.h"
#include "engine64/vita3k.h"
#include "engine64/rpcs3.h"
@ -42,7 +42,7 @@ std::vector<ENGINE *> check_engines()
new _5pb,
new TYPEMOON,
new ENTERGRAM,
new yuzusuyu,
new yuzu,
new PPSSPPengine,
new vita3k,
new rpcs3,

View File

@ -1,329 +1,377 @@
#include<queue>
#include"emujitarg.hpp"
#include <queue>
#include "emujitarg.hpp"
namespace ppsspp{
bool ULJS00403_filter(void* data, size_t* len, HookParam* hp){
std::string result = std::string((char*)data,*len);
std::regex newlinePattern(R"((\\n)+)");
result = std::regex_replace(result, newlinePattern, " ");
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);
namespace ppsspp
{
bool ULJS00403_filter(void *data, size_t *len, HookParam *hp)
{
std::string result = std::string((char *)data, *len);
std::regex newlinePattern(R"((\\n)+)");
result = std::regex_replace(result, newlinePattern, " ");
std::regex pattern(R"((\\d$|^\@[a-z]+|#.*?#|\$))");
result = std::regex_replace(result, pattern, "");
return write_string_overwrite(data, len, result);
}
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
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();
}
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++;
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 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 {
s+=buf;
}
i += 2;
return s;
}
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){
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;
}
void ULJM05054(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
if (hp->emu_addr != 0x886162c)
{
auto addr = PPSSPP::emu_arg(stack)[0] + 0x3c;
*data = addr;
*len = strlen((char *)addr);
return;
}
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){
auto address= PPSSPP::emu_arg(stack)[1];
bool haveNamve;
auto s=Corda::readBinaryString(address,&haveNamve);
*split=haveNamve;
write_string_new(data,len,s);
}
bool ULJM05943F(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
std::regex pattern1("#n+");
std::string replacement1 = " ";
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){
if (hp->emu_addr != 0x886162c) {
auto addr=PPSSPP::emu_arg(stack)[0]+0x3c;
*data=addr;*len=strlen((char*)addr);
return;
}
auto address= PPSSPP::emu_arg(stack)[1];
bool haveNamve;
auto s=Corda::readBinaryString(address,&haveNamve);
*split=haveNamve;
write_string_new(data,len,s);
}
bool FULJM05603(LPVOID data, size_t *size, HookParam *)
{
auto text = reinterpret_cast<LPSTR>(data);
auto len = reinterpret_cast<size_t *>(size);
StringCharReplacer(text, len, "%N", 2, ' ');
StringFilter(text, len, "%K", 2);
StringFilter(text, len, "%P", 2);
bool ULJM05943F(void* data, size_t* len, HookParam* hp){
auto s = std::string((char*)data,*len);
std::regex pattern1("#n+");
std::string replacement1 = " ";
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);
}
bool FULJM05603(LPVOID data, size_t* size, HookParam*)
{
auto text = reinterpret_cast<LPSTR>(data);
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;
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;
}
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){
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);
}
i += 1;
}
return true;
}
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){
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);
bool NPJH50505F(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
std::regex pattern3("#FAMILY");
std::string replacement3 = "$FAMILY";
std::string result3 = std::regex_replace(result2, pattern3, replacement3);
std::regex pattern2("#RUBS(#[A-Z0-9]+)*[^#]+");
std::string replacement2 = "";
std::string result2 = std::regex_replace(s, pattern2, replacement2);
std::regex pattern4("#GIVE");
std::string replacement4 = "$GIVE";
std::string result4 = std::regex_replace(result3, pattern4, replacement4);
std::regex pattern3("#FAMILY");
std::string replacement3 = "$FAMILY";
std::string result3 = std::regex_replace(result2, pattern3, replacement3);
std::regex pattern5("(#[A-Z0-9\\-]+)+");
std::string replacement5 = "";
std::string result5 = std::regex_replace(result4, pattern5, replacement5);
std::regex pattern4("#GIVE");
std::string replacement4 = "$GIVE";
std::string result4 = std::regex_replace(result3, pattern4, replacement4);
std::regex pattern6("\\n+");
std::string replacement6 = " ";
std::string result6 = std::regex_replace(result5, pattern6, replacement6);
std::regex pattern5("(#[A-Z0-9\\-]+)+");
std::string replacement5 = "";
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;
bool safeautoleaveveh = false;
bool SendJitVeh(PCONTEXT context, uintptr_t address, uintptr_t em_addr, JITTYPE jittype)
{
if (safeautoleaveveh)
@ -295,7 +294,7 @@ void SearchForHooks_Return()
if (!records[i].em_addr)
continue;
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;
}
NotifyHookFound(hp, (wchar_t *)records[i].text);

View File

@ -101,6 +101,15 @@ void ConsoleOutput(LPCSTR text, ...)
vsnprintf(buffer.message, MESSAGE_SIZE, text, args);
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;
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 ConsoleOutput(LPCSTR text, ...);
void WarningOutput(LPCSTR text, ...);
void NotifyHookFound(HookParam hp, wchar_t *text);
void NotifyHookRemove(uint64_t addr, 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;
void delayinsertadd(HookParam, std::string);
void delayinsertNewHook(uintptr_t);
inline bool safeautoleaveveh = false;
inline bool dont_detach = false;
inline bool host_connected = false;

View File

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

View File

@ -292,12 +292,16 @@ LunaHost::LunaHost()
hooksearchwindow->show();
};
Host::Start(
Host::StartEx(
std::bind(&LunaHost::on_proc_connect, 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_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->addcontrol(g_selectprocessbutton, 0, 0);
@ -448,6 +452,10 @@ bool LunaHost::on_text_recv(TextThread &thread, std::wstring &output)
}
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)
{
wchar_t buff[65535];

View File

@ -116,6 +116,7 @@ class LunaHost : public mainwindow
void on_thread_delete(TextThread &thread);
void on_proc_connect(DWORD pid);
void on_proc_disconnect(DWORD pid);
void on_warning(const std::wstring &);
void showtext(const std::wstring &text, bool clear);
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;
auto currthread = (TextThread *)host->currentselect;
SelectedProcessId = (currthread != 0) ? currthread->tp.processId : 0;
DWORD (*GetSelectedProcessId)
DWORD(*GetSelectedProcessId)
() = []
{ return SelectedProcessId; };

View File

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

View File

@ -2,15 +2,14 @@
#include <io.h>
#include <fcntl.h>
int main()
{
_setmode(_fileno(stdout), _O_U16TEXT);
_setmode(_fileno(stdin), _O_U16TEXT);
wprintf_s(L"Usage: {'attach'|'detach'|hookcode} -Pprocessid\n");
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",
thread.handle,
thread.tp.processId,
@ -22,53 +21,67 @@ int main()
output.c_str()
);
fflush(stdout);
return false;
});
return false; });
wchar_t input[500] = {};
SearchParam sp = {};
sp.codepage = Host::defaultCodepage;
sp.length = 0;
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] = {};
DWORD processId = 0;
int split;
for (split = wcslen(input) - 1; split >= 1; split--) {
if (input[split] == L'P' && input[split-1]=='-') {
for (split = wcslen(input) - 1; split >= 1; split--)
{
if (input[split] == L'P' && input[split - 1] == '-')
{
processId = _wtoi(input + split + 1);
break;
}
}
if (split == 1)continue;// ExitProcess(0);
if (split == 1)
continue; // ExitProcess(0);
split -= 2;
while (split > 0 && input[split] == L' ')split -= 1;
if (split == 0)continue;//ExitProcess(0);
while (split > 0 && input[split] == L' ')
split -= 1;
if (split == 0)
continue; // ExitProcess(0);
input[split + 1] = 0;
wcscpy(command, input);
//if (swscanf(input, L"%500s -P%d", command, &processId) != 2) ExitProcess(0);
if (_wcsicmp(command, L"attach") == 0) Host::InjectProcess(processId);
else if (_wcsicmp(command, L"detach") == 0) { Host::DetachProcess(processId); }
else if (_wcsicmp(command, L"find") == 0) {
// if (swscanf(input, L"%500s -P%d", command, &processId) != 2) ExitProcess(0);
if (_wcsicmp(command, L"attach") == 0)
Host::InjectProcess(processId);
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>>();
try
{
Host::FindHooks(processId, sp,
[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]"))) {
hooks->push_back(std::wstring(hp.hookcode) + L"=>" + text + L"\n");
[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]")))
{
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]
{
{
for (int lastSize = 0; hooks->size() == 0 || hooks->size() != lastSize; Sleep(2000)) lastSize = hooks->size();
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);
}
fclose(out);
}).detach();
fclose(out); })
.detach();
}
else {
if (command[0] == L'-') {
else
{
if (command[0] == L'-')
{
try
{
unsigned long long address;
swscanf_s(command, L"-%llu", &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;
swscanf_s(command, L"=%d", &codepage);
Host::defaultCodepage = codepage;
}
else if (command[0] == L'+') {
else if (command[0] == L'+')
{
int flushDelay;
swscanf_s(command, L"+%d", &flushDelay);
TextThread::flushDelay = flushDelay;
}
else if (auto hp = HookCode::Parse(command)) Host::InsertHook(processId, hp.value());
else ExitProcess(0);
else if (auto hp = HookCode::Parse(command))
Host::InsertHook(processId, hp.value());
else
ExitProcess(0);
}
}
ExitProcess(0);

View File

@ -26,7 +26,7 @@ typedef void (*EmbedCallback)(const wchar_t *, ThreadParam);
wchar_t hookcode[HOOKCODE_LEN]; \
wcscpy_s(hookcode, HOOKCODE_LEN, thread.hp.hookcode); \
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(
Connect,
@ -56,6 +56,10 @@ C_LUNA_API void Luna_Start(ProcessEvent Connect, ProcessEvent Disconnect, Thread
[=](const std::wstring &output, const ThreadParam &tp)
{
embed(output.c_str(), tp);
},
[=](const std::wstring &output)
{
Warning(output.c_str());
});
}
C_LUNA_API void Luna_Inject(DWORD pid, LPCWSTR basepath)

View File

@ -1,20 +1,19 @@
#include "host.h"
typedef LONG NTSTATUS;
#include"yapi.hpp"
#include"Lang/Lang.h"
#include "yapi.hpp"
#include "Lang/Lang.h"
namespace
{
class ProcessRecord
{
public:
ProcessRecord(DWORD processId, HANDLE pipe) :
pipe(pipe),
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))
{
embedsharedmem=(EmbedSharedMem*)MapViewOfFile(mappedFile2, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(EmbedSharedMem));
//放到构造表里就不行,不知道为何。
ProcessRecord(DWORD processId, HANDLE pipe) : pipe(pipe),
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))
{
embedsharedmem = (EmbedSharedMem *)MapViewOfFile(mappedFile2, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, sizeof(EmbedSharedMem));
// 放到构造表里就不行,不知道为何。
}
~ProcessRecord()
@ -27,18 +26,17 @@ namespace
{
static_assert(sizeof(data) < PIPE_BUFFER_SIZE);
std::thread([=]
{
WriteFile(pipe, &data, sizeof(data), DUMMY, nullptr);
}).detach();
{ WriteFile(pipe, &data, sizeof(data), DUMMY, nullptr); })
.detach();
}
Host::HookEventHandler OnHookFound = [](HookParam hp, std::wstring text)
{
Host::AddConsoleOutput(std::wstring(hp.hookcode) + L": " + text);
};
EmbedSharedMem *embedsharedmem;
private:
HANDLE pipe;
AutoHandle<> mappedFile2;
@ -51,13 +49,16 @@ namespace
Host::ProcessEventHandler OnConnect, OnDisconnect;
Host::ThreadEventHandler OnCreate, OnDestroy;
Host::ConsoleHandler OnConsole=0;
Host::HookInsertHandler HookInsert=0;
Host::EmbedCallback embedcallback=0;
Host::ConsoleHandler OnConsole = 0;
Host::ConsoleHandler OnWarning = 0;
Host::HookInsertHandler HookInsert = 0;
Host::EmbedCallback embedcallback = 0;
void RemoveThreads(std::function<bool(ThreadParam)> removeIf)
{
std::vector<TextThread*> threadsToRemove;
for (auto& [tp, thread] : textThreadsByParams.Acquire().contents) if (removeIf(tp)) threadsToRemove.push_back(&thread);
std::vector<TextThread *> threadsToRemove;
for (auto &[tp, thread] : textThreadsByParams.Acquire().contents)
if (removeIf(tp))
threadsToRemove.push_back(&thread);
for (auto thread : threadsToRemove)
{
OnDestroy(*thread);
@ -76,14 +77,14 @@ namespace
void CreatePipe(int pid)
{
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),
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());
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);
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);
std::thread([hookPipe,hostPipe,pipeAvailableEvent]
{
std::thread([hookPipe, hostPipe, pipeAvailableEvent]
{
ConnectNamedPipe(hookPipe, nullptr);
CloseHandle(pipeAvailableEvent);
BYTE buffer[PIPE_BUFFER_SIZE] = {};
@ -141,6 +142,12 @@ namespace
Host::AddConsoleOutput(StringToWideString(info.message));
}
break;
case HOST_NOTIFICATION_WARNING:
{
auto info = *(WarningNotif*)buffer;
Host::Warning(StringToWideString(info.message));
}
break;
default:
{
auto data=(TextOutput_T*)buffer;
@ -179,8 +186,8 @@ namespace
RemoveThreads([&](ThreadParam tp) { return tp.processId == processId; });
OnDisconnect(processId);
Host::AddConsoleOutput(FormatString(PROC_DISCONN,processId));
processRecordsByIds->erase(processId);
}).detach();
processRecordsByIds->erase(processId); })
.detach();
}
}
@ -189,156 +196,200 @@ namespace Host
std::mutex threadmutex;
std::mutex outputmutex;
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)...);};
OnDisconnect = [=](auto &&...args){std::lock_guard _(procmutex);Disconnect(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)...);};
OnConnect = [=](auto &&...args)
{std::lock_guard _(procmutex);Connect(std::forward<decltype(args)>(args)...); };
OnDisconnect = [=](auto &&...args)
{std::lock_guard _(procmutex);Disconnect(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){
OnCreate(textThreadsByParams->try_emplace(console, console, HookParam{} ,CONSOLE ).first->second);
if (createconsole)
{
OnCreate(textThreadsByParams->try_emplace(console, console, HookParam{}, CONSOLE).first->second);
Host::AddConsoleOutput(ProjectHomePage);
}
//CreatePipe();
// CreatePipe();
}
void StartEx(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output,ConsoleHandler console,HookInsertHandler hookinsert,EmbedCallback embed){
Start(Connect,Disconnect,Create,Destroy,Output,false);
OnConsole=[=](auto &&...args){std::lock_guard _(outputmutex);console(std::forward<decltype(args)>(args)...);};
HookInsert=[=](auto &&...args){std::lock_guard _(threadmutex);hookinsert(std::forward<decltype(args)>(args)...);};
embedcallback=[=](auto &&...args){std::lock_guard _(outputmutex);embed(std::forward<decltype(args)>(args)...);};
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, !console.has_value());
if (warning.has_value())
OnWarning = warning.value();
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=(
PROCESS_CREATE_THREAD |
PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION |
PROCESS_VM_WRITE |
PROCESS_VM_READ);
bool SafeInject(HANDLE process,const std::wstring &location){
//#ifdef _WIN64
constexpr auto PROCESS_INJECT_ACCESS = (PROCESS_CREATE_THREAD |
PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION |
PROCESS_VM_WRITE |
PROCESS_VM_READ);
bool SafeInject(HANDLE process, const std::wstring &location)
{
// #ifdef _WIN64
#if 0
BOOL invalidProcess = FALSE;
IsWow64Process(process, &invalidProcess);
if (invalidProcess) return AddConsoleOutput(NEED_32_BIT);
#endif
bool succ=false;
if (LPVOID remoteData = VirtualAllocEx(process, nullptr, (location.size() + 1) * sizeof(wchar_t), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))
bool succ = false;
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);
if (AutoHandle<> thread = CreateRemoteThread(process, nullptr, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, remoteData, 0, nullptr)){
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);
WaitForSingleObject(thread, INFINITE);
succ = true;
}
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;
yapi::YAPICall LoadLibraryW(process, _T("kernel32.dll"), "LoadLibraryW");
if(x64)injectedDll = LoadLibraryW.Dw64()(location.c_str());
else injectedDll = LoadLibraryW(location.c_str());
if(injectedDll)return true;
return false;
if (x64)
injectedDll = LoadLibraryW.Dw64()(location.c_str());
else
injectedDll = LoadLibraryW(location.c_str());
if (injectedDll)
return true;
return false;
}
bool CheckProcess(DWORD processId){
if (processId == GetCurrentProcessId()) return false;
bool CheckProcess(DWORD processId)
{
if (processId == GetCurrentProcessId())
return false;
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;
}
bool InjectDll(DWORD processId,const std::wstring locationX){
bool InjectDll(DWORD processId, const std::wstring locationX)
{
AutoHandle<> process = OpenProcess(PROCESS_INJECT_ACCESS, FALSE, processId);
if(!process)return false;
bool proc64=Is64BitProcess(process);
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);
if (!process)
return false;
bool proc64 = Is64BitProcess(process);
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);
if(proc64==x64){
return (SafeInject(process,location));
if (proc64 == x64)
{
return (SafeInject(process, location));
}
else
{
return (UnSafeInject(process, location));
}
else{
return (UnSafeInject(process,location));
}
}
bool CreatePipeAndCheck(DWORD processId){
bool CreatePipeAndCheck(DWORD processId)
{
CreatePipe(processId);
return CheckProcess(processId);
}
void InjectProcess(DWORD processId,const std::wstring locationX)
void InjectProcess(DWORD processId, const std::wstring locationX)
{
auto check=CreatePipeAndCheck(processId);
if(check==false)return;
auto check = CreatePipeAndCheck(processId);
if (check == false)
return;
std::thread([=]
{
{
if(InjectDll(processId,locationX))return ;
AddConsoleOutput(INJECT_FAILED);
}).detach();
AddConsoleOutput(INJECT_FAILED); })
.detach();
}
void DetachProcess(DWORD processId)
{
auto &prs=processRecordsByIds.Acquire().contents;
if(prs.find(processId)==prs.end())return;
auto &prs = processRecordsByIds.Acquire().contents;
if (prs.find(processId) == prs.end())
return;
prs.at(processId).Send(HOST_COMMAND_DETACH);
}
void InsertHook(DWORD processId, HookParam hp)
{
auto &prs=processRecordsByIds.Acquire().contents;
if(prs.find(processId)==prs.end())return;
auto &prs = processRecordsByIds.Acquire().contents;
if (prs.find(processId) == prs.end())
return;
prs.at(processId).Send(InsertHookCmd(hp));
}
void RemoveHook(DWORD processId, uint64_t address)
{
auto &prs=processRecordsByIds.Acquire().contents;
if(prs.find(processId)==prs.end())return;
auto &prs = processRecordsByIds.Acquire().contents;
if (prs.find(processId) == prs.end())
return;
prs.at(processId).Send(RemoveHookCmd(address));
}
void FindHooks(DWORD processId, SearchParam sp, HookEventHandler HookFound)
{
auto &prs=processRecordsByIds.Acquire().contents;
if(prs.find(processId)==prs.end())return;
if (HookFound) prs.at(processId).OnHookFound = HookFound;
auto &prs = processRecordsByIds.Acquire().contents;
if (prs.find(processId) == prs.end())
return;
if (HookFound)
prs.at(processId).OnHookFound = HookFound;
prs.at(processId).Send(FindHookCmd(sp));
}
TextThread& GetThread(ThreadParam tp)
TextThread &GetThread(ThreadParam 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;
return nullptr;
for (auto &[tp, thread] : textThreadsByParams.Acquire().contents)
if (thread.handle == handle)
return &thread;
return nullptr;
}
EmbedSharedMem* GetEmbedSharedMem(DWORD processId){
auto &prs=processRecordsByIds.Acquire().contents;
if(prs.find(processId)==prs.end())return 0;
EmbedSharedMem *GetEmbedSharedMem(DWORD processId)
{
auto &prs = processRecordsByIds.Acquire().contents;
if (prs.find(processId) == prs.end())
return 0;
return prs.at(processId).embedsharedmem;
}
void AddConsoleOutput(std::wstring text)
{
if(OnConsole)
if (OnConsole)
OnConsole(std::move(text));
else
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"
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 ThreadEventHandler = std::function<void(TextThread&)>;
using HookEventHandler = std::function<void(const HookParam&,const std::wstring& text)>;
using HookInsertHandler= std::function<void(uint64_t,const std::wstring&)>;
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 StartEx(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output,ConsoleHandler console,HookInsertHandler hookinsert,EmbedCallback embed);
void InjectProcess(DWORD processId,const std::wstring locationX=L"");
using ThreadEventHandler = std::function<void(TextThread &)>;
using HookEventHandler = std::function<void(const HookParam &, const std::wstring &text)>;
using HookInsertHandler = std::function<void(uint64_t, const std::wstring &)>;
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 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"");
bool CreatePipeAndCheck(DWORD processId);
void DetachProcess(DWORD processId);
@ -19,13 +19,14 @@ namespace Host
void InsertHook(DWORD processId, HookParam hp);
void RemoveHook(DWORD processId, uint64_t address);
void FindHooks(DWORD processId, SearchParam sp, HookEventHandler HookFound = {});
EmbedSharedMem* GetEmbedSharedMem(DWORD pid);
TextThread* GetThread(int64_t handle);
TextThread& GetThread(ThreadParam tp);
EmbedSharedMem *GetEmbedSharedMem(DWORD pid);
TextThread *GetThread(int64_t handle);
TextThread &GetThread(ThreadParam tp);
void AddConsoleOutput(std::wstring text);
void Warning(std::wstring text);
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 "host.h"
#include"Lang/Lang.h"
#include "Lang/Lang.h"
// 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)
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 false;
}
TextThread::TextThread(ThreadParam tp, HookParam hp, std::optional<std::wstring> name) :
handle(threadCounter++),
name(name.value_or(StringToWideString(hp.name))),
tp(tp),
hp(hp)
{}
TextThread::TextThread(ThreadParam tp, HookParam hp, std::optional<std::wstring> name) : handle(threadCounter++),
name(name.value_or(StringToWideString(hp.name))),
tp(tp),
hp(hp)
{
}
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()
@ -34,9 +35,10 @@ void TextThread::AddSentence(std::wstring 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);
BYTE doubleByteChar[2];
@ -56,19 +58,23 @@ void TextThread::Push(BYTE* data, int length)
length = 0;
}
}
auto converted = commonparsestring(data,length,&hp,Host::defaultCodepage);
if(converted)
auto converted = commonparsestring(data, length, &hp, Host::defaultCodepage);
if (converted)
{
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();
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
{
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);
// not sure if this should filter repetition
@ -96,21 +102,24 @@ void TextThread::Flush()
{
{
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;
queuedSentences->swap(sentences);
int totalSize = 0;
for (auto& sentence : sentences)
for (auto &sentence : sentences)
{
totalSize += sentence.size();
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);
if (buffer.empty()) return;
if (buffer.empty())
return;
if (buffer.size() > maxBufferSize || GetTickCount64() - lastPushTime > flushDelay)
{
AddSentence(std::move(buffer));

View File

@ -1,14 +1,13 @@
#pragma once
class TextThread
{
public:
using OutputCallback = std::function<bool(TextThread&, std::wstring&)>;
using OutputCallback = std::function<bool(TextThread &, std::wstring &)>;
inline static OutputCallback Output;
inline static bool filterRepetition = false;
inline static int flushDelay = 100;
inline static int flushDelay = 100;
inline static int maxBufferSize = 3000;
inline static int maxHistorySize = 10'000'000;
@ -17,8 +16,8 @@ public:
void Start();
void Stop();
void AddSentence(std::wstring sentence);
void Push(BYTE* data, int length);
void Push(const wchar_t* data);
void Push(BYTE *data, int length);
void Push(const wchar_t *data);
Synchronized<std::wstring> storage;
const int64_t handle;
@ -37,6 +36,9 @@ private:
std::mutex bufferMutex;
DWORD64 lastPushTime = 0;
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;
};

View File

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

View File

@ -183,6 +183,12 @@ struct ConsoleOutputNotif // From dll
HostNotificationType command = HOST_NOTIFICATION_TEXT;
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
{