pchooks.cc
13.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
// pchooks.cc
// 8/1/2014 jichi
#include "src/engine/pchooks.h"
#include "src/main.h"
//#include <gdiplus.h>
#define DEBUG "vnrcli"
#define DPRINT(cstr) ConsoleOutput(DEBUG ":" __FUNCTION__ ":" cstr) // defined in vnrcli
// 8/1/2014 jichi: Split is not used.
// Although split is specified, USING_SPLIT is not assigned.
// Use LPASTE to convert to wchar_t
// http://bytes.com/topic/c/answers/135834-defining-wide-character-strings-macros
//#define LPASTE(s) L##s
//#define L(s) LPASTE(s)
#define NEW_HOOK_AT(_addr, _fun, _data, _data_ind, _split_off, _split_ind, _type, _len_off) \
{ \
HookParam hp = {}; \
hp.address = _addr; \
hp.offset = _data; \
hp.index = _data_ind; \
hp.split = _split_off; \
hp.split_index = _split_ind; \
hp.type = _type; \
hp.length_offset = _len_off; \
NewHook(hp, #_fun); \
}
// Static hook
#define NEW_HOOK(_fun, _data, _data_ind, _split_off, _split_ind, _type, _len_off) \
NEW_HOOK_AT((DWORD)_fun, _fun, _data, _data_ind, _split_off, _split_ind, _type, _len_off) \
#define NEW_MODULE_HOOK(_module, _fun, _data, _data_ind, _split_off, _split_ind, _type, _len_off) \
{ \
if (DWORD addr = (DWORD)::GetProcAddress(_module, #_fun)) \
NEW_HOOK_AT(addr, _fun, _data, _data_ind, _split_off, _split_ind, _type, _len_off) \
}
// jichi 7/17/2014: Renamed from InitDefaultHook
void PcHooks::hookGDIFunctions()
{
DPRINT("enter");
// int TextHook::InitHook(LPVOID addr, DWORD data, DWORD data_ind, DWORD split_off, DWORD split_ind, WORD type, DWORD len_off)
//
// jichi 9/8/2013: Guessed meaning
// - data(off): 4 * the n-th (base 1) parameter representing the data of the string
// - len_off:
// - the n-th (base 1) parameter representing the length of the string
// - or 1 if is char
// - or 0 if detect on run time
// - type: USING_STRING if len_off != 1 else BIG_ENDIAN or USING_UNICODE
//
// Examples:
// int WINAPI lstrlenA(LPCSTR lpString)
// - data: 4 * 1 = 4, as lpString is the first
// - len_off: 0, as no parameter representing string length
// - type: BIG_ENDIAN, since len_off == 1
// BOOL GetTextExtentPoint32(HDC hdc, LPCTSTR lpString, int c, LPSIZE lpSize);
// - data: 4 * 2 = 0x8, as lpString is the second
// - len_off: 3, as nCount is the 3rd parameter
// - type: USING_STRING, since len_off != 1
//
// Note: All functions does not have NO_CONTEXT attribute and will be filtered.
enum stack {
s_retaddr = 0
, s_arg1 = 4 * 1 // 0x4
, s_arg2 = 4 * 2 // 0x8
, s_arg3 = 4 * 3 // 0xc
, s_arg4 = 4 * 4 // 0x10
, s_arg5 = 4 * 5 // 0x14
, s_arg6 = 4 * 6 // 0x18
};
//#define _(Name, ...) \
// hookman[HF_##Name].InitHook(Name, __VA_ARGS__); \
// hookman[HF_##Name].SetHookName(names[HF_##Name]);
// Always use s_arg1 = hDC as split_off
// 7/26/2014 jichi: Why there is no USING_SPLIT type?
// gdi32.dll
NEW_HOOK(GetTextExtentPoint32A, s_arg2, 0,s_arg1,0, USING_STRING, 3) // BOOL GetTextExtentPoint32(HDC hdc, LPCTSTR lpString, int c, LPSIZE lpSize);
NEW_HOOK(GetTextExtentExPointA, s_arg2, 0,s_arg1,0, USING_STRING, 3) // BOOL GetTextExtentExPoint(HDC hdc, LPCTSTR lpszStr, int cchString, int nMaxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize);
NEW_HOOK(GetTabbedTextExtentA, s_arg2, 0,s_arg1,0, USING_STRING, 3) // DWORD GetTabbedTextExtent(HDC hDC, LPCTSTR lpString, int nCount, int nTabPositions, const LPINT lpnTabStopPositions);
NEW_HOOK(GetCharacterPlacementA, s_arg2, 0,s_arg1,0, USING_STRING, 3) // DWORD GetCharacterPlacement(HDC hdc, LPCTSTR lpString, int nCount, int nMaxExtent, LPGCP_RESULTS lpResults, DWORD dwFlags);
NEW_HOOK(GetGlyphIndicesA, s_arg2, 0,s_arg1,0, USING_STRING, 3) // DWORD GetGlyphIndices( HDC hdc, LPCTSTR lpstr, int c, LPWORD pgi, DWORD fl);
NEW_HOOK(GetGlyphOutlineA, s_arg2, 0,s_arg1,0, BIG_ENDIAN, 1) // DWORD GetGlyphOutline(HDC hdc, UINT uChar, UINT uFormat, LPGLYPHMETRICS lpgm, DWORD cbBuffer, LPVOID lpvBuffer, const MAT2 *lpmat2);
NEW_HOOK(ExtTextOutA, s_arg6, 0,s_arg1,0, USING_STRING, 7) // BOOL ExtTextOut(HDC hdc, int X, int Y, UINT fuOptions, const RECT *lprc, LPCTSTR lpString, UINT cbCount, const INT *lpDx);
NEW_HOOK(TextOutA, s_arg4, 0,s_arg1,0, USING_STRING, 5) // BOOL TextOut(HDC hdc, int nXStart, int nYStart, LPCTSTR lpString, int cchString);
NEW_HOOK(TabbedTextOutA, s_arg4, 0,s_arg1,0, USING_STRING, 5) // LONG TabbedTextOut(HDC hDC, int X, int Y, LPCTSTR lpString, int nCount, int nTabPositions, const LPINT lpnTabStopPositions, int nTabOrigin);
NEW_HOOK(GetCharABCWidthsA, s_arg2, 0,s_arg1,0, BIG_ENDIAN, 1) // BOOL GetCharABCWidths(HDC hdc, UINT uFirstChar, UINT uLastChar, LPABC lpabc);
NEW_HOOK(GetCharABCWidthsFloatA, s_arg2, 0,s_arg1,0, BIG_ENDIAN, 1) // BOOL GetCharABCWidthsFloat(HDC hdc, UINT iFirstChar, UINT iLastChar, LPABCFLOAT lpABCF);
NEW_HOOK(GetCharWidth32A, s_arg2, 0,s_arg1,0, BIG_ENDIAN, 1) // BOOL GetCharWidth32(HDC hdc, UINT iFirstChar, UINT iLastChar, LPINT lpBuffer);
NEW_HOOK(GetCharWidthFloatA, s_arg2, 0,s_arg1,0, BIG_ENDIAN, 1) // BOOL GetCharWidthFloat(HDC hdc, UINT iFirstChar, UINT iLastChar, PFLOAT pxBuffer);
NEW_HOOK(GetTextExtentPoint32W, s_arg2, 0,s_arg1,0, USING_UNICODE|USING_STRING, 3)
NEW_HOOK(GetTextExtentExPointW, s_arg2, 0,s_arg1,0, USING_UNICODE|USING_STRING, 3)
NEW_HOOK(GetTabbedTextExtentW, s_arg2, 0,s_arg1,0, USING_UNICODE|USING_STRING, 3)
NEW_HOOK(GetCharacterPlacementW, s_arg2, 0,s_arg1,0, USING_UNICODE|USING_STRING, 3)
NEW_HOOK(GetGlyphIndicesW, s_arg2, 0,s_arg1,0, USING_UNICODE|USING_STRING, 3)
NEW_HOOK(GetGlyphOutlineW, s_arg2, 0,s_arg1,0, USING_UNICODE, 1)
NEW_HOOK(ExtTextOutW, s_arg6, 0,s_arg1,0, USING_UNICODE|USING_STRING, 7)
NEW_HOOK(TextOutW, s_arg4, 0,s_arg1,0, USING_UNICODE|USING_STRING, 5)
NEW_HOOK(TabbedTextOutW, s_arg4, 0,s_arg1,0, USING_UNICODE|USING_STRING, 5)
NEW_HOOK(GetCharABCWidthsW, s_arg2, 0,s_arg1,0, USING_UNICODE, 1)
NEW_HOOK(GetCharABCWidthsFloatW, s_arg2, 0,s_arg1,0, USING_UNICODE, 1)
NEW_HOOK(GetCharWidth32A, s_arg2, 0,s_arg1,0, USING_UNICODE, 1)
NEW_HOOK(GetCharWidthFloatA, s_arg2, 0,s_arg1,0, USING_UNICODE, 1)
// user32.dll
NEW_HOOK(DrawTextA, s_arg2, 0,s_arg1,0, USING_STRING, 3) // int DrawText(HDC hDC, LPCTSTR lpchText, int nCount, LPRECT lpRect, UINT uFormat);
NEW_HOOK(DrawTextExA, s_arg2, 0,s_arg1,0, USING_STRING, 3) // int DrawTextEx(HDC hdc, LPTSTR lpchText,int cchText, LPRECT lprc, UINT dwDTFormat, LPDRAWTEXTPARAMS lpDTParams);
NEW_HOOK(DrawTextW, s_arg2, 0,s_arg1,0, USING_UNICODE|USING_STRING, 3)
NEW_HOOK(DrawTextExW, s_arg2, 0,s_arg1,0, USING_UNICODE|USING_STRING, 3)
DPRINT("leave");
}
// jichi 6/18/2015: GDI+ functions
void PcHooks::hookGDIPlusFunctions()
{
HMODULE hModule = ::GetModuleHandleA("gdiplus.dll");
if (!hModule) {
DPRINT("not loaded");
return;
}
DPRINT("enter");
enum stack {
s_retaddr = 0
, s_arg1 = 4 * 1 // 0x4
, s_arg2 = 4 * 2 // 0x8
, s_arg3 = 4 * 3 // 0xc
, s_arg4 = 4 * 4 // 0x10
, s_arg5 = 4 * 5 // 0x14
, s_arg6 = 4 * 6 // 0x18
};
// gdiplus.dll
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms534053%28v=vs.85%29.aspx
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms534052%28v=vs.85%29.aspx
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms534039%28v=vs.85%29.aspx
// Use arg1 pionter to GpGraphics as split
//using namespace Gdiplus::DllExports;
// Use arg5 style as split
NEW_MODULE_HOOK(hModule, GdipAddPathString, s_arg2, 0,s_arg5,0, USING_UNICODE|USING_STRING, 3) // GpStatus WINGDIPAPI GdipAddPathString(GpPath *path, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFontFamily *family, INT style, REAL emSize, GDIPCONST RectF *layoutRect, GDIPCONST GpStringFormat *format)
NEW_MODULE_HOOK(hModule, GdipAddPathStringl, s_arg2, 0,s_arg5,0, USING_UNICODE|USING_STRING, 3) // GpStatus WINGDIPAPI GdipAddPathStringI(GpPath *path, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFontFamily *family, INT style, REAL emSize, GDIPCONST Rect *layoutRect, GDIPCONST GpStringFormat *format)
//NEW_MODULE_HOOK(hModule, GdipMeasureCharacterRanges, s_arg2, 0,s_arg1,0, USING_UNICODE|USING_STRING, 3) // GpStatus WINGDIPAPI GdipMeasureCharacterRanges(GpGraphics *graphics, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, GDIPCONST RectF &layoutRect, GDIPCONST GpStringFormat *stringFormat, INT regionCount, GpRegion **regions)
NEW_MODULE_HOOK(hModule, GdipDrawString, s_arg2, 0,s_arg1,0, USING_UNICODE|USING_STRING, 3) // GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, GDIPCONST RectF *layoutRect, GDIPCONST GpStringFormat *stringFormat, GDIPCONST GpBrush *brush);
NEW_MODULE_HOOK(hModule, GdipMeasureString, s_arg2, 0,s_arg1,0, USING_UNICODE|USING_STRING, 3) // GpStatus WINGDIPAPI GdipMeasureString(GpGraphics *graphics, GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font, GDIPCONST RectF *layoutRect, GDIPCONST GpStringFormat *stringFormat, RectF *boundingBox, INT *codepointsFitted, INT *linesFilled )
DPRINT("leave");
}
// jichi 10/2/2013
// Note: All functions does not have NO_CONTEXT attribute and will be filtered.
void PcHooks::hookLstrFunctions()
{
DPRINT("enter");
// int TextHook::InitHook(LPVOID addr, DWORD data, DWORD data_ind, DWORD split_off, DWORD split_ind, WORD type, DWORD len_off)
enum stack {
s_retaddr = 0
, s_arg1 = 4 * 1 // 0x4
//, s_arg2 = 4 * 2 // 0x8
//, s_arg3 = 4 * 3 // 0xc
//, s_arg4 = 4 * 4 // 0x10
//, s_arg5 = 4 * 5 // 0x14
//, s_arg6 = 4 * 6 // 0x18
};
// http://msdn.microsoft.com/en-us/library/78zh94ax.aspx
// int WINAPI lstrlen(LPCTSTR lpString);
// Lstr functions usually extracts rubbish, and might crash certain games like 「Magical Marriage Lunatics!!」
// Needed by Gift
// Use arg1 address for both split and data
NEW_HOOK(lstrlenA, s_arg1, 0,s_arg1,0, USING_STRING, 0) // 9/8/2013 jichi: int WINAPI lstrlen(LPCTSTR lpString);
NEW_HOOK(lstrlenW, s_arg1, 0,s_arg1,0, USING_UNICODE|USING_STRING, 0) // 9/8/2013 jichi: add lstrlen
// size_t strlen(const char *str);
// size_t strlen_l(const char *str, _locale_t locale);
// size_t wcslen(const wchar_t *str);
// size_t wcslen_l(const wchar_t *str, _locale_t locale);
// size_t _mbslen(const unsigned char *str);
// size_t _mbslen_l(const unsigned char *str, _locale_t locale);
// size_t _mbstrlen(const char *str);
// size_t _mbstrlen_l(const char *str, _locale_t locale);
// http://msdn.microsoft.com/en-us/library/ex0hs2ad.aspx
// Needed by 娘姉妹
//
// <tchar.h>
// char *_strinc(const char *current, _locale_t locale);
// wchar_t *_wcsinc(const wchar_t *current, _locale_t locale);
// <mbstring.h>
// unsigned char *_mbsinc(const unsigned char *current);
// unsigned char *_mbsinc_l(const unsigned char *current, _locale_t locale);
//_(L"_strinc", _strinc, 4, 0,4,0, USING_STRING, 0) // 12/13/2013 jichi
//_(L"_wcsinc", _wcsinc, 4, 0,4,0, USING_UNICODE|USING_STRING, 0)
DPRINT("leave");
}
void PcHooks::hookWcharFunctions()
{
DPRINT("enter");
// 12/1/2013 jichi:
// AlterEgo
// http://tieba.baidu.com/p/2736475133
// http://www.hongfire.com/forum/showthread.php/36807-AGTH-text-extraction-tool-for-games-translation/page355
//
// MultiByteToWideChar
// http://blgames.proboards.com/thread/265
//
// WideCharToMultiByte
// http://www.hongfire.com/forum/showthread.php/36807-AGTH-text-extraction-tool-for-games-translation/page156
//
// int MultiByteToWideChar(
// _In_ UINT CodePage,
// _In_ DWORD dwFlags,
// _In_ LPCSTR lpMultiByteStr, // hook here
// _In_ int cbMultiByte,
// _Out_opt_ LPWSTR lpWideCharStr,
// _In_ int cchWideChar
// );
// int WideCharToMultiByte(
// _In_ UINT CodePage,
// _In_ DWORD dwFlags,
// _In_ LPCWSTR lpWideCharStr,
// _In_ int cchWideChar,
// _Out_opt_ LPSTR lpMultiByteStr,
// _In_ int cbMultiByte,
// _In_opt_ LPCSTR lpDefaultChar,
// _Out_opt_ LPBOOL lpUsedDefaultChar
// );
enum stack {
s_retaddr = 0
, s_arg1 = 4 * 1 // 0x4
//, s_arg2 = 4 * 2 // 0x8
, s_arg3 = 4 * 3 // 0xc
//, s_arg4 = 4 * 4 // 0x10
//, s_arg5 = 4 * 5 // 0x14
//, s_arg6 = 4 * 6 // 0x18
};
// 3/17/2014 jichi: Temporarily disabled
// http://sakuradite.com/topic/159
NEW_HOOK(MultiByteToWideChar, s_arg3, 0,4,0, USING_STRING, 4)
NEW_HOOK(WideCharToMultiByte, s_arg3, 0,4,0, USING_UNICODE|USING_STRING, 4)
DPRINT("leave");
}
void PcHooks::hookCharNextFunctions()
{
enum stack {
s_retaddr = 0
, s_arg1 = 4 * 1 // 0x4
, s_arg2 = 4 * 2 // 0x8
//, s_arg3 = 4 * 3 // 0xc
//, s_arg4 = 4 * 4 // 0x10
//, s_arg5 = 4 * 5 // 0x14
//, s_arg6 = 4 * 6 // 0x18
};
DPRINT("enter");
NEW_HOOK(CharNextA, s_arg1, 0,0,0, USING_STRING|DATA_INDIRECT, 1) // LPTSTR WINAPI CharNext(_In_ LPCTSTR lpsz);
NEW_HOOK(CharNextW, s_arg1, 0,0,0, USING_UNICODE|DATA_INDIRECT, 1)
NEW_HOOK(CharPrevA, s_arg1, 0,0,0, USING_STRING|DATA_INDIRECT, 1) // LPTSTR WINAPI CharPrev(_In_ LPCTSTR lpszStart, _In_ LPCTSTR lpszCurrent);
NEW_HOOK(CharPrevW, s_arg1, 0,0,0, USING_UNICODE|DATA_INDIRECT, 1)
//NEW_HOOK(CharNextExA, s_arg2, 0,0,0, USING_STRING|DATA_INDIRECT, 1) // LPSTR WINAPI CharNextExA(_In_ WORD CodePage, _In_ LPCSTR lpCurrentChar, _In_ DWORD dwFlags);
//NEW_HOOK(CharNextExW, s_arg2, 0,0,0, USING_UNICODE|DATA_INDIRECT, 1)
DPRINT("leave");
}
// EOF