#include"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) { uint64_t addr1 = (uint64_t)GetProcAddress(module, "?Write@String@v8@@QEBAHPEAGHHH@Z"), // Artikash 6/7/2021: Add new hook for new version of V8 used by RPG Maker MZ addr2 = (uint64_t)GetProcAddress(module, "??$WriteToFlat@G@String@internal@v8@@SAXV012@PEAGHH@Z"); if (addr1 || addr2) { std::tie(spDefault.minAddress, spDefault.maxAddress) = Util::QueryModuleLimits(module); spDefault.maxRecords = Util::SearchMemory(spDefault.pattern, spDefault.length, PAGE_EXECUTE, spDefault.minAddress, spDefault.maxAddress).size() * 20; ConsoleOutput("JavaScript hook is known to be low quality: try searching for hooks if you don't like it"); } auto succ=false; if (addr1) { HookParam hp; hp.type = USING_STRING | CODEC_UTF16; hp.address = addr1; hp.text_fun = [](hook_stack* stack, HookParam *hp, uintptr_t* data, uintptr_t* split, size_t* count) { *data=(*(uintptr_t*)(stack->rcx))+23; int len = *(int*)(*data - 4); if(wcslen((wchar_t*)*data)*2rcx)+11; int len = *(int*)(*data - 4); if(wcslen((wchar_t*)*data)*2rcx)+0xf; int len = *(uintptr_t*)((uintptr_t)*data - 4); if(strlen((char*)*data)==len){ *count = len; hp->type=USING_STRING|CODEC_UTF8| DATA_INDIRECT|NO_CONTEXT; *split = (strchr((char*)*data, '<') != nullptr)&&(strchr((char*)*data, '>') != nullptr); *split+=0x10; } else if((wcslen((wchar_t*)*data)==len)){ *count = len*2; *split = (wcschr((wchar_t*)*data, L'<') != nullptr)&&(wcschr((wchar_t*)*data, L'>') != nullptr); hp->type=USING_STRING|CODEC_UTF16| DATA_INDIRECT|NO_CONTEXT; } else{ //ConsoleOutput("%d %d %d",len,strlen((char*)*data),wcslen((wchar_t*)*data)); return; } }; // hp.filter_fun=[](void* data, uintptr_t* size, HookParam*) { // auto text = reinterpret_cast(data); // std::wstring str = text; // str = str.substr(0, *size / 2); // std::wregex reg1(L"(.*?)"); // std::wstring result2 = std::regex_replace(str, reg1, L""); // std::wregex reg12(L"(.*?)"); // result2 = std::regex_replace(result2, reg12, L""); // std::wregex reg2(L"<(.*?)>"); // result2 = std::regex_replace(result2, reg2, L""); // std::wregex reg22(L"\n"); // result2 = std::regex_replace(result2, reg22, L""); // *size = (result2.size()) * 2; // wcscpy(text, result2.c_str()); // return true; // }; return NewHook(hp, "Write@String@v8"); } namespace{ uintptr_t forwardsearch(BYTE* b,int size,uintptr_t addr,int range){ for(int i=0;i hookw(HMODULE module){ const BYTE BYTES[] = { 0x81,XX,0x00,0xf8,0x00,0x00 }; std::vectorsave; auto addrs = Util::SearchMemory(BYTES, sizeof(BYTES), PAGE_EXECUTE, processStartAddress, processStopAddress); for(auto addr:addrs){ auto addrsave=addr; BYTE sig1[]={0x81,XX,0x00,0xD8,0x00,0x00}; BYTE sig2[]={0x81,XX,0x00,0xFC,0x00,0x00}; BYTE sig3[]={0x81,XX,0x00,0xDC,0x00,0x00}; BYTE sig4[]={XX,0x00,0x24,0xA0,0xFC}; addr=forwardsearch(sig1,sizeof(sig1),addr,0x20); if(addr==0)continue; addr=forwardsearch(sig2,sizeof(sig2),addr,0x100); if(addr==0)continue; addr=forwardsearch(sig3,sizeof(sig3),addr,0x20); if(addr==0)continue; addr=forwardsearch(sig4,sizeof(sig4),addr,0x20); if(addr==0)continue; auto off=andregimm((BYTE*)addrsave); if(off==regs::invalid)continue; HookParam hp; hp.address = (uint64_t)addrsave ; hp.type = CODEC_UTF16|NO_CONTEXT ; hp.offset =get_reg(off); save.push_back(hp); } return save; } std::vector v8hook1(HMODULE module) { const BYTE BYTES[] = { 0x81,0xE1,0x00,0xF8,0x00,0x00, 0x41,0xBE,0x01,0x00,0x00,0x00, 0x81,0xF9,0x00,0xD8,0x00,0x00 }; auto addrs = Util::SearchMemory(BYTES, sizeof(BYTES), PAGE_EXECUTE, processStartAddress, processStopAddress); if (addrs.size() != 1)return {}; auto addr = (uint64_t)addrs[0]; const BYTE start[] = { 0xCC }; const BYTE start2[] = { 0x41,0x57,0x41,0x56,0x41,0x55,0x41,0x54 }; addr=reverseFindBytes(start, sizeof(start), addr - 0x1000, addr); if (addr == 0)return {}; addr += 1; addrs = findxref_reverse(addr, addr - 0x10000, addr + 0x10000); if (addrs.size() != 1)return {}; addr = addrs[0]; addr = reverseFindBytes(start2, sizeof(start2), addr - 0x1000, addr); if (addr == 0)return {}; addrs = findxref_reverse(addr, addr - 0x10000, addr + 0x10000); std::vector save; for (auto addr : addrs) { addr = reverseFindBytes(start2, sizeof(start2), addr - 0x1000, addr); if (addr == 0)continue; HookParam hp; hp.address = (uint64_t)addr; hp.type = USING_STRING | CODEC_UTF16 | DATA_INDIRECT; hp.offset=get_reg(regs::rcx); hp.padding = 0xC; hp.index = 0; save.push_back(hp); } return save; } bool innerHTML(HMODULE module) { //花葬 //result = sub_142DF3CA0(a2, v5, 1u, (__int64)"innerHTML", a3); //r10当全为ascii是普通string,否则为wchar_t //a3是一个callback,并不是字符串。 char innerHTML[]="innerHTML"; auto addr = MemDbg::findBytes(innerHTML, sizeof(innerHTML), processStartAddress, processStopAddress); ConsoleOutput("%x",addr); if(addr==0)return false; bool ok=false; for(auto _addr=processStartAddress+4;_addrr10; if(strlen((char*) text)>1){ hp->type=USING_STRING|CODEC_UTF8|NO_CONTEXT; *split=0x1; *len=strrchr((char*)text,'>')+1-(char*)text; } else{ hp->type=USING_STRING|CODEC_UTF16|NO_CONTEXT; *split=0x10; *len=wcsrchr((wchar_t*)text,L'>')+1-(wchar_t*)text; *len*=2; } }; ok|=NewHook(hp,"innerHTML"); } } } } return ok; } bool addhooks(HMODULE module){ if (GetProcAddress(module, "?Write@String@v8@@QEBAHPEAVIsolate@2@PEAGHHH@Z") == 0)return false; bool success=false; for(auto h:v8hook1(module)){ success|=NewHook(h,"electronQ"); } for(auto h:hookw(module)){ success|=NewHook(h,"electronW"); } 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); 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"); } } 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){ return true; } } return false; }