more sane way to support 64 bit
This commit is contained in:
parent
1150d83474
commit
b8a76d79b7
@ -29,9 +29,5 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Build)
|
|||||||
set(CMAKE_CONFIGURATION_TYPES Debug Release)
|
set(CMAKE_CONFIGURATION_TYPES Debug Release)
|
||||||
|
|
||||||
add_subdirectory(host)
|
add_subdirectory(host)
|
||||||
if (${x64})
|
|
||||||
add_subdirectory(vnrhook64)
|
|
||||||
else(${x64})
|
|
||||||
add_subdirectory(vnrhook)
|
add_subdirectory(vnrhook)
|
||||||
endif(${x64})
|
|
||||||
add_subdirectory(GUI)
|
add_subdirectory(GUI)
|
||||||
|
@ -2,6 +2,18 @@ project(vnrhook)
|
|||||||
|
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
if (${x64})
|
||||||
|
set(vnrhook_src
|
||||||
|
include/const.h
|
||||||
|
include/defs.h
|
||||||
|
include/types.h
|
||||||
|
src/main.cc
|
||||||
|
src/main.h
|
||||||
|
src/pipe.cc
|
||||||
|
src/util/ithsys/ithsys.cc
|
||||||
|
src/hijack/texthook.cc
|
||||||
|
)
|
||||||
|
else(${x64})
|
||||||
set(vnrhook_src
|
set(vnrhook_src
|
||||||
include/const.h
|
include/const.h
|
||||||
include/defs.h
|
include/defs.h
|
||||||
@ -33,6 +45,7 @@ set(vnrhook_src
|
|||||||
src/util/mono/monoobject.h
|
src/util/mono/monoobject.h
|
||||||
src/util/mono/monotype.h
|
src/util/mono/monotype.h
|
||||||
)
|
)
|
||||||
|
endif(${x64})
|
||||||
|
|
||||||
include_directories(src/util)
|
include_directories(src/util)
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
#include "src/engine/engine.h"
|
#include "src/engine/engine.h"
|
||||||
|
#include "ntdll/ntdll.h"
|
||||||
#include "src/engine/match.h"
|
#include "src/engine/match.h"
|
||||||
#include "src/engine/hookdefs.h"
|
#include "src/engine/hookdefs.h"
|
||||||
#include "src/util/util.h"
|
#include "src/util/util.h"
|
||||||
|
@ -42,6 +42,7 @@ TextHook *hookman,
|
|||||||
|
|
||||||
// - Unnamed helpers -
|
// - Unnamed helpers -
|
||||||
|
|
||||||
|
#ifndef _WIN64
|
||||||
namespace { // unnamed
|
namespace { // unnamed
|
||||||
//provide const time hook entry.
|
//provide const time hook entry.
|
||||||
int userhook_count;
|
int userhook_count;
|
||||||
@ -204,9 +205,25 @@ int ProcessHook(DWORD dwDataBase, DWORD dwRetn, TextHook *hook) // Use SEH to en
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // unnamed namespace
|
} // unnamed namespace
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
// - TextHook methods -
|
// - TextHook methods -
|
||||||
|
|
||||||
|
int TextHook::InsertHook()
|
||||||
|
{
|
||||||
|
int ok = 1;
|
||||||
|
//ConsoleOutput("vnrcli:InsertHook: enter");
|
||||||
|
WaitForSingleObject(hmMutex, 0);
|
||||||
|
if (hp.type & DIRECT_READ) ok = InsertReadCode();
|
||||||
|
#ifndef _WIN64
|
||||||
|
else ok = InsertHookCode();
|
||||||
|
#endif
|
||||||
|
ReleaseMutex(hmMutex);
|
||||||
|
//ConsoleOutput("vnrcli:InsertHook: leave");
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN64
|
||||||
// jichi 12/2/2013: This function mostly return 0.
|
// jichi 12/2/2013: This function mostly return 0.
|
||||||
// It return the hook address only for auxiliary case.
|
// It return the hook address only for auxiliary case.
|
||||||
// However, because no known hooks are auxiliary, this function always return 0.
|
// However, because no known hooks are auxiliary, this function always return 0.
|
||||||
@ -314,18 +331,6 @@ DWORD TextHook::UnsafeSend(DWORD dwDataBase, DWORD dwRetn)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int TextHook::InsertHook()
|
|
||||||
{
|
|
||||||
int ok = 1;
|
|
||||||
//ConsoleOutput("vnrcli:InsertHook: enter");
|
|
||||||
WaitForSingleObject(hmMutex, 0);
|
|
||||||
if (hp.type & DIRECT_READ) ok = InsertReadCode();
|
|
||||||
else ok = InsertHookCode();
|
|
||||||
ReleaseMutex(hmMutex);
|
|
||||||
//ConsoleOutput("vnrcli:InsertHook: leave");
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
int TextHook::InsertHookCode()
|
int TextHook::InsertHookCode()
|
||||||
{
|
{
|
||||||
DWORD ret = no;
|
DWORD ret = no;
|
||||||
@ -336,72 +341,6 @@ int TextHook::InsertHookCode()
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD WINAPI ReaderThread(LPVOID threadParam)
|
|
||||||
{
|
|
||||||
TextHook* hook = (TextHook*)threadParam;
|
|
||||||
BYTE buffer[PIPE_BUFFER_SIZE] = {};
|
|
||||||
char testChar = 0;
|
|
||||||
unsigned int changeCount = 0;
|
|
||||||
const char* currentAddress = (char*)hook->hp.address;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
Sleep(50);
|
|
||||||
if (testChar == *currentAddress)
|
|
||||||
{
|
|
||||||
changeCount = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
testChar = *currentAddress;
|
|
||||||
if (++changeCount > 10)
|
|
||||||
{
|
|
||||||
ConsoleOutput("NextHooker: memory constantly changing, useless to read");
|
|
||||||
ConsoleOutput("NextHooker: remove read code");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dataLen;
|
|
||||||
if (hook->hp.type & USING_UNICODE)
|
|
||||||
dataLen = wcslen((const wchar_t*)currentAddress) * 2;
|
|
||||||
else
|
|
||||||
dataLen = strlen(currentAddress);
|
|
||||||
|
|
||||||
*(DWORD*)buffer = hook->hp.address;
|
|
||||||
*(DWORD*)(buffer + 4) = 0;
|
|
||||||
*(DWORD*)(buffer + 8) = 0;
|
|
||||||
memcpy(buffer + HEADER_SIZE, currentAddress, dataLen);
|
|
||||||
DWORD unused;
|
|
||||||
WriteFile(::hookPipe, buffer, dataLen + HEADER_SIZE, &unused, nullptr);
|
|
||||||
|
|
||||||
if (hook->hp.offset == 0) continue;
|
|
||||||
currentAddress += dataLen + hook->hp.offset;
|
|
||||||
testChar = *currentAddress;
|
|
||||||
}
|
|
||||||
hook->ClearHook();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int TextHook::InsertReadCode()
|
|
||||||
{
|
|
||||||
hp.hook_len = 0x40;
|
|
||||||
//Check if the new hook range conflict with existing ones. Clear older if conflict.
|
|
||||||
TextHook *it = hookman;
|
|
||||||
for (int i = 0; i < currentHook; it++) {
|
|
||||||
if (it->Address())
|
|
||||||
i++;
|
|
||||||
if (it == this)
|
|
||||||
continue;
|
|
||||||
if ((it->Address() >= hp.address && it->Address() < hp.hook_len + hp.address) || (it->Address() <= hp.address && it->Address() + it->Length() > hp.address))
|
|
||||||
it->ClearHook();
|
|
||||||
}
|
|
||||||
if (!IthGetMemoryRange((LPCVOID)hp.address, 0, 0))
|
|
||||||
{
|
|
||||||
ConsoleOutput("cannot access read address");
|
|
||||||
return no;
|
|
||||||
}
|
|
||||||
hp.readerHandle = CreateThread(nullptr, 0, ReaderThread, this, 0, nullptr);
|
|
||||||
return yes;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int TextHook::UnsafeInsertHookCode()
|
int TextHook::UnsafeInsertHookCode()
|
||||||
{
|
{
|
||||||
@ -503,6 +442,74 @@ int TextHook::UnsafeInsertHookCode()
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
DWORD WINAPI ReaderThread(LPVOID threadParam)
|
||||||
|
{
|
||||||
|
TextHook* hook = (TextHook*)threadParam;
|
||||||
|
BYTE buffer[PIPE_BUFFER_SIZE] = {};
|
||||||
|
char testChar = 0;
|
||||||
|
unsigned int changeCount = 0;
|
||||||
|
const char* currentAddress = (char*)hook->hp.address;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Sleep(1000);
|
||||||
|
if (testChar == *currentAddress)
|
||||||
|
{
|
||||||
|
changeCount = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
testChar = *currentAddress;
|
||||||
|
if (++changeCount > 10)
|
||||||
|
{
|
||||||
|
ConsoleOutput("NextHooker: memory constantly changing, useless to read");
|
||||||
|
ConsoleOutput("NextHooker: remove read code");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dataLen;
|
||||||
|
if (hook->hp.type & USING_UNICODE)
|
||||||
|
dataLen = wcslen((const wchar_t*)currentAddress) * 2;
|
||||||
|
else
|
||||||
|
dataLen = strlen(currentAddress);
|
||||||
|
|
||||||
|
*(DWORD*)buffer = hook->hp.address;
|
||||||
|
*(DWORD*)(buffer + 4) = 0;
|
||||||
|
*(DWORD*)(buffer + 8) = 0;
|
||||||
|
memcpy(buffer + HEADER_SIZE, currentAddress, dataLen);
|
||||||
|
DWORD unused;
|
||||||
|
WriteFile(::hookPipe, buffer, dataLen + HEADER_SIZE, &unused, nullptr);
|
||||||
|
|
||||||
|
if (hook->hp.offset == 0) continue;
|
||||||
|
currentAddress += dataLen + hook->hp.offset;
|
||||||
|
testChar = *currentAddress;
|
||||||
|
}
|
||||||
|
hook->ClearHook();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TextHook::InsertReadCode()
|
||||||
|
{
|
||||||
|
hp.hook_len = 0x40;
|
||||||
|
//Check if the new hook range conflict with existing ones. Clear older if conflict.
|
||||||
|
TextHook *it = hookman;
|
||||||
|
for (int i = 0; i < currentHook; it++) {
|
||||||
|
if (it->Address())
|
||||||
|
i++;
|
||||||
|
if (it == this)
|
||||||
|
continue;
|
||||||
|
if ((it->Address() >= hp.address && it->Address() < hp.hook_len + hp.address) || (it->Address() <= hp.address && it->Address() + it->Length() > hp.address))
|
||||||
|
it->ClearHook();
|
||||||
|
}
|
||||||
|
if (!IthGetMemoryRange((LPCVOID)hp.address, 0, 0))
|
||||||
|
{
|
||||||
|
ConsoleOutput("cannot access read address");
|
||||||
|
return no;
|
||||||
|
}
|
||||||
|
hp.readerHandle = CreateThread(nullptr, 0, ReaderThread, this, 0, nullptr);
|
||||||
|
return yes;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int TextHook::InitHook(const HookParam &h, LPCSTR name, WORD set_flag)
|
int TextHook::InitHook(const HookParam &h, LPCSTR name, WORD set_flag)
|
||||||
{
|
{
|
||||||
|
@ -80,12 +80,14 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID unused)
|
|||||||
|
|
||||||
::processStartAddress = ::processStopAddress = (DWORD)GetModuleHandleW(nullptr);
|
::processStartAddress = ::processStopAddress = (DWORD)GetModuleHandleW(nullptr);
|
||||||
|
|
||||||
|
#ifndef _WIN64
|
||||||
MEMORY_BASIC_INFORMATION info;
|
MEMORY_BASIC_INFORMATION info;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
VirtualQuery((void*)::processStopAddress, &info, sizeof(info));
|
VirtualQuery((void*)::processStopAddress, &info, sizeof(info));
|
||||||
::processStopAddress = (DWORD)info.BaseAddress + info.RegionSize;
|
::processStopAddress = (DWORD)info.BaseAddress + info.RegionSize;
|
||||||
} while (info.Protect);
|
} while (info.Protect);
|
||||||
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
wchar_t hm_mutex[0x100];
|
wchar_t hm_mutex[0x100];
|
||||||
|
@ -49,7 +49,11 @@ DWORD WINAPI PipeManager(LPVOID unused)
|
|||||||
CloseHandle(pipeAcquisitionMutex);
|
CloseHandle(pipeAcquisitionMutex);
|
||||||
|
|
||||||
ConsoleOutput("vnrcli:WaitForPipe: pipe connected");
|
ConsoleOutput("vnrcli:WaitForPipe: pipe connected");
|
||||||
|
#ifdef _WIN64
|
||||||
|
ConsoleOutput("Hooks don't work on x64, only read codes work. Engine disabled.");
|
||||||
|
#else
|
||||||
Engine::Hijack();
|
Engine::Hijack();
|
||||||
|
#endif
|
||||||
|
|
||||||
while (::running)
|
while (::running)
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# pragma warning(disable:4800) // C4800: forcing value to bool
|
# pragma warning(disable:4800) // C4800: forcing value to bool
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
#include "ntdll/ntdll.h"
|
//#include "ntdll/ntdll.h"
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
// jichi 8/24/2013: Why extern "C"? Any specific reason to use C instead of C++ naming?
|
// jichi 8/24/2013: Why extern "C"? Any specific reason to use C instead of C++ naming?
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
project(vnrhook)
|
|
||||||
|
|
||||||
include_directories(../vnrhook)
|
|
||||||
|
|
||||||
set(vnrhook_src
|
|
||||||
../vnrhook/include/const.h
|
|
||||||
../vnrhook/include/defs.h
|
|
||||||
../vnrhook/include/types.h
|
|
||||||
src/main.cc
|
|
||||||
src/main.h
|
|
||||||
src/pipe.cc
|
|
||||||
src/hijack/texthook.cc
|
|
||||||
src/hijack/texthook.h
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library(vnrhook SHARED ${vnrhook_src})
|
|
||||||
|
|
||||||
set_source_files_properties(
|
|
||||||
${PROJECT_SOURCE_DIR}/winseh/safeseh.asm
|
|
||||||
PROPERTIES
|
|
||||||
# CMAKE_ASM_MASM_FLAGS /safeseh # CMake bug 14711: http://www.cmake.org/Bug/view.php?id=14711
|
|
||||||
COMPILE_FLAGS /safeseh
|
|
||||||
)
|
|
||||||
|
|
||||||
set_target_properties(vnrhook PROPERTIES
|
|
||||||
LINK_FLAGS "/SUBSYSTEM:WINDOWS /MANIFEST:NO"
|
|
||||||
)
|
|
||||||
|
|
||||||
target_compile_options(vnrhook PRIVATE
|
|
||||||
/EHa
|
|
||||||
$<$<CONFIG:Release>:>
|
|
||||||
$<$<CONFIG:Debug>:>
|
|
||||||
)
|
|
||||||
|
|
||||||
set(vnrhook_libs
|
|
||||||
Version.lib
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(vnrhook ${vnrhook_libs})
|
|
||||||
|
|
||||||
target_compile_definitions(vnrhook
|
|
||||||
PRIVATE
|
|
||||||
ITH_HAS_CRT
|
|
||||||
ITH_HAS_SEH
|
|
||||||
_CRT_NON_CONFORMING_SWPRINTFS
|
|
||||||
)
|
|
@ -1,187 +0,0 @@
|
|||||||
// texthook.cc
|
|
||||||
// 8/24/2013 jichi
|
|
||||||
// Branch: ITH_DLL/texthook.cpp, rev 128
|
|
||||||
// 8/24/2013 TODO: Clean up this file
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
# pragma warning (disable:4100) // C4100: unreference formal parameter
|
|
||||||
# pragma warning (disable:4018) // C4018: sign/unsigned mismatch
|
|
||||||
//# pragma warning (disable:4733) // C4733: Inline asm assigning to 'FS:0' : handler not registered as safe handler
|
|
||||||
#endif // _MSC_VER
|
|
||||||
|
|
||||||
#include "../main.h"
|
|
||||||
#include "texthook.h"
|
|
||||||
#include "include/const.h"
|
|
||||||
//#include "winseh/winseh.h"
|
|
||||||
|
|
||||||
//#define ConsoleOutput(...) (void)0 // jichi 9/17/2013: I don't need this ><
|
|
||||||
|
|
||||||
// - Global variables -
|
|
||||||
|
|
||||||
// 10/14/2014 jichi: disable GDI hooks
|
|
||||||
static bool gdi_hook_enabled_ = true; // enable GDI by default
|
|
||||||
static bool gdiplus_hook_enabled_ = false; // disable GDIPlus by default
|
|
||||||
bool GDIHooksEnabled() { return ::gdi_hook_enabled_; }
|
|
||||||
bool GDIPlusHooksEnabled() { return ::gdiplus_hook_enabled_; }
|
|
||||||
void EnableGDIHooks() { ::gdi_hook_enabled_ = true; }
|
|
||||||
void EnableGDIPlusHooks() { ::gdiplus_hook_enabled_ = true; }
|
|
||||||
void DisableGDIHooks() { ::gdi_hook_enabled_ = false; }
|
|
||||||
void DisableGDIPlusHooks() { ::gdiplus_hook_enabled_ = false; }
|
|
||||||
|
|
||||||
//FilterRange filter[8];
|
|
||||||
|
|
||||||
DWORD flag,
|
|
||||||
enter_count;
|
|
||||||
|
|
||||||
TextHook *hookman,
|
|
||||||
*current_available;
|
|
||||||
|
|
||||||
// - TextHook methods -
|
|
||||||
|
|
||||||
// jichi 12/2/2013: This function mostly return 0.
|
|
||||||
// It return the hook address only for auxiliary case.
|
|
||||||
// However, because no known hooks are auxiliary, this function always return 0.
|
|
||||||
//
|
|
||||||
// jichi 5/11/2014:
|
|
||||||
// - dwDataBase: the stack address
|
|
||||||
// - dwRetn: the return address of the hook
|
|
||||||
|
|
||||||
|
|
||||||
int TextHook::InsertHook()
|
|
||||||
{
|
|
||||||
int ok = 1;
|
|
||||||
//ConsoleOutput("vnrcli:InsertHook: enter");
|
|
||||||
WaitForSingleObject(hmMutex, 0);
|
|
||||||
if (hp.type & DIRECT_READ) ok = InsertReadCode();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ConsoleOutput("only /R (read) codes supported in 64 bit");
|
|
||||||
}
|
|
||||||
ReleaseMutex(hmMutex);
|
|
||||||
//ConsoleOutput("vnrcli:InsertHook: leave");
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD WINAPI ReaderThread(LPVOID threadParam)
|
|
||||||
{
|
|
||||||
TextHook* hook = (TextHook*)threadParam;
|
|
||||||
BYTE buffer[PIPE_BUFFER_SIZE] = {};
|
|
||||||
char testChar = 0;
|
|
||||||
unsigned int changeCount = 0;
|
|
||||||
const char* currentAddress = (char*)hook->hp.address;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
Sleep(50);
|
|
||||||
if (testChar == *currentAddress)
|
|
||||||
{
|
|
||||||
changeCount = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
testChar = *currentAddress;
|
|
||||||
if (++changeCount > 10)
|
|
||||||
{
|
|
||||||
ConsoleOutput("NextHooker: memory constantly changing, useless to read");
|
|
||||||
ConsoleOutput("NextHooker: remove read code");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dataLen;
|
|
||||||
if (hook->hp.type & USING_UNICODE)
|
|
||||||
dataLen = wcslen((const wchar_t*)currentAddress) * 2;
|
|
||||||
else
|
|
||||||
dataLen = strlen(currentAddress);
|
|
||||||
|
|
||||||
*(DWORD*)buffer = hook->hp.address;
|
|
||||||
*(DWORD*)(buffer + 4) = 0;
|
|
||||||
*(DWORD*)(buffer + 8) = 0;
|
|
||||||
memcpy(buffer + HEADER_SIZE, currentAddress, dataLen);
|
|
||||||
DWORD unused;
|
|
||||||
WriteFile(::hookPipe, buffer, dataLen + HEADER_SIZE, &unused, nullptr);
|
|
||||||
|
|
||||||
if (hook->hp.offset == 0) continue;
|
|
||||||
currentAddress += dataLen + hook->hp.offset;
|
|
||||||
testChar = *currentAddress;
|
|
||||||
}
|
|
||||||
hook->ClearHook();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int TextHook::InsertReadCode()
|
|
||||||
{
|
|
||||||
hp.hook_len = 0x40;
|
|
||||||
//Check if the new hook range conflict with existing ones. Clear older if conflict.
|
|
||||||
TextHook *it = hookman;
|
|
||||||
for (int i = 0; i < currentHook; it++) {
|
|
||||||
if (it->Address())
|
|
||||||
i++;
|
|
||||||
if (it == this)
|
|
||||||
continue;
|
|
||||||
if ((it->Address() >= hp.address && it->Address() < hp.hook_len + hp.address) || (it->Address() <= hp.address && it->Address() + it->Length() > hp.address))
|
|
||||||
it->ClearHook();
|
|
||||||
}
|
|
||||||
//if (!IthGetMemoryRange((LPCVOID)hp.address, 0, 0))
|
|
||||||
//{
|
|
||||||
// ConsoleOutput("cannot access read address");
|
|
||||||
// return no;
|
|
||||||
//}
|
|
||||||
hp.readerHandle = CreateThread(nullptr, 0, ReaderThread, this, 0, nullptr);
|
|
||||||
return yes;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int TextHook::InitHook(const HookParam &h, LPCSTR name, WORD set_flag)
|
|
||||||
{
|
|
||||||
WaitForSingleObject(hmMutex, 0);
|
|
||||||
hp = h;
|
|
||||||
hp.type |= set_flag;
|
|
||||||
if (name && name != hook_name) {
|
|
||||||
SetHookName(name);
|
|
||||||
}
|
|
||||||
currentHook++;
|
|
||||||
current_available = this+1;
|
|
||||||
while (current_available->Address())
|
|
||||||
current_available++;
|
|
||||||
ReleaseMutex(hmMutex);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int TextHook::RemoveReadCode()
|
|
||||||
{
|
|
||||||
if (!hp.address) return no;
|
|
||||||
TerminateThread(hp.readerHandle, 0);
|
|
||||||
CloseHandle(hp.readerHandle);
|
|
||||||
return yes;
|
|
||||||
}
|
|
||||||
|
|
||||||
int TextHook::ClearHook()
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
WaitForSingleObject(hmMutex, 0);
|
|
||||||
ConsoleOutput("vnrcli:RemoveHook: enter");
|
|
||||||
err = RemoveReadCode();
|
|
||||||
NotifyHookRemove(hp.address);
|
|
||||||
if (hook_name) {
|
|
||||||
delete[] hook_name;
|
|
||||||
hook_name = nullptr;
|
|
||||||
}
|
|
||||||
memset(this, 0, sizeof(TextHook)); // jichi 11/30/2013: This is the original code of ITH
|
|
||||||
//if (current_available>this)
|
|
||||||
// current_available = this;
|
|
||||||
currentHook--;
|
|
||||||
ConsoleOutput("vnrcli:RemoveHook: leave");
|
|
||||||
ReleaseMutex(hmMutex);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
int TextHook::SetHookName(LPCSTR name)
|
|
||||||
{
|
|
||||||
name_length = strlen(name) + 1;
|
|
||||||
if (hook_name)
|
|
||||||
delete[] hook_name;
|
|
||||||
hook_name = new char[name_length];
|
|
||||||
//ITH_MEMSET_HEAP(hook_name, 0, sizeof(wchar_t) * name_length); // jichi 9/26/2013: zero memory
|
|
||||||
strcpy(hook_name, name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// EOF
|
|
@ -1,78 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// texthook.h
|
|
||||||
// 8/24/2013 jichi
|
|
||||||
// Branch: IHF_DLL/IHF_CLIENT.h, rev 133
|
|
||||||
//
|
|
||||||
// 8/24/2013 TODO:
|
|
||||||
// - Clean up this file
|
|
||||||
// - Reduce global variables. Use namespaces or singleton classes instead.
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include "include/types.h"
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
extern int currentHook;
|
|
||||||
extern WCHAR dll_mutex[];
|
|
||||||
//extern WCHAR dll_name[];
|
|
||||||
extern DWORD trigger;
|
|
||||||
//extern DWORD current_process_id;
|
|
||||||
|
|
||||||
// jichi 6/3/2014: Get memory range of the current module
|
|
||||||
extern DWORD processStartAddress,
|
|
||||||
processStopAddress;
|
|
||||||
|
|
||||||
void InitFilterTable();
|
|
||||||
|
|
||||||
// jichi 9/25/2013: This class will be used by NtMapViewOfSectionfor
|
|
||||||
// interprocedure communication, where constructor/destructor will NOT work.
|
|
||||||
class TextHook : public Hook
|
|
||||||
{
|
|
||||||
int InsertHookCode();
|
|
||||||
int InsertReadCode();
|
|
||||||
int UnsafeInsertHookCode();
|
|
||||||
DWORD UnsafeSend(DWORD dwDataBase, DWORD dwRetn);
|
|
||||||
int RemoveHookCode();
|
|
||||||
int RemoveReadCode();
|
|
||||||
int SetHookName(LPCSTR name);
|
|
||||||
public:
|
|
||||||
int InsertHook();
|
|
||||||
int InitHook(const HookParam &hp, LPCSTR name = 0, WORD set_flag = 0);
|
|
||||||
DWORD Send(DWORD dwDataBase, DWORD dwRetn);
|
|
||||||
int ClearHook();
|
|
||||||
int GetLength(DWORD base, DWORD in); // jichi 12/25/2013: Return 0 if failed
|
|
||||||
};
|
|
||||||
|
|
||||||
extern TextHook *hookman,
|
|
||||||
*current_available;
|
|
||||||
|
|
||||||
//void InitDefaultHook();
|
|
||||||
|
|
||||||
struct FilterRange { DWORD lower, upper; };
|
|
||||||
extern FilterRange *filter;
|
|
||||||
|
|
||||||
extern bool running,
|
|
||||||
live;
|
|
||||||
|
|
||||||
extern HANDLE hookPipe,
|
|
||||||
hmMutex;
|
|
||||||
|
|
||||||
DWORD WINAPI WaitForPipe(LPVOID lpThreadParameter);
|
|
||||||
DWORD WINAPI CommandPipe(LPVOID lpThreadParameter);
|
|
||||||
DWORD WINAPI PipeManager(LPVOID unused);
|
|
||||||
|
|
||||||
//void RequestRefreshProfile();
|
|
||||||
|
|
||||||
//typedef DWORD (*InsertHookFun)(DWORD);
|
|
||||||
//typedef DWORD (*IdentifyEngineFun)();
|
|
||||||
//typedef DWORD (*InsertDynamicHookFun)(LPVOID addr, DWORD frame, DWORD stack);
|
|
||||||
//extern IdentifyEngineFun IdentifyEngine;
|
|
||||||
//extern InsertDynamicHookFun InsertDynamicHook;
|
|
||||||
|
|
||||||
// jichi 9/28/2013: Protect pipeline in wine
|
|
||||||
void CliLockPipe();
|
|
||||||
void CliUnlockPipe();
|
|
||||||
|
|
||||||
enum : int { yes = 0, no = 1 };
|
|
||||||
|
|
||||||
// EOF
|
|
@ -1,150 +0,0 @@
|
|||||||
// main.cc
|
|
||||||
// 8/24/2013 jichi
|
|
||||||
// Branch: ITH_DLL/main.cpp, rev 128
|
|
||||||
// 8/24/2013 TODO: Clean up this file
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
# pragma warning (disable:4100) // C4100: unreference formal parameter
|
|
||||||
//# pragma warning (disable:4733) // C4733: Inline asm assigning to 'FS:0' : handler not registered as safe handler
|
|
||||||
#endif // _MSC_VER
|
|
||||||
|
|
||||||
#include "main.h"
|
|
||||||
#include "hijack/texthook.h"
|
|
||||||
#include "include/defs.h"
|
|
||||||
|
|
||||||
// Global variables
|
|
||||||
|
|
||||||
// jichi 6/3/2014: memory range of the current module
|
|
||||||
DWORD processStartAddress,
|
|
||||||
processStopAddress;
|
|
||||||
|
|
||||||
enum { HOOK_BUFFER_SIZE = MAX_HOOK * sizeof(TextHook) };
|
|
||||||
//#define MAX_HOOK (HOOK_BUFFER_SIZE/sizeof(TextHook))
|
|
||||||
DWORD hook_buff_len = HOOK_BUFFER_SIZE;
|
|
||||||
|
|
||||||
WCHAR hm_section[0x100];
|
|
||||||
HANDLE hSection;
|
|
||||||
bool running;
|
|
||||||
int currentHook = 0,
|
|
||||||
user_hook_count = 0;
|
|
||||||
HANDLE
|
|
||||||
hFile,
|
|
||||||
hMutex,
|
|
||||||
hmMutex;
|
|
||||||
HMODULE currentModule;
|
|
||||||
|
|
||||||
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID unused)
|
|
||||||
{
|
|
||||||
static HANDLE pipeThread;
|
|
||||||
|
|
||||||
|
|
||||||
switch (fdwReason) {
|
|
||||||
case DLL_PROCESS_ATTACH:
|
|
||||||
{
|
|
||||||
static bool attached_ = false;
|
|
||||||
if (attached_) // already attached
|
|
||||||
{
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
attached_ = true;
|
|
||||||
|
|
||||||
DisableThreadLibraryCalls(hModule);
|
|
||||||
|
|
||||||
swprintf(hm_section, ITH_SECTION_ L"%d", GetCurrentProcessId());
|
|
||||||
|
|
||||||
// jichi 9/25/2013: Interprocedural communication with vnrsrv.
|
|
||||||
hSection = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_EXECUTE_READWRITE, 0, HOOK_SECTION_SIZE, hm_section);
|
|
||||||
::hookman = nullptr;
|
|
||||||
// Artikash 6/20/2018: This crashes certain games (https://vndb.org/v7738). No idea why.
|
|
||||||
::hookman = (TextHook*)MapViewOfFile(hSection, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, HOOK_SECTION_SIZE / 2);
|
|
||||||
|
|
||||||
::processStartAddress = (DWORD)GetModuleHandleW(nullptr);
|
|
||||||
|
|
||||||
{
|
|
||||||
wchar_t hm_mutex[0x100];
|
|
||||||
swprintf(hm_mutex, ITH_HOOKMAN_MUTEX_ L"%d", GetCurrentProcessId());
|
|
||||||
::hmMutex = CreateMutexW(nullptr, FALSE, hm_mutex);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
wchar_t dll_mutex[0x100];
|
|
||||||
swprintf(dll_mutex, ITH_PROCESS_MUTEX_ L"%d", GetCurrentProcessId());
|
|
||||||
DWORD exists;
|
|
||||||
::hMutex = CreateMutexW(nullptr, TRUE, dll_mutex); // jichi 9/18/2013: own is true, make sure the injected dll is singleton
|
|
||||||
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
::running = true;
|
|
||||||
::current_available = ::hookman;
|
|
||||||
::currentModule = hModule;
|
|
||||||
|
|
||||||
pipeThread = CreateThread(nullptr, 0, PipeManager, 0, 0, nullptr);
|
|
||||||
} break;
|
|
||||||
case DLL_PROCESS_DETACH:
|
|
||||||
{
|
|
||||||
static bool detached_ = false;
|
|
||||||
if (detached_) // already detached
|
|
||||||
return TRUE;
|
|
||||||
detached_ = true;
|
|
||||||
|
|
||||||
// jichi 10/2/2103: Cannot use __try in functions that require object unwinding
|
|
||||||
//ITH_TRY {
|
|
||||||
::running = false;
|
|
||||||
|
|
||||||
if (pipeThread) {
|
|
||||||
WaitForSingleObject(pipeThread, TIMEOUT);
|
|
||||||
CloseHandle(pipeThread);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (TextHook *man = ::hookman; man < ::hookman + MAX_HOOK; man++)
|
|
||||||
man->ClearHook();
|
|
||||||
//if (ith_has_section)
|
|
||||||
UnmapViewOfFile(::hookman);
|
|
||||||
|
|
||||||
CloseHandle(hSection);
|
|
||||||
CloseHandle(hMutex);
|
|
||||||
CloseHandle(hmMutex);
|
|
||||||
//} ITH_EXCEPT {}
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
//extern "C" {
|
|
||||||
DWORD NewHook(const HookParam &hp, LPCSTR lpname, DWORD flag)
|
|
||||||
{
|
|
||||||
std::string name = lpname;
|
|
||||||
int current = ::current_available - ::hookman;
|
|
||||||
if (current < MAX_HOOK) {
|
|
||||||
//flag &= 0xffff;
|
|
||||||
//if ((flag & HOOK_AUXILIARY) == 0)
|
|
||||||
flag |= HOOK_ADDITIONAL;
|
|
||||||
if (name[0] == '\0')
|
|
||||||
{
|
|
||||||
name = "UserHook" + std::to_string(user_hook_count++);
|
|
||||||
}
|
|
||||||
|
|
||||||
ConsoleOutput(("vnrcli:NewHook: try inserting hook: " + name).c_str());
|
|
||||||
|
|
||||||
// jichi 7/13/2014: This function would raise when too many hooks added
|
|
||||||
::hookman[current].InitHook(hp, name.c_str(), flag & 0xffff);
|
|
||||||
|
|
||||||
if (::hookman[current].InsertHook() == 0) {
|
|
||||||
ConsoleOutput(("vnrcli:NewHook: inserted hook: " + name).c_str());
|
|
||||||
NotifyHookInsert(hp, name.c_str());
|
|
||||||
} else
|
|
||||||
ConsoleOutput("vnrcli:NewHook:WARNING: failed to insert hook");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
DWORD RemoveHook(DWORD addr)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < MAX_HOOK; i++)
|
|
||||||
if (::hookman[i].Address ()== addr) {
|
|
||||||
::hookman[i].ClearHook();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// EOF
|
|
@ -1,27 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// main.h
|
|
||||||
// 8/23/2013 jichi
|
|
||||||
// Branch: ITH/IHF_DLL.h, rev 66
|
|
||||||
|
|
||||||
#include <Windows.h>
|
|
||||||
#include "include/const.h"
|
|
||||||
#include "include/types.h"
|
|
||||||
|
|
||||||
void ConsoleOutput(LPCSTR text); // jichi 12/25/2013: Used to return length of sent text
|
|
||||||
void NotifyHookInsert(HookParam hp, LPCSTR name);
|
|
||||||
void NotifyHookRemove(DWORD addr);
|
|
||||||
DWORD NewHook(const HookParam &hp, LPCSTR name, DWORD flag = HOOK_ENGINE);
|
|
||||||
DWORD RemoveHook(DWORD addr);
|
|
||||||
DWORD SwitchTrigger(DWORD on);
|
|
||||||
DWORD GetFunctionAddr(const char *name, DWORD *addr, DWORD *base, DWORD *size, LPWSTR *base_name);
|
|
||||||
|
|
||||||
// 10/14/2014 jichi: disable GDI hooks
|
|
||||||
void EnableGDIHooks();
|
|
||||||
void EnableGDIPlusHooks();
|
|
||||||
void DisableGDIHooks();
|
|
||||||
void DisableGDIPlusHooks();
|
|
||||||
bool GDIHooksEnabled();
|
|
||||||
bool GDIPlusHooksEnabled();
|
|
||||||
|
|
||||||
// EOF
|
|
@ -1,127 +0,0 @@
|
|||||||
// pipe.cc
|
|
||||||
// 8/24/2013 jichi
|
|
||||||
// Branch: ITH_DLL/pipe.cpp, rev 66
|
|
||||||
// 8/24/2013 TODO: Clean up this file
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
# pragma warning (disable:4100) // C4100: unreference formal parameter
|
|
||||||
#endif // _MSC_VER
|
|
||||||
|
|
||||||
#include "main.h"
|
|
||||||
#include "include/defs.h"
|
|
||||||
#include "hijack/texthook.h"
|
|
||||||
|
|
||||||
HANDLE hookPipe;
|
|
||||||
extern HMODULE currentModule;
|
|
||||||
|
|
||||||
DWORD WINAPI PipeManager(LPVOID unused)
|
|
||||||
{
|
|
||||||
enum { STANDARD_WAIT = 50 };
|
|
||||||
while (::running)
|
|
||||||
{
|
|
||||||
DWORD count;
|
|
||||||
BYTE buffer[PIPE_BUFFER_SIZE];
|
|
||||||
HANDLE hostPipe = ::hookPipe = INVALID_HANDLE_VALUE,
|
|
||||||
pipeAcquisitionMutex = CreateMutexW(nullptr, TRUE, ITH_GRANTPIPE_MUTEX);
|
|
||||||
|
|
||||||
while (::hookPipe == INVALID_HANDLE_VALUE || hostPipe == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
Sleep(STANDARD_WAIT);
|
|
||||||
if (::hookPipe == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
::hookPipe = CreateFileW(ITH_TEXT_PIPE, GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
|
||||||
}
|
|
||||||
if (hostPipe == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
hostPipe = CreateFileW(ITH_COMMAND_PIPE, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*(DWORD*)buffer = GetCurrentProcessId();
|
|
||||||
WriteFile(::hookPipe, buffer, sizeof(DWORD), &count, nullptr);
|
|
||||||
|
|
||||||
ReleaseMutex(pipeAcquisitionMutex);
|
|
||||||
CloseHandle(pipeAcquisitionMutex);
|
|
||||||
|
|
||||||
ConsoleOutput("vnrcli:WaitForPipe: pipe connected");
|
|
||||||
ConsoleOutput("only read codes are supported on x64: engine disabled");
|
|
||||||
|
|
||||||
while (::running)
|
|
||||||
{
|
|
||||||
if (!ReadFile(hostPipe, buffer, PIPE_BUFFER_SIZE / 2, &count, nullptr)) // Artikash 5/21/2018: why / 2? wchar_t?
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
DWORD command = *(DWORD*)buffer;
|
|
||||||
switch (command)
|
|
||||||
{
|
|
||||||
case HOST_COMMAND_NEW_HOOK:
|
|
||||||
buffer[count] = 0;
|
|
||||||
NewHook(*(HookParam *)(buffer + sizeof(DWORD)), // Hook parameter
|
|
||||||
(LPSTR)(buffer + 4 + sizeof(HookParam)), // Hook name
|
|
||||||
0
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case HOST_COMMAND_REMOVE_HOOK:
|
|
||||||
{
|
|
||||||
TextHook *in = hookman;
|
|
||||||
for (int i = 0; i < currentHook; in++)
|
|
||||||
{
|
|
||||||
if (in->Address()) i++;
|
|
||||||
if (in->Address() == *(DWORD *)(buffer + sizeof(DWORD))) // Hook address
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (in->Address())
|
|
||||||
{
|
|
||||||
in->ClearHook();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case HOST_COMMAND_DETACH:
|
|
||||||
::running = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CloseHandle(::hookPipe);
|
|
||||||
CloseHandle(hostPipe);
|
|
||||||
}
|
|
||||||
FreeLibraryAndExitThread(::currentModule, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConsoleOutput(LPCSTR text)
|
|
||||||
{
|
|
||||||
BYTE buffer[PIPE_BUFFER_SIZE];
|
|
||||||
*(DWORD*)buffer = HOST_NOTIFICATION;
|
|
||||||
*(DWORD*)(buffer + sizeof(DWORD)) = HOST_NOTIFICATION_TEXT;
|
|
||||||
strcpy((char*)buffer + sizeof(DWORD) * 2, text);
|
|
||||||
DWORD unused;
|
|
||||||
WriteFile(::hookPipe, buffer, strlen(text) + sizeof(DWORD) * 2, &unused, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NotifyHookInsert(HookParam hp, LPCSTR name)
|
|
||||||
{
|
|
||||||
BYTE buffer[PIPE_BUFFER_SIZE];
|
|
||||||
*(DWORD*)buffer = HOST_NOTIFICATION;
|
|
||||||
*(DWORD*)(buffer + sizeof(DWORD)) = HOST_NOTIFICATION_NEWHOOK;
|
|
||||||
*(HookParam*)(buffer + sizeof(DWORD) * 2) = hp;
|
|
||||||
strcpy((char*)buffer + sizeof(DWORD) * 2 + sizeof(HookParam), name);
|
|
||||||
DWORD unused;
|
|
||||||
WriteFile(::hookPipe, buffer, strlen(name) + sizeof(DWORD) * 2 + sizeof(HookParam), &unused, nullptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NotifyHookRemove(DWORD addr)
|
|
||||||
{
|
|
||||||
BYTE buffer[sizeof(DWORD) * 3];
|
|
||||||
*(DWORD*)buffer = HOST_NOTIFICATION;
|
|
||||||
*(DWORD*)(buffer + sizeof(DWORD)) = HOST_NOTIFICATION_RMVHOOK;
|
|
||||||
*(DWORD*)(buffer + sizeof(DWORD) * 2) = addr;
|
|
||||||
DWORD unused;
|
|
||||||
WriteFile(::hookPipe, buffer, sizeof(DWORD) * 3, &unused, nullptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// EOF
|
|
Loading…
Reference in New Issue
Block a user