LunaHook-mirror/LunaHook/engines/v8/v8.cpp
恍兮惚兮 6a43cd5b86 pch
2024-05-06 23:31:54 +08:00

263 lines
10 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include"v8.h"
namespace{
constexpr auto magicsend =L"\x01LUNAFROMJS\x01";
constexpr auto magicrecv =L"\x01LUNAFROMHOST\x01";
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;
auto text=(wchar_t*)GlobalLock(hClipboardData);
if(startWith(text,magicsend)){
text+=wcslen(magicsend);
auto spl=wcschr(text,L'\x02');
*split=std::stoi(std::wstring(text,spl-text));
text=spl+1;
*data=(uintptr_t)text;
*len=wcslen(text)*2;
}
GlobalUnlock(hClipboardData);
};
hp.hook_after=[](hook_stack*s,void* data, size_t len){
std::wstring transwithfont=magicrecv;
transwithfont+=embedsharedmem->fontFamily;
transwithfont+=L'\x02';
transwithfont+=std::wstring((wchar_t*)data,len/2);
HGLOBAL hClipboardData = GlobalAlloc(GMEM_MOVEABLE, transwithfont.size()*2 +2);
auto pchData = (wchar_t*)GlobalLock(hClipboardData);
wcscpy(pchData, (wchar_t*)transwithfont.c_str());
GlobalUnlock(hClipboardData);
s->ARG2=(uintptr_t)hClipboardData;
};
return NewHook(hp,"hookClipboard");
}
}
namespace v8script{
HMODULE hmodule;
typedef void(*RequestInterrupt_callback)(void*, void*);
#ifndef _WIN64
#define fnRequestInterrupt "?RequestInterrupt@Isolate@v8@@QAEXP6AXPAV12@PAX@Z1@Z"
#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"
#else
#define fnRequestInterrupt "?RequestInterrupt@Isolate@v8@@QEAAXP6AXPEAV12@PEAX@Z1@Z"
#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"
#endif
typedef void*(THISCALL *GetCurrentContextt)(void*, void*);
typedef void*(THISCALL *Runt1)(void*,void*);
typedef void*(THISCALL *Runt2)(void*,void*,void*);
typedef void*(THISCALL *RequestInterruptt)(void*, RequestInterrupt_callback, void*);
typedef void*(*NewFromUtf8t)(void*, void*, const char*, int, int) ;
typedef void*(*Compilet)(void*, void*, void*, void*);
RequestInterruptt RequestInterrupt;
NewFromUtf8t NewFromUtf8=0,NewFromUtf8v2,NewFromUtf8v1;
GetCurrentContextt GetCurrentContext ;
Compilet Compile;
void* Run;
bool v8runscript_isolate(void* isolate){
if(isolate==0)return false;
RequestInterrupt= (decltype(RequestInterrupt))GetProcAddress(hmodule, fnRequestInterrupt);
NewFromUtf8v2 = (decltype(NewFromUtf8))GetProcAddress(hmodule, fnNewFromUtf8v2);
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 && RequestInterrupt))return false;
if(RequestInterrupt==0)return false;
RequestInterrupt(isolate,+[](void*isolate,void*){
void* context;
void* v8string;
void* script;
void* useless;
ConsoleOutput("isolate %p",isolate);
GetCurrentContext(isolate,&context);
ConsoleOutput("context %p",context);
if(context==0)return;
NewFromUtf8(&v8string,isolate,LoadResData(L"lunajspatch",L"JSSOURCE").c_str(),1,-1);
ConsoleOutput("v8string %p",v8string);
if(v8string==0)return;
if(NewFromUtf8v1)
{
Compile(&script,v8string,0,0);
ConsoleOutput("script %p",script);
if(script==0)return;
((Runt1)Run)(script,&useless);
ConsoleOutput("useless %p",useless);
}
else if(NewFromUtf8v2)
{
Compile(&script,context,v8string,0);
ConsoleOutput("script %p",script);
if(script==0)return ;
((Runt2)Run)(script,&useless,context);
ConsoleOutput("useless %p",useless);
}
},0);
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;
auto isolate=(void*)stack->ARG2;//测试正确且和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 fnisolategetters {"?New@Number@v8@@SA?AV?$Local@VNumber@v8@@@2@PEAVIsolate@2@N@Z","?New@Number@v8@@SA?AV?$Local@VNumber@v8@@@2@PAVIsolate@2@N@Z","?NewFromUtf8@String@v8@@SA?AV?$Local@VString@v8@@@2@PAVIsolate@2@PBDW4NewStringType@12@H@Z"}
#else
#define fnisolategetters {"?New@Integer@v8@@SA?AV?$Local@VInteger@v8@@@2@PEAVIsolate@2@H@Z","?New@Number@v8@@SA?AV?$Local@VNumber@v8@@@2@PEAVIsolate@2@N@Z","?New@Number@v8@@SA?AV?$Local@VNumber@v8@@@2@PAVIsolate@2@N@Z","?NewFromUtf8@String@v8@@SA?AV?$Local@VString@v8@@@2@PEAVIsolate@2@PEBDW4NewStringType@12@H@Z","?Utf8Length@String@v8@@QEBAHPEAVIsolate@2@@Z"}
#endif
bool succ=false;
for(auto fnisolategetter:fnisolategetters){
auto isolategetter=GetProcAddress(_hmodule,fnisolategetter);
if(!isolategetter)continue;
hmodule=_hmodule;
HookParam hp;
hp.address=(uintptr_t)isolategetter;
hp.text_fun=v8runscript_isolate_bypass;
succ|= NewHook(hp,"isolategetter");
}
return succ;
}
}
namespace{
#ifndef _WIN64
#define v8StringLength "?Length@String@v8@@QBEHXZ"
#define v8StringWriteUtf8 "?WriteUtf8@String@v8@@QBEHPADHPAHH@Z"
#define v8StringUtf8Length "?Utf8Length@String@v8@@QBEHXZ"
#define v8StringWrite "?Write@String@v8@@QBEHPAGHHH@Z"
#define v8StringWriteIsolate "?Write@String@v8@@QBEHPAVIsolate@2@PAGHHH@Z"
#else
#define v8StringLength "?Length@String@v8@@QEBAHXZ"
#define v8StringWriteUtf8 "?WriteUtf8@String@v8@@QEBAHPEADHPEAHH@Z"
#define v8StringUtf8Length "?Utf8Length@String@v8@@QEBAHXZ"
#define v8StringWrite "?Write@String@v8@@QEBAHPEAGHHH@Z"
#define v8StringWriteIsolate "?Write@String@v8@@QEBAHPEAVIsolate@2@PEAGHHH@Z"
#endif
uintptr_t WriteUtf8;
uintptr_t Utf8Length;
bool hookstring(HMODULE hm){
WriteUtf8=(uintptr_t)GetProcAddress(hm,v8StringWriteUtf8);
Utf8Length=(uintptr_t)GetProcAddress(hm,v8StringUtf8Length);
if(WriteUtf8==0||Utf8Length==0)return false;
HookParam hp;
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->THISCALLTHIS);
if(!length)return;
auto u8str=new char[length+1];
int writen;
((size_t(THISCALL *)(void*,char*,int,int*,int))WriteUtf8)((void*)stack->THISCALLTHIS,u8str,length,&writen,0);
*data=(uintptr_t)u8str;
*len=length;
};
hp.filter_fun=[](void* data, size_t* len, HookParam* hp){
if(strstr((char*)data,R"(\\?\)")!=0)return false;//过滤路径
return true;
};
bool succ=false;
auto pv8StringLength=GetProcAddress(hm,v8StringLength);
if(pv8StringLength){
hp.address=(uintptr_t)pv8StringLength;
succ|=NewHook(hp,"v8::String::Length");
}
auto pv8StringWrite=GetProcAddress(hm,v8StringWrite);
if(pv8StringWrite){
hp.address=(uintptr_t)pv8StringWrite;
succ|=NewHook(hp,"v8::String::Write");
}
auto pv8StringWriteIsolate=GetProcAddress(hm,v8StringWriteIsolate);
if(pv8StringWriteIsolate){
hp.address=(uintptr_t)pv8StringWriteIsolate;
succ|=NewHook(hp,"v8::String::Write::isolate");
}
return succ;
}
}
bool tryhookv8_internal(HMODULE hm){
auto succ=hookstring(hm);
if(!std::filesystem::exists(std::filesystem::path(GetModuleFilename().value()).replace_filename("disable.clipboard")))
if(v8script::v8runscript(hm))
succ|= hookClipboard();
return succ;
}
bool tryhookv8() {
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=tryhookv8_internal(hm);
if(ok) return true;
}
return false;
}