forked from Public-Mirror/Textractor
starting commit
This commit is contained in:
parent
62a204dc85
commit
14f251b213
47
vnr/ith/common/defs.h
Normal file
47
vnr/ith/common/defs.h
Normal file
@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
// ith/common/defs.h
|
||||
// 8/23/2013 jichi
|
||||
|
||||
// DLL files
|
||||
|
||||
//#define ITH_SERVER_DLL L"vnrsrv.dll"
|
||||
//#define ITH_CLIENT_DLL L"vnrcli.dll"
|
||||
//#define ITH_CLIENT_XP_DLL L"vnrclixp.dll"
|
||||
////#define ITH_CLIENT_UX_DLL L"vnrcliux.dll"
|
||||
//#define ITH_ENGINE_DLL L"vnreng.dll"
|
||||
//#define ITH_ENGINE_XP_DLL L"vnrengxp.dll"
|
||||
//#define ITH_ENGINE_UX_DLL L"vnrengux.dll"
|
||||
|
||||
#define ITH_DLL L"vnrhook.dll"
|
||||
#define ITH_DLL_XP L"vnrhookxp.dll"
|
||||
|
||||
// Pipes
|
||||
|
||||
#define ITH_TEXT_PIPE L"\\??\\pipe\\VNR_TEXT"
|
||||
#define ITH_COMMAND_PIPE L"\\??\\pipe\\VNR_COMMAND"
|
||||
|
||||
// Sections
|
||||
|
||||
#define ITH_SECTION_ L"VNR_SECTION_" // _%d
|
||||
|
||||
// Mutex
|
||||
|
||||
#define ITH_PROCESS_MUTEX_ L"VNR_PROCESS_" // ITH_%d
|
||||
#define ITH_HOOKMAN_MUTEX_ L"VNR_HOOKMAN_" // ITH_HOOKMAN_%d
|
||||
#define ITH_DETACH_MUTEX_ L"VNR_DETACH_" // ITH_DETACH_%d
|
||||
|
||||
#define ITH_GRANTPIPE_MUTEX L"VNR_GRANT_PIPE" // ITH_GRANT_PIPE
|
||||
|
||||
//#define ITH_ENGINE_MUTEX L"VNR_ENGINE" // ITH_ENGINE
|
||||
#define ITH_CLIENT_MUTEX L"VNR_CLIENT" // ITH_DLL_RUNNING
|
||||
#define ITH_SERVER_MUTEX L"VNR_SERVER" // ITH_RUNNING
|
||||
#define ITH_SERVER_HOOK_MUTEX L"VNR_SERVER_HOOK" // original
|
||||
|
||||
// Events
|
||||
|
||||
#define ITH_REMOVEHOOK_EVENT L"VNR_REMOVE_HOOK" // ITH_REMOVE_HOOK
|
||||
#define ITH_MODIFYHOOK_EVENT L"VNR_MODIFY_HOOK" // ITH_MODIFY_HOOK
|
||||
#define ITH_PIPEEXISTS_EVENT L"VNR_PIPE_EXISTS" // ITH_PIPE_EXIST
|
||||
|
||||
// EOF
|
25
vnr/ith/common/except.h
Normal file
25
vnr/ith/common/except.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
// ith/common/except.h
|
||||
// 9/17/2013 jichi
|
||||
|
||||
#define ITH_RAISE (*(int*)0 = 0) // raise C000005, for debugging only
|
||||
|
||||
#ifdef ITH_HAS_SEH
|
||||
|
||||
# define ITH_TRY __try
|
||||
# define ITH_EXCEPT __except(EXCEPTION_EXECUTE_HANDLER)
|
||||
# define ITH_WITH_SEH(...) \
|
||||
ITH_TRY { __VA_ARGS__; } ITH_EXCEPT {}
|
||||
|
||||
#else // for old msvcrt.dll on Windows XP that does not have exception handler
|
||||
|
||||
// Currently, only with_seh is implemented. Try and catch are not.
|
||||
# define ITH_TRY if (true)
|
||||
# define ITH_EXCEPT else
|
||||
# include "winseh/winseh.h"
|
||||
# define ITH_WITH_SEH(...) seh_with(__VA_ARGS__)
|
||||
|
||||
#endif // ITH_HAS_SEH
|
||||
|
||||
// EOF
|
85
vnr/ith/common/growl.h
Normal file
85
vnr/ith/common/growl.h
Normal file
@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
|
||||
// ith/common/growl.h
|
||||
// 9/17/2013 jichi
|
||||
|
||||
//#ifdef ITH_HAS_GROWL
|
||||
|
||||
#include <windows.h>
|
||||
#include "ith/common/string.h"
|
||||
|
||||
#define ITH_MSG_A(_msg) MessageBoxA(nullptr, _msg, "VNR Message", MB_OK)
|
||||
#define ITH_MSG(_msg) MessageBoxW(nullptr, _msg, L"VNR Message", MB_OK)
|
||||
#define ITH_WARN(_msg) MessageBoxW(nullptr, _msg, L"VNR Warning", MB_OK)
|
||||
#define ITH_ERROR(_msg) MessageBoxW(nullptr, _msg, L"VNR Error", MB_OK)
|
||||
|
||||
inline void ITH_GROWL_DWORD(DWORD value)
|
||||
{
|
||||
WCHAR buf[100];
|
||||
swprintf(buf, L"DWORD: %x", value);
|
||||
ITH_MSG(buf);
|
||||
}
|
||||
|
||||
inline void ITH_GROWL_DWORD2(DWORD v, DWORD v2)
|
||||
{
|
||||
WCHAR buf[100];
|
||||
swprintf(buf, L"DWORD2: %x,%x", v, v2);
|
||||
ITH_MSG(buf);
|
||||
}
|
||||
|
||||
inline void ITH_GROWL_DWORD3(DWORD v, DWORD v2, DWORD v3)
|
||||
{
|
||||
WCHAR buf[100];
|
||||
swprintf(buf, L"DWORD3: %x,%x,%x", v, v2, v3);
|
||||
ITH_MSG(buf);
|
||||
}
|
||||
|
||||
inline void ITH_GROWL_DWORD4(DWORD v, DWORD v2, DWORD v3, DWORD v4)
|
||||
{
|
||||
WCHAR buf[100];
|
||||
swprintf(buf, L"DWORD4: %x,%x,%x,%x", v, v2, v3, v4);
|
||||
ITH_MSG(buf);
|
||||
}
|
||||
|
||||
inline void ITH_GROWL_DWORD5(DWORD v, DWORD v2, DWORD v3, DWORD v4, DWORD v5)
|
||||
{
|
||||
WCHAR buf[100];
|
||||
swprintf(buf, L"DWORD5: %x,%x,%x,%x,%x", v, v2, v3, v4, v5);
|
||||
ITH_MSG(buf);
|
||||
}
|
||||
|
||||
inline void ITH_GROWL_DWORD6(DWORD v, DWORD v2, DWORD v3, DWORD v4, DWORD v5, DWORD v6)
|
||||
{
|
||||
WCHAR buf[100];
|
||||
swprintf(buf, L"DWORD6: %x,%x,%x,%x,%x,%x", v, v2, v3, v4, v5, v6);
|
||||
ITH_MSG(buf);
|
||||
}
|
||||
|
||||
inline void ITH_GROWL_DWORD7(DWORD v, DWORD v2, DWORD v3, DWORD v4, DWORD v5, DWORD v6, DWORD v7)
|
||||
{
|
||||
WCHAR buf[100];
|
||||
swprintf(buf, L"DWORD7: %x,%x,%x,%x,%x,%x,%x", v, v2, v3, v4, v5, v6, v7);
|
||||
ITH_MSG(buf);
|
||||
}
|
||||
|
||||
inline void ITH_GROWL_DWORD8(DWORD v, DWORD v2, DWORD v3, DWORD v4, DWORD v5, DWORD v6, DWORD v7, DWORD v8)
|
||||
{
|
||||
WCHAR buf[100];
|
||||
swprintf(buf, L"DWORD8: %x,%x,%x,%x,%x,%x,%x,%x", v, v2, v3, v4, v5, v6, v7, v8);
|
||||
ITH_MSG(buf);
|
||||
}
|
||||
|
||||
inline void ITH_GROWL_DWORD9(DWORD v, DWORD v2, DWORD v3, DWORD v4, DWORD v5, DWORD v6, DWORD v7, DWORD v8, DWORD v9)
|
||||
{
|
||||
WCHAR buf[100];
|
||||
swprintf(buf, L"DWORD9: %x,%x,%x,%x,%x,%x,%x,%x,%x", v, v2, v3, v4, v5, v6, v7, v8, v9);
|
||||
ITH_MSG(buf);
|
||||
}
|
||||
|
||||
inline void ITH_GROWL(DWORD v) { ITH_GROWL_DWORD(v); }
|
||||
inline void ITH_GROWL(LPCWSTR v) { ITH_MSG(v); }
|
||||
inline void ITH_GROWL(LPCSTR v) { ITH_MSG_A(v); }
|
||||
|
||||
//#endif // ITH_HAS_GROWL
|
||||
|
||||
// EOF
|
46
vnr/ith/common/memory.h
Normal file
46
vnr/ith/common/memory.h
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
// ith/common/memory.h
|
||||
// 8/23/2013 jichi
|
||||
// Branch: ITH/mem.h, revision 66
|
||||
|
||||
#ifndef ITH_HAS_HEAP
|
||||
# define ITH_MEMSET_HEAP(...) ::memset(__VA_ARGS__)
|
||||
#else
|
||||
# define ITH_MEMSET_HEAP(...) (void)0
|
||||
|
||||
// Defined in kernel32.lilb
|
||||
extern "C" {
|
||||
// PVOID RtlAllocateHeap( _In_ PVOID HeapHandle, _In_opt_ ULONG Flags, _In_ SIZE_T Size);
|
||||
__declspec(dllimport) void * __stdcall RtlAllocateHeap(void *HeapHandle, unsigned long Flags, unsigned long Size);
|
||||
|
||||
// BOOLEAN RtlFreeHeap( _In_ PVOID HeapHandle, _In_opt_ ULONG Flags, _In_ PVOID HeapBase);
|
||||
__declspec(dllimport) int __stdcall RtlFreeHeap(void *HeapHandle, unsigned long Flags, void *HeapBase);
|
||||
} // extern "C"
|
||||
|
||||
//NTSYSAPI
|
||||
//BOOL
|
||||
//NTAPI
|
||||
//RtlFreeHeap(
|
||||
// _In_ HANDLE hHeap,
|
||||
// _In_ DWORD dwFlags,
|
||||
// _In_ LPVOID lpMem
|
||||
//);
|
||||
|
||||
extern void *hHeap; // defined in ith/sys.cc
|
||||
|
||||
inline void * __cdecl operator new(size_t lSize)
|
||||
{
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa366597%28v=vs.85%29.aspx
|
||||
// HEAP_ZERO_MEMORY flag is critical. All new objects are assumed with zero initialized.
|
||||
enum { HEAP_ZERO_MEMORY = 0x00000008 };
|
||||
return RtlAllocateHeap(::hHeap, HEAP_ZERO_MEMORY, lSize);
|
||||
}
|
||||
|
||||
inline void __cdecl operator delete(void *pBlock)
|
||||
{ RtlFreeHeap(::hHeap, 0, pBlock); }
|
||||
|
||||
inline void __cdecl operator delete[](void *pBlock)
|
||||
{ RtlFreeHeap(::hHeap, 0, pBlock); }
|
||||
|
||||
#endif // ITH_HAS_HEAP
|
36
vnr/ith/common/string.h
Normal file
36
vnr/ith/common/string.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
// ith/common/string.h
|
||||
// 8/9/2013 jichi
|
||||
// Branch: ITH/string.h, rev 66
|
||||
|
||||
#ifdef ITH_HAS_CRT // ITH is linked with msvcrt dlls
|
||||
# include <cstdio>
|
||||
# include <cstring>
|
||||
|
||||
#else
|
||||
# define _INC_SWPRINTF_INL_
|
||||
# define CRT_IMPORT __declspec(dllimport)
|
||||
|
||||
#include <windows.h> // for wchar_t
|
||||
extern "C" {
|
||||
CRT_IMPORT int swprintf(wchar_t *src, const wchar_t *fmt, ...);
|
||||
CRT_IMPORT int sprintf(char *src, const char *fmt, ...);
|
||||
CRT_IMPORT int swscanf(const wchar_t *src, const wchar_t *fmt, ...);
|
||||
CRT_IMPORT int sscanf(const char *src, const char *fmt, ...);
|
||||
CRT_IMPORT int wprintf(const wchar_t *fmt, ...);
|
||||
CRT_IMPORT int printf(const char *fmt, ...);
|
||||
CRT_IMPORT int _wputs(const wchar_t *src);
|
||||
CRT_IMPORT int puts(const char *src);
|
||||
CRT_IMPORT int _stricmp(const char *x, const char *y);
|
||||
CRT_IMPORT int _wcsicmp(const wchar_t *x, const wchar_t *y);
|
||||
//CRT_IMPORT size_t strlen(const char *);
|
||||
//CRT_IMPORT size_t wcslen(const wchar_t *);
|
||||
//CRT_IMPORT char *strcpy(char *,const char *);
|
||||
//CRT_IMPORT wchar_t *wcscpy(wchar_t *,const wchar_t *);
|
||||
CRT_IMPORT void *memmove(void *dst, const void *src, size_t sz);
|
||||
CRT_IMPORT const char *strchr(const char *src, int val);
|
||||
CRT_IMPORT int strncmp(const char *x, const char *y, size_t sz);
|
||||
} // extern "C"
|
||||
|
||||
#endif // ITH_HAS_CRT
|
91
vnr/ith/common/types.h
Normal file
91
vnr/ith/common/types.h
Normal file
@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
|
||||
// ith/common/types.h
|
||||
// 8/23/2013 jichi
|
||||
// Branch: ITH/common.h, rev 128
|
||||
|
||||
#include <windows.h> // needed for windef types
|
||||
|
||||
/** jichi 3/7/2014: Add guessed comment
|
||||
*
|
||||
* DWORD addr absolute or relative address
|
||||
* DWORD split esp offset of the split character
|
||||
*
|
||||
* http://faydoc.tripod.com/cpu/pushad.htm
|
||||
* http://agth.wikia.com/wiki/Cheat_Engine_AGTH_Tutorial
|
||||
* The order is the same as pushd
|
||||
* EAX, ECX, EDX, EBX, ESP (original value), EBP, ESI, and EDI (if the current operand-size attribute is 32) and AX, CX, DX, BX, SP
|
||||
* Negative values of 'data_offset' and 'sub_offset' refer to registers:-4 for EAX, -8 for ECX, -C for EDX, -10 for EBX, -14 for ESP, -18 for EBP, -1C for ESI, -20 for EDI
|
||||
*/
|
||||
struct HookParam {
|
||||
// jichi 8/24/2013: For special hooks. Original name: DataFun
|
||||
typedef void (*text_fun_t)(DWORD esp, HookParam *hp, BYTE index, DWORD *data, DWORD *split, DWORD *len);
|
||||
|
||||
// jichi 10/24/2014: Add filter function. Return the if skip the text
|
||||
typedef bool (*filter_fun_t)(LPVOID str, DWORD *len, HookParam *hp, BYTE index);
|
||||
|
||||
// jichi 10/24/2014: Add generic hook function, return false if stop execution.
|
||||
typedef bool (*hook_fun_t)(DWORD esp, HookParam *hp);
|
||||
|
||||
DWORD addr; // absolute or relative address
|
||||
DWORD off, // offset of the data in the memory
|
||||
ind, // ?
|
||||
split, // esp offset of the split character = pusha offset - 4
|
||||
split_ind; // ?
|
||||
DWORD module, // hash of the module
|
||||
function;
|
||||
text_fun_t text_fun;
|
||||
filter_fun_t filter_fun;
|
||||
hook_fun_t hook_fun;
|
||||
DWORD type; // flags
|
||||
WORD length_offset; // index of the string length
|
||||
BYTE hook_len, // ?
|
||||
recover_len; // ?
|
||||
|
||||
// 2/2/2015: jichi number of times - 1 to run the hook
|
||||
BYTE extra_text_count;
|
||||
BYTE _unused; // jichi 2/2/2015: add a BYTE type to make to total sizeof(HookParam) even.
|
||||
|
||||
// 7/20/2014: jichi additional parameters for PSP games
|
||||
DWORD user_flags,
|
||||
user_value;
|
||||
};
|
||||
|
||||
// jichi 6/1/2014: Structure of the esp for extern functions
|
||||
struct HookStack
|
||||
{
|
||||
// pushad
|
||||
DWORD edi, // -0x24
|
||||
esi, // -0x20
|
||||
ebp, // -0x1c
|
||||
esp, // -0x18
|
||||
ebx, // -0x14
|
||||
edx, // -0x10
|
||||
ecx, // -0xc
|
||||
eax; // -0x8
|
||||
// pushfd
|
||||
DWORD eflags; // -0x4
|
||||
DWORD retaddr; // 0
|
||||
DWORD args[1]; // 0x4
|
||||
};
|
||||
|
||||
struct SendParam {
|
||||
DWORD type;
|
||||
HookParam hp;
|
||||
};
|
||||
|
||||
struct Hook { // size: 0x80
|
||||
HookParam hp;
|
||||
LPWSTR hook_name;
|
||||
int name_length;
|
||||
BYTE recover[0x68 - sizeof(HookParam)];
|
||||
BYTE original[0x10];
|
||||
|
||||
DWORD Address() const { return hp.addr; }
|
||||
DWORD Type() const { return hp.type; }
|
||||
WORD Length() const { return hp.hook_len; }
|
||||
LPWSTR Name() const { return hook_name; }
|
||||
int NameLength() const { return name_length; }
|
||||
};
|
||||
|
||||
// EOF
|
10
vnr/ith/dllconfig.h
Normal file
10
vnr/ith/dllconfig.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
// dllconfig.h
|
||||
// 8/23/2013 jichi
|
||||
|
||||
#include "ith/common/memory.h"
|
||||
#include "ith/common/string.h"
|
||||
#include "ntdll/ntdll.h"
|
||||
|
||||
// EOF
|
35
vnr/ith/dllconfig.pri
Normal file
35
vnr/ith/dllconfig.pri
Normal file
@ -0,0 +1,35 @@
|
||||
# dllconfig.pri
|
||||
# 8/9/2013 jichi
|
||||
# For linking ITH injectable dlls.
|
||||
# The dll is self-containd and Windows-independent.
|
||||
|
||||
CONFIG += dll noqt #noeh nosafeseh
|
||||
CONFIG -= embed_manifest_dll # dynamically load dlls
|
||||
win32 {
|
||||
CONFIG(eh): DEFINES += ITH_HAS_SEH # Do have exception handler in msvcrt.dll on Windows Vista and later
|
||||
CONFIG(noeh): DEFINES -= ITH_HAS_SEH # Do not have exception handler in msvcrt.dll on Windows XP and before
|
||||
}
|
||||
include(../../../config.pri)
|
||||
#win32 {
|
||||
# CONFIG(noeh): include($$LIBDIR/winseh/winseh_safe.pri)
|
||||
#}
|
||||
|
||||
# jichi 11/24/2013: Disable manual heap
|
||||
DEFINES -= ITH_HAS_HEAP
|
||||
|
||||
# jichi 11/13/2011: disable swprinf warning
|
||||
DEFINES += _CRT_NON_CONFORMING_SWPRINTFS
|
||||
|
||||
## Libraries
|
||||
|
||||
#LIBS += -lkernel32 -luser32 -lgdi32
|
||||
LIBS += -L$$WDK7_HOME/lib/wxp/i386 -lntdll
|
||||
LIBS += $$WDK7_HOME/lib/crt/i386/msvcrt.lib # Override msvcrt10
|
||||
#LIBS += -L$$WDK7_HOME/lib/crt/i386 -lmsvcrt
|
||||
#QMAKE_LFLAGS += $$WDK7_HOME/lib/crt/i386/msvcrt.lib # This will leave runtime flags in the dll
|
||||
|
||||
#LIBS += -L$$WDK8_HOME/lib/winv6.3/um/x86 -lntdll
|
||||
|
||||
HEADERS += $$PWD/dllconfig.h
|
||||
|
||||
# EOF
|
135
vnr/ith/hook/CMakeLists.txt
Normal file
135
vnr/ith/hook/CMakeLists.txt
Normal file
@ -0,0 +1,135 @@
|
||||
# hook.pro
|
||||
# CONFIG += eh eha
|
||||
# include(../dllconfig.pri)
|
||||
|
||||
# hookxp.pro
|
||||
# CONFIG += noeh
|
||||
# include(../dllconfig.pri)
|
||||
|
||||
# dllconfig.pri
|
||||
# include(../../../config.pri)
|
||||
# win32 {
|
||||
# CONFIG(eh): DEFINES += ITH_HAS_SEH
|
||||
# CONFIG(noeh): DEFINES -= ITH_HAS_SEH
|
||||
# }
|
||||
|
||||
# config.pri
|
||||
# CONFIG(eha) {
|
||||
# message(CONFIG eha)
|
||||
# QMAKE_CXXFLAGS_STL_ON -= /EHsc
|
||||
# QMAKE_CXXFLAGS_EXCEPTIONS_ON -= /EHsc
|
||||
# QMAKE_CXXFLAGS_STL_ON += /EHa
|
||||
# QMAKE_CXXFLAGS_EXCEPTIONS_ON += /EHa
|
||||
# }
|
||||
#
|
||||
# CONFIG(noeh) { # No Exception handler
|
||||
# QMAKE_CXXFLAGS += /GR-
|
||||
# QMAKE_CXXFLAGS_RTTI_ON -= /GR
|
||||
# QMAKE_CXXFLAGS_STL_ON -= /EHsc
|
||||
# QMAKE_CXXFLAGS_EXCEPTIONS_ON -= /EHsc
|
||||
# }
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
set(vnrhook_src
|
||||
cli.h
|
||||
config.h
|
||||
hook.h
|
||||
main.cc
|
||||
engine/engine.cc
|
||||
engine/engine.h
|
||||
engine/hookdefs.h
|
||||
engine/match.cc
|
||||
engine/match.h
|
||||
engine/pchooks.cc
|
||||
engine/pchooks.h
|
||||
engine/util.cc
|
||||
engine/util.h
|
||||
hijack/texthook.cc
|
||||
rpc/pipe.cc
|
||||
tree/avl.h
|
||||
${PROJECT_SOURCE_DIR}/ccutil/ccmacro.h
|
||||
${PROJECT_SOURCE_DIR}/cpputil/cpplocale.h
|
||||
${PROJECT_SOURCE_DIR}/cpputil/cppmarshal.h
|
||||
${PROJECT_SOURCE_DIR}/cpputil/cppmath.h
|
||||
${PROJECT_SOURCE_DIR}/cpputil/cpppath.h
|
||||
${PROJECT_SOURCE_DIR}/cpputil/cppstring.h
|
||||
${PROJECT_SOURCE_DIR}/cpputil/cpptype.h
|
||||
${PROJECT_SOURCE_DIR}/cpputil/cppunicode.h
|
||||
${PROJECT_SOURCE_DIR}/disasm/disasm.cc
|
||||
${PROJECT_SOURCE_DIR}/memdbg/memdbg.h
|
||||
${PROJECT_SOURCE_DIR}/memdbg/memsearch.cc
|
||||
${PROJECT_SOURCE_DIR}/memdbg/memsearch.h
|
||||
${PROJECT_SOURCE_DIR}/ntinspect/ntinspect.cc
|
||||
${PROJECT_SOURCE_DIR}/ntinspect/ntinspect.h
|
||||
${PROJECT_SOURCE_DIR}/winversion/winversion.cc
|
||||
${PROJECT_SOURCE_DIR}/winversion/winversion.h
|
||||
${common_src}
|
||||
${import_src}
|
||||
)
|
||||
|
||||
source_group("common" FILES ${common_src})
|
||||
source_group("import" FILES ${import_src})
|
||||
|
||||
add_library(vnrhook SHARED ${vnrhook_src})
|
||||
|
||||
set(vnrhookxp_src ${vnrhook_src}
|
||||
${PROJECT_SOURCE_DIR}/winseh/winseh.cc
|
||||
${PROJECT_SOURCE_DIR}/winseh/winseh_safe.cc
|
||||
${PROJECT_SOURCE_DIR}/winseh/winseh.h
|
||||
${PROJECT_SOURCE_DIR}/winseh/safeseh.asm
|
||||
)
|
||||
|
||||
enable_language(ASM_MASM)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
add_library(vnrhookxp SHARED ${vnrhookxp_src})
|
||||
|
||||
set_target_properties(vnrhook vnrhookxp PROPERTIES
|
||||
LINK_FLAGS "/SUBSYSTEM:WINDOWS /MANIFEST:NO"
|
||||
)
|
||||
|
||||
target_compile_options(vnrhook PRIVATE
|
||||
/EHa
|
||||
$<$<CONFIG:Release>:>
|
||||
$<$<CONFIG:Debug>:>
|
||||
)
|
||||
|
||||
target_compile_options(vnrhookxp PRIVATE
|
||||
/GR-
|
||||
# /EHs-c- # disable exception handling # CMake bug 15243: http://www.cmake.org/Bug/view.php?id=15243
|
||||
$<$<CONFIG:Release>:>
|
||||
$<$<CONFIG:Debug>:>
|
||||
)
|
||||
|
||||
if(TARGET vnrhookxp)
|
||||
STRING(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
endif(TARGET vnrhookxp)
|
||||
|
||||
set(vnrhook_libs
|
||||
vnrsys
|
||||
${WDK_HOME}/lib/wxp/i386/ntdll.lib
|
||||
Version.lib
|
||||
)
|
||||
|
||||
target_link_libraries(vnrhook ${vnrhook_libs})
|
||||
target_link_libraries(vnrhookxp ${vnrhook_libs})
|
||||
|
||||
target_compile_definitions(vnrhook
|
||||
PRIVATE
|
||||
-DITH_HAS_SEH
|
||||
)
|
||||
target_compile_definitions(vnrhookxp
|
||||
PRIVATE
|
||||
)
|
||||
|
||||
install(TARGETS vnrhook vnrhookxp RUNTIME
|
||||
DESTINATION .
|
||||
CONFIGURATIONS Release
|
||||
)
|
99
vnr/ith/hook/cli.h
Normal file
99
vnr/ith/hook/cli.h
Normal file
@ -0,0 +1,99 @@
|
||||
#pragma once
|
||||
|
||||
// cli.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 <windows.h>
|
||||
//#define IHF
|
||||
#include "config.h"
|
||||
#include "hook.h"
|
||||
|
||||
// jichi 12/25/2013: Header in each message sent to vnrsrv
|
||||
// There are totally three elements
|
||||
// - 0x0 dwAddr hook address
|
||||
// - 0x4 dwRetn return address
|
||||
// - 0x8 dwSplit split value
|
||||
#define HEADER_SIZE 0xc
|
||||
|
||||
extern int current_hook;
|
||||
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;
|
||||
|
||||
template <class T, class D, class fComp, class fCopy, class fLength>
|
||||
class AVLTree;
|
||||
struct FunctionInfo {
|
||||
DWORD addr;
|
||||
DWORD module;
|
||||
DWORD size;
|
||||
LPWSTR name;
|
||||
};
|
||||
struct SCMP;
|
||||
struct SCPY;
|
||||
struct SLEN;
|
||||
extern AVLTree<char, FunctionInfo, SCMP, SCPY, SLEN> *tree;
|
||||
|
||||
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 UnsafeInsertHookCode();
|
||||
DWORD UnsafeSend(DWORD dwDataBase, DWORD dwRetn);
|
||||
public:
|
||||
int InsertHook();
|
||||
int InsertHookCode();
|
||||
int InitHook(const HookParam &hp, LPCWSTR name = 0, WORD set_flag = 0);
|
||||
int InitHook(LPVOID addr, DWORD data, DWORD data_ind,
|
||||
DWORD split_off, DWORD split_ind, WORD type, DWORD len_off = 0);
|
||||
DWORD Send(DWORD dwDataBase, DWORD dwRetn);
|
||||
int RecoverHook();
|
||||
int RemoveHook();
|
||||
int ClearHook();
|
||||
int ModifyHook(const HookParam&);
|
||||
int SetHookName(LPCWSTR name);
|
||||
int GetLength(DWORD base, DWORD in); // jichi 12/25/2013: Return 0 if failed
|
||||
void CoolDown(); // jichi 9/28/2013: flush instruction cache on wine
|
||||
};
|
||||
|
||||
extern TextHook *hookman,
|
||||
*current_available;
|
||||
|
||||
//void InitDefaultHook();
|
||||
|
||||
struct FilterRange { DWORD lower, upper; };
|
||||
extern FilterRange *filter;
|
||||
|
||||
extern bool running,
|
||||
live;
|
||||
|
||||
extern HANDLE hPipe,
|
||||
hmMutex;
|
||||
|
||||
DWORD WINAPI WaitForPipe(LPVOID lpThreadParameter);
|
||||
DWORD WINAPI CommandPipe(LPVOID lpThreadParameter);
|
||||
|
||||
//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();
|
||||
|
||||
// EOF
|
10
vnr/ith/hook/config.h
Normal file
10
vnr/ith/hook/config.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
// config.h
|
||||
// 8/23/2013 jichi
|
||||
// The first header file that are included by all source files.
|
||||
|
||||
#define IHF // for dll import
|
||||
#include "ith/dllconfig.h"
|
||||
|
||||
// EOF
|
16384
vnr/ith/hook/engine/engine.cc
Normal file
16384
vnr/ith/hook/engine/engine.cc
Normal file
File diff suppressed because it is too large
Load Diff
162
vnr/ith/hook/engine/engine.h
Normal file
162
vnr/ith/hook/engine/engine.h
Normal file
@ -0,0 +1,162 @@
|
||||
#pragma once
|
||||
|
||||
// engine/engine.h
|
||||
// 8/23/2013 jichi
|
||||
// See: http://ja.wikipedia.org/wiki/プロジェクト:美少女ゲーム系/ゲームエンジン
|
||||
|
||||
#include "config.h"
|
||||
|
||||
struct HookParam; // defined in ith types.h
|
||||
|
||||
namespace Engine {
|
||||
|
||||
// Global variables
|
||||
extern wchar_t process_name_[MAX_PATH], // cached
|
||||
process_path_[MAX_PATH]; // cached
|
||||
extern DWORD module_base_,
|
||||
module_limit_;
|
||||
|
||||
//extern LPVOID trigger_addr;
|
||||
typedef bool (* trigger_fun_t)(LPVOID addr, DWORD frame, DWORD stack);
|
||||
extern trigger_fun_t trigger_fun_;
|
||||
|
||||
bool InsertMonoHooks(); // Mono
|
||||
|
||||
// Wii engines
|
||||
|
||||
bool InsertGCHooks(); // Dolphin
|
||||
bool InsertVanillawareGCHook();
|
||||
|
||||
// PS2 engines
|
||||
|
||||
bool InsertPCSX2Hooks(); // PCSX2
|
||||
bool InsertMarvelousPS2Hook(); // http://marvelous.jp
|
||||
bool InsertMarvelous2PS2Hook(); // http://marvelous.jp
|
||||
bool InsertTypeMoonPS2Hook(); // http://typemoon.com
|
||||
//bool InsertNamcoPS2Hook();
|
||||
|
||||
// PSP engines
|
||||
|
||||
void SpecialPSPHook(DWORD esp_base, HookParam *hp, DWORD *data, DWORD *split, DWORD *len); // General PSP extern hook
|
||||
|
||||
bool InsertPPSSPPHooks(); // PPSSPPWindows
|
||||
|
||||
bool InsertPPSSPPHLEHooks();
|
||||
bool InsertOtomatePPSSPPHook(); // PSP otomate.jp, 0.9.9.0 only
|
||||
|
||||
bool Insert5pbPSPHook(); // PSP 5pb.jp
|
||||
bool InsertAlchemistPSPHook(); // PSP Alchemist-net.co.jp, 0.9.8 only
|
||||
bool InsertAlchemist2PSPHook(); // PSP Alchemist-net.co.jp
|
||||
bool InsertBandaiNamePSPHook(); // PSP Bandai.co.jp
|
||||
bool InsertBandaiPSPHook(); // PSP Bandai.co.jp
|
||||
bool InsertBroccoliPSPHook(); // PSP Broccoli.co.jp
|
||||
bool InsertFelistellaPSPHook(); // PSP felistella.co.jp
|
||||
|
||||
bool InsertCyberfrontPSPHook(); // PSP CYBERFRONT (closed)
|
||||
bool InsertImageepochPSPHook(); // PSP Imageepoch.co.jp
|
||||
bool InsertImageepoch2PSPHook();// PSP Imageepoch.co.jp
|
||||
bool InsertKadokawaNamePSPHook(); // PSP Kadokawa.co.jp
|
||||
bool InsertKonamiPSPHook(); // PSP Konami.jp
|
||||
bool InsertTecmoPSPHook(); // PSP Koeitecmo.co.jp
|
||||
//bool InsertTypeMoonPSPHook(); // PSP Typemoon.com
|
||||
|
||||
bool InsertOtomatePSPHook(); // PSP Otomate.jp, 0.9.8 only
|
||||
//bool InsertOtomate2PSPHook(); // PSP otomate.jp >= 0.9.9.1
|
||||
|
||||
bool InsertIntensePSPHook(); // PSP Intense.jp
|
||||
bool InsertKidPSPHook(); // PSP Kid-game.co.jp
|
||||
bool InsertNippon1PSPHook(); // PSP Nippon1.jp
|
||||
bool InsertNippon2PSPHook(); // PSP Nippon1.jp
|
||||
bool InsertYetiPSPHook(); // PSP Yetigame.jp
|
||||
bool InsertYeti2PSPHook(); // PSP Yetigame.jp
|
||||
|
||||
// PC engines
|
||||
|
||||
bool Insert2RMHook(); // 2RM - Adventure Engine
|
||||
bool Insert5pbHook(); // 5pb.jp, PSP/PS3 games ported to PC
|
||||
bool InsertAB2TryHook(); // Yane@AkabeiSoft2Try: YaneSDK.dll.
|
||||
bool InsertAbelHook(); // Abel
|
||||
bool InsertAdobeAirHook(); // Adobe AIR
|
||||
bool InsertAdobeFlash10Hook(); // Adobe Flash Player 10
|
||||
bool InsertAliceHook(); // System40@AliceSoft; do not work for latest alice games
|
||||
bool InsertAmuseCraftHook(); // AMUSE CRAFT: *.pac
|
||||
bool InsertAnex86Hook(); // Anex86: anex86.exe
|
||||
bool InsertAOSHook(); // AOS: *.aos
|
||||
bool InsertApricoTHook(); // Apricot: arc.a*
|
||||
bool InsertArtemisHook(); // Artemis Engine: *.pfs
|
||||
bool InsertAtelierHook(); // Atelier Kaguya: message.dat
|
||||
bool InsertBGIHook(); // BGI: BGI.*
|
||||
bool InsertC4Hook(); // C4: C4.EXE or XEX.EXE
|
||||
bool InsertCaramelBoxHook(); // Caramel: *.bin
|
||||
bool InsertCandyHook(); // SystemC@CandySoft: *.fpk
|
||||
bool InsertCatSystemHook(); // CatSystem2: *.int
|
||||
bool InsertCMVSHook(); // CMVS: data/pack/*.cpz; do not support the latest cmvs32.exe and cmvs64.exe
|
||||
bool InsertCotophaHook(); // Cotopha: *.noa
|
||||
bool InsertDebonosuHook(); // Debonosu: bmp.bak and dsetup.dll
|
||||
bool InsertEaglsHook(); // E.A.G.L.S: EAGLES.dll
|
||||
bool InsertEMEHook(); // EmonEngine: emecfg.ecf
|
||||
bool InsertEushullyHook(); // Eushully: AGERC.DLL
|
||||
bool InsertExpHook(); // EXP: http://www.exp-inc.jp
|
||||
bool InsertFocasLensHook(); // FocasLens: Dat/*.arc, http://www.fo-lens.net
|
||||
bool InsertGesen18Hook(); // Gsen18: *.szs
|
||||
bool InsertGXPHook(); // GXP: *.gxp
|
||||
bool InsertHorkEyeHook(); // HorkEye: resource string
|
||||
bool InsertKAGParserHook(); // plugin/KAGParser.dll
|
||||
bool InsertKAGParserExHook(); // plugin/KAGParserEx.dll
|
||||
bool InsertKiriKiriHook(); // KiriKiri: *.xp3, resource string
|
||||
bool InsertKiriKiriZHook(); // KiriKiri: *.xp3, resource string
|
||||
bool InsertLeafHook(); // Leaf: *.pak
|
||||
bool InsertLiveHook(); // Live: live.dll
|
||||
bool InsertLunaSoftHook(); // LunaSoft: Pac/*.pac
|
||||
bool InsertMalieHook(); // Malie@light: malie.ini
|
||||
bool InsertMajiroHook(); // Majiro: *.arc
|
||||
bool InsertMarineHeartHook(); // Marine Heart: SAISYS.exe
|
||||
bool InsertMBLHook(); // MBL: *.mbl
|
||||
bool InsertMEDHook(); // MED: *.med
|
||||
bool InsertMinkHook(); // Mink: *.at2
|
||||
//bool InsertMonoHook(); // Mono (Unity3D): */Mono/mono.dll
|
||||
bool InsertNeXASHook(); // NeXAS: Thumbnail.pac
|
||||
bool InsertNextonHook(); // NEXTON: aInfo.db
|
||||
bool InsertNexton1Hook();
|
||||
bool InsertNitroPlusHook(); // NitroPlus: *.npa
|
||||
bool InsertPensilHook(); // Pensil: PSetup.exe
|
||||
bool InsertQLIEHook(); // QLiE: GameData/*.pack
|
||||
//bool InsertRai7Hook(); // Rai7puk: rai7.exe
|
||||
bool InsertRejetHook(); // Rejet: Module/{gd.dat,pf.dat,sd.dat}
|
||||
bool InsertRUGPHook(); // rUGP: rUGP.exe
|
||||
bool InsertRetouchHook(); // Retouch: resident.dll
|
||||
bool InsertRREHook(); // RunrunEngine: rrecfg.rcf
|
||||
bool InsertShinaHook(); // ShinaRio: Rio.ini
|
||||
bool InsertShinyDaysHook(); // ShinyDays
|
||||
bool InsertElfHook(); // elf: Silky.exe
|
||||
bool InsertScenarioPlayerHook();// sol-fa-soft: *.iar && *.sec5
|
||||
bool InsertSiglusHook(); // SiglusEngine: SiglusEngine.exe
|
||||
bool InsertSideBHook(); // SideB: Copyright side-B
|
||||
bool InsertSyuntadaHook(); // Syuntada: dSoh.dat
|
||||
bool InsertSystem43Hook(); // System43@AliceSoft: AliceStart.ini
|
||||
bool InsertSystemAoiHook(); // SystemAoi: *.vfs
|
||||
bool InsertTanukiHook(); // Tanuki: *.tak
|
||||
bool InsertTaskforce2Hook(); // Taskforce2.exe
|
||||
bool InsertTencoHook(); // Tenco: Check.mdx
|
||||
bool InsertTriangleHook(); // Triangle: Execle.exe
|
||||
bool InsertYukaSystem2Hook(); // YukaSystem2: *.ykc
|
||||
bool InsertYurisHook(); // YU-RIS: *.ypf
|
||||
bool InsertWillPlusHook(); // WillPlus: Rio.arc
|
||||
bool InsertWolfHook(); // Wolf: Data.wolf
|
||||
|
||||
void InsertBrunsHook(); // Bruns: bruns.exe
|
||||
void InsertIronGameSystemHook();// IroneGameSystem: igs_sample.exe
|
||||
void InsertLucifenHook(); // Lucifen@Navel: *.lpk
|
||||
void InsertRyokuchaHook(); // Ryokucha: _checksum.exe
|
||||
void InsertRealliveHook(); // RealLive: RealLive*.exe
|
||||
void InsertStuffScriptHook(); // Stuff: *.mpk
|
||||
void InsertTinkerBellHook(); // TinkerBell: arc00.dat
|
||||
void InsertWaffleHook(); // WAFFLE: cg.pak
|
||||
|
||||
// CIRCUS: avdata/
|
||||
bool InsertCircusHook1();
|
||||
bool InsertCircusHook2();
|
||||
|
||||
} // namespace Engine
|
||||
|
||||
// EOF
|
14
vnr/ith/hook/engine/hookdefs.h
Normal file
14
vnr/ith/hook/engine/hookdefs.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
// engine/hookdefs.h
|
||||
// 7/20/2014 jichi
|
||||
|
||||
#include "config.h"
|
||||
|
||||
// For HookParam user flags
|
||||
enum HookParamFlag : unsigned long {
|
||||
HPF_Null = 0 // never used
|
||||
, HPF_IgnoreSameAddress = 1 // ignore the last same text address
|
||||
};
|
||||
|
||||
// EOF
|
831
vnr/ith/hook/engine/match.cc
Normal file
831
vnr/ith/hook/engine/match.cc
Normal file
@ -0,0 +1,831 @@
|
||||
// eng/match.cc
|
||||
// 8/9/2013 jichi
|
||||
// Branch: ITH_Engine/engine.cpp, revision 133
|
||||
|
||||
#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 "engine/match.h"
|
||||
#include "engine/engine.h"
|
||||
#include "engine/pchooks.h"
|
||||
#include "engine/util.h"
|
||||
#include "hook.h"
|
||||
#include "ith/sys/sys.h"
|
||||
#include "ith/common/except.h"
|
||||
#include "ith/common/growl.h"
|
||||
#include "ccutil/ccmacro.h"
|
||||
|
||||
//#define ConsoleOutput(...) (void)0 // jichi 8/18/2013: I don't need ConsoleOutput
|
||||
|
||||
enum { MAX_REL_ADDR = 0x200000 }; // jichi 8/18/2013: maximum relative address
|
||||
|
||||
// - Global variables -
|
||||
|
||||
namespace Engine {
|
||||
|
||||
WCHAR process_name_[MAX_PATH], // cached
|
||||
process_path_[MAX_PATH]; // cached
|
||||
|
||||
DWORD module_base_,
|
||||
module_limit_;
|
||||
|
||||
//LPVOID trigger_addr;
|
||||
trigger_fun_t trigger_fun_;
|
||||
|
||||
} // namespace Engine
|
||||
|
||||
// - Methods -
|
||||
|
||||
namespace Engine { namespace { // unnamed
|
||||
|
||||
// jichi 7/17/2014: Disable GDI hooks for PPSSPP
|
||||
bool DeterminePCEngine()
|
||||
{
|
||||
if (IthFindFile(L"PPSSPP*.exe")) { // jichi 7/12/2014 PPSSPPWindows.exe, PPSSPPEX.exe PPSSPPSP.exe
|
||||
InsertPPSSPPHooks();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IthFindFile(L"pcsx2*.exe")) { // jichi 7/19/2014 PCSX2.exe or PCSX2WX.exe
|
||||
if (!InsertPCSX2Hooks()) { // don't forget to rebuild vnrcli to inject SSE
|
||||
// Always insert PC hooks so that user could add PCSX2 to VNR.
|
||||
// TO BE REMOVED after more PS2 engines are added.
|
||||
PcHooks::hookGDIFunctions();
|
||||
PcHooks::hookLstrFunctions();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IthFindFile(L"Dolphin.exe")) { // jichi 7/20/2014
|
||||
if (!InsertGCHooks()) {
|
||||
// Always insert PC hooks so that user could add PCSX2 to VNR.
|
||||
// TO BE REMOVED after more PS2 engines are added.
|
||||
PcHooks::hookGDIFunctions();
|
||||
PcHooks::hookLstrFunctions();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//if (IthFindFile(L"*\\Mono\\mono.dll")) { // jichi 4/21/2014: Mono
|
||||
//if (IthCheckFile(L"bsz2_Data\\Mono\\mono.dll")) { // jichi 4/21/2014: Mono
|
||||
// InsertMonoHook();
|
||||
// return true;
|
||||
//}
|
||||
if (::GetModuleHandleA("mono.dll")) {
|
||||
InsertMonoHooks();
|
||||
|
||||
// 3/20/2015 jichi
|
||||
// Always insert GDI hooks even for Mono games
|
||||
// For example: 新世黙示録 need GetGlyphOutlineA
|
||||
PcHooks::hookGDIFunctions();
|
||||
return true;
|
||||
}
|
||||
|
||||
// PC games
|
||||
PcHooks::hookGDIFunctions();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DetermineEngineByFile1()
|
||||
{
|
||||
if (IthFindFile(L"*.xp3") || Util::SearchResourceString(L"TVP(KIRIKIRI)")) {
|
||||
if (Util::SearchResourceString(L"TVP(KIRIKIRI) Z ")) { // TVP(KIRIKIRI) Z CORE
|
||||
// jichi 11/24/2014: Disabled that might crash VBH
|
||||
//if (IthCheckFile(L"plugin\\KAGParser.dll"))
|
||||
// InsertKAGParserHook();
|
||||
//else if (IthCheckFile(L"plugin\\KAGParserEx.dll"))
|
||||
// InsertKAGParserExHook();
|
||||
if (InsertKiriKiriZHook())
|
||||
return true;
|
||||
}
|
||||
InsertKiriKiriHook();
|
||||
return true;
|
||||
}
|
||||
// 8/2/2014 jichi: Game name shown as 2RM - Adventure Engine
|
||||
if (Util::SearchResourceString(L"2RM") && Util::SearchResourceString(L"Adventure Engine")) {
|
||||
Insert2RMHook();
|
||||
return true;
|
||||
}
|
||||
// 8/2/2014 jichi: Copyright is side-B, a conf.dat will be generated after the game is launched
|
||||
// It also contains lua5.1.dll and lua5.dll
|
||||
if (Util::SearchResourceString(L"side-B")) {
|
||||
InsertSideBHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"bgi.*")) {
|
||||
InsertBGIHook();
|
||||
return true;
|
||||
}
|
||||
if (IthCheckFile(L"AGERC.DLL")) { // 6/1/2014 jichi: Eushully, AGE.EXE
|
||||
InsertEushullyHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"data*.arc") && IthFindFile(L"stream*.arc")) {
|
||||
InsertMajiroHook();
|
||||
return true;
|
||||
}
|
||||
// jichi 5/31/2014
|
||||
if (//IthCheckFile(L"Silkys.exe") || // It might or might not have Silkys.exe
|
||||
// data, effect, layer, mes, music
|
||||
IthCheckFile(L"data.arc") && IthCheckFile(L"effect.arc") && IthCheckFile(L"mes.arc")) {
|
||||
InsertElfHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"data\\pack\\*.cpz")) {
|
||||
InsertCMVSHook();
|
||||
return true;
|
||||
}
|
||||
// jichi 10/12/2013: Restore wolf engine
|
||||
// jichi 10/18/2013: Check for data/*.wolf
|
||||
if (IthFindFile(L"data.wolf") || IthFindFile(L"data\\*.wolf")) {
|
||||
InsertWolfHook();
|
||||
return true;
|
||||
}
|
||||
if (IthCheckFile(L"advdata\\dat\\names.dat")) {
|
||||
InsertCircusHook1();
|
||||
return true;
|
||||
}
|
||||
if (IthCheckFile(L"advdata\\grp\\names.dat")) {
|
||||
InsertCircusHook2();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"*.noa")) {
|
||||
InsertCotophaHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"*.pfs")) { // jichi 10/1/2013
|
||||
InsertArtemisHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"*.int")) {
|
||||
InsertCatSystemHook();
|
||||
return true;
|
||||
}
|
||||
if (IthCheckFile(L"message.dat")) {
|
||||
InsertAtelierHook();
|
||||
return true;
|
||||
}
|
||||
if (IthCheckFile(L"Check.mdx")) { // jichi 4/1/2014: AUGame
|
||||
InsertTencoHook();
|
||||
return true;
|
||||
}
|
||||
// jichi 12/25/2013: It may or may not be QLIE.
|
||||
// AlterEgo also has GameData/sound.pack but is not QLIE
|
||||
if (IthFindFile(L"GameData\\*.pack") && InsertQLIEHook())
|
||||
return true;
|
||||
|
||||
if (IthFindFile(L"*.pac")) {
|
||||
// jichi 6/3/2014: AMUSE CRAFT and SOFTPAL
|
||||
// Selectively insert, so that lstrlenA can still get correct text if failed
|
||||
if (IthCheckFile(L"dll\\resource.dll") && IthCheckFile(L"dll\\pal.dll") && InsertAmuseCraftHook())
|
||||
return true;
|
||||
|
||||
if (IthCheckFile(L"Thumbnail.pac")) {
|
||||
//ConsoleOutput("vnreng: IGNORE NeXAS");
|
||||
InsertNeXASHook(); // jichi 7/6/2014: GIGA
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Util::SearchResourceString(L"SOFTPAL")) {
|
||||
ConsoleOutput("vnreng: IGNORE SoftPal UNiSONSHIFT");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// jichi 12/27/2014: LunaSoft
|
||||
if (IthFindFile(L"Pac\\*.pac")) {
|
||||
InsertLunaSoftHook();
|
||||
return true;
|
||||
}
|
||||
// jichi 9/16/2013: Add Gesen18
|
||||
if (IthFindFile(L"*.szs") || IthFindFile(L"Data\\*.szs")) {
|
||||
InsertGesen18Hook();
|
||||
return true;
|
||||
}
|
||||
// jichi 12/22/2013: Add rejet
|
||||
if (IthCheckFile(L"gd.dat") && IthCheckFile(L"pf.dat") && IthCheckFile(L"sd.dat")) {
|
||||
InsertRejetHook();
|
||||
return true;
|
||||
}
|
||||
// Only examined with version 1.0
|
||||
//if (IthFindFile(L"Adobe AIR\\Versions\\*\\Adobe AIR.dll")) { // jichi 4/15/2014: FIXME: Wildcard not working
|
||||
if (IthCheckFile(L"Adobe AIR\\Versions\\1.0\\Adobe AIR.dll")) { // jichi 4/15/2014: Adobe AIR
|
||||
InsertAdobeAirHook();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DetermineEngineByFile2()
|
||||
{
|
||||
if (IthCheckFile(L"resident.dll")) {
|
||||
InsertRetouchHook();
|
||||
return true;
|
||||
}
|
||||
if (IthCheckFile(L"Malie.ini") || IthCheckFile(L"Malie.exe")) { // jichi: 9/9/2014: Add malie.exe in case malie.ini is missing
|
||||
InsertMalieHook();
|
||||
return true;
|
||||
}
|
||||
if (IthCheckFile(L"live.dll")) {
|
||||
InsertLiveHook();
|
||||
return true;
|
||||
}
|
||||
// 9/5/2013 jichi
|
||||
if (IthCheckFile(L"aInfo.db")) {
|
||||
InsertNextonHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"*.lpk")) {
|
||||
InsertLucifenHook();
|
||||
return true;
|
||||
}
|
||||
if (IthCheckFile(L"cfg.pak")) {
|
||||
InsertWaffleHook();
|
||||
return true;
|
||||
}
|
||||
if (IthCheckFile(L"Arc00.dat")) {
|
||||
InsertTinkerBellHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"*.vfs")) { // jichi 7/6/2014: Better to test AoiLib.dll? ja.wikipedia.org/wiki/ソフトハウスキャラ
|
||||
InsertSystemAoiHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"*.mbl")) {
|
||||
InsertMBLHook();
|
||||
return true;
|
||||
}
|
||||
// jichi 8/1/2014: YU-RIS engine, lots of clockup game also has this pattern
|
||||
if (IthFindFile(L"pac\\*.ypf") || IthFindFile(L"*.ypf")) {
|
||||
// jichi 8/14/2013: CLOCLUP: "ノーブレスオブリージュ" would crash the game.
|
||||
if (!IthCheckFile(L"noblesse.exe"))
|
||||
InsertYurisHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"*.npa")) {
|
||||
InsertNitroPlusHook();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DetermineEngineByFile3()
|
||||
{
|
||||
//if (IthCheckFile(L"libscr.dll")) { // already checked
|
||||
// InsertBrunsHook();
|
||||
// return true;
|
||||
//}
|
||||
|
||||
// jichi 10/12/2013: Sample args.txt:
|
||||
// See: http://tieba.baidu.com/p/2631413816
|
||||
// -workdir
|
||||
// .
|
||||
// -loadpath
|
||||
// .
|
||||
// am.cfg
|
||||
if (IthCheckFile(L"args.txt")) {
|
||||
InsertBrunsHook();
|
||||
return true;
|
||||
}
|
||||
if (IthCheckFile(L"emecfg.ecf")) {
|
||||
InsertEMEHook();
|
||||
return true;
|
||||
}
|
||||
if (IthCheckFile(L"rrecfg.rcf")) {
|
||||
InsertRREHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"*.fpk") || IthFindFile(L"data\\*.fpk")) {
|
||||
InsertCandyHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"arc.a*")) {
|
||||
InsertApricoTHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"*.mpk")) {
|
||||
InsertStuffScriptHook();
|
||||
return true;
|
||||
}
|
||||
if (IthCheckFile(L"Execle.exe")) {
|
||||
InsertTriangleHook();
|
||||
return true;
|
||||
}
|
||||
// jichi 2/28/2015: No longer work for "大正×対称アリス episode I" from Primula
|
||||
//if (IthCheckFile(L"PSetup.exe")) {
|
||||
// InsertPensilHook();
|
||||
// return true;
|
||||
//}
|
||||
if (IthCheckFile(L"Yanesdk.dll")) {
|
||||
InsertAB2TryHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"*.med")) {
|
||||
InsertMEDHook();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DetermineEngineByFile4()
|
||||
{
|
||||
if (IthCheckFile(L"EAGLS.dll")) { // jichi 3/24/2014: E.A.G.L.S
|
||||
//ConsoleOutput("vnreng: IGNORE EAGLS");
|
||||
InsertEaglsHook();
|
||||
return true;
|
||||
}
|
||||
if (IthCheckFile(L"bmp.pak") && IthCheckFile(L"dsetup.dll")) {
|
||||
InsertDebonosuHook();
|
||||
return true;
|
||||
}
|
||||
if (IthCheckFile(L"C4.EXE") || IthCheckFile(L"XEX.EXE")) {
|
||||
InsertC4Hook();
|
||||
return true;
|
||||
}
|
||||
if (IthCheckFile(L"Rio.arc") && IthFindFile(L"Chip*.arc")) {
|
||||
InsertWillPlusHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"*.tac")) {
|
||||
InsertTanukiHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"*.gxp")) {
|
||||
InsertGXPHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"*.aos")) { // jichi 4/2/2014: AOS hook
|
||||
InsertAOSHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"*.at2")) { // jichi 12/23/2014: Mink, sample files: voice.at2, voice.det, voice.nme
|
||||
InsertMinkHook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"*.ykc")) { // jichi 7/15/2014: YukaSystem1 is not supported, though
|
||||
//ConsoleOutput("vnreng: IGNORE YKC:Feng/HookSoft(SMEE)");
|
||||
InsertYukaSystem2Hook();
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"model\\*.hed")) { // jichi 9/8/2014: EXP
|
||||
InsertExpHook();
|
||||
return true;
|
||||
}
|
||||
// jichi 2/6/2015 平安亭
|
||||
// dPi.dat, dPih.dat, dSc.dat, dSch.dat, dSo.dat, dSoh.dat, dSy.dat
|
||||
//if (IthCheckFile(L"dSoh.dat")) { // no idea why this file does not work
|
||||
if (IthCheckFile(L"dSch.dat")) {
|
||||
InsertSyuntadaHook();
|
||||
return true;
|
||||
}
|
||||
|
||||
// jichi 2/28/2015: Delay checking Pensil in case something went wrong
|
||||
// File pattern observed in [Primula] 大正×対称アリス episode I
|
||||
// - PSetup.exe no longer exists
|
||||
// - MovieTexture.dll information shows MovieTex dynamic library, copyright Pensil 2013
|
||||
// - ta_trial.exe information shows 2XT - Primula Adventure Engine
|
||||
if (IthFindFile(L"PSetup.exe") || IthFindFile(L"MovieTexture.dll") || Util::SearchResourceString(L"2XT -")) {
|
||||
InsertPensilHook();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DetermineEngineByProcessName()
|
||||
{
|
||||
WCHAR str[MAX_PATH];
|
||||
wcscpy(str, process_name_);
|
||||
_wcslwr(str); // lower case
|
||||
|
||||
if (wcsstr(str,L"reallive") || IthCheckFile(L"Reallive.exe")) {
|
||||
InsertRealliveHook();
|
||||
return true;
|
||||
}
|
||||
|
||||
// jichi 8/19/2013: DO NOT WORK for games like「ハピメア」
|
||||
//if (wcsstr(str,L"cmvs32") || wcsstr(str,L"cmvs64")) {
|
||||
// InsertCMVSHook();
|
||||
// return true;
|
||||
//}
|
||||
|
||||
// jichi 8/17/2013: Handle "~"
|
||||
if (wcsstr(str, L"siglusengine") || !wcsncmp(str, L"siglus~", 7) || IthCheckFile(L"SiglusEngine.exe")) {
|
||||
InsertSiglusHook();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (wcsstr(str, L"taskforce2") || !wcsncmp(str, L"taskfo~", 7) || IthCheckFile(L"Faskforce2.exe")) {
|
||||
InsertTaskforce2Hook();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (wcsstr(str,L"rugp") || IthCheckFile(L"rugp.exe")) {
|
||||
InsertRUGPHook();
|
||||
return true;
|
||||
}
|
||||
|
||||
// jichi 8/17/2013: Handle "~"
|
||||
if (wcsstr(str, L"igs_sample") || !wcsncmp(str, L"igs_sa~", 7) || IthCheckFile(L"igs_sample.exe")) {
|
||||
InsertIronGameSystemHook();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (wcsstr(str, L"bruns") || IthCheckFile(L"bruns.exe")) {
|
||||
InsertBrunsHook();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (wcsstr(str, L"anex86") || IthCheckFile(L"anex86.exe")) {
|
||||
InsertAnex86Hook();
|
||||
return true;
|
||||
}
|
||||
|
||||
// jichi 8/17/2013: Handle "~"
|
||||
if (wcsstr(str, L"shinydays") || !wcsncmp(str, L"shinyd~", 7) || IthCheckFile(L"ShinyDays.exe")) {
|
||||
InsertShinyDaysHook();
|
||||
return true;
|
||||
}
|
||||
|
||||
// jichi 10/3/2013: FIXME: Does not work
|
||||
// Raise C0000005 even with admin priv
|
||||
//if (wcsstr(str, L"bsz")) { // BALDRSKY ZERO
|
||||
// InsertBaldrHook();
|
||||
// return true;
|
||||
//}
|
||||
|
||||
if (wcsstr(process_name_, L"SAISYS") || IthCheckFile(L"SaiSys.exe")) { // jichi 4/19/2014: Marine Heart
|
||||
InsertMarineHeartHook();
|
||||
return true;
|
||||
}
|
||||
|
||||
DWORD len = wcslen(str);
|
||||
|
||||
// jichi 8/24/2013: Checking for Rio.ini or $procname.ini
|
||||
//wcscpy(str+len-4, L"_?.war");
|
||||
//if (IthFindFile(str)) {
|
||||
// InsertShinaHook();
|
||||
// return true;
|
||||
//}
|
||||
if (InsertShinaHook())
|
||||
return true;
|
||||
|
||||
// jichi 8/10/2013: Since *.bin is common, move CaramelBox to the end
|
||||
str[len - 3] = L'b';
|
||||
str[len - 2] = L'i';
|
||||
str[len - 1] = L'n';
|
||||
str[len] = 0;
|
||||
if (IthCheckFile(str) || IthCheckFile(L"trial.bin")) { // jichi 7/8/2014: add trial.bin
|
||||
InsertCaramelBoxHook();
|
||||
return true;
|
||||
}
|
||||
|
||||
// This must appear at last since str is modified
|
||||
wcscpy(str + len - 4, L"_checksum.exe");
|
||||
if (IthCheckFile(str)) {
|
||||
InsertRyokuchaHook();
|
||||
|
||||
if (IthFindFile(L"*.iar") && IthFindFile(L"*.sec5")) // jichi 9/27/2014: For new Ryokucha games
|
||||
InsertScenarioPlayerHook();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DetermineEngineOther()
|
||||
{
|
||||
if (InsertAliceHook())
|
||||
return true;
|
||||
// jichi 1/19/2015: Disable inserting Lstr for System40
|
||||
// See: http://sakuradite.com/topic/618
|
||||
if (IthCheckFile(L"System40.ini")) {
|
||||
ConsoleOutput("vnreng: IGNORE old System40.ini");
|
||||
return true;
|
||||
}
|
||||
// jichi 12/26/2013: Add this after alicehook
|
||||
if (IthCheckFile(L"AliceStart.ini")) {
|
||||
InsertSystem43Hook();
|
||||
return true;
|
||||
}
|
||||
|
||||
// jichi 8/24/2013: Move into functions
|
||||
static BYTE static_file_info[0x1000];
|
||||
if (IthGetFileInfo(L"*01", static_file_info))
|
||||
if (*(DWORD*)static_file_info == 0) {
|
||||
static WCHAR static_search_name[MAX_PATH];
|
||||
LPWSTR name=(LPWSTR)(static_file_info+0x5E);
|
||||
int len = wcslen(name);
|
||||
name[len - 2] = L'*';
|
||||
name[len - 1] = 0;
|
||||
wcscpy(static_search_name, name);
|
||||
IthGetFileInfo(static_search_name, static_file_info);
|
||||
union {
|
||||
FILE_BOTH_DIR_INFORMATION *both_info;
|
||||
DWORD addr;
|
||||
};
|
||||
both_info = (FILE_BOTH_DIR_INFORMATION *)static_file_info;
|
||||
//BYTE* ptr=static_file_info;
|
||||
len = 0;
|
||||
while (both_info->NextEntryOffset) {
|
||||
addr += both_info->NextEntryOffset;
|
||||
len++;
|
||||
}
|
||||
if (len > 3) {
|
||||
InsertAbelHook();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// jichi 8/17/2014
|
||||
// Put the patterns that might break other games at last
|
||||
bool DetermineEngineAtLast()
|
||||
{
|
||||
if (IthFindFile(L"data\\*.cpk")) { // jichi 12/2/2014
|
||||
Insert5pbHook();
|
||||
return true;
|
||||
}
|
||||
// jichi 7/6/2014: named as ScenarioPlayer since resource string could be: scenario player program for xxx
|
||||
// Do this at last as it is common
|
||||
if (IthFindFile(L"*.iar") && IthFindFile(L"*.sec5")) { // jichi 4/18/2014: Other game engine could also have *.iar such as Ryokucha
|
||||
InsertScenarioPlayerHook();
|
||||
return true;
|
||||
}
|
||||
//if (IthCheckFile(L"arc0.dat") && IthCheckFile(L"script.dat") // jichi 11/14/2014: too common
|
||||
if (Util::SearchResourceString(L"HorkEye")) { // appear in copyright: Copyright (C) HorkEye, http://horkeye.com
|
||||
InsertHorkEyeHook();
|
||||
return true;
|
||||
}
|
||||
if (IthCheckFile(L"comnArc.arc") // jichi 8/17/2014: this file might exist in multiple files
|
||||
&& InsertNexton1Hook()) // old nexton game
|
||||
return true;
|
||||
if (IthCheckFile(L"arc.dat") // jichi 9/27/2014: too common
|
||||
&& InsertApricoTHook())
|
||||
return true;
|
||||
if (IthFindFile(L"*.pak") // jichi 12/25/2014: too common
|
||||
&& InsertLeafHook())
|
||||
return true;
|
||||
// jichi 10/31/2014
|
||||
// File description: Adobe Flash Player 10.2r153
|
||||
// Product name: Shockwave Flash
|
||||
// Original filename: SAFlashPlayer.exe
|
||||
// Legal trademarks: Adobe Flash Player
|
||||
// No idea why, this must appear at last or it will crash
|
||||
if (Util::SearchResourceString(L"Adobe Flash Player 10")) {
|
||||
InsertAdobeFlash10Hook(); // only v10 might be supported. Otherwise, fallback to Lstr hooks
|
||||
return true;
|
||||
}
|
||||
if (IthFindFile(L"dat\\*.arc")) { // jichi 2/6/2015
|
||||
InsertFocasLensHook(); // Touhou
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// jichi 6/1/2014
|
||||
bool DetermineEngineGeneric()
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (IthCheckFile(L"AlterEgo.exe")) {
|
||||
ConsoleOutput("vnreng: AlterEgo, INSERT WideChar hooks");
|
||||
ret = true;
|
||||
} else if (IthFindFile(L"data\\Sky\\*")) {
|
||||
ConsoleOutput("vnreng: TEATIME, INSERT WideChar hooks");
|
||||
ret = true;
|
||||
}
|
||||
//} else if (IthFindFile(L"image\\*.po2") || IthFindFile(L"image\\*.jo2")) {
|
||||
// ConsoleOutput("vnreng: HarukaKanata, INSERT WideChar hooks"); // はるかかなた
|
||||
// ret = true;
|
||||
//}
|
||||
if (ret)
|
||||
PcHooks::hookWcharFunctions();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DetermineNoEngine()
|
||||
{
|
||||
//if (IthFindFile(L"*\\Managed\\UnityEngine.dll")) { // jichi 12/3/2013: Unity (BALDRSKY ZERO)
|
||||
// ConsoleOutput("vnreng: IGNORE Unity");
|
||||
// return true;
|
||||
//}
|
||||
//if (IthCheckFile(L"bsz_Data\\Managed\\UnityEngine.dll") || IthCheckFile(L"bsz2_Data\\Managed\\UnityEngine.dll")) {
|
||||
// ConsoleOutput("vnreng: IGNORE Unity");
|
||||
// return true;
|
||||
//}
|
||||
|
||||
// jichi 2/14/2015: Guilty+ RIN×SEN (PK)
|
||||
if (IthCheckFile(L"rio.ini") || IthFindFile(L"*.war")) {
|
||||
ConsoleOutput("vnreng: IGNORE unknown ShinaRio");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IthCheckFile(L"AdvHD.exe") || IthCheckFile(L"AdvHD.dll")) {
|
||||
ConsoleOutput("vnreng: IGNORE Adv Player HD");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IthCheckFile(L"ScrPlayer.exe")) {
|
||||
ConsoleOutput("vnreng: IGNORE ScrPlayer");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IthCheckFile(L"nnnConfig2.exe")) {
|
||||
ConsoleOutput("vnreng: IGNORE Nya NNNConfig");
|
||||
return true;
|
||||
}
|
||||
|
||||
//if (IthCheckFile(L"AGERC.DLL")) { // jichi 3/17/2014: Eushully, AGE.EXE
|
||||
// ConsoleOutput("vnreng: IGNORE Eushully");
|
||||
// return true;
|
||||
//}
|
||||
|
||||
if (IthCheckFile(L"game_sys.exe")) {
|
||||
ConsoleOutput("vnreng: IGNORE Atelier Kaguya BY/TH");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IthFindFile(L"*.bsa")) {
|
||||
ConsoleOutput("vnreng: IGNORE Bishop");
|
||||
return true;
|
||||
}
|
||||
|
||||
// jichi 3/19/2014: Escude game
|
||||
// Example: bgm.bin gfx.bin maou.bin script.bin snd.bin voc.bin
|
||||
if (IthCheckFile(L"gfx.bin") && IthCheckFile(L"snd.bin") && IthCheckFile(L"voc.bin")) {
|
||||
ConsoleOutput("vnreng: IGNORE Escude");
|
||||
return true;
|
||||
}
|
||||
|
||||
// jichi 2/18/2015: Ignore if there is Nitro+ copyright
|
||||
if (Util::SearchResourceString(L"Nitro+")) {
|
||||
ConsoleOutput("vnreng: IGNORE unknown Nitro+");
|
||||
return true;
|
||||
}
|
||||
|
||||
// jichi 12/28/2014: "Chartreux Inc." in Copyright.
|
||||
// Sublimary brands include Rosebleu, MORE, etc.
|
||||
// GetGlyphOutlineA already works.
|
||||
if (Util::SearchResourceString(L"Chartreux")) {
|
||||
ConsoleOutput("vnreng: IGNORE Chartreux");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (wcsstr(process_name_, L"lcsebody") || !wcsncmp(process_name_, L"lcsebo~", 7) || IthCheckFile(L"lcsebody")) { // jichi 3/19/2014: LC-ScriptEngine, GetGlyphOutlineA
|
||||
ConsoleOutput("vnreng: IGNORE lcsebody");
|
||||
return true;
|
||||
}
|
||||
|
||||
wchar_t str[MAX_PATH];
|
||||
DWORD i;
|
||||
for (i = 0; process_name_[i]; i++) {
|
||||
str[i] = process_name_[i];
|
||||
if (process_name_[i] == L'.')
|
||||
break;
|
||||
}
|
||||
*(DWORD *)(str + i + 1) = 0x630068; //.hcb
|
||||
*(DWORD *)(str + i + 3) = 0x62;
|
||||
if (IthCheckFile(str)) {
|
||||
ConsoleOutput("vnreng: IGNORE FVP"); // jichi 10/3/2013: such like アトリエかぐや
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 12/13/2013: Declare it in a way compatible to EXCEPTION_PROCEDURE
|
||||
EXCEPTION_DISPOSITION ExceptHandler(PEXCEPTION_RECORD ExceptionRecord, LPVOID, PCONTEXT, LPVOID)
|
||||
{
|
||||
if (ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) {
|
||||
module_limit_ = ExceptionRecord->ExceptionInformation[1];
|
||||
//OutputDWORD(module_limit_);
|
||||
__asm
|
||||
{
|
||||
mov eax,fs:[0x30] // jichi 12/13/2013: get PEB
|
||||
mov eax,[eax+0xc]
|
||||
mov eax,[eax+0xc]
|
||||
mov ecx,module_limit_
|
||||
sub ecx,module_base_
|
||||
mov [eax+0x20],ecx
|
||||
}
|
||||
}
|
||||
//ContextRecord->Esp = recv_esp;
|
||||
//ContextRecord->Eip = recv_eip;
|
||||
//return ExceptionContinueExecution; // jichi 3/11/2014: this will still crash. Not sure why ITH use this. Change to ExceptionContinueSearch
|
||||
return ExceptionContinueSearch; // an unwind is in progress,
|
||||
}
|
||||
|
||||
// jichi 9/14/2013: Certain ITH functions like FindEntryAligned might raise exception without admin priv
|
||||
// Return if succeeded.
|
||||
bool UnsafeDetermineEngineType()
|
||||
{
|
||||
return DeterminePCEngine()
|
||||
|| DetermineEngineByFile1()
|
||||
|| DetermineEngineByFile2()
|
||||
|| DetermineEngineByFile3()
|
||||
|| DetermineEngineByFile4()
|
||||
|| DetermineEngineByProcessName()
|
||||
|| DetermineEngineOther()
|
||||
|| DetermineEngineAtLast()
|
||||
|| DetermineEngineGeneric()
|
||||
|| DetermineNoEngine()
|
||||
;
|
||||
}
|
||||
|
||||
// jichi 10/21/2014: Return whether found the game engine
|
||||
bool DetermineEngineType()
|
||||
{
|
||||
// jichi 9/27/2013: disable game engine for debugging use
|
||||
#ifdef ITH_DISABLE_ENGINE
|
||||
PcHooks::hookLstrFunctions();
|
||||
return false;
|
||||
#else
|
||||
bool found = false;
|
||||
#ifdef ITH_HAS_SEH
|
||||
__try { found = UnsafeDetermineEngineType(); }
|
||||
__except(ExceptHandler((GetExceptionInformation())->ExceptionRecord, 0, 0, 0)) {}
|
||||
#else // use my own SEH
|
||||
seh_with_eh(ExceptHandler,
|
||||
found = UnsafeDetermineEngineType());
|
||||
#endif // ITH_HAS_SEH
|
||||
if (!found) // jichi 10/2/2013: Only enable it if no game engine is detected
|
||||
PcHooks::hookLstrFunctions();
|
||||
else
|
||||
ConsoleOutput("vnreng: found game engine, IGNORE non gui hooks");
|
||||
return found;
|
||||
#endif // ITH_DISABLE_ENGINE
|
||||
}
|
||||
|
||||
// __asm
|
||||
// {
|
||||
// mov eax,seh_recover
|
||||
// mov recv_eip,eax
|
||||
// push ExceptHandler
|
||||
// push fs:[0]
|
||||
// mov fs:[0],esp
|
||||
// pushad
|
||||
// mov recv_esp,esp
|
||||
// }
|
||||
// DetermineEngineType();
|
||||
// status++;
|
||||
// __asm
|
||||
// {
|
||||
//seh_recover:
|
||||
// popad
|
||||
// mov eax,[esp]
|
||||
// mov fs:[0],eax
|
||||
// add esp,8
|
||||
// }
|
||||
// if (status == 0)
|
||||
// ConsoleOutput("Fail to identify engine type.");
|
||||
// else
|
||||
// ConsoleOutput("Initialized successfully.");
|
||||
//}
|
||||
|
||||
}} // namespace Engine unnamed
|
||||
|
||||
// - API -
|
||||
|
||||
bool Engine::IdentifyEngine()
|
||||
{
|
||||
// jichi 12/18/2013: Though FillRange could raise, it should never raise for he current process
|
||||
// So, SEH is not used here.
|
||||
FillRange(process_name_, &module_base_, &module_limit_);
|
||||
return DetermineEngineType();
|
||||
}
|
||||
|
||||
DWORD Engine::InsertDynamicHook(LPVOID addr, DWORD frame, DWORD stack)
|
||||
{ return trigger_fun_ ? !trigger_fun_(addr, frame, stack) : 0; }
|
||||
|
||||
void Engine::match(LPVOID lpThreadParameter)
|
||||
{
|
||||
CC_UNUSED(lpThreadParameter);
|
||||
Util::GetProcessName(process_name_); // Initialize process name
|
||||
Util::GetProcessPath(process_path_); // Initialize process path
|
||||
::engine_registered = true;
|
||||
//::RegisterEngineModule((DWORD)IdentifyEngine, (DWORD)InsertDynamicHook);
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
||||
/*
|
||||
extern "C" {
|
||||
// http://gmogre3d.googlecode.com/svn-history/r815/trunk/OgreMain/src/WIN32/OgreMinGWSupport.cpp
|
||||
// http://forum.osdev.org/viewtopic.php?f=8&t=22352
|
||||
//#pragma data_seg()
|
||||
//#pragma comment(linker, "/merge:.CRT=.data") // works fine in visual c++ 6
|
||||
//#pragma data_seg()
|
||||
//#pragma comment(linker, "/merge:.CRT=.rdata")
|
||||
// MSVC libs use _chkstk for stack-probing. MinGW equivalent is _alloca.
|
||||
//void _alloca();
|
||||
//void _chkstk() { _alloca(); }
|
||||
|
||||
// MSVC uses security cookies to prevent some buffer overflow attacks.
|
||||
// provide dummy implementations.
|
||||
//void _fastcall __security_check_cookie(intptr_t i) {}
|
||||
void __declspec(naked) __fastcall __security_check_cookie(UINT_PTR cookie) {}
|
||||
}
|
||||
*/
|
24
vnr/ith/hook/engine/match.h
Normal file
24
vnr/ith/hook/engine/match.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
// engine/match.h
|
||||
// 8/23/2013 jichi
|
||||
// TODO: Clean up the interface to match game engines.
|
||||
// Split the engine match logic out of hooks.
|
||||
// Modify the game hook to allow replace functions for arbitary purpose
|
||||
// instead of just extracting text.
|
||||
|
||||
#include "config.h"
|
||||
|
||||
namespace Engine {
|
||||
|
||||
void match(LPVOID lpThreadParameter);
|
||||
|
||||
// jichi 10/21/2014: Return whether found the engine
|
||||
bool IdentifyEngine();
|
||||
|
||||
// jichi 10/21/2014: Return 0 if failed
|
||||
DWORD InsertDynamicHook(LPVOID addr, DWORD frame, DWORD stack);
|
||||
|
||||
} // namespace Engine
|
||||
|
||||
// EOF
|
192
vnr/ith/hook/engine/pchooks.cc
Normal file
192
vnr/ith/hook/engine/pchooks.cc
Normal file
@ -0,0 +1,192 @@
|
||||
// pchooks.cc
|
||||
// 8/1/2014 jichi
|
||||
|
||||
#include "engine/pchooks.h"
|
||||
#include "hook.h"
|
||||
|
||||
#define DEBUG "vnrcli"
|
||||
#define DPRINT(cstr) ConsoleOutput(DEBUG ":" __FUNCTION__ ":" cstr) // defined in vnrcli
|
||||
|
||||
// 8/1/2014 jichi: Split is not used.
|
||||
// Although split is specified, USING_SPLIT is not assigned.
|
||||
|
||||
// Use LPASTE to convert to wchar_t
|
||||
// http://bytes.com/topic/c/answers/135834-defining-wide-character-strings-macros
|
||||
#define LPASTE(s) L##s
|
||||
#define L(s) LPASTE(s)
|
||||
#define NEW_HOOK(_fun, _data, _data_ind, _split_off, _split_ind, _type, _len_off) \
|
||||
{ \
|
||||
HookParam hp = {}; \
|
||||
hp.addr = (DWORD)_fun; \
|
||||
hp.off = _data; \
|
||||
hp.ind = _data_ind; \
|
||||
hp.split = _split_off; \
|
||||
hp.split_ind = _split_ind; \
|
||||
hp.type = _type; \
|
||||
hp.length_offset = _len_off; \
|
||||
NewHook(hp, L(#_fun)); \
|
||||
}
|
||||
|
||||
// jichi 7/17/2014: Renamed from InitDefaultHook
|
||||
void PcHooks::hookGDIFunctions()
|
||||
{
|
||||
DPRINT("enter");
|
||||
// int TextHook::InitHook(LPVOID addr, DWORD data, DWORD data_ind, DWORD split_off, DWORD split_ind, WORD type, DWORD len_off)
|
||||
//
|
||||
// jichi 9/8/2013: Guessed meaning
|
||||
// - data(off): 4 * the n-th (base 1) parameter representing the data of the string
|
||||
// - len_off:
|
||||
// - the n-th (base 1) parameter representing the length of the string
|
||||
// - or 1 if is char
|
||||
// - or 0 if detect on run time
|
||||
// - type: USING_STRING if len_off != 1 else BIG_ENDIAN or USING_UNICODE
|
||||
//
|
||||
// Examples:
|
||||
// int WINAPI lstrlenA(LPCSTR lpString)
|
||||
// - data: 4 * 1 = 4, as lpString is the first
|
||||
// - len_off: 0, as no parameter representing string length
|
||||
// - type: BIG_ENDIAN, since len_off == 1
|
||||
// BOOL GetTextExtentPoint32(HDC hdc, LPCTSTR lpString, int c, LPSIZE lpSize);
|
||||
// - data: 4 * 2 = 0x8, as lpString is the second
|
||||
// - len_off: 3, as nCount is the 3rd parameter
|
||||
// - type: USING_STRING, since len_off != 1
|
||||
//
|
||||
// Note: All functions does not have NO_CONTEXT attribute and will be filtered.
|
||||
|
||||
enum stack {
|
||||
s_retaddr = 0
|
||||
, s_arg1 = 4 * 1 // 0x4
|
||||
, s_arg2 = 4 * 2 // 0x8
|
||||
, s_arg3 = 4 * 3 // 0xc
|
||||
, s_arg4 = 4 * 4 // 0x10
|
||||
, s_arg5 = 4 * 5 // 0x14
|
||||
, s_arg6 = 4 * 6 // 0x18
|
||||
};
|
||||
|
||||
//#define _(Name, ...) \
|
||||
// hookman[HF_##Name].InitHook(Name, __VA_ARGS__); \
|
||||
// hookman[HF_##Name].SetHookName(names[HF_##Name]);
|
||||
|
||||
// Always use s_arg1 = hDC as split_off
|
||||
// 7/26/2014 jichi: Why there is no USING_SPLIT type?
|
||||
|
||||
// gdi32.dll
|
||||
NEW_HOOK(GetTextExtentPoint32A, s_arg2, 0,s_arg1,0, USING_STRING, 3) // BOOL GetTextExtentPoint32(HDC hdc, LPCTSTR lpString, int c, LPSIZE lpSize);
|
||||
NEW_HOOK(GetGlyphOutlineA, s_arg2, 0,s_arg1,0, BIG_ENDIAN, 1) // DWORD GetGlyphOutline(HDC hdc, UINT uChar, UINT uFormat, LPGLYPHMETRICS lpgm, DWORD cbBuffer, LPVOID lpvBuffer, const MAT2 *lpmat2);
|
||||
NEW_HOOK(ExtTextOutA, s_arg6, 0,s_arg1,0, USING_STRING, 7) // BOOL ExtTextOut(HDC hdc, int X, int Y, UINT fuOptions, const RECT *lprc, LPCTSTR lpString, UINT cbCount, const INT *lpDx);
|
||||
NEW_HOOK(TextOutA, s_arg4, 0,s_arg1,0, USING_STRING, 5) // BOOL TextOut(HDC hdc, int nXStart, int nYStart, LPCTSTR lpString, int cchString);
|
||||
NEW_HOOK(GetCharABCWidthsA, s_arg2, 0,s_arg1,0, BIG_ENDIAN, 1) // BOOL GetCharABCWidths(HDC hdc, UINT uFirstChar, UINT uLastChar, LPABC lpabc);
|
||||
NEW_HOOK(GetTextExtentPoint32W, s_arg2, 0,s_arg1,0, USING_UNICODE|USING_STRING, 3)
|
||||
NEW_HOOK(GetGlyphOutlineW, s_arg2, 0,s_arg1,0, USING_UNICODE, 1)
|
||||
NEW_HOOK(ExtTextOutW, s_arg6, 0,s_arg1,0, USING_UNICODE|USING_STRING, 7)
|
||||
NEW_HOOK(TextOutW, s_arg4, 0,s_arg1,0, USING_UNICODE|USING_STRING, 5)
|
||||
NEW_HOOK(GetCharABCWidthsW, s_arg2, 0,s_arg1,0, USING_UNICODE, 1)
|
||||
|
||||
// user32.dll
|
||||
NEW_HOOK(DrawTextA, s_arg2, 0,s_arg1,0, USING_STRING, 3) // int DrawText(HDC hDC, LPCTSTR lpchText, int nCount, LPRECT lpRect, UINT uFormat);
|
||||
NEW_HOOK(DrawTextExA, s_arg2, 0,s_arg1,0, USING_STRING, 3) // int DrawTextEx(HDC hdc, LPTSTR lpchText,int cchText, LPRECT lprc, UINT dwDTFormat, LPDRAWTEXTPARAMS lpDTParams);
|
||||
NEW_HOOK(DrawTextW, s_arg2, 0,s_arg1,0, USING_UNICODE|USING_STRING, 3)
|
||||
NEW_HOOK(DrawTextExW, s_arg2, 0,s_arg1,0, USING_UNICODE|USING_STRING, 3)
|
||||
//#undef _
|
||||
DPRINT("leave");
|
||||
}
|
||||
|
||||
// jichi 10/2/2013
|
||||
// Note: All functions does not have NO_CONTEXT attribute and will be filtered.
|
||||
void PcHooks::hookLstrFunctions()
|
||||
{
|
||||
DPRINT("enter");
|
||||
// int TextHook::InitHook(LPVOID addr, DWORD data, DWORD data_ind, DWORD split_off, DWORD split_ind, WORD type, DWORD len_off)
|
||||
|
||||
enum stack {
|
||||
s_retaddr = 0
|
||||
, s_arg1 = 4 * 1 // 0x4
|
||||
//, s_arg2 = 4 * 2 // 0x8
|
||||
//, s_arg3 = 4 * 3 // 0xc
|
||||
//, s_arg4 = 4 * 4 // 0x10
|
||||
//, s_arg5 = 4 * 5 // 0x14
|
||||
//, s_arg6 = 4 * 6 // 0x18
|
||||
};
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/78zh94ax.aspx
|
||||
// int WINAPI lstrlen(LPCTSTR lpString);
|
||||
// Lstr functions usually extracts rubbish, and might crash certain games like 「Magical Marriage Lunatics!!」
|
||||
// Needed by Gift
|
||||
// Use arg1 address for both split and data
|
||||
NEW_HOOK(lstrlenA, s_arg1, 0,s_arg1,0, USING_STRING, 0) // 9/8/2013 jichi: int WINAPI lstrlen(LPCTSTR lpString);
|
||||
NEW_HOOK(lstrlenW, s_arg1, 0,s_arg1,0, USING_UNICODE|USING_STRING, 0) // 9/8/2013 jichi: add lstrlen
|
||||
|
||||
// size_t strlen(const char *str);
|
||||
// size_t strlen_l(const char *str, _locale_t locale);
|
||||
// size_t wcslen(const wchar_t *str);
|
||||
// size_t wcslen_l(const wchar_t *str, _locale_t locale);
|
||||
// size_t _mbslen(const unsigned char *str);
|
||||
// size_t _mbslen_l(const unsigned char *str, _locale_t locale);
|
||||
// size_t _mbstrlen(const char *str);
|
||||
// size_t _mbstrlen_l(const char *str, _locale_t locale);
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/ex0hs2ad.aspx
|
||||
// Needed by 娘姉妹
|
||||
//
|
||||
// <tchar.h>
|
||||
// char *_strinc(const char *current, _locale_t locale);
|
||||
// wchar_t *_wcsinc(const wchar_t *current, _locale_t locale);
|
||||
// <mbstring.h>
|
||||
// unsigned char *_mbsinc(const unsigned char *current);
|
||||
// unsigned char *_mbsinc_l(const unsigned char *current, _locale_t locale);
|
||||
//_(L"_strinc", _strinc, 4, 0,4,0, USING_STRING, 0) // 12/13/2013 jichi
|
||||
//_(L"_wcsinc", _wcsinc, 4, 0,4,0, USING_UNICODE|USING_STRING, 0)
|
||||
DPRINT("leave");
|
||||
}
|
||||
|
||||
void PcHooks::hookWcharFunctions()
|
||||
{
|
||||
DPRINT("enter");
|
||||
// 12/1/2013 jichi:
|
||||
// AlterEgo
|
||||
// http://tieba.baidu.com/p/2736475133
|
||||
// http://www.hongfire.com/forum/showthread.php/36807-AGTH-text-extraction-tool-for-games-translation/page355
|
||||
//
|
||||
// MultiByteToWideChar
|
||||
// http://blgames.proboards.com/thread/265
|
||||
//
|
||||
// WideCharToMultiByte
|
||||
// http://www.hongfire.com/forum/showthread.php/36807-AGTH-text-extraction-tool-for-games-translation/page156
|
||||
//
|
||||
// int MultiByteToWideChar(
|
||||
// _In_ UINT CodePage,
|
||||
// _In_ DWORD dwFlags,
|
||||
// _In_ LPCSTR lpMultiByteStr, // hook here
|
||||
// _In_ int cbMultiByte,
|
||||
// _Out_opt_ LPWSTR lpWideCharStr,
|
||||
// _In_ int cchWideChar
|
||||
// );
|
||||
// int WideCharToMultiByte(
|
||||
// _In_ UINT CodePage,
|
||||
// _In_ DWORD dwFlags,
|
||||
// _In_ LPCWSTR lpWideCharStr,
|
||||
// _In_ int cchWideChar,
|
||||
// _Out_opt_ LPSTR lpMultiByteStr,
|
||||
// _In_ int cbMultiByte,
|
||||
// _In_opt_ LPCSTR lpDefaultChar,
|
||||
// _Out_opt_ LPBOOL lpUsedDefaultChar
|
||||
// );
|
||||
|
||||
enum stack {
|
||||
s_retaddr = 0
|
||||
//, s_arg1 = 4 * 1 // 0x4
|
||||
//, s_arg2 = 4 * 2 // 0x8
|
||||
, s_arg3 = 4 * 3 // 0xc
|
||||
//, s_arg4 = 4 * 4 // 0x10
|
||||
//, s_arg5 = 4 * 5 // 0x14
|
||||
//, s_arg6 = 4 * 6 // 0x18
|
||||
};
|
||||
|
||||
// 3/17/2014 jichi: Temporarily disabled
|
||||
// http://sakuradite.com/topic/159
|
||||
NEW_HOOK(MultiByteToWideChar, s_arg3, 0,4,0, USING_STRING, 4)
|
||||
NEW_HOOK(WideCharToMultiByte, s_arg3, 0,4,0, USING_UNICODE|USING_STRING, 4)
|
||||
DPRINT("leave");
|
||||
}
|
||||
|
||||
// EOF
|
16
vnr/ith/hook/engine/pchooks.h
Normal file
16
vnr/ith/hook/engine/pchooks.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
// pchooks.h
|
||||
// 8/1/2014 jichi
|
||||
|
||||
#include "config.h"
|
||||
|
||||
namespace PcHooks {
|
||||
|
||||
void hookGDIFunctions();
|
||||
void hookLstrFunctions();
|
||||
void hookWcharFunctions();
|
||||
|
||||
} // namespace PcHooks
|
||||
|
||||
// EOF
|
305
vnr/ith/hook/engine/util.cc
Normal file
305
vnr/ith/hook/engine/util.cc
Normal file
@ -0,0 +1,305 @@
|
||||
// util/util.cc
|
||||
// 8/23/2013 jichi
|
||||
// Branch: ITH_Engine/engine.cpp, revision 133
|
||||
// See: http://ja.wikipedia.org/wiki/プロジェクト:美少女ゲーム系/ゲームエンジン
|
||||
|
||||
#include "engine/util.h"
|
||||
#include "ith/sys/sys.h"
|
||||
|
||||
namespace { // unnamed
|
||||
|
||||
// jichi 4/19/2014: Return the integer that can mask the signature
|
||||
DWORD SigMask(DWORD sig)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
xor ecx,ecx
|
||||
mov eax,sig
|
||||
_mask:
|
||||
shr eax,8
|
||||
inc ecx
|
||||
test eax,eax
|
||||
jnz _mask
|
||||
sub ecx,4
|
||||
neg ecx
|
||||
or eax,-1
|
||||
shl ecx,3
|
||||
shr eax,cl
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace unnamed
|
||||
|
||||
// jichi 8/24/2013: binary search?
|
||||
DWORD Util::GetCodeRange(DWORD hModule,DWORD *low, DWORD *high)
|
||||
{
|
||||
IMAGE_DOS_HEADER *DosHdr;
|
||||
IMAGE_NT_HEADERS *NtHdr;
|
||||
DWORD dwReadAddr;
|
||||
IMAGE_SECTION_HEADER *shdr;
|
||||
DosHdr = (IMAGE_DOS_HEADER *)hModule;
|
||||
if (IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {
|
||||
dwReadAddr = hModule + DosHdr->e_lfanew;
|
||||
NtHdr = (IMAGE_NT_HEADERS *)dwReadAddr;
|
||||
if (IMAGE_NT_SIGNATURE == NtHdr->Signature) {
|
||||
shdr = (PIMAGE_SECTION_HEADER)((DWORD)(&NtHdr->OptionalHeader) + NtHdr->FileHeader.SizeOfOptionalHeader);
|
||||
while ((shdr->Characteristics & IMAGE_SCN_CNT_CODE) == 0)
|
||||
shdr++;
|
||||
*low = hModule + shdr->VirtualAddress;
|
||||
*high = *low + (shdr->Misc.VirtualSize & 0xfffff000) + 0x1000;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD Util::FindCallAndEntryBoth(DWORD fun, DWORD size, DWORD pt, DWORD sig)
|
||||
{
|
||||
//WCHAR str[0x40];
|
||||
enum { reverse_length = 0x800 };
|
||||
DWORD t, l;
|
||||
DWORD mask = SigMask(sig);
|
||||
bool flag2;
|
||||
for (DWORD i = 0x1000; i < size-4; i++) {
|
||||
bool flag1 = false;
|
||||
if (*(BYTE *)(pt + i) == 0xe8) {
|
||||
flag1 = flag2 = true;
|
||||
t = *(DWORD *)(pt + i + 1);
|
||||
} else if (*(WORD *)(pt + i) == 0x15ff) {
|
||||
flag1 = true;
|
||||
flag2 = false;
|
||||
t = *(DWORD *)(pt + i + 2);
|
||||
}
|
||||
if (flag1) {
|
||||
if (flag2) {
|
||||
flag1 = (pt + i + 5 + t == fun);
|
||||
l = 5;
|
||||
} else if (t >= pt && t <= pt + size - 4) {
|
||||
flag1 = fun == *(DWORD *)t;
|
||||
l = 6;
|
||||
} else
|
||||
flag1 = false;
|
||||
if (flag1)
|
||||
//swprintf(str,L"CALL addr: 0x%.8X",pt + i);
|
||||
//OutputConsole(str);
|
||||
for (DWORD j = i; j > i - reverse_length; j--)
|
||||
if ((*(WORD *)(pt + j)) == (sig & mask)) //Fun entry 1.
|
||||
//swprintf(str,L"Entry: 0x%.8X",pt + j);
|
||||
//OutputConsole(str);
|
||||
return pt + j;
|
||||
else
|
||||
i += l;
|
||||
}
|
||||
}
|
||||
//OutputConsole(L"Find call and entry failed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD Util::FindCallOrJmpRel(DWORD fun, DWORD size, DWORD pt, bool jmp)
|
||||
{
|
||||
BYTE sig = (jmp) ? 0xe9 : 0xe8;
|
||||
for (DWORD i = 0x1000; i < size - 4; i++)
|
||||
if (sig == *(BYTE *)(pt + i)) {
|
||||
DWORD t = *(DWORD *)(pt + i + 1);
|
||||
if(fun == pt + i + 5 + t)
|
||||
//OutputDWORD(pt + i);
|
||||
return pt + i;
|
||||
else
|
||||
i += 5;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD Util::FindCallOrJmpAbs(DWORD fun, DWORD size, DWORD pt, bool jmp)
|
||||
{
|
||||
WORD sig = jmp ? 0x25ff : 0x15ff;
|
||||
for (DWORD i = 0x1000; i < size - 4; i++)
|
||||
if (sig == *(WORD *)(pt + i)) {
|
||||
DWORD t = *(DWORD *)(pt + i + 2);
|
||||
if (t > pt && t < pt + size) {
|
||||
if (fun == *(DWORD *)t)
|
||||
return pt + i;
|
||||
else
|
||||
i += 5;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD Util::FindCallBoth(DWORD fun, DWORD size, DWORD pt)
|
||||
{
|
||||
for (DWORD i = 0x1000; i < size - 4; i++) {
|
||||
if (*(BYTE *)(pt + i) == 0xe8) {
|
||||
DWORD t = *(DWORD *)(pt + i + 1) + pt + i + 5;
|
||||
if (t == fun)
|
||||
return i;
|
||||
}
|
||||
if (*(WORD *)(pt + i) == 0x15ff) {
|
||||
DWORD t = *(DWORD *)(pt + i + 2);
|
||||
if (t >= pt && t <= pt + size - 4) {
|
||||
if (*(DWORD *)t == fun)
|
||||
return i;
|
||||
else
|
||||
i += 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD Util::FindCallAndEntryAbs(DWORD fun, DWORD size, DWORD pt, DWORD sig)
|
||||
{
|
||||
//WCHAR str[0x40];
|
||||
enum { reverse_length = 0x800 };
|
||||
DWORD mask = SigMask(sig);
|
||||
for (DWORD i = 0x1000; i < size - 4; i++)
|
||||
if (*(WORD *)(pt + i) == 0x15ff) {
|
||||
DWORD t = *(DWORD *)(pt + i + 2);
|
||||
if (t >= pt && t <= pt + size - 4) {
|
||||
if (*(DWORD *)t == fun)
|
||||
//swprintf(str,L"CALL addr: 0x%.8X",pt + i);
|
||||
//OutputConsole(str);
|
||||
for (DWORD j = i ; j > i - reverse_length; j--)
|
||||
if ((*(DWORD *)(pt + j) & mask) == sig) // Fun entry 1.
|
||||
//swprintf(str,L"Entry: 0x%.8X",pt + j);
|
||||
//OutputConsole(str);
|
||||
return pt + j;
|
||||
|
||||
} else
|
||||
i += 6;
|
||||
}
|
||||
//OutputConsole(L"Find call and entry failed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD Util::FindCallAndEntryRel(DWORD fun, DWORD size, DWORD pt, DWORD sig)
|
||||
{
|
||||
//WCHAR str[0x40];
|
||||
enum { reverse_length = 0x800 };
|
||||
if (DWORD i = FindCallOrJmpRel(fun, size, pt, false)) {
|
||||
DWORD mask = SigMask(sig);
|
||||
for (DWORD j = i; j > i - reverse_length; j--)
|
||||
if (((*(DWORD *)j) & mask) == sig) //Fun entry 1.
|
||||
//swprintf(str,L"Entry: 0x%.8X",j);
|
||||
//OutputConsole(str);
|
||||
return j;
|
||||
//OutputConsole(L"Find call and entry failed.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
DWORD Util::FindEntryAligned(DWORD start, DWORD back_range)
|
||||
{
|
||||
start &= ~0xf;
|
||||
for (DWORD i = start, j = start - back_range; i > j; i-=0x10) {
|
||||
DWORD k = *(DWORD *)(i-4);
|
||||
if (k == 0xcccccccc
|
||||
|| k == 0x90909090
|
||||
|| k == 0xccccccc3
|
||||
|| k == 0x909090c3
|
||||
)
|
||||
return i;
|
||||
DWORD t = k & 0xff0000ff;
|
||||
if (t == 0xcc0000c2 || t == 0x900000c2)
|
||||
return i;
|
||||
k >>= 8;
|
||||
if (k == 0xccccc3 || k == 0x9090c3)
|
||||
return i;
|
||||
t = k & 0xff;
|
||||
if (t == 0xc2)
|
||||
return i;
|
||||
k >>= 8;
|
||||
if (k == 0xccc3 || k == 0x90c3)
|
||||
return i;
|
||||
k >>= 8;
|
||||
if (k == 0xc3)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD Util::FindImportEntry(DWORD hModule, DWORD fun)
|
||||
{
|
||||
IMAGE_DOS_HEADER *DosHdr;
|
||||
IMAGE_NT_HEADERS *NtHdr;
|
||||
DWORD IAT, end, pt, addr;
|
||||
DosHdr = (IMAGE_DOS_HEADER *)hModule;
|
||||
if (IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {
|
||||
NtHdr = (IMAGE_NT_HEADERS *)(hModule + DosHdr->e_lfanew);
|
||||
if (IMAGE_NT_SIGNATURE == NtHdr->Signature) {
|
||||
IAT = NtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress;
|
||||
end = NtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size;
|
||||
IAT += hModule;
|
||||
end += IAT;
|
||||
for (pt = IAT; pt < end; pt += 4) {
|
||||
addr = *(DWORD *)pt;
|
||||
if (addr == fun)
|
||||
return pt;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Search string in rsrc section. This section usually contains version and copyright info.
|
||||
bool Util::SearchResourceString(LPCWSTR str)
|
||||
{
|
||||
DWORD hModule = Util::GetModuleBase();
|
||||
IMAGE_DOS_HEADER *DosHdr;
|
||||
IMAGE_NT_HEADERS *NtHdr;
|
||||
DosHdr = (IMAGE_DOS_HEADER *)hModule;
|
||||
DWORD rsrc, size;
|
||||
//__asm int 3
|
||||
if (IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {
|
||||
NtHdr = (IMAGE_NT_HEADERS *)(hModule + DosHdr->e_lfanew);
|
||||
if (IMAGE_NT_SIGNATURE == NtHdr->Signature) {
|
||||
rsrc = NtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
|
||||
if (rsrc) {
|
||||
rsrc += hModule;
|
||||
if (IthGetMemoryRange((LPVOID)rsrc, &rsrc ,&size) &&
|
||||
SearchPattern(rsrc, size - 4, str, wcslen(str) << 1))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// jichi 4/15/2014: Copied from GetModuleBase in ITH CLI, for debugging purpose
|
||||
DWORD Util::FindModuleBase(DWORD hash)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax,fs:[0x30]
|
||||
mov eax,[eax+0xc]
|
||||
mov esi,[eax+0x14]
|
||||
mov edi,_wcslwr
|
||||
listfind:
|
||||
mov edx,[esi+0x28]
|
||||
test edx,edx
|
||||
jz notfound
|
||||
push edx
|
||||
call edi
|
||||
pop edx
|
||||
xor eax,eax
|
||||
calc:
|
||||
movzx ecx, word ptr [edx]
|
||||
test cl,cl
|
||||
jz fin
|
||||
ror eax,7
|
||||
add eax,ecx
|
||||
add edx,2
|
||||
jmp calc
|
||||
fin:
|
||||
cmp eax,[hash]
|
||||
je found
|
||||
mov esi,[esi]
|
||||
jmp listfind
|
||||
notfound:
|
||||
xor eax,eax
|
||||
jmp termin
|
||||
found:
|
||||
mov eax,[esi+0x10]
|
||||
termin:
|
||||
}
|
||||
}
|
||||
|
||||
// EOF
|
76
vnr/ith/hook/engine/util.h
Normal file
76
vnr/ith/hook/engine/util.h
Normal file
@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
// util/util.h
|
||||
// 8/23/2013 jichi
|
||||
|
||||
#include "config.h"
|
||||
|
||||
namespace Util {
|
||||
|
||||
DWORD GetCodeRange(DWORD hModule,DWORD *low, DWORD *high);
|
||||
DWORD FindCallAndEntryBoth(DWORD fun, DWORD size, DWORD pt, DWORD sig);
|
||||
DWORD FindCallOrJmpRel(DWORD fun, DWORD size, DWORD pt, bool jmp);
|
||||
DWORD FindCallOrJmpAbs(DWORD fun, DWORD size, DWORD pt, bool jmp);
|
||||
DWORD FindCallBoth(DWORD fun, DWORD size, DWORD pt);
|
||||
DWORD FindCallAndEntryAbs(DWORD fun, DWORD size, DWORD pt, DWORD sig);
|
||||
DWORD FindCallAndEntryRel(DWORD fun, DWORD size, DWORD pt, DWORD sig);
|
||||
DWORD FindEntryAligned(DWORD start, DWORD back_range);
|
||||
DWORD FindImportEntry(DWORD hModule, DWORD fun);
|
||||
|
||||
// jichi 4/15/2014: Copied from ITH CLI, for debugging purpose
|
||||
DWORD FindModuleBase(DWORD hash);
|
||||
|
||||
bool SearchResourceString(LPCWSTR str);
|
||||
|
||||
/**
|
||||
* @param name process name without path deliminator
|
||||
*/
|
||||
inline void GetProcessName(wchar_t *name)
|
||||
{
|
||||
//assert(name);
|
||||
PLDR_DATA_TABLE_ENTRY it;
|
||||
__asm
|
||||
{
|
||||
mov eax,fs:[0x30]
|
||||
mov eax,[eax+0xc]
|
||||
mov eax,[eax+0xc]
|
||||
mov it,eax
|
||||
}
|
||||
::wcscpy(name, it->BaseDllName.Buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param path with process name and directy name
|
||||
*/
|
||||
inline void GetProcessPath(wchar_t *path)
|
||||
{
|
||||
//assert(path);
|
||||
PLDR_DATA_TABLE_ENTRY it;
|
||||
__asm
|
||||
{
|
||||
mov eax,fs:[0x30]
|
||||
mov eax,[eax+0xc]
|
||||
mov eax,[eax+0xc]
|
||||
mov it,eax
|
||||
}
|
||||
::wcscpy(path, it->FullDllName.Buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HANDLE module handle
|
||||
*/
|
||||
inline DWORD GetModuleBase()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax,fs:[0x18]
|
||||
mov eax,[eax+0x30]
|
||||
mov eax,[eax+0xc]
|
||||
mov eax,[eax+0xc]
|
||||
mov eax,[eax+0x18]
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Util
|
||||
|
||||
// EOF
|
887
vnr/ith/hook/hijack/texthook.cc
Normal file
887
vnr/ith/hook/hijack/texthook.cc
Normal file
@ -0,0 +1,887 @@
|
||||
// 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 "cli.h"
|
||||
#include "engine/match.h"
|
||||
#include "ith/common/except.h"
|
||||
//#include "ith/common/growl.h"
|
||||
#include "ith/sys/sys.h"
|
||||
#include "disasm/disasm.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_disabled_ = false;
|
||||
void DisableGDIHooks()
|
||||
{ ::gdi_hook_disabled_ = true; }
|
||||
|
||||
static bool IsGDIFunction(LPCVOID addr)
|
||||
{
|
||||
static LPVOID funcs[] = { HOOK_GDI_FUNCTION_LIST };
|
||||
for (size_t i = 0; i < sizeof(funcs)/sizeof(*funcs); i++)
|
||||
if (addr == funcs[i])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//FilterRange filter[8];
|
||||
|
||||
DWORD flag,
|
||||
enter_count;
|
||||
|
||||
TextHook *hookman,
|
||||
*current_available;
|
||||
|
||||
// - Unnamed helpers -
|
||||
|
||||
namespace { // unnamed
|
||||
//provide const time hook entry.
|
||||
int userhook_count;
|
||||
|
||||
#if 0 // 3/6/2015 jichi: this hook is not used and hence disabled
|
||||
const byte common_hook2[] = {
|
||||
0x89, 0x3c,0xe4, // mov [esp],edi
|
||||
0x60, // pushad
|
||||
0x9c, // pushfd
|
||||
0x8d,0x54,0x24,0x28, // lea edx,[esp+0x28] ; esp value
|
||||
0x8b,0x32, // mov esi,[edx] ; return address
|
||||
0xb9, 0,0,0,0, // mov ecx, $ ; pointer to TextHook
|
||||
0xe8, 0,0,0,0, // call @hook
|
||||
0x9d, // popfd
|
||||
0x61, // popad
|
||||
0x5f, // pop edi ; skip return address on stack
|
||||
}; //...
|
||||
#endif // 0
|
||||
|
||||
const BYTE common_hook[] = {
|
||||
0x9c, // pushfd
|
||||
0x60, // pushad
|
||||
0x9c, // pushfd
|
||||
0x8d,0x54,0x24,0x28, // lea edx,[esp+0x28] ; esp value
|
||||
0x8b,0x32, // mov esi,[edx] ; return address
|
||||
0xb9, 0,0,0,0, // mov ecx, $ ; pointer to TexHhook
|
||||
0xe8, 0,0,0,0, // call @hook
|
||||
0x9d, // popfd
|
||||
0x61, // popad
|
||||
0x9d // popfd
|
||||
};
|
||||
|
||||
/**
|
||||
* jichi 7/19/2014
|
||||
*
|
||||
* @param original_addr
|
||||
* @param new_addr
|
||||
* @param hook_len
|
||||
* @param original_len
|
||||
* @return -1 if failed, else 0 if ?, else ?
|
||||
*/
|
||||
int MapInstruction(DWORD original_addr, DWORD new_addr, BYTE &hook_len, BYTE &original_len)
|
||||
{
|
||||
int flag = 0;
|
||||
DWORD l = 0;
|
||||
const BYTE *r = (const BYTE *)original_addr; // 7/19/2014 jichi: original address is not modified
|
||||
BYTE *c = (BYTE *)new_addr; // 7/19/2014 jichi: but new address might be modified
|
||||
while((r - (BYTE *) original_addr) < 5) {
|
||||
l = ::disasm(r);
|
||||
if (l == 0) {
|
||||
ConsoleOutput("vnrcli:MapInstruction: FAILED: failed to disasm");
|
||||
return -1;
|
||||
}
|
||||
|
||||
::memcpy(c, r, l);
|
||||
if (*r >= 0x70 && *r < 0x80) {
|
||||
c[0] = 0xf;
|
||||
c[1] = *r + 0x10;
|
||||
c += 6;
|
||||
__asm
|
||||
{
|
||||
mov eax,r
|
||||
add eax,2
|
||||
movsx edx,byte ptr [eax-1]
|
||||
add edx,eax
|
||||
mov eax,c
|
||||
sub edx,eax
|
||||
mov [eax-4],edx
|
||||
}
|
||||
} else if (*r == 0xeb) {
|
||||
c[0] = 0xe9;
|
||||
c += 5;
|
||||
__asm
|
||||
{
|
||||
mov eax,r
|
||||
add eax,2
|
||||
movsx edx,[eax-1]
|
||||
add edx,eax
|
||||
mov eax,c
|
||||
sub edx,eax
|
||||
mov [eax-4],edx
|
||||
}
|
||||
if (r - (BYTE *)original_addr < 5 - l) {
|
||||
ConsoleOutput("vnrcli:MapInstruction: not safe to move instruction right after short jmp");
|
||||
return -1; // Not safe to move instruction right after short jmp.
|
||||
} else
|
||||
flag = 1;
|
||||
} else if (*r == 0xe8 || *r == 0xe9) {
|
||||
c[0]=*r;
|
||||
c += 5;
|
||||
flag = (*r == 0xe9);
|
||||
__asm
|
||||
{
|
||||
mov eax,r
|
||||
add eax,5
|
||||
mov edx,[eax-4]
|
||||
add edx,eax
|
||||
mov eax,c
|
||||
sub edx,eax
|
||||
mov [eax-4],edx
|
||||
}
|
||||
} else if (*r == 0xf && (*(r + 1) >> 4) == 0x8) {
|
||||
c += 6;
|
||||
__asm
|
||||
{
|
||||
mov eax,r
|
||||
mov edx,dword ptr [eax+2]
|
||||
add eax,6
|
||||
add eax,edx
|
||||
mov edx,c
|
||||
sub eax,edx
|
||||
mov [edx-4],eax
|
||||
}
|
||||
}
|
||||
else
|
||||
c += l;
|
||||
r += l;
|
||||
}
|
||||
original_len = r - (BYTE *)original_addr;
|
||||
hook_len = c - (BYTE *)new_addr;
|
||||
return flag;
|
||||
}
|
||||
|
||||
//copy original instruction
|
||||
//jmp back
|
||||
DWORD GetModuleBase(DWORD hash)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax,fs:[0x30]
|
||||
mov eax,[eax+0xc]
|
||||
mov esi,[eax+0x14]
|
||||
mov edi,_wcslwr
|
||||
listfind:
|
||||
mov edx,[esi+0x28]
|
||||
test edx,edx
|
||||
jz notfound
|
||||
push edx
|
||||
call edi
|
||||
pop edx
|
||||
xor eax,eax
|
||||
calc:
|
||||
movzx ecx, word ptr [edx]
|
||||
test cl,cl
|
||||
jz fin
|
||||
ror eax,7
|
||||
add eax,ecx
|
||||
add edx,2
|
||||
jmp calc
|
||||
fin:
|
||||
cmp eax,[hash]
|
||||
je found
|
||||
mov esi,[esi]
|
||||
jmp listfind
|
||||
notfound:
|
||||
xor eax,eax
|
||||
jmp termin
|
||||
found:
|
||||
mov eax,[esi+0x10]
|
||||
termin:
|
||||
}
|
||||
}
|
||||
|
||||
DWORD GetModuleBase()
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax, fs:[0x18]
|
||||
mov eax, [eax + 0x30]
|
||||
mov eax, [eax + 0xc]
|
||||
mov eax, [eax + 0xc]
|
||||
mov eax, [eax + 0x18]
|
||||
}
|
||||
}
|
||||
|
||||
//void NotifyHookInsert()
|
||||
//{
|
||||
// if (live)
|
||||
// {
|
||||
// BYTE buffer[0x10];
|
||||
// *(DWORD*)buffer=-1;
|
||||
// *(DWORD*)(buffer+4)=1;
|
||||
// IO_STATUS_BLOCK ios;
|
||||
// NtWriteFile(hPipe,0,0,0,&ios,buffer,0x10,0,0);
|
||||
// }
|
||||
//}
|
||||
|
||||
__declspec(naked) void SafeExit() // Return to eax
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov [esp+0x24], eax
|
||||
popfd
|
||||
popad
|
||||
retn
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// jichi 12/2/2013: This function mostly return 0.
|
||||
// But sometimes return the hook address from TextHook::Send
|
||||
__declspec(naked) // jichi 10/2/2013: No prolog and epilog
|
||||
int ProcessHook(DWORD dwDataBase, DWORD dwRetn, TextHook *hook) // Use SEH to ensure normal execution even bad hook inserted.
|
||||
{
|
||||
//with_seh(hook->Send(dwDataBase, dwRetn));
|
||||
seh_push_(seh_exit, 0, eax, ebx) // jichi 12/13/2013: only eax and ebx are available. ecx and edx are used.
|
||||
__asm
|
||||
{
|
||||
push esi
|
||||
push edx
|
||||
call TextHook::UnsafeSend
|
||||
test eax, eax
|
||||
jz seh_exit // label in seh_pop
|
||||
mov ecx, SafeExit
|
||||
mov [esp + 8], ecx // jichi 12/13/2013: change exit point if Send returns non-zero, not + 8 beause two elements has been pused
|
||||
}
|
||||
seh_pop_(seh_exit)
|
||||
__asm retn // jichi 12/13/2013: return near, see: http://stackoverflow.com/questions/1396909/ret-retn-retf-how-to-use-them
|
||||
}
|
||||
#endif // 0
|
||||
|
||||
#if 1
|
||||
__declspec(naked) // jichi 10/2/2013: No prolog and epilog
|
||||
int ProcessHook(DWORD dwDataBase, DWORD dwRetn, TextHook *hook) // Use SEH to ensure normal execution even bad hook inserted.
|
||||
{
|
||||
// jichi 12/17/2013: The function parameters here are meaning leass. The parameters are in esi and edi
|
||||
__asm
|
||||
{
|
||||
push esi
|
||||
push edx
|
||||
call TextHook::Send
|
||||
test eax, eax
|
||||
jz ok // label in seh_pop
|
||||
mov ecx, SafeExit
|
||||
mov [esp], ecx // jichi 12/13/2013: change exit point if Send returns non-zero
|
||||
ok:
|
||||
retn // jichi 12/13/2013: return near, see: http://stackoverflow.com/questions/1396909/ret-retn-retf-how-to-use-them
|
||||
}
|
||||
}
|
||||
#endif // 1
|
||||
|
||||
// jichi 12/13/2013: return if the retn address is within the filter dlls
|
||||
inline bool HookFilter(DWORD retn)
|
||||
{
|
||||
for (DWORD i = 0; ::filter[i].lower; i++)
|
||||
if (retn > ::filter[i].lower && retn < ::filter[i].upper)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
// - 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
|
||||
DWORD TextHook::Send(DWORD dwDataBase, DWORD dwRetn)
|
||||
{
|
||||
DWORD ret = 0;
|
||||
//char b[0x100];
|
||||
//::wcstombs(b, hook_name, 0x100);
|
||||
//ConsoleOutput(b);
|
||||
ITH_WITH_SEH(ret = UnsafeSend(dwDataBase, dwRetn));
|
||||
return ret;
|
||||
}
|
||||
|
||||
DWORD TextHook::UnsafeSend(DWORD dwDataBase, DWORD dwRetn)
|
||||
{
|
||||
enum { SMALL_BUFF_SIZE = 0x80 };
|
||||
enum { MAX_DATA_SIZE = 0x10000 }; // jichi 12/25/2013: The same as the original ITH
|
||||
DWORD dwCount,
|
||||
dwAddr,
|
||||
dwDataIn,
|
||||
dwSplit;
|
||||
BYTE *pbData,
|
||||
pbSmallBuff[SMALL_BUFF_SIZE];
|
||||
DWORD dwType = hp.type;
|
||||
if (!live)
|
||||
return 0;
|
||||
if ((dwType & NO_CONTEXT) == 0 && HookFilter(dwRetn))
|
||||
return 0;
|
||||
|
||||
// jichi 10/24/2014: Skip GDI functions
|
||||
if (::gdi_hook_disabled_ && ::IsGDIFunction((LPCVOID)hp.addr))
|
||||
return 0;
|
||||
|
||||
dwAddr = hp.addr;
|
||||
|
||||
/** jichi 12/24/2014
|
||||
* @param addr function address
|
||||
* @param frame real address of the function, supposed to be the same as addr
|
||||
* @param stack address of current stack - 4
|
||||
* @return If success, which is reverted
|
||||
*/
|
||||
if (::trigger)
|
||||
::trigger = Engine::InsertDynamicHook((LPVOID)dwAddr, *(DWORD *)(dwDataBase - 0x1c), *(DWORD *)(dwDataBase-0x18));
|
||||
// jichi 10/21/2014: Directly invoke engine functions.
|
||||
//if (trigger) {
|
||||
// if (InsertDynamicHook)
|
||||
// trigger = InsertDynamicHook((LPVOID)dwAddr, *(DWORD *)(dwDataBase - 0x1c), *(DWORD *)(dwDataBase-0x18));
|
||||
// else
|
||||
// trigger = 0;
|
||||
//}
|
||||
#if 0 // diasble HOOK_AUXILIARY
|
||||
// jichi 12/13/2013: None of known hooks are auxiliary
|
||||
if (dwType & HOOK_AUXILIARY) {
|
||||
//Clean hook when dynamic hook finished.
|
||||
//AUX hook is only used for a foothold of dynamic hook.
|
||||
if (!trigger) {
|
||||
ClearHook();
|
||||
// jichi 12/13/2013: This is the only place where this function could return non-zero value
|
||||
// However, I non of the known hooks are auxiliary
|
||||
return dwAddr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif // 0
|
||||
// jichi 10/24/2014: generic hook function
|
||||
if (hp.hook_fun && !hp.hook_fun(dwDataBase, &hp))
|
||||
hp.hook_fun = nullptr;
|
||||
|
||||
if (dwType & HOOK_EMPTY) // jichi 10/24/2014: dummy hook only for dynamic hook
|
||||
return 0;
|
||||
|
||||
// jichi 2/2/2015: Send multiple texts
|
||||
for (BYTE textIndex = 0; textIndex <= hp.extra_text_count; textIndex++) {
|
||||
dwCount = 0;
|
||||
dwSplit = 0;
|
||||
dwDataIn = *(DWORD *)(dwDataBase + hp.off); // default value
|
||||
|
||||
//if (dwType & EXTERN_HOOK) {
|
||||
if (hp.text_fun) { // jichi 10/24/2014: remove EXTERN_HOOK
|
||||
//DataFun fun=(DataFun)hp.text_fun;
|
||||
//auto fun = hp.text_fun;
|
||||
hp.text_fun(dwDataBase, &hp, textIndex, &dwDataIn, &dwSplit, &dwCount);
|
||||
//if (dwCount == 0 || dwCount > MAX_DATA_SIZE)
|
||||
// return 0;
|
||||
if (dwSplit && (dwType & RELATIVE_SPLIT) && dwSplit > ::processStartAddress)
|
||||
dwSplit -= ::processStartAddress;
|
||||
} else {
|
||||
if (dwDataIn == 0)
|
||||
return 0;
|
||||
if (dwType & FIXING_SPLIT)
|
||||
dwSplit = FIXED_SPLIT_VALUE; // fuse all threads, and prevent floating
|
||||
else if (dwType & USING_SPLIT) {
|
||||
dwSplit = *(DWORD *)(dwDataBase + hp.split);
|
||||
if (dwType & SPLIT_INDIRECT) {
|
||||
if (IthGetMemoryRange((LPVOID)(dwSplit + hp.split_ind), 0, 0))
|
||||
dwSplit = *(DWORD *)(dwSplit + hp.split_ind);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
if (dwSplit && (dwType & RELATIVE_SPLIT) && dwSplit > ::processStartAddress)
|
||||
dwSplit -= ::processStartAddress;
|
||||
}
|
||||
if (dwType & DATA_INDIRECT) {
|
||||
if (IthGetMemoryRange((LPVOID)(dwDataIn + hp.ind), 0, 0))
|
||||
dwDataIn = *(DWORD *)(dwDataIn + hp.ind);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
//if (dwType & PRINT_DWORD) {
|
||||
// swprintf((WCHAR *)(pbSmallBuff + HEADER_SIZE), L"%.8X ", dwDataIn);
|
||||
// dwDataIn = (DWORD)pbSmallBuff + HEADER_SIZE;
|
||||
//}
|
||||
dwCount = GetLength(dwDataBase, dwDataIn);
|
||||
}
|
||||
|
||||
// jichi 12/25/2013: validate data size
|
||||
if (dwCount == 0 || dwCount > MAX_DATA_SIZE)
|
||||
return 0;
|
||||
|
||||
size_t sz = dwCount + HEADER_SIZE;
|
||||
if (sz >= SMALL_BUFF_SIZE)
|
||||
pbData = new BYTE[sz];
|
||||
//ITH_MEMSET_HEAP(pbData, 0, sz * sizeof(BYTE)); // jichi 9/26/2013: zero memory
|
||||
else
|
||||
pbData = pbSmallBuff;
|
||||
|
||||
if (hp.length_offset == 1) {
|
||||
if (dwType & STRING_LAST_CHAR) {
|
||||
LPWSTR ts = (LPWSTR)dwDataIn;
|
||||
dwDataIn = ts[::wcslen(ts) -1];
|
||||
}
|
||||
dwDataIn &= 0xffff;
|
||||
if ((dwType & BIG_ENDIAN) && (dwDataIn >> 8))
|
||||
dwDataIn = _byteswap_ushort(dwDataIn & 0xffff);
|
||||
if (dwCount == 1)
|
||||
dwDataIn &= 0xff;
|
||||
*(WORD *)(pbData + HEADER_SIZE) = dwDataIn & 0xffff;
|
||||
}
|
||||
else
|
||||
::memcpy(pbData + HEADER_SIZE, (void *)dwDataIn, dwCount);
|
||||
|
||||
// jichi 10/14/2014: Add filter function
|
||||
if (hp.filter_fun && !hp.filter_fun(pbData + HEADER_SIZE, &dwCount, &hp, textIndex) || dwCount <= 0) {
|
||||
if (pbData != pbSmallBuff)
|
||||
delete[] pbData;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*(DWORD *)pbData = dwAddr;
|
||||
if (dwType & (NO_CONTEXT|FIXING_SPLIT))
|
||||
dwRetn = 0;
|
||||
else if (dwRetn && (dwType & RELATIVE_SPLIT))
|
||||
dwRetn -= ::processStartAddress;
|
||||
|
||||
*((DWORD *)pbData + 1) = dwRetn;
|
||||
*((DWORD *)pbData + 2) = dwSplit;
|
||||
if (dwCount) {
|
||||
IO_STATUS_BLOCK ios = {};
|
||||
|
||||
IthCoolDown(); // jichi 9/28/2013: cool down to prevent parallelization in wine
|
||||
//CliLockPipe();
|
||||
if (STATUS_PENDING == NtWriteFile(hPipe, 0, 0, 0, &ios, pbData, dwCount + HEADER_SIZE, 0, 0)) {
|
||||
NtWaitForSingleObject(hPipe, 0, 0);
|
||||
NtFlushBuffersFile(hPipe, &ios);
|
||||
}
|
||||
//CliUnlockPipe();
|
||||
}
|
||||
if (pbData != pbSmallBuff)
|
||||
delete[] pbData;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int TextHook::InsertHook()
|
||||
{
|
||||
//ConsoleOutput("vnrcli:InsertHook: enter");
|
||||
NtWaitForSingleObject(hmMutex, 0, 0);
|
||||
int ok = InsertHookCode();
|
||||
IthReleaseMutex(hmMutex);
|
||||
if (hp.type & HOOK_ADDITIONAL) {
|
||||
NotifyHookInsert(hp.addr);
|
||||
//ConsoleOutput(hook_name);
|
||||
//RegisterHookName(hook_name,hp.addr);
|
||||
}
|
||||
//ConsoleOutput("vnrcli:InsertHook: leave");
|
||||
return ok;
|
||||
}
|
||||
|
||||
int TextHook::InsertHookCode()
|
||||
{
|
||||
enum : int { yes = 0, no = 1 };
|
||||
DWORD ret = no;
|
||||
// jichi 9/17/2013: might raise 0xC0000005 AccessViolationException on win7
|
||||
ITH_WITH_SEH(ret = UnsafeInsertHookCode());
|
||||
//if (ret == no)
|
||||
// ITH_WARN(L"Failed to insert hook");
|
||||
return ret;
|
||||
}
|
||||
|
||||
int TextHook::UnsafeInsertHookCode()
|
||||
{
|
||||
//ConsoleOutput("vnrcli:UnsafeInsertHookCode: enter");
|
||||
enum : int { yes = 0, no = 1 };
|
||||
// MODULE_OFFSET is set, but there's no module address
|
||||
// this means that this is an absolute address found on Windows 2000/XP
|
||||
// we make the address relative to the process base
|
||||
// we also store the original address in the function field because normally there can not
|
||||
// exist a function address without a module address
|
||||
if (hp.type & MODULE_OFFSET && !hp.module) {
|
||||
DWORD base = GetModuleBase();
|
||||
hp.function = hp.addr;
|
||||
hp.addr -= 0x400000;
|
||||
hp.addr += base;
|
||||
hp.type &= ~MODULE_OFFSET;
|
||||
}
|
||||
else if (hp.module && (hp.type & MODULE_OFFSET)) { // Map hook offset to real address.
|
||||
if (DWORD base = GetModuleBase(hp.module)) {
|
||||
if (hp.function && (hp.type & FUNCTION_OFFSET)) {
|
||||
base = GetExportAddress(base, hp.function);
|
||||
if (base)
|
||||
hp.addr += base;
|
||||
else {
|
||||
current_hook--;
|
||||
ConsoleOutput("vnrcli:UnsafeInsertHookCode: FAILED: function not found in the export table");
|
||||
return no;
|
||||
}
|
||||
}
|
||||
else {
|
||||
hp.addr += base;
|
||||
}
|
||||
hp.type &= ~(MODULE_OFFSET | FUNCTION_OFFSET);
|
||||
}
|
||||
else {
|
||||
current_hook--;
|
||||
ConsoleOutput("vnrcli:UnsafeInsertHookCode: FAILED: module not present");
|
||||
return no;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
TextHook *it = hookman;
|
||||
for (int i = 0; (i < current_hook) && it; it++) { // Check if there is a collision.
|
||||
if (it->Address())
|
||||
i++;
|
||||
//it = hookman + i;
|
||||
if (it == this)
|
||||
continue;
|
||||
if (it->Address() <= hp.addr &&
|
||||
it->Address() + it->Length() > hp.addr) {
|
||||
it->ClearHook();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify hp.addr.
|
||||
MEMORY_BASIC_INFORMATION info = {};
|
||||
NtQueryVirtualMemory(NtCurrentProcess(), (LPVOID)hp.addr, MemoryBasicInformation, &info, sizeof(info), nullptr);
|
||||
if (info.Type & PAGE_NOACCESS) {
|
||||
ConsoleOutput("vnrcli:UnsafeInsertHookCode: FAILED: page no access");
|
||||
return no;
|
||||
}
|
||||
|
||||
// Initialize common routine.
|
||||
memcpy(recover, common_hook, sizeof(common_hook));
|
||||
BYTE *c = (BYTE *)hp.addr,
|
||||
*r = recover;
|
||||
BYTE inst[8]; // jichi 9/27/2013: Why 8? Only 5 bytes will be written using NtWriteVirtualMemory
|
||||
inst[0] = 0xe9; // jichi 9/27/2013: 0xe9 is jump, see: http://code.google.com/p/sexyhook/wiki/SEXYHOOK_Hackers_Manual
|
||||
__asm
|
||||
{
|
||||
mov edx,r // r = recover
|
||||
mov eax,this
|
||||
mov [edx+0xa],eax // push TextHook*, resolve to correspond hook.
|
||||
lea eax,[edx+0x13]
|
||||
mov edx,ProcessHook
|
||||
sub edx,eax
|
||||
mov [eax-4],edx // call ProcessHook
|
||||
mov eax,c
|
||||
add eax,5
|
||||
mov edx,r
|
||||
sub edx,eax
|
||||
lea eax,inst+1
|
||||
mov [eax],edx // jichi 12/17/2013: the parameter of jmp is in edx. So, ProcessHook must be naked.
|
||||
}
|
||||
r += sizeof(common_hook);
|
||||
hp.hook_len = 5;
|
||||
//bool jmpflag=false; // jichi 9/28/2013: nto used
|
||||
// Copy original code.
|
||||
switch (MapInstruction(hp.addr, (DWORD)r, hp.hook_len, hp.recover_len)) {
|
||||
case -1:
|
||||
ConsoleOutput("vnrcli:UnsafeInsertHookCode: FAILED: failed to map instruction");
|
||||
return no;
|
||||
case 0:
|
||||
__asm
|
||||
{
|
||||
mov ecx,this
|
||||
movzx eax,[ecx]hp.hook_len
|
||||
movzx edx,[ecx]hp.recover_len
|
||||
add edx,[ecx]hp.addr
|
||||
add eax,r
|
||||
add eax,5
|
||||
sub edx,eax
|
||||
mov [eax-5],0xe9 // jichi 9/27/2013: 0xe9 is jump
|
||||
mov [eax-4],edx
|
||||
}
|
||||
}
|
||||
// jichi 9/27/2013: Save the original instructions in the memory
|
||||
memcpy(original, (LPVOID)hp.addr, hp.recover_len);
|
||||
//Check if the new hook range conflict with existing ones. Clear older if conflict.
|
||||
{
|
||||
TextHook *it = hookman;
|
||||
for (int i = 0; i < current_hook; it++) {
|
||||
if (it->Address())
|
||||
i++;
|
||||
if (it == this)
|
||||
continue;
|
||||
if (it->Address() >= hp.addr &&
|
||||
it->Address() < hp.hook_len + hp.addr) {
|
||||
it->ClearHook();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Insert hook and flush instruction cache.
|
||||
enum {c8 = 0xcccccccc};
|
||||
DWORD int3[] = {c8, c8};
|
||||
DWORD t = 0x100,
|
||||
old,
|
||||
len;
|
||||
// jichi 9/27/2013: Overwrite the memory with inst
|
||||
// See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Memory%20Management/Virtual%20Memory/NtProtectVirtualMemory.html
|
||||
// See: http://doxygen.reactos.org/d8/d6b/ndk_2mmfuncs_8h_af942709e0c57981d84586e74621912cd.html
|
||||
DWORD addr = hp.addr;
|
||||
NtProtectVirtualMemory(NtCurrentProcess(), (PVOID *)&addr, &t, PAGE_EXECUTE_READWRITE, &old);
|
||||
NtWriteVirtualMemory(NtCurrentProcess(), (BYTE *)hp.addr, inst, 5, &t);
|
||||
len = hp.recover_len - 5;
|
||||
if (len)
|
||||
NtWriteVirtualMemory(NtCurrentProcess(), (BYTE *)hp.addr + 5, int3, len, &t);
|
||||
NtFlushInstructionCache(NtCurrentProcess(), (LPVOID)hp.addr, hp.recover_len);
|
||||
NtFlushInstructionCache(NtCurrentProcess(), (LPVOID)::hookman, 0x1000);
|
||||
//ConsoleOutput("vnrcli:UnsafeInsertHookCode: leave: succeed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TextHook::InitHook(LPVOID addr, DWORD data, DWORD data_ind,
|
||||
DWORD split_off, DWORD split_ind, WORD type, DWORD len_off)
|
||||
{
|
||||
NtWaitForSingleObject(hmMutex, 0, 0);
|
||||
hp.addr = (DWORD)addr;
|
||||
hp.off = data;
|
||||
hp.ind = data_ind;
|
||||
hp.split = split_off;
|
||||
hp.split_ind = split_ind;
|
||||
hp.type = type;
|
||||
hp.hook_len = 0;
|
||||
hp.module = 0;
|
||||
hp.length_offset = len_off & 0xffff;
|
||||
current_hook++;
|
||||
if (current_available >= this)
|
||||
for (current_available = this + 1; current_available->Address(); current_available++);
|
||||
IthReleaseMutex(hmMutex);
|
||||
return this - hookman;
|
||||
}
|
||||
|
||||
int TextHook::InitHook(const HookParam &h, LPCWSTR name, WORD set_flag)
|
||||
{
|
||||
NtWaitForSingleObject(hmMutex, 0, 0);
|
||||
hp = h;
|
||||
hp.type |= set_flag;
|
||||
if (name && name != hook_name) {
|
||||
SetHookName(name);
|
||||
}
|
||||
current_hook++;
|
||||
current_available = this+1;
|
||||
while (current_available->Address())
|
||||
current_available++;
|
||||
IthReleaseMutex(hmMutex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int TextHook::RemoveHook()
|
||||
{
|
||||
enum : int { yes = 1, no = 0 };
|
||||
if (!hp.addr)
|
||||
return no;
|
||||
ConsoleOutput("vnrcli:RemoveHook: enter");
|
||||
const LONGLONG timeout = -50000000; // jichi 9/28/2012: in 100ns, wait at most for 5 seconds
|
||||
NtWaitForSingleObject(hmMutex, 0, (PLARGE_INTEGER)&timeout);
|
||||
DWORD l = hp.hook_len;
|
||||
//with_seh({ // jichi 9/17/2013: might crash ><
|
||||
// jichi 12/25/2013: Actually, __try cannot catch such kind of exception
|
||||
ITH_TRY {
|
||||
NtWriteVirtualMemory(NtCurrentProcess(), (LPVOID)hp.addr, original, hp.recover_len, &l);
|
||||
NtFlushInstructionCache(NtCurrentProcess(), (LPVOID)hp.addr, hp.recover_len);
|
||||
} ITH_EXCEPT {}
|
||||
//});
|
||||
hp.hook_len = 0;
|
||||
IthReleaseMutex(hmMutex);
|
||||
ConsoleOutput("vnrcli:RemoveHook: leave");
|
||||
return yes;
|
||||
}
|
||||
|
||||
int TextHook::ClearHook()
|
||||
{
|
||||
NtWaitForSingleObject(hmMutex, 0, 0);
|
||||
int err = RemoveHook();
|
||||
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;
|
||||
current_hook--;
|
||||
IthReleaseMutex(hmMutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
int TextHook::ModifyHook(const HookParam &hp)
|
||||
{
|
||||
//WCHAR name[0x40];
|
||||
DWORD len = 0;
|
||||
if (hook_name)
|
||||
len = wcslen(hook_name);
|
||||
LPWSTR name = 0;
|
||||
if (len) {
|
||||
name = new wchar_t[len + 1];
|
||||
//ITH_MEMSET_HEAP(name, 0, sizeof(wchar_t) * (len + 1)); // jichi 9/26/2013: zero memory
|
||||
name[len] = 0;
|
||||
wcscpy(name, hook_name);
|
||||
}
|
||||
ClearHook();
|
||||
InitHook(hp,name);
|
||||
InsertHook();
|
||||
if (name)
|
||||
delete[] name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TextHook::RecoverHook()
|
||||
{
|
||||
if (hp.addr) {
|
||||
// jichi 9/28/2013: Only enable TextOutA to debug Cross Channel
|
||||
//if (hp.addr == (DWORD)TextOutA)
|
||||
InsertHook();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TextHook::SetHookName(LPCWSTR name)
|
||||
{
|
||||
name_length = wcslen(name) + 1;
|
||||
if (hook_name)
|
||||
delete[] hook_name;
|
||||
hook_name = new wchar_t[name_length];
|
||||
//ITH_MEMSET_HEAP(hook_name, 0, sizeof(wchar_t) * name_length); // jichi 9/26/2013: zero memory
|
||||
hook_name[name_length - 1] = 0;
|
||||
wcscpy(hook_name, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TextHook::GetLength(DWORD base, DWORD in)
|
||||
{
|
||||
if (base == 0)
|
||||
return 0;
|
||||
int len;
|
||||
switch (hp.length_offset) {
|
||||
default: // jichi 12/26/2013: I should not put this default branch to the end
|
||||
len = *((int *)base + hp.length_offset);
|
||||
if (len >= 0) {
|
||||
if (hp.type & USING_UNICODE)
|
||||
len <<= 1;
|
||||
break;
|
||||
}
|
||||
else if (len != -1)
|
||||
break;
|
||||
//len == -1 then continue to case 0.
|
||||
case 0:
|
||||
if (hp.type & USING_UNICODE)
|
||||
len = wcslen((const wchar_t *)in) << 1;
|
||||
else
|
||||
len = strlen((const char *)in);
|
||||
break;
|
||||
case 1:
|
||||
if (hp.type & USING_UNICODE)
|
||||
len = 2;
|
||||
else {
|
||||
if (hp.type & BIG_ENDIAN)
|
||||
in >>= 8;
|
||||
len = LeadByteTable[in & 0xff]; //Slightly faster than IsDBCSLeadByte
|
||||
}
|
||||
break;
|
||||
}
|
||||
// jichi 12/25/2013: This function originally return -1 if failed
|
||||
//return len;
|
||||
return max(0, len);
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
||||
//typedef void (*DataFun)(DWORD, const HookParam*, DWORD*, DWORD*, DWORD*);
|
||||
|
||||
/*
|
||||
DWORD recv_esp, recv_addr;
|
||||
EXCEPTION_DISPOSITION ExceptHandler(EXCEPTION_RECORD *ExceptionRecord,
|
||||
void *EstablisherFrame, CONTEXT *ContextRecord, void *DispatcherContext)
|
||||
{
|
||||
//WCHAR str[0x40],
|
||||
// name[0x100];
|
||||
//ConsoleOutput(L"Exception raised during hook processing.");
|
||||
//swprintf(str, L"Exception code: 0x%.8X", ExceptionRecord->ExceptionCode);
|
||||
//ConsoleOutput(str);
|
||||
//MEMORY_BASIC_INFORMATION info;
|
||||
//if (NT_SUCCESS(NtQueryVirtualMemory(NtCurrentProcess(),(PVOID)ContextRecord->Eip,
|
||||
// MemoryBasicInformation,&info,sizeof(info),0)) &&
|
||||
// NT_SUCCESS(NtQueryVirtualMemory(NtCurrentProcess(),(PVOID)ContextRecord->Eip,
|
||||
// MemorySectionName,name,0x200,0))) {
|
||||
// swprintf(str, L"Exception offset: 0x%.8X:%s",
|
||||
// ContextRecord->Eip-(DWORD)info.AllocationBase,
|
||||
// wcsrchr(name,L'\\')+1);
|
||||
// ConsoleOutput(str);
|
||||
//}
|
||||
ContextRecord->Esp = recv_esp;
|
||||
ContextRecord->Eip = recv_addr;
|
||||
return ExceptionContinueExecution;
|
||||
}
|
||||
|
||||
|
||||
//typedef void (*DataFun)(DWORD, const HookParam*, DWORD*, DWORD*, DWORD*);
|
||||
|
||||
DWORD recv_esp, recv_addr;
|
||||
EXCEPTION_DISPOSITION ExceptHandler(EXCEPTION_RECORD *ExceptionRecord,
|
||||
void *EstablisherFrame, CONTEXT *ContextRecord, void *DispatcherContext)
|
||||
{
|
||||
//WCHAR str[0x40],
|
||||
// name[0x100];
|
||||
//ConsoleOutput(L"Exception raised during hook processing.");
|
||||
//swprintf(str, L"Exception code: 0x%.8X", ExceptionRecord->ExceptionCode);
|
||||
//ConsoleOutput(str);
|
||||
//MEMORY_BASIC_INFORMATION info;
|
||||
//if (NT_SUCCESS(NtQueryVirtualMemory(NtCurrentProcess(),(PVOID)ContextRecord->Eip,
|
||||
// MemoryBasicInformation,&info,sizeof(info),0)) &&
|
||||
// NT_SUCCESS(NtQueryVirtualMemory(NtCurrentProcess(),(PVOID)ContextRecord->Eip,
|
||||
// MemorySectionName,name,0x200,0))) {
|
||||
// swprintf(str, L"Exception offset: 0x%.8X:%s",
|
||||
// ContextRecord->Eip-(DWORD)info.AllocationBase,
|
||||
// wcsrchr(name,L'\\')+1);
|
||||
// ConsoleOutput(str);
|
||||
//}
|
||||
ContextRecord->Esp = recv_esp;
|
||||
ContextRecord->Eip = recv_addr;
|
||||
return ExceptionContinueExecution;
|
||||
}
|
||||
|
||||
__declspec(naked) // jichi 10/2/2013: No prolog and epilog
|
||||
int ProcessHook(DWORD dwDataBase, DWORD dwRetn, TextHook *hook) // Use SEH to ensure normal execution even bad hook inserted.
|
||||
{
|
||||
__asm
|
||||
{
|
||||
mov eax,seh_recover
|
||||
mov recv_addr,eax
|
||||
push ExceptHandler
|
||||
push fs:[0]
|
||||
mov recv_esp,esp
|
||||
mov fs:[0],esp
|
||||
push esi
|
||||
push edx
|
||||
call TextHook::Send
|
||||
test eax,eax
|
||||
jz seh_recover
|
||||
mov ecx,SafeExit
|
||||
mov [esp + 0x8], ecx // change exit point
|
||||
seh_recover:
|
||||
pop dword ptr fs:[0]
|
||||
pop ecx
|
||||
retn
|
||||
}
|
||||
}
|
||||
*/
|
Loading…
x
Reference in New Issue
Block a user