From a36c9b4f522a3880bc40da15bad44dbb41936ee4 Mon Sep 17 00:00:00 2001 From: Akash Mozumdar Date: Thu, 20 Sep 2018 21:17:51 -0400 Subject: [PATCH] best hook for v8 i think exists --- vnrhook/engine/engine.cc | 113 +++++++-------------------------------- vnrhook/engine/engine.h | 2 +- vnrhook/engine/match.cc | 19 ++++--- vnrhook/engine/v8/v8.h | 33 ------------ 4 files changed, 32 insertions(+), 135 deletions(-) delete mode 100644 vnrhook/engine/v8/v8.h diff --git a/vnrhook/engine/engine.cc b/vnrhook/engine/engine.cc index 36cd949..be0f8bd 100644 --- a/vnrhook/engine/engine.cc +++ b/vnrhook/engine/engine.cc @@ -10165,104 +10165,27 @@ bool InsertNexton1Hook() * Sample game: https://vndb.org/v22252: /HWN-8:-1C@233A54:yuika_t.exe * Artikash 9/11/2018: This is more than just Tyranobuilder. It's actually a hook for the V8 JavaScript runtime * Sample game: https://www.freem.ne.jp/win/game/9672: /HQ8@2317A0:Prison.exe This new hook seems more reliable -* Issue with hook: many garbage text threads. Maybe use another split? -* -* yuika_t.v8::Locker::IsLocked+2B57 - 56 - push esi -* yuika_t.v8::Locker::IsLocked+2B58 - 8B F3 - mov esi,ebx -* yuika_t.v8::Locker::IsLocked+2B5A - 33 C0 - xor eax,eax -* yuika_t.v8::Locker::IsLocked+2B5C - 2B F7 - sub esi,edi -* yuika_t.v8::Locker::IsLocked+2B5E - 33 D2 - xor edx,edx -* yuika_t.v8::Locker::IsLocked+2B60 - 46 - inc esi -* yuika_t.v8::Locker::IsLocked+2B61 - D1 EE - shr esi,1 -* yuika_t.v8::Locker::IsLocked+2B63 - 3B FB - cmp edi,ebx -* yuika_t.v8::Locker::IsLocked+2B65 - 0F47 F0 - cmova esi,eax -* yuika_t.v8::Locker::IsLocked+2B68 - 85 F6 - test esi,esi -* yuika_t.v8::Locker::IsLocked+2B6A - 74 15 - je yuika_t.v8::Locker::IsLocked+2B81 -* yuika_t.v8::Locker::IsLocked+2B6C - 8B 45 0C - mov eax,[ebp+0C] -* yuika_t.v8::Locker::IsLocked+2B6F - 2B F8 - sub edi,eax -* yuika_t.v8::Locker::IsLocked+2B71 - 66 8B 08 - mov cx,[eax]; Moves a wchar into ecx. -* yuika_t.v8::Locker::IsLocked+2B74 - 8D 40 02 - lea eax,[eax+02]; Hook here! -* yuika_t.v8::Locker::IsLocked+2B77 - 42 - inc edx -* yuika_t.v8::Locker::IsLocked+2B78 - 66 89 4C 07 FE - mov [edi+eax-02],cx -* yuika_t.v8::Locker::IsLocked+2B7D - 3B D6 - cmp edx,esi; esi holds string length. best split I can find but not ideal... -* yuika_t.v8::Locker::IsLocked+2B7F - 72 F0 - jb yuika_t.v8::Locker::IsLocked+2B71 -* yuika_t.v8::Locker::IsLocked+2B81 - 5E - pop esi -* yuika_t.v8::Locker::IsLocked+2B82 - 5F - pop edi -* yuika_t.v8::Locker::IsLocked+2B83 - 5B - pop ebx -* yuika_t.v8::Locker::IsLocked+2B84 - 5D - pop ebp -* yuika_t.v8::Locker::IsLocked+2B85 - C3 - ret -* -* Prison.v8::Locker::IsLocked+2B30 - 55 - push ebp -* Prison.v8::Locker::IsLocked+2B31 - 8B EC - mov ebp,esp -* Prison.v8::Locker::IsLocked+2B33 - 8B 45 10 - mov eax,[ebp+10] -* Prison.v8::Locker::IsLocked+2B36 - 53 - push ebx -* Prison.v8::Locker::IsLocked+2B37 - 57 - push edi -* Prison.v8::Locker::IsLocked+2B38 - 8B 7D 08 - mov edi,[ebp+08] -* Prison.v8::Locker::IsLocked+2B3B - 8D 0C 00 - lea ecx,[eax+eax] -* Prison.v8::Locker::IsLocked+2B3E - 8D 1C 39 - lea ebx,[ecx+edi] -* Prison.v8::Locker::IsLocked+2B41 - 83 F8 20 - cmp eax,20 { 32 } -* Prison.v8::Locker::IsLocked+2B44 - 7C 11 - jl Prison.v8::Locker::IsLocked+2B57 -* Prison.v8::Locker::IsLocked+2B46 - 51 - push ecx -* Prison.v8::Locker::IsLocked+2B47 - FF 75 0C - push [ebp+0C] -* Prison.v8::Locker::IsLocked+2B4A - 57 - push edi -* Prison.v8::Locker::IsLocked+2B4B - E8 10DBFFFF - call Prison.v8::Locker::IsLocked+660 -* Prison.v8::Locker::IsLocked+2B50 - 83 C4 0C - add esp,0C { 12 } -* Prison.v8::Locker::IsLocked+2B53 - 5F - pop edi -* Prison.v8::Locker::IsLocked+2B54 - 5B - pop ebx -* Prison.v8::Locker::IsLocked+2B55 - 5D - pop ebp -* Prison.v8::Locker::IsLocked+2B56 - C3 - ret -* Prison.v8::Locker::IsLocked+2B57 - 56 - push esi -* Prison.v8::Locker::IsLocked+2B58 - 8B F3 - mov esi,ebx -* Prison.v8::Locker::IsLocked+2B5A - 33 C0 - xor eax,eax -* Prison.v8::Locker::IsLocked+2B5C - 2B F7 - sub esi,edi -* Prison.v8::Locker::IsLocked+2B5E - 33 D2 - xor edx,edx -* Prison.v8::Locker::IsLocked+2B60 - 46 - inc esi -* Prison.v8::Locker::IsLocked+2B61 - D1 EE - shr esi,1 -* Prison.v8::Locker::IsLocked+2B63 - 3B FB - cmp edi,ebx -* Prison.v8::Locker::IsLocked+2B65 - 0F47 F0 - cmova esi,eax -* Prison.v8::Locker::IsLocked+2B68 - 85 F6 - test esi,esi -* Prison.v8::Locker::IsLocked+2B6A - 74 15 - je Prison.v8::Locker::IsLocked+2B81 -* Prison.v8::Locker::IsLocked+2B6C - 8B 45 0C - mov eax,[ebp+0C] -* Prison.v8::Locker::IsLocked+2B6F - 2B F8 - sub edi,eax -* Prison.v8::Locker::IsLocked+2B71 - 66 8B 08 - mov cx,[eax] -* Prison.v8::Locker::IsLocked+2B74 - 8D 40 02 - lea eax,[eax+02] -* Prison.v8::Locker::IsLocked+2B77 - 42 - inc edx -* Prison.v8::Locker::IsLocked+2B78 - 66 89 4C 07 FE - mov [edi+eax-02],cx -* Prison.v8::Locker::IsLocked+2B7D - 3B D6 - cmp edx,esi -* Prison.v8::Locker::IsLocked+2B7F - 72 F0 - jb Prison.v8::Locker::IsLocked+2B71 -* Prison.v8::Locker::IsLocked+2B81 - 5E - pop esi -* Prison.v8::Locker::IsLocked+2B82 - 5F - pop edi -* Prison.v8::Locker::IsLocked+2B83 - 5B - pop ebx -* Prison.v8::Locker::IsLocked+2B84 - 5D - pop ebp -* Prison.v8::Locker::IsLocked+2B85 - C3 - ret +* Nevermind both of those, just hook the v8::String::Write */ -bool InsertV8Hook() +void SpecialHookV8String(DWORD dwDatabase, HookParam* hp, BYTE, DWORD* data, DWORD* split, DWORD* len) { - const BYTE bytes[] = - { - 0x2b, 0xf8, // sub edi,edx - 0x66, 0x8b, 0x08, // mov cx,[eax] - 0x8d, 0x40, 0x02 // lea eax,[eax + 02] - }; - //DWORD addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress); - if(DWORD addr = Util::SearchMemory(bytes, sizeof(bytes))) - if (DWORD func = MemDbg::findEnclosingFunctionAfterInt3(addr)) - { - HookParam hp = {}; - hp.address = func; - hp.type = USING_UNICODE | USING_STRING /*| USING_SPLIT*/; - hp.length_offset = 3; // wow, this actually is useful - hp.offset = 8; - hp.split = 0xc; - - ConsoleOutput("NextHooker: INSERT JavaScript (V8)"); - NewHook(hp, "JavaScript"); - return true; - } - - ConsoleOutput("NextHooker: JavaScript: failed to find hook address"); - return false; + DWORD ecx = *data; + DWORD strPtr = *(DWORD*)ecx; + *data = strPtr + 0xb; + *len = *(short*)(strPtr + 7); + //*split = *(DWORD*)((BYTE*)hp->split + dwDatabase); +} +bool InsertV8Hook(HMODULE module) +{ + HookParam hp = {}; + hp.address = (DWORD)GetProcAddress(module, "?Write@String@v8@@QBEHPAGHHH@Z"); + hp.offset = pusha_ecx_off - 4; + hp.split = 0xc; + hp.type = USING_UNICODE | USING_STRING; + hp.text_fun = SpecialHookV8String; + NewHook(hp, "JavaScript"); + return true; } /** diff --git a/vnrhook/engine/engine.h b/vnrhook/engine/engine.h index ac8f1c7..3004ee8 100644 --- a/vnrhook/engine/engine.h +++ b/vnrhook/engine/engine.h @@ -150,7 +150,7 @@ bool InsertTanukiHook(); // Tanuki: *.tak bool InsertTaskforce2Hook(); // Taskforce2.exe bool InsertTencoHook(); // Tenco: Check.mdx bool InsertTriangleHook(); // Triangle: Execle.exe -bool InsertV8Hook(); // Tyranobuilder: has libuv +bool InsertV8Hook(HMODULE module); // V8 JavaScript runtime: has mangled v8::String::Write bool InsertUnicornHook(); // Gsen18: *.szs|Data/*.szs bool InsertWillPlusHook(); // WillPlus: Rio.arc bool InsertWolfHook(); // Wolf: Data.wolf diff --git a/vnrhook/engine/match.cc b/vnrhook/engine/match.cc index 69c6833..91fc4c7 100644 --- a/vnrhook/engine/match.cc +++ b/vnrhook/engine/match.cc @@ -10,7 +10,6 @@ #include "engine/match.h" #include "engine/engine.h" #include "engine/native/pchooks.h" -#include "engine/v8/v8.h" #include "util/growl.h" #include "util/util.h" #include "main.h" @@ -78,6 +77,14 @@ bool DeterminePCEngine() // ConsoleOutput("vnreng: IGNORE BALDRSKY ZEROs"); // return true; //} + + if (GetProcAddress((HMODULE)processStartAddress, "?Write@String@v8@@QBEHPAGHHH@Z")) + InsertV8Hook((HMODULE)processStartAddress); + if (HMODULE module = GetModuleHandleW(L"node.dll")) + InsertV8Hook(module); + if (HMODULE module = GetModuleHandleW(L"nw.dll")) + InsertV8Hook(module); + if (::GetModuleHandleA("mono.dll")) { InsertMonoHooks(); return true; @@ -552,11 +559,11 @@ bool DetermineEngineOther() } // Artikash 7/16/2018: Uses node/libuv: likely v8 - sample game https://vndb.org/v22975 - if (GetProcAddress(GetModuleHandleW(nullptr), "uv_uptime") || GetModuleHandleW(L"node.dll")) - { - InsertV8Hook(); - return true; - } + //if (GetProcAddress(GetModuleHandleW(nullptr), "uv_uptime") || GetModuleHandleW(L"node.dll")) + //{ + // InsertV8Hook(); + // return true; + //} // jichi 8/24/2013: Move into functions // Artikash 6/15/2018: Removed this detection for Abel Software games. IthGetFileInfo no longer works correctly diff --git a/vnrhook/engine/v8/v8.h b/vnrhook/engine/v8/v8.h deleted file mode 100644 index 151143b..0000000 --- a/vnrhook/engine/v8/v8.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -// v8.h -// 9/17/2018 Artikash -// Hooks for V8 JavaScript runtime -#include "common.h" -#include "types.h" - -namespace V8 -{ -#pragma pack(1) - struct V8String - { - BYTE filler[7]; - int length; - wchar_t string[1]; - }; - void SpecialHookV8String(DWORD dwDatabase, HookParam* hp, BYTE, DWORD* data, DWORD* split, DWORD* len) - { - V8String* str = *(V8String**)data; - *data = (DWORD)str->string; - *len = str->length; - if (hp->type & USING_SPLIT) *split = *(DWORD*)((BYTE*)hp->split + dwDatabase); - } - void HookV8Functions(HMODULE hModule) - { - const std::string V8_FUNCTIONS[] = - { - "", - "" - }; - } -} \ No newline at end of file