forked from Public-Mirror/Textractor
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)
|
||||
|
||||
add_subdirectory(host)
|
||||
if (${x64})
|
||||
add_subdirectory(vnrhook64)
|
||||
else(${x64})
|
||||
add_subdirectory(vnrhook)
|
||||
endif(${x64})
|
||||
add_subdirectory(vnrhook)
|
||||
add_subdirectory(GUI)
|
||||
|
@ -2,6 +2,18 @@ project(vnrhook)
|
||||
|
||||
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
|
||||
include/const.h
|
||||
include/defs.h
|
||||
@ -33,6 +45,7 @@ set(vnrhook_src
|
||||
src/util/mono/monoobject.h
|
||||
src/util/mono/monotype.h
|
||||
)
|
||||
endif(${x64})
|
||||
|
||||
include_directories(src/util)
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#endif // _MSC_VER
|
||||
|
||||
#include "src/engine/engine.h"
|
||||
#include "ntdll/ntdll.h"
|
||||
#include "src/engine/match.h"
|
||||
#include "src/engine/hookdefs.h"
|
||||
#include "src/util/util.h"
|
||||
|
@ -42,6 +42,7 @@ TextHook *hookman,
|
||||
|
||||
// - Unnamed helpers -
|
||||
|
||||
#ifndef _WIN64
|
||||
namespace { // unnamed
|
||||
//provide const time hook entry.
|
||||
int userhook_count;
|
||||
@ -204,9 +205,25 @@ int ProcessHook(DWORD dwDataBase, DWORD dwRetn, TextHook *hook) // Use SEH to en
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
#endif // _WIN32
|
||||
|
||||
// - 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.
|
||||
// It return the hook address only for auxiliary case.
|
||||
// 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()
|
||||
{
|
||||
DWORD ret = no;
|
||||
@ -336,72 +341,6 @@ int TextHook::InsertHookCode()
|
||||
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()
|
||||
{
|
||||
@ -503,6 +442,74 @@ int TextHook::UnsafeInsertHookCode()
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -80,12 +80,14 @@ BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID unused)
|
||||
|
||||
::processStartAddress = ::processStopAddress = (DWORD)GetModuleHandleW(nullptr);
|
||||
|
||||
#ifndef _WIN64
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
do
|
||||
{
|
||||
VirtualQuery((void*)::processStopAddress, &info, sizeof(info));
|
||||
::processStopAddress = (DWORD)info.BaseAddress + info.RegionSize;
|
||||
} while (info.Protect);
|
||||
#endif
|
||||
|
||||
{
|
||||
wchar_t hm_mutex[0x100];
|
||||
|
@ -49,7 +49,11 @@ DWORD WINAPI PipeManager(LPVOID unused)
|
||||
CloseHandle(pipeAcquisitionMutex);
|
||||
|
||||
ConsoleOutput("vnrcli:WaitForPipe: pipe connected");
|
||||
#ifdef _WIN64
|
||||
ConsoleOutput("Hooks don't work on x64, only read codes work. Engine disabled.");
|
||||
#else
|
||||
Engine::Hijack();
|
||||
#endif
|
||||
|
||||
while (::running)
|
||||
{
|
||||
|
@ -7,7 +7,8 @@
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(disable:4800) // C4800: forcing value to bool
|
||||
#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?
|
||||
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…
x
Reference in New Issue
Block a user