diff --git a/LunaHook/engine32/V8.cpp b/LunaHook/engine32/V8.cpp index 2dfc0e7..1cb9d87 100644 --- a/LunaHook/engine32/V8.cpp +++ b/LunaHook/engine32/V8.cpp @@ -1,5 +1,5 @@ #include"V8.h" - +#include"v8/v8.h" /** * Artikash 7/15/2018: Insert Tyranobuilder hook * Sample game: https://vndb.org/v22252: /HWN-8:-1C@233A54:yuika_t.exe @@ -105,53 +105,6 @@ bool hookv8exports(HMODULE module) { return NewHook(hp, "Write@String@v8"); } -namespace{ - bool hookstringlength(HMODULE hm){ - auto Length=GetProcAddress(hm,"?Length@String@v8@@QBEHXZ"); - static uintptr_t WriteUtf8; - static uintptr_t Utf8Length; - WriteUtf8=(uintptr_t)GetProcAddress(hm,"?WriteUtf8@String@v8@@QBEHPADHPAHH@Z"); - Utf8Length=(uintptr_t)GetProcAddress(hm,"?Utf8Length@String@v8@@QBEHXZ"); - if(Length==0||WriteUtf8==0||Utf8Length==0)return false; - HookParam hp; - hp.address=(uintptr_t)Length; - hp.type=USING_STRING|CODEC_UTF8; - hp.text_fun= - [](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len) - { - auto length=((size_t(__thiscall*)(void*))Utf8Length)((void*)stack->ecx); - if(!length)return; - auto u8str=new char[length+1]; - int writen; - ((size_t(__thiscall*)(void*,char*,int,int*,int))WriteUtf8)((void*)stack->ecx,u8str,length,&writen,0); - *data=(uintptr_t)u8str; - *len=length; - - }; - return NewHook(hp,"v8::String::Length"); - } -} -namespace{ - bool hookClipboard(){ - HookParam hp; - hp.address=(uintptr_t)SetClipboardData; - hp.type= USING_STRING|CODEC_UTF16|EMBED_ABLE|EMBED_BEFORE_SIMPLE; - hp.text_fun=[](hook_stack* stack, HookParam *hp, uintptr_t* data, uintptr_t* split, size_t* len){ - HGLOBAL hClipboardData=(HGLOBAL)stack->stack[2]; - *data=(uintptr_t)GlobalLock(hClipboardData); - *len=wcslen((wchar_t*)*data)*2; - GlobalUnlock(hClipboardData); - }; - hp.hook_after=[](hook_stack*s,void* data, size_t len){ - HGLOBAL hClipboardData = GlobalAlloc(GMEM_MOVEABLE, len +2); - auto pchData = (wchar_t*)GlobalLock(hClipboardData); - wcscpy(pchData, (wchar_t*)data); - GlobalUnlock(hClipboardData); - s->stack[2]=(uintptr_t)hClipboardData; - }; - return NewHook(hp,"hookClipboard"); - } -} bool V8::attach_function_() { for (const wchar_t* moduleName : { (const wchar_t*)NULL, L"node.dll", L"nw.dll" }) { auto hm=GetModuleHandleW(moduleName); @@ -161,9 +114,8 @@ bool V8::attach_function_() { bool b1= InsertV8Hook(hm); bool b2=hookv8addr(hm); bool b3=hookv8exports(hm); - b1=hookstringlength(hm)||b1; + b1=tryhookv8(hm)||b1; if(b1||b2||b3){ - hookClipboard(); return true; } } diff --git a/LunaHook/engine64/V8.cpp b/LunaHook/engine64/V8.cpp index 364aaac..e076fb4 100644 --- a/LunaHook/engine64/V8.cpp +++ b/LunaHook/engine64/V8.cpp @@ -1,6 +1,5 @@ #include"V8.h" - - +#include"v8/v8.h" // Artikash 6/23/2019: V8 (JavaScript runtime) has rcx = string** at v8::String::Write // sample game https://www.freem.ne.jp/dl/win/18963 bool InsertV8Hook(HMODULE module) @@ -259,65 +258,16 @@ namespace{ return innerHTML(module)|| success; } } -namespace{ - bool hookstringlength(HMODULE hm){ - auto Length=GetProcAddress(hm,"?Length@String@v8@@QEBAHXZ"); - static uintptr_t WriteUtf8; - static uintptr_t Utf8Length; - WriteUtf8=(uintptr_t)GetProcAddress(hm,"?WriteUtf8@String@v8@@QEBAHPEADHPEAHH@Z"); - Utf8Length=(uintptr_t)GetProcAddress(hm,"?Utf8Length@String@v8@@QEBAHXZ"); - if(Length==0||WriteUtf8==0||Utf8Length==0)return false; - HookParam hp; - hp.address=(uintptr_t)Length; - hp.type=USING_STRING|CODEC_UTF8; - hp.text_fun= - [](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len) - { - auto length=((size_t(*)(void*))Utf8Length)((void*)stack->rcx); - if(!length)return; - auto u8str=new char[length+1]; - int writen; - ((size_t(*)(void*,char*,int,int*,int))WriteUtf8)((void*)stack->rcx,u8str,length,&writen,0); - *data=(uintptr_t)u8str; - *len=length; - }; - return NewHook(hp,"v8::String::Length"); - } -} -namespace{ - bool hookClipboard(){ - HookParam hp; - hp.address=(uintptr_t)SetClipboardData; - hp.type= USING_STRING|CODEC_UTF16|EMBED_ABLE|EMBED_BEFORE_SIMPLE; - hp.text_fun=[](hook_stack* stack, HookParam *hp, uintptr_t* data, uintptr_t* split, size_t* len){ - HGLOBAL hClipboardData=(HGLOBAL)stack->rdx; - *data=(uintptr_t)GlobalLock(hClipboardData); - *len=wcslen((wchar_t*)*data)*2; - GlobalUnlock(hClipboardData); - }; - hp.hook_after=[](hook_stack*s,void* data, size_t len){ - HGLOBAL hClipboardData = GlobalAlloc(GMEM_MOVEABLE, len +2); - auto pchData = (wchar_t*)GlobalLock(hClipboardData); - wcscpy(pchData, (wchar_t*)data); - GlobalUnlock(hClipboardData); - s->rdx=(uintptr_t)hClipboardData; - }; - return NewHook(hp,"hookClipboard"); - } -} bool V8::attach_function_() { for (const wchar_t* moduleName : { (const wchar_t*)NULL, L"node.dll", L"nw.dll" }) { auto hm=GetModuleHandleW(moduleName); if(hm==0)continue; bool ok=InsertV8Hook(hm); ok= hookv8exports(hm)||ok; - ok=hookstringlength(hm)||ok; ok=addhooks(hm)||ok; - if(ok){ - hookClipboard(); - return true; - } + ok=tryhookv8(hm); + if(ok) return true; } return false; } diff --git a/LunaHook/engines/CMakeLists.txt b/LunaHook/engines/CMakeLists.txt index 7f6282d..21bfb12 100644 --- a/LunaHook/engines/CMakeLists.txt +++ b/LunaHook/engines/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(commonengine python/python2.cpp python/python3.cpp python/python.cpp pchooks/pchooks.cpp) +add_library(commonengine v8/v8.cpp python/python2.cpp python/python3.cpp python/python.cpp pchooks/pchooks.cpp) target_precompile_headers(commonengine REUSE_FROM pch) diff --git a/LunaHook/engines/v8/v8.cpp b/LunaHook/engines/v8/v8.cpp new file mode 100644 index 0000000..55a7f99 --- /dev/null +++ b/LunaHook/engines/v8/v8.cpp @@ -0,0 +1,220 @@ +#include"types.h" +#include"main.h" +#include"v8.h" +#ifndef _WIN64 +#define arg2 stack[2] +#else +#define arg2 rdx +#endif +namespace{ + + bool hookClipboard(){ + HookParam hp; + hp.address=(uintptr_t)SetClipboardData; + hp.type= USING_STRING|CODEC_UTF16|EMBED_ABLE|EMBED_BEFORE_SIMPLE; + hp.text_fun=[](hook_stack* stack, HookParam *hp, uintptr_t* data, uintptr_t* split, size_t* len){ + HGLOBAL hClipboardData=(HGLOBAL)stack->arg2; + *data=(uintptr_t)GlobalLock(hClipboardData); + *len=wcslen((wchar_t*)*data)*2; + GlobalUnlock(hClipboardData); + }; + hp.hook_after=[](hook_stack*s,void* data, size_t len){ + HGLOBAL hClipboardData = GlobalAlloc(GMEM_MOVEABLE, len +2); + auto pchData = (wchar_t*)GlobalLock(hClipboardData); + wcscpy(pchData, (wchar_t*)data); + GlobalUnlock(hClipboardData); + s->arg2=(uintptr_t)hClipboardData; + }; + return NewHook(hp,"hookClipboard"); + } +} +namespace v8script{ +HMODULE hmodule; +#ifndef _WIN64 + +#define fnNewFromUtf8v2 "?NewFromUtf8@String@v8@@SA?AV?$MaybeLocal@VString@v8@@@2@PAVIsolate@2@PBDW4NewStringType@2@H@Z" +#define fnNewFromUtf8v1 "?NewFromUtf8@String@v8@@SA?AV?$Local@VString@v8@@@2@PAVIsolate@2@PBDW4NewStringType@12@H@Z" +#define fnGetCurrentContext "?GetCurrentContext@Isolate@v8@@QAE?AV?$Local@VContext@v8@@@2@XZ" +#define fnCompilev1 "?Compile@Script@v8@@SA?AV?$Local@VScript@v8@@@2@V?$Handle@VString@v8@@@2@PAVScriptOrigin@2@@Z" +#define fnCompilev12 "?Compile@Script@v8@@SA?AV?$Local@VScript@v8@@@2@V?$Local@VString@v8@@@2@PAVScriptOrigin@2@@Z" +#define fnRunv1 "?Run@Script@v8@@QAE?AV?$Local@VValue@v8@@@2@XZ" +#define fnCompilev2 "?Compile@Script@v8@@SA?AV?$MaybeLocal@VScript@v8@@@2@V?$Local@VContext@v8@@@2@V?$Local@VString@v8@@@2@PAVScriptOrigin@2@@Z" +#define fnRunv2 "?Run@Script@v8@@QAE?AV?$MaybeLocal@VValue@v8@@@2@V?$Local@VContext@v8@@@2@@Z" +typedef void*(__thiscall *GetCurrentContextt)(void*, void*); + +typedef void*(__thiscall*Runt1)(void*,void*); +typedef void*(__thiscall*Runt2)(void*,void*,void*); + +#else +#define fnNewFromUtf8v2 "?NewFromUtf8@String@v8@@SA?AV?$MaybeLocal@VString@v8@@@2@PEAVIsolate@2@PEBDW4NewStringType@2@H@Z" +#define fnNewFromUtf8v1 "?NewFromUtf8@String@v8@@SA?AV?$Local@VString@v8@@@2@PEAVIsolate@2@PEBDW4NewStringType@12@H@Z" +#define fnGetCurrentContext "?GetCurrentContext@Isolate@v8@@QEAA?AV?$Local@VContext@v8@@@2@XZ" +#define fnCompilev1 "?Compile@Script@v8@@SA?AV?$Local@VScript@v8@@@2@V?$Handle@VString@v8@@@2@PEAVScriptOrigin@2@@Z" +#define fnCompilev12 fnCompilev1 +#define fnRunv1 "?Run@Script@v8@@QEAA?AV?$Local@VValue@v8@@@2@XZ" +#define fnCompilev2 "?Compile@Script@v8@@SA?AV?$MaybeLocal@VScript@v8@@@2@V?$Local@VContext@v8@@@2@V?$Local@VString@v8@@@2@PEAVScriptOrigin@2@@Z" +#define fnRunv2 "?Run@Script@v8@@QEAA?AV?$MaybeLocal@VValue@v8@@@2@V?$Local@VContext@v8@@@2@@Z" +typedef void*(*GetCurrentContextt)(void*, void*); +typedef void*(*Runt1)(void*,void*); +typedef void*(*Runt2)(void*,void*,void*); +#endif +typedef void*(*NewFromUtf8t)(void*, void*, const char*, int, int) ; +typedef void*(*Compilet)(void*, void*, void*, void*); + +bool v8runscript_isolate(void* isolate){ + + if(isolate==0)return false; + NewFromUtf8t NewFromUtf8=0; + GetCurrentContextt GetCurrentContext ; + Compilet Compile; + void* Run; + auto NewFromUtf8v2 = (decltype(NewFromUtf8))GetProcAddress(hmodule, fnNewFromUtf8v2); + auto NewFromUtf8v1 = (decltype(NewFromUtf8))GetProcAddress(hmodule, fnNewFromUtf8v1); + + GetCurrentContext = (decltype(GetCurrentContext))GetProcAddress(hmodule, fnGetCurrentContext); + + if(NewFromUtf8v1) + { + NewFromUtf8=NewFromUtf8v1; + Compile = (decltype(Compile))GetProcAddress(hmodule, fnCompilev1); + if(!Compile) Compile=(decltype(Compile))GetProcAddress(hmodule, fnCompilev12); + Run = (decltype(Run))GetProcAddress(hmodule, fnRunv1); + } + else if(NewFromUtf8v2) + { + NewFromUtf8=NewFromUtf8v2; + Compile = (decltype(Compile))GetProcAddress(hmodule, fnCompilev2); + Run = (decltype(Run))GetProcAddress(hmodule, fnRunv2); + } + ConsoleOutput("%p %p",NewFromUtf8v1,NewFromUtf8v2); + ConsoleOutput("%p %p %p %p",GetCurrentContext, NewFromUtf8, Compile, Run); + if(!(GetCurrentContext && NewFromUtf8 && Compile && Run))return false; + + + void* context; + void* v8string; + void* script; + void* useless; + ConsoleOutput("isolate %p",isolate); + GetCurrentContext(isolate,&context); + ConsoleOutput("context %p",context); + if(context==0)return false; + NewFromUtf8(&v8string,isolate,LoadResData(L"lunajspatch",L"JSSOURCE").c_str(),1,-1); + ConsoleOutput("v8string %p",v8string); + if(v8string==0)return false; + if(NewFromUtf8v1) + { + Compile(&script,v8string,0,0); + ConsoleOutput("script %p",script); + if(script==0)return false; + ((Runt1)Run)(script,&useless); + } + else if(NewFromUtf8v2) + { + Compile(&script,context,v8string,0); + ConsoleOutput("script %p",script); + if(script==0)return false; + ((Runt2)Run)(script,&useless,context); + ConsoleOutput("useless %p",useless); + } + return true; +} + +void v8runscript_isolate_bypass(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){ + + hp->type=HOOK_EMPTY;hp->text_fun=nullptr; +#ifndef _WIN64 +#define isolatearg stack[2] +#else +#define isolatearg rdx +#endif + auto isolate=(void*)stack->isolatearg;//测试正确,且和v8::Isolate::GetCurrent结果相同 + + v8runscript_isolate(isolate); +} +void* v8getcurrisolate(HMODULE hmod){ +#ifndef _WIN64 +#define fnGetCurrent "?GetCurrent@Isolate@v8@@SAPAV12@XZ" +#define fnTryGetCurrent "?TryGetCurrent@Isolate@v8@@SAPAV12@XZ" +#else +#define fnGetCurrent "?GetCurrent@Isolate@v8@@SAPEAV12@XZ" +#define fnTryGetCurrent "?TryGetCurrent@Isolate@v8@@SAPEAV12@XZ" +#endif + void* GetCurrent; + GetCurrent = GetProcAddress(hmod, fnGetCurrent); + if ( !GetCurrent ) + GetCurrent = GetProcAddress(hmod, fnTryGetCurrent); + if(!GetCurrent)return 0; + auto isolate=((void*(*)())GetCurrent)(); + return isolate; +} +bool v8runscript(HMODULE _hmodule){ + auto isolate=v8getcurrisolate(_hmodule); + if(isolate) + return v8runscript_isolate(isolate); +#ifndef _WIN64 +#define isolategetter "?NewFromUtf8@String@v8@@SA?AV?$Local@VString@v8@@@2@PAVIsolate@2@PBDW4NewStringType@12@H@Z" +#else +#define isolategetter "?Utf8Length@String@v8@@QEBAHPEAVIsolate@2@@Z" //旧版没有 +//??0TryCatch@v8@@QEAA@PEAVIsolate@1@@Z也可以,但是有报错 +#endif + auto stringlengthisolate=GetProcAddress(_hmodule,isolategetter); + if(!stringlengthisolate)return false; + + hmodule=_hmodule; + HookParam hp; + hp.address=(uintptr_t)stringlengthisolate; + hp.text_fun=v8runscript_isolate_bypass; + return NewHook(hp,"v8isolate"); + +} +} +namespace{ + bool hookstringlength(HMODULE hm){ + #ifndef _WIN64 + #define v8StringLength "?Length@String@v8@@QBEHXZ" + #define v8StringWriteUtf8 "?WriteUtf8@String@v8@@QBEHPADHPAHH@Z" + #define v8StringUtf8Length "?Utf8Length@String@v8@@QBEHXZ" + #else + #define v8StringLength "?Length@String@v8@@QEBAHXZ" + #define v8StringWriteUtf8 "?WriteUtf8@String@v8@@QEBAHPEADHPEAHH@Z" + #define v8StringUtf8Length "?Utf8Length@String@v8@@QEBAHXZ" + #endif + auto Length=GetProcAddress(hm,v8StringLength); + static uintptr_t WriteUtf8; + static uintptr_t Utf8Length; + WriteUtf8=(uintptr_t)GetProcAddress(hm,v8StringWriteUtf8); + Utf8Length=(uintptr_t)GetProcAddress(hm,v8StringUtf8Length); + if(Length==0||WriteUtf8==0||Utf8Length==0)return false; + HookParam hp; + hp.address=(uintptr_t)Length; + hp.type=USING_STRING|CODEC_UTF8; + hp.text_fun= + [](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len) + { + #ifndef _WIN64 + auto length=((size_t(__thiscall*)(void*))Utf8Length)((void*)stack->ecx); + #else + auto length=((size_t(*)(void*))Utf8Length)((void*)stack->rcx); + #endif + if(!length)return; + auto u8str=new char[length+1]; + int writen; + #ifndef _WIN64 + ((size_t(__thiscall*)(void*,char*,int,int*,int))WriteUtf8)((void*)stack->ecx,u8str,length,&writen,0); + #else + ((size_t(*)(void*,char*,int,int*,int))WriteUtf8)((void*)stack->rcx,u8str,length,&writen,0); + #endif + *data=(uintptr_t)u8str; + *len=length; + + }; + return NewHook(hp,"v8::String::Length"); + } +} +bool tryhookv8(HMODULE hm){ + auto succ=hookstringlength(hm); + if(v8script::v8runscript(hm)) + succ|= hookClipboard(); + return succ; +} \ No newline at end of file diff --git a/LunaHook/engines/v8/v8.h b/LunaHook/engines/v8/v8.h new file mode 100644 index 0000000..8634b71 --- /dev/null +++ b/LunaHook/engines/v8/v8.h @@ -0,0 +1,2 @@ + +bool tryhookv8(HMODULE hm); \ No newline at end of file diff --git a/LunaHook/resource.rc b/LunaHook/resource.rc index 0cc00cf..59bf83b 100644 --- a/LunaHook/resource.rc +++ b/LunaHook/resource.rc @@ -6,4 +6,6 @@ compound_chars_Robotics_Notes_Elite COMPOUND_CHARS "resource/compound_chars_Robo compound_chars_Robotics_Notes_Dash COMPOUND_CHARS "resource/compound_chars_Robotics_Notes_Dash.txt" renpy_hook_font PYSOURCE "resource/renpy_hook_font.py" -renpy_hook_text PYSOURCE "resource/renpy_hook_text.py" \ No newline at end of file +renpy_hook_text PYSOURCE "resource/renpy_hook_text.py" + +lunajspatch JSSOURCE "resource/lunajspatch.js" \ No newline at end of file diff --git a/LunaHook/resource/lunajspatch.js b/LunaHook/resource/lunajspatch.js new file mode 100644 index 0000000..17bdc79 --- /dev/null +++ b/LunaHook/resource/lunajspatch.js @@ -0,0 +1,47 @@ + + +function NWjshook(){ + function NWjssend(s) { + const _clipboard = require('nw.gui').Clipboard.get(); + _clipboard.set(s, 'text'); + return _clipboard.get('text') + } + if(Window_Message.prototype.originstartMessage)return; + Window_Message.prototype.originstartMessage=Window_Message.prototype.startMessage; + Window_Message.prototype.startMessage = function() + { + gametext = $gameMessage.allText(); + resp=NWjssend(gametext); + $gameMessage._texts=[resp] + this.originstartMessage(); + }; +} + +function Electronhook() { + + function Electronsend(s) { + const { clipboard } = require('electron'); + clipboard.writeText(s); + return clipboard.readText(); + } + if(tyrano.plugin.kag.tag.text.originshowMessage)return; + tyrano.plugin.kag.tag.text.originshowMessage=tyrano.plugin.kag.tag.text.showMessage; + tyrano.plugin.kag.tag.text.showMessage = function () { + arguments[0]=Electronsend(arguments[0]); + return tyrano.plugin.kag.tag.text.originshowMessage.apply(this, arguments); + } + +} +function retryinject(times){ + if(times==0)return; + if(window.tyrano && tyrano.plugin){ + Electronhook(); + } + else if(window.Utils && Utils.RPGMAKER_NAME){ + NWjshook(); + } + else{ + setTimeout(retryinject,3000,times-1); + } +} +setTimeout(retryinject,3000,3); \ No newline at end of file