Showing
21 changed files
with
3126 additions
and
0 deletions
vnr/ith/common/defs.h
0 → 100644
1 | +#pragma once | ||
2 | + | ||
3 | +// ith/common/defs.h | ||
4 | +// 8/23/2013 jichi | ||
5 | + | ||
6 | +// DLL files | ||
7 | + | ||
8 | +//#define ITH_SERVER_DLL L"vnrsrv.dll" | ||
9 | +//#define ITH_CLIENT_DLL L"vnrcli.dll" | ||
10 | +//#define ITH_CLIENT_XP_DLL L"vnrclixp.dll" | ||
11 | +////#define ITH_CLIENT_UX_DLL L"vnrcliux.dll" | ||
12 | +//#define ITH_ENGINE_DLL L"vnreng.dll" | ||
13 | +//#define ITH_ENGINE_XP_DLL L"vnrengxp.dll" | ||
14 | +//#define ITH_ENGINE_UX_DLL L"vnrengux.dll" | ||
15 | + | ||
16 | +#define ITH_DLL L"vnrhook.dll" | ||
17 | +#define ITH_DLL_XP L"vnrhookxp.dll" | ||
18 | + | ||
19 | +// Pipes | ||
20 | + | ||
21 | +#define ITH_TEXT_PIPE L"\\??\\pipe\\VNR_TEXT" | ||
22 | +#define ITH_COMMAND_PIPE L"\\??\\pipe\\VNR_COMMAND" | ||
23 | + | ||
24 | +// Sections | ||
25 | + | ||
26 | +#define ITH_SECTION_ L"VNR_SECTION_" // _%d | ||
27 | + | ||
28 | +// Mutex | ||
29 | + | ||
30 | +#define ITH_PROCESS_MUTEX_ L"VNR_PROCESS_" // ITH_%d | ||
31 | +#define ITH_HOOKMAN_MUTEX_ L"VNR_HOOKMAN_" // ITH_HOOKMAN_%d | ||
32 | +#define ITH_DETACH_MUTEX_ L"VNR_DETACH_" // ITH_DETACH_%d | ||
33 | + | ||
34 | +#define ITH_GRANTPIPE_MUTEX L"VNR_GRANT_PIPE" // ITH_GRANT_PIPE | ||
35 | + | ||
36 | +//#define ITH_ENGINE_MUTEX L"VNR_ENGINE" // ITH_ENGINE | ||
37 | +#define ITH_CLIENT_MUTEX L"VNR_CLIENT" // ITH_DLL_RUNNING | ||
38 | +#define ITH_SERVER_MUTEX L"VNR_SERVER" // ITH_RUNNING | ||
39 | +#define ITH_SERVER_HOOK_MUTEX L"VNR_SERVER_HOOK" // original | ||
40 | + | ||
41 | +// Events | ||
42 | + | ||
43 | +#define ITH_REMOVEHOOK_EVENT L"VNR_REMOVE_HOOK" // ITH_REMOVE_HOOK | ||
44 | +#define ITH_MODIFYHOOK_EVENT L"VNR_MODIFY_HOOK" // ITH_MODIFY_HOOK | ||
45 | +#define ITH_PIPEEXISTS_EVENT L"VNR_PIPE_EXISTS" // ITH_PIPE_EXIST | ||
46 | + | ||
47 | +// EOF |
vnr/ith/common/except.h
0 → 100644
1 | +#pragma once | ||
2 | + | ||
3 | +// ith/common/except.h | ||
4 | +// 9/17/2013 jichi | ||
5 | + | ||
6 | +#define ITH_RAISE (*(int*)0 = 0) // raise C000005, for debugging only | ||
7 | + | ||
8 | +#ifdef ITH_HAS_SEH | ||
9 | + | ||
10 | +# define ITH_TRY __try | ||
11 | +# define ITH_EXCEPT __except(EXCEPTION_EXECUTE_HANDLER) | ||
12 | +# define ITH_WITH_SEH(...) \ | ||
13 | + ITH_TRY { __VA_ARGS__; } ITH_EXCEPT {} | ||
14 | + | ||
15 | +#else // for old msvcrt.dll on Windows XP that does not have exception handler | ||
16 | + | ||
17 | +// Currently, only with_seh is implemented. Try and catch are not. | ||
18 | +# define ITH_TRY if (true) | ||
19 | +# define ITH_EXCEPT else | ||
20 | +# include "winseh/winseh.h" | ||
21 | +# define ITH_WITH_SEH(...) seh_with(__VA_ARGS__) | ||
22 | + | ||
23 | +#endif // ITH_HAS_SEH | ||
24 | + | ||
25 | +// EOF |
vnr/ith/common/growl.h
0 → 100644
1 | +#pragma once | ||
2 | + | ||
3 | +// ith/common/growl.h | ||
4 | +// 9/17/2013 jichi | ||
5 | + | ||
6 | +//#ifdef ITH_HAS_GROWL | ||
7 | + | ||
8 | +#include <windows.h> | ||
9 | +#include "ith/common/string.h" | ||
10 | + | ||
11 | +#define ITH_MSG_A(_msg) MessageBoxA(nullptr, _msg, "VNR Message", MB_OK) | ||
12 | +#define ITH_MSG(_msg) MessageBoxW(nullptr, _msg, L"VNR Message", MB_OK) | ||
13 | +#define ITH_WARN(_msg) MessageBoxW(nullptr, _msg, L"VNR Warning", MB_OK) | ||
14 | +#define ITH_ERROR(_msg) MessageBoxW(nullptr, _msg, L"VNR Error", MB_OK) | ||
15 | + | ||
16 | +inline void ITH_GROWL_DWORD(DWORD value) | ||
17 | +{ | ||
18 | + WCHAR buf[100]; | ||
19 | + swprintf(buf, L"DWORD: %x", value); | ||
20 | + ITH_MSG(buf); | ||
21 | +} | ||
22 | + | ||
23 | +inline void ITH_GROWL_DWORD2(DWORD v, DWORD v2) | ||
24 | +{ | ||
25 | + WCHAR buf[100]; | ||
26 | + swprintf(buf, L"DWORD2: %x,%x", v, v2); | ||
27 | + ITH_MSG(buf); | ||
28 | +} | ||
29 | + | ||
30 | +inline void ITH_GROWL_DWORD3(DWORD v, DWORD v2, DWORD v3) | ||
31 | +{ | ||
32 | + WCHAR buf[100]; | ||
33 | + swprintf(buf, L"DWORD3: %x,%x,%x", v, v2, v3); | ||
34 | + ITH_MSG(buf); | ||
35 | +} | ||
36 | + | ||
37 | +inline void ITH_GROWL_DWORD4(DWORD v, DWORD v2, DWORD v3, DWORD v4) | ||
38 | +{ | ||
39 | + WCHAR buf[100]; | ||
40 | + swprintf(buf, L"DWORD4: %x,%x,%x,%x", v, v2, v3, v4); | ||
41 | + ITH_MSG(buf); | ||
42 | +} | ||
43 | + | ||
44 | +inline void ITH_GROWL_DWORD5(DWORD v, DWORD v2, DWORD v3, DWORD v4, DWORD v5) | ||
45 | +{ | ||
46 | + WCHAR buf[100]; | ||
47 | + swprintf(buf, L"DWORD5: %x,%x,%x,%x,%x", v, v2, v3, v4, v5); | ||
48 | + ITH_MSG(buf); | ||
49 | +} | ||
50 | + | ||
51 | +inline void ITH_GROWL_DWORD6(DWORD v, DWORD v2, DWORD v3, DWORD v4, DWORD v5, DWORD v6) | ||
52 | +{ | ||
53 | + WCHAR buf[100]; | ||
54 | + swprintf(buf, L"DWORD6: %x,%x,%x,%x,%x,%x", v, v2, v3, v4, v5, v6); | ||
55 | + ITH_MSG(buf); | ||
56 | +} | ||
57 | + | ||
58 | +inline void ITH_GROWL_DWORD7(DWORD v, DWORD v2, DWORD v3, DWORD v4, DWORD v5, DWORD v6, DWORD v7) | ||
59 | +{ | ||
60 | + WCHAR buf[100]; | ||
61 | + swprintf(buf, L"DWORD7: %x,%x,%x,%x,%x,%x,%x", v, v2, v3, v4, v5, v6, v7); | ||
62 | + ITH_MSG(buf); | ||
63 | +} | ||
64 | + | ||
65 | +inline void ITH_GROWL_DWORD8(DWORD v, DWORD v2, DWORD v3, DWORD v4, DWORD v5, DWORD v6, DWORD v7, DWORD v8) | ||
66 | +{ | ||
67 | + WCHAR buf[100]; | ||
68 | + swprintf(buf, L"DWORD8: %x,%x,%x,%x,%x,%x,%x,%x", v, v2, v3, v4, v5, v6, v7, v8); | ||
69 | + ITH_MSG(buf); | ||
70 | +} | ||
71 | + | ||
72 | +inline void ITH_GROWL_DWORD9(DWORD v, DWORD v2, DWORD v3, DWORD v4, DWORD v5, DWORD v6, DWORD v7, DWORD v8, DWORD v9) | ||
73 | +{ | ||
74 | + WCHAR buf[100]; | ||
75 | + swprintf(buf, L"DWORD9: %x,%x,%x,%x,%x,%x,%x,%x,%x", v, v2, v3, v4, v5, v6, v7, v8, v9); | ||
76 | + ITH_MSG(buf); | ||
77 | +} | ||
78 | + | ||
79 | +inline void ITH_GROWL(DWORD v) { ITH_GROWL_DWORD(v); } | ||
80 | +inline void ITH_GROWL(LPCWSTR v) { ITH_MSG(v); } | ||
81 | +inline void ITH_GROWL(LPCSTR v) { ITH_MSG_A(v); } | ||
82 | + | ||
83 | +//#endif // ITH_HAS_GROWL | ||
84 | + | ||
85 | +// EOF |
vnr/ith/common/memory.h
0 → 100644
1 | +#pragma once | ||
2 | + | ||
3 | +// ith/common/memory.h | ||
4 | +// 8/23/2013 jichi | ||
5 | +// Branch: ITH/mem.h, revision 66 | ||
6 | + | ||
7 | +#ifndef ITH_HAS_HEAP | ||
8 | +# define ITH_MEMSET_HEAP(...) ::memset(__VA_ARGS__) | ||
9 | +#else | ||
10 | +# define ITH_MEMSET_HEAP(...) (void)0 | ||
11 | + | ||
12 | +// Defined in kernel32.lilb | ||
13 | +extern "C" { | ||
14 | +// PVOID RtlAllocateHeap( _In_ PVOID HeapHandle, _In_opt_ ULONG Flags, _In_ SIZE_T Size); | ||
15 | +__declspec(dllimport) void * __stdcall RtlAllocateHeap(void *HeapHandle, unsigned long Flags, unsigned long Size); | ||
16 | + | ||
17 | +// BOOLEAN RtlFreeHeap( _In_ PVOID HeapHandle, _In_opt_ ULONG Flags, _In_ PVOID HeapBase); | ||
18 | +__declspec(dllimport) int __stdcall RtlFreeHeap(void *HeapHandle, unsigned long Flags, void *HeapBase); | ||
19 | +} // extern "C" | ||
20 | + | ||
21 | +//NTSYSAPI | ||
22 | +//BOOL | ||
23 | +//NTAPI | ||
24 | +//RtlFreeHeap( | ||
25 | +// _In_ HANDLE hHeap, | ||
26 | +// _In_ DWORD dwFlags, | ||
27 | +// _In_ LPVOID lpMem | ||
28 | +//); | ||
29 | + | ||
30 | +extern void *hHeap; // defined in ith/sys.cc | ||
31 | + | ||
32 | +inline void * __cdecl operator new(size_t lSize) | ||
33 | +{ | ||
34 | + // http://msdn.microsoft.com/en-us/library/windows/desktop/aa366597%28v=vs.85%29.aspx | ||
35 | + // HEAP_ZERO_MEMORY flag is critical. All new objects are assumed with zero initialized. | ||
36 | + enum { HEAP_ZERO_MEMORY = 0x00000008 }; | ||
37 | + return RtlAllocateHeap(::hHeap, HEAP_ZERO_MEMORY, lSize); | ||
38 | +} | ||
39 | + | ||
40 | +inline void __cdecl operator delete(void *pBlock) | ||
41 | +{ RtlFreeHeap(::hHeap, 0, pBlock); } | ||
42 | + | ||
43 | +inline void __cdecl operator delete[](void *pBlock) | ||
44 | +{ RtlFreeHeap(::hHeap, 0, pBlock); } | ||
45 | + | ||
46 | +#endif // ITH_HAS_HEAP |
vnr/ith/common/string.h
0 → 100644
1 | +#pragma once | ||
2 | + | ||
3 | +// ith/common/string.h | ||
4 | +// 8/9/2013 jichi | ||
5 | +// Branch: ITH/string.h, rev 66 | ||
6 | + | ||
7 | +#ifdef ITH_HAS_CRT // ITH is linked with msvcrt dlls | ||
8 | +# include <cstdio> | ||
9 | +# include <cstring> | ||
10 | + | ||
11 | +#else | ||
12 | +# define _INC_SWPRINTF_INL_ | ||
13 | +# define CRT_IMPORT __declspec(dllimport) | ||
14 | + | ||
15 | +#include <windows.h> // for wchar_t | ||
16 | +extern "C" { | ||
17 | +CRT_IMPORT int swprintf(wchar_t *src, const wchar_t *fmt, ...); | ||
18 | +CRT_IMPORT int sprintf(char *src, const char *fmt, ...); | ||
19 | +CRT_IMPORT int swscanf(const wchar_t *src, const wchar_t *fmt, ...); | ||
20 | +CRT_IMPORT int sscanf(const char *src, const char *fmt, ...); | ||
21 | +CRT_IMPORT int wprintf(const wchar_t *fmt, ...); | ||
22 | +CRT_IMPORT int printf(const char *fmt, ...); | ||
23 | +CRT_IMPORT int _wputs(const wchar_t *src); | ||
24 | +CRT_IMPORT int puts(const char *src); | ||
25 | +CRT_IMPORT int _stricmp(const char *x, const char *y); | ||
26 | +CRT_IMPORT int _wcsicmp(const wchar_t *x, const wchar_t *y); | ||
27 | +//CRT_IMPORT size_t strlen(const char *); | ||
28 | +//CRT_IMPORT size_t wcslen(const wchar_t *); | ||
29 | +//CRT_IMPORT char *strcpy(char *,const char *); | ||
30 | +//CRT_IMPORT wchar_t *wcscpy(wchar_t *,const wchar_t *); | ||
31 | +CRT_IMPORT void *memmove(void *dst, const void *src, size_t sz); | ||
32 | +CRT_IMPORT const char *strchr(const char *src, int val); | ||
33 | +CRT_IMPORT int strncmp(const char *x, const char *y, size_t sz); | ||
34 | +} // extern "C" | ||
35 | + | ||
36 | +#endif // ITH_HAS_CRT |
vnr/ith/common/types.h
0 → 100644
1 | +#pragma once | ||
2 | + | ||
3 | +// ith/common/types.h | ||
4 | +// 8/23/2013 jichi | ||
5 | +// Branch: ITH/common.h, rev 128 | ||
6 | + | ||
7 | +#include <windows.h> // needed for windef types | ||
8 | + | ||
9 | + /** jichi 3/7/2014: Add guessed comment | ||
10 | + * | ||
11 | + * DWORD addr absolute or relative address | ||
12 | + * DWORD split esp offset of the split character | ||
13 | + * | ||
14 | + * http://faydoc.tripod.com/cpu/pushad.htm | ||
15 | + * http://agth.wikia.com/wiki/Cheat_Engine_AGTH_Tutorial | ||
16 | + * The order is the same as pushd | ||
17 | + * 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 | ||
18 | + * 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 | ||
19 | + */ | ||
20 | +struct HookParam { | ||
21 | + // jichi 8/24/2013: For special hooks. Original name: DataFun | ||
22 | + typedef void (*text_fun_t)(DWORD esp, HookParam *hp, BYTE index, DWORD *data, DWORD *split, DWORD *len); | ||
23 | + | ||
24 | + // jichi 10/24/2014: Add filter function. Return the if skip the text | ||
25 | + typedef bool (*filter_fun_t)(LPVOID str, DWORD *len, HookParam *hp, BYTE index); | ||
26 | + | ||
27 | + // jichi 10/24/2014: Add generic hook function, return false if stop execution. | ||
28 | + typedef bool (*hook_fun_t)(DWORD esp, HookParam *hp); | ||
29 | + | ||
30 | + DWORD addr; // absolute or relative address | ||
31 | + DWORD off, // offset of the data in the memory | ||
32 | + ind, // ? | ||
33 | + split, // esp offset of the split character = pusha offset - 4 | ||
34 | + split_ind; // ? | ||
35 | + DWORD module, // hash of the module | ||
36 | + function; | ||
37 | + text_fun_t text_fun; | ||
38 | + filter_fun_t filter_fun; | ||
39 | + hook_fun_t hook_fun; | ||
40 | + DWORD type; // flags | ||
41 | + WORD length_offset; // index of the string length | ||
42 | + BYTE hook_len, // ? | ||
43 | + recover_len; // ? | ||
44 | + | ||
45 | + // 2/2/2015: jichi number of times - 1 to run the hook | ||
46 | + BYTE extra_text_count; | ||
47 | + BYTE _unused; // jichi 2/2/2015: add a BYTE type to make to total sizeof(HookParam) even. | ||
48 | + | ||
49 | + // 7/20/2014: jichi additional parameters for PSP games | ||
50 | + DWORD user_flags, | ||
51 | + user_value; | ||
52 | +}; | ||
53 | + | ||
54 | +// jichi 6/1/2014: Structure of the esp for extern functions | ||
55 | +struct HookStack | ||
56 | +{ | ||
57 | + // pushad | ||
58 | + DWORD edi, // -0x24 | ||
59 | + esi, // -0x20 | ||
60 | + ebp, // -0x1c | ||
61 | + esp, // -0x18 | ||
62 | + ebx, // -0x14 | ||
63 | + edx, // -0x10 | ||
64 | + ecx, // -0xc | ||
65 | + eax; // -0x8 | ||
66 | + // pushfd | ||
67 | + DWORD eflags; // -0x4 | ||
68 | + DWORD retaddr; // 0 | ||
69 | + DWORD args[1]; // 0x4 | ||
70 | +}; | ||
71 | + | ||
72 | +struct SendParam { | ||
73 | + DWORD type; | ||
74 | + HookParam hp; | ||
75 | +}; | ||
76 | + | ||
77 | +struct Hook { // size: 0x80 | ||
78 | + HookParam hp; | ||
79 | + LPWSTR hook_name; | ||
80 | + int name_length; | ||
81 | + BYTE recover[0x68 - sizeof(HookParam)]; | ||
82 | + BYTE original[0x10]; | ||
83 | + | ||
84 | + DWORD Address() const { return hp.addr; } | ||
85 | + DWORD Type() const { return hp.type; } | ||
86 | + WORD Length() const { return hp.hook_len; } | ||
87 | + LPWSTR Name() const { return hook_name; } | ||
88 | + int NameLength() const { return name_length; } | ||
89 | +}; | ||
90 | + | ||
91 | +// EOF |
vnr/ith/dllconfig.h
0 → 100644
vnr/ith/dllconfig.pri
0 → 100644
1 | +# dllconfig.pri | ||
2 | +# 8/9/2013 jichi | ||
3 | +# For linking ITH injectable dlls. | ||
4 | +# The dll is self-containd and Windows-independent. | ||
5 | + | ||
6 | +CONFIG += dll noqt #noeh nosafeseh | ||
7 | +CONFIG -= embed_manifest_dll # dynamically load dlls | ||
8 | +win32 { | ||
9 | + CONFIG(eh): DEFINES += ITH_HAS_SEH # Do have exception handler in msvcrt.dll on Windows Vista and later | ||
10 | + CONFIG(noeh): DEFINES -= ITH_HAS_SEH # Do not have exception handler in msvcrt.dll on Windows XP and before | ||
11 | +} | ||
12 | +include(../../../config.pri) | ||
13 | +#win32 { | ||
14 | +# CONFIG(noeh): include($$LIBDIR/winseh/winseh_safe.pri) | ||
15 | +#} | ||
16 | + | ||
17 | +# jichi 11/24/2013: Disable manual heap | ||
18 | +DEFINES -= ITH_HAS_HEAP | ||
19 | + | ||
20 | +# jichi 11/13/2011: disable swprinf warning | ||
21 | +DEFINES += _CRT_NON_CONFORMING_SWPRINTFS | ||
22 | + | ||
23 | +## Libraries | ||
24 | + | ||
25 | +#LIBS += -lkernel32 -luser32 -lgdi32 | ||
26 | +LIBS += -L$$WDK7_HOME/lib/wxp/i386 -lntdll | ||
27 | +LIBS += $$WDK7_HOME/lib/crt/i386/msvcrt.lib # Override msvcrt10 | ||
28 | +#LIBS += -L$$WDK7_HOME/lib/crt/i386 -lmsvcrt | ||
29 | +#QMAKE_LFLAGS += $$WDK7_HOME/lib/crt/i386/msvcrt.lib # This will leave runtime flags in the dll | ||
30 | + | ||
31 | +#LIBS += -L$$WDK8_HOME/lib/winv6.3/um/x86 -lntdll | ||
32 | + | ||
33 | +HEADERS += $$PWD/dllconfig.h | ||
34 | + | ||
35 | +# EOF |
vnr/ith/hook/CMakeLists.txt
0 → 100644
1 | +# hook.pro | ||
2 | +# CONFIG += eh eha | ||
3 | +# include(../dllconfig.pri) | ||
4 | + | ||
5 | +# hookxp.pro | ||
6 | +# CONFIG += noeh | ||
7 | +# include(../dllconfig.pri) | ||
8 | + | ||
9 | +# dllconfig.pri | ||
10 | +# include(../../../config.pri) | ||
11 | +# win32 { | ||
12 | +# CONFIG(eh): DEFINES += ITH_HAS_SEH | ||
13 | +# CONFIG(noeh): DEFINES -= ITH_HAS_SEH | ||
14 | +# } | ||
15 | + | ||
16 | +# config.pri | ||
17 | +# CONFIG(eha) { | ||
18 | +# message(CONFIG eha) | ||
19 | +# QMAKE_CXXFLAGS_STL_ON -= /EHsc | ||
20 | +# QMAKE_CXXFLAGS_EXCEPTIONS_ON -= /EHsc | ||
21 | +# QMAKE_CXXFLAGS_STL_ON += /EHa | ||
22 | +# QMAKE_CXXFLAGS_EXCEPTIONS_ON += /EHa | ||
23 | +# } | ||
24 | +# | ||
25 | +# CONFIG(noeh) { # No Exception handler | ||
26 | +# QMAKE_CXXFLAGS += /GR- | ||
27 | +# QMAKE_CXXFLAGS_RTTI_ON -= /GR | ||
28 | +# QMAKE_CXXFLAGS_STL_ON -= /EHsc | ||
29 | +# QMAKE_CXXFLAGS_EXCEPTIONS_ON -= /EHsc | ||
30 | +# } | ||
31 | + | ||
32 | +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) | ||
33 | + | ||
34 | +set(vnrhook_src | ||
35 | + cli.h | ||
36 | + config.h | ||
37 | + hook.h | ||
38 | + main.cc | ||
39 | + engine/engine.cc | ||
40 | + engine/engine.h | ||
41 | + engine/hookdefs.h | ||
42 | + engine/match.cc | ||
43 | + engine/match.h | ||
44 | + engine/pchooks.cc | ||
45 | + engine/pchooks.h | ||
46 | + engine/util.cc | ||
47 | + engine/util.h | ||
48 | + hijack/texthook.cc | ||
49 | + rpc/pipe.cc | ||
50 | + tree/avl.h | ||
51 | + ${PROJECT_SOURCE_DIR}/ccutil/ccmacro.h | ||
52 | + ${PROJECT_SOURCE_DIR}/cpputil/cpplocale.h | ||
53 | + ${PROJECT_SOURCE_DIR}/cpputil/cppmarshal.h | ||
54 | + ${PROJECT_SOURCE_DIR}/cpputil/cppmath.h | ||
55 | + ${PROJECT_SOURCE_DIR}/cpputil/cpppath.h | ||
56 | + ${PROJECT_SOURCE_DIR}/cpputil/cppstring.h | ||
57 | + ${PROJECT_SOURCE_DIR}/cpputil/cpptype.h | ||
58 | + ${PROJECT_SOURCE_DIR}/cpputil/cppunicode.h | ||
59 | + ${PROJECT_SOURCE_DIR}/disasm/disasm.cc | ||
60 | + ${PROJECT_SOURCE_DIR}/memdbg/memdbg.h | ||
61 | + ${PROJECT_SOURCE_DIR}/memdbg/memsearch.cc | ||
62 | + ${PROJECT_SOURCE_DIR}/memdbg/memsearch.h | ||
63 | + ${PROJECT_SOURCE_DIR}/ntinspect/ntinspect.cc | ||
64 | + ${PROJECT_SOURCE_DIR}/ntinspect/ntinspect.h | ||
65 | + ${PROJECT_SOURCE_DIR}/winversion/winversion.cc | ||
66 | + ${PROJECT_SOURCE_DIR}/winversion/winversion.h | ||
67 | + ${common_src} | ||
68 | + ${import_src} | ||
69 | +) | ||
70 | + | ||
71 | +source_group("common" FILES ${common_src}) | ||
72 | +source_group("import" FILES ${import_src}) | ||
73 | + | ||
74 | +add_library(vnrhook SHARED ${vnrhook_src}) | ||
75 | + | ||
76 | +set(vnrhookxp_src ${vnrhook_src} | ||
77 | + ${PROJECT_SOURCE_DIR}/winseh/winseh.cc | ||
78 | + ${PROJECT_SOURCE_DIR}/winseh/winseh_safe.cc | ||
79 | + ${PROJECT_SOURCE_DIR}/winseh/winseh.h | ||
80 | + ${PROJECT_SOURCE_DIR}/winseh/safeseh.asm | ||
81 | +) | ||
82 | + | ||
83 | +enable_language(ASM_MASM) | ||
84 | + | ||
85 | +set_source_files_properties( | ||
86 | + ${PROJECT_SOURCE_DIR}/winseh/safeseh.asm | ||
87 | + PROPERTIES | ||
88 | + # CMAKE_ASM_MASM_FLAGS /safeseh # CMake bug 14711: http://www.cmake.org/Bug/view.php?id=14711 | ||
89 | + COMPILE_FLAGS /safeseh | ||
90 | +) | ||
91 | + | ||
92 | +add_library(vnrhookxp SHARED ${vnrhookxp_src}) | ||
93 | + | ||
94 | +set_target_properties(vnrhook vnrhookxp PROPERTIES | ||
95 | + LINK_FLAGS "/SUBSYSTEM:WINDOWS /MANIFEST:NO" | ||
96 | +) | ||
97 | + | ||
98 | +target_compile_options(vnrhook PRIVATE | ||
99 | + /EHa | ||
100 | + $<$<CONFIG:Release>:> | ||
101 | + $<$<CONFIG:Debug>:> | ||
102 | +) | ||
103 | + | ||
104 | +target_compile_options(vnrhookxp PRIVATE | ||
105 | + /GR- | ||
106 | +# /EHs-c- # disable exception handling # CMake bug 15243: http://www.cmake.org/Bug/view.php?id=15243 | ||
107 | + $<$<CONFIG:Release>:> | ||
108 | + $<$<CONFIG:Debug>:> | ||
109 | +) | ||
110 | + | ||
111 | +if(TARGET vnrhookxp) | ||
112 | + STRING(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) | ||
113 | +endif(TARGET vnrhookxp) | ||
114 | + | ||
115 | +set(vnrhook_libs | ||
116 | + vnrsys | ||
117 | + ${WDK_HOME}/lib/wxp/i386/ntdll.lib | ||
118 | + Version.lib | ||
119 | +) | ||
120 | + | ||
121 | +target_link_libraries(vnrhook ${vnrhook_libs}) | ||
122 | +target_link_libraries(vnrhookxp ${vnrhook_libs}) | ||
123 | + | ||
124 | +target_compile_definitions(vnrhook | ||
125 | + PRIVATE | ||
126 | + -DITH_HAS_SEH | ||
127 | +) | ||
128 | +target_compile_definitions(vnrhookxp | ||
129 | + PRIVATE | ||
130 | +) | ||
131 | + | ||
132 | +install(TARGETS vnrhook vnrhookxp RUNTIME | ||
133 | + DESTINATION . | ||
134 | + CONFIGURATIONS Release | ||
135 | +) |
vnr/ith/hook/cli.h
0 → 100644
1 | +#pragma once | ||
2 | + | ||
3 | +// cli.h | ||
4 | +// 8/24/2013 jichi | ||
5 | +// Branch: IHF_DLL/IHF_CLIENT.h, rev 133 | ||
6 | +// | ||
7 | +// 8/24/2013 TODO: | ||
8 | +// - Clean up this file | ||
9 | +// - Reduce global variables. Use namespaces or singleton classes instead. | ||
10 | + | ||
11 | +//#include <windows.h> | ||
12 | +//#define IHF | ||
13 | +#include "config.h" | ||
14 | +#include "hook.h" | ||
15 | + | ||
16 | +// jichi 12/25/2013: Header in each message sent to vnrsrv | ||
17 | +// There are totally three elements | ||
18 | +// - 0x0 dwAddr hook address | ||
19 | +// - 0x4 dwRetn return address | ||
20 | +// - 0x8 dwSplit split value | ||
21 | +#define HEADER_SIZE 0xc | ||
22 | + | ||
23 | +extern int current_hook; | ||
24 | +extern WCHAR dll_mutex[]; | ||
25 | +//extern WCHAR dll_name[]; | ||
26 | +extern DWORD trigger; | ||
27 | +//extern DWORD current_process_id; | ||
28 | + | ||
29 | +// jichi 6/3/2014: Get memory range of the current module | ||
30 | +extern DWORD processStartAddress, | ||
31 | + processStopAddress; | ||
32 | + | ||
33 | +template <class T, class D, class fComp, class fCopy, class fLength> | ||
34 | +class AVLTree; | ||
35 | +struct FunctionInfo { | ||
36 | + DWORD addr; | ||
37 | + DWORD module; | ||
38 | + DWORD size; | ||
39 | + LPWSTR name; | ||
40 | +}; | ||
41 | +struct SCMP; | ||
42 | +struct SCPY; | ||
43 | +struct SLEN; | ||
44 | +extern AVLTree<char, FunctionInfo, SCMP, SCPY, SLEN> *tree; | ||
45 | + | ||
46 | +void InitFilterTable(); | ||
47 | + | ||
48 | +// jichi 9/25/2013: This class will be used by NtMapViewOfSectionfor | ||
49 | +// interprocedure communication, where constructor/destructor will NOT work. | ||
50 | +class TextHook : public Hook | ||
51 | +{ | ||
52 | + int UnsafeInsertHookCode(); | ||
53 | + DWORD UnsafeSend(DWORD dwDataBase, DWORD dwRetn); | ||
54 | +public: | ||
55 | + int InsertHook(); | ||
56 | + int InsertHookCode(); | ||
57 | + int InitHook(const HookParam &hp, LPCWSTR name = 0, WORD set_flag = 0); | ||
58 | + int InitHook(LPVOID addr, DWORD data, DWORD data_ind, | ||
59 | + DWORD split_off, DWORD split_ind, WORD type, DWORD len_off = 0); | ||
60 | + DWORD Send(DWORD dwDataBase, DWORD dwRetn); | ||
61 | + int RecoverHook(); | ||
62 | + int RemoveHook(); | ||
63 | + int ClearHook(); | ||
64 | + int ModifyHook(const HookParam&); | ||
65 | + int SetHookName(LPCWSTR name); | ||
66 | + int GetLength(DWORD base, DWORD in); // jichi 12/25/2013: Return 0 if failed | ||
67 | + void CoolDown(); // jichi 9/28/2013: flush instruction cache on wine | ||
68 | +}; | ||
69 | + | ||
70 | +extern TextHook *hookman, | ||
71 | + *current_available; | ||
72 | + | ||
73 | +//void InitDefaultHook(); | ||
74 | + | ||
75 | +struct FilterRange { DWORD lower, upper; }; | ||
76 | +extern FilterRange *filter; | ||
77 | + | ||
78 | +extern bool running, | ||
79 | + live; | ||
80 | + | ||
81 | +extern HANDLE hPipe, | ||
82 | + hmMutex; | ||
83 | + | ||
84 | +DWORD WINAPI WaitForPipe(LPVOID lpThreadParameter); | ||
85 | +DWORD WINAPI CommandPipe(LPVOID lpThreadParameter); | ||
86 | + | ||
87 | +//void RequestRefreshProfile(); | ||
88 | + | ||
89 | +//typedef DWORD (*InsertHookFun)(DWORD); | ||
90 | +//typedef DWORD (*IdentifyEngineFun)(); | ||
91 | +//typedef DWORD (*InsertDynamicHookFun)(LPVOID addr, DWORD frame, DWORD stack); | ||
92 | +//extern IdentifyEngineFun IdentifyEngine; | ||
93 | +//extern InsertDynamicHookFun InsertDynamicHook; | ||
94 | + | ||
95 | +// jichi 9/28/2013: Protect pipeline in wine | ||
96 | +void CliLockPipe(); | ||
97 | +void CliUnlockPipe(); | ||
98 | + | ||
99 | +// EOF |
vnr/ith/hook/config.h
0 → 100644
vnr/ith/hook/engine/engine.cc
0 → 100644
This diff could not be displayed because it is too large.
vnr/ith/hook/engine/engine.h
0 → 100644
1 | +#pragma once | ||
2 | + | ||
3 | +// engine/engine.h | ||
4 | +// 8/23/2013 jichi | ||
5 | +// See: http://ja.wikipedia.org/wiki/プロジェクト:美少女ゲーム系/ゲームエンジン | ||
6 | + | ||
7 | +#include "config.h" | ||
8 | + | ||
9 | +struct HookParam; // defined in ith types.h | ||
10 | + | ||
11 | +namespace Engine { | ||
12 | + | ||
13 | +// Global variables | ||
14 | +extern wchar_t process_name_[MAX_PATH], // cached | ||
15 | + process_path_[MAX_PATH]; // cached | ||
16 | +extern DWORD module_base_, | ||
17 | + module_limit_; | ||
18 | + | ||
19 | +//extern LPVOID trigger_addr; | ||
20 | +typedef bool (* trigger_fun_t)(LPVOID addr, DWORD frame, DWORD stack); | ||
21 | +extern trigger_fun_t trigger_fun_; | ||
22 | + | ||
23 | +bool InsertMonoHooks(); // Mono | ||
24 | + | ||
25 | +// Wii engines | ||
26 | + | ||
27 | +bool InsertGCHooks(); // Dolphin | ||
28 | +bool InsertVanillawareGCHook(); | ||
29 | + | ||
30 | +// PS2 engines | ||
31 | + | ||
32 | +bool InsertPCSX2Hooks(); // PCSX2 | ||
33 | +bool InsertMarvelousPS2Hook(); // http://marvelous.jp | ||
34 | +bool InsertMarvelous2PS2Hook(); // http://marvelous.jp | ||
35 | +bool InsertTypeMoonPS2Hook(); // http://typemoon.com | ||
36 | +//bool InsertNamcoPS2Hook(); | ||
37 | + | ||
38 | +// PSP engines | ||
39 | + | ||
40 | +void SpecialPSPHook(DWORD esp_base, HookParam *hp, DWORD *data, DWORD *split, DWORD *len); // General PSP extern hook | ||
41 | + | ||
42 | +bool InsertPPSSPPHooks(); // PPSSPPWindows | ||
43 | + | ||
44 | +bool InsertPPSSPPHLEHooks(); | ||
45 | +bool InsertOtomatePPSSPPHook(); // PSP otomate.jp, 0.9.9.0 only | ||
46 | + | ||
47 | +bool Insert5pbPSPHook(); // PSP 5pb.jp | ||
48 | +bool InsertAlchemistPSPHook(); // PSP Alchemist-net.co.jp, 0.9.8 only | ||
49 | +bool InsertAlchemist2PSPHook(); // PSP Alchemist-net.co.jp | ||
50 | +bool InsertBandaiNamePSPHook(); // PSP Bandai.co.jp | ||
51 | +bool InsertBandaiPSPHook(); // PSP Bandai.co.jp | ||
52 | +bool InsertBroccoliPSPHook(); // PSP Broccoli.co.jp | ||
53 | +bool InsertFelistellaPSPHook(); // PSP felistella.co.jp | ||
54 | + | ||
55 | +bool InsertCyberfrontPSPHook(); // PSP CYBERFRONT (closed) | ||
56 | +bool InsertImageepochPSPHook(); // PSP Imageepoch.co.jp | ||
57 | +bool InsertImageepoch2PSPHook();// PSP Imageepoch.co.jp | ||
58 | +bool InsertKadokawaNamePSPHook(); // PSP Kadokawa.co.jp | ||
59 | +bool InsertKonamiPSPHook(); // PSP Konami.jp | ||
60 | +bool InsertTecmoPSPHook(); // PSP Koeitecmo.co.jp | ||
61 | +//bool InsertTypeMoonPSPHook(); // PSP Typemoon.com | ||
62 | + | ||
63 | +bool InsertOtomatePSPHook(); // PSP Otomate.jp, 0.9.8 only | ||
64 | +//bool InsertOtomate2PSPHook(); // PSP otomate.jp >= 0.9.9.1 | ||
65 | + | ||
66 | +bool InsertIntensePSPHook(); // PSP Intense.jp | ||
67 | +bool InsertKidPSPHook(); // PSP Kid-game.co.jp | ||
68 | +bool InsertNippon1PSPHook(); // PSP Nippon1.jp | ||
69 | +bool InsertNippon2PSPHook(); // PSP Nippon1.jp | ||
70 | +bool InsertYetiPSPHook(); // PSP Yetigame.jp | ||
71 | +bool InsertYeti2PSPHook(); // PSP Yetigame.jp | ||
72 | + | ||
73 | +// PC engines | ||
74 | + | ||
75 | +bool Insert2RMHook(); // 2RM - Adventure Engine | ||
76 | +bool Insert5pbHook(); // 5pb.jp, PSP/PS3 games ported to PC | ||
77 | +bool InsertAB2TryHook(); // Yane@AkabeiSoft2Try: YaneSDK.dll. | ||
78 | +bool InsertAbelHook(); // Abel | ||
79 | +bool InsertAdobeAirHook(); // Adobe AIR | ||
80 | +bool InsertAdobeFlash10Hook(); // Adobe Flash Player 10 | ||
81 | +bool InsertAliceHook(); // System40@AliceSoft; do not work for latest alice games | ||
82 | +bool InsertAmuseCraftHook(); // AMUSE CRAFT: *.pac | ||
83 | +bool InsertAnex86Hook(); // Anex86: anex86.exe | ||
84 | +bool InsertAOSHook(); // AOS: *.aos | ||
85 | +bool InsertApricoTHook(); // Apricot: arc.a* | ||
86 | +bool InsertArtemisHook(); // Artemis Engine: *.pfs | ||
87 | +bool InsertAtelierHook(); // Atelier Kaguya: message.dat | ||
88 | +bool InsertBGIHook(); // BGI: BGI.* | ||
89 | +bool InsertC4Hook(); // C4: C4.EXE or XEX.EXE | ||
90 | +bool InsertCaramelBoxHook(); // Caramel: *.bin | ||
91 | +bool InsertCandyHook(); // SystemC@CandySoft: *.fpk | ||
92 | +bool InsertCatSystemHook(); // CatSystem2: *.int | ||
93 | +bool InsertCMVSHook(); // CMVS: data/pack/*.cpz; do not support the latest cmvs32.exe and cmvs64.exe | ||
94 | +bool InsertCotophaHook(); // Cotopha: *.noa | ||
95 | +bool InsertDebonosuHook(); // Debonosu: bmp.bak and dsetup.dll | ||
96 | +bool InsertEaglsHook(); // E.A.G.L.S: EAGLES.dll | ||
97 | +bool InsertEMEHook(); // EmonEngine: emecfg.ecf | ||
98 | +bool InsertEushullyHook(); // Eushully: AGERC.DLL | ||
99 | +bool InsertExpHook(); // EXP: http://www.exp-inc.jp | ||
100 | +bool InsertFocasLensHook(); // FocasLens: Dat/*.arc, http://www.fo-lens.net | ||
101 | +bool InsertGesen18Hook(); // Gsen18: *.szs | ||
102 | +bool InsertGXPHook(); // GXP: *.gxp | ||
103 | +bool InsertHorkEyeHook(); // HorkEye: resource string | ||
104 | +bool InsertKAGParserHook(); // plugin/KAGParser.dll | ||
105 | +bool InsertKAGParserExHook(); // plugin/KAGParserEx.dll | ||
106 | +bool InsertKiriKiriHook(); // KiriKiri: *.xp3, resource string | ||
107 | +bool InsertKiriKiriZHook(); // KiriKiri: *.xp3, resource string | ||
108 | +bool InsertLeafHook(); // Leaf: *.pak | ||
109 | +bool InsertLiveHook(); // Live: live.dll | ||
110 | +bool InsertLunaSoftHook(); // LunaSoft: Pac/*.pac | ||
111 | +bool InsertMalieHook(); // Malie@light: malie.ini | ||
112 | +bool InsertMajiroHook(); // Majiro: *.arc | ||
113 | +bool InsertMarineHeartHook(); // Marine Heart: SAISYS.exe | ||
114 | +bool InsertMBLHook(); // MBL: *.mbl | ||
115 | +bool InsertMEDHook(); // MED: *.med | ||
116 | +bool InsertMinkHook(); // Mink: *.at2 | ||
117 | +//bool InsertMonoHook(); // Mono (Unity3D): */Mono/mono.dll | ||
118 | +bool InsertNeXASHook(); // NeXAS: Thumbnail.pac | ||
119 | +bool InsertNextonHook(); // NEXTON: aInfo.db | ||
120 | +bool InsertNexton1Hook(); | ||
121 | +bool InsertNitroPlusHook(); // NitroPlus: *.npa | ||
122 | +bool InsertPensilHook(); // Pensil: PSetup.exe | ||
123 | +bool InsertQLIEHook(); // QLiE: GameData/*.pack | ||
124 | +//bool InsertRai7Hook(); // Rai7puk: rai7.exe | ||
125 | +bool InsertRejetHook(); // Rejet: Module/{gd.dat,pf.dat,sd.dat} | ||
126 | +bool InsertRUGPHook(); // rUGP: rUGP.exe | ||
127 | +bool InsertRetouchHook(); // Retouch: resident.dll | ||
128 | +bool InsertRREHook(); // RunrunEngine: rrecfg.rcf | ||
129 | +bool InsertShinaHook(); // ShinaRio: Rio.ini | ||
130 | +bool InsertShinyDaysHook(); // ShinyDays | ||
131 | +bool InsertElfHook(); // elf: Silky.exe | ||
132 | +bool InsertScenarioPlayerHook();// sol-fa-soft: *.iar && *.sec5 | ||
133 | +bool InsertSiglusHook(); // SiglusEngine: SiglusEngine.exe | ||
134 | +bool InsertSideBHook(); // SideB: Copyright side-B | ||
135 | +bool InsertSyuntadaHook(); // Syuntada: dSoh.dat | ||
136 | +bool InsertSystem43Hook(); // System43@AliceSoft: AliceStart.ini | ||
137 | +bool InsertSystemAoiHook(); // SystemAoi: *.vfs | ||
138 | +bool InsertTanukiHook(); // Tanuki: *.tak | ||
139 | +bool InsertTaskforce2Hook(); // Taskforce2.exe | ||
140 | +bool InsertTencoHook(); // Tenco: Check.mdx | ||
141 | +bool InsertTriangleHook(); // Triangle: Execle.exe | ||
142 | +bool InsertYukaSystem2Hook(); // YukaSystem2: *.ykc | ||
143 | +bool InsertYurisHook(); // YU-RIS: *.ypf | ||
144 | +bool InsertWillPlusHook(); // WillPlus: Rio.arc | ||
145 | +bool InsertWolfHook(); // Wolf: Data.wolf | ||
146 | + | ||
147 | +void InsertBrunsHook(); // Bruns: bruns.exe | ||
148 | +void InsertIronGameSystemHook();// IroneGameSystem: igs_sample.exe | ||
149 | +void InsertLucifenHook(); // Lucifen@Navel: *.lpk | ||
150 | +void InsertRyokuchaHook(); // Ryokucha: _checksum.exe | ||
151 | +void InsertRealliveHook(); // RealLive: RealLive*.exe | ||
152 | +void InsertStuffScriptHook(); // Stuff: *.mpk | ||
153 | +void InsertTinkerBellHook(); // TinkerBell: arc00.dat | ||
154 | +void InsertWaffleHook(); // WAFFLE: cg.pak | ||
155 | + | ||
156 | +// CIRCUS: avdata/ | ||
157 | +bool InsertCircusHook1(); | ||
158 | +bool InsertCircusHook2(); | ||
159 | + | ||
160 | +} // namespace Engine | ||
161 | + | ||
162 | +// EOF |
vnr/ith/hook/engine/hookdefs.h
0 → 100644
vnr/ith/hook/engine/match.cc
0 → 100644
1 | +// eng/match.cc | ||
2 | +// 8/9/2013 jichi | ||
3 | +// Branch: ITH_Engine/engine.cpp, revision 133 | ||
4 | + | ||
5 | +#ifdef _MSC_VER | ||
6 | +# pragma warning (disable:4100) // C4100: unreference formal parameter | ||
7 | +//# pragma warning (disable:4733) // C4733: Inline asm assigning to 'FS:0' : handler not registered as safe handler | ||
8 | +#endif // _MSC_VER | ||
9 | + | ||
10 | +#include "engine/match.h" | ||
11 | +#include "engine/engine.h" | ||
12 | +#include "engine/pchooks.h" | ||
13 | +#include "engine/util.h" | ||
14 | +#include "hook.h" | ||
15 | +#include "ith/sys/sys.h" | ||
16 | +#include "ith/common/except.h" | ||
17 | +#include "ith/common/growl.h" | ||
18 | +#include "ccutil/ccmacro.h" | ||
19 | + | ||
20 | +//#define ConsoleOutput(...) (void)0 // jichi 8/18/2013: I don't need ConsoleOutput | ||
21 | + | ||
22 | +enum { MAX_REL_ADDR = 0x200000 }; // jichi 8/18/2013: maximum relative address | ||
23 | + | ||
24 | +// - Global variables - | ||
25 | + | ||
26 | +namespace Engine { | ||
27 | + | ||
28 | +WCHAR process_name_[MAX_PATH], // cached | ||
29 | + process_path_[MAX_PATH]; // cached | ||
30 | + | ||
31 | +DWORD module_base_, | ||
32 | + module_limit_; | ||
33 | + | ||
34 | +//LPVOID trigger_addr; | ||
35 | +trigger_fun_t trigger_fun_; | ||
36 | + | ||
37 | +} // namespace Engine | ||
38 | + | ||
39 | +// - Methods - | ||
40 | + | ||
41 | +namespace Engine { namespace { // unnamed | ||
42 | + | ||
43 | +// jichi 7/17/2014: Disable GDI hooks for PPSSPP | ||
44 | +bool DeterminePCEngine() | ||
45 | +{ | ||
46 | + if (IthFindFile(L"PPSSPP*.exe")) { // jichi 7/12/2014 PPSSPPWindows.exe, PPSSPPEX.exe PPSSPPSP.exe | ||
47 | + InsertPPSSPPHooks(); | ||
48 | + return true; | ||
49 | + } | ||
50 | + | ||
51 | + if (IthFindFile(L"pcsx2*.exe")) { // jichi 7/19/2014 PCSX2.exe or PCSX2WX.exe | ||
52 | + if (!InsertPCSX2Hooks()) { // don't forget to rebuild vnrcli to inject SSE | ||
53 | + // Always insert PC hooks so that user could add PCSX2 to VNR. | ||
54 | + // TO BE REMOVED after more PS2 engines are added. | ||
55 | + PcHooks::hookGDIFunctions(); | ||
56 | + PcHooks::hookLstrFunctions(); | ||
57 | + } | ||
58 | + | ||
59 | + return true; | ||
60 | + } | ||
61 | + | ||
62 | + if (IthFindFile(L"Dolphin.exe")) { // jichi 7/20/2014 | ||
63 | + if (!InsertGCHooks()) { | ||
64 | + // Always insert PC hooks so that user could add PCSX2 to VNR. | ||
65 | + // TO BE REMOVED after more PS2 engines are added. | ||
66 | + PcHooks::hookGDIFunctions(); | ||
67 | + PcHooks::hookLstrFunctions(); | ||
68 | + } | ||
69 | + | ||
70 | + return true; | ||
71 | + } | ||
72 | + | ||
73 | + //if (IthFindFile(L"*\\Mono\\mono.dll")) { // jichi 4/21/2014: Mono | ||
74 | + //if (IthCheckFile(L"bsz2_Data\\Mono\\mono.dll")) { // jichi 4/21/2014: Mono | ||
75 | + // InsertMonoHook(); | ||
76 | + // return true; | ||
77 | + //} | ||
78 | + if (::GetModuleHandleA("mono.dll")) { | ||
79 | + InsertMonoHooks(); | ||
80 | + | ||
81 | + // 3/20/2015 jichi | ||
82 | + // Always insert GDI hooks even for Mono games | ||
83 | + // For example: 新世黙示録 need GetGlyphOutlineA | ||
84 | + PcHooks::hookGDIFunctions(); | ||
85 | + return true; | ||
86 | + } | ||
87 | + | ||
88 | + // PC games | ||
89 | + PcHooks::hookGDIFunctions(); | ||
90 | + return false; | ||
91 | +} | ||
92 | + | ||
93 | +bool DetermineEngineByFile1() | ||
94 | +{ | ||
95 | + if (IthFindFile(L"*.xp3") || Util::SearchResourceString(L"TVP(KIRIKIRI)")) { | ||
96 | + if (Util::SearchResourceString(L"TVP(KIRIKIRI) Z ")) { // TVP(KIRIKIRI) Z CORE | ||
97 | + // jichi 11/24/2014: Disabled that might crash VBH | ||
98 | + //if (IthCheckFile(L"plugin\\KAGParser.dll")) | ||
99 | + // InsertKAGParserHook(); | ||
100 | + //else if (IthCheckFile(L"plugin\\KAGParserEx.dll")) | ||
101 | + // InsertKAGParserExHook(); | ||
102 | + if (InsertKiriKiriZHook()) | ||
103 | + return true; | ||
104 | + } | ||
105 | + InsertKiriKiriHook(); | ||
106 | + return true; | ||
107 | + } | ||
108 | + // 8/2/2014 jichi: Game name shown as 2RM - Adventure Engine | ||
109 | + if (Util::SearchResourceString(L"2RM") && Util::SearchResourceString(L"Adventure Engine")) { | ||
110 | + Insert2RMHook(); | ||
111 | + return true; | ||
112 | + } | ||
113 | + // 8/2/2014 jichi: Copyright is side-B, a conf.dat will be generated after the game is launched | ||
114 | + // It also contains lua5.1.dll and lua5.dll | ||
115 | + if (Util::SearchResourceString(L"side-B")) { | ||
116 | + InsertSideBHook(); | ||
117 | + return true; | ||
118 | + } | ||
119 | + if (IthFindFile(L"bgi.*")) { | ||
120 | + InsertBGIHook(); | ||
121 | + return true; | ||
122 | + } | ||
123 | + if (IthCheckFile(L"AGERC.DLL")) { // 6/1/2014 jichi: Eushully, AGE.EXE | ||
124 | + InsertEushullyHook(); | ||
125 | + return true; | ||
126 | + } | ||
127 | + if (IthFindFile(L"data*.arc") && IthFindFile(L"stream*.arc")) { | ||
128 | + InsertMajiroHook(); | ||
129 | + return true; | ||
130 | + } | ||
131 | + // jichi 5/31/2014 | ||
132 | + if (//IthCheckFile(L"Silkys.exe") || // It might or might not have Silkys.exe | ||
133 | + // data, effect, layer, mes, music | ||
134 | + IthCheckFile(L"data.arc") && IthCheckFile(L"effect.arc") && IthCheckFile(L"mes.arc")) { | ||
135 | + InsertElfHook(); | ||
136 | + return true; | ||
137 | + } | ||
138 | + if (IthFindFile(L"data\\pack\\*.cpz")) { | ||
139 | + InsertCMVSHook(); | ||
140 | + return true; | ||
141 | + } | ||
142 | + // jichi 10/12/2013: Restore wolf engine | ||
143 | + // jichi 10/18/2013: Check for data/*.wolf | ||
144 | + if (IthFindFile(L"data.wolf") || IthFindFile(L"data\\*.wolf")) { | ||
145 | + InsertWolfHook(); | ||
146 | + return true; | ||
147 | + } | ||
148 | + if (IthCheckFile(L"advdata\\dat\\names.dat")) { | ||
149 | + InsertCircusHook1(); | ||
150 | + return true; | ||
151 | + } | ||
152 | + if (IthCheckFile(L"advdata\\grp\\names.dat")) { | ||
153 | + InsertCircusHook2(); | ||
154 | + return true; | ||
155 | + } | ||
156 | + if (IthFindFile(L"*.noa")) { | ||
157 | + InsertCotophaHook(); | ||
158 | + return true; | ||
159 | + } | ||
160 | + if (IthFindFile(L"*.pfs")) { // jichi 10/1/2013 | ||
161 | + InsertArtemisHook(); | ||
162 | + return true; | ||
163 | + } | ||
164 | + if (IthFindFile(L"*.int")) { | ||
165 | + InsertCatSystemHook(); | ||
166 | + return true; | ||
167 | + } | ||
168 | + if (IthCheckFile(L"message.dat")) { | ||
169 | + InsertAtelierHook(); | ||
170 | + return true; | ||
171 | + } | ||
172 | + if (IthCheckFile(L"Check.mdx")) { // jichi 4/1/2014: AUGame | ||
173 | + InsertTencoHook(); | ||
174 | + return true; | ||
175 | + } | ||
176 | + // jichi 12/25/2013: It may or may not be QLIE. | ||
177 | + // AlterEgo also has GameData/sound.pack but is not QLIE | ||
178 | + if (IthFindFile(L"GameData\\*.pack") && InsertQLIEHook()) | ||
179 | + return true; | ||
180 | + | ||
181 | + if (IthFindFile(L"*.pac")) { | ||
182 | + // jichi 6/3/2014: AMUSE CRAFT and SOFTPAL | ||
183 | + // Selectively insert, so that lstrlenA can still get correct text if failed | ||
184 | + if (IthCheckFile(L"dll\\resource.dll") && IthCheckFile(L"dll\\pal.dll") && InsertAmuseCraftHook()) | ||
185 | + return true; | ||
186 | + | ||
187 | + if (IthCheckFile(L"Thumbnail.pac")) { | ||
188 | + //ConsoleOutput("vnreng: IGNORE NeXAS"); | ||
189 | + InsertNeXASHook(); // jichi 7/6/2014: GIGA | ||
190 | + return true; | ||
191 | + } | ||
192 | + | ||
193 | + if (Util::SearchResourceString(L"SOFTPAL")) { | ||
194 | + ConsoleOutput("vnreng: IGNORE SoftPal UNiSONSHIFT"); | ||
195 | + return true; | ||
196 | + } | ||
197 | + } | ||
198 | + // jichi 12/27/2014: LunaSoft | ||
199 | + if (IthFindFile(L"Pac\\*.pac")) { | ||
200 | + InsertLunaSoftHook(); | ||
201 | + return true; | ||
202 | + } | ||
203 | + // jichi 9/16/2013: Add Gesen18 | ||
204 | + if (IthFindFile(L"*.szs") || IthFindFile(L"Data\\*.szs")) { | ||
205 | + InsertGesen18Hook(); | ||
206 | + return true; | ||
207 | + } | ||
208 | + // jichi 12/22/2013: Add rejet | ||
209 | + if (IthCheckFile(L"gd.dat") && IthCheckFile(L"pf.dat") && IthCheckFile(L"sd.dat")) { | ||
210 | + InsertRejetHook(); | ||
211 | + return true; | ||
212 | + } | ||
213 | + // Only examined with version 1.0 | ||
214 | + //if (IthFindFile(L"Adobe AIR\\Versions\\*\\Adobe AIR.dll")) { // jichi 4/15/2014: FIXME: Wildcard not working | ||
215 | + if (IthCheckFile(L"Adobe AIR\\Versions\\1.0\\Adobe AIR.dll")) { // jichi 4/15/2014: Adobe AIR | ||
216 | + InsertAdobeAirHook(); | ||
217 | + return true; | ||
218 | + } | ||
219 | + return false; | ||
220 | +} | ||
221 | + | ||
222 | +bool DetermineEngineByFile2() | ||
223 | +{ | ||
224 | + if (IthCheckFile(L"resident.dll")) { | ||
225 | + InsertRetouchHook(); | ||
226 | + return true; | ||
227 | + } | ||
228 | + if (IthCheckFile(L"Malie.ini") || IthCheckFile(L"Malie.exe")) { // jichi: 9/9/2014: Add malie.exe in case malie.ini is missing | ||
229 | + InsertMalieHook(); | ||
230 | + return true; | ||
231 | + } | ||
232 | + if (IthCheckFile(L"live.dll")) { | ||
233 | + InsertLiveHook(); | ||
234 | + return true; | ||
235 | + } | ||
236 | + // 9/5/2013 jichi | ||
237 | + if (IthCheckFile(L"aInfo.db")) { | ||
238 | + InsertNextonHook(); | ||
239 | + return true; | ||
240 | + } | ||
241 | + if (IthFindFile(L"*.lpk")) { | ||
242 | + InsertLucifenHook(); | ||
243 | + return true; | ||
244 | + } | ||
245 | + if (IthCheckFile(L"cfg.pak")) { | ||
246 | + InsertWaffleHook(); | ||
247 | + return true; | ||
248 | + } | ||
249 | + if (IthCheckFile(L"Arc00.dat")) { | ||
250 | + InsertTinkerBellHook(); | ||
251 | + return true; | ||
252 | + } | ||
253 | + if (IthFindFile(L"*.vfs")) { // jichi 7/6/2014: Better to test AoiLib.dll? ja.wikipedia.org/wiki/ソフトハウスキャラ | ||
254 | + InsertSystemAoiHook(); | ||
255 | + return true; | ||
256 | + } | ||
257 | + if (IthFindFile(L"*.mbl")) { | ||
258 | + InsertMBLHook(); | ||
259 | + return true; | ||
260 | + } | ||
261 | + // jichi 8/1/2014: YU-RIS engine, lots of clockup game also has this pattern | ||
262 | + if (IthFindFile(L"pac\\*.ypf") || IthFindFile(L"*.ypf")) { | ||
263 | + // jichi 8/14/2013: CLOCLUP: "ノーブレスオブリージュ" would crash the game. | ||
264 | + if (!IthCheckFile(L"noblesse.exe")) | ||
265 | + InsertYurisHook(); | ||
266 | + return true; | ||
267 | + } | ||
268 | + if (IthFindFile(L"*.npa")) { | ||
269 | + InsertNitroPlusHook(); | ||
270 | + return true; | ||
271 | + } | ||
272 | + return false; | ||
273 | +} | ||
274 | + | ||
275 | +bool DetermineEngineByFile3() | ||
276 | +{ | ||
277 | + //if (IthCheckFile(L"libscr.dll")) { // already checked | ||
278 | + // InsertBrunsHook(); | ||
279 | + // return true; | ||
280 | + //} | ||
281 | + | ||
282 | + // jichi 10/12/2013: Sample args.txt: | ||
283 | + // See: http://tieba.baidu.com/p/2631413816 | ||
284 | + // -workdir | ||
285 | + // . | ||
286 | + // -loadpath | ||
287 | + // . | ||
288 | + // am.cfg | ||
289 | + if (IthCheckFile(L"args.txt")) { | ||
290 | + InsertBrunsHook(); | ||
291 | + return true; | ||
292 | + } | ||
293 | + if (IthCheckFile(L"emecfg.ecf")) { | ||
294 | + InsertEMEHook(); | ||
295 | + return true; | ||
296 | + } | ||
297 | + if (IthCheckFile(L"rrecfg.rcf")) { | ||
298 | + InsertRREHook(); | ||
299 | + return true; | ||
300 | + } | ||
301 | + if (IthFindFile(L"*.fpk") || IthFindFile(L"data\\*.fpk")) { | ||
302 | + InsertCandyHook(); | ||
303 | + return true; | ||
304 | + } | ||
305 | + if (IthFindFile(L"arc.a*")) { | ||
306 | + InsertApricoTHook(); | ||
307 | + return true; | ||
308 | + } | ||
309 | + if (IthFindFile(L"*.mpk")) { | ||
310 | + InsertStuffScriptHook(); | ||
311 | + return true; | ||
312 | + } | ||
313 | + if (IthCheckFile(L"Execle.exe")) { | ||
314 | + InsertTriangleHook(); | ||
315 | + return true; | ||
316 | + } | ||
317 | + // jichi 2/28/2015: No longer work for "大正×対称アリス episode I" from Primula | ||
318 | + //if (IthCheckFile(L"PSetup.exe")) { | ||
319 | + // InsertPensilHook(); | ||
320 | + // return true; | ||
321 | + //} | ||
322 | + if (IthCheckFile(L"Yanesdk.dll")) { | ||
323 | + InsertAB2TryHook(); | ||
324 | + return true; | ||
325 | + } | ||
326 | + if (IthFindFile(L"*.med")) { | ||
327 | + InsertMEDHook(); | ||
328 | + return true; | ||
329 | + } | ||
330 | + return false; | ||
331 | +} | ||
332 | + | ||
333 | +bool DetermineEngineByFile4() | ||
334 | +{ | ||
335 | + if (IthCheckFile(L"EAGLS.dll")) { // jichi 3/24/2014: E.A.G.L.S | ||
336 | + //ConsoleOutput("vnreng: IGNORE EAGLS"); | ||
337 | + InsertEaglsHook(); | ||
338 | + return true; | ||
339 | + } | ||
340 | + if (IthCheckFile(L"bmp.pak") && IthCheckFile(L"dsetup.dll")) { | ||
341 | + InsertDebonosuHook(); | ||
342 | + return true; | ||
343 | + } | ||
344 | + if (IthCheckFile(L"C4.EXE") || IthCheckFile(L"XEX.EXE")) { | ||
345 | + InsertC4Hook(); | ||
346 | + return true; | ||
347 | + } | ||
348 | + if (IthCheckFile(L"Rio.arc") && IthFindFile(L"Chip*.arc")) { | ||
349 | + InsertWillPlusHook(); | ||
350 | + return true; | ||
351 | + } | ||
352 | + if (IthFindFile(L"*.tac")) { | ||
353 | + InsertTanukiHook(); | ||
354 | + return true; | ||
355 | + } | ||
356 | + if (IthFindFile(L"*.gxp")) { | ||
357 | + InsertGXPHook(); | ||
358 | + return true; | ||
359 | + } | ||
360 | + if (IthFindFile(L"*.aos")) { // jichi 4/2/2014: AOS hook | ||
361 | + InsertAOSHook(); | ||
362 | + return true; | ||
363 | + } | ||
364 | + if (IthFindFile(L"*.at2")) { // jichi 12/23/2014: Mink, sample files: voice.at2, voice.det, voice.nme | ||
365 | + InsertMinkHook(); | ||
366 | + return true; | ||
367 | + } | ||
368 | + if (IthFindFile(L"*.ykc")) { // jichi 7/15/2014: YukaSystem1 is not supported, though | ||
369 | + //ConsoleOutput("vnreng: IGNORE YKC:Feng/HookSoft(SMEE)"); | ||
370 | + InsertYukaSystem2Hook(); | ||
371 | + return true; | ||
372 | + } | ||
373 | + if (IthFindFile(L"model\\*.hed")) { // jichi 9/8/2014: EXP | ||
374 | + InsertExpHook(); | ||
375 | + return true; | ||
376 | + } | ||
377 | + // jichi 2/6/2015 平安亭 | ||
378 | + // dPi.dat, dPih.dat, dSc.dat, dSch.dat, dSo.dat, dSoh.dat, dSy.dat | ||
379 | + //if (IthCheckFile(L"dSoh.dat")) { // no idea why this file does not work | ||
380 | + if (IthCheckFile(L"dSch.dat")) { | ||
381 | + InsertSyuntadaHook(); | ||
382 | + return true; | ||
383 | + } | ||
384 | + | ||
385 | + // jichi 2/28/2015: Delay checking Pensil in case something went wrong | ||
386 | + // File pattern observed in [Primula] 大正×対称アリス episode I | ||
387 | + // - PSetup.exe no longer exists | ||
388 | + // - MovieTexture.dll information shows MovieTex dynamic library, copyright Pensil 2013 | ||
389 | + // - ta_trial.exe information shows 2XT - Primula Adventure Engine | ||
390 | + if (IthFindFile(L"PSetup.exe") || IthFindFile(L"MovieTexture.dll") || Util::SearchResourceString(L"2XT -")) { | ||
391 | + InsertPensilHook(); | ||
392 | + return true; | ||
393 | + } | ||
394 | + return false; | ||
395 | +} | ||
396 | + | ||
397 | +bool DetermineEngineByProcessName() | ||
398 | +{ | ||
399 | + WCHAR str[MAX_PATH]; | ||
400 | + wcscpy(str, process_name_); | ||
401 | + _wcslwr(str); // lower case | ||
402 | + | ||
403 | + if (wcsstr(str,L"reallive") || IthCheckFile(L"Reallive.exe")) { | ||
404 | + InsertRealliveHook(); | ||
405 | + return true; | ||
406 | + } | ||
407 | + | ||
408 | + // jichi 8/19/2013: DO NOT WORK for games like「ハピメア」 | ||
409 | + //if (wcsstr(str,L"cmvs32") || wcsstr(str,L"cmvs64")) { | ||
410 | + // InsertCMVSHook(); | ||
411 | + // return true; | ||
412 | + //} | ||
413 | + | ||
414 | + // jichi 8/17/2013: Handle "~" | ||
415 | + if (wcsstr(str, L"siglusengine") || !wcsncmp(str, L"siglus~", 7) || IthCheckFile(L"SiglusEngine.exe")) { | ||
416 | + InsertSiglusHook(); | ||
417 | + return true; | ||
418 | + } | ||
419 | + | ||
420 | + if (wcsstr(str, L"taskforce2") || !wcsncmp(str, L"taskfo~", 7) || IthCheckFile(L"Faskforce2.exe")) { | ||
421 | + InsertTaskforce2Hook(); | ||
422 | + return true; | ||
423 | + } | ||
424 | + | ||
425 | + if (wcsstr(str,L"rugp") || IthCheckFile(L"rugp.exe")) { | ||
426 | + InsertRUGPHook(); | ||
427 | + return true; | ||
428 | + } | ||
429 | + | ||
430 | + // jichi 8/17/2013: Handle "~" | ||
431 | + if (wcsstr(str, L"igs_sample") || !wcsncmp(str, L"igs_sa~", 7) || IthCheckFile(L"igs_sample.exe")) { | ||
432 | + InsertIronGameSystemHook(); | ||
433 | + return true; | ||
434 | + } | ||
435 | + | ||
436 | + if (wcsstr(str, L"bruns") || IthCheckFile(L"bruns.exe")) { | ||
437 | + InsertBrunsHook(); | ||
438 | + return true; | ||
439 | + } | ||
440 | + | ||
441 | + if (wcsstr(str, L"anex86") || IthCheckFile(L"anex86.exe")) { | ||
442 | + InsertAnex86Hook(); | ||
443 | + return true; | ||
444 | + } | ||
445 | + | ||
446 | + // jichi 8/17/2013: Handle "~" | ||
447 | + if (wcsstr(str, L"shinydays") || !wcsncmp(str, L"shinyd~", 7) || IthCheckFile(L"ShinyDays.exe")) { | ||
448 | + InsertShinyDaysHook(); | ||
449 | + return true; | ||
450 | + } | ||
451 | + | ||
452 | + // jichi 10/3/2013: FIXME: Does not work | ||
453 | + // Raise C0000005 even with admin priv | ||
454 | + //if (wcsstr(str, L"bsz")) { // BALDRSKY ZERO | ||
455 | + // InsertBaldrHook(); | ||
456 | + // return true; | ||
457 | + //} | ||
458 | + | ||
459 | + if (wcsstr(process_name_, L"SAISYS") || IthCheckFile(L"SaiSys.exe")) { // jichi 4/19/2014: Marine Heart | ||
460 | + InsertMarineHeartHook(); | ||
461 | + return true; | ||
462 | + } | ||
463 | + | ||
464 | + DWORD len = wcslen(str); | ||
465 | + | ||
466 | + // jichi 8/24/2013: Checking for Rio.ini or $procname.ini | ||
467 | + //wcscpy(str+len-4, L"_?.war"); | ||
468 | + //if (IthFindFile(str)) { | ||
469 | + // InsertShinaHook(); | ||
470 | + // return true; | ||
471 | + //} | ||
472 | + if (InsertShinaHook()) | ||
473 | + return true; | ||
474 | + | ||
475 | + // jichi 8/10/2013: Since *.bin is common, move CaramelBox to the end | ||
476 | + str[len - 3] = L'b'; | ||
477 | + str[len - 2] = L'i'; | ||
478 | + str[len - 1] = L'n'; | ||
479 | + str[len] = 0; | ||
480 | + if (IthCheckFile(str) || IthCheckFile(L"trial.bin")) { // jichi 7/8/2014: add trial.bin | ||
481 | + InsertCaramelBoxHook(); | ||
482 | + return true; | ||
483 | + } | ||
484 | + | ||
485 | + // This must appear at last since str is modified | ||
486 | + wcscpy(str + len - 4, L"_checksum.exe"); | ||
487 | + if (IthCheckFile(str)) { | ||
488 | + InsertRyokuchaHook(); | ||
489 | + | ||
490 | + if (IthFindFile(L"*.iar") && IthFindFile(L"*.sec5")) // jichi 9/27/2014: For new Ryokucha games | ||
491 | + InsertScenarioPlayerHook(); | ||
492 | + return true; | ||
493 | + } | ||
494 | + | ||
495 | + return false; | ||
496 | +} | ||
497 | + | ||
498 | +bool DetermineEngineOther() | ||
499 | +{ | ||
500 | + if (InsertAliceHook()) | ||
501 | + return true; | ||
502 | + // jichi 1/19/2015: Disable inserting Lstr for System40 | ||
503 | + // See: http://sakuradite.com/topic/618 | ||
504 | + if (IthCheckFile(L"System40.ini")) { | ||
505 | + ConsoleOutput("vnreng: IGNORE old System40.ini"); | ||
506 | + return true; | ||
507 | + } | ||
508 | + // jichi 12/26/2013: Add this after alicehook | ||
509 | + if (IthCheckFile(L"AliceStart.ini")) { | ||
510 | + InsertSystem43Hook(); | ||
511 | + return true; | ||
512 | + } | ||
513 | + | ||
514 | + // jichi 8/24/2013: Move into functions | ||
515 | + static BYTE static_file_info[0x1000]; | ||
516 | + if (IthGetFileInfo(L"*01", static_file_info)) | ||
517 | + if (*(DWORD*)static_file_info == 0) { | ||
518 | + static WCHAR static_search_name[MAX_PATH]; | ||
519 | + LPWSTR name=(LPWSTR)(static_file_info+0x5E); | ||
520 | + int len = wcslen(name); | ||
521 | + name[len - 2] = L'*'; | ||
522 | + name[len - 1] = 0; | ||
523 | + wcscpy(static_search_name, name); | ||
524 | + IthGetFileInfo(static_search_name, static_file_info); | ||
525 | + union { | ||
526 | + FILE_BOTH_DIR_INFORMATION *both_info; | ||
527 | + DWORD addr; | ||
528 | + }; | ||
529 | + both_info = (FILE_BOTH_DIR_INFORMATION *)static_file_info; | ||
530 | + //BYTE* ptr=static_file_info; | ||
531 | + len = 0; | ||
532 | + while (both_info->NextEntryOffset) { | ||
533 | + addr += both_info->NextEntryOffset; | ||
534 | + len++; | ||
535 | + } | ||
536 | + if (len > 3) { | ||
537 | + InsertAbelHook(); | ||
538 | + return true; | ||
539 | + } | ||
540 | + } | ||
541 | + return false; | ||
542 | +} | ||
543 | + | ||
544 | +// jichi 8/17/2014 | ||
545 | +// Put the patterns that might break other games at last | ||
546 | +bool DetermineEngineAtLast() | ||
547 | +{ | ||
548 | + if (IthFindFile(L"data\\*.cpk")) { // jichi 12/2/2014 | ||
549 | + Insert5pbHook(); | ||
550 | + return true; | ||
551 | + } | ||
552 | + // jichi 7/6/2014: named as ScenarioPlayer since resource string could be: scenario player program for xxx | ||
553 | + // Do this at last as it is common | ||
554 | + if (IthFindFile(L"*.iar") && IthFindFile(L"*.sec5")) { // jichi 4/18/2014: Other game engine could also have *.iar such as Ryokucha | ||
555 | + InsertScenarioPlayerHook(); | ||
556 | + return true; | ||
557 | + } | ||
558 | + //if (IthCheckFile(L"arc0.dat") && IthCheckFile(L"script.dat") // jichi 11/14/2014: too common | ||
559 | + if (Util::SearchResourceString(L"HorkEye")) { // appear in copyright: Copyright (C) HorkEye, http://horkeye.com | ||
560 | + InsertHorkEyeHook(); | ||
561 | + return true; | ||
562 | + } | ||
563 | + if (IthCheckFile(L"comnArc.arc") // jichi 8/17/2014: this file might exist in multiple files | ||
564 | + && InsertNexton1Hook()) // old nexton game | ||
565 | + return true; | ||
566 | + if (IthCheckFile(L"arc.dat") // jichi 9/27/2014: too common | ||
567 | + && InsertApricoTHook()) | ||
568 | + return true; | ||
569 | + if (IthFindFile(L"*.pak") // jichi 12/25/2014: too common | ||
570 | + && InsertLeafHook()) | ||
571 | + return true; | ||
572 | + // jichi 10/31/2014 | ||
573 | + // File description: Adobe Flash Player 10.2r153 | ||
574 | + // Product name: Shockwave Flash | ||
575 | + // Original filename: SAFlashPlayer.exe | ||
576 | + // Legal trademarks: Adobe Flash Player | ||
577 | + // No idea why, this must appear at last or it will crash | ||
578 | + if (Util::SearchResourceString(L"Adobe Flash Player 10")) { | ||
579 | + InsertAdobeFlash10Hook(); // only v10 might be supported. Otherwise, fallback to Lstr hooks | ||
580 | + return true; | ||
581 | + } | ||
582 | + if (IthFindFile(L"dat\\*.arc")) { // jichi 2/6/2015 | ||
583 | + InsertFocasLensHook(); // Touhou | ||
584 | + return true; | ||
585 | + } | ||
586 | + return false; | ||
587 | +} | ||
588 | + | ||
589 | +// jichi 6/1/2014 | ||
590 | +bool DetermineEngineGeneric() | ||
591 | +{ | ||
592 | + bool ret = false; | ||
593 | + | ||
594 | + if (IthCheckFile(L"AlterEgo.exe")) { | ||
595 | + ConsoleOutput("vnreng: AlterEgo, INSERT WideChar hooks"); | ||
596 | + ret = true; | ||
597 | + } else if (IthFindFile(L"data\\Sky\\*")) { | ||
598 | + ConsoleOutput("vnreng: TEATIME, INSERT WideChar hooks"); | ||
599 | + ret = true; | ||
600 | + } | ||
601 | + //} else if (IthFindFile(L"image\\*.po2") || IthFindFile(L"image\\*.jo2")) { | ||
602 | + // ConsoleOutput("vnreng: HarukaKanata, INSERT WideChar hooks"); // はるかかなた | ||
603 | + // ret = true; | ||
604 | + //} | ||
605 | + if (ret) | ||
606 | + PcHooks::hookWcharFunctions(); | ||
607 | + return ret; | ||
608 | +} | ||
609 | + | ||
610 | +bool DetermineNoEngine() | ||
611 | +{ | ||
612 | + //if (IthFindFile(L"*\\Managed\\UnityEngine.dll")) { // jichi 12/3/2013: Unity (BALDRSKY ZERO) | ||
613 | + // ConsoleOutput("vnreng: IGNORE Unity"); | ||
614 | + // return true; | ||
615 | + //} | ||
616 | + //if (IthCheckFile(L"bsz_Data\\Managed\\UnityEngine.dll") || IthCheckFile(L"bsz2_Data\\Managed\\UnityEngine.dll")) { | ||
617 | + // ConsoleOutput("vnreng: IGNORE Unity"); | ||
618 | + // return true; | ||
619 | + //} | ||
620 | + | ||
621 | + // jichi 2/14/2015: Guilty+ RIN×SEN (PK) | ||
622 | + if (IthCheckFile(L"rio.ini") || IthFindFile(L"*.war")) { | ||
623 | + ConsoleOutput("vnreng: IGNORE unknown ShinaRio"); | ||
624 | + return true; | ||
625 | + } | ||
626 | + | ||
627 | + if (IthCheckFile(L"AdvHD.exe") || IthCheckFile(L"AdvHD.dll")) { | ||
628 | + ConsoleOutput("vnreng: IGNORE Adv Player HD"); | ||
629 | + return true; | ||
630 | + } | ||
631 | + | ||
632 | + if (IthCheckFile(L"ScrPlayer.exe")) { | ||
633 | + ConsoleOutput("vnreng: IGNORE ScrPlayer"); | ||
634 | + return true; | ||
635 | + } | ||
636 | + | ||
637 | + if (IthCheckFile(L"nnnConfig2.exe")) { | ||
638 | + ConsoleOutput("vnreng: IGNORE Nya NNNConfig"); | ||
639 | + return true; | ||
640 | + } | ||
641 | + | ||
642 | + //if (IthCheckFile(L"AGERC.DLL")) { // jichi 3/17/2014: Eushully, AGE.EXE | ||
643 | + // ConsoleOutput("vnreng: IGNORE Eushully"); | ||
644 | + // return true; | ||
645 | + //} | ||
646 | + | ||
647 | + if (IthCheckFile(L"game_sys.exe")) { | ||
648 | + ConsoleOutput("vnreng: IGNORE Atelier Kaguya BY/TH"); | ||
649 | + return true; | ||
650 | + } | ||
651 | + | ||
652 | + if (IthFindFile(L"*.bsa")) { | ||
653 | + ConsoleOutput("vnreng: IGNORE Bishop"); | ||
654 | + return true; | ||
655 | + } | ||
656 | + | ||
657 | + // jichi 3/19/2014: Escude game | ||
658 | + // Example: bgm.bin gfx.bin maou.bin script.bin snd.bin voc.bin | ||
659 | + if (IthCheckFile(L"gfx.bin") && IthCheckFile(L"snd.bin") && IthCheckFile(L"voc.bin")) { | ||
660 | + ConsoleOutput("vnreng: IGNORE Escude"); | ||
661 | + return true; | ||
662 | + } | ||
663 | + | ||
664 | + // jichi 2/18/2015: Ignore if there is Nitro+ copyright | ||
665 | + if (Util::SearchResourceString(L"Nitro+")) { | ||
666 | + ConsoleOutput("vnreng: IGNORE unknown Nitro+"); | ||
667 | + return true; | ||
668 | + } | ||
669 | + | ||
670 | + // jichi 12/28/2014: "Chartreux Inc." in Copyright. | ||
671 | + // Sublimary brands include Rosebleu, MORE, etc. | ||
672 | + // GetGlyphOutlineA already works. | ||
673 | + if (Util::SearchResourceString(L"Chartreux")) { | ||
674 | + ConsoleOutput("vnreng: IGNORE Chartreux"); | ||
675 | + return true; | ||
676 | + } | ||
677 | + | ||
678 | + if (wcsstr(process_name_, L"lcsebody") || !wcsncmp(process_name_, L"lcsebo~", 7) || IthCheckFile(L"lcsebody")) { // jichi 3/19/2014: LC-ScriptEngine, GetGlyphOutlineA | ||
679 | + ConsoleOutput("vnreng: IGNORE lcsebody"); | ||
680 | + return true; | ||
681 | + } | ||
682 | + | ||
683 | + wchar_t str[MAX_PATH]; | ||
684 | + DWORD i; | ||
685 | + for (i = 0; process_name_[i]; i++) { | ||
686 | + str[i] = process_name_[i]; | ||
687 | + if (process_name_[i] == L'.') | ||
688 | + break; | ||
689 | + } | ||
690 | + *(DWORD *)(str + i + 1) = 0x630068; //.hcb | ||
691 | + *(DWORD *)(str + i + 3) = 0x62; | ||
692 | + if (IthCheckFile(str)) { | ||
693 | + ConsoleOutput("vnreng: IGNORE FVP"); // jichi 10/3/2013: such like アトリエかぐや | ||
694 | + return true; | ||
695 | + } | ||
696 | + return false; | ||
697 | +} | ||
698 | + | ||
699 | +// 12/13/2013: Declare it in a way compatible to EXCEPTION_PROCEDURE | ||
700 | +EXCEPTION_DISPOSITION ExceptHandler(PEXCEPTION_RECORD ExceptionRecord, LPVOID, PCONTEXT, LPVOID) | ||
701 | +{ | ||
702 | + if (ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) { | ||
703 | + module_limit_ = ExceptionRecord->ExceptionInformation[1]; | ||
704 | + //OutputDWORD(module_limit_); | ||
705 | + __asm | ||
706 | + { | ||
707 | + mov eax,fs:[0x30] // jichi 12/13/2013: get PEB | ||
708 | + mov eax,[eax+0xc] | ||
709 | + mov eax,[eax+0xc] | ||
710 | + mov ecx,module_limit_ | ||
711 | + sub ecx,module_base_ | ||
712 | + mov [eax+0x20],ecx | ||
713 | + } | ||
714 | + } | ||
715 | + //ContextRecord->Esp = recv_esp; | ||
716 | + //ContextRecord->Eip = recv_eip; | ||
717 | + //return ExceptionContinueExecution; // jichi 3/11/2014: this will still crash. Not sure why ITH use this. Change to ExceptionContinueSearch | ||
718 | + return ExceptionContinueSearch; // an unwind is in progress, | ||
719 | +} | ||
720 | + | ||
721 | +// jichi 9/14/2013: Certain ITH functions like FindEntryAligned might raise exception without admin priv | ||
722 | +// Return if succeeded. | ||
723 | +bool UnsafeDetermineEngineType() | ||
724 | +{ | ||
725 | + return DeterminePCEngine() | ||
726 | + || DetermineEngineByFile1() | ||
727 | + || DetermineEngineByFile2() | ||
728 | + || DetermineEngineByFile3() | ||
729 | + || DetermineEngineByFile4() | ||
730 | + || DetermineEngineByProcessName() | ||
731 | + || DetermineEngineOther() | ||
732 | + || DetermineEngineAtLast() | ||
733 | + || DetermineEngineGeneric() | ||
734 | + || DetermineNoEngine() | ||
735 | + ; | ||
736 | +} | ||
737 | + | ||
738 | +// jichi 10/21/2014: Return whether found the game engine | ||
739 | +bool DetermineEngineType() | ||
740 | +{ | ||
741 | + // jichi 9/27/2013: disable game engine for debugging use | ||
742 | +#ifdef ITH_DISABLE_ENGINE | ||
743 | + PcHooks::hookLstrFunctions(); | ||
744 | + return false; | ||
745 | +#else | ||
746 | + bool found = false; | ||
747 | +#ifdef ITH_HAS_SEH | ||
748 | + __try { found = UnsafeDetermineEngineType(); } | ||
749 | + __except(ExceptHandler((GetExceptionInformation())->ExceptionRecord, 0, 0, 0)) {} | ||
750 | +#else // use my own SEH | ||
751 | + seh_with_eh(ExceptHandler, | ||
752 | + found = UnsafeDetermineEngineType()); | ||
753 | +#endif // ITH_HAS_SEH | ||
754 | + if (!found) // jichi 10/2/2013: Only enable it if no game engine is detected | ||
755 | + PcHooks::hookLstrFunctions(); | ||
756 | + else | ||
757 | + ConsoleOutput("vnreng: found game engine, IGNORE non gui hooks"); | ||
758 | + return found; | ||
759 | +#endif // ITH_DISABLE_ENGINE | ||
760 | +} | ||
761 | + | ||
762 | +// __asm | ||
763 | +// { | ||
764 | +// mov eax,seh_recover | ||
765 | +// mov recv_eip,eax | ||
766 | +// push ExceptHandler | ||
767 | +// push fs:[0] | ||
768 | +// mov fs:[0],esp | ||
769 | +// pushad | ||
770 | +// mov recv_esp,esp | ||
771 | +// } | ||
772 | +// DetermineEngineType(); | ||
773 | +// status++; | ||
774 | +// __asm | ||
775 | +// { | ||
776 | +//seh_recover: | ||
777 | +// popad | ||
778 | +// mov eax,[esp] | ||
779 | +// mov fs:[0],eax | ||
780 | +// add esp,8 | ||
781 | +// } | ||
782 | +// if (status == 0) | ||
783 | +// ConsoleOutput("Fail to identify engine type."); | ||
784 | +// else | ||
785 | +// ConsoleOutput("Initialized successfully."); | ||
786 | +//} | ||
787 | + | ||
788 | +}} // namespace Engine unnamed | ||
789 | + | ||
790 | +// - API - | ||
791 | + | ||
792 | +bool Engine::IdentifyEngine() | ||
793 | +{ | ||
794 | + // jichi 12/18/2013: Though FillRange could raise, it should never raise for he current process | ||
795 | + // So, SEH is not used here. | ||
796 | + FillRange(process_name_, &module_base_, &module_limit_); | ||
797 | + return DetermineEngineType(); | ||
798 | +} | ||
799 | + | ||
800 | +DWORD Engine::InsertDynamicHook(LPVOID addr, DWORD frame, DWORD stack) | ||
801 | +{ return trigger_fun_ ? !trigger_fun_(addr, frame, stack) : 0; } | ||
802 | + | ||
803 | +void Engine::match(LPVOID lpThreadParameter) | ||
804 | +{ | ||
805 | + CC_UNUSED(lpThreadParameter); | ||
806 | + Util::GetProcessName(process_name_); // Initialize process name | ||
807 | + Util::GetProcessPath(process_path_); // Initialize process path | ||
808 | + ::engine_registered = true; | ||
809 | + //::RegisterEngineModule((DWORD)IdentifyEngine, (DWORD)InsertDynamicHook); | ||
810 | +} | ||
811 | + | ||
812 | +// EOF | ||
813 | + | ||
814 | +/* | ||
815 | +extern "C" { | ||
816 | + // http://gmogre3d.googlecode.com/svn-history/r815/trunk/OgreMain/src/WIN32/OgreMinGWSupport.cpp | ||
817 | + // http://forum.osdev.org/viewtopic.php?f=8&t=22352 | ||
818 | + //#pragma data_seg() | ||
819 | + //#pragma comment(linker, "/merge:.CRT=.data") // works fine in visual c++ 6 | ||
820 | + //#pragma data_seg() | ||
821 | + //#pragma comment(linker, "/merge:.CRT=.rdata") | ||
822 | + // MSVC libs use _chkstk for stack-probing. MinGW equivalent is _alloca. | ||
823 | + //void _alloca(); | ||
824 | + //void _chkstk() { _alloca(); } | ||
825 | + | ||
826 | + // MSVC uses security cookies to prevent some buffer overflow attacks. | ||
827 | + // provide dummy implementations. | ||
828 | + //void _fastcall __security_check_cookie(intptr_t i) {} | ||
829 | + void __declspec(naked) __fastcall __security_check_cookie(UINT_PTR cookie) {} | ||
830 | +} | ||
831 | +*/ |
vnr/ith/hook/engine/match.h
0 → 100644
1 | +#pragma once | ||
2 | + | ||
3 | +// engine/match.h | ||
4 | +// 8/23/2013 jichi | ||
5 | +// TODO: Clean up the interface to match game engines. | ||
6 | +// Split the engine match logic out of hooks. | ||
7 | +// Modify the game hook to allow replace functions for arbitary purpose | ||
8 | +// instead of just extracting text. | ||
9 | + | ||
10 | +#include "config.h" | ||
11 | + | ||
12 | +namespace Engine { | ||
13 | + | ||
14 | +void match(LPVOID lpThreadParameter); | ||
15 | + | ||
16 | +// jichi 10/21/2014: Return whether found the engine | ||
17 | +bool IdentifyEngine(); | ||
18 | + | ||
19 | +// jichi 10/21/2014: Return 0 if failed | ||
20 | +DWORD InsertDynamicHook(LPVOID addr, DWORD frame, DWORD stack); | ||
21 | + | ||
22 | +} // namespace Engine | ||
23 | + | ||
24 | +// EOF |
vnr/ith/hook/engine/pchooks.cc
0 → 100644
1 | +// pchooks.cc | ||
2 | +// 8/1/2014 jichi | ||
3 | + | ||
4 | +#include "engine/pchooks.h" | ||
5 | +#include "hook.h" | ||
6 | + | ||
7 | +#define DEBUG "vnrcli" | ||
8 | +#define DPRINT(cstr) ConsoleOutput(DEBUG ":" __FUNCTION__ ":" cstr) // defined in vnrcli | ||
9 | + | ||
10 | +// 8/1/2014 jichi: Split is not used. | ||
11 | +// Although split is specified, USING_SPLIT is not assigned. | ||
12 | + | ||
13 | +// Use LPASTE to convert to wchar_t | ||
14 | +// http://bytes.com/topic/c/answers/135834-defining-wide-character-strings-macros | ||
15 | +#define LPASTE(s) L##s | ||
16 | +#define L(s) LPASTE(s) | ||
17 | +#define NEW_HOOK(_fun, _data, _data_ind, _split_off, _split_ind, _type, _len_off) \ | ||
18 | + { \ | ||
19 | + HookParam hp = {}; \ | ||
20 | + hp.addr = (DWORD)_fun; \ | ||
21 | + hp.off = _data; \ | ||
22 | + hp.ind = _data_ind; \ | ||
23 | + hp.split = _split_off; \ | ||
24 | + hp.split_ind = _split_ind; \ | ||
25 | + hp.type = _type; \ | ||
26 | + hp.length_offset = _len_off; \ | ||
27 | + NewHook(hp, L(#_fun)); \ | ||
28 | + } | ||
29 | + | ||
30 | +// jichi 7/17/2014: Renamed from InitDefaultHook | ||
31 | +void PcHooks::hookGDIFunctions() | ||
32 | +{ | ||
33 | + DPRINT("enter"); | ||
34 | + // int TextHook::InitHook(LPVOID addr, DWORD data, DWORD data_ind, DWORD split_off, DWORD split_ind, WORD type, DWORD len_off) | ||
35 | + // | ||
36 | + // jichi 9/8/2013: Guessed meaning | ||
37 | + // - data(off): 4 * the n-th (base 1) parameter representing the data of the string | ||
38 | + // - len_off: | ||
39 | + // - the n-th (base 1) parameter representing the length of the string | ||
40 | + // - or 1 if is char | ||
41 | + // - or 0 if detect on run time | ||
42 | + // - type: USING_STRING if len_off != 1 else BIG_ENDIAN or USING_UNICODE | ||
43 | + // | ||
44 | + // Examples: | ||
45 | + // int WINAPI lstrlenA(LPCSTR lpString) | ||
46 | + // - data: 4 * 1 = 4, as lpString is the first | ||
47 | + // - len_off: 0, as no parameter representing string length | ||
48 | + // - type: BIG_ENDIAN, since len_off == 1 | ||
49 | + // BOOL GetTextExtentPoint32(HDC hdc, LPCTSTR lpString, int c, LPSIZE lpSize); | ||
50 | + // - data: 4 * 2 = 0x8, as lpString is the second | ||
51 | + // - len_off: 3, as nCount is the 3rd parameter | ||
52 | + // - type: USING_STRING, since len_off != 1 | ||
53 | + // | ||
54 | + // Note: All functions does not have NO_CONTEXT attribute and will be filtered. | ||
55 | + | ||
56 | + enum stack { | ||
57 | + s_retaddr = 0 | ||
58 | + , s_arg1 = 4 * 1 // 0x4 | ||
59 | + , s_arg2 = 4 * 2 // 0x8 | ||
60 | + , s_arg3 = 4 * 3 // 0xc | ||
61 | + , s_arg4 = 4 * 4 // 0x10 | ||
62 | + , s_arg5 = 4 * 5 // 0x14 | ||
63 | + , s_arg6 = 4 * 6 // 0x18 | ||
64 | + }; | ||
65 | + | ||
66 | +//#define _(Name, ...) \ | ||
67 | +// hookman[HF_##Name].InitHook(Name, __VA_ARGS__); \ | ||
68 | +// hookman[HF_##Name].SetHookName(names[HF_##Name]); | ||
69 | + | ||
70 | + // Always use s_arg1 = hDC as split_off | ||
71 | + // 7/26/2014 jichi: Why there is no USING_SPLIT type? | ||
72 | + | ||
73 | + // gdi32.dll | ||
74 | + NEW_HOOK(GetTextExtentPoint32A, s_arg2, 0,s_arg1,0, USING_STRING, 3) // BOOL GetTextExtentPoint32(HDC hdc, LPCTSTR lpString, int c, LPSIZE lpSize); | ||
75 | + 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); | ||
76 | + 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); | ||
77 | + NEW_HOOK(TextOutA, s_arg4, 0,s_arg1,0, USING_STRING, 5) // BOOL TextOut(HDC hdc, int nXStart, int nYStart, LPCTSTR lpString, int cchString); | ||
78 | + NEW_HOOK(GetCharABCWidthsA, s_arg2, 0,s_arg1,0, BIG_ENDIAN, 1) // BOOL GetCharABCWidths(HDC hdc, UINT uFirstChar, UINT uLastChar, LPABC lpabc); | ||
79 | + NEW_HOOK(GetTextExtentPoint32W, s_arg2, 0,s_arg1,0, USING_UNICODE|USING_STRING, 3) | ||
80 | + NEW_HOOK(GetGlyphOutlineW, s_arg2, 0,s_arg1,0, USING_UNICODE, 1) | ||
81 | + NEW_HOOK(ExtTextOutW, s_arg6, 0,s_arg1,0, USING_UNICODE|USING_STRING, 7) | ||
82 | + NEW_HOOK(TextOutW, s_arg4, 0,s_arg1,0, USING_UNICODE|USING_STRING, 5) | ||
83 | + NEW_HOOK(GetCharABCWidthsW, s_arg2, 0,s_arg1,0, USING_UNICODE, 1) | ||
84 | + | ||
85 | + // user32.dll | ||
86 | + NEW_HOOK(DrawTextA, s_arg2, 0,s_arg1,0, USING_STRING, 3) // int DrawText(HDC hDC, LPCTSTR lpchText, int nCount, LPRECT lpRect, UINT uFormat); | ||
87 | + 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); | ||
88 | + NEW_HOOK(DrawTextW, s_arg2, 0,s_arg1,0, USING_UNICODE|USING_STRING, 3) | ||
89 | + NEW_HOOK(DrawTextExW, s_arg2, 0,s_arg1,0, USING_UNICODE|USING_STRING, 3) | ||
90 | +//#undef _ | ||
91 | + DPRINT("leave"); | ||
92 | +} | ||
93 | + | ||
94 | +// jichi 10/2/2013 | ||
95 | +// Note: All functions does not have NO_CONTEXT attribute and will be filtered. | ||
96 | +void PcHooks::hookLstrFunctions() | ||
97 | +{ | ||
98 | + DPRINT("enter"); | ||
99 | + // int TextHook::InitHook(LPVOID addr, DWORD data, DWORD data_ind, DWORD split_off, DWORD split_ind, WORD type, DWORD len_off) | ||
100 | + | ||
101 | + enum stack { | ||
102 | + s_retaddr = 0 | ||
103 | + , s_arg1 = 4 * 1 // 0x4 | ||
104 | + //, s_arg2 = 4 * 2 // 0x8 | ||
105 | + //, s_arg3 = 4 * 3 // 0xc | ||
106 | + //, s_arg4 = 4 * 4 // 0x10 | ||
107 | + //, s_arg5 = 4 * 5 // 0x14 | ||
108 | + //, s_arg6 = 4 * 6 // 0x18 | ||
109 | + }; | ||
110 | + | ||
111 | + // http://msdn.microsoft.com/en-us/library/78zh94ax.aspx | ||
112 | + // int WINAPI lstrlen(LPCTSTR lpString); | ||
113 | + // Lstr functions usually extracts rubbish, and might crash certain games like 「Magical Marriage Lunatics!!」 | ||
114 | + // Needed by Gift | ||
115 | + // Use arg1 address for both split and data | ||
116 | + NEW_HOOK(lstrlenA, s_arg1, 0,s_arg1,0, USING_STRING, 0) // 9/8/2013 jichi: int WINAPI lstrlen(LPCTSTR lpString); | ||
117 | + NEW_HOOK(lstrlenW, s_arg1, 0,s_arg1,0, USING_UNICODE|USING_STRING, 0) // 9/8/2013 jichi: add lstrlen | ||
118 | + | ||
119 | + // size_t strlen(const char *str); | ||
120 | + // size_t strlen_l(const char *str, _locale_t locale); | ||
121 | + // size_t wcslen(const wchar_t *str); | ||
122 | + // size_t wcslen_l(const wchar_t *str, _locale_t locale); | ||
123 | + // size_t _mbslen(const unsigned char *str); | ||
124 | + // size_t _mbslen_l(const unsigned char *str, _locale_t locale); | ||
125 | + // size_t _mbstrlen(const char *str); | ||
126 | + // size_t _mbstrlen_l(const char *str, _locale_t locale); | ||
127 | + | ||
128 | + // http://msdn.microsoft.com/en-us/library/ex0hs2ad.aspx | ||
129 | + // Needed by 娘姉妹 | ||
130 | + // | ||
131 | + // <tchar.h> | ||
132 | + // char *_strinc(const char *current, _locale_t locale); | ||
133 | + // wchar_t *_wcsinc(const wchar_t *current, _locale_t locale); | ||
134 | + // <mbstring.h> | ||
135 | + // unsigned char *_mbsinc(const unsigned char *current); | ||
136 | + // unsigned char *_mbsinc_l(const unsigned char *current, _locale_t locale); | ||
137 | + //_(L"_strinc", _strinc, 4, 0,4,0, USING_STRING, 0) // 12/13/2013 jichi | ||
138 | + //_(L"_wcsinc", _wcsinc, 4, 0,4,0, USING_UNICODE|USING_STRING, 0) | ||
139 | + DPRINT("leave"); | ||
140 | +} | ||
141 | + | ||
142 | +void PcHooks::hookWcharFunctions() | ||
143 | +{ | ||
144 | + DPRINT("enter"); | ||
145 | + // 12/1/2013 jichi: | ||
146 | + // AlterEgo | ||
147 | + // http://tieba.baidu.com/p/2736475133 | ||
148 | + // http://www.hongfire.com/forum/showthread.php/36807-AGTH-text-extraction-tool-for-games-translation/page355 | ||
149 | + // | ||
150 | + // MultiByteToWideChar | ||
151 | + // http://blgames.proboards.com/thread/265 | ||
152 | + // | ||
153 | + // WideCharToMultiByte | ||
154 | + // http://www.hongfire.com/forum/showthread.php/36807-AGTH-text-extraction-tool-for-games-translation/page156 | ||
155 | + // | ||
156 | + // int MultiByteToWideChar( | ||
157 | + // _In_ UINT CodePage, | ||
158 | + // _In_ DWORD dwFlags, | ||
159 | + // _In_ LPCSTR lpMultiByteStr, // hook here | ||
160 | + // _In_ int cbMultiByte, | ||
161 | + // _Out_opt_ LPWSTR lpWideCharStr, | ||
162 | + // _In_ int cchWideChar | ||
163 | + // ); | ||
164 | + // int WideCharToMultiByte( | ||
165 | + // _In_ UINT CodePage, | ||
166 | + // _In_ DWORD dwFlags, | ||
167 | + // _In_ LPCWSTR lpWideCharStr, | ||
168 | + // _In_ int cchWideChar, | ||
169 | + // _Out_opt_ LPSTR lpMultiByteStr, | ||
170 | + // _In_ int cbMultiByte, | ||
171 | + // _In_opt_ LPCSTR lpDefaultChar, | ||
172 | + // _Out_opt_ LPBOOL lpUsedDefaultChar | ||
173 | + // ); | ||
174 | + | ||
175 | + enum stack { | ||
176 | + s_retaddr = 0 | ||
177 | + //, s_arg1 = 4 * 1 // 0x4 | ||
178 | + //, s_arg2 = 4 * 2 // 0x8 | ||
179 | + , s_arg3 = 4 * 3 // 0xc | ||
180 | + //, s_arg4 = 4 * 4 // 0x10 | ||
181 | + //, s_arg5 = 4 * 5 // 0x14 | ||
182 | + //, s_arg6 = 4 * 6 // 0x18 | ||
183 | + }; | ||
184 | + | ||
185 | + // 3/17/2014 jichi: Temporarily disabled | ||
186 | + // http://sakuradite.com/topic/159 | ||
187 | + NEW_HOOK(MultiByteToWideChar, s_arg3, 0,4,0, USING_STRING, 4) | ||
188 | + NEW_HOOK(WideCharToMultiByte, s_arg3, 0,4,0, USING_UNICODE|USING_STRING, 4) | ||
189 | + DPRINT("leave"); | ||
190 | +} | ||
191 | + | ||
192 | +// EOF |
vnr/ith/hook/engine/pchooks.h
0 → 100644
vnr/ith/hook/engine/util.cc
0 → 100644
1 | +// util/util.cc | ||
2 | +// 8/23/2013 jichi | ||
3 | +// Branch: ITH_Engine/engine.cpp, revision 133 | ||
4 | +// See: http://ja.wikipedia.org/wiki/プロジェクト:美少女ゲーム系/ゲームエンジン | ||
5 | + | ||
6 | +#include "engine/util.h" | ||
7 | +#include "ith/sys/sys.h" | ||
8 | + | ||
9 | +namespace { // unnamed | ||
10 | + | ||
11 | +// jichi 4/19/2014: Return the integer that can mask the signature | ||
12 | +DWORD SigMask(DWORD sig) | ||
13 | +{ | ||
14 | + __asm | ||
15 | + { | ||
16 | + xor ecx,ecx | ||
17 | + mov eax,sig | ||
18 | +_mask: | ||
19 | + shr eax,8 | ||
20 | + inc ecx | ||
21 | + test eax,eax | ||
22 | + jnz _mask | ||
23 | + sub ecx,4 | ||
24 | + neg ecx | ||
25 | + or eax,-1 | ||
26 | + shl ecx,3 | ||
27 | + shr eax,cl | ||
28 | + } | ||
29 | +} | ||
30 | + | ||
31 | +} // namespace unnamed | ||
32 | + | ||
33 | +// jichi 8/24/2013: binary search? | ||
34 | +DWORD Util::GetCodeRange(DWORD hModule,DWORD *low, DWORD *high) | ||
35 | +{ | ||
36 | + IMAGE_DOS_HEADER *DosHdr; | ||
37 | + IMAGE_NT_HEADERS *NtHdr; | ||
38 | + DWORD dwReadAddr; | ||
39 | + IMAGE_SECTION_HEADER *shdr; | ||
40 | + DosHdr = (IMAGE_DOS_HEADER *)hModule; | ||
41 | + if (IMAGE_DOS_SIGNATURE == DosHdr->e_magic) { | ||
42 | + dwReadAddr = hModule + DosHdr->e_lfanew; | ||
43 | + NtHdr = (IMAGE_NT_HEADERS *)dwReadAddr; | ||
44 | + if (IMAGE_NT_SIGNATURE == NtHdr->Signature) { | ||
45 | + shdr = (PIMAGE_SECTION_HEADER)((DWORD)(&NtHdr->OptionalHeader) + NtHdr->FileHeader.SizeOfOptionalHeader); | ||
46 | + while ((shdr->Characteristics & IMAGE_SCN_CNT_CODE) == 0) | ||
47 | + shdr++; | ||
48 | + *low = hModule + shdr->VirtualAddress; | ||
49 | + *high = *low + (shdr->Misc.VirtualSize & 0xfffff000) + 0x1000; | ||
50 | + } | ||
51 | + } | ||
52 | + return 0; | ||
53 | +} | ||
54 | + | ||
55 | +DWORD Util::FindCallAndEntryBoth(DWORD fun, DWORD size, DWORD pt, DWORD sig) | ||
56 | +{ | ||
57 | + //WCHAR str[0x40]; | ||
58 | + enum { reverse_length = 0x800 }; | ||
59 | + DWORD t, l; | ||
60 | + DWORD mask = SigMask(sig); | ||
61 | + bool flag2; | ||
62 | + for (DWORD i = 0x1000; i < size-4; i++) { | ||
63 | + bool flag1 = false; | ||
64 | + if (*(BYTE *)(pt + i) == 0xe8) { | ||
65 | + flag1 = flag2 = true; | ||
66 | + t = *(DWORD *)(pt + i + 1); | ||
67 | + } else if (*(WORD *)(pt + i) == 0x15ff) { | ||
68 | + flag1 = true; | ||
69 | + flag2 = false; | ||
70 | + t = *(DWORD *)(pt + i + 2); | ||
71 | + } | ||
72 | + if (flag1) { | ||
73 | + if (flag2) { | ||
74 | + flag1 = (pt + i + 5 + t == fun); | ||
75 | + l = 5; | ||
76 | + } else if (t >= pt && t <= pt + size - 4) { | ||
77 | + flag1 = fun == *(DWORD *)t; | ||
78 | + l = 6; | ||
79 | + } else | ||
80 | + flag1 = false; | ||
81 | + if (flag1) | ||
82 | + //swprintf(str,L"CALL addr: 0x%.8X",pt + i); | ||
83 | + //OutputConsole(str); | ||
84 | + for (DWORD j = i; j > i - reverse_length; j--) | ||
85 | + if ((*(WORD *)(pt + j)) == (sig & mask)) //Fun entry 1. | ||
86 | + //swprintf(str,L"Entry: 0x%.8X",pt + j); | ||
87 | + //OutputConsole(str); | ||
88 | + return pt + j; | ||
89 | + else | ||
90 | + i += l; | ||
91 | + } | ||
92 | + } | ||
93 | + //OutputConsole(L"Find call and entry failed."); | ||
94 | + return 0; | ||
95 | +} | ||
96 | + | ||
97 | +DWORD Util::FindCallOrJmpRel(DWORD fun, DWORD size, DWORD pt, bool jmp) | ||
98 | +{ | ||
99 | + BYTE sig = (jmp) ? 0xe9 : 0xe8; | ||
100 | + for (DWORD i = 0x1000; i < size - 4; i++) | ||
101 | + if (sig == *(BYTE *)(pt + i)) { | ||
102 | + DWORD t = *(DWORD *)(pt + i + 1); | ||
103 | + if(fun == pt + i + 5 + t) | ||
104 | + //OutputDWORD(pt + i); | ||
105 | + return pt + i; | ||
106 | + else | ||
107 | + i += 5; | ||
108 | + } | ||
109 | + return 0; | ||
110 | +} | ||
111 | + | ||
112 | +DWORD Util::FindCallOrJmpAbs(DWORD fun, DWORD size, DWORD pt, bool jmp) | ||
113 | +{ | ||
114 | + WORD sig = jmp ? 0x25ff : 0x15ff; | ||
115 | + for (DWORD i = 0x1000; i < size - 4; i++) | ||
116 | + if (sig == *(WORD *)(pt + i)) { | ||
117 | + DWORD t = *(DWORD *)(pt + i + 2); | ||
118 | + if (t > pt && t < pt + size) { | ||
119 | + if (fun == *(DWORD *)t) | ||
120 | + return pt + i; | ||
121 | + else | ||
122 | + i += 5; | ||
123 | + } | ||
124 | + } | ||
125 | + return 0; | ||
126 | +} | ||
127 | + | ||
128 | +DWORD Util::FindCallBoth(DWORD fun, DWORD size, DWORD pt) | ||
129 | +{ | ||
130 | + for (DWORD i = 0x1000; i < size - 4; i++) { | ||
131 | + if (*(BYTE *)(pt + i) == 0xe8) { | ||
132 | + DWORD t = *(DWORD *)(pt + i + 1) + pt + i + 5; | ||
133 | + if (t == fun) | ||
134 | + return i; | ||
135 | + } | ||
136 | + if (*(WORD *)(pt + i) == 0x15ff) { | ||
137 | + DWORD t = *(DWORD *)(pt + i + 2); | ||
138 | + if (t >= pt && t <= pt + size - 4) { | ||
139 | + if (*(DWORD *)t == fun) | ||
140 | + return i; | ||
141 | + else | ||
142 | + i += 6; | ||
143 | + } | ||
144 | + } | ||
145 | + } | ||
146 | + return 0; | ||
147 | +} | ||
148 | + | ||
149 | +DWORD Util::FindCallAndEntryAbs(DWORD fun, DWORD size, DWORD pt, DWORD sig) | ||
150 | +{ | ||
151 | + //WCHAR str[0x40]; | ||
152 | + enum { reverse_length = 0x800 }; | ||
153 | + DWORD mask = SigMask(sig); | ||
154 | + for (DWORD i = 0x1000; i < size - 4; i++) | ||
155 | + if (*(WORD *)(pt + i) == 0x15ff) { | ||
156 | + DWORD t = *(DWORD *)(pt + i + 2); | ||
157 | + if (t >= pt && t <= pt + size - 4) { | ||
158 | + if (*(DWORD *)t == fun) | ||
159 | + //swprintf(str,L"CALL addr: 0x%.8X",pt + i); | ||
160 | + //OutputConsole(str); | ||
161 | + for (DWORD j = i ; j > i - reverse_length; j--) | ||
162 | + if ((*(DWORD *)(pt + j) & mask) == sig) // Fun entry 1. | ||
163 | + //swprintf(str,L"Entry: 0x%.8X",pt + j); | ||
164 | + //OutputConsole(str); | ||
165 | + return pt + j; | ||
166 | + | ||
167 | + } else | ||
168 | + i += 6; | ||
169 | + } | ||
170 | + //OutputConsole(L"Find call and entry failed."); | ||
171 | + return 0; | ||
172 | +} | ||
173 | + | ||
174 | +DWORD Util::FindCallAndEntryRel(DWORD fun, DWORD size, DWORD pt, DWORD sig) | ||
175 | +{ | ||
176 | + //WCHAR str[0x40]; | ||
177 | + enum { reverse_length = 0x800 }; | ||
178 | + if (DWORD i = FindCallOrJmpRel(fun, size, pt, false)) { | ||
179 | + DWORD mask = SigMask(sig); | ||
180 | + for (DWORD j = i; j > i - reverse_length; j--) | ||
181 | + if (((*(DWORD *)j) & mask) == sig) //Fun entry 1. | ||
182 | + //swprintf(str,L"Entry: 0x%.8X",j); | ||
183 | + //OutputConsole(str); | ||
184 | + return j; | ||
185 | + //OutputConsole(L"Find call and entry failed."); | ||
186 | + } | ||
187 | + return 0; | ||
188 | +} | ||
189 | +DWORD Util::FindEntryAligned(DWORD start, DWORD back_range) | ||
190 | +{ | ||
191 | + start &= ~0xf; | ||
192 | + for (DWORD i = start, j = start - back_range; i > j; i-=0x10) { | ||
193 | + DWORD k = *(DWORD *)(i-4); | ||
194 | + if (k == 0xcccccccc | ||
195 | + || k == 0x90909090 | ||
196 | + || k == 0xccccccc3 | ||
197 | + || k == 0x909090c3 | ||
198 | + ) | ||
199 | + return i; | ||
200 | + DWORD t = k & 0xff0000ff; | ||
201 | + if (t == 0xcc0000c2 || t == 0x900000c2) | ||
202 | + return i; | ||
203 | + k >>= 8; | ||
204 | + if (k == 0xccccc3 || k == 0x9090c3) | ||
205 | + return i; | ||
206 | + t = k & 0xff; | ||
207 | + if (t == 0xc2) | ||
208 | + return i; | ||
209 | + k >>= 8; | ||
210 | + if (k == 0xccc3 || k == 0x90c3) | ||
211 | + return i; | ||
212 | + k >>= 8; | ||
213 | + if (k == 0xc3) | ||
214 | + return i; | ||
215 | + } | ||
216 | + return 0; | ||
217 | +} | ||
218 | + | ||
219 | +DWORD Util::FindImportEntry(DWORD hModule, DWORD fun) | ||
220 | +{ | ||
221 | + IMAGE_DOS_HEADER *DosHdr; | ||
222 | + IMAGE_NT_HEADERS *NtHdr; | ||
223 | + DWORD IAT, end, pt, addr; | ||
224 | + DosHdr = (IMAGE_DOS_HEADER *)hModule; | ||
225 | + if (IMAGE_DOS_SIGNATURE == DosHdr->e_magic) { | ||
226 | + NtHdr = (IMAGE_NT_HEADERS *)(hModule + DosHdr->e_lfanew); | ||
227 | + if (IMAGE_NT_SIGNATURE == NtHdr->Signature) { | ||
228 | + IAT = NtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress; | ||
229 | + end = NtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size; | ||
230 | + IAT += hModule; | ||
231 | + end += IAT; | ||
232 | + for (pt = IAT; pt < end; pt += 4) { | ||
233 | + addr = *(DWORD *)pt; | ||
234 | + if (addr == fun) | ||
235 | + return pt; | ||
236 | + } | ||
237 | + } | ||
238 | + } | ||
239 | + return 0; | ||
240 | +} | ||
241 | + | ||
242 | +// Search string in rsrc section. This section usually contains version and copyright info. | ||
243 | +bool Util::SearchResourceString(LPCWSTR str) | ||
244 | +{ | ||
245 | + DWORD hModule = Util::GetModuleBase(); | ||
246 | + IMAGE_DOS_HEADER *DosHdr; | ||
247 | + IMAGE_NT_HEADERS *NtHdr; | ||
248 | + DosHdr = (IMAGE_DOS_HEADER *)hModule; | ||
249 | + DWORD rsrc, size; | ||
250 | + //__asm int 3 | ||
251 | + if (IMAGE_DOS_SIGNATURE == DosHdr->e_magic) { | ||
252 | + NtHdr = (IMAGE_NT_HEADERS *)(hModule + DosHdr->e_lfanew); | ||
253 | + if (IMAGE_NT_SIGNATURE == NtHdr->Signature) { | ||
254 | + rsrc = NtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; | ||
255 | + if (rsrc) { | ||
256 | + rsrc += hModule; | ||
257 | + if (IthGetMemoryRange((LPVOID)rsrc, &rsrc ,&size) && | ||
258 | + SearchPattern(rsrc, size - 4, str, wcslen(str) << 1)) | ||
259 | + return true; | ||
260 | + } | ||
261 | + } | ||
262 | + } | ||
263 | + return false; | ||
264 | +} | ||
265 | + | ||
266 | +// jichi 4/15/2014: Copied from GetModuleBase in ITH CLI, for debugging purpose | ||
267 | +DWORD Util::FindModuleBase(DWORD hash) | ||
268 | +{ | ||
269 | + __asm | ||
270 | + { | ||
271 | + mov eax,fs:[0x30] | ||
272 | + mov eax,[eax+0xc] | ||
273 | + mov esi,[eax+0x14] | ||
274 | + mov edi,_wcslwr | ||
275 | +listfind: | ||
276 | + mov edx,[esi+0x28] | ||
277 | + test edx,edx | ||
278 | + jz notfound | ||
279 | + push edx | ||
280 | + call edi | ||
281 | + pop edx | ||
282 | + xor eax,eax | ||
283 | +calc: | ||
284 | + movzx ecx, word ptr [edx] | ||
285 | + test cl,cl | ||
286 | + jz fin | ||
287 | + ror eax,7 | ||
288 | + add eax,ecx | ||
289 | + add edx,2 | ||
290 | + jmp calc | ||
291 | +fin: | ||
292 | + cmp eax,[hash] | ||
293 | + je found | ||
294 | + mov esi,[esi] | ||
295 | + jmp listfind | ||
296 | +notfound: | ||
297 | + xor eax,eax | ||
298 | + jmp termin | ||
299 | +found: | ||
300 | + mov eax,[esi+0x10] | ||
301 | +termin: | ||
302 | + } | ||
303 | +} | ||
304 | + | ||
305 | +// EOF |
vnr/ith/hook/engine/util.h
0 → 100644
1 | +#pragma once | ||
2 | + | ||
3 | +// util/util.h | ||
4 | +// 8/23/2013 jichi | ||
5 | + | ||
6 | +#include "config.h" | ||
7 | + | ||
8 | +namespace Util { | ||
9 | + | ||
10 | +DWORD GetCodeRange(DWORD hModule,DWORD *low, DWORD *high); | ||
11 | +DWORD FindCallAndEntryBoth(DWORD fun, DWORD size, DWORD pt, DWORD sig); | ||
12 | +DWORD FindCallOrJmpRel(DWORD fun, DWORD size, DWORD pt, bool jmp); | ||
13 | +DWORD FindCallOrJmpAbs(DWORD fun, DWORD size, DWORD pt, bool jmp); | ||
14 | +DWORD FindCallBoth(DWORD fun, DWORD size, DWORD pt); | ||
15 | +DWORD FindCallAndEntryAbs(DWORD fun, DWORD size, DWORD pt, DWORD sig); | ||
16 | +DWORD FindCallAndEntryRel(DWORD fun, DWORD size, DWORD pt, DWORD sig); | ||
17 | +DWORD FindEntryAligned(DWORD start, DWORD back_range); | ||
18 | +DWORD FindImportEntry(DWORD hModule, DWORD fun); | ||
19 | + | ||
20 | +// jichi 4/15/2014: Copied from ITH CLI, for debugging purpose | ||
21 | +DWORD FindModuleBase(DWORD hash); | ||
22 | + | ||
23 | +bool SearchResourceString(LPCWSTR str); | ||
24 | + | ||
25 | +/** | ||
26 | + * @param name process name without path deliminator | ||
27 | + */ | ||
28 | +inline void GetProcessName(wchar_t *name) | ||
29 | +{ | ||
30 | + //assert(name); | ||
31 | + PLDR_DATA_TABLE_ENTRY it; | ||
32 | + __asm | ||
33 | + { | ||
34 | + mov eax,fs:[0x30] | ||
35 | + mov eax,[eax+0xc] | ||
36 | + mov eax,[eax+0xc] | ||
37 | + mov it,eax | ||
38 | + } | ||
39 | + ::wcscpy(name, it->BaseDllName.Buffer); | ||
40 | +} | ||
41 | + | ||
42 | +/** | ||
43 | + * @param path with process name and directy name | ||
44 | + */ | ||
45 | +inline void GetProcessPath(wchar_t *path) | ||
46 | +{ | ||
47 | + //assert(path); | ||
48 | + PLDR_DATA_TABLE_ENTRY it; | ||
49 | + __asm | ||
50 | + { | ||
51 | + mov eax,fs:[0x30] | ||
52 | + mov eax,[eax+0xc] | ||
53 | + mov eax,[eax+0xc] | ||
54 | + mov it,eax | ||
55 | + } | ||
56 | + ::wcscpy(path, it->FullDllName.Buffer); | ||
57 | +} | ||
58 | + | ||
59 | +/** | ||
60 | + * @return HANDLE module handle | ||
61 | + */ | ||
62 | +inline DWORD GetModuleBase() | ||
63 | +{ | ||
64 | + __asm | ||
65 | + { | ||
66 | + mov eax,fs:[0x18] | ||
67 | + mov eax,[eax+0x30] | ||
68 | + mov eax,[eax+0xc] | ||
69 | + mov eax,[eax+0xc] | ||
70 | + mov eax,[eax+0x18] | ||
71 | + } | ||
72 | +} | ||
73 | + | ||
74 | +} // namespace Util | ||
75 | + | ||
76 | +// EOF |
vnr/ith/hook/hijack/texthook.cc
0 → 100644
1 | +// texthook.cc | ||
2 | +// 8/24/2013 jichi | ||
3 | +// Branch: ITH_DLL/texthook.cpp, rev 128 | ||
4 | +// 8/24/2013 TODO: Clean up this file | ||
5 | + | ||
6 | +#ifdef _MSC_VER | ||
7 | +# pragma warning (disable:4100) // C4100: unreference formal parameter | ||
8 | +# pragma warning (disable:4018) // C4018: sign/unsigned mismatch | ||
9 | +//# pragma warning (disable:4733) // C4733: Inline asm assigning to 'FS:0' : handler not registered as safe handler | ||
10 | +#endif // _MSC_VER | ||
11 | + | ||
12 | +#include "cli.h" | ||
13 | +#include "engine/match.h" | ||
14 | +#include "ith/common/except.h" | ||
15 | +//#include "ith/common/growl.h" | ||
16 | +#include "ith/sys/sys.h" | ||
17 | +#include "disasm/disasm.h" | ||
18 | +//#include "winseh/winseh.h" | ||
19 | + | ||
20 | +//#define ConsoleOutput(...) (void)0 // jichi 9/17/2013: I don't need this >< | ||
21 | + | ||
22 | +// - Global variables - | ||
23 | + | ||
24 | +// 10/14/2014 jichi: disable GDI hooks | ||
25 | +static bool gdi_hook_disabled_ = false; | ||
26 | +void DisableGDIHooks() | ||
27 | +{ ::gdi_hook_disabled_ = true; } | ||
28 | + | ||
29 | +static bool IsGDIFunction(LPCVOID addr) | ||
30 | +{ | ||
31 | + static LPVOID funcs[] = { HOOK_GDI_FUNCTION_LIST }; | ||
32 | + for (size_t i = 0; i < sizeof(funcs)/sizeof(*funcs); i++) | ||
33 | + if (addr == funcs[i]) | ||
34 | + return true; | ||
35 | + return false; | ||
36 | +} | ||
37 | + | ||
38 | +//FilterRange filter[8]; | ||
39 | + | ||
40 | +DWORD flag, | ||
41 | + enter_count; | ||
42 | + | ||
43 | +TextHook *hookman, | ||
44 | + *current_available; | ||
45 | + | ||
46 | +// - Unnamed helpers - | ||
47 | + | ||
48 | +namespace { // unnamed | ||
49 | +//provide const time hook entry. | ||
50 | +int userhook_count; | ||
51 | + | ||
52 | +#if 0 // 3/6/2015 jichi: this hook is not used and hence disabled | ||
53 | +const byte common_hook2[] = { | ||
54 | + 0x89, 0x3c,0xe4, // mov [esp],edi | ||
55 | + 0x60, // pushad | ||
56 | + 0x9c, // pushfd | ||
57 | + 0x8d,0x54,0x24,0x28, // lea edx,[esp+0x28] ; esp value | ||
58 | + 0x8b,0x32, // mov esi,[edx] ; return address | ||
59 | + 0xb9, 0,0,0,0, // mov ecx, $ ; pointer to TextHook | ||
60 | + 0xe8, 0,0,0,0, // call @hook | ||
61 | + 0x9d, // popfd | ||
62 | + 0x61, // popad | ||
63 | + 0x5f, // pop edi ; skip return address on stack | ||
64 | +}; //... | ||
65 | +#endif // 0 | ||
66 | + | ||
67 | +const BYTE common_hook[] = { | ||
68 | + 0x9c, // pushfd | ||
69 | + 0x60, // pushad | ||
70 | + 0x9c, // pushfd | ||
71 | + 0x8d,0x54,0x24,0x28, // lea edx,[esp+0x28] ; esp value | ||
72 | + 0x8b,0x32, // mov esi,[edx] ; return address | ||
73 | + 0xb9, 0,0,0,0, // mov ecx, $ ; pointer to TexHhook | ||
74 | + 0xe8, 0,0,0,0, // call @hook | ||
75 | + 0x9d, // popfd | ||
76 | + 0x61, // popad | ||
77 | + 0x9d // popfd | ||
78 | +}; | ||
79 | + | ||
80 | +/** | ||
81 | + * jichi 7/19/2014 | ||
82 | + * | ||
83 | + * @param original_addr | ||
84 | + * @param new_addr | ||
85 | + * @param hook_len | ||
86 | + * @param original_len | ||
87 | + * @return -1 if failed, else 0 if ?, else ? | ||
88 | + */ | ||
89 | +int MapInstruction(DWORD original_addr, DWORD new_addr, BYTE &hook_len, BYTE &original_len) | ||
90 | +{ | ||
91 | + int flag = 0; | ||
92 | + DWORD l = 0; | ||
93 | + const BYTE *r = (const BYTE *)original_addr; // 7/19/2014 jichi: original address is not modified | ||
94 | + BYTE *c = (BYTE *)new_addr; // 7/19/2014 jichi: but new address might be modified | ||
95 | + while((r - (BYTE *) original_addr) < 5) { | ||
96 | + l = ::disasm(r); | ||
97 | + if (l == 0) { | ||
98 | + ConsoleOutput("vnrcli:MapInstruction: FAILED: failed to disasm"); | ||
99 | + return -1; | ||
100 | + } | ||
101 | + | ||
102 | + ::memcpy(c, r, l); | ||
103 | + if (*r >= 0x70 && *r < 0x80) { | ||
104 | + c[0] = 0xf; | ||
105 | + c[1] = *r + 0x10; | ||
106 | + c += 6; | ||
107 | + __asm | ||
108 | + { | ||
109 | + mov eax,r | ||
110 | + add eax,2 | ||
111 | + movsx edx,byte ptr [eax-1] | ||
112 | + add edx,eax | ||
113 | + mov eax,c | ||
114 | + sub edx,eax | ||
115 | + mov [eax-4],edx | ||
116 | + } | ||
117 | + } else if (*r == 0xeb) { | ||
118 | + c[0] = 0xe9; | ||
119 | + c += 5; | ||
120 | + __asm | ||
121 | + { | ||
122 | + mov eax,r | ||
123 | + add eax,2 | ||
124 | + movsx edx,[eax-1] | ||
125 | + add edx,eax | ||
126 | + mov eax,c | ||
127 | + sub edx,eax | ||
128 | + mov [eax-4],edx | ||
129 | + } | ||
130 | + if (r - (BYTE *)original_addr < 5 - l) { | ||
131 | + ConsoleOutput("vnrcli:MapInstruction: not safe to move instruction right after short jmp"); | ||
132 | + return -1; // Not safe to move instruction right after short jmp. | ||
133 | + } else | ||
134 | + flag = 1; | ||
135 | + } else if (*r == 0xe8 || *r == 0xe9) { | ||
136 | + c[0]=*r; | ||
137 | + c += 5; | ||
138 | + flag = (*r == 0xe9); | ||
139 | + __asm | ||
140 | + { | ||
141 | + mov eax,r | ||
142 | + add eax,5 | ||
143 | + mov edx,[eax-4] | ||
144 | + add edx,eax | ||
145 | + mov eax,c | ||
146 | + sub edx,eax | ||
147 | + mov [eax-4],edx | ||
148 | + } | ||
149 | + } else if (*r == 0xf && (*(r + 1) >> 4) == 0x8) { | ||
150 | + c += 6; | ||
151 | + __asm | ||
152 | + { | ||
153 | + mov eax,r | ||
154 | + mov edx,dword ptr [eax+2] | ||
155 | + add eax,6 | ||
156 | + add eax,edx | ||
157 | + mov edx,c | ||
158 | + sub eax,edx | ||
159 | + mov [edx-4],eax | ||
160 | + } | ||
161 | + } | ||
162 | + else | ||
163 | + c += l; | ||
164 | + r += l; | ||
165 | + } | ||
166 | + original_len = r - (BYTE *)original_addr; | ||
167 | + hook_len = c - (BYTE *)new_addr; | ||
168 | + return flag; | ||
169 | +} | ||
170 | + | ||
171 | +//copy original instruction | ||
172 | +//jmp back | ||
173 | +DWORD GetModuleBase(DWORD hash) | ||
174 | +{ | ||
175 | + __asm | ||
176 | + { | ||
177 | + mov eax,fs:[0x30] | ||
178 | + mov eax,[eax+0xc] | ||
179 | + mov esi,[eax+0x14] | ||
180 | + mov edi,_wcslwr | ||
181 | +listfind: | ||
182 | + mov edx,[esi+0x28] | ||
183 | + test edx,edx | ||
184 | + jz notfound | ||
185 | + push edx | ||
186 | + call edi | ||
187 | + pop edx | ||
188 | + xor eax,eax | ||
189 | +calc: | ||
190 | + movzx ecx, word ptr [edx] | ||
191 | + test cl,cl | ||
192 | + jz fin | ||
193 | + ror eax,7 | ||
194 | + add eax,ecx | ||
195 | + add edx,2 | ||
196 | + jmp calc | ||
197 | +fin: | ||
198 | + cmp eax,[hash] | ||
199 | + je found | ||
200 | + mov esi,[esi] | ||
201 | + jmp listfind | ||
202 | +notfound: | ||
203 | + xor eax,eax | ||
204 | + jmp termin | ||
205 | +found: | ||
206 | + mov eax,[esi+0x10] | ||
207 | +termin: | ||
208 | + } | ||
209 | +} | ||
210 | + | ||
211 | +DWORD GetModuleBase() | ||
212 | +{ | ||
213 | + __asm | ||
214 | + { | ||
215 | + mov eax, fs:[0x18] | ||
216 | + mov eax, [eax + 0x30] | ||
217 | + mov eax, [eax + 0xc] | ||
218 | + mov eax, [eax + 0xc] | ||
219 | + mov eax, [eax + 0x18] | ||
220 | + } | ||
221 | +} | ||
222 | + | ||
223 | +//void NotifyHookInsert() | ||
224 | +//{ | ||
225 | +// if (live) | ||
226 | +// { | ||
227 | +// BYTE buffer[0x10]; | ||
228 | +// *(DWORD*)buffer=-1; | ||
229 | +// *(DWORD*)(buffer+4)=1; | ||
230 | +// IO_STATUS_BLOCK ios; | ||
231 | +// NtWriteFile(hPipe,0,0,0,&ios,buffer,0x10,0,0); | ||
232 | +// } | ||
233 | +//} | ||
234 | + | ||
235 | +__declspec(naked) void SafeExit() // Return to eax | ||
236 | +{ | ||
237 | + __asm | ||
238 | + { | ||
239 | + mov [esp+0x24], eax | ||
240 | + popfd | ||
241 | + popad | ||
242 | + retn | ||
243 | + } | ||
244 | +} | ||
245 | + | ||
246 | +#if 0 | ||
247 | +// jichi 12/2/2013: This function mostly return 0. | ||
248 | +// But sometimes return the hook address from TextHook::Send | ||
249 | +__declspec(naked) // jichi 10/2/2013: No prolog and epilog | ||
250 | +int ProcessHook(DWORD dwDataBase, DWORD dwRetn, TextHook *hook) // Use SEH to ensure normal execution even bad hook inserted. | ||
251 | +{ | ||
252 | + //with_seh(hook->Send(dwDataBase, dwRetn)); | ||
253 | + seh_push_(seh_exit, 0, eax, ebx) // jichi 12/13/2013: only eax and ebx are available. ecx and edx are used. | ||
254 | + __asm | ||
255 | + { | ||
256 | + push esi | ||
257 | + push edx | ||
258 | + call TextHook::UnsafeSend | ||
259 | + test eax, eax | ||
260 | + jz seh_exit // label in seh_pop | ||
261 | + mov ecx, SafeExit | ||
262 | + mov [esp + 8], ecx // jichi 12/13/2013: change exit point if Send returns non-zero, not + 8 beause two elements has been pused | ||
263 | + } | ||
264 | + seh_pop_(seh_exit) | ||
265 | + __asm retn // jichi 12/13/2013: return near, see: http://stackoverflow.com/questions/1396909/ret-retn-retf-how-to-use-them | ||
266 | +} | ||
267 | +#endif // 0 | ||
268 | + | ||
269 | +#if 1 | ||
270 | +__declspec(naked) // jichi 10/2/2013: No prolog and epilog | ||
271 | +int ProcessHook(DWORD dwDataBase, DWORD dwRetn, TextHook *hook) // Use SEH to ensure normal execution even bad hook inserted. | ||
272 | +{ | ||
273 | + // jichi 12/17/2013: The function parameters here are meaning leass. The parameters are in esi and edi | ||
274 | + __asm | ||
275 | + { | ||
276 | + push esi | ||
277 | + push edx | ||
278 | + call TextHook::Send | ||
279 | + test eax, eax | ||
280 | + jz ok // label in seh_pop | ||
281 | + mov ecx, SafeExit | ||
282 | + mov [esp], ecx // jichi 12/13/2013: change exit point if Send returns non-zero | ||
283 | + ok: | ||
284 | + retn // jichi 12/13/2013: return near, see: http://stackoverflow.com/questions/1396909/ret-retn-retf-how-to-use-them | ||
285 | + } | ||
286 | +} | ||
287 | +#endif // 1 | ||
288 | + | ||
289 | + // jichi 12/13/2013: return if the retn address is within the filter dlls | ||
290 | +inline bool HookFilter(DWORD retn) | ||
291 | +{ | ||
292 | + for (DWORD i = 0; ::filter[i].lower; i++) | ||
293 | + if (retn > ::filter[i].lower && retn < ::filter[i].upper) | ||
294 | + return true; | ||
295 | + return false; | ||
296 | +} | ||
297 | + | ||
298 | +} // unnamed namespace | ||
299 | + | ||
300 | +// - TextHook methods - | ||
301 | + | ||
302 | +// jichi 12/2/2013: This function mostly return 0. | ||
303 | +// It return the hook address only for auxiliary case. | ||
304 | +// However, because no known hooks are auxiliary, this function always return 0. | ||
305 | +// | ||
306 | +// jichi 5/11/2014: | ||
307 | +// - dwDataBase: the stack address | ||
308 | +// - dwRetn: the return address of the hook | ||
309 | +DWORD TextHook::Send(DWORD dwDataBase, DWORD dwRetn) | ||
310 | +{ | ||
311 | + DWORD ret = 0; | ||
312 | + //char b[0x100]; | ||
313 | + //::wcstombs(b, hook_name, 0x100); | ||
314 | + //ConsoleOutput(b); | ||
315 | + ITH_WITH_SEH(ret = UnsafeSend(dwDataBase, dwRetn)); | ||
316 | + return ret; | ||
317 | +} | ||
318 | + | ||
319 | +DWORD TextHook::UnsafeSend(DWORD dwDataBase, DWORD dwRetn) | ||
320 | +{ | ||
321 | + enum { SMALL_BUFF_SIZE = 0x80 }; | ||
322 | + enum { MAX_DATA_SIZE = 0x10000 }; // jichi 12/25/2013: The same as the original ITH | ||
323 | + DWORD dwCount, | ||
324 | + dwAddr, | ||
325 | + dwDataIn, | ||
326 | + dwSplit; | ||
327 | + BYTE *pbData, | ||
328 | + pbSmallBuff[SMALL_BUFF_SIZE]; | ||
329 | + DWORD dwType = hp.type; | ||
330 | + if (!live) | ||
331 | + return 0; | ||
332 | + if ((dwType & NO_CONTEXT) == 0 && HookFilter(dwRetn)) | ||
333 | + return 0; | ||
334 | + | ||
335 | + // jichi 10/24/2014: Skip GDI functions | ||
336 | + if (::gdi_hook_disabled_ && ::IsGDIFunction((LPCVOID)hp.addr)) | ||
337 | + return 0; | ||
338 | + | ||
339 | + dwAddr = hp.addr; | ||
340 | + | ||
341 | + /** jichi 12/24/2014 | ||
342 | + * @param addr function address | ||
343 | + * @param frame real address of the function, supposed to be the same as addr | ||
344 | + * @param stack address of current stack - 4 | ||
345 | + * @return If success, which is reverted | ||
346 | + */ | ||
347 | + if (::trigger) | ||
348 | + ::trigger = Engine::InsertDynamicHook((LPVOID)dwAddr, *(DWORD *)(dwDataBase - 0x1c), *(DWORD *)(dwDataBase-0x18)); | ||
349 | + // jichi 10/21/2014: Directly invoke engine functions. | ||
350 | + //if (trigger) { | ||
351 | + // if (InsertDynamicHook) | ||
352 | + // trigger = InsertDynamicHook((LPVOID)dwAddr, *(DWORD *)(dwDataBase - 0x1c), *(DWORD *)(dwDataBase-0x18)); | ||
353 | + // else | ||
354 | + // trigger = 0; | ||
355 | + //} | ||
356 | +#if 0 // diasble HOOK_AUXILIARY | ||
357 | + // jichi 12/13/2013: None of known hooks are auxiliary | ||
358 | + if (dwType & HOOK_AUXILIARY) { | ||
359 | + //Clean hook when dynamic hook finished. | ||
360 | + //AUX hook is only used for a foothold of dynamic hook. | ||
361 | + if (!trigger) { | ||
362 | + ClearHook(); | ||
363 | + // jichi 12/13/2013: This is the only place where this function could return non-zero value | ||
364 | + // However, I non of the known hooks are auxiliary | ||
365 | + return dwAddr; | ||
366 | + } | ||
367 | + return 0; | ||
368 | + } | ||
369 | +#endif // 0 | ||
370 | + // jichi 10/24/2014: generic hook function | ||
371 | + if (hp.hook_fun && !hp.hook_fun(dwDataBase, &hp)) | ||
372 | + hp.hook_fun = nullptr; | ||
373 | + | ||
374 | + if (dwType & HOOK_EMPTY) // jichi 10/24/2014: dummy hook only for dynamic hook | ||
375 | + return 0; | ||
376 | + | ||
377 | + // jichi 2/2/2015: Send multiple texts | ||
378 | + for (BYTE textIndex = 0; textIndex <= hp.extra_text_count; textIndex++) { | ||
379 | + dwCount = 0; | ||
380 | + dwSplit = 0; | ||
381 | + dwDataIn = *(DWORD *)(dwDataBase + hp.off); // default value | ||
382 | + | ||
383 | + //if (dwType & EXTERN_HOOK) { | ||
384 | + if (hp.text_fun) { // jichi 10/24/2014: remove EXTERN_HOOK | ||
385 | + //DataFun fun=(DataFun)hp.text_fun; | ||
386 | + //auto fun = hp.text_fun; | ||
387 | + hp.text_fun(dwDataBase, &hp, textIndex, &dwDataIn, &dwSplit, &dwCount); | ||
388 | + //if (dwCount == 0 || dwCount > MAX_DATA_SIZE) | ||
389 | + // return 0; | ||
390 | + if (dwSplit && (dwType & RELATIVE_SPLIT) && dwSplit > ::processStartAddress) | ||
391 | + dwSplit -= ::processStartAddress; | ||
392 | + } else { | ||
393 | + if (dwDataIn == 0) | ||
394 | + return 0; | ||
395 | + if (dwType & FIXING_SPLIT) | ||
396 | + dwSplit = FIXED_SPLIT_VALUE; // fuse all threads, and prevent floating | ||
397 | + else if (dwType & USING_SPLIT) { | ||
398 | + dwSplit = *(DWORD *)(dwDataBase + hp.split); | ||
399 | + if (dwType & SPLIT_INDIRECT) { | ||
400 | + if (IthGetMemoryRange((LPVOID)(dwSplit + hp.split_ind), 0, 0)) | ||
401 | + dwSplit = *(DWORD *)(dwSplit + hp.split_ind); | ||
402 | + else | ||
403 | + return 0; | ||
404 | + } | ||
405 | + if (dwSplit && (dwType & RELATIVE_SPLIT) && dwSplit > ::processStartAddress) | ||
406 | + dwSplit -= ::processStartAddress; | ||
407 | + } | ||
408 | + if (dwType & DATA_INDIRECT) { | ||
409 | + if (IthGetMemoryRange((LPVOID)(dwDataIn + hp.ind), 0, 0)) | ||
410 | + dwDataIn = *(DWORD *)(dwDataIn + hp.ind); | ||
411 | + else | ||
412 | + return 0; | ||
413 | + } | ||
414 | + //if (dwType & PRINT_DWORD) { | ||
415 | + // swprintf((WCHAR *)(pbSmallBuff + HEADER_SIZE), L"%.8X ", dwDataIn); | ||
416 | + // dwDataIn = (DWORD)pbSmallBuff + HEADER_SIZE; | ||
417 | + //} | ||
418 | + dwCount = GetLength(dwDataBase, dwDataIn); | ||
419 | + } | ||
420 | + | ||
421 | + // jichi 12/25/2013: validate data size | ||
422 | + if (dwCount == 0 || dwCount > MAX_DATA_SIZE) | ||
423 | + return 0; | ||
424 | + | ||
425 | + size_t sz = dwCount + HEADER_SIZE; | ||
426 | + if (sz >= SMALL_BUFF_SIZE) | ||
427 | + pbData = new BYTE[sz]; | ||
428 | + //ITH_MEMSET_HEAP(pbData, 0, sz * sizeof(BYTE)); // jichi 9/26/2013: zero memory | ||
429 | + else | ||
430 | + pbData = pbSmallBuff; | ||
431 | + | ||
432 | + if (hp.length_offset == 1) { | ||
433 | + if (dwType & STRING_LAST_CHAR) { | ||
434 | + LPWSTR ts = (LPWSTR)dwDataIn; | ||
435 | + dwDataIn = ts[::wcslen(ts) -1]; | ||
436 | + } | ||
437 | + dwDataIn &= 0xffff; | ||
438 | + if ((dwType & BIG_ENDIAN) && (dwDataIn >> 8)) | ||
439 | + dwDataIn = _byteswap_ushort(dwDataIn & 0xffff); | ||
440 | + if (dwCount == 1) | ||
441 | + dwDataIn &= 0xff; | ||
442 | + *(WORD *)(pbData + HEADER_SIZE) = dwDataIn & 0xffff; | ||
443 | + } | ||
444 | + else | ||
445 | + ::memcpy(pbData + HEADER_SIZE, (void *)dwDataIn, dwCount); | ||
446 | + | ||
447 | + // jichi 10/14/2014: Add filter function | ||
448 | + if (hp.filter_fun && !hp.filter_fun(pbData + HEADER_SIZE, &dwCount, &hp, textIndex) || dwCount <= 0) { | ||
449 | + if (pbData != pbSmallBuff) | ||
450 | + delete[] pbData; | ||
451 | + return 0; | ||
452 | + } | ||
453 | + | ||
454 | + *(DWORD *)pbData = dwAddr; | ||
455 | + if (dwType & (NO_CONTEXT|FIXING_SPLIT)) | ||
456 | + dwRetn = 0; | ||
457 | + else if (dwRetn && (dwType & RELATIVE_SPLIT)) | ||
458 | + dwRetn -= ::processStartAddress; | ||
459 | + | ||
460 | + *((DWORD *)pbData + 1) = dwRetn; | ||
461 | + *((DWORD *)pbData + 2) = dwSplit; | ||
462 | + if (dwCount) { | ||
463 | + IO_STATUS_BLOCK ios = {}; | ||
464 | + | ||
465 | + IthCoolDown(); // jichi 9/28/2013: cool down to prevent parallelization in wine | ||
466 | + //CliLockPipe(); | ||
467 | + if (STATUS_PENDING == NtWriteFile(hPipe, 0, 0, 0, &ios, pbData, dwCount + HEADER_SIZE, 0, 0)) { | ||
468 | + NtWaitForSingleObject(hPipe, 0, 0); | ||
469 | + NtFlushBuffersFile(hPipe, &ios); | ||
470 | + } | ||
471 | + //CliUnlockPipe(); | ||
472 | + } | ||
473 | + if (pbData != pbSmallBuff) | ||
474 | + delete[] pbData; | ||
475 | + } | ||
476 | + return 0; | ||
477 | + | ||
478 | +} | ||
479 | + | ||
480 | +int TextHook::InsertHook() | ||
481 | +{ | ||
482 | + //ConsoleOutput("vnrcli:InsertHook: enter"); | ||
483 | + NtWaitForSingleObject(hmMutex, 0, 0); | ||
484 | + int ok = InsertHookCode(); | ||
485 | + IthReleaseMutex(hmMutex); | ||
486 | + if (hp.type & HOOK_ADDITIONAL) { | ||
487 | + NotifyHookInsert(hp.addr); | ||
488 | + //ConsoleOutput(hook_name); | ||
489 | + //RegisterHookName(hook_name,hp.addr); | ||
490 | + } | ||
491 | + //ConsoleOutput("vnrcli:InsertHook: leave"); | ||
492 | + return ok; | ||
493 | +} | ||
494 | + | ||
495 | +int TextHook::InsertHookCode() | ||
496 | +{ | ||
497 | + enum : int { yes = 0, no = 1 }; | ||
498 | + DWORD ret = no; | ||
499 | + // jichi 9/17/2013: might raise 0xC0000005 AccessViolationException on win7 | ||
500 | + ITH_WITH_SEH(ret = UnsafeInsertHookCode()); | ||
501 | + //if (ret == no) | ||
502 | + // ITH_WARN(L"Failed to insert hook"); | ||
503 | + return ret; | ||
504 | +} | ||
505 | + | ||
506 | +int TextHook::UnsafeInsertHookCode() | ||
507 | +{ | ||
508 | + //ConsoleOutput("vnrcli:UnsafeInsertHookCode: enter"); | ||
509 | + enum : int { yes = 0, no = 1 }; | ||
510 | + // MODULE_OFFSET is set, but there's no module address | ||
511 | + // this means that this is an absolute address found on Windows 2000/XP | ||
512 | + // we make the address relative to the process base | ||
513 | + // we also store the original address in the function field because normally there can not | ||
514 | + // exist a function address without a module address | ||
515 | + if (hp.type & MODULE_OFFSET && !hp.module) { | ||
516 | + DWORD base = GetModuleBase(); | ||
517 | + hp.function = hp.addr; | ||
518 | + hp.addr -= 0x400000; | ||
519 | + hp.addr += base; | ||
520 | + hp.type &= ~MODULE_OFFSET; | ||
521 | + } | ||
522 | + else if (hp.module && (hp.type & MODULE_OFFSET)) { // Map hook offset to real address. | ||
523 | + if (DWORD base = GetModuleBase(hp.module)) { | ||
524 | + if (hp.function && (hp.type & FUNCTION_OFFSET)) { | ||
525 | + base = GetExportAddress(base, hp.function); | ||
526 | + if (base) | ||
527 | + hp.addr += base; | ||
528 | + else { | ||
529 | + current_hook--; | ||
530 | + ConsoleOutput("vnrcli:UnsafeInsertHookCode: FAILED: function not found in the export table"); | ||
531 | + return no; | ||
532 | + } | ||
533 | + } | ||
534 | + else { | ||
535 | + hp.addr += base; | ||
536 | + } | ||
537 | + hp.type &= ~(MODULE_OFFSET | FUNCTION_OFFSET); | ||
538 | + } | ||
539 | + else { | ||
540 | + current_hook--; | ||
541 | + ConsoleOutput("vnrcli:UnsafeInsertHookCode: FAILED: module not present"); | ||
542 | + return no; | ||
543 | + } | ||
544 | + } | ||
545 | + | ||
546 | + { | ||
547 | + TextHook *it = hookman; | ||
548 | + for (int i = 0; (i < current_hook) && it; it++) { // Check if there is a collision. | ||
549 | + if (it->Address()) | ||
550 | + i++; | ||
551 | + //it = hookman + i; | ||
552 | + if (it == this) | ||
553 | + continue; | ||
554 | + if (it->Address() <= hp.addr && | ||
555 | + it->Address() + it->Length() > hp.addr) { | ||
556 | + it->ClearHook(); | ||
557 | + break; | ||
558 | + } | ||
559 | + } | ||
560 | + } | ||
561 | + | ||
562 | + // Verify hp.addr. | ||
563 | + MEMORY_BASIC_INFORMATION info = {}; | ||
564 | + NtQueryVirtualMemory(NtCurrentProcess(), (LPVOID)hp.addr, MemoryBasicInformation, &info, sizeof(info), nullptr); | ||
565 | + if (info.Type & PAGE_NOACCESS) { | ||
566 | + ConsoleOutput("vnrcli:UnsafeInsertHookCode: FAILED: page no access"); | ||
567 | + return no; | ||
568 | + } | ||
569 | + | ||
570 | + // Initialize common routine. | ||
571 | + memcpy(recover, common_hook, sizeof(common_hook)); | ||
572 | + BYTE *c = (BYTE *)hp.addr, | ||
573 | + *r = recover; | ||
574 | + BYTE inst[8]; // jichi 9/27/2013: Why 8? Only 5 bytes will be written using NtWriteVirtualMemory | ||
575 | + inst[0] = 0xe9; // jichi 9/27/2013: 0xe9 is jump, see: http://code.google.com/p/sexyhook/wiki/SEXYHOOK_Hackers_Manual | ||
576 | + __asm | ||
577 | + { | ||
578 | + mov edx,r // r = recover | ||
579 | + mov eax,this | ||
580 | + mov [edx+0xa],eax // push TextHook*, resolve to correspond hook. | ||
581 | + lea eax,[edx+0x13] | ||
582 | + mov edx,ProcessHook | ||
583 | + sub edx,eax | ||
584 | + mov [eax-4],edx // call ProcessHook | ||
585 | + mov eax,c | ||
586 | + add eax,5 | ||
587 | + mov edx,r | ||
588 | + sub edx,eax | ||
589 | + lea eax,inst+1 | ||
590 | + mov [eax],edx // jichi 12/17/2013: the parameter of jmp is in edx. So, ProcessHook must be naked. | ||
591 | + } | ||
592 | + r += sizeof(common_hook); | ||
593 | + hp.hook_len = 5; | ||
594 | + //bool jmpflag=false; // jichi 9/28/2013: nto used | ||
595 | + // Copy original code. | ||
596 | + switch (MapInstruction(hp.addr, (DWORD)r, hp.hook_len, hp.recover_len)) { | ||
597 | + case -1: | ||
598 | + ConsoleOutput("vnrcli:UnsafeInsertHookCode: FAILED: failed to map instruction"); | ||
599 | + return no; | ||
600 | + case 0: | ||
601 | + __asm | ||
602 | + { | ||
603 | + mov ecx,this | ||
604 | + movzx eax,[ecx]hp.hook_len | ||
605 | + movzx edx,[ecx]hp.recover_len | ||
606 | + add edx,[ecx]hp.addr | ||
607 | + add eax,r | ||
608 | + add eax,5 | ||
609 | + sub edx,eax | ||
610 | + mov [eax-5],0xe9 // jichi 9/27/2013: 0xe9 is jump | ||
611 | + mov [eax-4],edx | ||
612 | + } | ||
613 | + } | ||
614 | + // jichi 9/27/2013: Save the original instructions in the memory | ||
615 | + memcpy(original, (LPVOID)hp.addr, hp.recover_len); | ||
616 | + //Check if the new hook range conflict with existing ones. Clear older if conflict. | ||
617 | + { | ||
618 | + TextHook *it = hookman; | ||
619 | + for (int i = 0; i < current_hook; it++) { | ||
620 | + if (it->Address()) | ||
621 | + i++; | ||
622 | + if (it == this) | ||
623 | + continue; | ||
624 | + if (it->Address() >= hp.addr && | ||
625 | + it->Address() < hp.hook_len + hp.addr) { | ||
626 | + it->ClearHook(); | ||
627 | + break; | ||
628 | + } | ||
629 | + } | ||
630 | + } | ||
631 | + // Insert hook and flush instruction cache. | ||
632 | + enum {c8 = 0xcccccccc}; | ||
633 | + DWORD int3[] = {c8, c8}; | ||
634 | + DWORD t = 0x100, | ||
635 | + old, | ||
636 | + len; | ||
637 | + // jichi 9/27/2013: Overwrite the memory with inst | ||
638 | + // See: http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Memory%20Management/Virtual%20Memory/NtProtectVirtualMemory.html | ||
639 | + // See: http://doxygen.reactos.org/d8/d6b/ndk_2mmfuncs_8h_af942709e0c57981d84586e74621912cd.html | ||
640 | + DWORD addr = hp.addr; | ||
641 | + NtProtectVirtualMemory(NtCurrentProcess(), (PVOID *)&addr, &t, PAGE_EXECUTE_READWRITE, &old); | ||
642 | + NtWriteVirtualMemory(NtCurrentProcess(), (BYTE *)hp.addr, inst, 5, &t); | ||
643 | + len = hp.recover_len - 5; | ||
644 | + if (len) | ||
645 | + NtWriteVirtualMemory(NtCurrentProcess(), (BYTE *)hp.addr + 5, int3, len, &t); | ||
646 | + NtFlushInstructionCache(NtCurrentProcess(), (LPVOID)hp.addr, hp.recover_len); | ||
647 | + NtFlushInstructionCache(NtCurrentProcess(), (LPVOID)::hookman, 0x1000); | ||
648 | + //ConsoleOutput("vnrcli:UnsafeInsertHookCode: leave: succeed"); | ||
649 | + return 0; | ||
650 | +} | ||
651 | + | ||
652 | +int TextHook::InitHook(LPVOID addr, DWORD data, DWORD data_ind, | ||
653 | + DWORD split_off, DWORD split_ind, WORD type, DWORD len_off) | ||
654 | +{ | ||
655 | + NtWaitForSingleObject(hmMutex, 0, 0); | ||
656 | + hp.addr = (DWORD)addr; | ||
657 | + hp.off = data; | ||
658 | + hp.ind = data_ind; | ||
659 | + hp.split = split_off; | ||
660 | + hp.split_ind = split_ind; | ||
661 | + hp.type = type; | ||
662 | + hp.hook_len = 0; | ||
663 | + hp.module = 0; | ||
664 | + hp.length_offset = len_off & 0xffff; | ||
665 | + current_hook++; | ||
666 | + if (current_available >= this) | ||
667 | + for (current_available = this + 1; current_available->Address(); current_available++); | ||
668 | + IthReleaseMutex(hmMutex); | ||
669 | + return this - hookman; | ||
670 | +} | ||
671 | + | ||
672 | +int TextHook::InitHook(const HookParam &h, LPCWSTR name, WORD set_flag) | ||
673 | +{ | ||
674 | + NtWaitForSingleObject(hmMutex, 0, 0); | ||
675 | + hp = h; | ||
676 | + hp.type |= set_flag; | ||
677 | + if (name && name != hook_name) { | ||
678 | + SetHookName(name); | ||
679 | + } | ||
680 | + current_hook++; | ||
681 | + current_available = this+1; | ||
682 | + while (current_available->Address()) | ||
683 | + current_available++; | ||
684 | + IthReleaseMutex(hmMutex); | ||
685 | + return 1; | ||
686 | +} | ||
687 | + | ||
688 | +int TextHook::RemoveHook() | ||
689 | +{ | ||
690 | + enum : int { yes = 1, no = 0 }; | ||
691 | + if (!hp.addr) | ||
692 | + return no; | ||
693 | + ConsoleOutput("vnrcli:RemoveHook: enter"); | ||
694 | + const LONGLONG timeout = -50000000; // jichi 9/28/2012: in 100ns, wait at most for 5 seconds | ||
695 | + NtWaitForSingleObject(hmMutex, 0, (PLARGE_INTEGER)&timeout); | ||
696 | + DWORD l = hp.hook_len; | ||
697 | + //with_seh({ // jichi 9/17/2013: might crash >< | ||
698 | + // jichi 12/25/2013: Actually, __try cannot catch such kind of exception | ||
699 | + ITH_TRY { | ||
700 | + NtWriteVirtualMemory(NtCurrentProcess(), (LPVOID)hp.addr, original, hp.recover_len, &l); | ||
701 | + NtFlushInstructionCache(NtCurrentProcess(), (LPVOID)hp.addr, hp.recover_len); | ||
702 | + } ITH_EXCEPT {} | ||
703 | + //}); | ||
704 | + hp.hook_len = 0; | ||
705 | + IthReleaseMutex(hmMutex); | ||
706 | + ConsoleOutput("vnrcli:RemoveHook: leave"); | ||
707 | + return yes; | ||
708 | +} | ||
709 | + | ||
710 | +int TextHook::ClearHook() | ||
711 | +{ | ||
712 | + NtWaitForSingleObject(hmMutex, 0, 0); | ||
713 | + int err = RemoveHook(); | ||
714 | + if (hook_name) { | ||
715 | + delete[] hook_name; | ||
716 | + hook_name = nullptr; | ||
717 | + } | ||
718 | + memset(this, 0, sizeof(TextHook)); // jichi 11/30/2013: This is the original code of ITH | ||
719 | + //if (current_available>this) | ||
720 | + // current_available = this; | ||
721 | + current_hook--; | ||
722 | + IthReleaseMutex(hmMutex); | ||
723 | + return err; | ||
724 | +} | ||
725 | + | ||
726 | +int TextHook::ModifyHook(const HookParam &hp) | ||
727 | +{ | ||
728 | + //WCHAR name[0x40]; | ||
729 | + DWORD len = 0; | ||
730 | + if (hook_name) | ||
731 | + len = wcslen(hook_name); | ||
732 | + LPWSTR name = 0; | ||
733 | + if (len) { | ||
734 | + name = new wchar_t[len + 1]; | ||
735 | + //ITH_MEMSET_HEAP(name, 0, sizeof(wchar_t) * (len + 1)); // jichi 9/26/2013: zero memory | ||
736 | + name[len] = 0; | ||
737 | + wcscpy(name, hook_name); | ||
738 | + } | ||
739 | + ClearHook(); | ||
740 | + InitHook(hp,name); | ||
741 | + InsertHook(); | ||
742 | + if (name) | ||
743 | + delete[] name; | ||
744 | + return 0; | ||
745 | +} | ||
746 | + | ||
747 | +int TextHook::RecoverHook() | ||
748 | +{ | ||
749 | + if (hp.addr) { | ||
750 | + // jichi 9/28/2013: Only enable TextOutA to debug Cross Channel | ||
751 | + //if (hp.addr == (DWORD)TextOutA) | ||
752 | + InsertHook(); | ||
753 | + return 1; | ||
754 | + } | ||
755 | + return 0; | ||
756 | +} | ||
757 | + | ||
758 | +int TextHook::SetHookName(LPCWSTR name) | ||
759 | +{ | ||
760 | + name_length = wcslen(name) + 1; | ||
761 | + if (hook_name) | ||
762 | + delete[] hook_name; | ||
763 | + hook_name = new wchar_t[name_length]; | ||
764 | + //ITH_MEMSET_HEAP(hook_name, 0, sizeof(wchar_t) * name_length); // jichi 9/26/2013: zero memory | ||
765 | + hook_name[name_length - 1] = 0; | ||
766 | + wcscpy(hook_name, name); | ||
767 | + return 0; | ||
768 | +} | ||
769 | + | ||
770 | +int TextHook::GetLength(DWORD base, DWORD in) | ||
771 | +{ | ||
772 | + if (base == 0) | ||
773 | + return 0; | ||
774 | + int len; | ||
775 | + switch (hp.length_offset) { | ||
776 | + default: // jichi 12/26/2013: I should not put this default branch to the end | ||
777 | + len = *((int *)base + hp.length_offset); | ||
778 | + if (len >= 0) { | ||
779 | + if (hp.type & USING_UNICODE) | ||
780 | + len <<= 1; | ||
781 | + break; | ||
782 | + } | ||
783 | + else if (len != -1) | ||
784 | + break; | ||
785 | + //len == -1 then continue to case 0. | ||
786 | + case 0: | ||
787 | + if (hp.type & USING_UNICODE) | ||
788 | + len = wcslen((const wchar_t *)in) << 1; | ||
789 | + else | ||
790 | + len = strlen((const char *)in); | ||
791 | + break; | ||
792 | + case 1: | ||
793 | + if (hp.type & USING_UNICODE) | ||
794 | + len = 2; | ||
795 | + else { | ||
796 | + if (hp.type & BIG_ENDIAN) | ||
797 | + in >>= 8; | ||
798 | + len = LeadByteTable[in & 0xff]; //Slightly faster than IsDBCSLeadByte | ||
799 | + } | ||
800 | + break; | ||
801 | + } | ||
802 | + // jichi 12/25/2013: This function originally return -1 if failed | ||
803 | + //return len; | ||
804 | + return max(0, len); | ||
805 | +} | ||
806 | + | ||
807 | +// EOF | ||
808 | + | ||
809 | +//typedef void (*DataFun)(DWORD, const HookParam*, DWORD*, DWORD*, DWORD*); | ||
810 | + | ||
811 | +/* | ||
812 | +DWORD recv_esp, recv_addr; | ||
813 | +EXCEPTION_DISPOSITION ExceptHandler(EXCEPTION_RECORD *ExceptionRecord, | ||
814 | + void *EstablisherFrame, CONTEXT *ContextRecord, void *DispatcherContext) | ||
815 | +{ | ||
816 | + //WCHAR str[0x40], | ||
817 | + // name[0x100]; | ||
818 | + //ConsoleOutput(L"Exception raised during hook processing."); | ||
819 | + //swprintf(str, L"Exception code: 0x%.8X", ExceptionRecord->ExceptionCode); | ||
820 | + //ConsoleOutput(str); | ||
821 | + //MEMORY_BASIC_INFORMATION info; | ||
822 | + //if (NT_SUCCESS(NtQueryVirtualMemory(NtCurrentProcess(),(PVOID)ContextRecord->Eip, | ||
823 | + // MemoryBasicInformation,&info,sizeof(info),0)) && | ||
824 | + // NT_SUCCESS(NtQueryVirtualMemory(NtCurrentProcess(),(PVOID)ContextRecord->Eip, | ||
825 | + // MemorySectionName,name,0x200,0))) { | ||
826 | + // swprintf(str, L"Exception offset: 0x%.8X:%s", | ||
827 | + // ContextRecord->Eip-(DWORD)info.AllocationBase, | ||
828 | + // wcsrchr(name,L'\\')+1); | ||
829 | + // ConsoleOutput(str); | ||
830 | + //} | ||
831 | + ContextRecord->Esp = recv_esp; | ||
832 | + ContextRecord->Eip = recv_addr; | ||
833 | + return ExceptionContinueExecution; | ||
834 | +} | ||
835 | + | ||
836 | + | ||
837 | +//typedef void (*DataFun)(DWORD, const HookParam*, DWORD*, DWORD*, DWORD*); | ||
838 | + | ||
839 | +DWORD recv_esp, recv_addr; | ||
840 | +EXCEPTION_DISPOSITION ExceptHandler(EXCEPTION_RECORD *ExceptionRecord, | ||
841 | + void *EstablisherFrame, CONTEXT *ContextRecord, void *DispatcherContext) | ||
842 | +{ | ||
843 | + //WCHAR str[0x40], | ||
844 | + // name[0x100]; | ||
845 | + //ConsoleOutput(L"Exception raised during hook processing."); | ||
846 | + //swprintf(str, L"Exception code: 0x%.8X", ExceptionRecord->ExceptionCode); | ||
847 | + //ConsoleOutput(str); | ||
848 | + //MEMORY_BASIC_INFORMATION info; | ||
849 | + //if (NT_SUCCESS(NtQueryVirtualMemory(NtCurrentProcess(),(PVOID)ContextRecord->Eip, | ||
850 | + // MemoryBasicInformation,&info,sizeof(info),0)) && | ||
851 | + // NT_SUCCESS(NtQueryVirtualMemory(NtCurrentProcess(),(PVOID)ContextRecord->Eip, | ||
852 | + // MemorySectionName,name,0x200,0))) { | ||
853 | + // swprintf(str, L"Exception offset: 0x%.8X:%s", | ||
854 | + // ContextRecord->Eip-(DWORD)info.AllocationBase, | ||
855 | + // wcsrchr(name,L'\\')+1); | ||
856 | + // ConsoleOutput(str); | ||
857 | + //} | ||
858 | + ContextRecord->Esp = recv_esp; | ||
859 | + ContextRecord->Eip = recv_addr; | ||
860 | + return ExceptionContinueExecution; | ||
861 | +} | ||
862 | + | ||
863 | +__declspec(naked) // jichi 10/2/2013: No prolog and epilog | ||
864 | +int ProcessHook(DWORD dwDataBase, DWORD dwRetn, TextHook *hook) // Use SEH to ensure normal execution even bad hook inserted. | ||
865 | +{ | ||
866 | + __asm | ||
867 | + { | ||
868 | + mov eax,seh_recover | ||
869 | + mov recv_addr,eax | ||
870 | + push ExceptHandler | ||
871 | + push fs:[0] | ||
872 | + mov recv_esp,esp | ||
873 | + mov fs:[0],esp | ||
874 | + push esi | ||
875 | + push edx | ||
876 | + call TextHook::Send | ||
877 | + test eax,eax | ||
878 | + jz seh_recover | ||
879 | + mov ecx,SafeExit | ||
880 | + mov [esp + 0x8], ecx // change exit point | ||
881 | +seh_recover: | ||
882 | + pop dword ptr fs:[0] | ||
883 | + pop ecx | ||
884 | + retn | ||
885 | + } | ||
886 | +} | ||
887 | +*/ |
-
Please register or login to post a comment