mireado

exclude useless file

Showing 63 changed files with 0 additions and 12899 deletions
1 -/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
2 - * This file is part of the Interactive Text Hooker.
3 -
4 - * Interactive Text Hooker is free software: you can redistribute it and/or
5 - * modify it under the terms of the GNU General Public License as published
6 - * by the Free Software Foundation, either version 3 of the License, or
7 - * (at your option) any later version.
8 -
9 - * This program is distributed in the hope that it will be useful,
10 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 - * GNU General Public License for more details.
13 -
14 - * You should have received a copy of the GNU General Public License
15 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 - */
17 -
18 -#pragma once
19 -
20 -template <class T, unsigned int default_size>
21 -class PointerTable
22 -{
23 -public:
24 - PointerTable()
25 - {
26 - assert((default_size & (default_size - 1)) == 0);
27 - size = default_size;
28 - table = new T*[size];
29 - used = 0;
30 - next = 0;
31 - memset(table, 0, size * sizeof(T*));
32 - }
33 - ~PointerTable()
34 - {
35 - delete table;
36 - }
37 - T* Set(unsigned int number, T* ptr)
38 - {
39 - if (number >= size - 2)
40 - {
41 - unsigned int new_size = size;
42 - while (number >= new_size - 2) new_size <<= 1;
43 - Resize(new_size);
44 - }
45 - T* original = table[number + 1];
46 - table[number + 1] = ptr;
47 - if (ptr == 0) //Clear pointer.
48 - {
49 - if (number < next) next = number;
50 - if (number == used - 1) //Last used position is cleared.
51 - {
52 - table[0] = (T*)1;
53 - for (used--; table[used] == 0; used--);
54 - }
55 - }
56 - else //Set pointer.
57 - {
58 - __assume(number < size - 2); //Otherwise a resize operation is invoked.
59 - if (number == next)
60 - {
61 - next++; //Next position is occupied.
62 - for (next++; table[next]; next++); //There is always a zero in the end.
63 - next--; //next is zero based but the table start at one(zero is used as sentry).
64 - }
65 - if (number >= used) used = number + 1;
66 - }
67 - return original;
68 - }
69 - T* Get(unsigned int number)
70 - {
71 - number++;
72 - if (number <= used) return table[number];
73 - else return 0;
74 - }
75 - T* operator [](unsigned int number)
76 - {
77 - number++;
78 - if (number <= used) return table[number];
79 - else return 0;
80 - }
81 - void Append(T* ptr)
82 - {
83 - Set(next,ptr);
84 - }
85 - void Resize(unsigned int new_size)
86 - {
87 - assert(new_size > size);
88 - assert((new_size & (new_size - 1)) == 0);
89 - assert(new_size < 0x10000);
90 -
91 - T** temp = new T*[new_size];
92 - memcpy(temp, table, size * sizeof(T*));
93 - memset(temp + size, 0, (new_size - size) * sizeof(T*));
94 - delete table;
95 - size = new_size;
96 - table = temp;
97 - }
98 - void DeleteAll() //Release all pointers on demand.
99 - {
100 - T* p;
101 - next = 0;
102 - while (used)
103 - {
104 - p = table[used];
105 - if (p) delete p;
106 - table[used] = 0;
107 - used--;
108 - }
109 - }
110 - void Reset() //Reset without release pointers.
111 - {
112 - memset(table, 0, sizeof(T*) * (used + 1));
113 - next = 0;
114 - used = 0;
115 -
116 - }
117 - unsigned int size,next,used;
118 - T** table;
119 -};
1 -/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
2 - * This file is part of the Interactive Text Hooker.
3 -
4 - * Interactive Text Hooker is free software: you can redistribute it and/or
5 - * modify it under the terms of the GNU General Public License as published
6 - * by the Free Software Foundation, either version 3 of the License, or
7 - * (at your option) any later version.
8 -
9 - * This program is distributed in the hope that it will be useful,
10 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 - * GNU General Public License for more details.
13 -
14 - * You should have received a copy of the GNU General Public License
15 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 - */
17 -
18 -
19 -#include "ITH.h"
20 -#include "ith/host/srv.h"
21 -#include "ith/host/hookman.h"
22 -#include "ith/common/types.h"
23 -#include "ith/common/const.h"
24 -#include "Profile.h"
25 -#include "utility.h"
26 -
27 -Profile::Profile(const std::wstring& title) :
28 -select_index(-1),
29 -title(title)
30 -{}
31 -
32 -std::vector<thread_ptr>::const_iterator Profile::FindThreadProfile(const ThreadParameter& tp) const
33 -{
34 - auto thread_profile = std::find_if(threads.begin(), threads.end(),
35 - [&tp](const thread_ptr& thread_profile) -> bool
36 - {
37 - if (thread_profile->HookAddress() != tp.hook)
38 - return false;
39 - DWORD t1 = thread_profile->Return();
40 - DWORD t2 = tp.retn;
41 - if (thread_profile->Flags() & THREAD_MASK_RETN)
42 - {
43 - t1 &= 0xFFFF;
44 - t2 &= 0xFFFF;
45 - }
46 - if (t1 != t2)
47 - return false;
48 - t1 = thread_profile->Split();
49 - t2 = tp.spl;
50 - if (thread_profile->Flags() & THREAD_MASK_SPLIT)
51 - {
52 - t1 &= 0xFFFF;
53 - t2 &= 0xFFFF;
54 - }
55 - return t1 == t2;
56 - });
57 - return thread_profile;
58 -}
59 -
60 -const std::vector<hook_ptr>& Profile::Hooks() const
61 -{
62 - return hooks;
63 -}
64 -
65 -const std::vector<thread_ptr>& Profile::Threads() const
66 -{
67 - return threads;
68 -}
69 -
70 -const std::vector<link_ptr>& Profile::Links() const
71 -{
72 - return links;
73 -}
74 -
75 -bool Profile::XmlReadProfile(pugi::xml_node profile)
76 -{
77 - auto hooks_node = profile.child(L"Hooks");
78 - auto threads_node = profile.child(L"Threads");
79 - auto links_node = profile.child(L"Links");
80 - if (hooks_node && !XmlReadProfileHook(hooks_node))
81 - return false;
82 - if (threads_node && !XmlReadProfileThread(threads_node))
83 - return false;
84 - if (links_node && !XmlReadProfileLink(links_node))
85 - return false;
86 - auto select_node = profile.child(L"Select");
87 - if (select_node)
88 - {
89 - auto thread_index = select_node.attribute(L"ThreadIndex");
90 - if (!thread_index)
91 - return false;
92 - DWORD tmp_select = std::stoul(thread_index.value(), NULL, 16);
93 - select_index = tmp_select & 0xFFFF;
94 - }
95 - return true;
96 -}
97 -
98 -bool Profile::XmlReadProfileHook(pugi::xml_node hooks_node)
99 -{
100 - for (auto hook = hooks_node.begin(); hook != hooks_node.end(); ++hook)
101 - {
102 - std::wstring name = hook->name();
103 - if (name.empty() || name.compare(L"Hook") != 0)
104 - return false;
105 - auto type = hook->attribute(L"Type");
106 - if (!type || type.empty())
107 - return false;
108 - auto code = hook->attribute(L"Code");
109 - if (!code)
110 - return false;
111 - std::wstring code_value = code.value();
112 - HookParam hp = {};
113 - switch (type.value()[0])
114 - {
115 - case L'H':
116 - if (code_value[0] != L'/')
117 - return false;
118 - if (code_value[1] != L'H' && code_value[1] != L'h')
119 - return false;
120 - if (Parse(code_value.substr(2), hp))
121 - {
122 - auto name = hook->attribute(L"Name");
123 - if (!name || name.empty())
124 - AddHook(hp, L"");
125 - else
126 - AddHook(hp, name.value());
127 - }
128 - break;
129 - default:
130 - return false;
131 - }
132 - }
133 - return true;
134 -}
135 -
136 -bool Profile::XmlReadProfileThread(pugi::xml_node threads_node)
137 -{
138 - std::wstring hook_name_buffer;
139 - for (auto thread = threads_node.begin(); thread != threads_node.end(); ++thread)
140 - {
141 - std::wstring name = thread->name();
142 - if (name.empty() || name.compare(L"Thread") != 0)
143 - return false;
144 - auto hook_name = thread->attribute(L"HookName");
145 - if (!hook_name)
146 - return false;
147 - auto context = thread->attribute(L"Context");
148 - if (!context)
149 - return false;
150 - auto sub_context = thread->attribute(L"SubContext");
151 - if (!sub_context)
152 - return false;
153 - auto mask = thread->attribute(L"Mask");
154 - if (!mask)
155 - return false;
156 - DWORD mask_tmp = std::stoul(mask.value(), NULL, 16);
157 - auto comment = thread->attribute(L"Comment");
158 - auto retn = std::stoul(context.value(), NULL, 16);
159 - WORD hm_index = 0;
160 - auto hook_addr = 0;
161 - auto split = std::stoul(sub_context.value(), NULL, 16);
162 - WORD flags = mask_tmp & 0xFFFF;
163 - auto tp = new ThreadProfile(hook_name.value(), retn, split, hook_addr, hm_index, flags,
164 - comment.value());
165 - AddThread(thread_ptr(tp));
166 - }
167 - return true;
168 -}
169 -
170 -bool Profile::XmlReadProfileLink(pugi::xml_node links_node)
171 -{
172 - for (auto link = links_node.begin(); link != links_node.end(); ++link)
173 - {
174 - std::wstring name = link->name();
175 - if (name.empty() || name.compare(L"Link") != 0)
176 - return false;
177 - auto from = link->attribute(L"From");
178 - if (!from)
179 - return false;
180 - DWORD link_from = std::stoul(from.value(), NULL, 16);
181 - auto to = link->attribute(L"To");
182 - if (!to)
183 - return false;
184 - DWORD link_to = std::stoul(to.value(), NULL, 16);
185 - auto lp = new LinkProfile(link_from & 0xFFFF, link_to & 0xFFFF);
186 - AddLink(link_ptr(lp));
187 - }
188 - return true;
189 -}
190 -
191 -bool Profile::XmlWriteProfile(pugi::xml_node profile_node)
192 -{
193 - if (!hooks.empty())
194 - {
195 - auto node = profile_node.append_child(L"Hooks");
196 - XmlWriteProfileHook(node);
197 - }
198 - if (!threads.empty())
199 - {
200 - auto node = profile_node.append_child(L"Threads");
201 - XmlWriteProfileThread(node);
202 - }
203 - if (!links.empty())
204 - {
205 - auto node = profile_node.append_child(L"Links");
206 - XmlWriteProfileLink(node);
207 - }
208 - if (select_index != 0xFFFF)
209 - {
210 - auto node = profile_node.append_child(L"Select");
211 - node.append_attribute(L"ThreadIndex") = select_index;
212 - }
213 - return true;
214 -}
215 -
216 -bool Profile::XmlWriteProfileHook(pugi::xml_node hooks_node)
217 -{
218 - for (auto hook = hooks.begin(); hook != hooks.end(); ++hook)
219 - {
220 - auto hook_node = hooks_node.append_child(L"Hook");
221 - hook_node.append_attribute(L"Type") = L"H";
222 - hook_node.append_attribute(L"Code") = GetCode((*hook)->HP()).c_str();
223 - if (!(*hook)->Name().empty())
224 - hook_node.append_attribute(L"Name") = (*hook)->Name().c_str();
225 - }
226 - return true;
227 -}
228 -
229 -bool Profile::XmlWriteProfileThread(pugi::xml_node threads_node)
230 -{
231 - for (auto thread = threads.begin(); thread != threads.end(); ++thread)
232 - {
233 - const std::wstring& name = (*thread)->HookName();
234 - if (name.empty())
235 - return false;
236 - auto node = threads_node.append_child(L"Thread");
237 - node.append_attribute(L"HookName") = name.c_str();
238 - node.append_attribute(L"Mask") = ToHexString((*thread)->Flags() & 3).c_str();
239 - node.append_attribute(L"SubContext") = ToHexString((*thread)->Split()).c_str();
240 - node.append_attribute(L"Context") = ToHexString((*thread)->Return()).c_str();
241 - if (!(*thread)->Comment().empty())
242 - node.append_attribute(L"Comment") = (*thread)->Comment().c_str();
243 - }
244 - return true;
245 -}
246 -
247 -bool Profile::XmlWriteProfileLink(pugi::xml_node links_node)
248 -{
249 - for (auto link = links.begin(); link != links.end(); ++link)
250 - {
251 - auto node = links_node.append_child(L"Link");
252 - node.append_attribute(L"From") = ToHexString((*link)->FromIndex()).c_str();
253 - node.append_attribute(L"To") = ToHexString((*link)->ToIndex()).c_str();
254 - }
255 - return true;
256 -}
257 -
258 -void Profile::Clear()
259 -{
260 - title = L"";
261 - select_index = -1;
262 - hooks.clear();
263 - threads.clear();
264 - links.clear();
265 -}
266 -
267 -int Profile::AddHook(const HookParam& hp, const std::wstring& name)
268 -{
269 - //if (hook_count == 4) return;
270 - auto it = std::find_if(hooks.begin(), hooks.end(), [&hp](hook_ptr& hook)
271 - {
272 - return hook->HP().addr == hp.addr &&
273 - hook->HP().module == hp.module &&
274 - hook->HP().function == hp.function;
275 - });
276 - if (it != hooks.end())
277 - return it - hooks.begin();
278 - hooks.emplace_back(new HookProfile(hp, name));
279 - return hooks.size() - 1;
280 -}
281 -
282 -// add the thread profile and return its index
283 -int Profile::AddThread(thread_ptr tp)
284 -{
285 - auto it = std::find_if(threads.begin(), threads.end(), [&tp](thread_ptr& thread)
286 - {
287 - return thread->HookName().compare(tp->HookName()) == 0 &&
288 - thread->Return() == tp->Return() &&
289 - thread->Split() == tp->Split();
290 - });
291 - if (it != threads.end())
292 - return it - threads.begin();
293 - threads.push_back(std::move(tp));
294 - return threads.size() - 1;
295 -}
296 -
297 -int Profile::AddLink(link_ptr lp)
298 -{
299 - auto it = std::find_if(links.begin(), links.end(), [&lp] (link_ptr& link)
300 - {
301 - return link->FromIndex() == lp->FromIndex() &&
302 - link->ToIndex() == lp->ToIndex();
303 - });
304 - if (it != links.end())
305 - return it - links.begin();
306 - links.push_back(std::move(lp));
307 - return links.size() - 1;
308 -}
309 -
310 -void Profile::RemoveHook(DWORD index)
311 -{
312 - if (index >= 0 && index < hooks.size())
313 - hooks.erase(hooks.begin() + index);
314 -}
315 -
316 -void Profile::RemoveThread(DWORD index)
317 -{
318 - if (index >= 0 && index < threads.size())
319 - {
320 - links.erase(std::remove_if(links.begin(), links.end(), [index](link_ptr& link)
321 - {
322 - return link->FromIndex() == index + 1 || link->ToIndex() == index + 1;
323 - }), links.end());
324 - if (select_index == index)
325 - select_index = -1;
326 - threads.erase(threads.begin() + index);
327 - if (index < select_index)
328 - select_index--;
329 - }
330 -}
331 -
332 -void Profile::RemoveLink(DWORD index)
333 -{
334 - if (index >= 0 && index < links.size())
335 - links.erase(links.begin() + index);
336 -}
337 -
338 -const std::wstring& Profile::Title() const
339 -{
340 - return title;
341 -}
1 -/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
2 - * This file is part of the Interactive Text Hooker.
3 -
4 - * Interactive Text Hooker is free software: you can redistribute it and/or
5 - * modify it under the terms of the GNU General Public License as published
6 - * by the Free Software Foundation, either version 3 of the License, or
7 - * (at your option) any later version.
8 -
9 - * This program is distributed in the hope that it will be useful,
10 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 - * GNU General Public License for more details.
13 -
14 - * You should have received a copy of the GNU General Public License
15 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 - */
17 -
18 -#pragma once
19 -#include "ITH.h"
20 -#include "ith/common/types.h" // HookParam
21 -
22 -struct ThreadParameter;
23 -
24 -#define THREAD_MASK_RETN 1
25 -#define THREAD_MASK_SPLIT 2
26 -
27 -class HookProfile
28 -{
29 - HookParam hp;
30 - std::wstring name;
31 -public:
32 - HookProfile(const HookParam& hp, const std::wstring& name):
33 - hp(hp),
34 - name(name)
35 - {}
36 - const HookParam& HP() const { return hp; };
37 - const std::wstring& Name() const { return name; };
38 -};
39 -
40 -class ThreadProfile
41 -{
42 - std::wstring hook_name;
43 - DWORD retn;
44 - DWORD split;
45 - DWORD hook_addr;
46 - WORD hm_index, flags;
47 - std::wstring comment;
48 -public:
49 - ThreadProfile(const std::wstring& hook_name,
50 - DWORD retn,
51 - DWORD split,
52 - DWORD hook_addr,
53 - WORD hm_index,
54 - WORD flags,
55 - const std::wstring& comment) :
56 - hook_name(hook_name),
57 - retn(retn),
58 - split(split),
59 - hook_addr(hook_addr),
60 - hm_index(hm_index),
61 - flags(flags),
62 - comment(comment)
63 - {
64 - }
65 - const std::wstring& HookName() const { return hook_name; }
66 - const std::wstring& Comment() const { return comment; }
67 - DWORD Return() const { return retn; }
68 - DWORD Split() const { return split; }
69 - DWORD& HookAddress() { return hook_addr; }
70 - WORD& HookManagerIndex() { return hm_index; }
71 - WORD Flags() const { return flags; }
72 -};
73 -
74 -class LinkProfile
75 -{
76 - WORD from_index, to_index;
77 -public:
78 - LinkProfile(WORD from_index, WORD to_index):
79 - from_index(from_index),
80 - to_index(to_index)
81 - {}
82 - WORD FromIndex() const { return from_index; }
83 - WORD ToIndex() const { return to_index; }
84 -};
85 -
86 -typedef std::unique_ptr<HookProfile> hook_ptr;
87 -typedef std::unique_ptr<ThreadProfile> thread_ptr;
88 -typedef std::unique_ptr<LinkProfile> link_ptr;
89 -
90 -class Profile
91 -{
92 -public:
93 - Profile(const std::wstring& title);
94 - bool XmlReadProfile(pugi::xml_node profile_node);
95 - bool XmlWriteProfile(pugi::xml_node profile_node);
96 - int AddHook(const HookParam& hp, const std::wstring& name);
97 - int AddThread(thread_ptr tp);
98 - int AddLink(link_ptr lp);
99 - void Clear();
100 - const std::vector<hook_ptr>& Hooks() const;
101 - const std::vector<thread_ptr>& Threads() const;
102 - const std::vector<link_ptr>& Links() const;
103 - const std::wstring& Title() const;
104 - std::vector<thread_ptr>::const_iterator FindThreadProfile(const ThreadParameter& tp) const;
105 - WORD& SelectedIndex() { return select_index; }
106 -
107 -private:
108 - void RemoveLink(DWORD index);
109 - void RemoveHook(DWORD index);
110 - void RemoveThread(DWORD index);
111 -
112 - bool XmlReadProfileHook(pugi::xml_node hooks_node);
113 - bool XmlReadProfileThread(pugi::xml_node threads_node);
114 - bool XmlReadProfileLink(pugi::xml_node links_node);
115 - bool XmlWriteProfileHook(pugi::xml_node hooks_node);
116 - bool XmlWriteProfileThread(pugi::xml_node threads_node);
117 - bool XmlWriteProfileLink(pugi::xml_node links_node);
118 -
119 - std::wstring title;
120 - std::vector<hook_ptr> hooks;
121 - std::vector<thread_ptr> threads;
122 - std::vector<link_ptr> links;
123 -
124 - WORD select_index;
125 -};
1 -/**
2 - * pugixml parser - version 1.5
3 - * --------------------------------------------------------
4 - * Copyright (C) 2006-2014, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
5 - * Report bugs and download new versions at http://pugixml.org/
6 - *
7 - * This library is distributed under the MIT License. See notice at the end
8 - * of this file.
9 - *
10 - * This work is based on the pugxml parser, which is:
11 - * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
12 - */
13 -
14 -#ifndef HEADER_PUGICONFIG_HPP
15 -#define HEADER_PUGICONFIG_HPP
16 -
17 -// Uncomment this to enable wchar_t mode
18 -#define PUGIXML_WCHAR_MODE
19 -
20 -// Uncomment this to disable XPath
21 -// #define PUGIXML_NO_XPATH
22 -
23 -// Uncomment this to disable STL
24 -// #define PUGIXML_NO_STL
25 -
26 -// Uncomment this to disable exceptions
27 -// #define PUGIXML_NO_EXCEPTIONS
28 -
29 -// Set this to control attributes for public classes/functions, i.e.:
30 -// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
31 -// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
32 -// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
33 -// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
34 -
35 -// Tune these constants to adjust memory-related behavior
36 -// #define PUGIXML_MEMORY_PAGE_SIZE 32768
37 -// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
38 -// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
39 -
40 -// Uncomment this to switch to header-only version
41 -// #define PUGIXML_HEADER_ONLY
42 -// #include "pugixml.cpp"
43 -
44 -// Uncomment this to enable long long support
45 -// #define PUGIXML_HAS_LONG_LONG
46 -
47 -#endif
48 -
49 -/**
50 - * Copyright (c) 2006-2014 Arseny Kapoulkine
51 - *
52 - * Permission is hereby granted, free of charge, to any person
53 - * obtaining a copy of this software and associated documentation
54 - * files (the "Software"), to deal in the Software without
55 - * restriction, including without limitation the rights to use,
56 - * copy, modify, merge, publish, distribute, sublicense, and/or sell
57 - * copies of the Software, and to permit persons to whom the
58 - * Software is furnished to do so, subject to the following
59 - * conditions:
60 - *
61 - * The above copyright notice and this permission notice shall be
62 - * included in all copies or substantial portions of the Software.
63 - *
64 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
65 - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
66 - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
67 - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
68 - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
69 - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
70 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
71 - * OTHER DEALINGS IN THE SOFTWARE.
72 - */
This diff could not be displayed because it is too large.
1 -/**
2 - * pugixml parser - version 1.5
3 - * --------------------------------------------------------
4 - * Copyright (C) 2006-2014, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
5 - * Report bugs and download new versions at http://pugixml.org/
6 - *
7 - * This library is distributed under the MIT License. See notice at the end
8 - * of this file.
9 - *
10 - * This work is based on the pugxml parser, which is:
11 - * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
12 - */
13 -
14 -#ifndef PUGIXML_VERSION
15 -// Define version macro; evaluates to major * 100 + minor so that it's safe to use in less-than comparisons
16 -# define PUGIXML_VERSION 150
17 -#endif
18 -
19 -// Include user configuration file (this can define various configuration macros)
20 -#include "pugiconfig.hpp"
21 -
22 -#ifndef HEADER_PUGIXML_HPP
23 -#define HEADER_PUGIXML_HPP
24 -
25 -// Include stddef.h for size_t and ptrdiff_t
26 -#include <stddef.h>
27 -
28 -// Include exception header for XPath
29 -#if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS)
30 -# include <exception>
31 -#endif
32 -
33 -// Include STL headers
34 -#ifndef PUGIXML_NO_STL
35 -# include <iterator>
36 -# include <iosfwd>
37 -# include <string>
38 -#endif
39 -
40 -// Macro for deprecated features
41 -#ifndef PUGIXML_DEPRECATED
42 -# if defined(__GNUC__)
43 -# define PUGIXML_DEPRECATED __attribute__((deprecated))
44 -# elif defined(_MSC_VER) && _MSC_VER >= 1300
45 -# define PUGIXML_DEPRECATED __declspec(deprecated)
46 -# else
47 -# define PUGIXML_DEPRECATED
48 -# endif
49 -#endif
50 -
51 -// If no API is defined, assume default
52 -#ifndef PUGIXML_API
53 -# define PUGIXML_API
54 -#endif
55 -
56 -// If no API for classes is defined, assume default
57 -#ifndef PUGIXML_CLASS
58 -# define PUGIXML_CLASS PUGIXML_API
59 -#endif
60 -
61 -// If no API for functions is defined, assume default
62 -#ifndef PUGIXML_FUNCTION
63 -# define PUGIXML_FUNCTION PUGIXML_API
64 -#endif
65 -
66 -// If the platform is known to have long long support, enable long long functions
67 -#ifndef PUGIXML_HAS_LONG_LONG
68 -# if defined(__cplusplus) && __cplusplus >= 201103
69 -# define PUGIXML_HAS_LONG_LONG
70 -# elif defined(_MSC_VER) && _MSC_VER >= 1400
71 -# define PUGIXML_HAS_LONG_LONG
72 -# endif
73 -#endif
74 -
75 -// Character interface macros
76 -#ifdef PUGIXML_WCHAR_MODE
77 -# define PUGIXML_TEXT(t) L ## t
78 -# define PUGIXML_CHAR wchar_t
79 -#else
80 -# define PUGIXML_TEXT(t) t
81 -# define PUGIXML_CHAR char
82 -#endif
83 -
84 -namespace pugi
85 -{
86 - // Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE
87 - typedef PUGIXML_CHAR char_t;
88 -
89 -#ifndef PUGIXML_NO_STL
90 - // String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE
91 - typedef std::basic_string<PUGIXML_CHAR, std::char_traits<PUGIXML_CHAR>, std::allocator<PUGIXML_CHAR> > string_t;
92 -#endif
93 -}
94 -
95 -// The PugiXML namespace
96 -namespace pugi
97 -{
98 - // Tree node types
99 - enum xml_node_type
100 - {
101 - node_null, // Empty (null) node handle
102 - node_document, // A document tree's absolute root
103 - node_element, // Element tag, i.e. '<node/>'
104 - node_pcdata, // Plain character data, i.e. 'text'
105 - node_cdata, // Character data, i.e. '<![CDATA[text]]>'
106 - node_comment, // Comment tag, i.e. '<!-- text -->'
107 - node_pi, // Processing instruction, i.e. '<?name?>'
108 - node_declaration, // Document declaration, i.e. '<?xml version="1.0"?>'
109 - node_doctype // Document type declaration, i.e. '<!DOCTYPE doc>'
110 - };
111 -
112 - // Parsing options
113 -
114 - // Minimal parsing mode (equivalent to turning all other flags off).
115 - // Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed.
116 - const unsigned int parse_minimal = 0x0000;
117 -
118 - // This flag determines if processing instructions (node_pi) are added to the DOM tree. This flag is off by default.
119 - const unsigned int parse_pi = 0x0001;
120 -
121 - // This flag determines if comments (node_comment) are added to the DOM tree. This flag is off by default.
122 - const unsigned int parse_comments = 0x0002;
123 -
124 - // This flag determines if CDATA sections (node_cdata) are added to the DOM tree. This flag is on by default.
125 - const unsigned int parse_cdata = 0x0004;
126 -
127 - // This flag determines if plain character data (node_pcdata) that consist only of whitespace are added to the DOM tree.
128 - // This flag is off by default; turning it on usually results in slower parsing and more memory consumption.
129 - const unsigned int parse_ws_pcdata = 0x0008;
130 -
131 - // This flag determines if character and entity references are expanded during parsing. This flag is on by default.
132 - const unsigned int parse_escapes = 0x0010;
133 -
134 - // This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default.
135 - const unsigned int parse_eol = 0x0020;
136 -
137 - // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default.
138 - const unsigned int parse_wconv_attribute = 0x0040;
139 -
140 - // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default.
141 - const unsigned int parse_wnorm_attribute = 0x0080;
142 -
143 - // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default.
144 - const unsigned int parse_declaration = 0x0100;
145 -
146 - // This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default.
147 - const unsigned int parse_doctype = 0x0200;
148 -
149 - // This flag determines if plain character data (node_pcdata) that is the only child of the parent node and that consists only
150 - // of whitespace is added to the DOM tree.
151 - // This flag is off by default; turning it on may result in slower parsing and more memory consumption.
152 - const unsigned int parse_ws_pcdata_single = 0x0400;
153 -
154 - // This flag determines if leading and trailing whitespace is to be removed from plain character data. This flag is off by default.
155 - const unsigned int parse_trim_pcdata = 0x0800;
156 -
157 - // This flag determines if plain character data that does not have a parent node is added to the DOM tree, and if an empty document
158 - // is a valid document. This flag is off by default.
159 - const unsigned int parse_fragment = 0x1000;
160 -
161 - // The default parsing mode.
162 - // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded,
163 - // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules.
164 - const unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol;
165 -
166 - // The full parsing mode.
167 - // Nodes of all types are added to the DOM tree, character/reference entities are expanded,
168 - // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules.
169 - const unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype;
170 -
171 - // These flags determine the encoding of input data for XML document
172 - enum xml_encoding
173 - {
174 - encoding_auto, // Auto-detect input encoding using BOM or < / <? detection; use UTF8 if BOM is not found
175 - encoding_utf8, // UTF8 encoding
176 - encoding_utf16_le, // Little-endian UTF16
177 - encoding_utf16_be, // Big-endian UTF16
178 - encoding_utf16, // UTF16 with native endianness
179 - encoding_utf32_le, // Little-endian UTF32
180 - encoding_utf32_be, // Big-endian UTF32
181 - encoding_utf32, // UTF32 with native endianness
182 - encoding_wchar, // The same encoding wchar_t has (either UTF16 or UTF32)
183 - encoding_latin1
184 - };
185 -
186 - // Formatting flags
187 -
188 - // Indent the nodes that are written to output stream with as many indentation strings as deep the node is in DOM tree. This flag is on by default.
189 - const unsigned int format_indent = 0x01;
190 -
191 - // Write encoding-specific BOM to the output stream. This flag is off by default.
192 - const unsigned int format_write_bom = 0x02;
193 -
194 - // Use raw output mode (no indentation and no line breaks are written). This flag is off by default.
195 - const unsigned int format_raw = 0x04;
196 -
197 - // Omit default XML declaration even if there is no declaration in the document. This flag is off by default.
198 - const unsigned int format_no_declaration = 0x08;
199 -
200 - // Don't escape attribute values and PCDATA contents. This flag is off by default.
201 - const unsigned int format_no_escapes = 0x10;
202 -
203 - // Open file using text mode in xml_document::save_file. This enables special character (i.e. new-line) conversions on some systems. This flag is off by default.
204 - const unsigned int format_save_file_text = 0x20;
205 -
206 - // The default set of formatting flags.
207 - // Nodes are indented depending on their depth in DOM tree, a default declaration is output if document has none.
208 - const unsigned int format_default = format_indent;
209 -
210 - // Forward declarations
211 - struct xml_attribute_struct;
212 - struct xml_node_struct;
213 -
214 - class xml_node_iterator;
215 - class xml_attribute_iterator;
216 - class xml_named_node_iterator;
217 -
218 - class xml_tree_walker;
219 -
220 - struct xml_parse_result;
221 -
222 - class xml_node;
223 -
224 - class xml_text;
225 -
226 - #ifndef PUGIXML_NO_XPATH
227 - class xpath_node;
228 - class xpath_node_set;
229 - class xpath_query;
230 - class xpath_variable_set;
231 - #endif
232 -
233 - // Range-based for loop support
234 - template <typename It> class xml_object_range
235 - {
236 - public:
237 - typedef It const_iterator;
238 - typedef It iterator;
239 -
240 - xml_object_range(It b, It e): _begin(b), _end(e)
241 - {
242 - }
243 -
244 - It begin() const { return _begin; }
245 - It end() const { return _end; }
246 -
247 - private:
248 - It _begin, _end;
249 - };
250 -
251 - // Writer interface for node printing (see xml_node::print)
252 - class PUGIXML_CLASS xml_writer
253 - {
254 - public:
255 - virtual ~xml_writer() {}
256 -
257 - // Write memory chunk into stream/file/whatever
258 - virtual void write(const void* data, size_t size) = 0;
259 - };
260 -
261 - // xml_writer implementation for FILE*
262 - class PUGIXML_CLASS xml_writer_file: public xml_writer
263 - {
264 - public:
265 - // Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio
266 - xml_writer_file(void* file);
267 -
268 - virtual void write(const void* data, size_t size);
269 -
270 - private:
271 - void* file;
272 - };
273 -
274 - #ifndef PUGIXML_NO_STL
275 - // xml_writer implementation for streams
276 - class PUGIXML_CLASS xml_writer_stream: public xml_writer
277 - {
278 - public:
279 - // Construct writer from an output stream object
280 - xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream);
281 - xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream);
282 -
283 - virtual void write(const void* data, size_t size);
284 -
285 - private:
286 - std::basic_ostream<char, std::char_traits<char> >* narrow_stream;
287 - std::basic_ostream<wchar_t, std::char_traits<wchar_t> >* wide_stream;
288 - };
289 - #endif
290 -
291 - // A light-weight handle for manipulating attributes in DOM tree
292 - class PUGIXML_CLASS xml_attribute
293 - {
294 - friend class xml_attribute_iterator;
295 - friend class xml_node;
296 -
297 - private:
298 - xml_attribute_struct* _attr;
299 -
300 - typedef void (*unspecified_bool_type)(xml_attribute***);
301 -
302 - public:
303 - // Default constructor. Constructs an empty attribute.
304 - xml_attribute();
305 -
306 - // Constructs attribute from internal pointer
307 - explicit xml_attribute(xml_attribute_struct* attr);
308 -
309 - // Safe bool conversion operator
310 - operator unspecified_bool_type() const;
311 -
312 - // Borland C++ workaround
313 - bool operator!() const;
314 -
315 - // Comparison operators (compares wrapped attribute pointers)
316 - bool operator==(const xml_attribute& r) const;
317 - bool operator!=(const xml_attribute& r) const;
318 - bool operator<(const xml_attribute& r) const;
319 - bool operator>(const xml_attribute& r) const;
320 - bool operator<=(const xml_attribute& r) const;
321 - bool operator>=(const xml_attribute& r) const;
322 -
323 - // Check if attribute is empty
324 - bool empty() const;
325 -
326 - // Get attribute name/value, or "" if attribute is empty
327 - const char_t* name() const;
328 - const char_t* value() const;
329 -
330 - // Get attribute value, or the default value if attribute is empty
331 - const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const;
332 -
333 - // Get attribute value as a number, or the default value if conversion did not succeed or attribute is empty
334 - int as_int(int def = 0) const;
335 - unsigned int as_uint(unsigned int def = 0) const;
336 - double as_double(double def = 0) const;
337 - float as_float(float def = 0) const;
338 -
339 - #ifdef PUGIXML_HAS_LONG_LONG
340 - long long as_llong(long long def = 0) const;
341 - unsigned long long as_ullong(unsigned long long def = 0) const;
342 - #endif
343 -
344 - // Get attribute value as bool (returns true if first character is in '1tTyY' set), or the default value if attribute is empty
345 - bool as_bool(bool def = false) const;
346 -
347 - // Set attribute name/value (returns false if attribute is empty or there is not enough memory)
348 - bool set_name(const char_t* rhs);
349 - bool set_value(const char_t* rhs);
350 -
351 - // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
352 - bool set_value(int rhs);
353 - bool set_value(unsigned int rhs);
354 - bool set_value(double rhs);
355 - bool set_value(bool rhs);
356 -
357 - #ifdef PUGIXML_HAS_LONG_LONG
358 - bool set_value(long long rhs);
359 - bool set_value(unsigned long long rhs);
360 - #endif
361 -
362 - // Set attribute value (equivalent to set_value without error checking)
363 - xml_attribute& operator=(const char_t* rhs);
364 - xml_attribute& operator=(int rhs);
365 - xml_attribute& operator=(unsigned int rhs);
366 - xml_attribute& operator=(double rhs);
367 - xml_attribute& operator=(bool rhs);
368 -
369 - #ifdef PUGIXML_HAS_LONG_LONG
370 - xml_attribute& operator=(long long rhs);
371 - xml_attribute& operator=(unsigned long long rhs);
372 - #endif
373 -
374 - // Get next/previous attribute in the attribute list of the parent node
375 - xml_attribute next_attribute() const;
376 - xml_attribute previous_attribute() const;
377 -
378 - // Get hash value (unique for handles to the same object)
379 - size_t hash_value() const;
380 -
381 - // Get internal pointer
382 - xml_attribute_struct* internal_object() const;
383 - };
384 -
385 -#ifdef __BORLANDC__
386 - // Borland C++ workaround
387 - bool PUGIXML_FUNCTION operator&&(const xml_attribute& lhs, bool rhs);
388 - bool PUGIXML_FUNCTION operator||(const xml_attribute& lhs, bool rhs);
389 -#endif
390 -
391 - // A light-weight handle for manipulating nodes in DOM tree
392 - class PUGIXML_CLASS xml_node
393 - {
394 - friend class xml_attribute_iterator;
395 - friend class xml_node_iterator;
396 - friend class xml_named_node_iterator;
397 -
398 - protected:
399 - xml_node_struct* _root;
400 -
401 - typedef void (*unspecified_bool_type)(xml_node***);
402 -
403 - public:
404 - // Default constructor. Constructs an empty node.
405 - xml_node();
406 -
407 - // Constructs node from internal pointer
408 - explicit xml_node(xml_node_struct* p);
409 -
410 - // Safe bool conversion operator
411 - operator unspecified_bool_type() const;
412 -
413 - // Borland C++ workaround
414 - bool operator!() const;
415 -
416 - // Comparison operators (compares wrapped node pointers)
417 - bool operator==(const xml_node& r) const;
418 - bool operator!=(const xml_node& r) const;
419 - bool operator<(const xml_node& r) const;
420 - bool operator>(const xml_node& r) const;
421 - bool operator<=(const xml_node& r) const;
422 - bool operator>=(const xml_node& r) const;
423 -
424 - // Check if node is empty.
425 - bool empty() const;
426 -
427 - // Get node type
428 - xml_node_type type() const;
429 -
430 - // Get node name, or "" if node is empty or it has no name
431 - const char_t* name() const;
432 -
433 - // Get node value, or "" if node is empty or it has no value
434 - // Note: For <node>text</node> node.value() does not return "text"! Use child_value() or text() methods to access text inside nodes.
435 - const char_t* value() const;
436 -
437 - // Get attribute list
438 - xml_attribute first_attribute() const;
439 - xml_attribute last_attribute() const;
440 -
441 - // Get children list
442 - xml_node first_child() const;
443 - xml_node last_child() const;
444 -
445 - // Get next/previous sibling in the children list of the parent node
446 - xml_node next_sibling() const;
447 - xml_node previous_sibling() const;
448 -
449 - // Get parent node
450 - xml_node parent() const;
451 -
452 - // Get root of DOM tree this node belongs to
453 - xml_node root() const;
454 -
455 - // Get text object for the current node
456 - xml_text text() const;
457 -
458 - // Get child, attribute or next/previous sibling with the specified name
459 - xml_node child(const char_t* name) const;
460 - xml_attribute attribute(const char_t* name) const;
461 - xml_node next_sibling(const char_t* name) const;
462 - xml_node previous_sibling(const char_t* name) const;
463 -
464 - // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA
465 - const char_t* child_value() const;
466 -
467 - // Get child value of child with specified name. Equivalent to child(name).child_value().
468 - const char_t* child_value(const char_t* name) const;
469 -
470 - // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value)
471 - bool set_name(const char_t* rhs);
472 - bool set_value(const char_t* rhs);
473 -
474 - // Add attribute with specified name. Returns added attribute, or empty attribute on errors.
475 - xml_attribute append_attribute(const char_t* name);
476 - xml_attribute prepend_attribute(const char_t* name);
477 - xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr);
478 - xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr);
479 -
480 - // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors.
481 - xml_attribute append_copy(const xml_attribute& proto);
482 - xml_attribute prepend_copy(const xml_attribute& proto);
483 - xml_attribute insert_copy_after(const xml_attribute& proto, const xml_attribute& attr);
484 - xml_attribute insert_copy_before(const xml_attribute& proto, const xml_attribute& attr);
485 -
486 - // Add child node with specified type. Returns added node, or empty node on errors.
487 - xml_node append_child(xml_node_type type = node_element);
488 - xml_node prepend_child(xml_node_type type = node_element);
489 - xml_node insert_child_after(xml_node_type type, const xml_node& node);
490 - xml_node insert_child_before(xml_node_type type, const xml_node& node);
491 -
492 - // Add child element with specified name. Returns added node, or empty node on errors.
493 - xml_node append_child(const char_t* name);
494 - xml_node prepend_child(const char_t* name);
495 - xml_node insert_child_after(const char_t* name, const xml_node& node);
496 - xml_node insert_child_before(const char_t* name, const xml_node& node);
497 -
498 - // Add a copy of the specified node as a child. Returns added node, or empty node on errors.
499 - xml_node append_copy(const xml_node& proto);
500 - xml_node prepend_copy(const xml_node& proto);
501 - xml_node insert_copy_after(const xml_node& proto, const xml_node& node);
502 - xml_node insert_copy_before(const xml_node& proto, const xml_node& node);
503 -
504 - // Move the specified node to become a child of this node. Returns moved node, or empty node on errors.
505 - xml_node append_move(const xml_node& moved);
506 - xml_node prepend_move(const xml_node& moved);
507 - xml_node insert_move_after(const xml_node& moved, const xml_node& node);
508 - xml_node insert_move_before(const xml_node& moved, const xml_node& node);
509 -
510 - // Remove specified attribute
511 - bool remove_attribute(const xml_attribute& a);
512 - bool remove_attribute(const char_t* name);
513 -
514 - // Remove specified child
515 - bool remove_child(const xml_node& n);
516 - bool remove_child(const char_t* name);
517 -
518 - // Parses buffer as an XML document fragment and appends all nodes as children of the current node.
519 - // Copies/converts the buffer, so it may be deleted or changed after the function returns.
520 - // Note: append_buffer allocates memory that has the lifetime of the owning document; removing the appended nodes does not immediately reclaim that memory.
521 - xml_parse_result append_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
522 -
523 - // Find attribute using predicate. Returns first attribute for which predicate returned true.
524 - template <typename Predicate> xml_attribute find_attribute(Predicate pred) const
525 - {
526 - if (!_root) return xml_attribute();
527 -
528 - for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute())
529 - if (pred(attrib))
530 - return attrib;
531 -
532 - return xml_attribute();
533 - }
534 -
535 - // Find child node using predicate. Returns first child for which predicate returned true.
536 - template <typename Predicate> xml_node find_child(Predicate pred) const
537 - {
538 - if (!_root) return xml_node();
539 -
540 - for (xml_node node = first_child(); node; node = node.next_sibling())
541 - if (pred(node))
542 - return node;
543 -
544 - return xml_node();
545 - }
546 -
547 - // Find node from subtree using predicate. Returns first node from subtree (depth-first), for which predicate returned true.
548 - template <typename Predicate> xml_node find_node(Predicate pred) const
549 - {
550 - if (!_root) return xml_node();
551 -
552 - xml_node cur = first_child();
553 -
554 - while (cur._root && cur._root != _root)
555 - {
556 - if (pred(cur)) return cur;
557 -
558 - if (cur.first_child()) cur = cur.first_child();
559 - else if (cur.next_sibling()) cur = cur.next_sibling();
560 - else
561 - {
562 - while (!cur.next_sibling() && cur._root != _root) cur = cur.parent();
563 -
564 - if (cur._root != _root) cur = cur.next_sibling();
565 - }
566 - }
567 -
568 - return xml_node();
569 - }
570 -
571 - // Find child node by attribute name/value
572 - xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const;
573 - xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const;
574 -
575 - #ifndef PUGIXML_NO_STL
576 - // Get the absolute node path from root as a text string.
577 - string_t path(char_t delimiter = '/') const;
578 - #endif
579 -
580 - // Search for a node by path consisting of node names and . or .. elements.
581 - xml_node first_element_by_path(const char_t* path, char_t delimiter = '/') const;
582 -
583 - // Recursively traverse subtree with xml_tree_walker
584 - bool traverse(xml_tree_walker& walker);
585 -
586 - #ifndef PUGIXML_NO_XPATH
587 - // Select single node by evaluating XPath query. Returns first node from the resulting node set.
588 - xpath_node select_node(const char_t* query, xpath_variable_set* variables = 0) const;
589 - xpath_node select_node(const xpath_query& query) const;
590 -
591 - // Select node set by evaluating XPath query
592 - xpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = 0) const;
593 - xpath_node_set select_nodes(const xpath_query& query) const;
594 -
595 - // (deprecated: use select_node instead) Select single node by evaluating XPath query.
596 - xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const;
597 - xpath_node select_single_node(const xpath_query& query) const;
598 -
599 - #endif
600 -
601 - // Print subtree using a writer object
602 - void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const;
603 -
604 - #ifndef PUGIXML_NO_STL
605 - // Print subtree to stream
606 - void print(std::basic_ostream<char, std::char_traits<char> >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const;
607 - void print(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& os, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, unsigned int depth = 0) const;
608 - #endif
609 -
610 - // Child nodes iterators
611 - typedef xml_node_iterator iterator;
612 -
613 - iterator begin() const;
614 - iterator end() const;
615 -
616 - // Attribute iterators
617 - typedef xml_attribute_iterator attribute_iterator;
618 -
619 - attribute_iterator attributes_begin() const;
620 - attribute_iterator attributes_end() const;
621 -
622 - // Range-based for support
623 - xml_object_range<xml_node_iterator> children() const;
624 - xml_object_range<xml_named_node_iterator> children(const char_t* name) const;
625 - xml_object_range<xml_attribute_iterator> attributes() const;
626 -
627 - // Get node offset in parsed file/string (in char_t units) for debugging purposes
628 - ptrdiff_t offset_debug() const;
629 -
630 - // Get hash value (unique for handles to the same object)
631 - size_t hash_value() const;
632 -
633 - // Get internal pointer
634 - xml_node_struct* internal_object() const;
635 - };
636 -
637 -#ifdef __BORLANDC__
638 - // Borland C++ workaround
639 - bool PUGIXML_FUNCTION operator&&(const xml_node& lhs, bool rhs);
640 - bool PUGIXML_FUNCTION operator||(const xml_node& lhs, bool rhs);
641 -#endif
642 -
643 - // A helper for working with text inside PCDATA nodes
644 - class PUGIXML_CLASS xml_text
645 - {
646 - friend class xml_node;
647 -
648 - xml_node_struct* _root;
649 -
650 - typedef void (*unspecified_bool_type)(xml_text***);
651 -
652 - explicit xml_text(xml_node_struct* root);
653 -
654 - xml_node_struct* _data_new();
655 - xml_node_struct* _data() const;
656 -
657 - public:
658 - // Default constructor. Constructs an empty object.
659 - xml_text();
660 -
661 - // Safe bool conversion operator
662 - operator unspecified_bool_type() const;
663 -
664 - // Borland C++ workaround
665 - bool operator!() const;
666 -
667 - // Check if text object is empty
668 - bool empty() const;
669 -
670 - // Get text, or "" if object is empty
671 - const char_t* get() const;
672 -
673 - // Get text, or the default value if object is empty
674 - const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const;
675 -
676 - // Get text as a number, or the default value if conversion did not succeed or object is empty
677 - int as_int(int def = 0) const;
678 - unsigned int as_uint(unsigned int def = 0) const;
679 - double as_double(double def = 0) const;
680 - float as_float(float def = 0) const;
681 -
682 - #ifdef PUGIXML_HAS_LONG_LONG
683 - long long as_llong(long long def = 0) const;
684 - unsigned long long as_ullong(unsigned long long def = 0) const;
685 - #endif
686 -
687 - // Get text as bool (returns true if first character is in '1tTyY' set), or the default value if object is empty
688 - bool as_bool(bool def = false) const;
689 -
690 - // Set text (returns false if object is empty or there is not enough memory)
691 - bool set(const char_t* rhs);
692 -
693 - // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
694 - bool set(int rhs);
695 - bool set(unsigned int rhs);
696 - bool set(double rhs);
697 - bool set(bool rhs);
698 -
699 - #ifdef PUGIXML_HAS_LONG_LONG
700 - bool set(long long rhs);
701 - bool set(unsigned long long rhs);
702 - #endif
703 -
704 - // Set text (equivalent to set without error checking)
705 - xml_text& operator=(const char_t* rhs);
706 - xml_text& operator=(int rhs);
707 - xml_text& operator=(unsigned int rhs);
708 - xml_text& operator=(double rhs);
709 - xml_text& operator=(bool rhs);
710 -
711 - #ifdef PUGIXML_HAS_LONG_LONG
712 - xml_text& operator=(long long rhs);
713 - xml_text& operator=(unsigned long long rhs);
714 - #endif
715 -
716 - // Get the data node (node_pcdata or node_cdata) for this object
717 - xml_node data() const;
718 - };
719 -
720 -#ifdef __BORLANDC__
721 - // Borland C++ workaround
722 - bool PUGIXML_FUNCTION operator&&(const xml_text& lhs, bool rhs);
723 - bool PUGIXML_FUNCTION operator||(const xml_text& lhs, bool rhs);
724 -#endif
725 -
726 - // Child node iterator (a bidirectional iterator over a collection of xml_node)
727 - class PUGIXML_CLASS xml_node_iterator
728 - {
729 - friend class xml_node;
730 -
731 - private:
732 - mutable xml_node _wrap;
733 - xml_node _parent;
734 -
735 - xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent);
736 -
737 - public:
738 - // Iterator traits
739 - typedef ptrdiff_t difference_type;
740 - typedef xml_node value_type;
741 - typedef xml_node* pointer;
742 - typedef xml_node& reference;
743 -
744 - #ifndef PUGIXML_NO_STL
745 - typedef std::bidirectional_iterator_tag iterator_category;
746 - #endif
747 -
748 - // Default constructor
749 - xml_node_iterator();
750 -
751 - // Construct an iterator which points to the specified node
752 - xml_node_iterator(const xml_node& node);
753 -
754 - // Iterator operators
755 - bool operator==(const xml_node_iterator& rhs) const;
756 - bool operator!=(const xml_node_iterator& rhs) const;
757 -
758 - xml_node& operator*() const;
759 - xml_node* operator->() const;
760 -
761 - const xml_node_iterator& operator++();
762 - xml_node_iterator operator++(int);
763 -
764 - const xml_node_iterator& operator--();
765 - xml_node_iterator operator--(int);
766 - };
767 -
768 - // Attribute iterator (a bidirectional iterator over a collection of xml_attribute)
769 - class PUGIXML_CLASS xml_attribute_iterator
770 - {
771 - friend class xml_node;
772 -
773 - private:
774 - mutable xml_attribute _wrap;
775 - xml_node _parent;
776 -
777 - xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent);
778 -
779 - public:
780 - // Iterator traits
781 - typedef ptrdiff_t difference_type;
782 - typedef xml_attribute value_type;
783 - typedef xml_attribute* pointer;
784 - typedef xml_attribute& reference;
785 -
786 - #ifndef PUGIXML_NO_STL
787 - typedef std::bidirectional_iterator_tag iterator_category;
788 - #endif
789 -
790 - // Default constructor
791 - xml_attribute_iterator();
792 -
793 - // Construct an iterator which points to the specified attribute
794 - xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent);
795 -
796 - // Iterator operators
797 - bool operator==(const xml_attribute_iterator& rhs) const;
798 - bool operator!=(const xml_attribute_iterator& rhs) const;
799 -
800 - xml_attribute& operator*() const;
801 - xml_attribute* operator->() const;
802 -
803 - const xml_attribute_iterator& operator++();
804 - xml_attribute_iterator operator++(int);
805 -
806 - const xml_attribute_iterator& operator--();
807 - xml_attribute_iterator operator--(int);
808 - };
809 -
810 - // Named node range helper
811 - class PUGIXML_CLASS xml_named_node_iterator
812 - {
813 - friend class xml_node;
814 -
815 - public:
816 - // Iterator traits
817 - typedef ptrdiff_t difference_type;
818 - typedef xml_node value_type;
819 - typedef xml_node* pointer;
820 - typedef xml_node& reference;
821 -
822 - #ifndef PUGIXML_NO_STL
823 - typedef std::bidirectional_iterator_tag iterator_category;
824 - #endif
825 -
826 - // Default constructor
827 - xml_named_node_iterator();
828 -
829 - // Construct an iterator which points to the specified node
830 - xml_named_node_iterator(const xml_node& node, const char_t* name);
831 -
832 - // Iterator operators
833 - bool operator==(const xml_named_node_iterator& rhs) const;
834 - bool operator!=(const xml_named_node_iterator& rhs) const;
835 -
836 - xml_node& operator*() const;
837 - xml_node* operator->() const;
838 -
839 - const xml_named_node_iterator& operator++();
840 - xml_named_node_iterator operator++(int);
841 -
842 - const xml_named_node_iterator& operator--();
843 - xml_named_node_iterator operator--(int);
844 -
845 - private:
846 - mutable xml_node _wrap;
847 - xml_node _parent;
848 - const char_t* _name;
849 -
850 - xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name);
851 - };
852 -
853 - // Abstract tree walker class (see xml_node::traverse)
854 - class PUGIXML_CLASS xml_tree_walker
855 - {
856 - friend class xml_node;
857 -
858 - private:
859 - int _depth;
860 -
861 - protected:
862 - // Get current traversal depth
863 - int depth() const;
864 -
865 - public:
866 - xml_tree_walker();
867 - virtual ~xml_tree_walker();
868 -
869 - // Callback that is called when traversal begins
870 - virtual bool begin(xml_node& node);
871 -
872 - // Callback that is called for each node traversed
873 - virtual bool for_each(xml_node& node) = 0;
874 -
875 - // Callback that is called when traversal ends
876 - virtual bool end(xml_node& node);
877 - };
878 -
879 - // Parsing status, returned as part of xml_parse_result object
880 - enum xml_parse_status
881 - {
882 - status_ok = 0, // No error
883 -
884 - status_file_not_found, // File was not found during load_file()
885 - status_io_error, // Error reading from file/stream
886 - status_out_of_memory, // Could not allocate memory
887 - status_internal_error, // Internal error occurred
888 -
889 - status_unrecognized_tag, // Parser could not determine tag type
890 -
891 - status_bad_pi, // Parsing error occurred while parsing document declaration/processing instruction
892 - status_bad_comment, // Parsing error occurred while parsing comment
893 - status_bad_cdata, // Parsing error occurred while parsing CDATA section
894 - status_bad_doctype, // Parsing error occurred while parsing document type declaration
895 - status_bad_pcdata, // Parsing error occurred while parsing PCDATA section
896 - status_bad_start_element, // Parsing error occurred while parsing start element tag
897 - status_bad_attribute, // Parsing error occurred while parsing element attribute
898 - status_bad_end_element, // Parsing error occurred while parsing end element tag
899 - status_end_element_mismatch,// There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag)
900 -
901 - status_append_invalid_root, // Unable to append nodes since root type is not node_element or node_document (exclusive to xml_node::append_buffer)
902 -
903 - status_no_document_element // Parsing resulted in a document without element nodes
904 - };
905 -
906 - // Parsing result
907 - struct PUGIXML_CLASS xml_parse_result
908 - {
909 - // Parsing status (see xml_parse_status)
910 - xml_parse_status status;
911 -
912 - // Last parsed offset (in char_t units from start of input data)
913 - ptrdiff_t offset;
914 -
915 - // Source document encoding
916 - xml_encoding encoding;
917 -
918 - // Default constructor, initializes object to failed state
919 - xml_parse_result();
920 -
921 - // Cast to bool operator
922 - operator bool() const;
923 -
924 - // Get error description
925 - const char* description() const;
926 - };
927 -
928 - // Document class (DOM tree root)
929 - class PUGIXML_CLASS xml_document: public xml_node
930 - {
931 - private:
932 - char_t* _buffer;
933 -
934 - char _memory[192];
935 -
936 - // Non-copyable semantics
937 - xml_document(const xml_document&);
938 - const xml_document& operator=(const xml_document&);
939 -
940 - void create();
941 - void destroy();
942 -
943 - public:
944 - // Default constructor, makes empty document
945 - xml_document();
946 -
947 - // Destructor, invalidates all node/attribute handles to this document
948 - ~xml_document();
949 -
950 - // Removes all nodes, leaving the empty document
951 - void reset();
952 -
953 - // Removes all nodes, then copies the entire contents of the specified document
954 - void reset(const xml_document& proto);
955 -
956 - #ifndef PUGIXML_NO_STL
957 - // Load document from stream.
958 - xml_parse_result load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
959 - xml_parse_result load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options = parse_default);
960 - #endif
961 -
962 - // (deprecated: use load_string instead) Load document from zero-terminated string. No encoding conversions are applied.
963 - xml_parse_result load(const char_t* contents, unsigned int options = parse_default);
964 -
965 - // Load document from zero-terminated string. No encoding conversions are applied.
966 - xml_parse_result load_string(const char_t* contents, unsigned int options = parse_default);
967 -
968 - // Load document from file
969 - xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
970 - xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
971 -
972 - // Load document from buffer. Copies/converts the buffer, so it may be deleted or changed after the function returns.
973 - xml_parse_result load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
974 -
975 - // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data).
976 - // You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed.
977 - xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
978 -
979 - // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data).
980 - // You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore).
981 - xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
982 -
983 - // Save XML document to writer (semantics is slightly different from xml_node::print, see documentation for details).
984 - void save(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
985 -
986 - #ifndef PUGIXML_NO_STL
987 - // Save XML document to stream (semantics is slightly different from xml_node::print, see documentation for details).
988 - void save(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
989 - void save(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default) const;
990 - #endif
991 -
992 - // Save XML to file
993 - bool save_file(const char* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
994 - bool save_file(const wchar_t* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
995 -
996 - // Get document element
997 - xml_node document_element() const;
998 - };
999 -
1000 -#ifndef PUGIXML_NO_XPATH
1001 - // XPath query return type
1002 - enum xpath_value_type
1003 - {
1004 - xpath_type_none, // Unknown type (query failed to compile)
1005 - xpath_type_node_set, // Node set (xpath_node_set)
1006 - xpath_type_number, // Number
1007 - xpath_type_string, // String
1008 - xpath_type_boolean // Boolean
1009 - };
1010 -
1011 - // XPath parsing result
1012 - struct PUGIXML_CLASS xpath_parse_result
1013 - {
1014 - // Error message (0 if no error)
1015 - const char* error;
1016 -
1017 - // Last parsed offset (in char_t units from string start)
1018 - ptrdiff_t offset;
1019 -
1020 - // Default constructor, initializes object to failed state
1021 - xpath_parse_result();
1022 -
1023 - // Cast to bool operator
1024 - operator bool() const;
1025 -
1026 - // Get error description
1027 - const char* description() const;
1028 - };
1029 -
1030 - // A single XPath variable
1031 - class PUGIXML_CLASS xpath_variable
1032 - {
1033 - friend class xpath_variable_set;
1034 -
1035 - protected:
1036 - xpath_value_type _type;
1037 - xpath_variable* _next;
1038 -
1039 - xpath_variable();
1040 -
1041 - // Non-copyable semantics
1042 - xpath_variable(const xpath_variable&);
1043 - xpath_variable& operator=(const xpath_variable&);
1044 -
1045 - public:
1046 - // Get variable name
1047 - const char_t* name() const;
1048 -
1049 - // Get variable type
1050 - xpath_value_type type() const;
1051 -
1052 - // Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error
1053 - bool get_boolean() const;
1054 - double get_number() const;
1055 - const char_t* get_string() const;
1056 - const xpath_node_set& get_node_set() const;
1057 -
1058 - // Set variable value; no type conversion is performed, false is returned on type mismatch error
1059 - bool set(bool value);
1060 - bool set(double value);
1061 - bool set(const char_t* value);
1062 - bool set(const xpath_node_set& value);
1063 - };
1064 -
1065 - // A set of XPath variables
1066 - class PUGIXML_CLASS xpath_variable_set
1067 - {
1068 - private:
1069 - xpath_variable* _data[64];
1070 -
1071 - // Non-copyable semantics
1072 - xpath_variable_set(const xpath_variable_set&);
1073 - xpath_variable_set& operator=(const xpath_variable_set&);
1074 -
1075 - xpath_variable* find(const char_t* name) const;
1076 -
1077 - public:
1078 - // Default constructor/destructor
1079 - xpath_variable_set();
1080 - ~xpath_variable_set();
1081 -
1082 - // Add a new variable or get the existing one, if the types match
1083 - xpath_variable* add(const char_t* name, xpath_value_type type);
1084 -
1085 - // Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch
1086 - bool set(const char_t* name, bool value);
1087 - bool set(const char_t* name, double value);
1088 - bool set(const char_t* name, const char_t* value);
1089 - bool set(const char_t* name, const xpath_node_set& value);
1090 -
1091 - // Get existing variable by name
1092 - xpath_variable* get(const char_t* name);
1093 - const xpath_variable* get(const char_t* name) const;
1094 - };
1095 -
1096 - // A compiled XPath query object
1097 - class PUGIXML_CLASS xpath_query
1098 - {
1099 - private:
1100 - void* _impl;
1101 - xpath_parse_result _result;
1102 -
1103 - typedef void (*unspecified_bool_type)(xpath_query***);
1104 -
1105 - // Non-copyable semantics
1106 - xpath_query(const xpath_query&);
1107 - xpath_query& operator=(const xpath_query&);
1108 -
1109 - public:
1110 - // Construct a compiled object from XPath expression.
1111 - // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors.
1112 - explicit xpath_query(const char_t* query, xpath_variable_set* variables = 0);
1113 -
1114 - // Destructor
1115 - ~xpath_query();
1116 -
1117 - // Get query expression return type
1118 - xpath_value_type return_type() const;
1119 -
1120 - // Evaluate expression as boolean value in the specified context; performs type conversion if necessary.
1121 - // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
1122 - bool evaluate_boolean(const xpath_node& n) const;
1123 -
1124 - // Evaluate expression as double value in the specified context; performs type conversion if necessary.
1125 - // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
1126 - double evaluate_number(const xpath_node& n) const;
1127 -
1128 - #ifndef PUGIXML_NO_STL
1129 - // Evaluate expression as string value in the specified context; performs type conversion if necessary.
1130 - // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
1131 - string_t evaluate_string(const xpath_node& n) const;
1132 - #endif
1133 -
1134 - // Evaluate expression as string value in the specified context; performs type conversion if necessary.
1135 - // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero).
1136 - // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
1137 - // If PUGIXML_NO_EXCEPTIONS is defined, returns empty set instead.
1138 - size_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const;
1139 -
1140 - // Evaluate expression as node set in the specified context.
1141 - // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors.
1142 - // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead.
1143 - xpath_node_set evaluate_node_set(const xpath_node& n) const;
1144 -
1145 - // Evaluate expression as node set in the specified context.
1146 - // Return first node in document order, or empty node if node set is empty.
1147 - // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors.
1148 - // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node instead.
1149 - xpath_node evaluate_node(const xpath_node& n) const;
1150 -
1151 - // Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode)
1152 - const xpath_parse_result& result() const;
1153 -
1154 - // Safe bool conversion operator
1155 - operator unspecified_bool_type() const;
1156 -
1157 - // Borland C++ workaround
1158 - bool operator!() const;
1159 - };
1160 -
1161 - #ifndef PUGIXML_NO_EXCEPTIONS
1162 - // XPath exception class
1163 - class PUGIXML_CLASS xpath_exception: public std::exception
1164 - {
1165 - private:
1166 - xpath_parse_result _result;
1167 -
1168 - public:
1169 - // Construct exception from parse result
1170 - explicit xpath_exception(const xpath_parse_result& result);
1171 -
1172 - // Get error message
1173 - virtual const char* what() const throw();
1174 -
1175 - // Get parse result
1176 - const xpath_parse_result& result() const;
1177 - };
1178 - #endif
1179 -
1180 - // XPath node class (either xml_node or xml_attribute)
1181 - class PUGIXML_CLASS xpath_node
1182 - {
1183 - private:
1184 - xml_node _node;
1185 - xml_attribute _attribute;
1186 -
1187 - typedef void (*unspecified_bool_type)(xpath_node***);
1188 -
1189 - public:
1190 - // Default constructor; constructs empty XPath node
1191 - xpath_node();
1192 -
1193 - // Construct XPath node from XML node/attribute
1194 - xpath_node(const xml_node& node);
1195 - xpath_node(const xml_attribute& attribute, const xml_node& parent);
1196 -
1197 - // Get node/attribute, if any
1198 - xml_node node() const;
1199 - xml_attribute attribute() const;
1200 -
1201 - // Get parent of contained node/attribute
1202 - xml_node parent() const;
1203 -
1204 - // Safe bool conversion operator
1205 - operator unspecified_bool_type() const;
1206 -
1207 - // Borland C++ workaround
1208 - bool operator!() const;
1209 -
1210 - // Comparison operators
1211 - bool operator==(const xpath_node& n) const;
1212 - bool operator!=(const xpath_node& n) const;
1213 - };
1214 -
1215 -#ifdef __BORLANDC__
1216 - // Borland C++ workaround
1217 - bool PUGIXML_FUNCTION operator&&(const xpath_node& lhs, bool rhs);
1218 - bool PUGIXML_FUNCTION operator||(const xpath_node& lhs, bool rhs);
1219 -#endif
1220 -
1221 - // A fixed-size collection of XPath nodes
1222 - class PUGIXML_CLASS xpath_node_set
1223 - {
1224 - public:
1225 - // Collection type
1226 - enum type_t
1227 - {
1228 - type_unsorted, // Not ordered
1229 - type_sorted, // Sorted by document order (ascending)
1230 - type_sorted_reverse // Sorted by document order (descending)
1231 - };
1232 -
1233 - // Constant iterator type
1234 - typedef const xpath_node* const_iterator;
1235 -
1236 - // We define non-constant iterator to be the same as constant iterator so that various generic algorithms (i.e. boost foreach) work
1237 - typedef const xpath_node* iterator;
1238 -
1239 - // Default constructor. Constructs empty set.
1240 - xpath_node_set();
1241 -
1242 - // Constructs a set from iterator range; data is not checked for duplicates and is not sorted according to provided type, so be careful
1243 - xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted);
1244 -
1245 - // Destructor
1246 - ~xpath_node_set();
1247 -
1248 - // Copy constructor/assignment operator
1249 - xpath_node_set(const xpath_node_set& ns);
1250 - xpath_node_set& operator=(const xpath_node_set& ns);
1251 -
1252 - // Get collection type
1253 - type_t type() const;
1254 -
1255 - // Get collection size
1256 - size_t size() const;
1257 -
1258 - // Indexing operator
1259 - const xpath_node& operator[](size_t index) const;
1260 -
1261 - // Collection iterators
1262 - const_iterator begin() const;
1263 - const_iterator end() const;
1264 -
1265 - // Sort the collection in ascending/descending order by document order
1266 - void sort(bool reverse = false);
1267 -
1268 - // Get first node in the collection by document order
1269 - xpath_node first() const;
1270 -
1271 - // Check if collection is empty
1272 - bool empty() const;
1273 -
1274 - private:
1275 - type_t _type;
1276 -
1277 - xpath_node _storage;
1278 -
1279 - xpath_node* _begin;
1280 - xpath_node* _end;
1281 -
1282 - void _assign(const_iterator begin, const_iterator end);
1283 - };
1284 -#endif
1285 -
1286 -#ifndef PUGIXML_NO_STL
1287 - // Convert wide string to UTF8
1288 - std::basic_string<char, std::char_traits<char>, std::allocator<char> > PUGIXML_FUNCTION as_utf8(const wchar_t* str);
1289 - std::basic_string<char, std::char_traits<char>, std::allocator<char> > PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >& str);
1290 -
1291 - // Convert UTF8 to wide string
1292 - std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > PUGIXML_FUNCTION as_wide(const char* str);
1293 - std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > PUGIXML_FUNCTION as_wide(const std::basic_string<char, std::char_traits<char>, std::allocator<char> >& str);
1294 -#endif
1295 -
1296 - // Memory allocation function interface; returns pointer to allocated memory or NULL on failure
1297 - typedef void* (*allocation_function)(size_t size);
1298 -
1299 - // Memory deallocation function interface
1300 - typedef void (*deallocation_function)(void* ptr);
1301 -
1302 - // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions.
1303 - void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate);
1304 -
1305 - // Get current memory management functions
1306 - allocation_function PUGIXML_FUNCTION get_memory_allocation_function();
1307 - deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function();
1308 -}
1309 -
1310 -#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))
1311 -namespace std
1312 -{
1313 - // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier)
1314 - std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_node_iterator&);
1315 - std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_attribute_iterator&);
1316 - std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_named_node_iterator&);
1317 -}
1318 -#endif
1319 -
1320 -#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC)
1321 -namespace std
1322 -{
1323 - // Workarounds for (non-standard) iterator category detection
1324 - std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_node_iterator&);
1325 - std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_attribute_iterator&);
1326 - std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_named_node_iterator&);
1327 -}
1328 -#endif
1329 -
1330 -#endif
1331 -
1332 -/**
1333 - * Copyright (c) 2006-2014 Arseny Kapoulkine
1334 - *
1335 - * Permission is hereby granted, free of charge, to any person
1336 - * obtaining a copy of this software and associated documentation
1337 - * files (the "Software"), to deal in the Software without
1338 - * restriction, including without limitation the rights to use,
1339 - * copy, modify, merge, publish, distribute, sublicense, and/or sell
1340 - * copies of the Software, and to permit persons to whom the
1341 - * Software is furnished to do so, subject to the following
1342 - * conditions:
1343 - *
1344 - * The above copyright notice and this permission notice shall be
1345 - * included in all copies or substantial portions of the Software.
1346 - *
1347 - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1348 - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
1349 - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1350 - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
1351 - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
1352 - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1353 - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
1354 - * OTHER DEALINGS IN THE SOFTWARE.
1355 - */
1 -# ith/common/common.pri
2 -# 8/9/2011 jichi
3 -# Overwrite ITH headers
4 -
5 -#DEFINES += ITH_HAS_CRT # whether ITH is linked with msvcrt
6 -#DEFINES += ITH_HAS_CXX # whether ITH has access to native C++ syntax
7 -
8 -DEPENDPATH += $$PWD
9 -
10 -HEADERS += \
11 - $$PWD/const.h \
12 - $$PWD/defs.h \
13 - $$PWD/except.h \
14 - $$PWD/growl.h \
15 - $$PWD/memory.h \
16 - $$PWD/string.h \
17 - $$PWD/types.h
18 -
19 -DEFINES += _CRT_NON_CONFORMING_SWPRINTFS
20 -
21 -# jichi 9/14/2013: Whether using SEH exception handle.
22 -# msvcrt on Windows XP is missin EH
23 -#DEFINES += ITH_HAS_SEH
24 -
25 -# jichi 9/22/2013: Whether let ITH manage heap
26 -#DEFINES += ITH_HAS_HEAP
27 -
28 -# EOF
1 -#pragma once
2 -
3 -// ith/common/const.h
4 -// 8/23/2013 jichi
5 -// Branch: ITH/common.h, rev 128
6 -
7 -// jichi 9/9/2013: Another importnat function is lstrcatA, which is already handled by
8 -// Debonosu hooks. Wait until it is really needed by certain games.
9 -// The order of the functions is used in several place.
10 -// I need to recompile all of the dlls to modify the order.
11 -enum HookFunType {
12 - HF_Null = -1
13 - , HF_GetTextExtentPoint32A
14 - , HF_GetGlyphOutlineA
15 - , HF_ExtTextOutA
16 - , HF_TextOutA
17 - , HF_GetCharABCWidthsA
18 - , HF_DrawTextA
19 - , HF_DrawTextExA
20 - //, HF_lstrlenA
21 - , HF_GetTextExtentPoint32W
22 - , HF_GetGlyphOutlineW
23 - , HF_ExtTextOutW
24 - , HF_TextOutW
25 - , HF_GetCharABCWidthsW
26 - , HF_DrawTextW
27 - , HF_DrawTextExW
28 - //, HF_lstrlenW
29 - , HookFunCount // 14
30 -};
31 -
32 -// jichi 10/14/2014
33 -#define HOOK_GDI_FUNCTION_LIST \
34 - GetTextExtentPoint32A \
35 - , GetGlyphOutlineA \
36 - , ExtTextOutA \
37 - , TextOutA \
38 - , GetCharABCWidthsA \
39 - , GetTextExtentPoint32W \
40 - , GetGlyphOutlineW \
41 - , ExtTextOutW \
42 - , TextOutW \
43 - , GetCharABCWidthsW \
44 - , DrawTextA \
45 - , DrawTextExA \
46 - , DrawTextW \
47 - , DrawTextExW
48 -
49 -enum { HOOK_FUN_COUNT = HookFunCount };
50 -// jichi 1/16/2015: Though called max hook, it means max number of text threads
51 -enum { MAX_HOOK = 32 }; // must be larger than HookFunCount
52 -//enum { HOOK_SECTION_SIZE = 0x2000 }; // default ITH value
53 -// jichi 1/16/2015: Change to a very large number to prevent crash
54 -//enum { MAX_HOOK = 0x100 }; // must be larger than HookFunCount
55 -enum { HOOK_SECTION_SIZE = MAX_HOOK * 0x100 }; // default ITH value is 0x2000 for 32 hook (0x100 per hook)
56 -
57 -// jichi 375/2014: Add offset of pusha/pushad
58 -// http://faydoc.tripod.com/cpu/pushad.htm
59 -// http://agth.wikia.com/wiki/Cheat_Engine_AGTH_Tutorial
60 -//
61 -// Warning: The offset in ITH has -4 offset comparing to pusha and AGTH
62 -enum pusha_off {
63 - pusha_eax_off = -0x4
64 - , pusha_ecx_off = -0x8
65 - , pusha_edx_off = -0xc
66 - , pusha_ebx_off = -0x10
67 - , pusha_esp_off = -0x14
68 - , pusha_ebp_off = -0x18
69 - , pusha_esi_off = -0x1c
70 - , pusha_edi_off = -0x20
71 - , pusha_off = -0x24 // pushad offset
72 -};
73 -
74 -enum IhfCommandType {
75 - IHF_COMMAND = -1 // null type
76 - , IHF_COMMAND_NEW_HOOK = 0
77 - , IHF_COMMAND_REMOVE_HOOK = 1
78 - , IHF_COMMAND_MODIFY_HOOK = 2
79 - , IHF_COMMAND_DETACH = 3
80 -};
81 -
82 -enum IhfNotificationType {
83 - IHF_NOTIFICATION = -1 // null type
84 - , IHF_NOTIFICATION_TEXT = 0
85 - , IHF_NOTIFICATION_NEWHOOK = 1
86 -};
87 -
88 -// jichi 9/8/2013: The meaning are guessed
89 -// Values must be within DWORD
90 -// Unused values are as follows:
91 -// - 0x100
92 -enum HookParamType : unsigned long {
93 - USING_STRING = 0x1 // type(data) is char* or wchar_t* and has length
94 - , USING_UTF8 = USING_STRING // jichi 10/21/2014: temporarily handled the same way as USING_STRING
95 - , USING_UNICODE = 0x2 // type(data) is wchar_t or wchar_t*
96 - , BIG_ENDIAN = 0x4 // type(data) is char
97 - , DATA_INDIRECT = 0x8
98 - , USING_SPLIT = 0x10 // aware of split time?
99 - , SPLIT_INDIRECT = 0x20
100 - , MODULE_OFFSET = 0x40 // do hash module, and the address is relative to module
101 - , FUNCTION_OFFSET = 0x80 // do hash function, and the address is relative to funccion
102 - , PRINT_DWORD = 0x100 // jichi 12/7/2014: Removed
103 - , STRING_LAST_CHAR = 0x200
104 - , NO_CONTEXT = 0x400
105 - //, EXTERN_HOOK = 0x800 // jichi 10/24/2014: Removed
106 - //, HOOK_AUXILIARY = 0x2000 // jichi 12/13/2013: None of known hooks are auxiliary
107 - , HOOK_ENGINE = 0x4000
108 - , HOOK_ADDITIONAL = 0x8000
109 -
110 - // jichi 10/24/2014: Only trigger the dynamic function, do not return any data
111 - , HOOK_EMPTY = 0x800
112 - // jichi 6/1/2014: fix the split value to 0x10001
113 - , FIXING_SPLIT = 0x1000
114 - , RELATIVE_SPLIT = 0x2000 // relative split return address
115 -};
116 -
117 -// 6/1/2014: Fixed split value for hok parameter
118 -// Fuse all threads, and prevent floating
119 -enum { FIXED_SPLIT_VALUE = 0x10001 };
120 -
121 -// jichi 12/18/2013:
122 -// These dlls are used to guess the range for non-NO_CONTEXT hooks.
123 -//
124 -// Disabling uxtheme.dll would crash certain system: http://tieba.baidu.com/p/2764436254
125 -#define IHF_FILTER_DLL_LIST \
126 - /* ITH original filters */ \
127 - L"gdiplus.dll" /* Graphics functions like TextOutA */ \
128 - , L"lpk.dll" /* Language package scripts and fonts */ \
129 - , L"msctf.dll" /* Text service */ \
130 - , L"psapi.dll" /* Processes */ \
131 - , L"usp10.dll" /* UNICODE rendering */ \
132 - , L"user32.dll" /* Non-graphics functions like lstrlenA */ \
133 - , L"uxtheme.dll" /* Theme */ \
134 - \
135 - /* Windows DLLs */ \
136 - , L"advapi32.dll" /* Advanced services */ \
137 - , L"apphelp.dll" /* Appliation help */ \
138 - , L"audioses.dll" /* Audios */ \
139 - , L"avrt.dll" /* Audio video runtime */ \
140 - , L"cfgmgr32.dll" /* Configuration manager */ \
141 - , L"clbcatq.dll" /* COM query service */ \
142 - , L"comctl32.dll" /* Common control library */ \
143 - , L"comdlg32.dll" /* Common dialogs */ \
144 - , L"crypt32.dll" /* Security cryption */ \
145 - , L"cryptbase.dll"/* Security cryption */ \
146 - , L"cryptsp.dll" /* Security cryption */ \
147 - , L"d3d8thk.dll" /* Direct3D 8 */ \
148 - , L"d3d9.dll" /* Direct3D 9 */ \
149 - , L"dbghelp.dll" /* Debug help */ \
150 - , L"dciman32.dll" /* Display cotrol */ \
151 - , L"devobj.dll" /* Device object */ \
152 - , L"ddraw.dll" /* Direct draw */ \
153 - , L"dinput.dll" /* Diret input */ \
154 - , L"dsound.dll" /* Direct sound */ \
155 - , L"DShowRdpFilter.dll" /* Direct show */ \
156 - , L"dwmapi.dll" /* Windows manager */ \
157 - , L"gdi32.dll" /* GDI32 */ \
158 - , L"hid.dll" /* HID user library */ \
159 - , L"iertutil.dll" /* IE runtime */ \
160 - , L"imagehlp.dll" /* Image help */ \
161 - , L"imm32.dll" /* Input method */ \
162 - , L"ksuser.dll" /* Kernel service */ \
163 - , L"ole32.dll" /* COM OLE */ \
164 - , L"oleacc.dll" /* OLE access */ \
165 - , L"oleaut32.dll" /* COM OLE */ \
166 - , L"kernel.dll" /* Kernel functions */ \
167 - , L"kernelbase.dll" /* Kernel functions */ \
168 - , L"midimap.dll" /* MIDI */ \
169 - , L"mmdevapi.dll" /* Audio device */ \
170 - , L"mpr.dll" /* Winnet */ \
171 - , L"msacm32.dll" /* MS ACM */ \
172 - , L"msacm32.drv" /* MS ACM */ \
173 - , L"msasn1.dll" /* Encoding/decoding */ \
174 - , L"msimg32.dll" /* Image */ \
175 - , L"msvfw32.dll" /* Media play */ \
176 - , L"netapi32.dll" /* Network service */ \
177 - , L"normaliz.dll" /* Normalize */ \
178 - , L"nsi.dll" /* NSI */ \
179 - , L"ntdll.dll" /* NT functions */ \
180 - , L"ntmarta.dll" /* NT MARTA */ \
181 - , L"nvd3dum.dll" /* Direct 3D */ \
182 - , L"powerprof.dll"/* Power profile */ \
183 - , L"profapi.dll" /* Profile API */ \
184 - , L"propsys.dll" /* System properties */ \
185 - , L"quartz.dll" /* OpenGL */ \
186 - , L"rpcrt4.dll" /* RPC runtime */ \
187 - , L"rpcrtremote.dll" /* RPC runtime */ \
188 - , L"rsabase.dll" /* RSA cryption */ \
189 - , L"rsaenh.dll" /* RSA cryption */ \
190 - , L"schannel.dll" /* Security channel */ \
191 - , L"sechost.dll" /* Service host */ \
192 - , L"setupapi.dll" /* Setup service */ \
193 - , L"shell32.dll" /* Windows shell */ \
194 - , L"shlwapi.dll" /* Light-weighted shell */ \
195 - , L"slc.dll" /* SLC */ \
196 - , L"srvcli.dll" /* Service client */ \
197 - , L"version.dll" /* Windows version */ \
198 - , L"wdmaud.drv" /* Wave output */ \
199 - , L"wldap32.dll" /* Wireless */ \
200 - , L"wininet.dll" /* Internet access */ \
201 - , L"winmm.dll" /* Windows sound */ \
202 - , L"winsta.dll" /* Connection system */ \
203 - , L"wtsapi32.dll" /* Windows terminal server */ \
204 - , L"wintrust.dll" /* Windows trust */ \
205 - , L"wsock32.dll" /* Windows sock */ \
206 - , L"ws2_32.dll" /* Terminal server */ \
207 - , L"wkscli.dll" /* ACIS */ \
208 - \
209 - /* MSVCRT */ \
210 - , L"msvcrt.dll" /* VC rutime */ \
211 - , L"msvcr80.dll" /* VC rutime 8 */ \
212 - , L"msvcp80.dll" /* VC rutime 8 */ \
213 - , L"msvcr90.dll" /* VC rutime 9 */ \
214 - , L"msvcp90.dll" /* VC rutime 9 */ \
215 - , L"msvcr100.dll" /* VC rutime 10 */ \
216 - , L"msvcp100.dll" /* VC rutime 10 */ \
217 - , L"msvcr110.dll" /* VC rutime 11 */ \
218 - , L"msvcp110.dll" /* VC rutime 11 */ \
219 - \
220 - /* VNR */ \
221 - , L"vnrhook.dll" \
222 - , L"vnrhookxp.dll" \
223 - \
224 - /* Sogou IME */ \
225 - , L"sogoupy.ime" \
226 - , L"PicFace.dll" \
227 - , L"AddressSearch.dll" \
228 - \
229 - /* QQ IME */ \
230 - , L"QQPINYIN.IME" \
231 - \
232 - /* AlphaROM */ \
233 - , L"kDays.dll" \
234 - \
235 - /* 360Safe */ \
236 - , L"safemon.dll" \
237 - \
238 - /* Locale changers */ \
239 - , L"AlLayer.dll" /* AppLocale */ \
240 - , L"LocaleEmulator.dll" /* Locale Emulator */ \
241 - , L"LSH.dll" /* LocaleSwitch */ \
242 - , L"ntleah.dll" /* NTLEA */
243 -
244 - // Google Japanese IME
245 - //, L"GoogleIMEJaTIP32.dll"
246 -
247 -enum {
248 - //IHF_FILTER_COUNT = 7
249 - IHF_FILTER_COUNT = 7 + 72 + 9 + 4 + 3 + 1 + 1 + 1 + 4 // count of total dlls to filter
250 - , IHF_FILTER_CAPACITY = IHF_FILTER_COUNT + 1 // one more than the dll count
251 -};
252 -
253 -// EOF
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
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
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
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
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
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
1 -#pragma once
2 -
3 -// dllconfig.h
4 -// 8/23/2013 jichi
5 -
6 -#include "ith/common/memory.h"
7 -#include "ith/common/string.h"
8 -#include "ntdll/ntdll.h"
9 -
10 -// EOF
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
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 -)
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
1 -#pragma once
2 -
3 -// config.h
4 -// 8/23/2013 jichi
5 -// The first header file that are included by all source files.
6 -
7 -#define IHF // for dll import
8 -#include "ith/dllconfig.h"
9 -
10 -// EOF
This diff could not be displayed because it is too large.
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
1 -#pragma once
2 -
3 -// engine/hookdefs.h
4 -// 7/20/2014 jichi
5 -
6 -#include "config.h"
7 -
8 -// For HookParam user flags
9 -enum HookParamFlag : unsigned long {
10 - HPF_Null = 0 // never used
11 - , HPF_IgnoreSameAddress = 1 // ignore the last same text address
12 -};
13 -
14 -// EOF
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 -*/
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
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
1 -#pragma once
2 -
3 -// pchooks.h
4 -// 8/1/2014 jichi
5 -
6 -#include "config.h"
7 -
8 -namespace PcHooks {
9 -
10 -void hookGDIFunctions();
11 -void hookLstrFunctions();
12 -void hookWcharFunctions();
13 -
14 -} // namespace PcHooks
15 -
16 -// EOF
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
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
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 -*/
1 -#pragma once
2 -
3 -// hook.h
4 -// 8/23/2013 jichi
5 -// Branch: ITH/IHF_DLL.h, rev 66
6 -
7 -#include "ith/common/const.h"
8 -#include "ith/common/types.h"
9 -
10 -//#ifdef IHF
11 -//# define IHFAPI __declspec(dllexport) __stdcall
12 -//#else
13 -//# define IHFAPI __declspec(dllimport) __stdcall
14 -//#endif // IHF
15 -#define IHFAPI // 9/19/2014 jichi: dummy
16 -
17 -//extern "C" {
18 -//DWORD IHFAPI OutputConsole(LPCWSTR text);
19 -void IHFAPI ConsoleOutput(LPCSTR text); // jichi 12/25/2013: Used to return length of sent text
20 -//DWORD IHFAPI OutputDWORD(DWORD d);
21 -//DWORD IHFAPI OutputRegister(DWORD *base);
22 -DWORD IHFAPI NotifyHookInsert(DWORD addr);
23 -DWORD IHFAPI NewHook(const HookParam &hp, LPCWSTR name, DWORD flag = HOOK_ENGINE);
24 -DWORD IHFAPI RemoveHook(DWORD addr);
25 -DWORD IHFAPI SwitchTrigger(DWORD on);
26 -DWORD IHFAPI GetFunctionAddr(const char *name, DWORD *addr, DWORD *base, DWORD *size, LPWSTR *base_name);
27 -//DWORD IHFAPI RegisterEngineModule(DWORD idEngine, DWORD dnHook);
28 -//} // extern "C"
29 -
30 -// 10/21/2014 jichi: TODO: Get rid of this global variable
31 -// Defined in pipe.cc
32 -extern bool engine_registered;
33 -
34 -
35 -// 10/14/2014 jichi: disable GDI hooks
36 -void DisableGDIHooks();
37 -
38 -// EOF
1 -# hook.pro
2 -# 8/9/2013 jichi
3 -# Build vnrhook.dll for Windows 7+
4 -
5 -CONFIG += eh eha # exception handler to catch all exceptions
6 -#CONFIG += noeh # msvcrt on Windows XP does not has exception handler
7 -include(../dllconfig.pri)
8 -include(../sys/sys.pri)
9 -include($$LIBDIR/disasm/disasm.pri)
10 -include($$LIBDIR/memdbg/memdbg.pri)
11 -include($$LIBDIR/ntinspect/ntinspect.pri)
12 -#include($$LIBDIR/winseh/winseh_safe.pri)
13 -include($$LIBDIR/winversion/winversion.pri)
14 -
15 -# 9/27/2013: disable ITH this game engine, only for debugging purpose
16 -#DEFINES += ITH_DISABLE_ENGINE
17 -
18 -# jichi 9/22/2013: When ITH is on wine, mutex is needed to protect NtWriteFile
19 -#DEFINES += ITH_WINE
20 -#DEFINES += ITH_SYNC_PIPE
21 -
22 -## Libraries
23 -
24 -LIBS += -lkernel32 -luser32 -lgdi32
25 -
26 -## Sources
27 -
28 -TEMPLATE = lib
29 -TARGET = vnrhook
30 -
31 -#CONFIG += staticlib
32 -
33 -HEADERS += \
34 - config.h \
35 - cli.h \
36 - hook.h \
37 - engine/engine.h \
38 - engine/hookdefs.h \
39 - engine/match.h \
40 - engine/pchooks.h \
41 - engine/util.h \
42 - tree/avl.h
43 -
44 -SOURCES += \
45 - main.cc \
46 - rpc/pipe.cc \
47 - hijack/texthook.cc \
48 - engine/engine.cc \
49 - engine/match.cc \
50 - engine/pchooks.cc \
51 - engine/util.cc
52 -
53 -#RC_FILE += vnrhook.rc
54 -#OTHER_FILES += vnrhook.rc
55 -
56 -# EOF
1 -// main.cc
2 -// 8/24/2013 jichi
3 -// Branch: ITH_DLL/main.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:4733) // C4733: Inline asm assigning to 'FS:0' : handler not registered as safe handler
9 -#endif // _MSC_VER
10 -
11 -#include "cli.h"
12 -#include "tree/avl.h"
13 -#include "engine/match.h"
14 -#include "ith/common/const.h"
15 -#include "ith/common/defs.h"
16 -#include "ith/common/except.h"
17 -//#include "ith/common/growl.h"
18 -#include "ith/sys/sys.h"
19 -#include "ccutil/ccmacro.h"
20 -//#include "ntinspect/ntinspect.h"
21 -//#include "winseh/winseh.h"
22 -//#include <boost/foreach.hpp>
23 -//#include "md5.h"
24 -//#include <ITH\AVL.h>
25 -//#include <ITH\ntdll.h>
26 -
27 -// Global variables
28 -
29 -// jichi 6/3/2014: memory range of the current module
30 -DWORD processStartAddress,
31 - processStopAddress;
32 -
33 -namespace { // unnamed
34 -wchar_t processName[MAX_PATH];
35 -
36 -inline void GetProcessName(wchar_t *name)
37 -{
38 - //assert(name);
39 - PLDR_DATA_TABLE_ENTRY it;
40 - __asm
41 - {
42 - mov eax,fs:[0x30]
43 - mov eax,[eax+0xc]
44 - mov eax,[eax+0xc]
45 - mov it,eax
46 - }
47 - wcscpy(name, it->BaseDllName.Buffer);
48 -}
49 -} // unmaed namespace
50 -
51 -enum { HOOK_BUFFER_SIZE = MAX_HOOK * sizeof(TextHook) };
52 -//#define MAX_HOOK (HOOK_BUFFER_SIZE/sizeof(TextHook))
53 -DWORD hook_buff_len = HOOK_BUFFER_SIZE;
54 -
55 -namespace { FilterRange _filter[IHF_FILTER_CAPACITY]; }
56 -FilterRange *filter = _filter;
57 -
58 -WCHAR dll_mutex[0x100];
59 -//WCHAR dll_name[0x100];
60 -WCHAR hm_mutex[0x100];
61 -WCHAR hm_section[0x100];
62 -HINSTANCE hDLL;
63 -HANDLE hSection;
64 -bool running,
65 - live = false;
66 -int current_hook = 0,
67 - user_hook_count = 0;
68 -DWORD trigger = 0;
69 -HANDLE
70 - hFile,
71 - hMutex,
72 - hmMutex;
73 -//DWORD current_process_id;
74 -extern DWORD enter_count;
75 -//extern LPWSTR current_dir;
76 -extern DWORD engine_type;
77 -extern DWORD module_base;
78 -AVLTree<char, FunctionInfo, SCMP, SCPY, SLEN> *tree;
79 -
80 -namespace { // unnamed
81 -
82 -void AddModule(DWORD hModule, DWORD size, LPWSTR name)
83 -{
84 - IMAGE_DOS_HEADER *DosHdr;
85 - IMAGE_NT_HEADERS *NtHdr;
86 - IMAGE_EXPORT_DIRECTORY *ExtDir;
87 - UINT uj;
88 - FunctionInfo info = {0, hModule, size, name};
89 - char *pcFuncPtr, *pcBuffer;
90 - DWORD dwReadAddr, dwFuncName, dwExportAddr;
91 - WORD wOrd;
92 - DosHdr = (IMAGE_DOS_HEADER *)hModule;
93 - if (IMAGE_DOS_SIGNATURE==DosHdr->e_magic) {
94 - dwReadAddr = hModule + DosHdr->e_lfanew;
95 - NtHdr = (IMAGE_NT_HEADERS *)dwReadAddr;
96 - if (IMAGE_NT_SIGNATURE == NtHdr->Signature) {
97 - dwExportAddr = NtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
98 - if (dwExportAddr == 0)
99 - return;
100 - dwExportAddr+=hModule;
101 - ExtDir=(IMAGE_EXPORT_DIRECTORY*)dwExportAddr;
102 - dwExportAddr=hModule+ExtDir->AddressOfNames;
103 - for (uj = 0; uj < ExtDir->NumberOfNames; uj++) {
104 - dwFuncName=*(DWORD*)dwExportAddr;
105 - pcBuffer = (char *)(hModule+dwFuncName);
106 - pcFuncPtr=(char *)(hModule+(DWORD)ExtDir->AddressOfNameOrdinals+(uj*sizeof(WORD)));
107 - wOrd = *(WORD *)pcFuncPtr;
108 - pcFuncPtr = (char *)(hModule+(DWORD)ExtDir->AddressOfFunctions+(wOrd*sizeof(DWORD)));
109 - info.addr=hModule+*(DWORD*)pcFuncPtr;
110 - ::tree->Insert(pcBuffer,info);
111 - dwExportAddr+=sizeof(DWORD);
112 - }
113 - }
114 - }
115 -}
116 -
117 -void GetFunctionNames()
118 -{
119 - // jichi 9/26/2013: AVLTree is already zero
120 - PPEB ppeb;
121 - __asm {
122 - mov eax, fs:[0x30]
123 - mov ppeb, eax
124 - }
125 - DWORD temp = *(DWORD *)(&ppeb->Ldr->InLoadOrderModuleList);
126 - PLDR_DATA_TABLE_ENTRY it = (PLDR_DATA_TABLE_ENTRY)temp;
127 - while (it->SizeOfImage) {
128 - AddModule((DWORD)it->DllBase, it->SizeOfImage, it->BaseDllName.Buffer);
129 - it = (PLDR_DATA_TABLE_ENTRY)it->InLoadOrderModuleList.Flink;
130 - if (*(DWORD *)it == temp)
131 - break;
132 - }
133 -}
134 -
135 -void RequestRefreshProfile()
136 -{
137 - if (::live) {
138 - BYTE buffer[0x80] = {}; // 11/14/2013: reset to zero. Shouldn't it be 0x8 instead of 0x80?
139 - *(DWORD *)buffer = -1;
140 - *(DWORD *)(buffer + 4) = 1;
141 - *(DWORD *)(buffer + 8) = 0;
142 - IO_STATUS_BLOCK ios;
143 - CliLockPipe();
144 - NtWriteFile(hPipe, 0, 0, 0, &ios, buffer, HEADER_SIZE, 0, 0);
145 - CliUnlockPipe();
146 - }
147 -}
148 -
149 -} // unnamed namespace
150 -
151 -DWORD IHFAPI GetFunctionAddr(const char *name, DWORD *addr, DWORD *base, DWORD *size, LPWSTR *base_name)
152 -{
153 - TreeNode<char *,FunctionInfo> *node = ::tree->Search(name);
154 - if (node) {
155 - if (addr) *addr = node->data.addr;
156 - if (base) *base = node->data.module;
157 - if (size) *size = node->data.size;
158 - if (base_name) *base_name = node->data.name;
159 - return TRUE;
160 - }
161 - else
162 - return FALSE;
163 -}
164 -
165 -BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID lpReserved)
166 -{
167 -
168 - static HANDLE hSendThread,
169 - hCmdThread,
170 - hEngineThread;
171 -
172 -
173 - CC_UNUSED(lpReserved);
174 -
175 - //static WCHAR dll_exist[] = L"ITH_DLL_RUNNING";
176 - static WCHAR dll_exist[] = ITH_CLIENT_MUTEX;
177 - static HANDLE hDllExist;
178 -
179 - // jichi 9/23/2013: wine deficenciy on mapping sections
180 - // Whe set to false, do not map sections.
181 - //static bool ith_has_section = true;
182 -
183 - switch (fdwReason) {
184 - case DLL_PROCESS_ATTACH:
185 - {
186 - LdrDisableThreadCalloutsForDll(hModule);
187 - //IthBreak();
188 - ::module_base = (DWORD)hModule;
189 - IthInitSystemService();
190 - swprintf(hm_section, ITH_SECTION_ L"%d", current_process_id);
191 -
192 - // jichi 9/25/2013: Interprocedural communication with vnrsrv.
193 - hSection = IthCreateSection(hm_section, HOOK_SECTION_SIZE, PAGE_EXECUTE_READWRITE);
194 - ::hookman = nullptr;
195 - NtMapViewOfSection(hSection, NtCurrentProcess(),
196 - (LPVOID *)&::hookman, 0, hook_buff_len, 0, &hook_buff_len, ViewUnmap, 0,
197 - PAGE_EXECUTE_READWRITE);
198 - //PAGE_EXECUTE_READWRITE);
199 -
200 - GetProcessName(::processName);
201 - FillRange(::processName, &::processStartAddress, &::processStopAddress);
202 - //NtInspect::getCurrentMemoryRange(&::processStartAddress, &::processStopAddress);
203 -
204 - //if (!::hookman) {
205 - // ith_has_section = false;
206 - // ::hookman = new TextHook[MAX_HOOK];
207 - // memset(::hookman, 0, MAX_HOOK * sizeof(TextHook));
208 - //}
209 -
210 - //LPCWSTR p;
211 - //for (p = GetMainModulePath(); *p; p++);
212 - //for (p = p; *p != L'\\'; p--);
213 - //wcscpy(dll_name, p + 1);
214 - //swprintf(dll_mutex,L"ITH_%.4d_%s",current_process_id,current_dir);
215 - swprintf(dll_mutex, ITH_PROCESS_MUTEX_ L"%d", current_process_id);
216 - swprintf(hm_mutex, ITH_HOOKMAN_MUTEX_ L"%d", current_process_id);
217 - hmMutex = IthCreateMutex(hm_mutex, FALSE);
218 -
219 - DWORD s;
220 - hMutex = IthCreateMutex(dll_mutex, TRUE, &s); // jichi 9/18/2013: own is true
221 - if (s)
222 - return FALSE;
223 -
224 - hDllExist = IthCreateMutex(dll_exist, 0);
225 - hDLL = hModule;
226 - ::running = true;
227 - ::current_available = ::hookman;
228 - ::tree = new AVLTree<char, FunctionInfo, SCMP, SCPY, SLEN>;
229 - GetFunctionNames();
230 - InitFilterTable();
231 - //InitDefaultHook(); // jichi 7/17/2014: Disabled by default
232 - hSendThread = IthCreateThread(WaitForPipe, 0);
233 - hCmdThread = IthCreateThread(CommandPipe, 0);
234 - hEngineThread = IthCreateThread(Engine::match, 0);
235 - }
236 - break;
237 - case DLL_PROCESS_DETACH:
238 - {
239 - // jichi 10/2/2103: Cannot use __try in functions that require object unwinding
240 - //ITH_TRY {
241 - ::running = false;
242 - ::live = false;
243 -
244 - const LONGLONG timeout = -50000000; // in nanoseconds = 5 seconds
245 -
246 - if (hEngineThread) {
247 - NtWaitForSingleObject(hEngineThread, 0, (PLARGE_INTEGER)&timeout);
248 - NtClose(hEngineThread);
249 - }
250 -
251 - if (hSendThread) {
252 - NtWaitForSingleObject(hSendThread, 0, (PLARGE_INTEGER)&timeout);
253 - NtClose(hSendThread);
254 - }
255 -
256 - if (hCmdThread) {
257 - NtWaitForSingleObject(hCmdThread, 0, (PLARGE_INTEGER)&timeout);
258 - NtClose(hCmdThread);
259 - }
260 -
261 - for (TextHook *man = ::hookman; man->RemoveHook(); man++);
262 - //LARGE_INTEGER lint = {-10000, -1};
263 - while (::enter_count)
264 - IthSleep(1); // jichi 9/28/2013: sleep for 1 ms
265 - //NtDelayExecution(0, &lint);
266 - for (TextHook *man = ::hookman; man < ::hookman + MAX_HOOK; man++)
267 - man->ClearHook();
268 - //if (ith_has_section)
269 - NtUnmapViewOfSection(NtCurrentProcess(), ::hookman);
270 - //else
271 - // delete[] ::hookman;
272 - NtClose(hSection);
273 - NtClose(hMutex);
274 -
275 - delete ::tree;
276 - IthCloseSystemService();
277 - NtClose(hmMutex);
278 - NtClose(hDllExist);
279 - //} ITH_EXCEPT {}
280 - } break;
281 - }
282 - return TRUE;
283 -}
284 -
285 -//extern "C" {
286 -DWORD IHFAPI NewHook(const HookParam &hp, LPCWSTR name, DWORD flag)
287 -{
288 - WCHAR str[128];
289 - int current = ::current_available - ::hookman;
290 - if (current < MAX_HOOK) {
291 - //flag &= 0xffff;
292 - //if ((flag & HOOK_AUXILIARY) == 0)
293 - flag |= HOOK_ADDITIONAL;
294 - if (name == NULL || name[0] == '\0')
295 - {
296 - swprintf(str, L"UserHook%d", user_hook_count++);
297 - }
298 - else
299 - {
300 - wcscpy(str, name);
301 - }
302 -
303 - ConsoleOutput("vnrcli:NewHook: try inserting hook");
304 -
305 - // jichi 7/13/2014: This function would raise when too many hooks added
306 - ::hookman[current].InitHook(hp, str, flag & 0xffff);
307 -
308 - if (::hookman[current].InsertHook() == 0) {
309 - ConsoleOutput("vnrcli:NewHook: hook inserted");
310 - //ConsoleOutputW(name);
311 - //swprintf(str,L"Insert address 0x%.8X.", hookman[current].Address());
312 - RequestRefreshProfile();
313 - } else
314 - ConsoleOutput("vnrcli:NewHook:WARNING: failed to insert hook");
315 - }
316 - return 0;
317 -}
318 -DWORD IHFAPI RemoveHook(DWORD addr)
319 -{
320 - for (int i = 0; i < MAX_HOOK; i++)
321 - if (::hookman[i].Address ()== addr) {
322 - ::hookman[i].ClearHook();
323 - return 0;
324 - }
325 - return 0;
326 -}
327 -
328 -DWORD IHFAPI SwitchTrigger(DWORD t)
329 -{
330 - trigger = t;
331 - return 0;
332 -}
333 -
334 -//} // extern "C"
335 -
336 -
337 -namespace { // unnamed
338 -
339 -BOOL SafeFillRange(LPCWSTR dll, DWORD *lower, DWORD *upper)
340 -{
341 - BOOL ret = FALSE;
342 - ITH_WITH_SEH(ret = FillRange(dll, lower, upper));
343 - return ret;
344 -}
345 -
346 -} // unnamed namespace
347 -
348 -// jichi 12/13/2013
349 -// Use listdlls from SystemInternals
350 -void InitFilterTable()
351 -{
352 - LPCWSTR l[] = { IHF_FILTER_DLL_LIST };
353 - enum { capacity = sizeof(l)/sizeof(*l) };
354 -
355 - size_t count = 0;
356 - //for (auto p : l)
357 - for (size_t i = 0; i < capacity; i++)
358 - if (SafeFillRange(l[i], &::filter[count].lower, &::filter[count].upper))
359 - count++;
360 -}
361 -
362 -// EOF
363 -/*
364 -
365 -static DWORD recv_esp, recv_addr;
366 -static CONTEXT recover_context;
367 -static __declspec(naked) void MySEH()
368 -{
369 - __asm{
370 - mov eax, [esp+0xC]
371 - mov edi,eax
372 - mov ecx,0xB3
373 - mov esi, offset recover_context
374 - rep movs
375 - mov ecx, [recv_esp]
376 - mov [eax+0xC4],ecx
377 - mov edx, [recv_addr]
378 - mov [eax+0xB8],edx
379 - xor eax,eax
380 - retn
381 - }
382 -}
383 -
384 -EXCEPTION_DISPOSITION ExceptHandler(
385 - EXCEPTION_RECORD *ExceptionRecord,
386 - void * EstablisherFrame,
387 - CONTEXT *ContextRecord,
388 - void * DispatcherContext )
389 -{
390 - ContextRecord->Esp=recv_esp;
391 - ContextRecord->Eip=recv_addr;
392 - return ExceptionContinueExecution;
393 -}
394 -int GuardRange(LPWSTR module, DWORD *a, DWORD *b)
395 -{
396 - int flag=0;
397 - __asm
398 - {
399 - mov eax,seh_recover
400 - mov recv_addr,eax
401 - push ExceptHandler
402 - push fs:[0]
403 - mov recv_esp,esp
404 - mov fs:[0],esp
405 - }
406 - flag = FillRange(module, a, b);
407 - __asm
408 - {
409 -seh_recover:
410 - mov eax,[esp]
411 - mov fs:[0],eax
412 - add esp,8
413 - }
414 - return flag;
415 -}
416 -*/
1 -// pipe.cc
2 -// 8/24/2013 jichi
3 -// Branch: ITH_DLL/pipe.cpp, rev 66
4 -// 8/24/2013 TODO: Clean up this file
5 -
6 -#ifdef _MSC_VER
7 -# pragma warning (disable:4100) // C4100: unreference formal parameter
8 -#endif // _MSC_VER
9 -
10 -#include "cli.h"
11 -#include "engine/match.h"
12 -#include "ith/common/defs.h"
13 -//#include "ith/common/growl.h"
14 -#include "ith/sys/sys.h"
15 -#include "ccutil/ccmacro.h"
16 -
17 -//#include <ITH\AVL.h>
18 -//#include <ITH\ntdll.h>
19 -WCHAR mutex[] = ITH_GRANTPIPE_MUTEX;
20 -WCHAR exist[] = ITH_PIPEEXISTS_EVENT;
21 -WCHAR detach_mutex[0x20];
22 -//WCHAR write_event[0x20];
23 -//WCHAR engine_event[0x20];
24 -
25 -//WCHAR recv_pipe[] = L"\\??\\pipe\\ITH_PIPE";
26 -//WCHAR command[] = L"\\??\\pipe\\ITH_COMMAND";
27 -wchar_t recv_pipe[] = ITH_TEXT_PIPE;
28 -wchar_t command[] = ITH_COMMAND_PIPE;
29 -
30 -LARGE_INTEGER wait_time = {-100*10000, -1};
31 -LARGE_INTEGER sleep_time = {-20*10000, -1};
32 -
33 -DWORD engine_type;
34 -DWORD module_base;
35 -
36 -//DWORD engine_base;
37 -bool engine_registered; // 10/19/2014 jichi: disable engine dll
38 -
39 -HANDLE hPipe,
40 - hCommand,
41 - hDetach; //,hLose;
42 -//InsertHookFun InsertHook;
43 -//IdentifyEngineFun IdentifyEngine;
44 -//InsertDynamicHookFun InsertDynamicHook;
45 -
46 -bool hook_inserted = false;
47 -
48 -// jichi 9/28/2013: protect pipe on wine
49 -// Put the definition in this file so that it might be inlined
50 -void CliUnlockPipe()
51 -{
52 - if (IthIsWine())
53 - IthReleaseMutex(::hmMutex);
54 -}
55 -
56 -void CliLockPipe()
57 -{
58 - if (IthIsWine()) {
59 - const LONGLONG timeout = -50000000; // in nanoseconds = 5 seconds
60 - NtWaitForSingleObject(hmMutex, 0, (PLARGE_INTEGER)&timeout);
61 - }
62 -}
63 -
64 -HANDLE IthOpenPipe(LPWSTR name, ACCESS_MASK direction)
65 -{
66 - UNICODE_STRING us;
67 - RtlInitUnicodeString(&us,name);
68 - SECURITY_DESCRIPTOR sd = {1};
69 - OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, &sd, 0};
70 - HANDLE hFile;
71 - IO_STATUS_BLOCK isb;
72 - if (NT_SUCCESS(NtCreateFile(&hFile, direction, &oa, &isb, 0, 0, FILE_SHARE_READ, FILE_OPEN, 0, 0, 0)))
73 - return hFile;
74 - else
75 - return INVALID_HANDLE_VALUE;
76 -}
77 -
78 -DWORD WINAPI WaitForPipe(LPVOID lpThreadParameter) // Dynamically detect ITH main module status.
79 -{
80 - CC_UNUSED(lpThreadParameter);
81 - int i;
82 - TextHook *man;
83 - struct {
84 - DWORD pid;
85 - TextHook *man;
86 - DWORD module;
87 - //DWORD engine;
88 - } u;
89 - HANDLE hMutex,
90 - hPipeExist;
91 - //swprintf(engine_event,L"ITH_ENGINE_%d",current_process_id);
92 - swprintf(detach_mutex, ITH_DETACH_MUTEX_ L"%d", current_process_id);
93 - //swprintf(lose_event,L"ITH_LOSEPIPE_%d",current_process_id);
94 - //hEngine=IthCreateEvent(engine_event);
95 - //NtWaitForSingleObject(hEngine,0,0);
96 - //NtClose(hEngine);
97 - while (!engine_registered)
98 - NtDelayExecution(0, &wait_time);
99 - //LoadEngine(L"ITH_Engine.dll");
100 - u.module = module_base;
101 - u.pid = current_process_id;
102 - u.man = hookman;
103 - //u.engine = engine_base; // jichi 10/19/2014: disable the second dll
104 - hPipeExist = IthOpenEvent(exist);
105 - IO_STATUS_BLOCK ios;
106 - //hLose=IthCreateEvent(lose_event,0,0);
107 - if (hPipeExist != INVALID_HANDLE_VALUE)
108 - while (running) {
109 - hPipe = INVALID_HANDLE_VALUE;
110 - hCommand = INVALID_HANDLE_VALUE;
111 - while (NtWaitForSingleObject(hPipeExist,0,&wait_time) == WAIT_TIMEOUT)
112 - if (!running)
113 - goto _release;
114 - hMutex = IthCreateMutex(mutex,0);
115 - NtWaitForSingleObject(hMutex,0,0);
116 - while (hPipe == INVALID_HANDLE_VALUE||
117 - hCommand == INVALID_HANDLE_VALUE) {
118 - NtDelayExecution(0, &sleep_time);
119 - if (hPipe == INVALID_HANDLE_VALUE)
120 - hPipe = IthOpenPipe(recv_pipe, GENERIC_WRITE);
121 - if (hCommand == INVALID_HANDLE_VALUE)
122 - hCommand = IthOpenPipe(command, GENERIC_READ);
123 - }
124 - //NtClearEvent(hLose);
125 - CliLockPipe();
126 - NtWriteFile(hPipe, 0, 0, 0, &ios, &u, sizeof(u), 0, 0);
127 - CliUnlockPipe();
128 - live = true;
129 - for (man = hookman, i = 0; i < current_hook; man++)
130 - if (man->RecoverHook()) // jichi 9/27/2013: This is the place where built-in hooks like TextOutA are inserted
131 - i++;
132 - //ConsoleOutput(dll_name);
133 - ConsoleOutput("vnrcli:WaitForPipe: pipe connected");
134 - //OutputDWORD(tree->Count());
135 - NtReleaseMutant(hMutex,0);
136 - NtClose(hMutex);
137 - if (!hook_inserted && engine_registered) {
138 - hook_inserted = true;
139 - Engine::IdentifyEngine();
140 - }
141 - hDetach = IthCreateMutex(detach_mutex,1);
142 - while (running && NtWaitForSingleObject(hPipeExist, 0, &sleep_time) == WAIT_OBJECT_0)
143 - NtDelayExecution(0, &sleep_time);
144 - live = false;
145 - for (man = hookman, i = 0; i < current_hook; man++)
146 - if (man->RemoveHook())
147 - i++;
148 - if (!running) {
149 - IthCoolDown(); // jichi 9/28/2013: Use cooldown instead of lock pipe to prevent from hanging on exit
150 - //CliLockPipe();
151 - NtWriteFile(hPipe, 0, 0, 0, &ios, man, 4, 0, 0);
152 - //CliUnlockPipe();
153 - IthReleaseMutex(hDetach);
154 - }
155 - NtClose(hDetach);
156 - NtClose(hPipe);
157 - }
158 -_release:
159 - //NtClose(hLose);
160 - NtClose(hPipeExist);
161 - return 0;
162 -}
163 -DWORD WINAPI CommandPipe(LPVOID lpThreadParameter)
164 -{
165 - CC_UNUSED(lpThreadParameter);
166 - DWORD command;
167 - BYTE buff[0x400] = {};
168 - HANDLE hPipeExist;
169 - hPipeExist = IthOpenEvent(exist);
170 - IO_STATUS_BLOCK ios={};
171 - if (hPipeExist!=INVALID_HANDLE_VALUE)
172 - while (running) {
173 - while (!live) {
174 - if (!running)
175 - goto _detach;
176 - NtDelayExecution(0, &sleep_time);
177 - }
178 - // jichi 9/27/2013: Why 0x200 not 0x400? wchar_t?
179 - switch (NtReadFile(hCommand, 0, 0, 0, &ios, buff, 0x200, 0, 0)) {
180 - case STATUS_PIPE_BROKEN:
181 - case STATUS_PIPE_DISCONNECTED:
182 - NtClearEvent(hPipeExist);
183 - continue;
184 - case STATUS_PENDING:
185 - NtWaitForSingleObject(hCommand, 0, 0);
186 - switch (ios.Status) {
187 - case STATUS_PIPE_BROKEN:
188 - case STATUS_PIPE_DISCONNECTED:
189 - NtClearEvent(hPipeExist);
190 - continue;
191 - case 0: break;
192 - default:
193 - if (NtWaitForSingleObject(hDetach, 0, &wait_time) == WAIT_OBJECT_0)
194 - goto _detach;
195 - }
196 - }
197 - if (ios.uInformation && live) {
198 - command = *(DWORD *)buff;
199 - switch(command) {
200 - case IHF_COMMAND_NEW_HOOK:
201 - //IthBreak();
202 - buff[ios.uInformation] = 0;
203 - buff[ios.uInformation + 1] = 0;
204 - NewHook(*(HookParam *)(buff + 4), (LPWSTR)(buff + 4 + sizeof(HookParam)), 0);
205 - break;
206 - case IHF_COMMAND_REMOVE_HOOK:
207 - {
208 - DWORD rm_addr = *(DWORD *)(buff+4);
209 - HANDLE hRemoved = IthOpenEvent(ITH_REMOVEHOOK_EVENT);
210 -
211 - TextHook *in = hookman;
212 - for (int i = 0; i < current_hook; in++) {
213 - if (in->Address()) i++;
214 - if (in->Address() == rm_addr) break;
215 - }
216 - if (in->Address())
217 - in->ClearHook();
218 - IthSetEvent(hRemoved);
219 - NtClose(hRemoved);
220 - } break;
221 - case IHF_COMMAND_MODIFY_HOOK:
222 - {
223 - DWORD rm_addr = *(DWORD *)(buff + 4);
224 - HANDLE hModify = IthOpenEvent(ITH_MODIFYHOOK_EVENT);
225 - TextHook *in = hookman;
226 - for (int i = 0; i < current_hook; in++) {
227 - if (in->Address())
228 - i++;
229 - if (in->Address() == rm_addr)
230 - break;
231 - }
232 - if (in->Address())
233 - in->ModifyHook(*(HookParam *)(buff + 4));
234 - IthSetEvent(hModify);
235 - NtClose(hModify);
236 - } break;
237 - case IHF_COMMAND_DETACH:
238 - running = false;
239 - live = false;
240 - goto _detach;
241 - default: ;
242 - }
243 - }
244 - }
245 -_detach:
246 - NtClose(hPipeExist);
247 - NtClose(hCommand);
248 - return 0;
249 -}
250 -//extern "C" {
251 -void IHFAPI ConsoleOutput(LPCSTR text)
252 -{ // jichi 12/25/2013: Rewrite the implementation
253 - if (!live || !text)
254 - return;
255 - enum { buf_size = 0x50 };
256 - BYTE buf[buf_size]; // buffer is needed to append the message header
257 - size_t text_size = strlen(text) + 1;
258 - size_t data_size = text_size + 8;
259 -
260 - BYTE *data = (data_size <= buf_size) ? buf : new BYTE[data_size];
261 - *(DWORD *)data = IHF_NOTIFICATION; //cmd
262 - *(DWORD *)(data + 4) = IHF_NOTIFICATION_TEXT; //console
263 - memcpy(data + 8, text, text_size);
264 -
265 - IO_STATUS_BLOCK ios;
266 - NtWriteFile(hPipe, 0, 0, 0, &ios, data, data_size, 0, 0);
267 - if (data != buf)
268 - delete[] data;
269 -}
270 - //if (str) {
271 - // int t, len, sum;
272 - // BYTE buffer[0x80];
273 - // BYTE *buff;
274 - // len = wcslen(str) << 1;
275 - // t = swprintf((LPWSTR)(buffer + 8),L"%d: ",current_process_id) << 1;
276 - // sum = len + t + 8;
277 - // if (sum > 0x80) {
278 - // buff = new BYTE[sum];
279 - // memset(buff, 0, sum); // jichi 9/25/2013: zero memory
280 - // memcpy(buff + 8, buffer + 8, t);
281 - // }
282 - // else
283 - // buff = buffer;
284 - // *(DWORD *)buff = IHF_NOTIFICATION; //cmd
285 - // *(DWORD *)(buff + 4) = IHF_NOTIFICATION_TEXT; //console
286 - // memcpy(buff + t + 8, str, len);
287 - // IO_STATUS_BLOCK ios;
288 - // NtWriteFile(hPipe,0,0,0,&ios,buff,sum,0,0);
289 - // if (buff != buffer)
290 - // delete[] buff;
291 - // return len;
292 - //}
293 -
294 -//DWORD IHFAPI OutputDWORD(DWORD d)
295 -//{
296 -// WCHAR str[0x10];
297 -// swprintf(str,L"%.8X",d);
298 -// ConsoleOutput(str);
299 -// return 0;
300 -//}
301 -//DWORD IHFAPI OutputRegister(DWORD *base)
302 -//{
303 -// WCHAR str[0x40];
304 -// swprintf(str,L"EAX:%.8X",base[0]);
305 -// ConsoleOutput(str);
306 -// swprintf(str,L"ECX:%.8X",base[-1]);
307 -// ConsoleOutput(str);
308 -// swprintf(str,L"EDX:%.8X",base[-2]);
309 -// ConsoleOutput(str);
310 -// swprintf(str,L"EBX:%.8X",base[-3]);
311 -// ConsoleOutput(str);
312 -// swprintf(str,L"ESP:%.8X",base[-4]);
313 -// ConsoleOutput(str);
314 -// swprintf(str,L"EBP:%.8X",base[-5]);
315 -// ConsoleOutput(str);
316 -// swprintf(str,L"ESI:%.8X",base[-6]);
317 -// ConsoleOutput(str);
318 -// swprintf(str,L"EDI:%.8X",base[-7]);
319 -// ConsoleOutput(str);
320 -// return 0;
321 -//}
322 -//DWORD IHFAPI RegisterEngineModule(DWORD idEngine, DWORD dnHook)
323 -//{
324 -// ::IdentifyEngine = (IdentifyEngineFun)idEngine;
325 -// ::InsertDynamicHook = (InsertDynamicHookFun)dnHook;
326 -// ::engine_registered = true;
327 -// return 0;
328 -//}
329 -DWORD IHFAPI NotifyHookInsert(DWORD addr)
330 -{
331 - if (live) {
332 - BYTE buffer[0x10];
333 - *(DWORD *)buffer = IHF_NOTIFICATION;
334 - *(DWORD *)(buffer + 4) = IHF_NOTIFICATION_NEWHOOK;
335 - *(DWORD *)(buffer + 8) = addr;
336 - *(DWORD *)(buffer + 0xc) = 0;
337 - IO_STATUS_BLOCK ios;
338 - CliLockPipe();
339 - NtWriteFile(hPipe,0,0,0,&ios,buffer,0x10,0,0);
340 - CliUnlockPipe();
341 - }
342 - return 0;
343 -}
344 -//} // extern "C"
345 -
346 -// EOF
1 -#pragma once
2 -
3 -// avl.h
4 -// 8/23/2013 jichi
5 -// Branch: ITH/AVL.h, rev 133
6 -// 8/24/2013 TODO: Clean up this file
7 -
8 -#include "config.h"
9 -
10 -enum { STACK_SIZE = 32 };
11 -
12 -//#ifndef ITH_STACK
13 -//#define ITH_STACK
14 -
15 -template<class T, int stack_size>
16 -class MyStack
17 -{
18 - int index;
19 - T s[stack_size];
20 -
21 -public:
22 - MyStack(): index(0)
23 - { ITH_MEMSET_HEAP(s, 0, sizeof(s)); } // jichi 9/21/2013: assume T is atomic type
24 -
25 - T &back() { return s[index-1]; }
26 - int size() { return index; }
27 -
28 - void push_back(const T &e)
29 - {
30 - if (index < stack_size)
31 - s[index++]=e;
32 - }
33 -
34 - void pop_back() { index--; }
35 -
36 - T &operator[](int i) { return s[i]; }
37 -};
38 -//#endif // ITH_STACK
39 -
40 -// jichi 9/22/2013: T must be a pointer type which can be deleted
41 -template <class T, class D>
42 -struct TreeNode
43 -{
44 - //typedef TreeNode<T, D> Self;
45 - TreeNode() :
46 - Left(nullptr), Right(nullptr), Parent(nullptr)
47 - , rank(1)
48 - , factor('\0'), reserve('\0')
49 - //, key()
50 - //, data()
51 - {
52 - ITH_MEMSET_HEAP(&key, 0, sizeof(key)); // jichi 9/26/2013: zero memory
53 - ITH_MEMSET_HEAP(&data, 0, sizeof(data)); // jichi 9/26/2013: zero memory
54 - }
55 -
56 - TreeNode(const T &k, const D &d) :
57 - Left(nullptr), Right(nullptr), Parent(nullptr)
58 - , rank(1)
59 - , factor('\0'), reserve('\0') // jichi 9/21/2013: zero reserve
60 - , key(k)
61 - , data(d)
62 - {}
63 -
64 - TreeNode *Successor()
65 - {
66 - TreeNode *Node,
67 - *ParentNode;
68 - Node = Right;
69 - if (!Node) {
70 - Node = this;
71 - for (;;) {
72 - ParentNode = Node->Parent;
73 - if (!ParentNode)
74 - return nullptr;
75 - if (ParentNode->Left == Node)
76 - break;
77 - Node = ParentNode;
78 - }
79 - return ParentNode;
80 - }
81 - else
82 - while (Node->Left)
83 - Node = Node->Left;
84 - return Node;
85 - }
86 - TreeNode *Predecessor()
87 - {
88 - TreeNode *Node,
89 - *ParentNode;
90 - Node = Left;
91 - if (!Node) {
92 - Node = this;
93 - for(;;) {
94 - ParentNode = Node->Parent;
95 - if (!ParentNode)
96 - return nullptr;
97 - if (ParentNode->Right == Node)
98 - break;
99 - Node = ParentNode;
100 - }
101 - return ParentNode;
102 - }
103 - else
104 - while (Node->Right)
105 - Node = Node->Right;
106 - return Node;
107 - }
108 - int height()
109 - {
110 - if (!this) // jichi 9/26/2013: what?!
111 - return 0;
112 - int l = Left->height(),
113 - r = Right->height(),
114 - f = factor;
115 - if (l - r + f != 0)
116 - __debugbreak();
117 - f = l > r ? l : r;
118 - return f + 1;
119 - }
120 - TreeNode *Left,
121 - *Right,
122 - *Parent;
123 - unsigned short rank;
124 - char factor,
125 - reserve;
126 - T key;
127 - D data;
128 -};
129 -
130 -template<class T,class D>
131 -struct NodePath
132 -{
133 - NodePath() { memset(this, 0, sizeof(NodePath)); } // jichi 11/30/2013: This is the original code in ITH
134 - NodePath(TreeNode<T,D> *n, int f): Node(n), fact(f) {}
135 - TreeNode<T,D> *Node;
136 - union { char factor; int fact; };
137 -};
138 -
139 -template <class T, class D, class fComp, class fCopy, class fLength>
140 -class AVLTree
141 -{
142 - fComp fCmp;
143 - fCopy fCpy;
144 - fLength fLen;
145 -
146 -protected:
147 - TreeNode<T*, D> head;
148 -
149 -public:
150 - // - Construction -
151 - AVLTree() {}
152 -
153 - virtual ~AVLTree() { DeleteAll(); }
154 -
155 - // - Properties -
156 -
157 - TreeNode<T*, D> *TreeRoot() const { return head.Left; }
158 -
159 - // - Actions -
160 -
161 - void DeleteAll()
162 - {
163 - while (head.Left)
164 - DeleteRoot();
165 - }
166 -
167 - TreeNode<T*, D> *Insert(const T *key, const D &data)
168 - {
169 - if (head.Left) {
170 - MyStack<TreeNode<T*, D> *,STACK_SIZE> path;
171 - TreeNode<T*,D> *DownNode, *ParentNode, *BalanceNode, *TryNode, *NewNode; //P,T,S,Q
172 - ParentNode = &head;
173 - path.push_back(ParentNode);
174 - char factor,f;
175 - BalanceNode = DownNode = head.Left;
176 - for (;;) { //The first part of AVL tree insert. Just do as binary tree insert routine and record some nodes.
177 - factor = fCmp(key,DownNode->key);
178 - if (factor == 0)
179 - return DownNode; //Duplicate key. Return and do nothing.
180 - TryNode = _FactorLink(DownNode, factor);
181 - if (factor == -1)
182 - path.push_back(DownNode);
183 - if (TryNode) { //DownNode has a child.
184 - if (TryNode->factor != 0) { //Keep track of unbalance node and its parent.
185 - ParentNode = DownNode;
186 - BalanceNode = TryNode;
187 - }
188 - DownNode = TryNode;
189 - }
190 - else
191 - break; //Finished binary tree search;
192 - }
193 - while (path.size()) {
194 - path.back()->rank++;
195 - path.pop_back();
196 - }
197 - size_t sz = fLen(key) + 1;
198 - T *new_key = new T[sz];
199 - ITH_MEMSET_HEAP(new_key, 0, sz * sizeof(T)); // jichi 9/26/2013: Zero memory
200 - fCpy(new_key, key);
201 - TryNode = new TreeNode<T*, D>(new_key, data);
202 - _FactorLink(DownNode, factor) = TryNode;
203 - TryNode->Parent = DownNode;
204 - NewNode = TryNode;
205 - //Finished binary tree insert. Next to do is to modify balance factors between
206 - //BalanceNode and the new node.
207 - TreeNode<T*, D> *ModifyNode;
208 - factor = fCmp(key, BalanceNode->key);
209 - //factor=key<BalanceNode->key ? factor=-1:1; //Determine the balance factor at BalanceNode.
210 - ModifyNode = DownNode = _FactorLink(BalanceNode,factor);
211 - //ModifyNode will be the 1st child.
212 - //DownNode will travel from here to the recent inserted node (TryNode).
213 - while (DownNode != TryNode) { //Check if we reach the bottom.
214 - f = fCmp(key,DownNode->key);
215 - //f=_FactorCompare(key,DownNode->key);
216 - DownNode->factor = f;
217 - DownNode = _FactorLink(DownNode, f);//Modify balance factor and travels down.
218 - }
219 - //Finshed modifying balance factor.
220 - //Next to do is check the tree if it's unbalance and recover balance.
221 - if (BalanceNode->factor == 0) { //Tree has grown higher.
222 - BalanceNode->factor = factor;
223 - _IncreaseHeight(); //Modify balance factor and increase the height.
224 - return NewNode;
225 - }
226 - if (BalanceNode->factor + factor == 0) { //Tree has gotten more balanced.
227 - BalanceNode->factor = 0; //Set balance factor to 0.
228 - return NewNode;
229 - }
230 - //Tree has gotten out of balance.
231 - if (ModifyNode->factor == factor) //A node and its child has same factor. Single rotation.
232 - DownNode = _SingleRotation(BalanceNode, ModifyNode, factor);
233 - else //A node and its child has converse factor. Double rotation.
234 - DownNode = _DoubleRotation(BalanceNode, ModifyNode, factor);
235 - //Finished the balancing work. Set child field to the root of the new child tree.
236 - if (BalanceNode == ParentNode->Left)
237 - ParentNode->Left = DownNode;
238 - else
239 - ParentNode->Right = DownNode;
240 - return NewNode;
241 - }
242 - else { //root null?
243 - size_t sz = fLen(key) + 1;
244 - T *new_key = new T[sz];
245 - ITH_MEMSET_HEAP(new_key, 0, sz * sizeof(T)); // jichi 9/26/2013: Zero memory
246 - fCpy(new_key, key);
247 - head.Left = new TreeNode<T *, D>(new_key, data);
248 - head.rank++;
249 - _IncreaseHeight();
250 - return head.Left;
251 - }
252 - }
253 - bool Delete(T *key)
254 - {
255 - NodePath<T*,D> PathNode;
256 - MyStack<NodePath<T*,D>,STACK_SIZE> path; //Use to record a path to the destination node.
257 - path.push_back(NodePath<T*,D>(&head,-1));
258 - TreeNode<T*,D> *TryNode,*ChildNode,*BalanceNode,*SuccNode;
259 - TryNode=head.Left;
260 - char factor;
261 - for (;;) { //Search for the
262 - if (TryNode == 0)
263 - return false; //Not found.
264 - factor = fCmp(key, TryNode->key);
265 - if (factor == 0)
266 - break; //Key found, continue to delete.
267 - //factor = _FactorCompare( key, TryNode->key );
268 - path.push_back(NodePath<T*,D>(TryNode,factor));
269 - TryNode = _FactorLink(TryNode,factor); //Move to left.
270 - }
271 - SuccNode = TryNode->Right; //Find a successor.
272 - factor = 1;
273 - if (SuccNode == 0) {
274 - SuccNode = TryNode->Left;
275 - factor = -1;
276 - }
277 - path.push_back(NodePath<T*,D>(TryNode,factor));
278 - while (SuccNode) {
279 - path.push_back(NodePath<T*,D>(SuccNode, -factor));
280 - SuccNode = _FactorLink(SuccNode,-factor);
281 - }
282 - PathNode = path.back();
283 - delete[] TryNode->key; // jichi 9/22/2013: key is supposed to be an array
284 - TryNode->key = PathNode.Node->key; //Replace key and data field with the successor or predecessor.
285 - PathNode.Node->key = nullptr;
286 - TryNode->data = PathNode.Node->data;
287 - path.pop_back();
288 - _FactorLink(path.back().Node,path.back().factor) = _FactorLink(PathNode.Node,-PathNode.factor);
289 - delete PathNode.Node; //Remove the successor from the tree and release memory.
290 - PathNode = path.back();
291 - for (int i=0; i<path.size(); i++)
292 - if (path[i].factor==-1)
293 - path[i].Node->rank--;
294 - for (;;) { //Rebalance the tree along the path back to the root.
295 - if (path.size()==1) {
296 - _DecreaseHeight();
297 - break;
298 - }
299 - BalanceNode = PathNode.Node;
300 - if (BalanceNode->factor == 0) { // A balance node, just need to adjust the factor. Don't have to recurve since subtree height stays.
301 - BalanceNode->factor=-PathNode.factor;
302 - break;
303 - }
304 - if (BalanceNode->factor == PathNode.factor) { // Node get more balance. Subtree height decrease, need to recurve.
305 - BalanceNode->factor = 0;
306 - path.pop_back();
307 - PathNode = path.back();
308 - continue;
309 - }
310 - //Node get out of balance. Here raises 3 cases.
311 - ChildNode = _FactorLink(BalanceNode, -PathNode.factor);
312 - if (ChildNode->factor == 0) { // New case different to insert operation.
313 - TryNode = _SingleRotation2( BalanceNode, ChildNode, BalanceNode->factor );
314 - path.pop_back();
315 - PathNode = path.back();
316 - _FactorLink(PathNode.Node, PathNode.factor) = TryNode;
317 - break;
318 - }
319 - else {
320 - if (ChildNode->factor == BalanceNode->factor) // Analogous to insert operation case 1.
321 - TryNode = _SingleRotation( BalanceNode, ChildNode, BalanceNode->factor );
322 - else if (ChildNode->factor + BalanceNode->factor == 0) // Analogous to insert operation case 2.
323 - TryNode = _DoubleRotation( BalanceNode, ChildNode, BalanceNode->factor );
324 - }
325 - path.pop_back(); //Recurse back along the path.
326 - PathNode = path.back();
327 - _FactorLink(PathNode.Node, PathNode.factor) = TryNode;
328 - }
329 - return true;
330 - }
331 -
332 - D &operator [](T *key)
333 - { return (Insert(key,D())->data); }
334 -
335 - TreeNode<T*,D> *Search(const T *key)
336 - {
337 - TreeNode<T*,D> *Find=head.Left;
338 - char k;
339 - while (Find != 0) {//&&Find->key!=key)
340 - k=fCmp(key, Find->key);
341 - if (k==0) break;
342 - Find = _FactorLink(Find, k);
343 - }
344 - return Find;
345 - }
346 -
347 - TreeNode<T*,D> *SearchIndex(unsigned int rank)
348 - {
349 - unsigned int r = head.rank;
350 - if (rank == -1)
351 - return 0;
352 - if (++rank>=r)
353 - return 0;
354 - TreeNode<T*,D> *n=&head;
355 - while (r!=rank) {
356 - if (rank>r) {
357 - n=n->Right;
358 - rank-=r;
359 - r=n->rank;
360 - } else {
361 - n=n->Left;
362 - r=n->rank;
363 - }
364 - }
365 - return n;
366 - }
367 -
368 - TreeNode<T*,D> *Begin()
369 - {
370 - TreeNode<T*,D> *Node = head.Left;
371 - if (Node)
372 - while (Node->Left) Node = Node->Left;
373 - return Node;
374 - }
375 -
376 - TreeNode<T*,D> *End()
377 - {
378 - TreeNode<T*,D> *Node=head.Left;
379 - if (Node)
380 - while (Node->Right) Node = Node->Right;
381 - return Node;
382 - }
383 - unsigned int Count() const { return head.rank - 1; }
384 -
385 - template <class Fn>
386 - Fn TraverseTree(Fn &f)
387 - { return TraverseTreeNode(head.Left,f); }
388 -
389 -protected:
390 - bool DeleteRoot()
391 - {
392 - NodePath<T*,D> PathNode;
393 - MyStack<NodePath<T*,D>,STACK_SIZE> path; //Use to record a path to the destination node.
394 - path.push_back(NodePath<T*,D>(&head,-1));
395 - TreeNode<T*,D> *TryNode,*ChildNode,*BalanceNode,*SuccNode;
396 - TryNode=head.Left;
397 - char factor;
398 - SuccNode=TryNode->Right; //Find a successor.
399 - factor=1;
400 - if (SuccNode==0)
401 - {
402 - SuccNode=TryNode->Left;
403 - factor=-1;
404 - }
405 - path.push_back(NodePath<T*,D>(TryNode,factor));
406 - while (SuccNode) {
407 - path.push_back(NodePath<T*,D>(SuccNode,-factor));
408 - SuccNode=_FactorLink(SuccNode,-factor);
409 - }
410 - PathNode=path.back();
411 - delete[] TryNode->key; // jichi 9/22/2013: key is supposed to be an array
412 - TryNode->key=PathNode.Node->key; //Replace key and data field with the successor.
413 - PathNode.Node->key = nullptr;
414 - TryNode->data=PathNode.Node->data;
415 - path.pop_back();
416 - _FactorLink(path.back().Node,path.back().factor) = _FactorLink(PathNode.Node,-PathNode.factor);
417 - delete PathNode.Node; //Remove the successor from the tree and release memory.
418 - PathNode=path.back();
419 - for (int i=0;i<path.size();i++)
420 - if (path[i].factor==-1)
421 - path[i].Node->rank--;
422 - for (;;) { //Rebalance the tree along the path back to the root.
423 - if (path.size() == 1) {
424 - _DecreaseHeight();
425 - break;
426 - }
427 -
428 - BalanceNode = PathNode.Node;
429 - if (BalanceNode->factor == 0) { // A balance node, just need to adjust the factor. Don't have to recurse since subtree height not changed.
430 - BalanceNode->factor=-PathNode.factor;
431 - break;
432 - }
433 - if (BalanceNode->factor==PathNode.factor) { // Node get more balance. Subtree height decrease, need to recurse.
434 - BalanceNode->factor=0;
435 - path.pop_back();
436 - PathNode=path.back();
437 - continue;
438 - }
439 - //Node get out of balance. Here raises 3 cases.
440 - ChildNode = _FactorLink(BalanceNode, -PathNode.factor);
441 - if (ChildNode->factor == 0) { // New case different to insert operation.
442 - TryNode = _SingleRotation2( BalanceNode, ChildNode, BalanceNode->factor );
443 - path.pop_back();
444 - PathNode=path.back();
445 - _FactorLink(PathNode.Node, PathNode.factor) = TryNode;
446 - break;
447 - } else {
448 - if (ChildNode->factor == BalanceNode->factor) // Analogous to insert operation case 1.
449 - TryNode = _SingleRotation( BalanceNode, ChildNode, BalanceNode->factor );
450 - else if (ChildNode->factor + BalanceNode->factor == 0) // Analogous to insert operation case 2.
451 - TryNode = _DoubleRotation( BalanceNode, ChildNode, BalanceNode->factor );
452 - }
453 - path.pop_back(); // Recurve back along the path.
454 - PathNode=path.back();
455 - _FactorLink(PathNode.Node, PathNode.factor) = TryNode;
456 - }
457 - return true;
458 - }
459 - template <class Fn>
460 - Fn TraverseTreeNode(TreeNode<T*,D> *Node, Fn &f)
461 - {
462 - if (Node) {
463 - if (Node->Left)
464 - TraverseTreeNode(Node->Left,f);
465 - f(Node);
466 - if (Node->Right)
467 - TraverseTreeNode(Node->Right,f);
468 - }
469 - return f;
470 - }
471 - TreeNode<T*,D> *_SingleRotation(TreeNode<T*,D> *BalanceNode, TreeNode<T*,D> *ModifyNode, char factor)
472 - {
473 - TreeNode<T*,D> *Node = _FactorLink(ModifyNode, -factor);
474 - _FactorLink(BalanceNode, factor) = Node;
475 - _FactorLink(ModifyNode, -factor) = BalanceNode;
476 - if (Node)
477 - Node->Parent = BalanceNode;
478 - ModifyNode->Parent = BalanceNode->Parent;
479 - BalanceNode->Parent = ModifyNode;
480 - BalanceNode->factor = ModifyNode->factor = 0; //After single rotation, set all factor of 3 node to 0.
481 - if (factor == 1)
482 - ModifyNode->rank += BalanceNode->rank;
483 - else
484 - BalanceNode->rank -= ModifyNode->rank;
485 - return ModifyNode;
486 - }
487 - TreeNode<T*,D> *_SingleRotation2(TreeNode<T*,D> *BalanceNode, TreeNode<T*,D> *ModifyNode, char factor)
488 - {
489 - TreeNode<T*,D> *Node = _FactorLink(ModifyNode, -factor);
490 - _FactorLink(BalanceNode, factor) = Node;
491 - _FactorLink(ModifyNode, -factor) = BalanceNode;
492 - if (Node) Node->Parent = BalanceNode;
493 - ModifyNode->Parent = BalanceNode->Parent;
494 - BalanceNode->Parent = ModifyNode;
495 - ModifyNode->factor = -factor;
496 - if (factor == 1)
497 - ModifyNode->rank+=BalanceNode->rank;
498 - else
499 - BalanceNode->rank-=ModifyNode->rank;
500 - return ModifyNode;
501 - }
502 - TreeNode<T*,D> *_DoubleRotation(TreeNode<T*,D> *BalanceNode, TreeNode<T*,D> *ModifyNode, char factor)
503 - {
504 - TreeNode<T*,D> *DownNode = _FactorLink(ModifyNode, -factor);
505 - TreeNode<T*,D> *Node1, *Node2;
506 - Node1 = _FactorLink(DownNode, factor);
507 - Node2 = _FactorLink(DownNode, -factor);
508 - _FactorLink(ModifyNode, -factor) = Node1;
509 - _FactorLink(DownNode, factor) = ModifyNode;
510 - _FactorLink(BalanceNode, factor) = Node2;
511 - _FactorLink(DownNode, -factor) = BalanceNode;
512 - if (Node1)
513 - Node1->Parent = ModifyNode;
514 - if (Node2)
515 - Node2->Parent = BalanceNode;
516 - DownNode->Parent = BalanceNode->Parent;
517 - BalanceNode->Parent = DownNode;
518 - ModifyNode->Parent = DownNode;
519 - //Set factor according to the result.
520 - if (DownNode->factor == factor) {
521 - BalanceNode->factor = -factor;
522 - ModifyNode->factor = 0;
523 - } else if (DownNode->factor == 0)
524 - BalanceNode->factor = ModifyNode->factor = 0;
525 - else {
526 - BalanceNode->factor = 0;
527 - ModifyNode->factor = factor;
528 - }
529 - DownNode->factor = 0;
530 - if (factor==1) {
531 - ModifyNode->rank -= DownNode->rank;
532 - DownNode->rank += BalanceNode->rank;
533 - } else {
534 - DownNode->rank += ModifyNode->rank;
535 - BalanceNode->rank -= DownNode->rank;
536 - }
537 - return DownNode;
538 - }
539 -
540 - TreeNode<T*,D>* &__fastcall _FactorLink(TreeNode<T*,D> *Node, char factor)
541 - //Private helper method to retrieve child according to factor.
542 - //Return right child if factor>0 and left child otherwise.
543 - { return factor>0? Node->Right : Node->Left; }
544 -
545 - void Check()
546 - {
547 - unsigned int k = (unsigned int)head.Right;
548 - unsigned int t = head.Left->height();
549 - if (k != t)
550 - __debugbreak();
551 - }
552 -
553 - void _IncreaseHeight()
554 - {
555 - unsigned int k = (unsigned int)head.Right;
556 - head.Right = (TreeNode<T*,D>*)++k;
557 - }
558 -
559 - void _DecreaseHeight()
560 - {
561 - unsigned int k = (unsigned int)head.Right;
562 - head.Right = (TreeNode<T*,D>*)--k;
563 - }
564 -};
565 -
566 -struct SCMP
567 -{
568 - char operator()(const char *s1,const char *s2)
569 - {
570 - int t = _stricmp(s1, s2);
571 - return t == 0 ? 0 : t > 0 ? 1 :-1;
572 - }
573 -};
574 -
575 -struct SCPY { char *operator()(char *dest, const char *src) { return strcpy(dest, src); } };
576 -struct SLEN { int operator()(const char *str) { return strlen(str); } };
577 -
578 -struct WCMP
579 -{
580 - char operator()(const wchar_t *s1,const wchar_t *s2)
581 - {
582 - int t =_wcsicmp(s1, s2);
583 - return t == 0 ? 0 : t > 0 ? 1 : -1;
584 - }
585 -};
586 -
587 -struct WCPY { wchar_t *operator()(wchar_t *dest, const wchar_t *src) { return wcscpy(dest,src); } };
588 -struct WLEN { int operator()(const wchar_t *str) { return wcslen(str); } };
589 -
590 -// EOF
1 -# hookxp.pro
2 -# 8/9/2013 jichi
3 -# Build vnrhookxp.dll for Windows XP
4 -
5 -CONFIG += noeh # msvcrt on Windows XP does not has exception handler
6 -include(../dllconfig.pri)
7 -include(../sys/sys.pri)
8 -include($$LIBDIR/disasm/disasm.pri)
9 -include($$LIBDIR/memdbg/memdbg.pri)
10 -include($$LIBDIR/ntinspect/ntinspect.pri)
11 -include($$LIBDIR/winseh/winseh_safe.pri)
12 -include($$LIBDIR/winversion/winversion.pri)
13 -
14 -VPATH += ../hook
15 -INCLUDEPATH += ../hook
16 -
17 -# 9/27/2013: disable ITH this game engine, only for debugging purpose
18 -#DEFINES += ITH_DISABLE_ENGINE
19 -
20 -
21 -# jichi 9/22/2013: When ITH is on wine, mutex is needed to protect NtWriteFile
22 -#DEFINES += ITH_WINE
23 -#DEFINES += ITH_SYNC_PIPE
24 -
25 -## Libraries
26 -
27 -LIBS += -lkernel32 -luser32 -lgdi32
28 -
29 -## Sources
30 -
31 -TEMPLATE = lib
32 -TARGET = vnrhookxp
33 -
34 -#CONFIG += staticlib
35 -
36 -HEADERS += \
37 - config.h \
38 - cli.h \
39 - hook.h \
40 - engine/engine.h \
41 - engine/hookdefs.h \
42 - engine/match.h \
43 - engine/pchooks.h \
44 - engine/util.h \
45 - tree/avl.h
46 -
47 -SOURCES += \
48 - main.cc \
49 - rpc/pipe.cc \
50 - hijack/texthook.cc \
51 - engine/engine.cc \
52 - engine/match.cc \
53 - engine/pchooks.cc \
54 - engine/util.cc
55 -
56 -#RC_FILE += vnrhook.rc
57 -#OTHER_FILES += vnrhook.rc
58 -
59 -# EOF
1 -# host.pro
2 -# #CONFIG += eha # 3/1/2014: catchlng all exceptions will break pytexthook on Windows XP
3 -# CONFIG += noeh # Needed by pytexthook ONLY on windows xp orz
4 -# include(../dllconfig.pri)
5 -# include(../sys/sys.pri)
6 -# include($$LIBDIR/winmaker/winmaker.pri)
7 -# include($$LIBDIR/winmutex/winmutex.pri)
8 -
9 -# config.pri
10 -# CONFIG(noeh) { # No Exception handler
11 -# message(CONFIG noeh)
12 -# QMAKE_CXXFLAGS += /GR-
13 -# QMAKE_CXXFLAGS_RTTI_ON -= /GR
14 -# QMAKE_CXXFLAGS_STL_ON -= /EHsc
15 -# QMAKE_CXXFLAGS_EXCEPTIONS_ON -= /EHsc
16 -# CONFIG(dll) {
17 -# QMAKE_LFLAGS += /ENTRY:"DllMain"
18 -# }
19 -# }
20 -
21 -set(vnrhost_src
22 - avl_p.h
23 - config.h
24 - hookman.h
25 - settings.h
26 - srv.h
27 - srv_p.h
28 - textthread.h
29 - textthread_p.h
30 - SettingManager.h
31 - hookman.cc
32 - main.cc
33 - pipe.cc
34 - textthread.cc
35 - ${PROJECT_SOURCE_DIR}/winmaker/winmaker.h
36 - ${PROJECT_SOURCE_DIR}/winmaker/winmaker.cc
37 - ${PROJECT_SOURCE_DIR}/winmutex/winmutex.h
38 - ${common_src}
39 -)
40 -
41 -source_group("common" FILES ${common_src})
42 -
43 -add_library(vnrhost SHARED ${vnrhost_src})
44 -
45 -set_target_properties(vnrhost PROPERTIES LINK_FLAGS /SUBSYSTEM:WINDOWS)
46 -
47 -target_compile_options(vnrhost PRIVATE
48 - /GR-
49 - $<$<CONFIG:Release>:>
50 - $<$<CONFIG:Debug>:>
51 -)
52 -
53 -STRING(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
54 -
55 -target_link_libraries(vnrhost
56 - vnrsys
57 - ${WDK_HOME}/lib/wxp/i386/ntdll.lib
58 -)
59 -
60 -target_compile_definitions(vnrhost PRIVATE
61 -)
62 -
63 -install(TARGETS vnrhost RUNTIME
64 - DESTINATION .
65 - CONFIGURATIONS Release
66 -)
1 -/* Copyright (C) 2010-2012 kaosu (qiupf2000@gmail.com)
2 - * This file is part of the Interactive Text Hooker.
3 -
4 - * Interactive Text Hooker is free software: you can redistribute it and/or
5 - * modify it under the terms of the GNU General Public License as published
6 - * by the Free Software Foundation, either version 3 of the License, or
7 - * (at your option) any later version.
8 -
9 - * This program is distributed in the hope that it will be useful,
10 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 - * GNU General Public License for more details.
13 -
14 - * You should have received a copy of the GNU General Public License
15 - * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 - */
17 -
18 -#pragma once
19 -#include "config.h"
20 -#include <intrin.h>
21 -#define SETTING_SPLIT_TIME 0
22 -#define SETTING_CYCLIC_REMOVE 1
23 -#define SETTING_REPEAT_COUNT 2
24 -#define SETTING_CLIPFLAG 3
25 -#define SETTING_MAX_INDEX 4
26 -class IHFSERVICE SettingManager
27 -{
28 -public:
29 - SettingManager() {memset(setting_int,0,sizeof(setting_int));}
30 - ~SettingManager(){}
31 - unsigned int SetValue(unsigned int index, unsigned int value)
32 - {
33 - if (index < SETTING_MAX_INDEX)
34 - return (unsigned int)_InterlockedExchange((long*)setting_int+index,(long)value);
35 - else return 0;
36 - }
37 - unsigned int GetValue(unsigned int index)
38 - {
39 - if (index < SETTING_MAX_INDEX)
40 - return setting_int[index];
41 - else return 0;
42 - }
43 -private:
44 - unsigned int setting_int[SETTING_MAX_INDEX];
45 -
46 -};
...\ No newline at end of file ...\ No newline at end of file
1 -#pragma once
2 -// avl_p.h
3 -// 8/23/2013 jichi
4 -// Branch: ITH/AVL.h, rev 133
5 -
6 -#include "config.h"
7 -
8 -enum { STACK_SIZE = 32 };
9 -
10 -//#ifndef ITH_STACK
11 -//#define ITH_STACK
12 -
13 -template<class T, int stack_size>
14 -class MyStack
15 -{
16 - int index;
17 - T s[stack_size];
18 -
19 -public:
20 - MyStack(): index(0)
21 - { ITH_MEMSET_HEAP(s, 0, sizeof(s)); } // jichi 9/21/2013: assume T is atomic type
22 -
23 - T &back() { return s[index-1]; }
24 - int size() { return index; }
25 -
26 - void push_back(const T &e)
27 - {
28 - if (index < stack_size)
29 - s[index++]=e;
30 - }
31 -
32 - void pop_back() { index--; }
33 -
34 - T &operator[](int i) { return s[i]; }
35 -};
36 -//#endif // ITH_STACK
37 -
38 -// jichi 9/22/2013: T must be a pointer type which can be deleted
39 -template <class T, class D>
40 -struct IHFSERVICE TreeNode
41 -{
42 - //typedef TreeNode<T, D> Self;
43 - TreeNode() :
44 - Left(nullptr), Right(nullptr), Parent(nullptr)
45 - , rank(1)
46 - , factor('\0'), reserve('\0')
47 - //, key()
48 - //, data()
49 - {
50 - ITH_MEMSET_HEAP(&key, 0, sizeof(key)); // jcihi 9/26/2013: zero memory
51 - ITH_MEMSET_HEAP(&data, 0, sizeof(data)); // jcihi 9/26/2013: zero memory
52 - }
53 -
54 - TreeNode(const T &k, const D &d) :
55 - Left(nullptr), Right(nullptr), Parent(nullptr)
56 - , rank(1)
57 - , factor('\0'), reserve('\0') // jichi 9/21/2013: zero reserve
58 - , key(k)
59 - , data(d)
60 - {}
61 -
62 - TreeNode *Successor()
63 - {
64 - TreeNode *Node,
65 - *ParentNode;
66 - Node = Right;
67 - if (!Node) {
68 - Node = this;
69 - for (;;) {
70 - ParentNode = Node->Parent;
71 - if (!ParentNode)
72 - return nullptr;
73 - if (ParentNode->Left == Node)
74 - break;
75 - Node = ParentNode;
76 - }
77 - return ParentNode;
78 - }
79 - else
80 - while (Node->Left)
81 - Node = Node->Left;
82 - return Node;
83 - }
84 - TreeNode *Predecessor()
85 - {
86 - TreeNode *Node,
87 - *ParentNode;
88 - Node = Left;
89 - if (!Node) {
90 - Node = this;
91 - for(;;) {
92 - ParentNode = Node->Parent;
93 - if (!ParentNode)
94 - return nullptr;
95 - if (ParentNode->Right == Node)
96 - break;
97 - Node = ParentNode;
98 - }
99 - return ParentNode;
100 - }
101 - else
102 - while (Node->Right)
103 - Node = Node->Right;
104 - return Node;
105 - }
106 - int height()
107 - {
108 - if (!this) // jichi 9/26/2013: what?!
109 - return 0;
110 - int l = Left->height(),
111 - r = Right->height(),
112 - f = factor;
113 - if (l - r + f != 0)
114 - __debugbreak();
115 - f = l > r ? l : r;
116 - return f + 1;
117 - }
118 - TreeNode *Left,
119 - *Right,
120 - *Parent;
121 - unsigned short rank;
122 - char factor,
123 - reserve;
124 - T key;
125 - D data;
126 -};
127 -
128 -template<class T,class D>
129 -struct NodePath
130 -{
131 - NodePath() { memset(this, 0, sizeof(NodePath)); } // jichi 11/30/2013: This is the original code in ITH
132 - NodePath(TreeNode<T,D> *n, int f): Node(n), fact(f) {}
133 - TreeNode<T,D> *Node;
134 - union { char factor; int fact; };
135 -};
136 -
137 -template <class T, class D, class fComp, class fCopy, class fLength>
138 -class IHFSERVICE AVLTree
139 -{
140 -protected:
141 - TreeNode<T*, D> head;
142 - fComp fCmp;
143 - fCopy fCpy;
144 - fLength fLen;
145 -
146 -public:
147 - // - Construction -
148 - AVLTree() {}
149 -
150 - virtual ~AVLTree() { DeleteAll(); }
151 -
152 - // - Properties -
153 -
154 - TreeNode<T*, D> *TreeRoot() const { return head.Left; }
155 -
156 - // - Actions -
157 -
158 - void DeleteAll()
159 - {
160 - while (head.Left)
161 - DeleteRoot();
162 - }
163 -
164 - TreeNode<T*, D> *Insert(const T *key, const D &data)
165 - {
166 - if (head.Left) {
167 - MyStack<TreeNode<T*, D> *,STACK_SIZE> path;
168 - TreeNode<T*,D> *DownNode, *ParentNode, *BalanceNode, *TryNode, *NewNode; //P,T,S,Q
169 - ParentNode = &head;
170 - path.push_back(ParentNode);
171 - char factor,f;
172 - BalanceNode = DownNode = head.Left;
173 - for (;;) { //The first part of AVL tree insert. Just do as binary tree insert routine and record some nodes.
174 - factor = fCmp(key,DownNode->key);
175 - if (factor == 0)
176 - return DownNode; //Duplicate key. Return and do nothing.
177 - TryNode = _FactorLink(DownNode, factor);
178 - if (factor == -1)
179 - path.push_back(DownNode);
180 - if (TryNode) { //DownNode has a child.
181 - if (TryNode->factor != 0) { //Keep track of unbalance node and its parent.
182 - ParentNode = DownNode;
183 - BalanceNode = TryNode;
184 - }
185 - DownNode = TryNode;
186 - }
187 - else
188 - break; //Finished binary tree search;
189 - }
190 - while (path.size()) {
191 - path.back()->rank++;
192 - path.pop_back();
193 - }
194 - size_t sz = fLen(key) + 1;
195 - T *new_key = new T[sz];
196 - ITH_MEMSET_HEAP(new_key, 0, sz * sizeof(T)); // jichi 9/26/2013: Zero memory
197 - fCpy(new_key, key);
198 - TryNode = new TreeNode<T*, D>(new_key, data);
199 - _FactorLink(DownNode, factor) = TryNode;
200 - TryNode->Parent = DownNode;
201 - NewNode = TryNode;
202 - //Finished binary tree insert. Next to do is to modify balance factors between
203 - //BalanceNode and the new node.
204 - TreeNode<T*, D> *ModifyNode;
205 - factor = fCmp(key, BalanceNode->key);
206 - //factor=key<BalanceNode->key ? factor=-1:1; //Determine the balance factor at BalanceNode.
207 - ModifyNode = DownNode = _FactorLink(BalanceNode,factor);
208 - //ModifyNode will be the 1st child.
209 - //DownNode will travel from here to the recent inserted node (TryNode).
210 - while (DownNode != TryNode) { //Check if we reach the bottom.
211 - f = fCmp(key,DownNode->key);
212 - //f=_FactorCompare(key,DownNode->key);
213 - DownNode->factor = f;
214 - DownNode = _FactorLink(DownNode, f);//Modify balance factor and travels down.
215 - }
216 - //Finshed modifying balance factor.
217 - //Next to do is check the tree if it's unbalance and recover balance.
218 - if (BalanceNode->factor == 0) { //Tree has grown higher.
219 - BalanceNode->factor = factor;
220 - _IncreaseHeight(); //Modify balance factor and increase the height.
221 - return NewNode;
222 - }
223 - if (BalanceNode->factor + factor == 0) { //Tree has gotten more balanced.
224 - BalanceNode->factor = 0; //Set balance factor to 0.
225 - return NewNode;
226 - }
227 - //Tree has gotten out of balance.
228 - if (ModifyNode->factor == factor) //A node and its child has same factor. Single rotation.
229 - DownNode = _SingleRotation(BalanceNode, ModifyNode, factor);
230 - else //A node and its child has converse factor. Double rotation.
231 - DownNode = _DoubleRotation(BalanceNode, ModifyNode, factor);
232 - //Finished the balancing work. Set child field to the root of the new child tree.
233 - if (BalanceNode == ParentNode->Left)
234 - ParentNode->Left = DownNode;
235 - else
236 - ParentNode->Right = DownNode;
237 - return NewNode;
238 - }
239 - else { //root null?
240 - size_t sz = fLen(key) + 1;
241 - T *new_key = new T[sz];
242 - ITH_MEMSET_HEAP(new_key, 0, sz * sizeof(T)); // jichi 9/26/2013: Zero memory
243 - fCpy(new_key, key);
244 - head.Left = new TreeNode<T *, D>(new_key, data);
245 - head.rank++;
246 - _IncreaseHeight();
247 - return head.Left;
248 - }
249 - }
250 - bool Delete(T *key)
251 - {
252 - NodePath<T*,D> PathNode;
253 - MyStack<NodePath<T*,D>,STACK_SIZE> path; //Use to record a path to the destination node.
254 - path.push_back(NodePath<T*,D>(&head,-1));
255 - TreeNode<T*,D> *TryNode,*ChildNode,*BalanceNode,*SuccNode;
256 - TryNode=head.Left;
257 - char factor;
258 - for (;;) { //Search for the
259 - if (TryNode == 0)
260 - return false; //Not found.
261 - factor = fCmp(key, TryNode->key);
262 - if (factor == 0)
263 - break; //Key found, continue to delete.
264 - //factor = _FactorCompare( key, TryNode->key );
265 - path.push_back(NodePath<T*,D>(TryNode,factor));
266 - TryNode = _FactorLink(TryNode,factor); //Move to left.
267 - }
268 - SuccNode = TryNode->Right; //Find a successor.
269 - factor = 1;
270 - if (SuccNode == 0) {
271 - SuccNode = TryNode->Left;
272 - factor = -1;
273 - }
274 - path.push_back(NodePath<T*,D>(TryNode,factor));
275 - while (SuccNode) {
276 - path.push_back(NodePath<T*,D>(SuccNode, -factor));
277 - SuccNode = _FactorLink(SuccNode,-factor);
278 - }
279 - PathNode = path.back();
280 - delete[] TryNode->key; // jichi 9/22/2013: key is supposed to be an array
281 - TryNode->key = PathNode.Node->key; //Replace key and data field with the successor or predecessor.
282 - PathNode.Node->key = nullptr;
283 - TryNode->data = PathNode.Node->data;
284 - path.pop_back();
285 - _FactorLink(path.back().Node,path.back().factor) = _FactorLink(PathNode.Node,-PathNode.factor);
286 - delete PathNode.Node; //Remove the successor from the tree and release memory.
287 - PathNode = path.back();
288 - for (int i=0; i<path.size(); i++)
289 - if (path[i].factor==-1)
290 - path[i].Node->rank--;
291 - for (;;) { //Rebalance the tree along the path back to the root.
292 - if (path.size()==1) {
293 - _DecreaseHeight();
294 - break;
295 - }
296 - BalanceNode = PathNode.Node;
297 - if (BalanceNode->factor == 0) { // A balance node, just need to adjust the factor. Don't have to recurve since subtree height stays.
298 - BalanceNode->factor=-PathNode.factor;
299 - break;
300 - }
301 - if (BalanceNode->factor == PathNode.factor) { // Node get more balance. Subtree height decrease, need to recurve.
302 - BalanceNode->factor = 0;
303 - path.pop_back();
304 - PathNode = path.back();
305 - continue;
306 - }
307 - //Node get out of balance. Here raises 3 cases.
308 - ChildNode = _FactorLink(BalanceNode, -PathNode.factor);
309 - if (ChildNode->factor == 0) { // New case different to insert operation.
310 - TryNode = _SingleRotation2( BalanceNode, ChildNode, BalanceNode->factor );
311 - path.pop_back();
312 - PathNode = path.back();
313 - _FactorLink(PathNode.Node, PathNode.factor) = TryNode;
314 - break;
315 - }
316 - else {
317 - if (ChildNode->factor == BalanceNode->factor) // Analogous to insert operation case 1.
318 - TryNode = _SingleRotation( BalanceNode, ChildNode, BalanceNode->factor );
319 - else if (ChildNode->factor + BalanceNode->factor == 0) // Analogous to insert operation case 2.
320 - TryNode = _DoubleRotation( BalanceNode, ChildNode, BalanceNode->factor );
321 - }
322 - path.pop_back(); //Recurse back along the path.
323 - PathNode = path.back();
324 - _FactorLink(PathNode.Node, PathNode.factor) = TryNode;
325 - }
326 - return true;
327 - }
328 -
329 - D &operator [](T *key)
330 - { return (Insert(key,D())->data); }
331 -
332 - TreeNode<T*,D> *Search(const T *key)
333 - {
334 - TreeNode<T*,D> *Find=head.Left;
335 - char k;
336 - while (Find != 0) {//&&Find->key!=key)
337 - k = fCmp(key, Find->key);
338 - if (k == 0) break;
339 - Find = _FactorLink(Find, k);
340 - }
341 - return Find;
342 - }
343 -
344 - TreeNode<T*,D> *SearchIndex(unsigned int rank)
345 - {
346 - unsigned int r = head.rank;
347 - if (rank == -1)
348 - return 0;
349 - if (++rank>=r)
350 - return 0;
351 - TreeNode<T*,D> *n=&head;
352 - while (r!=rank) {
353 - if (rank>r) {
354 - n=n->Right;
355 - rank-=r;
356 - r=n->rank;
357 - } else {
358 - n=n->Left;
359 - r=n->rank;
360 - }
361 - }
362 - return n;
363 - }
364 -
365 - TreeNode<T*,D> *Begin()
366 - {
367 - TreeNode<T*,D> *Node = head.Left;
368 - if (Node)
369 - while (Node->Left) Node = Node->Left;
370 - return Node;
371 - }
372 -
373 - TreeNode<T*,D> *End()
374 - {
375 - TreeNode<T*,D> *Node=head.Left;
376 - if (Node)
377 - while (Node->Right) Node = Node->Right;
378 - return Node;
379 - }
380 - unsigned int Count() const { return head.rank - 1; }
381 -
382 - template <class Fn>
383 - Fn TraverseTree(Fn &f)
384 - { return TraverseTreeNode(head.Left,f); }
385 -
386 -protected:
387 - bool DeleteRoot()
388 - {
389 - NodePath<T*,D> PathNode;
390 - MyStack<NodePath<T*,D>,STACK_SIZE> path; //Use to record a path to the destination node.
391 - path.push_back(NodePath<T*,D>(&head,-1));
392 - TreeNode<T*,D> *TryNode,*ChildNode,*BalanceNode,*SuccNode;
393 - TryNode=head.Left;
394 - char factor;
395 - SuccNode=TryNode->Right; //Find a successor.
396 - factor=1;
397 - if (SuccNode==0)
398 - {
399 - SuccNode=TryNode->Left;
400 - factor=-1;
401 - }
402 - path.push_back(NodePath<T*,D>(TryNode,factor));
403 - while (SuccNode) {
404 - path.push_back(NodePath<T*,D>(SuccNode,-factor));
405 - SuccNode=_FactorLink(SuccNode,-factor);
406 - }
407 - PathNode=path.back();
408 - delete[] TryNode->key; // jichi 9/22/2013: key is supposed to be an array
409 - TryNode->key=PathNode.Node->key; //Replace key and data field with the successor.
410 - PathNode.Node->key = nullptr;
411 - TryNode->data=PathNode.Node->data;
412 - path.pop_back();
413 - _FactorLink(path.back().Node,path.back().factor) = _FactorLink(PathNode.Node,-PathNode.factor);
414 - delete PathNode.Node; //Remove the successor from the tree and release memory.
415 - PathNode=path.back();
416 - for (int i=0;i<path.size();i++)
417 - if (path[i].factor==-1)
418 - path[i].Node->rank--;
419 - for (;;) { //Rebalance the tree along the path back to the root.
420 - if (path.size() == 1) {
421 - _DecreaseHeight();
422 - break;
423 - }
424 -
425 - BalanceNode = PathNode.Node;
426 - if (BalanceNode->factor == 0) { // A balance node, just need to adjust the factor. Don't have to recurse since subtree height not changed.
427 - BalanceNode->factor=-PathNode.factor;
428 - break;
429 - }
430 - if (BalanceNode->factor==PathNode.factor) { // Node get more balance. Subtree height decrease, need to recurse.
431 - BalanceNode->factor=0;
432 - path.pop_back();
433 - PathNode=path.back();
434 - continue;
435 - }
436 - //Node get out of balance. Here raises 3 cases.
437 - ChildNode = _FactorLink(BalanceNode, -PathNode.factor);
438 - if (ChildNode->factor == 0) { // New case different to insert operation.
439 - TryNode = _SingleRotation2( BalanceNode, ChildNode, BalanceNode->factor );
440 - path.pop_back();
441 - PathNode=path.back();
442 - _FactorLink(PathNode.Node, PathNode.factor) = TryNode;
443 - break;
444 - } else {
445 - if (ChildNode->factor == BalanceNode->factor) // Analogous to insert operation case 1.
446 - TryNode = _SingleRotation( BalanceNode, ChildNode, BalanceNode->factor );
447 - else if (ChildNode->factor + BalanceNode->factor == 0) // Analogous to insert operation case 2.
448 - TryNode = _DoubleRotation( BalanceNode, ChildNode, BalanceNode->factor );
449 - }
450 - path.pop_back(); // Recurve back along the path.
451 - PathNode=path.back();
452 - _FactorLink(PathNode.Node, PathNode.factor) = TryNode;
453 - }
454 - return true;
455 - }
456 - template <class Fn>
457 - Fn TraverseTreeNode(TreeNode<T*,D> *Node, Fn &f)
458 - {
459 - if (Node) {
460 - if (Node->Left)
461 - TraverseTreeNode(Node->Left,f);
462 - f(Node);
463 - if (Node->Right)
464 - TraverseTreeNode(Node->Right,f);
465 - }
466 - return f;
467 - }
468 - TreeNode<T*,D> *_SingleRotation(TreeNode<T*,D> *BalanceNode, TreeNode<T*,D> *ModifyNode, char factor)
469 - {
470 - TreeNode<T*,D> *Node = _FactorLink(ModifyNode, -factor);
471 - _FactorLink(BalanceNode, factor) = Node;
472 - _FactorLink(ModifyNode, -factor) = BalanceNode;
473 - if (Node)
474 - Node->Parent = BalanceNode;
475 - ModifyNode->Parent = BalanceNode->Parent;
476 - BalanceNode->Parent = ModifyNode;
477 - BalanceNode->factor = ModifyNode->factor = 0; //After single rotation, set all factor of 3 node to 0.
478 - if (factor == 1)
479 - ModifyNode->rank += BalanceNode->rank;
480 - else
481 - BalanceNode->rank -= ModifyNode->rank;
482 - return ModifyNode;
483 - }
484 - TreeNode<T*,D> *_SingleRotation2(TreeNode<T*,D> *BalanceNode, TreeNode<T*,D> *ModifyNode, char factor)
485 - {
486 - TreeNode<T*,D> *Node = _FactorLink(ModifyNode, -factor);
487 - _FactorLink(BalanceNode, factor) = Node;
488 - _FactorLink(ModifyNode, -factor) = BalanceNode;
489 - if (Node) Node->Parent = BalanceNode;
490 - ModifyNode->Parent = BalanceNode->Parent;
491 - BalanceNode->Parent = ModifyNode;
492 - ModifyNode->factor = -factor;
493 - if (factor == 1)
494 - ModifyNode->rank+=BalanceNode->rank;
495 - else
496 - BalanceNode->rank-=ModifyNode->rank;
497 - return ModifyNode;
498 - }
499 - TreeNode<T*,D> *_DoubleRotation(TreeNode<T*,D> *BalanceNode, TreeNode<T*,D> *ModifyNode, char factor)
500 - {
501 - TreeNode<T*,D> *DownNode = _FactorLink(ModifyNode, -factor);
502 - TreeNode<T*,D> *Node1, *Node2;
503 - Node1 = _FactorLink(DownNode, factor);
504 - Node2 = _FactorLink(DownNode, -factor);
505 - _FactorLink(ModifyNode, -factor) = Node1;
506 - _FactorLink(DownNode, factor) = ModifyNode;
507 - _FactorLink(BalanceNode, factor) = Node2;
508 - _FactorLink(DownNode, -factor) = BalanceNode;
509 - if (Node1)
510 - Node1->Parent = ModifyNode;
511 - if (Node2)
512 - Node2->Parent = BalanceNode;
513 - DownNode->Parent = BalanceNode->Parent;
514 - BalanceNode->Parent = DownNode;
515 - ModifyNode->Parent = DownNode;
516 - //Set factor according to the result.
517 - if (DownNode->factor == factor) {
518 - BalanceNode->factor = -factor;
519 - ModifyNode->factor = 0;
520 - } else if (DownNode->factor == 0)
521 - BalanceNode->factor = ModifyNode->factor = 0;
522 - else {
523 - BalanceNode->factor = 0;
524 - ModifyNode->factor = factor;
525 - }
526 - DownNode->factor = 0;
527 - if (factor==1) {
528 - ModifyNode->rank -= DownNode->rank;
529 - DownNode->rank += BalanceNode->rank;
530 - } else {
531 - DownNode->rank += ModifyNode->rank;
532 - BalanceNode->rank -= DownNode->rank;
533 - }
534 - return DownNode;
535 - }
536 -
537 - TreeNode<T*,D>* &__fastcall _FactorLink(TreeNode<T*,D> *Node, char factor)
538 - //Private helper method to retrieve child according to factor.
539 - //Return right child if factor>0 and left child otherwise.
540 - { return factor>0? Node->Right : Node->Left; }
541 -
542 - void Check()
543 - {
544 - unsigned int k = (unsigned int)head.Right;
545 - unsigned int t = head.Left->height();
546 - if (k != t)
547 - __debugbreak();
548 - }
549 -
550 - void _IncreaseHeight()
551 - {
552 - unsigned int k = (unsigned int)head.Right;
553 - head.Right = (TreeNode<T*,D>*)++k;
554 - }
555 -
556 - void _DecreaseHeight()
557 - {
558 - unsigned int k = (unsigned int)head.Right;
559 - head.Right = (TreeNode<T*,D>*)--k;
560 - }
561 -};
562 -
563 -struct SCMP
564 -{
565 - char operator()(const char *s1,const char *s2)
566 - {
567 - int t = _stricmp(s1, s2);
568 - return t == 0 ? 0 : t > 0 ? 1 :-1;
569 - }
570 -};
571 -
572 -struct SCPY { char *operator()(char *dest, const char *src) { return strcpy(dest, src); } };
573 -struct SLEN { int operator()(const char *str) { return strlen(str); } };
574 -
575 -struct WCMP
576 -{
577 - char operator()(const wchar_t *s1,const wchar_t *s2)
578 - {
579 - int t =_wcsicmp(s1, s2);
580 - return t == 0 ? 0 : t > 0 ? 1 : -1;
581 - }
582 -};
583 -
584 -struct WCPY { wchar_t *operator()(wchar_t *dest, const wchar_t *src) { return wcscpy(dest,src); } };
585 -struct WLEN { int operator()(const wchar_t *str) { return wcslen(str); } };
586 -
587 -// EOF
1 -#pragma once
2 -
3 -// config.h
4 -// 8/23/2013 jichi
5 -// The first header file that are included by all source files.
6 -
7 -#define IHF // for dll import
8 -#include "ith/dllconfig.h"
9 -#define IHFAPI __stdcall
10 -#ifdef IHF
11 -# define IHFSERVICE __declspec(dllexport)
12 -#else
13 -# define IHFSERVICE __declspec(dllimport)
14 -#endif
15 -
16 -// EOF
1 -// hookman.cc
2 -// 8/24/2013 jichi
3 -// Branch IHF/HookManager.cpp, rev 133
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:4146) // C4146: unary minus operator applied to unsigned type
9 -#endif // _MSC_VER
10 -
11 -#include "hookman.h"
12 -#include "ith/common/const.h"
13 -#include "ith/common/defs.h"
14 -#include "ith/common/types.h"
15 -//#include "ith/common/growl.h"
16 -#include "ith/sys/sys.h"
17 -//#include <emmintrin.h>
18 -
19 -namespace { // unnamed
20 -//enum { MAX_ENTRY = 0x40 };
21 -
22 -#define HM_LOCK win_mutex_lock<HookManager::mutex_type> d_locker(hmcs) // Synchronized scope for accessing private data
23 -// jichi 9/23/2013: wine deficenciy on mapping sections
24 -// Whe set to false, do not map sections.
25 -//bool ith_has_section = true;
26 -
27 -// jichi 9/28/2013: Remove ConsoleOutput from available hooks
28 -//LPWSTR HookNameInitTable[]={ L"ConsoleOutput" , HOOK_FUN_NAME_LIST };
29 -//LPCWSTR HookNameInitTable[] = {HOOK_FUN_NAME_LIST};
30 -//LPVOID DefaultHookAddr[HOOK_FUN_COUNT];
31 -
32 -//BYTE null_buffer[4]={0,0,0,0};
33 -//BYTE static_small_buffer[0x100];
34 -//DWORD zeros[4]={0,0,0,0};
35 -//WCHAR user_entry[0x40];
36 -
37 -bool GetProcessPath(HANDLE hProc, __out LPWSTR path)
38 -{
39 - PROCESS_BASIC_INFORMATION info;
40 - LDR_DATA_TABLE_ENTRY entry;
41 - PEB_LDR_DATA ldr;
42 - PEB peb;
43 - if (NT_SUCCESS(NtQueryInformationProcess(hProc, ProcessBasicInformation, &info, sizeof(info), 0)))
44 - if (info.PebBaseAddress)
45 - if (NT_SUCCESS(NtReadVirtualMemory(hProc, info.PebBaseAddress, &peb,sizeof(peb), 0)))
46 - if (NT_SUCCESS(NtReadVirtualMemory(hProc, peb.Ldr, &ldr, sizeof(ldr), 0)))
47 - if (NT_SUCCESS(NtReadVirtualMemory(hProc, (LPVOID)ldr.InLoadOrderModuleList.Flink,
48 - &entry, sizeof(LDR_DATA_TABLE_ENTRY), 0)))
49 - if (NT_SUCCESS(NtReadVirtualMemory(hProc, entry.FullDllName.Buffer,
50 - path, MAX_PATH * 2, 0)))
51 - return true;
52 - path = L"";
53 - return false;
54 -}
55 -
56 -bool GetProcessPath(DWORD pid, __out LPWSTR path)
57 -{
58 - CLIENT_ID id;
59 - OBJECT_ATTRIBUTES oa = {};
60 - HANDLE hProc;
61 - id.UniqueProcess = pid;
62 - id.UniqueThread = 0;
63 - oa.uLength = sizeof(oa);
64 - if (NT_SUCCESS(NtOpenProcess(&hProc , PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, &oa, &id))) {
65 - bool flag = GetProcessPath(hProc, path);
66 - NtClose(hProc);
67 - return flag;
68 - }
69 - path = L"";
70 - return false;
71 -}
72 -
73 -} // unnamed namespace
74 -
75 -HookManager *man; // jichi 9/22/2013: initialized in main
76 -//BitMap* pid_map;
77 -DWORD clipboard_flag,
78 - split_time,
79 - repeat_count,
80 - global_filter,
81 - cyclic_remove;
82 -
83 -DWORD GetHookName(LPWSTR str, DWORD pid, DWORD hook_addr, DWORD max)
84 -{
85 - if (!pid)
86 - return 0;
87 -
88 - DWORD len = 0;
89 - max--; //for '\0' magic marker.
90 -
91 - //if (pid == 0) {
92 - // len = wcslen(HookNameInitTable[0]);
93 - // if (len >= max)
94 - // len = max;
95 - // memcpy(str, HookNameInitTable[0], len << 1);
96 - // str[len] = 0;
97 - // return len;
98 - //}
99 -
100 - //::man->LockProcessHookman(pid);
101 - ProcessRecord *pr = ::man->GetProcessRecord(pid);
102 - if (!pr)
103 - return 0;
104 - NtWaitForSingleObject(pr->hookman_mutex, 0, 0);
105 - Hook *hks = (Hook *)pr->hookman_map;
106 - for (int i = 0; i < MAX_HOOK; i++)
107 - if (hks[i].Address() == hook_addr) {
108 - len = hks[i].NameLength();
109 - if (len >= max)
110 - len = max;
111 - NtReadVirtualMemory(pr->process_handle, hks[i].Name(), str, len << 1, &len);
112 - if (str[len - 1] == 0)
113 - len--;
114 - else
115 - str[len] = 0;
116 - break;
117 - }
118 -
119 - // jichi 9/27/2013: The hook man should be consistent with the one defined in vnrcli
120 - //Hook *h = (Hook *)hks;
121 - //for (int i = 0; i < MAX_HOOK; i++)
122 - // if (!h[i].hook_name)
123 - // break;
124 - // else {
125 - // const Hook &hi = h[i];
126 - // wchar_t buffer[1000];
127 - // DWORD len = hi.NameLength();
128 - // NtReadVirtualMemory(pr->process_handle, hi.hook_name, buffer, len << 1, &len);
129 - // buffer[len] = 0;
130 - // ITH_MSG(buffer);
131 - // }
132 -
133 - NtReleaseMutant(pr->hookman_mutex, 0);
134 - //::man->UnlockProcessHookman(pid);
135 - return len;
136 -}
137 -
138 -int GetHookNameByIndex(LPWSTR str, DWORD pid, DWORD index)
139 -{
140 - if (!pid)
141 - return 0;
142 -
143 - //if (pid == 0) {
144 - // wcscpy(str, HookNameInitTable[0]);
145 - // return wcslen(HookNameInitTable[0]);
146 - //}
147 - DWORD len = 0;
148 - //::man->LockProcessHookman(pid);
149 - ProcessRecord *pr = ::man->GetProcessRecord(pid);
150 - if (!pr)
151 - return 0;
152 - //NtWaitForSingleObject(pr->hookman_mutex,0,0); //already locked
153 - Hook *hks = (Hook *)pr->hookman_map;
154 - if (hks[index].Address()) {
155 - NtReadVirtualMemory(pr->process_handle, hks[index].Name(), str, hks[index].NameLength() << 1, &len);
156 - len = hks[index].NameLength();
157 - }
158 - //NtReleaseMutant(pr->hookman_mutex,0);
159 - return len;
160 -}
161 -
162 -//int GetHookString(LPWSTR str, DWORD pid, DWORD hook_addr, DWORD status)
163 -//{
164 -// LPWSTR begin=str;
165 -// str+=swprintf(str,L"%4d:0x%08X:",pid,hook_addr);
166 -// str+=GetHookName(str,pid,hook_addr);
167 -// return str-begin;
168 -//}
169 -
170 -
171 -void ThreadTable::SetThread(DWORD num, TextThread *ptr)
172 -{
173 - int number = num;
174 - if (number >= size) {
175 - while (number >= size)
176 - size <<= 1;
177 - TextThread **temp;
178 - //if (size < 0x10000) {
179 - temp = new TextThread*[size];
180 - if (size > used)
181 - ITH_MEMSET_HEAP(temp, 0, (size - used) * sizeof(TextThread *)); // jichi 9/21/2013: zero memory
182 - memcpy(temp, storage, used * sizeof(TextThread *));
183 - //}
184 - delete[] storage;
185 - storage = temp;
186 - }
187 - storage[number] = ptr;
188 - if (ptr == nullptr) {
189 - if (number == used - 1)
190 - while (storage[used - 1] == 0)
191 - used--;
192 - } else if (number >= used)
193 - used = number + 1;
194 -}
195 -
196 -TextThread *ThreadTable::FindThread(DWORD number)
197 -{ return number <= (DWORD)used ? storage[number] : nullptr; }
198 -
199 -static const char sse_table_eq[0x100]={
200 - -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, //0, compare 1
201 - -1,-1,1,1, -1,-1,1,1, -1,-1,1,1, -1,-1,1,1, //1, compare 2
202 - -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, //0, compare 1
203 - -1,-1,-1,-1, 1,1,1,1, -1,-1,-1,-1, 1,1,1,1, //3, compare 3
204 - -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, //0, compare 1
205 - -1,-1,1,1, -1,-1,1,1, -1,-1,1,1, -1,-1,1,1, //1, compare 2
206 - -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, //0, compare 1
207 - -1,-1,-1,-1, -1,-1,-1,-1, 1,1,1,1, 1,1,1,1, //7, compare 4
208 - -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, //0, compare 1
209 - -1,-1,1,1, -1,-1,1,1, -1,-1,1,1, -1,-1,1,1, //1, compare 2
210 - -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, //0, compare 1
211 - -1,-1,-1,-1, 1,1,1,1, -1,-1,-1,-1, 1,1,1,1, //3, compare 3
212 - -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, //0, compare 1
213 - -1,-1,1,1, -1,-1,1,1, -1,-1,1,1, -1,-1,1,1, //1, compare 2
214 - -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, -1,1,-1,1, //0, compare 1
215 - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 //f, equal
216 -};
217 -char original_cmp(const ThreadParameter *t1, const ThreadParameter *t2)
218 -{
219 - //Q_ASSERT(t1 && t2);
220 - int t = t1->pid - t2->pid;
221 - if (t == 0) {
222 - t = t1->hook - t2->hook;
223 - if (t == 0) {
224 - t = t1->retn - t2->retn;
225 - if (t == 0) {
226 - t = t1->spl-t2->spl;
227 - if (t == 0) return 0;
228 - return t1->spl > t2->spl ? 1 : -1;
229 - }
230 - else return t1->retn > t2->retn ? 1 : -1;
231 - }
232 - else return t1->hook > t2->hook ? 1: -1;
233 - }
234 - else return t1->pid > t2->pid ? 1 : -1;
235 - //return t>0?1:-1;
236 -}
237 -char TCmp::operator()(const ThreadParameter* t1, const ThreadParameter* t2)
238 - //SSE speed up. Compare four integers in const time without branching.
239 - //The AVL tree branching operation needs 2 bit of information.
240 - //One bit for equality and one bit for "less than" or "greater than".
241 -
242 -{
243 - union{__m128 m0;__m128i i0;};
244 - union{__m128 m1;__m128i i1;};
245 - union{__m128 m2;__m128i i2;};
246 - int k0,k1;
247 - i1 = _mm_loadu_si128((const __m128i*)t1);
248 - i2 = _mm_loadu_si128((const __m128i*)t2);
249 - i0 = _mm_cmpgt_epi32(i1,i2);
250 - k0 = _mm_movemask_ps(m0);
251 - i1 = _mm_cmpeq_epi32(i1,i2);
252 - k1 = _mm_movemask_ps(m1);
253 - return sse_table_eq[k1*16+k0];
254 -}
255 -void TCpy::operator()(ThreadParameter* t1, const ThreadParameter* t2)
256 -{ memcpy(t1,t2,sizeof(ThreadParameter)); }
257 -
258 -int TLen::operator()(const ThreadParameter* t) { return 0; }
259 -
260 -#define NAMED_PIPE_DISCONNECT 1
261 -//Class member of HookManger
262 -HookManager::HookManager() :
263 - // jichi 9/21/2013: Zero memory
264 - //CRITICAL_SECTION hmcs;
265 - current(nullptr)
266 - , console(nullptr)
267 - , wconsole(nullptr)
268 - , create(nullptr)
269 - , remove(nullptr)
270 - , reset(nullptr)
271 - , attach(nullptr)
272 - , detach(nullptr)
273 - , hook(nullptr)
274 - , current_pid(0)
275 - , thread_table(nullptr)
276 - , destroy_event(nullptr)
277 - , register_count(0)
278 - , new_thread_number(0)
279 -{
280 - // jichi 9/21/2013: zero memory
281 - ITH_MEMSET_HEAP(record, 0, sizeof(record));
282 - ITH_MEMSET_HEAP(text_pipes, 0, sizeof(text_pipes));
283 - ITH_MEMSET_HEAP(cmd_pipes, 0, sizeof(cmd_pipes));
284 - ITH_MEMSET_HEAP(recv_threads, 0, sizeof(recv_threads));
285 -
286 - head.key = new ThreadParameter;
287 - head.key->pid = 0;
288 - head.key->hook = -1;
289 - head.key->retn = -1;
290 - head.key->spl = -1;
291 - head.data = 0;
292 - thread_table = new ThreadTable; // jichi 9/26/2013: zero memory in ThreadTable
293 -
294 - TextThread *entry = new TextThread(0, -1,-1,-1, new_thread_number++); // jichi 9/26/2013: zero memory in TextThread
295 - thread_table->SetThread(0, entry);
296 - SetCurrent(entry);
297 - entry->Status() |= USING_UNICODE;
298 - //texts->SetUnicode(true);
299 - //entry->AddToCombo();
300 - //entry->ComboSelectCurrent();
301 -
302 - //if (background==0) entry->AddToStore((BYTE*)BackgroundMsg,wcslen(BackgroundMsg)<<1,0,1);
303 -
304 - //InitializeCriticalSection(&hmcs);
305 - destroy_event = IthCreateEvent(0, 0, 0);
306 -}
307 -
308 -HookManager::~HookManager()
309 -{
310 - //LARGE_INTEGER timeout={-1000*1000,-1};
311 - //IthBreak();
312 - NtWaitForSingleObject(destroy_event, 0, 0);
313 - NtClose(destroy_event);
314 - NtClose(cmd_pipes[0]);
315 - NtClose(recv_threads[0]);
316 - delete thread_table;
317 - delete head.key;
318 - //DeleteCriticalSection(&hmcs);
319 -}
320 -
321 -TextThread *HookManager::FindSingle(DWORD pid, DWORD hook, DWORD retn, DWORD split)
322 -{
323 - if (pid == 0)
324 - return thread_table->FindThread(0);
325 - ThreadParameter tp = {pid, hook, retn, split};
326 - TreeNode<ThreadParameter *,DWORD> *node = Search(&tp);
327 - return node ? thread_table->FindThread(node->data) : nullptr;
328 -}
329 -
330 -TextThread *HookManager::FindSingle(DWORD number)
331 -{ return (number & 0x80008000) ? nullptr : thread_table->FindThread(number); }
332 -
333 -void HookManager::DetachProcess(DWORD pid) {}
334 -
335 -void HookManager::SetCurrent(TextThread *it)
336 -{
337 - if (current)
338 - current->Status() &= ~CURRENT_SELECT;
339 - current = it;
340 - if (it)
341 - it->Status() |= CURRENT_SELECT;
342 -}
343 -void HookManager::SelectCurrent(DWORD num)
344 -{
345 - if (TextThread *st = FindSingle(num)) {
346 - SetCurrent(st);
347 - if (reset)
348 - reset(st);
349 - //st->ResetEditText();
350 - }
351 -}
352 -void HookManager::RemoveSingleHook(DWORD pid, DWORD addr)
353 -{
354 - HM_LOCK;
355 - //ConsoleOutput("vnrhost:RemoveSingleHook: lock");
356 - //EnterCriticalSection(&hmcs);
357 - DWORD max = thread_table->Used();
358 - bool flag = false;
359 - for (DWORD i = 1; i <= max; i++)
360 - if (TextThread *it = thread_table->FindThread(i))
361 - if (it->PID() == pid && it->Addr() == addr) {
362 - flag |= (it == current);
363 - //flag|=it->RemoveFromCombo();
364 - thread_table->SetThread(i, 0);
365 - if (it->Number() < new_thread_number)
366 - new_thread_number = it->Number();
367 - Delete(it->GetThreadParameter());
368 - if (remove)
369 - remove(it);
370 - delete it;
371 - }
372 -
373 - for (DWORD i = 0; i <= max; i++)
374 - if (TextThread *it = thread_table->FindThread(i))
375 - if (it->Link() && thread_table->FindThread(it->LinkNumber()) == nullptr) {
376 - it->LinkNumber() = -1;
377 - it->Link() = nullptr;
378 - }
379 -
380 - if (flag) {
381 - current = nullptr;
382 - DWORD number = head.Left ? head.Left->data : 0;
383 - SetCurrent(thread_table->FindThread(number));
384 - if (reset && current)
385 - reset(current);
386 - //it->ResetEditText();
387 - }
388 - //LeaveCriticalSection(&hmcs);
389 - //ConsoleOutput("vnrhost:RemoveSingleHook: unlock");
390 -}
391 -void HookManager::RemoveSingleThread(DWORD number)
392 -{
393 - if (number == 0)
394 - return;
395 - HM_LOCK;
396 - //ConsoleOutput("vnrhost:RemoveSingleThread: lock");
397 - //EnterCriticalSection(&hmcs);
398 - if (TextThread *it = thread_table->FindThread(number)) {
399 - thread_table->SetThread(number, 0);
400 - Delete(it->GetThreadParameter());
401 - if (remove)
402 - remove(it);
403 - bool flag = (it == current);
404 - if (it->Number() < new_thread_number)
405 - new_thread_number = it->Number();
406 - delete it;
407 - for (int i = 0; i <= thread_table->Used(); i++)
408 - if (TextThread *t = thread_table->FindThread(i))
409 - if (t->LinkNumber() == number) {
410 - t->Link() = 0;
411 - t->LinkNumber() = -1;
412 - }
413 -
414 - if (flag) {
415 - current = nullptr;
416 - number = head.Left ? head.Left->data : 0;
417 - SetCurrent(thread_table->FindThread(number));
418 - if (reset && current)
419 - reset(current);
420 - //it->ResetEditText();
421 - }
422 - }
423 - //LeaveCriticalSection(&hmcs);
424 - //ConsoleOutput("vnrhost:RemoveSingleThread: unlock");
425 -}
426 -
427 -void HookManager::RemoveProcessContext(DWORD pid)
428 -{
429 - HM_LOCK;
430 - bool flag = false;
431 - //ConsoleOutput("vnrhost:RemoveProcessContext: lock");
432 - //EnterCriticalSection(&hmcs);
433 - for (int i = 1; i < thread_table->Used(); i++)
434 - if (TextThread *it = thread_table->FindThread(i))
435 - if (it->PID() == pid) {
436 - Delete(it->GetThreadParameter());
437 - //if (false == Delete(it->GetThreadParameter())) {
438 - // // jichi 11/26/2013: Remove debugging instructions
439 - // //if (debug)
440 - // // __asm int 3
441 - //}
442 - flag |= (it == current);
443 - //flag|=it->RemoveFromCombo();
444 - if (it->Number() <new_thread_number)
445 - new_thread_number = it->Number();
446 - thread_table->SetThread(i,0);
447 - if (remove)
448 - remove(it);
449 - delete it;
450 - }
451 -
452 - for (int i = 0; i < thread_table->Used(); i++)
453 - if (TextThread *it=thread_table->FindThread(i))
454 - if (it->Link() && thread_table->FindThread(it->LinkNumber()) == nullptr) {
455 - it->LinkNumber()=-1;
456 - it->Link() = nullptr;
457 - }
458 -
459 - if (flag) {
460 - current = nullptr;
461 - DWORD number = head.Left ? head.Left->data : 0;
462 - SetCurrent(thread_table->FindThread(number));
463 - if (reset && current)
464 - reset(current);
465 - //if (it) it->ResetEditText();
466 - }
467 - //LeaveCriticalSection(&hmcs);
468 - //ConsoleOutput("vnrhost:RemoveProcessContext: unlock");
469 -}
470 -void HookManager::RegisterThread(TextThread* it, DWORD num)
471 -{ thread_table->SetThread(num, it); }
472 -
473 -void HookManager::RegisterPipe(HANDLE text, HANDLE cmd, HANDLE thread)
474 -{
475 - text_pipes[register_count] = text;
476 - cmd_pipes[register_count] = cmd;
477 - recv_threads[register_count] = thread;
478 - register_count++;
479 - if (register_count == 1)
480 - NtSetEvent(destroy_event, 0);
481 - else
482 - NtClearEvent(destroy_event);
483 -}
484 -void HookManager::RegisterProcess(DWORD pid, DWORD hookman, DWORD module)
485 -{
486 - HM_LOCK;
487 - wchar_t str[0x40],
488 - path[MAX_PATH];
489 - //pid_map->Set(pid>>2);
490 - //ConsoleOutput("vnrhost:RegisterProcess: lock");
491 - //EnterCriticalSection(&hmcs);
492 - record[register_count - 1].pid_register = pid;
493 - record[register_count - 1].hookman_register = hookman;
494 - record[register_count - 1].module_register = module;
495 - //record[register_count - 1].engine_register = engine;
496 - swprintf(str, ITH_SECTION_ L"%d", pid);
497 - HANDLE hSection = IthCreateSection(str, HOOK_SECTION_SIZE, PAGE_READONLY);
498 - LPVOID map = nullptr;
499 - //DWORD map_size = 0x1000;
500 - DWORD map_size = HOOK_SECTION_SIZE / 2; // jichi 1/16/2015: Changed to half to hook section size
501 - //if (::ith_has_section)
502 - NtMapViewOfSection(hSection, NtCurrentProcess(),
503 - &map, 0, map_size, 0, &map_size, ViewUnmap, 0,
504 - PAGE_READONLY);
505 -
506 - record[register_count - 1].hookman_section = hSection;
507 - record[register_count - 1].hookman_map = map;
508 -
509 - HANDLE hProc;
510 - CLIENT_ID id;
511 - id.UniqueProcess = pid;
512 - id.UniqueThread = 0;
513 - OBJECT_ATTRIBUTES oa = {};
514 - oa.uLength = sizeof(oa);
515 - if (NT_SUCCESS(NtOpenProcess(&hProc,
516 - PROCESS_QUERY_INFORMATION|
517 - PROCESS_CREATE_THREAD|
518 - PROCESS_VM_READ|
519 - PROCESS_VM_WRITE|
520 - PROCESS_VM_OPERATION,
521 - &oa,&id)))
522 - record[register_count - 1].process_handle = hProc;
523 - else {
524 - ConsoleOutput("failed to open process");
525 - //::man->AddConsoleOutput(ErrorOpenProcess);
526 - //LeaveCriticalSection(&hmcs);
527 - //ConsoleOutput("vnrhost:RegisterProcess: unlock");
528 - return;
529 - }
530 -
531 - // jichi 9/27/2013: The hook man should be consistent with the one defined in vnrcli
532 - //Hook *h = (Hook *)map;
533 - //for (int i = 0; i < MAX_HOOK; i++)
534 - // if (!h[i].hook_name)
535 - // break;
536 - // else {
537 - // const Hook &hi = h[i];
538 - // wchar_t buffer[1000];
539 - // DWORD len = hi.NameLength();
540 - // NtReadVirtualMemory(hProc, hi.hook_name, buffer, len << 1, &len);
541 - // buffer[len] = 0;
542 - // ITH_MSG(buffer);
543 - // }
544 -
545 - swprintf(str, ITH_HOOKMAN_MUTEX_ L"%d", pid);
546 - record[register_count - 1].hookman_mutex = IthOpenMutex(str);
547 - if (!GetProcessPath(pid, path))
548 - path[0] = 0;
549 - //swprintf(str,L"%.4d:%s", pid, wcsrchr(path, L'\\') + 1); // jichi 9/25/2013: this is useless?
550 - current_pid = pid;
551 - if (attach)
552 - attach(pid);
553 - //LeaveCriticalSection(&hmcs);
554 - //ConsoleOutput("vnrhost:RegisterProcess: unlock");
555 -}
556 -
557 -void HookManager::UnRegisterProcess(DWORD pid)
558 -{
559 - HM_LOCK;
560 - //ConsoleOutput("vnrhost:UnRegisterProcess: lock");
561 - //EnterCriticalSection(&hmcs);
562 -
563 - int i;
564 - for (i = 0; i < MAX_REGISTER; i++)
565 - if(record[i].pid_register == pid)
566 - break;
567 -
568 - if (i < MAX_REGISTER) {
569 - NtClose(text_pipes[i]);
570 - NtClose(cmd_pipes[i]);
571 - NtClose(recv_threads[i]);
572 - NtClose(record[i].hookman_mutex);
573 -
574 - //if (::ith_has_section)
575 - NtUnmapViewOfSection(NtCurrentProcess(), record[i].hookman_map);
576 - //else
577 - // delete[] record[i].hookman_map;
578 -
579 - NtClose(record[i].process_handle);
580 - NtClose(record[i].hookman_section);
581 -
582 - for (; i < MAX_REGISTER; i++) {
583 - record[i] = record[i+1];
584 - text_pipes[i] = text_pipes[i+1];
585 - cmd_pipes[i] = cmd_pipes[i+1];
586 - recv_threads[i] = recv_threads[i+1];
587 - if (text_pipes[i] == 0)
588 - break;
589 - }
590 - register_count--;
591 - if (current_pid == pid)
592 - current_pid = register_count ? record[0].pid_register : 0;
593 - RemoveProcessContext(pid);
594 - }
595 - //pid_map->Clear(pid>>2);
596 -
597 - if (register_count == 1)
598 - NtSetEvent(destroy_event, 0);
599 - //LeaveCriticalSection(&hmcs);
600 - //ConsoleOutput("vnrhost:UnRegisterProcess: unlock");
601 - if (detach)
602 - detach(pid);
603 -}
604 -
605 -// jichi 9/28/2013: I do not need this
606 -//void HookManager::SetName(DWORD type)
607 -//{
608 -// WCHAR c;
609 -// if (type & PRINT_DWORD)
610 -// c = L'H';
611 -// else if (type & USING_UNICODE) {
612 -// if (type & STRING_LAST_CHAR)
613 -// c = L'L';
614 -// else if (type & USING_STRING)
615 -// c = L'Q';
616 -// else
617 -// c = L'W';
618 -// } else {
619 -// if (type & USING_STRING)
620 -// c = L'S';
621 -// else if (type & BIG_ENDIAN)
622 -// c = L'A';
623 -// else
624 -// c = L'B';
625 -// }
626 -// //swprintf(user_entry,L"UserHook%c",c);
627 -//}
628 -
629 -void HookManager::AddLink(WORD from, WORD to)
630 -{
631 - HM_LOCK;
632 - //bool flag=false;
633 - //ConsoleOutput("vnrhost:AddLink: lock");
634 - //EnterCriticalSection(&hmcs);
635 - TextThread *from_thread = thread_table->FindThread(from),
636 - *to_thread = thread_table->FindThread(to);
637 - if (to_thread && from_thread) {
638 - if (from_thread->GetThreadParameter()->pid != to_thread->GetThreadParameter()->pid)
639 - ConsoleOutput("vnrhost:AddLink: link to different process");
640 - else if (from_thread->Link()==to_thread)
641 - ConsoleOutput("vnrhost:AddLink: link already exists");
642 - else if (to_thread->CheckCycle(from_thread))
643 - ConsoleOutput("vnrhost:AddLink: cyclic link");
644 - else {
645 - from_thread->Link()=to_thread;
646 - from_thread->LinkNumber()=to;
647 - ConsoleOutput("vnrhost:AddLink: thread linked");
648 - if (addRemoveLink)
649 - addRemoveLink(from_thread);
650 - //WCHAR str[0x40];
651 - //swprintf(str,FormatLink,from,to);
652 - //AddConsoleOutput(str);
653 - }
654 - } else
655 - ConsoleOutput("vnrhost:AddLink: error link");
656 - //else
657 - // AddConsoleOutput(ErrorLink);
658 - //LeaveCriticalSection(&hmcs);
659 - //ConsoleOutput("vnrhost:AddLink: unlock");
660 -}
661 -void HookManager::UnLink(WORD from)
662 -{
663 - HM_LOCK;
664 - //bool flag=false;
665 - //ConsoleOutput("vnrhost:UnLink: lock");
666 - //EnterCriticalSection(&hmcs);
667 - if (TextThread *from_thread = thread_table->FindThread(from)) {
668 - from_thread->Link() = nullptr;
669 - from_thread->LinkNumber() = 0xffff;
670 - ConsoleOutput("vnrhost:UnLink: link deleted");
671 - if (addRemoveLink)
672 - addRemoveLink(from_thread);
673 - }
674 - //else // jichi 12/25/2013: This could happen when the game exist
675 - // ConsoleOutput("vnrhost:UnLink: thread does not exist");
676 - //LeaveCriticalSection(&hmcs);
677 - //ConsoleOutput("vnrhost:UnLink: unlock");
678 -}
679 -void HookManager::UnLinkAll(WORD from)
680 -{
681 - HM_LOCK;
682 - //bool flag=false;
683 - //ConsoleOutput("vnrhost:UnLinkAll: lock");
684 - //EnterCriticalSection(&hmcs);
685 - if (TextThread *from_thread = thread_table->FindThread(from)) {
686 - from_thread->UnLinkAll();
687 - ConsoleOutput("vnrhost:UnLinkAll: link deleted");
688 - }
689 - //else // jichi 12/25/2013: This could happen after the process exists
690 - // ConsoleOutput("vnrhost:UnLinkAll: thread not exist");
691 - //AddConsoleOutput(L"Link deleted.");
692 - //} else
693 - // AddConsoleOutput(L"Thread not exist.");
694 - //LeaveCriticalSection(&hmcs);
695 - //ConsoleOutput("vnrhost:UnLinkAll: unlock");
696 -}
697 -
698 -void HookManager::DispatchText(DWORD pid, const BYTE *text, DWORD hook, DWORD retn, DWORD spl, int len, bool space)
699 -{
700 - // jichi 20/27/2013: When PID is zero, the text comes from console, which I don't need
701 - if (!text || !pid || (len <= 0 && !space))
702 - return;
703 - HM_LOCK;
704 - //bool flag=false;
705 - ThreadParameter tp = {pid, hook, retn, spl};
706 - //ConsoleOutput("vnrhost:DispatchText: lock");
707 - //EnterCriticalSection(&hmcs);
708 - TextThread *it;
709 - //`try {
710 - if (TreeNode<ThreadParameter *,DWORD> *in = Search(&tp)) {
711 - DWORD number = in->data;
712 - it = thread_table->FindThread(number);
713 - } else if (IsFull()) { // jichi 1/16/2015: Skip adding threads when full
714 - static bool once = true; // output only once
715 - if (once) {
716 - once = false;
717 - ConsoleOutput("vnrhost:DispatchText: so many new threads, skip");
718 - }
719 - return;
720 - } else { // New thread
721 - Insert(&tp, new_thread_number);
722 - it = new TextThread(pid, hook, retn, spl, new_thread_number);
723 - RegisterThread(it, new_thread_number);
724 - ConsoleOutput("vnrhost:DispatchText: found new thread");
725 - WCHAR entstr[0x200];
726 - it->GetEntryString(entstr);
727 - ConsoleOutputW(entstr);
728 - while (thread_table->FindThread(++new_thread_number));
729 - if (create)
730 - create(it);
731 - }
732 - if (it)
733 - it->AddText(text, len, false, space); // jichi 10/27/2013: new line is false
734 - //LeaveCriticalSection(&hmcs);
735 - //ConsoleOutput("vnrhost:DispatchText: unlock");
736 - //} catch (...) {
737 - // // ignored
738 - //}
739 -}
740 -
741 -void HookManager::AddConsoleOutput(LPCWSTR text)
742 -{
743 - if (text) {
744 - int len = wcslen(text) << 1;
745 - TextThread *console = thread_table->FindThread(0);
746 - //EnterCriticalSection(&hmcs);
747 - console->AddText((BYTE*)text,len,false,true);
748 - console->AddText((BYTE*)L"\r\n",4,false,true);
749 - //LeaveCriticalSection(&hmcs);
750 - }
751 -}
752 -
753 -void HookManager::ClearText(DWORD pid, DWORD hook, DWORD retn, DWORD spl)
754 -{
755 - HM_LOCK;
756 - //bool flag=false;
757 - //ConsoleOutput("vnrhost:ClearText: lock");
758 - //EnterCriticalSection(&hmcs);
759 - ThreadParameter tp = {pid, hook, retn, spl};
760 - if (TreeNode<ThreadParameter *, DWORD> *in = Search(&tp))
761 - if (TextThread *it = thread_table->FindThread(in->data)) {
762 - it->Reset();
763 - //SetCurrent(it);
764 - if (reset)
765 - reset(it);
766 - //it->ResetEditText();
767 - }
768 -
769 - //LeaveCriticalSection(&hmcs);
770 - //ConsoleOutput("vnrhost:ClearText: unlock");
771 -}
772 -void HookManager::ClearCurrent()
773 -{
774 - HM_LOCK;
775 - //ConsoleOutput("vnrhost:ClearCurrent: lock");
776 - //EnterCriticalSection(&hmcs);
777 - if (current) {
778 - current->Reset();
779 - if (reset)
780 - reset(current);
781 - }
782 - //current->ResetEditText();
783 - //LeaveCriticalSection(&hmcs);
784 - //ConsoleOutput("vnrhost:ClearCurrent: unlock");
785 -}
786 -void HookManager::ResetRepeatStatus()
787 -{
788 - HM_LOCK;
789 - //ConsoleOutput("vnrhost:ResetRepeatStatus: lock");
790 - //EnterCriticalSection(&hmcs);
791 - for (int i = 1; i < thread_table->Used(); i++)
792 - if (TextThread *it = thread_table->FindThread(i))
793 - it->ResetRepeatStatus();
794 -
795 - //LeaveCriticalSection(&hmcs);
796 - //ConsoleOutput("vnrhost:ResetRepeatStatus: unlock");
797 -}
798 -//void HookManager::LockHookman(){ EnterCriticalSection(&hmcs); }
799 -//void HookManager::UnlockHookman(){ LeaveCriticalSection(&hmcs); }
800 -void HookManager::LockHookman(){ hmcs.lock(); }
801 -void HookManager::UnlockHookman(){ hmcs.unlock(); }
802 -
803 -/*void HookManager::SetProcessEngineType(DWORD pid, DWORD type)
804 -{
805 - int i;
806 - for (i=0;i<MAX_REGISTER;i++)
807 - if (record[i].pid_register==pid) break;
808 - if (i<MAX_REGISTER)
809 - {
810 - record[i].engine_register|=type;
811 - }
812 -}*/
813 -
814 -ProcessRecord *HookManager::GetProcessRecord(DWORD pid)
815 -{
816 - HM_LOCK;
817 - //EnterCriticalSection(&hmcs);
818 - for (int i = 0; i < MAX_REGISTER; i++)
819 - if (record[i].pid_register == pid)
820 - return record + i;
821 - return nullptr;
822 - //ProcessRecord *pr = i < MAX_REGISTER ? record + i : nullptr;
823 - //LeaveCriticalSection(&hmcs);
824 - //return pr;
825 -}
826 -
827 -DWORD HookManager::GetProcessIDByPath(LPCWSTR str)
828 -{
829 - WCHAR path[MAX_PATH];
830 - for (int i = 0; i < 8 && record[i].process_handle; i++) {
831 - ::GetProcessPath(record[i].process_handle, path);
832 - if (_wcsicmp(path,str) == 0)
833 - return record[i].pid_register;
834 - }
835 - return 0;
836 -}
837 -
838 -DWORD HookManager::GetCurrentPID() { return current_pid; }
839 -
840 -HANDLE HookManager::GetCmdHandleByPID(DWORD pid)
841 -{
842 - HM_LOCK;
843 - //EnterCriticalSection(&hmcs);
844 - for (int i = 0; i < MAX_REGISTER; i++)
845 - if (record[i].pid_register == pid)
846 - return cmd_pipes[i];
847 - return nullptr;
848 - //HANDLE h = i < MAX_REGISTER ? cmd_pipes[i] : 0;
849 - //LeaveCriticalSection(&hmcs);
850 - //return h;
851 -}
852 -
853 -MK_BASIC_TYPE(DWORD)
854 -MK_BASIC_TYPE(LPVOID)
855 -
856 -//DWORD Hash(LPCWSTR module, int length)
857 -//{
858 -// bool flag = (length==-1);
859 -// DWORD hash = 0;
860 -// for (;*module && (flag || length--); module++)
861 -// hash = ((hash>>7)|(hash<<25)) + *module;
862 -// return hash;
863 -//}
864 -
865 -DWORD GetCurrentPID() { return ::man->GetCurrentPID(); }
866 -
867 -HANDLE GetCmdHandleByPID(DWORD pid) { return ::man->GetCmdHandleByPID(pid); }
868 -
869 -void AddLink(WORD from, WORD to) { ::man->AddLink(from, to); }
870 -
871 -// jichi 9/27/2013: Unparse to hook parameters /H code
872 -void GetCode(const HookParam &hp, LPWSTR buffer, DWORD pid)
873 -{
874 - WCHAR c;
875 - LPWSTR ptr = buffer;
876 - // jichi 12/7/2014: disabled
877 - //if (hp.type&PRINT_DWORD)
878 - // c = L'H';
879 - if (hp.type&USING_UNICODE) {
880 - if (hp.type&USING_STRING)
881 - c = L'Q';
882 - else if (hp.type&STRING_LAST_CHAR)
883 - c = L'L';
884 - else
885 - c = L'W';
886 - } else {
887 - if (hp.type&USING_STRING)
888 - c = L'S';
889 - else if (hp.type&BIG_ENDIAN)
890 - c = L'A';
891 - else if (hp.type&STRING_LAST_CHAR)
892 - c = L'E';
893 - else
894 - c = L'B';
895 - }
896 - ptr += swprintf(ptr, L"/H%c",c);
897 - if (hp.type & NO_CONTEXT)
898 - *ptr++ = L'N';
899 - if (hp.off>>31)
900 - ptr += swprintf(ptr,L"-%X",-(hp.off+4));
901 - else
902 - ptr += swprintf(ptr,L"%X",hp.off);
903 - if (hp.type & DATA_INDIRECT) {
904 - if (hp.ind>>31)
905 - ptr += swprintf(ptr,L"*-%X",-hp.ind);
906 - else
907 - ptr += swprintf(ptr,L"*%X",hp.ind);
908 - }
909 - if (hp.type & USING_SPLIT) {
910 - if (hp.split >> 31)
911 - ptr += swprintf(ptr,L":-%X", -(4 + hp.split));
912 - else
913 - ptr += swprintf(ptr,L":%X", hp.split);
914 - }
915 - if (hp.type & SPLIT_INDIRECT) {
916 - if (hp.split_ind >> 31)
917 - ptr += swprintf(ptr, L"*-%X", -hp.split_ind);
918 - else
919 - ptr += swprintf(ptr, L"*%X", hp.split_ind);
920 - }
921 - if (hp.module) {
922 - if (pid) {
923 - WCHAR path[MAX_PATH];
924 - MEMORY_BASIC_INFORMATION info;
925 - ProcessRecord* pr = ::man->GetProcessRecord(pid);
926 - if (pr) {
927 - HANDLE hProc = pr->process_handle;
928 - if (NT_SUCCESS(NtQueryVirtualMemory(hProc,(PVOID)hp.addr, MemorySectionName, path, MAX_PATH*2, 0)) &&
929 - NT_SUCCESS(NtQueryVirtualMemory(hProc,(PVOID)hp.addr, MemoryBasicInformation, &info, sizeof(info), 0)))
930 - ptr += swprintf(ptr, L"@%X:%s", hp.addr - (DWORD)info. AllocationBase, wcsrchr(path,L'\\') + 1);
931 - }
932 - } else {
933 - ptr += swprintf(ptr, L"@%X!%X", hp.addr, hp.module);
934 - if (hp.function)
935 - ptr += swprintf(ptr, L"!%X", hp.function);
936 - }
937 - }
938 - else
939 - ptr += swprintf(ptr, L"@%X", hp.addr);
940 -}
941 -
942 -// jichi 1/16/2015
943 -bool HookManager::IsFull() const { return new_thread_number >= MAX_HOOK; }
944 -
945 -// EOF
1 -#pragma once
2 -
3 -// hookman.h
4 -// 8/23/2013 jichi
5 -// Branch: ITH/HookManager.h, rev 133
6 -
7 -#include "ith/host/avl_p.h"
8 -#include "ith/host/textthread.h"
9 -#include "winmutex/winmutex.h"
10 -
11 -enum { MAX_REGISTER = 0xf };
12 -enum { MAX_PREV_REPEAT_LENGTH = 0x20 };
13 -
14 -struct ProcessRecord {
15 - DWORD pid_register;
16 - DWORD hookman_register;
17 - DWORD module_register;
18 - //DWORD engine_register; // jichi 10/19/2014: removed
19 - HANDLE process_handle;
20 - HANDLE hookman_mutex;
21 - HANDLE hookman_section;
22 - LPVOID hookman_map;
23 -};
24 -
25 -class ThreadTable : public MyVector<TextThread *, 0x40>
26 -{
27 -public:
28 - virtual void SetThread(DWORD number, TextThread *ptr);
29 - virtual TextThread *FindThread(DWORD number);
30 -};
31 -
32 -struct TCmp { char operator()(const ThreadParameter *t1,const ThreadParameter *t2); };
33 -struct TCpy { void operator()(ThreadParameter *t1,const ThreadParameter *t2); };
34 -struct TLen { int operator()(const ThreadParameter *t); };
35 -
36 -typedef DWORD (*ProcessEventCallback)(DWORD pid);
37 -
38 -class IHFSERVICE HookManager : public AVLTree<ThreadParameter, DWORD, TCmp, TCpy, TLen>
39 -{
40 -public:
41 - HookManager();
42 - ~HookManager();
43 - // jichi 12/26/2013: remove virtual modifiers
44 - TextThread *FindSingle(DWORD pid, DWORD hook, DWORD retn, DWORD split);
45 - TextThread *FindSingle(DWORD number);
46 - ProcessRecord *GetProcessRecord(DWORD pid);
47 - DWORD GetProcessIDByPath(LPCWSTR str);
48 - void RemoveSingleThread(DWORD number);
49 - void LockHookman();
50 - void UnlockHookman();
51 - void ResetRepeatStatus();
52 - void ClearCurrent();
53 - void AddLink(WORD from, WORD to);
54 - void UnLink(WORD from);
55 - void UnLinkAll(WORD from);
56 - void SelectCurrent(DWORD num);
57 - void DetachProcess(DWORD pid);
58 - void SetCurrent(TextThread *it);
59 - void AddConsoleOutput(LPCWSTR text);
60 -
61 - // jichi 10/27/2013: Add const; add space.
62 - void DispatchText(DWORD pid, const BYTE *text, DWORD hook, DWORD retn, DWORD split, int len, bool space);
63 -
64 - void ClearText(DWORD pid, DWORD hook, DWORD retn, DWORD split);
65 - void RemoveProcessContext(DWORD pid);
66 - void RemoveSingleHook(DWORD pid, DWORD addr);
67 - void RegisterThread(TextThread*, DWORD);
68 - void RegisterPipe(HANDLE text, HANDLE cmd, HANDLE thread);
69 - void RegisterProcess(DWORD pid, DWORD hookman, DWORD module);
70 - void UnRegisterProcess(DWORD pid);
71 - //void SetName(DWORD);
72 -
73 - DWORD GetCurrentPID();
74 - HANDLE GetCmdHandleByPID(DWORD pid);
75 -
76 - ConsoleCallback RegisterConsoleCallback(ConsoleCallback cf)
77 - { return (ConsoleCallback)_InterlockedExchange((long*)&console,(long)cf); }
78 -
79 - ConsoleWCallback RegisterConsoleWCallback(ConsoleWCallback cf)
80 - { return (ConsoleWCallback)_InterlockedExchange((long*)&wconsole,(long)cf); }
81 -
82 - ThreadEventCallback RegisterThreadCreateCallback(ThreadEventCallback cf)
83 - { return (ThreadEventCallback)_InterlockedExchange((long*)&create,(long)cf); }
84 -
85 - ThreadEventCallback RegisterThreadRemoveCallback(ThreadEventCallback cf)
86 - { return (ThreadEventCallback)_InterlockedExchange((long*)&remove,(long)cf); }
87 -
88 - ThreadEventCallback RegisterThreadResetCallback(ThreadEventCallback cf)
89 - { return (ThreadEventCallback)_InterlockedExchange((long*)&reset,(long)cf); }
90 -
91 - ThreadEventCallback RegisterAddRemoveLinkCallback(ThreadEventCallback cf)
92 - { return (ThreadEventCallback)_InterlockedExchange((long*)&addRemoveLink, (long)cf); }
93 -
94 - ProcessEventCallback RegisterProcessAttachCallback(ProcessEventCallback cf)
95 - { return (ProcessEventCallback)_InterlockedExchange((long*)&attach,(long)cf); }
96 -
97 - ProcessEventCallback RegisterProcessDetachCallback(ProcessEventCallback cf)
98 - { return (ProcessEventCallback)_InterlockedExchange((long*)&detach,(long)cf); }
99 -
100 - ProcessEventCallback RegisterProcessNewHookCallback(ProcessEventCallback cf)
101 - { return (ProcessEventCallback)_InterlockedExchange((long*)&hook,(long)cf); }
102 -
103 - ProcessEventCallback ProcessNewHook() { return hook; }
104 - TextThread *GetCurrentThread() { return current; }
105 - ProcessRecord *Records() { return record; }
106 - ThreadTable *Table() { return thread_table; }
107 -
108 - //DWORD& SplitTime() { return split_time; }
109 - //DWORD& RepeatCount() { return repeat_count; }
110 - //DWORD& CyclicRemove() { return cyclic_remove; }
111 - //DWORD& GlobalFilter() { return global_filter; }
112 - void ConsoleOutput(LPCSTR text) { if (console) console(text); } // not thread safe
113 - void ConsoleOutputW(LPCWSTR text) { if (wconsole) wconsole(text); } // not thread safe
114 -
115 -private:
116 - typedef win_mutex<CRITICAL_SECTION> mutex_type;
117 - mutex_type hmcs;
118 -
119 - TextThread *current;
120 - ConsoleCallback console; // jichi 12/25/2013: add console output callback
121 - ConsoleWCallback wconsole;
122 - ThreadEventCallback create,
123 - remove,
124 - reset,
125 - addRemoveLink;
126 - ProcessEventCallback attach,
127 - detach,
128 - hook;
129 - DWORD current_pid;
130 - ThreadTable *thread_table;
131 - HANDLE destroy_event;
132 - ProcessRecord record[MAX_REGISTER + 1];
133 - HANDLE text_pipes[MAX_REGISTER + 1],
134 - cmd_pipes[MAX_REGISTER + 1],
135 - recv_threads[MAX_REGISTER + 1];
136 - WORD register_count,
137 - new_thread_number;
138 -
139 - // jichi 1/16/2014: Stop adding new threads when full
140 - bool IsFull() const; // { return new_thread_number >= MAX_HOOK; }
141 - bool IsEmpty() const { return !new_thread_number; }
142 -};
143 -
144 -// EOF
1 -# host.pri
2 -# 8/9/2011 jichi
3 -
4 -DEFINES += WITH_LIB_ITH_HOST
5 -
6 -DEPENDPATH += $$PWD
7 -
8 -LIBS += -lvnrhost
9 -
10 -HEADERS += \
11 - $$PWD/avl_p.h \
12 - $$PWD/hookman.h \
13 - $$PWD/settings.h \
14 - $$PWD/srv.h \
15 - $$PWD/textthread.h \
16 - $$PWD/textthread_p.h
17 -
18 -# EOF
1 -# host.pro
2 -# 8/9/2013 jichi
3 -# Build vnrhost
4 -
5 -#CONFIG += eha # 3/1/2014: catchlng all exceptions will break pytexthook on Windows XP
6 -CONFIG += noeh # Needed by pytexthook ONLY on windows xp orz
7 -include(../dllconfig.pri)
8 -include(../sys/sys.pri)
9 -include($$LIBDIR/winmaker/winmaker.pri)
10 -include($$LIBDIR/winmutex/winmutex.pri)
11 -
12 -# 9/22/2013: When ITH is on wine, certain NT functions are replaced
13 -#DEFINES += ITH_WINE
14 -
15 -# 9/27/2013: Only for debugging purpose
16 -#DEFINES += ITH_DISABLE_REPEAT # disable repetition elimination
17 -#DEFINES += ITH_DISABLE_FILTER # disable space filter in pipe
18 -
19 -## Libraries
20 -
21 -LIBS += -lkernel32 -luser32 #-lcomctl32
22 -
23 -## Sources
24 -
25 -TEMPLATE = lib
26 -#TARGET = IHF # compatible with ITHv3
27 -TARGET = vnrhost
28 -
29 -#CONFIG += staticlib
30 -
31 -HEADERS += \
32 - avl_p.h \
33 - config.h \
34 - hookman.h \
35 - settings.h \
36 - srv.h \
37 - srv_p.h \
38 - textthread.h \
39 - textthread_p.h
40 - #util.h
41 -
42 -SOURCES += \
43 - hookman.cc \
44 - main.cc \
45 - pipe.cc \
46 - textthread.cc
47 - #util.cc
48 -
49 -#RC_FILE += engine.rc
50 -#OTHER_FILES += engine.rc
51 -
52 -OTHER_FILES += host.pri
53 -
54 -# EOF
1 -// main.cc
2 -// 8/24/2013 jichi
3 -// Branch IHF/main.cpp, rev 111
4 -// 8/24/2013 TODO: Clean up this file
5 -
6 -//#ifdef _MSC_VER
7 -//# pragma warning(disable:4800) // C4800: forcing value to bool (performance warning)
8 -//#endif // _MSC_VER
9 -
10 -#include "config.h"
11 -//#include "customfilter.h"
12 -#include "srv.h"
13 -#include "srv_p.h"
14 -#include "settings.h"
15 -#include "ith/common/const.h"
16 -#include "ith/common/defs.h"
17 -#include "ith/common/growl.h"
18 -#include "ith/common/types.h"
19 -#include "ith/sys/sys.h"
20 -#include "winmaker/winmaker.h"
21 -#include "ccutil/ccmacro.h"
22 -#include <commctrl.h>
23 -
24 -//#define ITH_WINE
25 -//#define ITH_USE_UX_DLLS IthIsWine()
26 -#define ITH_USE_XP_DLLS (IthIsWindowsXp() && !IthIsWine())
27 -
28 -namespace { // unnamed
29 -
30 -//enum { HOOK_TIMEOUT = -50000000 }; // in nanoseconds = 5 seconds
31 -
32 -CRITICAL_SECTION cs;
33 -//WCHAR exist[] = ITH_PIPEEXISTS_EVENT;
34 -//WCHAR mutex[] = L"ITH_RUNNING";
35 -//WCHAR EngineName[] = ITH_ENGINE_DLL;
36 -//WCHAR EngineNameXp[] = ITH_ENGINE_XP_DLL;
37 -//WCHAR DllName[] = ITH_CLIENT_DLL;
38 -//WCHAR DllNameXp[] = ITH_CLIENT_XP_DLL;
39 -HANDLE hServerMutex; // jichi 9/28/2013: used to guard pipe
40 -HANDLE hHookMutex; // jichi 9/28/2013: used to guard hook modification
41 -DWORD admin;
42 -} // unnamed namespace
43 -
44 -//extern LPWSTR current_dir;
45 -extern CRITICAL_SECTION detach_cs;
46 -
47 -SettingManager* setman;
48 -Settings *settings;
49 -HWND hMainWnd;
50 -HANDLE hPipeExist;
51 -BOOL running;
52 -
53 -#define ITH_SYNC_HOOK IthMutexLocker locker(::hHookMutex)
54 -
55 -namespace { // unnamed
56 -
57 -void GetDebugPriv()
58 -{
59 - HANDLE hToken;
60 - DWORD dwRet;
61 - NTSTATUS status;
62 -
63 - TOKEN_PRIVILEGES Privileges = {1,{0x14,0,SE_PRIVILEGE_ENABLED}};
64 -
65 - NtOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
66 -
67 - status = NtAdjustPrivilegesToken(hToken, 0, &Privileges, sizeof(Privileges), 0, &dwRet);
68 - admin = 1; // jichi 8/24/2013: ITH do not need admin
69 - //if (STATUS_SUCCESS == status)
70 - //{
71 - // admin = 1;
72 - //}
73 - //else
74 - //{
75 - // WCHAR buffer[0x10];
76 - // swprintf(buffer, L"%.8X",status);
77 - // MessageBox(0, NotAdmin, buffer, 0);
78 - //}
79 - NtClose(hToken);
80 -}
81 -
82 -// jichi 9/22/2013: Change current directory to the same as main module path
83 -// Otherwise NtFile* would not work for files with relative paths.
84 -//BOOL ChangeCurrentDirectory()
85 -//{
86 -// if (const wchar_t *path = GetMainModulePath()) // path to VNR's python exe
87 -// if (const wchar_t *base = wcsrchr(path, L'\\')) {
88 -// size_t len = base - path;
89 -// if (len < MAX_PATH) {
90 -// wchar_t buf[MAX_PATH];
91 -// wcsncpy(buf, path, len);
92 -// buf[len] = 0;
93 -// return SetCurrentDirectoryW(buf);
94 -// }
95 -// }
96 -// return FALSE;
97 -//}
98 -
99 -DWORD Inject(HANDLE hProc)
100 -{
101 - enum : DWORD { error = (DWORD)-1 };
102 - LPVOID lpvAllocAddr = 0;
103 - DWORD dwWrite = 0x1000; //, len = 0;
104 - HANDLE hTH;
105 - //LPWSTR dllname = (IthIsWindowsXp() && !IthIsWine()) ? DllNameXp : DllName;
106 - LPCWSTR dllname = ITH_USE_XP_DLLS ? ITH_DLL_XP : ITH_DLL;
107 - //if (!IthCheckFile(dllname))
108 - // return error;
109 - wchar_t path[MAX_PATH];
110 - size_t len = IthGetCurrentModulePath(path, MAX_PATH);
111 - if (!len)
112 - return error;
113 -
114 - wchar_t *p;
115 - for (p = path + len; *p != L'\\'; p--);
116 - p++; // ending with L"\\"
117 -
118 - //LPCWSTR mp = GetMainModulePath();
119 - //len = wcslen(mp);
120 - //memcpy(path, mp, len << 1);
121 - //memset(path + len, 0, (MAX_PATH - len) << 1);
122 - //LPWSTR p;
123 - //for (p = path + len; *p != L'\\'; p--); // Always a \ after drive letter.
124 - //p++;
125 - wcscpy(p, dllname);
126 - //if (IthIsWine())
127 - // lpvAllocAddr = VirtualAllocEx(hProc, nullptr, dwWrite, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
128 - //else
129 - NtAllocateVirtualMemory(hProc, &lpvAllocAddr, 0, &dwWrite, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
130 - if (!lpvAllocAddr)
131 - return error;
132 -
133 - CheckThreadStart();
134 -
135 - //Copy module path into address space of target process.
136 - //if (IthIsWine())
137 - // WriteProcessMemory(hProc, lpvAllocAddr, path, MAX_PATH << 1, &dwWrite);
138 - //else
139 - NtWriteVirtualMemory(hProc, lpvAllocAddr, path, MAX_PATH << 1, &dwWrite);
140 - hTH = IthCreateThread(LoadLibraryW, (DWORD)lpvAllocAddr, hProc);
141 - if (hTH == 0 || hTH == INVALID_HANDLE_VALUE) {
142 - ConsoleOutput("vnrhost:inject: ERROR: failed to create remote cli thread");
143 - //ConsoleOutput(ErrorRemoteThread);
144 - return -1;
145 - }
146 - // jichi 9/28/2013: no wait as it will not blocked
147 - NtWaitForSingleObject(hTH, 0, nullptr);
148 - THREAD_BASIC_INFORMATION info;
149 - NtQueryInformationThread(hTH, ThreadBasicInformation, &info, sizeof(info), &dwWrite);
150 - NtClose(hTH);
151 -
152 - // jichi 10/19/2014: Disable inject the second dll
153 - //if (info.ExitStatus) {
154 - // //IthCoolDown();
155 - // wcscpy(p, engine);
156 - // //if (IthIsWine())
157 - // // WriteProcessMemory(hProc, lpvAllocAddr, path, MAX_PATH << 1, &dwWrite);
158 - // //else
159 - // NtWriteVirtualMemory(hProc, lpvAllocAddr, path, MAX_PATH << 1, &dwWrite);
160 - // hTH = IthCreateThread(LoadLibraryW, (DWORD)lpvAllocAddr, hProc);
161 - // if (hTH == 0 || hTH == INVALID_HANDLE_VALUE) {
162 - // //ConsoleOutput(ErrorRemoteThread);
163 - // ConsoleOutput("vnrhost:inject: ERROR: failed to create remote eng thread");
164 - // return error;
165 - // }
166 - //
167 - // // jichi 9/28/2013: no wait as it will not blocked
168 - // NtWaitForSingleObject(hTH, 0, nullptr);
169 - // NtClose(hTH);
170 - //}
171 -
172 - dwWrite = 0;
173 - //if (IthIsWine())
174 - // VirtualFreeEx(hProc, lpvAllocAddr, dwWrite, MEM_RELEASE);
175 - //else
176 - NtFreeVirtualMemory(hProc, &lpvAllocAddr, &dwWrite, MEM_RELEASE);
177 - return info.ExitStatus;
178 -}
179 -
180 -
181 -} // unnamed namespace
182 -
183 -void CreateNewPipe();
184 -
185 -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
186 -{
187 - CC_UNUSED(lpvReserved);
188 - switch (fdwReason)
189 - {
190 - case DLL_PROCESS_ATTACH:
191 - LdrDisableThreadCalloutsForDll(hinstDLL);
192 - InitializeCriticalSection(&cs);
193 - IthInitSystemService();
194 - GetDebugPriv();
195 - // jichi 12/20/2013: Since I already have a GUI, I don't have to InitCommonControls()
196 - //Used by timers.
197 - InitCommonControls();
198 - // jichi 8/24/2013: Create hidden window so that ITH can access timer and events
199 - //hMainWnd = CreateWindowW(L"Button", L"InternalWindow", 0, 0, 0, 0, 0, 0, 0, hinstDLL, 0);
200 - //wm_register_hidden_class("vnrsrv.class");
201 - hMainWnd = (HWND)wm_create_hidden_window(L"vnrsrv", L"Button", hinstDLL);
202 - //ChangeCurrentDirectory();
203 - break;
204 - case DLL_PROCESS_DETACH:
205 - if (::running)
206 - IHF_Cleanup();
207 - DeleteCriticalSection(&cs);
208 - IthCloseSystemService();
209 - wm_destroy_window(hMainWnd);
210 - break;
211 - default:
212 - break;
213 - }
214 - return true;
215 -}
216 -
217 -HANDLE IthOpenPipe(LPWSTR name, ACCESS_MASK direction)
218 -{
219 - UNICODE_STRING us;
220 - RtlInitUnicodeString(&us, name);
221 - SECURITY_DESCRIPTOR sd = {1};
222 - OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, &sd, 0};
223 - HANDLE hFile;
224 - IO_STATUS_BLOCK isb;
225 - if (NT_SUCCESS(NtCreateFile(&hFile, direction, &oa, &isb, 0, 0, FILE_SHARE_READ, FILE_OPEN, 0, 0, 0)))
226 - return hFile;
227 - else
228 - return INVALID_HANDLE_VALUE;
229 -}
230 -
231 -void ConsoleOutput(LPCSTR text) { man->ConsoleOutput(text); }
232 -void ConsoleOutputW(LPCWSTR text) { man->ConsoleOutputW(text); }
233 -
234 -enum { IHS_SIZE = 0x80 };
235 -enum { IHS_BUFF_SIZE = IHS_SIZE - sizeof(HookParam) };
236 -
237 -struct InsertHookStruct
238 -{
239 - SendParam sp;
240 - BYTE name_buffer[IHS_SIZE];
241 -};
242 -
243 -IHFSERVICE DWORD IHFAPI IHF_Init()
244 -{
245 - BOOL result = false;
246 - DWORD present;
247 - EnterCriticalSection(&cs);
248 - hServerMutex = IthCreateMutex(ITH_SERVER_MUTEX, 1, &present);
249 - if (present)
250 - //MessageBox(0,L"Already running.",0,0);
251 - // jichi 8/24/2013
252 - ITH_WARN(L"I am sorry that this game is attached by some other VNR ><\nPlease restart the game and try again!");
253 - else if (!::running) {
254 - ::running = true;
255 - ::settings = new Settings;
256 - setman = new SettingManager;
257 - setman->SetValue(SETTING_SPLIT_TIME, 200);
258 - ::man = new HookManager;
259 - //cmdq = new CommandQueue;
260 - InitializeCriticalSection(&detach_cs);
261 -
262 - ::hHookMutex = IthCreateMutex(ITH_SERVER_HOOK_MUTEX, FALSE);
263 - result = true;
264 -
265 - }
266 - LeaveCriticalSection(&cs);
267 - return result;
268 -}
269 -
270 -IHFSERVICE DWORD IHFAPI IHF_Start()
271 -{
272 - //IthBreak();
273 - CreateNewPipe();
274 - hPipeExist = IthCreateEvent(ITH_PIPEEXISTS_EVENT);
275 - NtSetEvent(hPipeExist, nullptr);
276 - return 0;
277 -}
278 -
279 -IHFSERVICE DWORD IHFAPI IHF_Cleanup()
280 -{
281 - BOOL result = FALSE;
282 - EnterCriticalSection(&cs);
283 - if (::running) {
284 - ::running = FALSE;
285 - HANDLE hRecvPipe = IthOpenPipe(recv_pipe, GENERIC_WRITE);
286 - NtClose(hRecvPipe);
287 - NtClearEvent(hPipeExist);
288 - //delete cmdq;
289 - delete man;
290 - delete settings;
291 - NtClose(::hHookMutex);
292 - NtClose(hServerMutex);
293 - NtClose(hPipeExist);
294 - DeleteCriticalSection(&detach_cs);
295 - result = TRUE;
296 - }
297 - LeaveCriticalSection(&cs);
298 - return result;
299 -}
300 -
301 -IHFSERVICE DWORD IHFAPI IHF_GetPIDByName(LPCWSTR pwcTarget)
302 -{
303 - DWORD dwSize = 0x20000,
304 - dwExpectSize = 0;
305 - LPVOID pBuffer = 0;
306 - SYSTEM_PROCESS_INFORMATION *spiProcessInfo;
307 - DWORD dwPid = 0;
308 - DWORD dwStatus;
309 -
310 - NtAllocateVirtualMemory(NtCurrentProcess(), &pBuffer, 0, &dwSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
311 - dwStatus = NtQuerySystemInformation(SystemProcessInformation, pBuffer, dwSize, &dwExpectSize);
312 - if (!NT_SUCCESS(dwStatus)) {
313 - NtFreeVirtualMemory(NtCurrentProcess(),&pBuffer,&dwSize,MEM_RELEASE);
314 - if (dwStatus != STATUS_INFO_LENGTH_MISMATCH || dwExpectSize < dwSize)
315 - return 0;
316 - dwSize = (dwExpectSize | 0xFFF) + 0x4001; //
317 - pBuffer = 0;
318 - NtAllocateVirtualMemory(NtCurrentProcess(), &pBuffer, 0, &dwSize, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
319 - dwStatus = NtQuerySystemInformation(SystemProcessInformation, pBuffer, dwSize, &dwExpectSize);
320 - if (!NT_SUCCESS(dwStatus)) goto _end;
321 - }
322 -
323 - for (spiProcessInfo = (SYSTEM_PROCESS_INFORMATION *)pBuffer; spiProcessInfo->dNext;) {
324 - spiProcessInfo = (SYSTEM_PROCESS_INFORMATION *)
325 - ((DWORD)spiProcessInfo + spiProcessInfo -> dNext);
326 - if (_wcsicmp(pwcTarget, spiProcessInfo -> usName.Buffer) == 0) {
327 - dwPid = spiProcessInfo->dUniqueProcessId;
328 - break;
329 - }
330 - }
331 - if (!dwPid)
332 - ConsoleOutput("vnrhost:IHF_GetPIDByName: pid not found");
333 - //if (dwPid == 0) ConsoleOutput(ErrorNoProcess);
334 -_end:
335 - NtFreeVirtualMemory(NtCurrentProcess(),&pBuffer,&dwSize,MEM_RELEASE);
336 - return dwPid;
337 -}
338 -
339 -IHFSERVICE DWORD IHFAPI IHF_InjectByPID(DWORD pid)
340 -{
341 - WCHAR str[0x80];
342 - if (!::running)
343 - return 0;
344 - if (pid == current_process_id) {
345 - //ConsoleOutput(SelfAttach);
346 - ConsoleOutput("vnrhost:IHF_InjectByPID: refuse to inject myself");
347 - return -1;
348 - }
349 - if (man->GetProcessRecord(pid)) {
350 - //ConsoleOutput(AlreadyAttach);
351 - ConsoleOutput("vnrhost:IHF_InjectByPID: already attached");
352 - return -1;
353 - }
354 - swprintf(str, ITH_HOOKMAN_MUTEX_ L"%d", pid);
355 - DWORD s;
356 - NtClose(IthCreateMutex(str, 0, &s));
357 - if (s)
358 - return -1;
359 - CLIENT_ID id;
360 - OBJECT_ATTRIBUTES oa = {};
361 - HANDLE hProc;
362 - id.UniqueProcess = pid;
363 - id.UniqueThread = 0;
364 - oa.uLength = sizeof(oa);
365 - if (!NT_SUCCESS(NtOpenProcess(&hProc,
366 - PROCESS_QUERY_INFORMATION|
367 - PROCESS_CREATE_THREAD|
368 - PROCESS_VM_OPERATION|
369 - PROCESS_VM_READ|
370 - PROCESS_VM_WRITE,
371 - &oa, &id))) {
372 - //ConsoleOutput(ErrorOpenProcess);
373 - ConsoleOutput("vnrhost:IHF_InjectByPID: failed to open process");
374 - return -1;
375 - }
376 -
377 - //if (!engine)
378 - // engine = ITH_USE_XP_DLLS ? ITH_ENGINE_XP_DLL : ITH_ENGINE_DLL;
379 - DWORD module = Inject(hProc);
380 - NtClose(hProc);
381 - if (module == -1)
382 - return -1;
383 - //swprintf(str, FormatInject, pid, module);
384 - //ConsoleOutput(str);
385 - ConsoleOutput("vnrhost:IHF_InjectByPID: inject succeed");
386 - return module;
387 -}
388 -
389 -// jichi 7/16/2014: Test if process is valid before creating remote threads
390 -// See: http://msdn.microsoft.com/en-us/library/ms687032.aspx
391 -static bool isProcessTerminated(HANDLE hProc)
392 -{ return WAIT_OBJECT_0 == ::WaitForSingleObject(hProc, 0); }
393 -//static bool isProcessRunning(HANDLE hProc)
394 -//{ return WAIT_TIMEOUT == ::WaitForSingleObject(hProc, 0); }
395 -
396 -// jichi 7/16/2014: Test if process is valid before creating remote threads
397 -//static bool isProcessRunning(DWORD pid)
398 -//{
399 -// bool ret = false;
400 -// HANDLE hProc = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
401 -// if (hProc) {
402 -// DWORD status;
403 -// if (::GetExitCodeProcess(hProc, &status)) {
404 -// ret = status == STILL_ACTIVE;
405 -// ::CloseHandle(hProc);
406 -// } else
407 -// ret = true;
408 -// }
409 -// return ret;
410 -//}
411 -
412 -IHFSERVICE DWORD IHFAPI IHF_ActiveDetachProcess(DWORD pid)
413 -{
414 - ITH_SYNC_HOOK;
415 -
416 - DWORD module;
417 - HANDLE hProc, hThread;
418 - IO_STATUS_BLOCK ios;
419 - //man->LockHookman();
420 - ProcessRecord *pr = man->GetProcessRecord(pid);
421 - HANDLE hCmd = man->GetCmdHandleByPID(pid);
422 - if (pr == 0 || hCmd == 0)
423 - return FALSE;
424 - //hProc = pr->process_handle; //This handle may be closed(thus invalid) during the detach process.
425 - NtDuplicateObject(NtCurrentProcess(), pr->process_handle,
426 - NtCurrentProcess(), &hProc, 0, 0, DUPLICATE_SAME_ACCESS); // Make a copy of the process handle.
427 - module = pr->module_register;
428 - if (module == 0)
429 - return FALSE;
430 -
431 - // jichi 7/15/2014: Process already closed
432 - if (isProcessTerminated(hProc)) {
433 - ConsoleOutput("vnrhost::activeDetach: process has terminated");
434 - return FALSE;
435 - }
436 -
437 - // jichi 10/19/2014: Disable the second dll
438 - //engine = pr->engine_register;
439 - //engine &= ~0xff;
440 -
441 - SendParam sp = {};
442 - sp.type = 4;
443 -
444 - ConsoleOutput("vnrhost:IHF_ActiveDetachProcess: sending cmd");
445 - NtWriteFile(hCmd, 0,0,0, &ios, &sp, sizeof(SendParam), 0,0);
446 - ConsoleOutput("vnrhost:IHF_ActiveDetachProcess: cmd sent");
447 -
448 - //cmdq->AddRequest(sp, pid);
449 -////#ifdef ITH_WINE // Nt series crash on wine
450 -//// hThread = IthCreateThread(FreeLibrary, engine, hProc);
451 -////#else
452 -// hThread = IthCreateThread(LdrUnloadDll, engine, hProc);
453 -////#endif // ITH_WINE
454 -// if (hThread == 0 || hThread == INVALID_HANDLE_VALUE)
455 -// return FALSE;
456 -// // jichi 10/22/2013: Timeout might crash vnrsrv
457 -// //const LONGLONG timeout = HOOK_TIMEOUT;
458 -// //NtWaitForSingleObject(hThread, 0, (PLARGE_INTEGER)&timeout);
459 -// NtWaitForSingleObject(hThread, 0, nullptr);
460 -// NtClose(hThread);
461 -
462 - // jichi 7/15/2014: Process already closed
463 - if (isProcessTerminated(hProc)) {
464 - ConsoleOutput("vnrhost:activeDetach: process has terminated");
465 - return FALSE;
466 - }
467 -
468 - //IthCoolDown();
469 -//#ifdef ITH_WINE // Nt series crash on wine
470 -// hThread = IthCreateThread(FreeLibrary, engine, hProc);
471 -//#else
472 - hThread = IthCreateThread(LdrUnloadDll, module, hProc);
473 -//#endif // ITH_WINE
474 - if (hThread == 0 || hThread == INVALID_HANDLE_VALUE)
475 - return FALSE;
476 - // jichi 10/22/2013: Timeout might crash vnrsrv
477 - //NtWaitForSingleObject(hThread, 0, (PLARGE_INTEGER)&timeout);
478 - NtWaitForSingleObject(hThread, 0, nullptr);
479 - //man->UnlockHookman();
480 - THREAD_BASIC_INFORMATION info;
481 - NtQueryInformationThread(hThread, ThreadBasicInformation, &info, sizeof(info), 0);
482 - NtClose(hThread);
483 - NtSetEvent(hPipeExist, 0);
484 - FreeThreadStart(hProc);
485 - NtClose(hProc);
486 - return info.ExitStatus;
487 -}
488 -
489 -IHFSERVICE DWORD IHFAPI IHF_GetHookManager(HookManager** hookman)
490 -{
491 - if (::running) {
492 - *hookman = man;
493 - return 0;
494 - }
495 - else
496 - return 1;
497 -}
498 -
499 -IHFSERVICE DWORD IHFAPI IHF_GetSettingManager(SettingManager** set_man)
500 -{
501 - if (running)
502 - {
503 - *set_man = setman;
504 - return 0;
505 - }
506 - else return 1;
507 -}
508 -
509 -IHFSERVICE DWORD IHFAPI IHF_GetSettings(Settings **p)
510 -{
511 - if (::running) {
512 - *p = settings;
513 - return 0;
514 - }
515 - else
516 - return 1;
517 -}
518 -
519 -IHFSERVICE DWORD IHFAPI IHF_InsertHook(DWORD pid, HookParam *hp, LPCWSTR name)
520 -{
521 - ITH_SYNC_HOOK;
522 -
523 - HANDLE hCmd = man->GetCmdHandleByPID(pid);
524 - if (hCmd == 0)
525 - return -1;
526 -
527 - InsertHookStruct s;
528 - s.sp.type = IHF_COMMAND_NEW_HOOK;
529 - s.sp.hp = *hp;
530 - DWORD len;
531 - if (name) len = wcslen(name) << 1;
532 - else len = 0;
533 - if (len >= IHS_BUFF_SIZE - 2) len = IHS_BUFF_SIZE - 2;
534 - memcpy(s.name_buffer, name, len);
535 - s.name_buffer[len] = 0;
536 - s.name_buffer[len + 1] = 0;
537 - IO_STATUS_BLOCK ios;
538 - NtWriteFile(hCmd, 0,0,0, &ios, &s, IHS_SIZE, 0, 0);
539 -
540 - //memcpy(&sp.hp,hp,sizeof(HookParam));
541 - //cmdq->AddRequest(sp, pid);
542 - return 0;
543 -}
544 -
545 -IHFSERVICE DWORD IHFAPI IHF_ModifyHook(DWORD pid, HookParam *hp)
546 -{
547 - ITH_SYNC_HOOK;
548 -
549 - SendParam sp;
550 - HANDLE hModify,hCmd;
551 - hCmd = GetCmdHandleByPID(pid);
552 - if (hCmd == 0)
553 - return -1;
554 - hModify = IthCreateEvent(ITH_MODIFYHOOK_EVENT);
555 - sp.type = IHF_COMMAND_MODIFY_HOOK;
556 - sp.hp = *hp;
557 - IO_STATUS_BLOCK ios;
558 - if (NT_SUCCESS(NtWriteFile(hCmd, 0,0,0, &ios, &sp, sizeof(SendParam), 0, 0)))
559 - // jichi 9/28/2013: no wait timeout
560 - //const LONGLONG timeout = HOOK_TIMEOUT;
561 - NtWaitForSingleObject(hModify, 0, nullptr);
562 - NtClose(hModify);
563 - man->RemoveSingleHook(pid, sp.hp.addr);
564 - return 0;
565 -}
566 -
567 -IHFSERVICE DWORD IHFAPI IHF_RemoveHook(DWORD pid, DWORD addr)
568 -{
569 - ITH_SYNC_HOOK;
570 -
571 - HANDLE hRemoved,hCmd;
572 - hCmd = GetCmdHandleByPID(pid);
573 - if (hCmd == 0)
574 - return -1;
575 - hRemoved = IthCreateEvent(ITH_REMOVEHOOK_EVENT);
576 - SendParam sp = {};
577 - IO_STATUS_BLOCK ios;
578 - sp.type = IHF_COMMAND_REMOVE_HOOK;
579 - sp.hp.addr = addr;
580 - //cmdq -> AddRequest(sp, pid);
581 - NtWriteFile(hCmd, 0,0,0, &ios, &sp, sizeof(SendParam),0,0);
582 - // jichi 10/22/2013: Timeout might crash vnrsrv
583 - //const LONGLONG timeout = HOOK_TIMEOUT;
584 - //NtWaitForSingleObject(hRemoved, 0, (PLARGE_INTEGER)&timeout);
585 - NtWaitForSingleObject(hRemoved, 0, nullptr);
586 - NtClose(hRemoved);
587 - man -> RemoveSingleHook(pid, sp.hp.addr);
588 - return 0;
589 -}
590 -
591 -IHFSERVICE DWORD IHFAPI IHF_IsAdmin() { return admin; }
592 -
593 -IHFSERVICE DWORD IHFAPI IHF_AddLink(DWORD from, DWORD to)
594 -{
595 - man->AddLink(from & 0xffff, to & 0xffff);
596 - return 0;
597 -}
598 -
599 -IHFSERVICE DWORD IHFAPI IHF_UnLink(DWORD from)
600 -{
601 - man->UnLink(from & 0xffff);
602 - return 0;
603 -}
604 -
605 -IHFSERVICE DWORD IHFAPI IHF_UnLinkAll(DWORD from)
606 -{
607 - man->UnLinkAll(from & 0xffff);
608 - return 0;
609 -}
610 -
611 -// EOF
1 -// pipe.cc
2 -// 8/24/2013 jichi
3 -// Branch IHF/pipe.cpp, rev 93
4 -// 8/24/2013 TODO: Clean up this file
5 -
6 -#include "srv_p.h"
7 -#include "hookman.h"
8 -#include "ith/common/defs.h"
9 -#include "ith/common/const.h"
10 -//#include "ith/common/growl.h"
11 -#include "ith/sys/sys.h"
12 -//#include "CommandQueue.h"
13 -
14 -//DWORD WINAPI UpdateWindows(LPVOID lpThreadParameter);
15 -
16 -namespace { // unnamed
17 -enum NamedPipeCommand {
18 - NAMED_PIPE_DISCONNECT = 1
19 - , NAMED_PIPE_CONNECT = 2
20 -};
21 -
22 -bool newline = false;
23 -bool detach = false;
24 -
25 -// jichi 10/27/2013
26 -// Check if text has leading space
27 -enum { _filter_limit = 0x20 }; // The same as the orignal ITH filter. So, I don't have to check \u3000
28 -//enum { _filter_limit = 0x19 };
29 -inline bool has_leading_space(const BYTE *text, int len)
30 -{
31 - return len == 1 ? *text <= _filter_limit : // 1 byte
32 - *reinterpret_cast<const WORD *>(text) <= _filter_limit; // 2 bytes
33 -}
34 -
35 -// jichi 9/28/2013: Skip leading garbage
36 -// Note:
37 -// - Modifying limit will break manual translation. The orignal one is 0x20
38 -// - Eliminating 0x20 will break English-translated games
39 -const BYTE *Filter(const BYTE *str, int len)
40 -{
41 -#ifdef ITH_DISABLE_FILTER // jichi 9/28/2013: only for debugging purpose
42 - return str;
43 -#endif // ITH_DISABLE_FILTER
44 -// if (len && *str == 0x10) // jichi 9/28/2013: garbage on wine, data link escape, or ^P
45 -// return nullptr;
46 - //enum { limit = 0x19 };
47 - while (true)
48 - if (len >= 2) {
49 - if (*(const WORD *)str <= _filter_limit) { // jichi 10/27/2013: two bytes
50 - str += 2;
51 - len -= 2;
52 - } else
53 - break;
54 - } else if (*str <= _filter_limit) { // jichi 10/27/2013: 1 byte
55 - str++;
56 - len--;
57 - } else
58 - break;
59 - return str;
60 -}
61 -} // unnamed namespace
62 -
63 -//WCHAR recv_pipe[] = L"\\??\\pipe\\ITH_PIPE";
64 -//WCHAR command_pipe[] = L"\\??\\pipe\\ITH_COMMAND";
65 -wchar_t recv_pipe[] = ITH_TEXT_PIPE;
66 -wchar_t command_pipe[] = ITH_COMMAND_PIPE;
67 -
68 -CRITICAL_SECTION detach_cs; // jichi 9/27/2013: also used in main
69 -//HANDLE hDetachEvent;
70 -extern HANDLE hPipeExist;
71 -
72 -void CreateNewPipe()
73 -{
74 - static DWORD acl[7] = {
75 - 0x1C0002,
76 - 1,
77 - 0x140000,
78 - GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
79 - 0x101,
80 - 0x1000000,
81 - 0};
82 - static SECURITY_DESCRIPTOR sd = {1, 0, 4, 0, 0, 0, (PACL)acl};
83 -
84 - HANDLE hTextPipe, hCmdPipe, hThread;
85 - IO_STATUS_BLOCK ios;
86 - UNICODE_STRING us;
87 -
88 - OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, &sd, 0};
89 - LARGE_INTEGER time = {-500000, -1};
90 -
91 - RtlInitUnicodeString(&us, recv_pipe);
92 - if (!NT_SUCCESS(NtCreateNamedPipeFile(
93 - &hTextPipe,
94 - GENERIC_READ | SYNCHRONIZE,
95 - &oa,
96 - &ios,
97 - FILE_SHARE_WRITE,
98 - FILE_OPEN_IF,
99 - FILE_SYNCHRONOUS_IO_NONALERT,
100 - 1, 1, 0, -1,
101 - 0x1000,
102 - 0x1000,
103 - &time))) {
104 - //ConsoleOutput(ErrorCreatePipe);
105 - ConsoleOutput("vnrhost:CreateNewPipe: failed to create recv pipe");
106 - return;
107 - }
108 -
109 - RtlInitUnicodeString(&us, command_pipe);
110 - if (!NT_SUCCESS(NtCreateNamedPipeFile(
111 - &hCmdPipe,
112 - GENERIC_WRITE | SYNCHRONIZE,
113 - &oa,
114 - &ios,
115 - FILE_SHARE_READ,
116 - FILE_OPEN_IF,
117 - FILE_SYNCHRONOUS_IO_NONALERT,
118 - 1, 1, 0, -1,
119 - 0x1000,
120 - 0x1000,
121 - &time))) {
122 - //ConsoleOutput(ErrorCreatePipe);
123 - ConsoleOutput("vnrhost:CreateNewPipe: failed to create cmd pipe");
124 - return;
125 - }
126 -
127 - hThread = IthCreateThread(RecvThread, (DWORD)hTextPipe);
128 - man->RegisterPipe(hTextPipe, hCmdPipe, hThread);
129 -}
130 -
131 -void DetachFromProcess(DWORD pid)
132 -{
133 - HANDLE hMutex = INVALID_HANDLE_VALUE,
134 - hEvent = INVALID_HANDLE_VALUE;
135 - //try {
136 - IO_STATUS_BLOCK ios;
137 - ProcessRecord *pr = man->GetProcessRecord(pid);
138 - if (!pr)
139 - return;
140 - //IthBreak();
141 - hEvent = IthCreateEvent(nullptr);
142 - if (STATUS_PENDING == NtFsControlFile(
143 - man->GetCmdHandleByPID(pid),
144 - hEvent,
145 - 0,0,
146 - &ios,
147 - CTL_CODE(FILE_DEVICE_NAMED_PIPE, NAMED_PIPE_DISCONNECT, 0, 0),
148 - 0,0,0,0))
149 - NtWaitForSingleObject(hEvent, 0, 0);
150 - NtClose(hEvent);
151 - //hEvent = INVALID_HANDLE_VALUE;
152 -
153 - WCHAR mutex[0x20];
154 - swprintf(mutex, ITH_DETACH_MUTEX_ L"%d", pid);
155 - hMutex = IthOpenMutex(mutex);
156 - if (hMutex != INVALID_HANDLE_VALUE) {
157 - NtWaitForSingleObject(hMutex, 0, 0);
158 - NtReleaseMutant(hMutex, 0);
159 - NtClose(hMutex);
160 - //hMutex = INVALID_HANDLE_VALUE;
161 - }
162 -
163 - //} catch (...) {
164 - // if (hEvent != INVALID_HANDLE_VALUE)
165 - // NtClose(hEvent);
166 - // else if (hMutex != INVALID_HANDLE_VALUE) {
167 - // NtWaitForSingleObject(hMutex, 0, 0);
168 - // NtReleaseMutant(hMutex, 0);
169 - // NtClose(hMutex);
170 - // }
171 - //}
172 -
173 - //NtSetEvent(hDetachEvent, 0);
174 - if (::running)
175 - NtSetEvent(hPipeExist, 0);
176 -}
177 -
178 -// jichi 9/27/2013: I don't need this
179 -//void OutputDWORD(DWORD d)
180 -//{
181 -// WCHAR str[0x20];
182 -// swprintf(str, L"%.8X", d);
183 -// ConsoleOutput(str);
184 -//}
185 -
186 -DWORD WINAPI RecvThread(LPVOID lpThreadParameter)
187 -{
188 - HANDLE hTextPipe = (HANDLE)lpThreadParameter;
189 -
190 - IO_STATUS_BLOCK ios;
191 - NtFsControlFile(hTextPipe,
192 - 0, 0, 0,
193 - &ios,
194 - CTL_CODE(FILE_DEVICE_NAMED_PIPE, NAMED_PIPE_CONNECT, 0, 0),
195 - 0, 0, 0, 0);
196 - if (!::running) {
197 - NtClose(hTextPipe);
198 - return 0;
199 - }
200 -
201 - BYTE *buff;
202 -
203 - enum { PipeBufferSize = 0x1000 };
204 - buff = new BYTE[PipeBufferSize];
205 - ITH_MEMSET_HEAP(buff, 0, PipeBufferSize); // jichi 8/27/2013: zero memory, or it will crash wine on start up
206 -
207 - // 10/19/2014 jichi: there are totally three words received
208 - // See: hook/rpc/pipe.cc
209 - // struct {
210 - // DWORD pid;
211 - // TextHook *man;
212 - // DWORD module;
213 - // //DWORD engine;
214 - // } u;
215 - enum { module_struct_size = 12 };
216 - NtReadFile(hTextPipe, 0, 0, 0, &ios, buff, module_struct_size, 0, 0);
217 -
218 - DWORD pid = *(DWORD *)buff,
219 - hookman = *(DWORD *)(buff + 0x4),
220 - module = *(DWORD *)(buff + 0x8);
221 - //engine = *(DWORD *)(buff + 0xc);
222 - man->RegisterProcess(pid, hookman, module);
223 -
224 - // jichi 9/27/2013: why recursion?
225 - CreateNewPipe();
226 -
227 - //NtClose(IthCreateThread(UpdateWindows,0));
228 - while (::running) {
229 - if (!NT_SUCCESS(NtReadFile(hTextPipe,
230 - 0, 0, 0,
231 - &ios,
232 - buff,
233 - 0xf80,
234 - 0, 0)))
235 - break;
236 -
237 - enum { data_offset = 0xc }; // jichi 10/27/2013: Seem to be the data offset in the pipe
238 -
239 - DWORD RecvLen = ios.uInformation;
240 - if (RecvLen < data_offset)
241 - break;
242 - DWORD hook = *(DWORD *)buff;
243 -
244 - union { DWORD retn; DWORD cmd_type; };
245 - union { DWORD split; DWORD new_engine_type; };
246 -
247 - retn = *(DWORD *)(buff + 4);
248 - split = *(DWORD *)(buff + 8);
249 -
250 - buff[RecvLen] = 0;
251 - buff[RecvLen + 1] = 0;
252 -
253 - if (hook == IHF_NOTIFICATION) {
254 - switch (cmd_type) {
255 - case IHF_NOTIFICATION_NEWHOOK:
256 - {
257 - static long lock;
258 - while (InterlockedExchange(&lock, 1) == 1);
259 - ProcessEventCallback new_hook = man->ProcessNewHook();
260 - if (new_hook)
261 - new_hook(pid);
262 - lock = 0;
263 - } break;
264 - case IHF_NOTIFICATION_TEXT:
265 - ConsoleOutput((LPCSTR)(buff + 8));
266 - break;
267 - }
268 - } else {
269 - // jichi 9/28/2013: Debug raw data
270 - //ITH_DEBUG_DWORD9(RecvLen - 0xc,
271 - // buff[0xc], buff[0xd], buff[0xe], buff[0xf],
272 - // buff[0x10], buff[0x11], buff[0x12], buff[0x13]);
273 -
274 - const BYTE *data = buff + data_offset; // th
275 - int len = RecvLen - data_offset;
276 - bool space = ::has_leading_space(data, len);
277 - if (space) {
278 - const BYTE *it = ::Filter(data, len);
279 - len -= it - data;
280 - data = it;
281 - }
282 - if (len >> 31) // jichi 10/27/2013: len is too large, which seldom happens
283 - len = 0;
284 - //man->DispatchText(pid, len ? data : nullptr, hook, retn, split, len, space);
285 - man->DispatchText(pid, data, hook, retn, split, len, space);
286 - }
287 - }
288 -
289 - EnterCriticalSection(&detach_cs);
290 -
291 - HANDLE hDisconnect = IthCreateEvent(nullptr);
292 -
293 - if (STATUS_PENDING == NtFsControlFile(
294 - hTextPipe,
295 - hDisconnect,
296 - 0, 0,
297 - &ios,
298 - CTL_CODE(FILE_DEVICE_NAMED_PIPE, NAMED_PIPE_DISCONNECT, 0, 0),
299 - 0, 0, 0, 0))
300 - NtWaitForSingleObject(hDisconnect, 0, 0);
301 -
302 - NtClose(hDisconnect);
303 - DetachFromProcess(pid);
304 - man->UnRegisterProcess(pid);
305 -
306 - //NtClearEvent(hDetachEvent);
307 -
308 - LeaveCriticalSection(&detach_cs);
309 - delete[] buff;
310 -
311 - if (::running)
312 - ConsoleOutput("vnrhost:DetachFromProcess: detached");
313 -
314 - //if (::running) {
315 - // swprintf((LPWSTR)buff, FormatDetach, pid);
316 - // ConsoleOutput((LPWSTR)buff);
317 - // NtClose(IthCreateThread(UpdateWindows, 0));
318 - //}
319 - return 0;
320 -}
321 -
322 -// EOF
1 -#pragma once
2 -
3 -// settings.h
4 -// 8/24/2013 jichi
5 -
6 -struct Settings {
7 - //bool debug; // whether output debug messages using pipes
8 - int splittingInterval;// time to split text into sentences
9 -
10 - Settings() : splittingInterval(200) {}
11 -
12 -};
13 -
14 -// EOF
1 -#pragma once
2 -
3 -// srv.h
4 -// 8/23/2013 jichi
5 -// Branch: ITH/IHF.h, rev 105
6 -
7 -#include "config.h"
8 -//#include "ith/host/settings.h"
9 -#include "ith/host/hookman.h"
10 -#include "ith/host/SettingManager.h"
11 -
12 -struct Settings;
13 -struct HookParam;
14 -
15 -// jichi 8/24/2013: Why extern "C"? Any specific reason to use C instead of C++ naming?
16 -extern "C" {
17 -IHFSERVICE DWORD IHFAPI IHF_Init();
18 -IHFSERVICE DWORD IHFAPI IHF_Start();
19 -IHFSERVICE DWORD IHFAPI IHF_Cleanup();
20 -IHFSERVICE DWORD IHFAPI IHF_GetPIDByName(LPCWSTR pwcTarget);
21 -IHFSERVICE DWORD IHFAPI IHF_InjectByPID(DWORD pid);
22 -IHFSERVICE DWORD IHFAPI IHF_ActiveDetachProcess(DWORD pid);
23 -IHFSERVICE DWORD IHFAPI IHF_GetHookManager(HookManager **hookman);
24 -IHFSERVICE DWORD IHFAPI IHF_GetSettingManager(SettingManager** set_man);
25 -IHFSERVICE DWORD IHFAPI IHF_GetSettings(Settings **settings);
26 -IHFSERVICE DWORD IHFAPI IHF_InsertHook(DWORD pid, HookParam *hp, LPCWSTR name = 0);
27 -IHFSERVICE DWORD IHFAPI IHF_ModifyHook(DWORD pid, HookParam *hp);
28 -IHFSERVICE DWORD IHFAPI IHF_RemoveHook(DWORD pid, DWORD addr);
29 -IHFSERVICE DWORD IHFAPI IHF_IsAdmin();
30 -//IHFSERVICE DWORD IHFAPI IHF_GetFilters(PVOID *mb_filter, PVOID *uni_filter);
31 -IHFSERVICE DWORD IHFAPI IHF_AddLink(DWORD from, DWORD to);
32 -IHFSERVICE DWORD IHFAPI IHF_UnLink(DWORD from);
33 -IHFSERVICE DWORD IHFAPI IHF_UnLinkAll(DWORD from);
34 -} // extern "C"
35 -
36 -// EOF
1 -#pragma once
2 -// srv_p.h
3 -// 8/24/2013 jichi
4 -// Branch IHF/main.h, rev 111
5 -#include "config.h"
6 -
7 -#define GLOBAL extern
8 -#define SHIFT_JIS 0x3A4
9 -class HookManager;
10 -//class CommandQueue;
11 -class SettingManager;
12 -class TextHook;
13 -//class BitMap;
14 -//class CustomFilterMultiByte;
15 -//class CustomFilterUnicode;
16 -//#define TextHook Hook
17 -GLOBAL BOOL running;
18 -//GLOBAL BitMap *pid_map;
19 -//GLOBAL CustomFilterMultiByte *mb_filter;
20 -//GLOBAL CustomFilterUnicode *uni_filter;
21 -GLOBAL HookManager *man;
22 -//GLOBAL CommandQueue *cmdq;
23 -GLOBAL SettingManager *setman;
24 -GLOBAL WCHAR recv_pipe[];
25 -GLOBAL WCHAR command[];
26 -GLOBAL HANDLE hPipeExist;
27 -GLOBAL DWORD split_time,
28 - cyclic_remove,
29 - clipboard_flag,
30 - global_filter;
31 -GLOBAL CRITICAL_SECTION detach_cs;
32 -
33 -DWORD WINAPI RecvThread(LPVOID lpThreadParameter);
34 -DWORD WINAPI CmdThread(LPVOID lpThreadParameter);
35 -
36 -void ConsoleOutput(LPCSTR text);
37 -void ConsoleOutputW(LPCWSTR text);
38 -DWORD GetCurrentPID();
39 -//DWORD GetProcessIDByPath(LPWSTR str);
40 -HANDLE GetCmdHandleByPID(DWORD pid);
41 -//DWORD Inject(HANDLE hProc);
42 -//DWORD InjectByPID(DWORD pid);
43 -//DWORD PIDByName(LPWSTR target);
44 -//DWORD Hash(LPCWSTR module, int length=-1);
45 -
46 -// EOF
1 -// textthread.cc
2 -// 8/24/2013 jichi
3 -// Branch IHF/TextThread.cpp, rev 133
4 -// 8/24/2013 TODO: Clean up this file
5 -
6 -#ifdef _MSC_VER
7 -# pragma warning (disable:4100) // C4100: unreference formal parameter
8 -#endif // _MSC_VER
9 -
10 -#include "config.h"
11 -#include "settings.h"
12 -#include "textthread.h"
13 -#include "ith/common/const.h"
14 -#include "ith/sys/sys.h"
15 -#include "SettingManager.h"
16 -
17 -MK_BASIC_TYPE(BYTE)
18 -MK_BASIC_TYPE(ThreadParameter)
19 -
20 -static DWORD MIN_DETECT = 0x20;
21 -static DWORD MIN_REDETECT = 0x80;
22 -//#define MIN_DETECT 0x20
23 -//#define MIN_REDETECT 0x80
24 -#ifndef CURRENT_SELECT
25 -# define CURRENT_SELECT 0x1000
26 -#endif
27 -#ifndef REPEAT_NUMBER_DECIDED
28 -# define REPEAT_NUMBER_DECIDED 0x2000
29 -#endif
30 -
31 -DWORD GetHookName(LPWSTR str, DWORD pid, DWORD hook_addr,DWORD max);
32 -
33 -extern SettingManager* setman;
34 -extern Settings *settings;
35 -extern HWND hMainWnd;
36 -void CALLBACK NewLineBuff(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
37 -{
38 - KillTimer(hwnd,idEvent);
39 - TextThread *id=(TextThread*)idEvent;
40 -
41 - if (id->Status()&CURRENT_SELECT)
42 - //texts->SetLine();
43 - id->CopyLastToClipboard();
44 - id->SetNewLineFlag();
45 -}
46 -
47 -// jichi 10/27/2013: removed
48 -//void CALLBACK NewLineConsole(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
49 -//{
50 -// KillTimer(hwnd,idEvent);
51 -// TextThread *id=(TextThread*)idEvent;
52 -// if (id->Status()&USING_UNICODE)
53 -// id->AddText((BYTE*)L"\r\n",4,true,true);
54 -// if (id->Status()&CURRENT_SELECT)
55 -// {
56 -// //texts->SetLine();
57 -// }
58 -//}
59 -
60 -// jichi 10/27/2013: removed
61 -//void ReplaceSentence(BYTE* text, int len)
62 -//{
63 -// __asm int 3
64 -//}
65 -
66 -TextThread::TextThread(DWORD id, DWORD hook, DWORD retn, DWORD spl, WORD num) :
67 - //,tp
68 - thread_number(num)
69 - // jichi 9/21/2013: zero all fields
70 - , link_number(-1)
71 - , last (0)
72 - , align_space(0)
73 - , repeat_single(0)
74 - , repeat_single_current(0)
75 - , repeat_single_count(0)
76 - , repeat_detect_count(0)
77 - , head(new RepeatCountNode())
78 - , link(nullptr)
79 - //, filter(nullptr)
80 - , output(nullptr)
81 - , app_data(nullptr)
82 - //, comment(nullptr)
83 - , thread_string(nullptr)
84 - , timer(0)
85 - , status (0)
86 - , repeat_detect_limit(0x80)
87 - , last_sentence(0)
88 - , prev_sentence(0)
89 - , sentence_length(0)
90 - , repeat_index(0)
91 - , last_time(0)
92 -// , tp({id, hook, retn, spl})
93 -{
94 - tp.pid = id;
95 - tp.hook = hook;
96 - tp.retn = retn;
97 - tp.spl = spl;
98 - //head = new RepeatCountNode;
99 - //ITH_MEMSET_HEAP(head, 0, sizeof(RepeatCountNode)); // jichi 9/21/2013: zero memory
100 - //link_number = -1;
101 - //repeat_detect_limit = 0x80;
102 - //filter = nullptr;
103 - //output = nullptr;
104 -}
105 -TextThread::~TextThread()
106 -{
107 - //KillTimer(hMainWnd,timer);
108 - RepeatCountNode *t = head,
109 - *tt;
110 - while (t) {
111 - tt = t;
112 - t = tt->next;
113 - delete tt;
114 - }
115 - head = nullptr;
116 - //if (comment) {
117 - // delete[] comment;
118 - // comment = nullptr;
119 - //}
120 - if (thread_string)
121 - delete[] thread_string;
122 -}
123 -void TextThread::Reset()
124 -{
125 - //timer=0;
126 - last_sentence = 0;
127 - //if (comment) {
128 - // delete[] comment;
129 - // comment = nullptr;
130 - //}
131 - MyVector::Reset();
132 -}
133 -void TextThread::RemoveSingleRepeatAuto(const BYTE *con, int &len)
134 -{
135 -#ifdef ITH_DISABLE_REPEAT // jichi 9/28/2013: only for debugging purpose
136 - return;
137 -#endif // ITH_DISABLE_REPEAT
138 - WORD *text = (WORD *)con;
139 - if (len <= 2) {
140 - if (repeat_single) {
141 - if (repeat_single_count<repeat_single&&
142 - last == *text) {
143 - len = 0;
144 - repeat_single_count++;
145 - } else {
146 - last = *text;
147 - repeat_single_count=0;
148 - }
149 - }
150 - if (status & REPEAT_NUMBER_DECIDED) {
151 - if (++repeat_detect_count>MIN_REDETECT) {
152 - repeat_detect_count = 0;
153 - status ^= REPEAT_NUMBER_DECIDED;
154 - last = 0;
155 - RepeatCountNode *t = head,
156 - *tt;
157 - while (t) {
158 - tt = t;
159 - t = tt->next;
160 - delete tt;
161 - }
162 - head = new RepeatCountNode;
163 - ITH_MEMSET_HEAP(head, 0, sizeof(RepeatCountNode)); // jichi 9/21/2013: zero memory
164 - }
165 - } else {
166 - repeat_detect_count++;
167 - if (last == *text)
168 - repeat_single_current++;
169 - else {
170 - if (last == 0) {
171 - last = *text;
172 - return;
173 - }
174 - if (repeat_single_current == 0) {
175 - status |= REPEAT_NUMBER_DECIDED;
176 - repeat_single = 0;
177 - return;
178 - }
179 - last = *text;
180 - RepeatCountNode *it = head;
181 - if (repeat_detect_count > MIN_DETECT) {
182 - while (it = it->next)
183 - if (it->count>head->count) {
184 - head->count=it->count;
185 - head->repeat=it->repeat;
186 - }
187 - repeat_single = head->repeat;
188 - repeat_single_current = 0;
189 - repeat_detect_count = 0;
190 - status |= REPEAT_NUMBER_DECIDED;
191 - DWORD repeat_sc = repeat_single*4;
192 - if (repeat_sc > MIN_DETECT) {
193 - MIN_DETECT <<= 1;
194 - MIN_REDETECT <<= 1;
195 - }
196 - } else {
197 - bool flag=true;
198 - while (it) {
199 - if (it->repeat == repeat_single_current) {
200 - it->count++;
201 - flag = false;
202 - break;
203 - }
204 - it=it->next;
205 - }
206 - if (flag) {
207 - RepeatCountNode *n = new RepeatCountNode;
208 - n->count = 1;
209 - n->repeat = repeat_single_current;
210 - n->next = head->next;
211 - head->next = n;
212 - }
213 - repeat_single_current = 0;
214 - } //Decide repeat_single
215 - } //Check Repeat
216 - } //repeat_single decided?
217 - } //len
218 - else {
219 - status |= REPEAT_NUMBER_DECIDED;
220 - repeat_single = 0;
221 - }
222 -}
223 -
224 -void TextThread::RemoveSingleRepeatForce(BYTE *con,int &len)
225 -{
226 - // jichi 9/1/2013: manual repetition count removed
227 - WORD *text = (WORD *)con;
228 - //if (repeat_single_count<setman->GetValue(SETTING_REPEAT_COUNT)&&last==*text) {
229 - // len=0;
230 - // repeat_single_count++;
231 - //}
232 - //else
233 - {
234 - last = *text;
235 - repeat_single_count=0;
236 - }
237 -}
238 -void TextThread::RemoveCyclicRepeat(BYTE* &con, int &len)
239 -{
240 - DWORD currnet_time = GetTickCount();
241 - if (status & REPEAT_SUPPRESS) {
242 - if (currnet_time - last_time < (unsigned)settings->splittingInterval &&
243 - ::memcmp(storage + last_sentence + repeat_index, con, len) == 0) {
244 - repeat_index += len;
245 - if (repeat_index>=sentence_length)
246 - repeat_index -= sentence_length;
247 - len = 0;
248 - } else {
249 - repeat_index = 0;
250 - status &= ~REPEAT_SUPPRESS;
251 - }
252 - } else if (status & REPEAT_DETECT) {
253 - if (::memcmp(storage + last_sentence + repeat_index, con, len) == 0) {
254 - int half_length=repeat_index+len;
255 - if (::memcmp(storage + last_sentence, storage + last_sentence + half_length, repeat_index) == 0) {
256 - len=0;
257 - sentence_length=half_length;
258 - status&=~REPEAT_DETECT;
259 - status|=REPEAT_SUPPRESS;
260 -
261 - // jichi 10/27/2013: Not used
262 - //if (status&CURRENT_SELECT)
263 - // ReplaceSentence(storage+last_sentence+half_length,repeat_index);
264 - ClearMemory(last_sentence+half_length,repeat_index);
265 - used-=repeat_index;
266 - repeat_index=0;
267 - }
268 - else
269 - repeat_index += len;
270 - }
271 - else {
272 - repeat_index=0;
273 - status &= ~REPEAT_DETECT;
274 - }
275 - } else {
276 - if (sentence_length == 0)
277 - return;
278 - else if (len <= (int)sentence_length) {
279 - if (memcmp(storage + last_sentence, con, len) == 0) {
280 - status |= REPEAT_DETECT;
281 - repeat_index = len;
282 - if (repeat_index == sentence_length) {
283 - repeat_index = 0;
284 - len = 0;
285 - }
286 - } else if (sentence_length > repeat_detect_limit) {
287 - if (len > 2) {
288 - DWORD u = used;
289 - while (memcmp(storage + u - len, con, len) == 0)
290 - u -= len;
291 - ClearMemory(u, used - u);
292 - used = u;
293 - repeat_index = 0;
294 - // jichi 10/27/2013: Not used
295 - //if (status & CURRENT_SELECT)
296 - // ReplaceSentence(storage + last_sentence, used - u);
297 - status |= REPEAT_SUPPRESS;
298 - len = 0;
299 - } else if (len <= 2)
300 - {
301 - WORD tmp = *(WORD *)(storage + last_sentence);
302 - DWORD index, last_index, tmp_len;
303 - index = used-len;
304 - if (index < last_sentence)
305 - index = last_sentence;
306 - //Locate position of current input.
307 -_again:
308 - *(WORD *)(storage+last_sentence) = *(WORD *)con;
309 - while (*(WORD *)(storage + index) != *(WORD *)con)
310 - index--;
311 - *(WORD *)(storage + last_sentence) = tmp;
312 - if (index > last_sentence) {
313 - tmp_len = used - index;
314 - if (tmp_len <= 2) {
315 - repeat_detect_limit += 0x40;
316 - last_time = currnet_time;
317 - return;
318 - }
319 - if (index - last_sentence >= tmp_len &&
320 - memcmp(storage + index - tmp_len, storage + index, tmp_len) == 0) {
321 - repeat_detect_limit = 0x80;
322 - sentence_length =tmp_len;
323 - index -= tmp_len;
324 - while (memcmp(storage + index - sentence_length, storage + index, sentence_length) == 0)
325 - index -= sentence_length;
326 - repeat_index = 2;
327 - len = 0;
328 - last_index = index;
329 - if (status&USING_UNICODE) {
330 - while (storage[index] == storage[index + sentence_length])
331 - index -= 2;
332 - index += 2;
333 - while (true) {
334 - tmp = *(WORD *)(storage + index);
335 - if (tmp >= 0x3000 && tmp < 0x3020)
336 - index += 2;
337 - else
338 - break;
339 - }
340 - } else {
341 - DWORD last_char_len;
342 - while (storage[index] == storage[index + sentence_length]) {
343 - last_char_len = LeadByteTable[storage[index]];
344 - index -= last_char_len;
345 - }
346 - index += last_char_len;
347 - while (storage[index] == 0x81) {
348 - if ((storage[index+1]>>4) == 4)
349 - index += 2;
350 - else
351 - break;
352 - }
353 - }
354 - repeat_index += last_index - index;
355 - status |= REPEAT_SUPPRESS;
356 - last_sentence = index;
357 -
358 - index += sentence_length;
359 - // jichi 10/27/2013: Not used
360 - //if (status&CURRENT_SELECT)
361 - // ReplaceSentence(storage + index, used - index);
362 -
363 - ClearMemory(index, used - index);
364 - //memset(storage + index, 0, used - index);
365 - used = index;
366 - } else {
367 - index--;
368 - goto _again;
369 - }
370 - }
371 - else
372 - repeat_detect_limit += 0x40;
373 - }
374 - }
375 - }
376 - }
377 - last_time = currnet_time;
378 -}
379 -
380 -void TextThread::ResetRepeatStatus()
381 -{
382 - last=0;
383 - repeat_single=0;
384 - repeat_single_current=0;
385 - repeat_single_count=0;
386 - repeat_detect_count=0;
387 - RepeatCountNode *t = head->next,
388 - *tt;
389 - while (t) {
390 - tt = t;
391 - t = tt->next;
392 - delete tt;
393 - }
394 - //head=new RepeatCountNode;
395 - head->count = head->repeat = 0;
396 - status &= ~REPEAT_NUMBER_DECIDED;
397 -}
398 -void TextThread::AddLineBreak()
399 -{
400 - if (sentence_length == 0) return;
401 - if (status&BUFF_NEWLINE)
402 - {
403 - prev_sentence=last_sentence;
404 - sentence_length=0;
405 - if (status & USING_UNICODE)
406 - AddToStore((BYTE *)L"\r\n\r\n", 8);
407 - else
408 - AddToStore((BYTE *)"\r\n\r\n", 4);
409 - if (output)
410 - output(this, 0, 8, TRUE, app_data, false); // jichi 10/27/2013: space is false
411 - last_sentence = used;
412 - status &= ~BUFF_NEWLINE;
413 - }
414 -}
415 -void TextThread::AddText(const BYTE *con, int len, bool new_line, bool space)
416 -{
417 - if (!con || (len <= 0 && !space))
418 - return;
419 - if (len && !new_line) {
420 - // jichi 9/1/2013: manual repetition count removed
421 - //if (setman->GetValue(SETTING_REPEAT_COUNT)) {
422 - // status|=REPEAT_NUMBER_DECIDED;
423 - // RemoveSingleRepeatForce(con,len);
424 - //}
425 - //else
426 - RemoveSingleRepeatAuto(con, len);
427 - if (len <= 0 && !space)
428 - return;
429 - }
430 -
431 - // jichi 9/1/2013: manual repetition count removed
432 - //if(setman->GetValue(SETTING_CYCLIC_REMOVE)) {
433 - // //if (status & REPEAT_NUMBER_DECIDED)
434 - // RemoveCyclicRepeat(con,len);
435 - //}
436 - //if (len <= 0)
437 - // return;
438 -
439 - // jichi 10/27/2013: User-defined filter callback is disabled
440 - //if (filter)
441 - // len = filter(this, con,len, new_line, app_data);
442 - //if (len <= 0)
443 - // return;
444 -
445 - if (len && sentence_length == 0) {
446 - if (status & USING_UNICODE) {
447 - if (*(WORD *)con == 0x3000) { // jichi 10/27/2013: why skip unicode space?!
448 - con += 2;
449 - len -= 2;
450 - }
451 - } else if (*(WORD *)con == 0x4081) {
452 - con += 2;
453 - len -= 2;
454 - }
455 -
456 - if (len <= 0 && !space)
457 - return;
458 - }
459 -
460 - if (status & BUFF_NEWLINE)
461 - AddLineBreak();
462 -
463 - if (len)
464 - if (new_line) {
465 - prev_sentence = last_sentence;
466 - last_sentence = used + 4;
467 - if (status & USING_UNICODE)
468 - last_sentence += 4;
469 - sentence_length = 0;
470 - } else {
471 - SetNewLineTimer();
472 - if (link) {
473 - const BYTE *send = con;
474 - int l = len;
475 - if (status & USING_UNICODE) { // Although unlikely, a thread and its link may have different encoding.
476 - if ((link->Status() & USING_UNICODE) == 0) {
477 - send = new BYTE[l];
478 - //ITH_MEMSET_HEAP(send, 0, l); // jichi 9/26/2013: zero memory
479 - l = WC_MB((LPWSTR)con, (char *)send);
480 - }
481 - link->AddTextDirect(send, l, space);
482 - } else {
483 - if (link->Status() & USING_UNICODE) {
484 - size_t sz = len * 2 + 2;
485 - send = new BYTE[sz];
486 - //ITH_MEMSET_HEAP(send, 0, sz); // jichi 9/26/2013: zero memory
487 - l = MB_WC((char *)con, (LPWSTR)send) << 1;
488 - }
489 - link->AddTextDirect(send, l, space);
490 - }
491 - link->SetNewLineTimer();
492 - if (send != con)
493 - delete[] send;
494 - }
495 - sentence_length += len;
496 - }
497 -
498 - BYTE *data = const_cast<BYTE *>(con); // jichi 10/27/2013: TODO: Figure out where con is modified
499 - if (output)
500 - len = output(this, data, len, new_line, app_data, space);
501 - if (AddToStore(data, len)) {
502 - //sentence_length += len;
503 - /*ResetRepeatStatus();
504 - last_sentence=0;
505 - prev_sentence=0;
506 - sentence_length=len;
507 - repeat_index=0;
508 - status&=~REPEAT_DETECT|REPEAT_SUPPRESS; */
509 - }
510 -}
511 -
512 -void TextThread::AddTextDirect(const BYTE* con, int len, bool space) // Add to store directly, penetrating repetition filters.
513 -{
514 - // jichi 10/27/2013: Accordig to the logic, both len and con must be > 0
515 - if (status & BUFF_NEWLINE)
516 - AddLineBreak();
517 - SetNewLineTimer();
518 - if (link) {
519 - const BYTE *send = con;
520 - int l = len;
521 - if (status & USING_UNICODE) {
522 - if ((link->Status()&USING_UNICODE) == 0) {
523 - send = new BYTE[l];
524 - //ITH_MEMSET_HEAP(send, 0, l); // jichi 9/26/2013: zero memory
525 - l = WC_MB((LPWSTR)con,(char*)send);
526 - }
527 - link->AddText(send, l, false, space); // new_line is false
528 - } else {
529 - if (link->Status()&USING_UNICODE) {
530 - size_t sz = len * 2 + 2;
531 - send = new BYTE[sz];
532 - //ITH_MEMSET_HEAP(send, 0, sz); // jichi 9/26/2013: zero memory
533 - l = MB_WC((char *)con, (LPWSTR)send) << 1;
534 - }
535 - link->AddText(send, l, false, space); // new_line is false
536 - }
537 - link->SetNewLineTimer();
538 - if (send != con)
539 - delete[] send;
540 - }
541 - sentence_length += len;
542 -
543 - BYTE *data = const_cast<BYTE *>(con); // jichi 10/27/2013: TODO: Figure out where con is modified
544 - if (output)
545 - len = output(this, data, len, false, app_data, space);
546 - AddToStore(data, len);
547 -}
548 -
549 -DWORD TextThread::GetEntryString(LPWSTR str, DWORD max)
550 -{
551 - DWORD len = 0;
552 - if (str && max > 0x40) {
553 - max--;
554 - if (thread_string) {
555 - len = wcslen(thread_string);
556 - len = len < max ? len : max;
557 - memcpy(str, thread_string, len << 1);
558 - str[len] = 0;
559 -
560 - } else {
561 - len = swprintf(str, L"%.4X:%.4d:0x%08X:0x%08X:0x%08X:",
562 - thread_number, tp. pid, tp.hook, tp.retn, tp.spl);
563 -
564 - len += GetHookName(str + len, tp.pid, tp.hook, max - len);
565 - thread_string = new wchar_t[len + 1];
566 - //ITH_MEMSET_HEAP(thread_string, 0, (len+1) * sizeof(wchar_t)); // jichi 9/26/2013: zero memory
567 - thread_string[len] = 0;
568 - memcpy(thread_string, str, len * sizeof(wchar_t));
569 - }
570 - //if (comment) {
571 - // str += len;
572 - // max--;
573 - // DWORD cl = wcslen(comment);
574 - // if (len + cl >= max)
575 - // cl = max - len;
576 - // *str++ = L'-';
577 - // memcpy(str, comment, cl << 1);
578 - // str[cl] = 0;
579 - // len += cl;
580 - //}
581 - }
582 - return len;
583 -}
584 -// jichi 9/28/2013: removed
585 -//void TextThread::CopyLastSentence(LPWSTR str)
586 -//{
587 -// int i,j,l;
588 -// if (status&USING_UNICODE)
589 -// {
590 -// if (used>8)
591 -// {
592 -// j=used>0xF0?(used-0xF0):0;
593 -// for (i=used-0xA;i>=j;i-=2)
594 -// {
595 -// if (*(DWORD*)(storage+i)==0xA000D) break;
596 -// }
597 -// if (i>=j)
598 -// {
599 -// l=used-i;
600 -// if (i>j) l-=4;
601 -// j=4;
602 -// }
603 -// else
604 -// {
605 -// i+=2;
606 -// l=used-i;
607 -// j=0;
608 -// }
609 -// memcpy(str,storage+i+j,l);
610 -// str[l>>1]=0;
611 -// }
612 -// else
613 -// {
614 -// memcpy(str,storage,used);
615 -// str[used>>1]=0;
616 -// }
617 -// }
618 -// else
619 -// {
620 -// if (used>4)
621 -// {
622 -// j=used>0x80?(used-0x80):0;
623 -// for (i=used-5;i>=j;i--)
624 -// {
625 -// if (*(DWORD*)(storage+i)==0xA0D0A0D) break;
626 -// }
627 -// if (i>=j)
628 -// {
629 -// l=used-i;
630 -// if (i>j) l-=4;
631 -// j=4;
632 -// }
633 -// else
634 -// {
635 -// i++;
636 -// l=used-i;
637 -// j=0;
638 -// }
639 -// size_t sz = (l|0xF) + 1;
640 -// char *buff = new char[sz];
641 -// //memset(buff, 0, sz); // jichi 9/26/2013: zero memory
642 -// memcpy(buff, storage + i + j, l);
643 -// buff[l] = 0;
644 -// str[MB_WC(buff, str)] = 0;
645 -// delete[] buff;
646 -// } else {
647 -// storage[used] = 0;
648 -// str[MB_WC((char *)storage, str)] = 0;
649 -// }
650 -// }
651 -//}
652 -
653 -static char clipboard_buffer[0x400];
654 -// jichi 8/25/2013: clipboard removed
655 -void CopyToClipboard(void* str,bool unicode, int len)
656 -{
657 - if (setman->GetValue(SETTING_CLIPFLAG) && str && len > 0)
658 - {
659 - int size=(len*2|0xF)+1;
660 - if (len>=1022) return;
661 - memcpy(clipboard_buffer,str,len);
662 - *(WORD*)(clipboard_buffer+len)=0;
663 - HGLOBAL hCopy;
664 - LPWSTR copy;
665 - if (OpenClipboard(0))
666 - {
667 - if (hCopy=GlobalAlloc(GMEM_MOVEABLE,size))
668 - {
669 - if (copy=(LPWSTR)GlobalLock(hCopy))
670 - {
671 - if (unicode)
672 - {
673 - memcpy(copy,clipboard_buffer,len+2);
674 - }
675 - else
676 - copy[MB_WC(clipboard_buffer,copy)]=0;
677 - GlobalUnlock(hCopy);
678 - EmptyClipboard();
679 - SetClipboardData(CF_UNICODETEXT,hCopy);
680 - }
681 - }
682 - CloseClipboard();
683 - }
684 - }
685 -}
686 -void TextThread::CopyLastToClipboard()
687 -{
688 - // jichi 8/25/2013: clipboard removed
689 - CopyToClipboard(storage+last_sentence,(status&USING_UNICODE)>0,used-last_sentence);
690 -}
691 -
692 -//void TextThread::ResetEditText()
693 -//{
694 -// //__asm int 3;
695 -// WCHAR str[0x20];
696 -// swprintf(str,L"%.8X",_ReturnAddress());
697 -//}
698 -
699 -// jichi 9/25/2013: Removed
700 -//void TextThread::ExportTextToFile(LPWSTR) //filename)
701 -//{
702 -// HANDLE hFile=IthCreateFile(filename,FILE_WRITE_DATA,0,FILE_OPEN_IF);
703 -// if (hFile==INVALID_HANDLE_VALUE) return;
704 -// EnterCriticalSection(&cs_store);
705 -// IO_STATUS_BLOCK ios;
706 -// LPVOID buffer=storage;
707 -// DWORD len=used;
708 -// BYTE bom[4]={0xFF,0xFE,0,0};
709 -// LARGE_INTEGER offset={2,0};
710 -// if ((status&USING_UNICODE)==0)
711 -// {
712 -// len=MB_WC_count((char*)storage,used);
713 -// buffer = new wchar_t[len+1];
714 -// MB_WC((char*)storage,(wchar_t*)buffer);
715 -// len<<=1;
716 -// }
717 -// NtWriteFile(hFile,0,0,0,&ios,bom,2,0,0);
718 -// NtWriteFile(hFile,0,0,0,&ios,buffer,len,&offset,0);
719 -// NtFlushBuffersFile(hFile,&ios);
720 -// if (buffer !=storage)
721 -// delete[] buffer;
722 -// NtClose(hFile);
723 -// LeaveCriticalSection(&cs_store);
724 -//}
725 -
726 -//void TextThread::SetComment(LPWSTR str)
727 -//{
728 -// if (comment)
729 -// delete[] comment;
730 -// size_t sz = wcslen(str);
731 -// comment = new wchar_t[sz + 1];
732 -// comment[sz] = 0;
733 -// wcscpy(comment, str);
734 -//}
735 -
736 -void TextThread::SetNewLineFlag() { status |= BUFF_NEWLINE; }
737 -
738 -bool TextThread::CheckCycle(TextThread* start)
739 -{
740 - if (link==start||this==start) return true;
741 - if (link==0) return false;
742 - return link->CheckCycle(start);
743 -}
744 -void TextThread::SetNewLineTimer()
745 -{
746 - if (thread_number == 0)
747 - // jichi 10/27/2013: Not used
748 - timer = 0; //SetTimer(hMainWnd,(UINT_PTR)this, settings->splittingInterval, NewLineConsole);
749 - else
750 - timer = SetTimer(hMainWnd,(UINT_PTR)this, settings->splittingInterval, NewLineBuff);
751 -}
752 -
753 -DWORD TextThread::GetThreadString(LPWSTR str, DWORD max)
754 -{
755 - DWORD len = 0;
756 - if (max) {
757 - wchar_t buffer[0x200];
758 - wchar_t c;
759 - if (thread_string == nullptr)
760 - GetEntryString(buffer, 0x200); //This will allocate thread_string.
761 - LPWSTR p1,
762 - end;
763 - for (end = thread_string; *end; end++);
764 - c = thread_string[0];
765 - thread_string[0] = L':';
766 - for (p1 = end; *p1 != L':'; p1--);
767 - thread_string[0] = c;
768 - if (p1 == thread_string)
769 - return 0;
770 - p1++;
771 - len = end - p1;
772 - if (len >= max)
773 - len = max;
774 - memcpy(str, p1, len << 1);
775 - str[len] = 0;
776 - }
777 -
778 - return len;
779 -}
780 -void TextThread::UnLinkAll()
781 -{
782 - if (link) link->UnLinkAll();
783 - link = 0;
784 - link_number = -1;
785 -}
786 -
787 -// EOF
1 -#pragma once
2 -
3 -// textthread.h
4 -// 8/23/2013 jichi
5 -// Branch: ITH/TextThread.h, rev 120
6 -
7 -#include "ith/host/textthread_p.h"
8 -#include <intrin.h> // require _InterlockedExchange
9 -
10 -struct RepeatCountNode {
11 - short repeat;
12 - short count;
13 - RepeatCountNode *next;
14 -
15 - //RepeatCountNode() : repeat(0), count(0), next(nullptr) {}
16 -};
17 -
18 -struct ThreadParameter {
19 - DWORD pid; // jichi: 5/11/2014: The process ID
20 - DWORD hook;
21 - DWORD retn; // jichi 5/11/2014: The return address of the hook
22 - DWORD spl; // jichi 5/11/2014: the processed split value of the hook parameter
23 -};
24 -
25 -#define CURRENT_SELECT 0x1000
26 -#define REPEAT_NUMBER_DECIDED 0x2000
27 -#define BUFF_NEWLINE 0x4000
28 -#define CYCLIC_REPEAT 0x8000
29 -#define COUNT_PER_FOWARD 0x200
30 -#define REPEAT_DETECT 0x10000
31 -#define REPEAT_SUPPRESS 0x20000
32 -#define REPEAT_NEWLINE 0x40000
33 -
34 -class TextThread;
35 -typedef void (* ConsoleCallback)(LPCSTR text);
36 -typedef void (* ConsoleWCallback)(LPCWSTR text);
37 -typedef DWORD (* ThreadOutputFilterCallback)(TextThread *, BYTE *, DWORD, DWORD, PVOID, bool space); // jichi 10/27/2013: Add space
38 -typedef DWORD (* ThreadEventCallback)(TextThread *);
39 -
40 -//extern DWORD split_time,repeat_count,global_filter,cyclic_remove;
41 -
42 -class TextThread : public MyVector<BYTE, 0x200>
43 -{
44 -public:
45 - TextThread(DWORD pid, DWORD hook, DWORD retn, DWORD spl, WORD num);
46 - ~TextThread();
47 - //virtual void CopyLastSentence(LPWSTR str);
48 - //virtual void SetComment(LPWSTR);
49 - //virtual void ExportTextToFile(LPWSTR filename);
50 -
51 - virtual bool CheckCycle(TextThread *start);
52 - virtual DWORD GetThreadString(LPWSTR str, DWORD max);
53 - virtual DWORD GetEntryString(LPWSTR str, DWORD max = 0x200);
54 -
55 - void Reset();
56 - void AddText(const BYTE *con,int len, bool new_line, bool space); // jichi 10/27/2013: add const; remove console; add space
57 - void RemoveSingleRepeatAuto(const BYTE *con, int &len); // jichi 10/27/2013: add const
58 - void RemoveSingleRepeatForce(BYTE *con, int &len);
59 - void RemoveCyclicRepeat(BYTE *&con, int &len);
60 - void ResetRepeatStatus();
61 - void AddLineBreak();
62 - //void ResetEditText();
63 - void ComboSelectCurrent();
64 - void UnLinkAll();
65 - void CopyLastToClipboard();
66 -
67 - //void AdjustPrevRepeat(DWORD len);
68 - //void PrevRepeatLength(DWORD &len);
69 -
70 - //bool AddToCombo();
71 - bool RemoveFromCombo();
72 -
73 - void SetNewLineFlag();
74 - void SetNewLineTimer();
75 -
76 - BYTE *GetStore(DWORD *len) { if (len) *len = used; return storage; }
77 - DWORD LastSentenceLen() { return used - last_sentence; }
78 - DWORD PID() const { return tp.pid; }
79 - DWORD Addr() const {return tp.hook; }
80 - DWORD &Status() { return status; }
81 - WORD Number() const { return thread_number; }
82 - WORD &Last() { return last; }
83 - WORD &LinkNumber() { return link_number; }
84 - UINT_PTR &Timer() { return timer; }
85 - ThreadParameter *GetThreadParameter() { return &tp; }
86 - TextThread *&Link() { return link; }
87 - //LPCWSTR GetComment() { return comment; }
88 -
89 - ThreadOutputFilterCallback RegisterOutputCallBack(ThreadOutputFilterCallback cb, PVOID data)
90 - {
91 - app_data = data;
92 - return (ThreadOutputFilterCallback)_InterlockedExchange((long*)&output,(long)cb);
93 - }
94 -
95 - ThreadOutputFilterCallback RegisterFilterCallBack(ThreadOutputFilterCallback cb, PVOID data)
96 - {
97 - app_data = data;
98 - return (ThreadOutputFilterCallback)_InterlockedExchange((long*)&filter,(long)cb);
99 - }
100 -
101 - void SetRepeatFlag() { status |= CYCLIC_REPEAT; }
102 - void ClearNewLineFlag() { status &= ~BUFF_NEWLINE; }
103 - void ClearRepeatFlag() { status &= ~CYCLIC_REPEAT; }
104 -
105 -protected:
106 - void AddTextDirect(const BYTE *con, int len, bool space); // jichi 10/27/2013: add const; add space; change to protected
107 -
108 -private:
109 - ThreadParameter tp;
110 -
111 - WORD thread_number,
112 - link_number;
113 - WORD last,
114 - align_space;
115 - WORD repeat_single;
116 - WORD repeat_single_current;
117 - WORD repeat_single_count;
118 - WORD repeat_detect_count;
119 - RepeatCountNode *head;
120 -
121 - TextThread *link;
122 - ThreadOutputFilterCallback filter; // jichi 10/27/2013: Remove filter
123 - ThreadOutputFilterCallback output;
124 - PVOID app_data;
125 - //LPWSTR comment,
126 - LPWSTR thread_string;
127 - UINT_PTR timer;
128 - DWORD status,repeat_detect_limit;
129 - DWORD last_sentence,
130 - prev_sentence,
131 - sentence_length,
132 - repeat_index,
133 - last_time;
134 -};
135 -
136 -// EOF
1 -#pragma once
2 -// textthread_p.h
3 -// 8/14/2013 jichi
4 -// Branch: ITH/main_template.h, rev 66
5 -
6 -#include "config.h"
7 -
8 -template <typename T>
9 -void Release(const T &p) { delete p; }
10 -
11 -// Prevent memory release.
12 -// Used when T is basic types and will be automatically released (on stack).
13 -#define MK_BASIC_TYPE(T) \
14 - template<> \
15 - void Release<T>(const T &p) {}
16 -
17 -template<class T>
18 -struct BinaryEqual {
19 - bool operator ()(const T &a, const T &b, DWORD) { return a == b; }
20 -};
21 -
22 -template<class T, int default_size, class fComp=BinaryEqual<T> >
23 -class MyVector
24 -{
25 -public:
26 - MyVector() : size(default_size), used(0)
27 - {
28 - InitializeCriticalSection(&cs_store);
29 - storage = new T[size];
30 - // jichi 9/21/2013: zero memory
31 - // This would cause trouble if T is not an atomic type
32 - ITH_MEMSET_HEAP(storage, 0, sizeof(T) * size);
33 - }
34 -
35 - virtual ~MyVector()
36 - {
37 - if (storage)
38 - delete[] storage;
39 - DeleteCriticalSection(&cs_store);
40 - storage = 0;
41 - }
42 -
43 - void Reset()
44 - {
45 - EnterCriticalSection(&cs_store);
46 - for (int i = 0; i < used; i++) {
47 - Release<T>(storage[i]);
48 - storage[i] = T();
49 - }
50 - used = 0;
51 - LeaveCriticalSection(&cs_store);
52 - }
53 - void Remove(int index)
54 - {
55 - if (index>=used)
56 - return;
57 - Release<T>(storage[index]);
58 - for (int i = index; i < used; i++)
59 - storage[i] = storage[i+1];
60 - used--;
61 - }
62 - void ClearMemory(int offset, int clear_size)
63 - {
64 - if (clear_size < 0)
65 - return;
66 - EnterCriticalSection(&cs_store);
67 - if (offset+clear_size <= size)
68 - memset(storage+offset, 0, clear_size * sizeof(T)); // jichi 11/30/2013: This is the original code of ITH
69 - LeaveCriticalSection(&cs_store);
70 - //else __asm int 3
71 - }
72 - int AddToStore(T *con,int amount)
73 - {
74 - if (amount <= 0 || con == 0)
75 - return 0;
76 - int status = 0;
77 - EnterCriticalSection(&cs_store);
78 - if (amount + used + 2 >= size) {
79 - while (amount + used + 2 >= size)
80 - size<<=1;
81 - T *temp;
82 - if (size * sizeof(T) < 0x1000000) {
83 - temp = new T[size];
84 - if (size > used)
85 - ITH_MEMSET_HEAP(temp, 0, (size - used) * sizeof(T)); // jichi 9/25/2013: zero memory
86 - memcpy(temp, storage, used * sizeof(T));
87 - } else {
88 - size = default_size;
89 - temp = new T[size];
90 - ITH_MEMSET_HEAP(temp, 0, sizeof(T) * size); // jichi 9/25/2013: zero memory
91 - used = 0;
92 - status = 1;
93 - }
94 - delete[] storage;
95 - storage = temp;
96 - }
97 - memcpy(storage+used, con, amount * sizeof(T));
98 - used += amount;
99 - LeaveCriticalSection(&cs_store);
100 - return status;
101 - }
102 - int Find(const T &item, int start = 0, DWORD control = 0)
103 - {
104 - int c = -1;
105 - for (int i=start; i < used; i++)
106 - if (fCmp(storage[i],item,control)) {
107 - c=i;
108 - break;
109 - }
110 - //if (storage[i]==item) {c=i;break;}
111 - return c;
112 - }
113 - int Used() const { return used; }
114 - T *Storage() const { return storage; }
115 - void LockVector() { EnterCriticalSection(&cs_store); }
116 - void UnlockVector() { LeaveCriticalSection(&cs_store); }
117 -protected:
118 - CRITICAL_SECTION cs_store;
119 - int size,
120 - used;
121 - T *storage;
122 - fComp fCmp;
123 -};
124 -
125 -// EOF
126 -
127 -/*
128 -#ifndef ITH_STACK
129 -#define ITH_STACK
130 -template<class T, int default_size>
131 -class MyStack
132 -{
133 -public:
134 - MyStack(): index(0) {}
135 - void push_back(const T& e)
136 - {
137 - if (index<default_size)
138 - s[index++]=e;
139 - }
140 - void pop_back()
141 - {
142 - index--;
143 - }
144 - T& back()
145 - {
146 - return s[index-1];
147 - }
148 - T& operator[](int i) {return s[i];}
149 - int size() {return index;}
150 -private:
151 - int index;
152 - T s[default_size];
153 -};
154 -#endif
155 -*/
1 -#pragma once
2 -
3 -// mono/funcinfo.h
4 -// 12/26/2014
5 -// https://github.com/mono/mono/blob/master/mono/metadata/object.h
6 -// http://api.xamarin.com/index.aspx?link=xhtml%3Adeploy%2Fmono-api-string.html
7 -
8 -//#include "ith/import/mono/types.h"
9 -
10 -// MonoString* mono_string_new (MonoDomain *domain,
11 -// const char *text);
12 -// MonoString* mono_string_new_len (MonoDomain *domain,
13 -// const char *text,
14 -// guint length);
15 -// MonoString* mono_string_new_size (MonoDomain *domain,
16 -// gint32 len);
17 -// MonoString* mono_string_new_utf16 (MonoDomain *domain,
18 -// const guint16 *text,
19 -// gint32 len);
20 -// MonoString* mono_string_from_utf16 (gunichar2 *data);
21 -// mono_unichar2* mono_string_to_utf16 (MonoString *s);
22 -// char* mono_string_to_utf8 (MonoString *s);
23 -// gboolean mono_string_equal (MonoString *s1,
24 -// MonoString *s2);
25 -// guint mono_string_hash (MonoString *s);
26 -// MonoString* mono_string_intern (MonoString *str);
27 -// MonoString* mono_string_is_interned (MonoString *o);
28 -// MonoString* mono_string_new_wrapper (const char *text);
29 -// gunichar2* mono_string_chars (MonoString *s);
30 -// int mono_string_length (MonoString *s);
31 -// gunichar2* mono_unicode_from_external (const gchar *in, gsize *bytes);
32 -// gchar* mono_unicode_to_external (const gunichar2 *uni);
33 -// gchar* mono_utf8_from_external (const gchar *in);
34 -
35 -struct MonoFunction {
36 - const wchar_t *hookName;
37 - const char *functionName;
38 - size_t textIndex; // argument index, starting from 0
39 - size_t lengthIndex; // argument index, start from 0
40 - unsigned long hookType; // HookParam type
41 - void *text_fun; // HookParam::text_fun_t
42 -};
43 -
44 -#define MONO_FUNCTIONS_INITIALIZER \
45 - { L"mono_string_to_utf8", "mono_string_to_utf8", 0, 0, USING_UNICODE, SpecialHookMonoString } \
46 - , { L"mono_string_to_utf16", "mono_string_to_utf16", 0, 0, USING_UNICODE, SpecialHookMonoString } \
47 - , { L"mono_utf8_from_external", "mono_utf8_from_external", 1, 0, USING_STRING|USING_UTF8, nullptr } \
48 - , { L"mono_string_from_utf16", "mono_string_from_utf16", 1, 0, USING_UNICODE, nullptr } \
49 - , { L"mono_unicode_from_external", "mono_unicode_from_external", 1, 2, USING_UNICODE, nullptr } \
50 - , { L"mono_unicode_to_external", "mono_unicode_to_external", 1, 0, USING_UNICODE, nullptr }
51 -
52 -// EOF
1 -# mono.pri
2 -# 12/26/2014 jichi
3 -
4 -DEPENDPATH += $$PWD
5 -
6 -HEADERS += \
7 - $$PWD/funcinfo.h \
8 - $$PWD/types.h
9 -
10 -# EOF
1 -#pragma once
2 -
3 -// mono/types.h
4 -// 12/26/2014
5 -// https://github.com/mono/mono/blob/master/mono/metadata/object.h
6 -// http://api.xamarin.com/index.aspx?link=xhtml%3Adeploy%2Fmono-api-string.html
7 -
8 -#include <cstdint>
9 -
10 -// mono/io-layer/uglify.h
11 -typedef int8_t gint8;
12 -typedef int32_t gint32;
13 -typedef wchar_t gunichar2; // either char or wchar_t, depending on how mono is compiled
14 -
15 -typedef gint8 mono_byte;
16 -typedef gunichar2 mono_unichar2;
17 -
18 -// mono/metadata/object.h
19 -
20 -typedef mono_byte MonoBoolean;
21 -
22 -struct MonoArray;
23 -struct MonoDelegate;
24 -struct MonoException;
25 -struct MonoString;
26 -struct MonoThreadsSync;
27 -struct MonoThread;
28 -struct MonoVTable;
29 -
30 -struct MonoObject {
31 - MonoVTable *vtable;
32 - MonoThreadsSync *synchronisation;
33 -};
34 -
35 -struct MonoString {
36 - MonoObject object;
37 - gint32 length;
38 - gunichar2 chars[0];
39 -};
40 -
41 -// EOF
1 -#pragma once
2 -//#include "ith/common/const.h"
3 -
4 -// ppsspp/funcinfo.h
5 -// 12/26/2014
6 -// See: https://github.com/hrydgard/ppsspp
7 -
8 -// Core/HLE (High Level Emulator)
9 -// - sceCcc
10 -// #void sceCccSetTable(u32 jis2ucs, u32 ucs2jis)
11 -// int sceCccUTF8toUTF16(u32 dstAddr, u32 dstSize, u32 srcAddr)
12 -// int sceCccUTF8toSJIS(u32 dstAddr, u32 dstSize, u32 srcAddr)
13 -// int sceCccUTF16toUTF8(u32 dstAddr, u32 dstSize, u32 srcAddr)
14 -// int sceCccUTF16toSJIS(u32 dstAddr, u32 dstSize, u32 srcAddr)
15 -// int sceCccSJIStoUTF8(u32 dstAddr, u32 dstSize, u32 srcAddr)
16 -// int sceCccSJIStoUTF16(u32 dstAddr, u32 dstSize, u32 srcAddr)
17 -// int sceCccStrlenUTF8(u32 strAddr)
18 -// int sceCccStrlenUTF16(u32 strAddr)
19 -// int sceCccStrlenSJIS(u32 strAddr)
20 -// u32 sceCccEncodeUTF8(u32 dstAddrAddr, u32 ucs)
21 -// void sceCccEncodeUTF16(u32 dstAddrAddr, u32 ucs)
22 -// u32 sceCccEncodeSJIS(u32 dstAddrAddr, u32 jis)
23 -// u32 sceCccDecodeUTF8(u32 dstAddrAddr)
24 -// u32 sceCccDecodeUTF16(u32 dstAddrAddr)
25 -// u32 sceCccDecodeSJIS(u32 dstAddrAddr)
26 -// int sceCccIsValidUTF8(u32 c)
27 -// int sceCccIsValidUTF16(u32 c)
28 -// int sceCccIsValidSJIS(u32 c)
29 -// int sceCccIsValidUCS2(u32 c)
30 -// int sceCccIsValidUCS4(u32 c)
31 -// int sceCccIsValidJIS(u32 c)
32 -// int sceCccIsValidUnicode(u32 c)
33 -// #u32 sceCccSetErrorCharUTF8(u32 c)
34 -// #u32 sceCccSetErrorCharUTF16(u32 c)
35 -// #u32 sceCccSetErrorCharSJIS(u32 c)
36 -// u32 sceCccUCStoJIS(u32 c, u32 alt)
37 -// u32 sceCccJIStoUCS(u32 c, u32 alt)
38 -// - sceFont: search charCode
39 -// int sceFontGetCharInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr)
40 -// int sceFontGetShadowInfo(u32 fontHandle, u32 charCode, u32 charInfoPtr)
41 -// int sceFontGetCharImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr)
42 -// int sceFontGetShadowImageRect(u32 fontHandle, u32 charCode, u32 charRectPtr)
43 -// int sceFontGetCharGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr)
44 -// int sceFontGetCharGlyphImage_Clip(u32 fontHandle, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight)
45 -// #int sceFontSetAltCharacterCode(u32 fontLibHandle, u32 charCode)
46 -// int sceFontGetShadowGlyphImage(u32 fontHandle, u32 charCode, u32 glyphImagePtr)
47 -// int sceFontGetShadowGlyphImage_Clip(u32 fontHandle, u32 charCode, u32 glyphImagePtr, int clipXPos, int clipYPos, int clipWidth, int clipHeight)
48 -// - sceKernelInterrupt
49 -// u32 sysclib_strcat(u32 dst, u32 src)
50 -// int sysclib_strcmp(u32 dst, u32 src)
51 -// u32 sysclib_strcpy(u32 dst, u32 src)
52 -// u32 sysclib_strlen(u32 src)
53 -//
54 -// Sample debug string:
55 -// 006EFD8E PUSH PPSSPPWi.00832188 ASCII "sceCccEncodeSJIS(%08x, U+%04x)"
56 -// Corresponding source code in sceCcc:
57 -// ERROR_LOG(HLE, "sceCccEncodeSJIS(%08x, U+%04x): invalid pointer", dstAddrAddr, jis);
58 -
59 -struct PPSSPPFunction
60 -{
61 - const wchar_t *hookName; // hook name
62 - size_t argIndex; // argument index
63 - unsigned long hookType; // hook parameter type
64 - unsigned long hookSplit; // hook parameter split, positive: stack, negative: registers
65 - const char *pattern; // debug string used within the function
66 -};
67 -
68 -// jichi 7/14/2014: UTF-8 is treated as STRING
69 -// http://867258173.diandian.com/post/2014-06-26/40062099618
70 -// sceFontGetCharGlyphImage_Clip
71 -// Sample game: [KID] Monochrome: sceFontGetCharInfo, sceFontGetCharGlyphImage_Clip
72 -//
73 -// Example: { L"sceFontGetCharInfo", 2, USING_UNICODE, 4, "sceFontGetCharInfo(" }
74 -// Text is at arg2, using arg1 as split
75 -#define PPSSPP_FUNCTIONS_INITIALIZER \
76 - { L"sceCccStrlenSJIS", 1, USING_STRING, 0, "sceCccStrlenSJIS(" } \
77 - , { L"sceCccStrlenUTF8", 1, USING_UTF8, 0, "sceCccStrlenUTF8(" } \
78 - , { L"sceCccStrlenUTF16", 1, USING_UNICODE, 0, "sceCccStrlenUTF16(" } \
79 -\
80 - , { L"sceCccSJIStoUTF8", 3, USING_UTF8, 0, "sceCccSJIStoUTF8(" } \
81 - , { L"sceCccSJIStoUTF16", 3, USING_STRING, 0, "sceCccSJIStoUTF16(" } \
82 - , { L"sceCccUTF8toSJIS", 3, USING_UTF8, 0, "sceCccUTF8toSJIS(" } \
83 - , { L"sceCccUTF8toUTF16", 3, USING_UTF8, 0, "sceCccUTF8toUTF16(" } \
84 - , { L"sceCccUTF16toSJIS", 3, USING_UNICODE, 0, "sceCccUTF16toSJIS(" } \
85 - , { L"sceCccUTF16toUTF8", 3, USING_UNICODE, 0, "sceCccUTF16toUTF8(" } \
86 -\
87 - , { L"sceFontGetCharInfo", 2, USING_UNICODE, 4, "sceFontGetCharInfo(" } \
88 - , { L"sceFontGetShadowInfo", 2, USING_UNICODE, 4, "sceFontGetShadowInfo("} \
89 - , { L"sceFontGetCharImageRect", 2, USING_UNICODE, 4, "sceFontGetCharImageRect(" } \
90 - , { L"sceFontGetShadowImageRect", 2, USING_UNICODE, 4, "sceFontGetShadowImageRect(" } \
91 - , { L"sceFontGetCharGlyphImage", 2, USING_UNICODE, 4, "sceFontGetCharGlyphImage(" } \
92 - , { L"sceFontGetCharGlyphImage_Clip", 2, USING_UNICODE, 4, "sceFontGetCharGlyphImage_Clip(" } \
93 - , { L"sceFontGetShadowGlyphImage", 2, USING_UNICODE, 4, "sceFontGetShadowGlyphImage(" } \
94 - , { L"sceFontGetShadowGlyphImage_Clip", 2, USING_UNICODE, 4, "sceFontGetShadowGlyphImage_Clip(" } \
95 -\
96 - , { L"sysclib_strcat", 2, USING_STRING, 0, "Untested sysclib_strcat(" } \
97 - , { L"sysclib_strcpy", 2, USING_STRING, 0, "Untested sysclib_strcpy(" } \
98 - , { L"sysclib_strlen", 1, USING_STRING, 0, "Untested sysclib_strlen(" }
99 -
100 - // Disabled as I am not sure how to deal with the source string
101 - //, { L"sceCccEncodeSJIS", 2, USING_STRING, 0, "sceCccEncodeSJIS(" }
102 - //, { L"sceCccEncodeUTF8", 2, USING_UTF8, 0, "sceCccEncodeUTF8(" }
103 - //, { L"sceCccEncodeUTF16", 2, USING_UNICODE, 0, "sceCccEncodeUTF16(" }
104 - //, { L"sysclib_strcmp", 2, USING_STRING, 0, "Untested sysclib_strcmp(" }
105 -
106 -// EOF
1 -# ppsspp.pri
2 -# 12/26/2014 jichi
3 -
4 -DEPENDPATH += $$PWD
5 -
6 -HEADERS += \
7 - $$PWD/funcinfo.h
8 -
9 -# EOF
1 -# ith.pro
2 -# 10/13/2011 jichi
3 -
4 -TEMPLATE = subdirs
5 -
6 -# The order is important!
7 -SUBDIRS += \
8 - sys \
9 - hook hookxp \
10 - host
11 -
12 -OTHER_FILES += dllconfig.pri
13 -
14 -include(common/common.pri) # not used
15 -include(import/mono/mono.pri) # not used
16 -include(import/ppsspp/ppsspp.pri) # not used
17 -
18 -# EOF
1 -# sys.pro
2 -# CONFIG += noqt noeh staticlib
3 -
4 -# CONFIG(noeh) {
5 -# message(CONFIG noeh)
6 -# QMAKE_CXXFLAGS += /GR-
7 -# QMAKE_CXXFLAGS_RTTI_ON -= /GR
8 -# QMAKE_CXXFLAGS_STL_ON -= /EHsc
9 -# QMAKE_CXXFLAGS_EXCEPTIONS_ON -= /EHsc
10 -# CONFIG(dll) {
11 -# QMAKE_LFLAGS += /ENTRY:"DllMain"
12 -# }
13 -# }
14 -
15 -set(vnrsys_src
16 - sys.h
17 - sys.cc
18 -)
19 -
20 -add_library(vnrsys STATIC ${vnrsys_src})
21 -
22 -target_compile_options(vnrsys PRIVATE
23 - # http://msdn.microsoft.com/library/we6hfdy0.aspx
24 - /GR- # disable RTTI
25 - # http://msdn.microsoft.com/library/1deeycx5.aspx
26 - # /EHs-c- # disable exception handling # CMake bug 15243: http://www.cmake.org/Bug/view.php?id=15243
27 - $<$<CONFIG:Release>:>
28 - $<$<CONFIG:Debug>:>
29 -)
30 -
31 -STRING(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
32 -
33 -target_link_libraries(vnrsys comctl32.lib)
34 -
35 -target_compile_definitions(vnrsys
36 - PRIVATE
37 -)
1 -// sys.cc
2 -// 8/21/2013 jichi
3 -// Branch: ITH_SYS/SYS.cpp, rev 126
4 -//
5 -// 8/24/2013 TODO:
6 -// - Clean up the code
7 -// - Move my old create remote thread for ITH2 here
8 -
9 -#include "ith/sys/sys.h"
10 -//#include "ith/common/growl.h"
11 -//#include "ith/common/except.h"
12 -
13 -//#define ITH_SYS_SECTION L"ITH_SysSection"
14 -#define ITH_THREADMAN_SECTION L"VNR_SYS_THREAD"
15 -
16 -// jichi 9/28/2013: Weither use NtThread or RemoteThread
17 -// RemoteThread works on both Windows 7 or Wine, while NtThread does not work on wine
18 -#define ITH_ENABLE_THREADMAN (!IthIsWindows8OrGreater() && !IthIsWine())
19 -//#define ITH_ENABLE_THREADMAN true
20 -
21 -// Helpers
22 -
23 -// jichi 2/3/2015: About GetVersion
24 -// Windows XP SP3: 5.1
25 -// Windows 7: 6.1, 0x1db10106
26 -// Windows 8: 6.2, 0x23f00206
27 -// Windows 10: 6.2, 0x23f00206 (build 9926):
28 -
29 -BOOL IthIsWindowsXp()
30 -{
31 - static BOOL ret = -1; // cached
32 - if (ret < 0) {
33 - // http://msdn.microsoft.com/en-us/library/windows/desktop/ms724439%28v=vs.85%29.aspx
34 - DWORD v = ::GetVersion();
35 - BYTE major = LOBYTE(LOWORD(v));
36 - //DWORD minor = (DWORD)(HIBYTE(LOWORD(v)));
37 -
38 - // Windows XP = 5.1
39 - //ret = major < 6 ? 1 : 0;
40 - ret = major < 6;
41 - }
42 - return ret;
43 -}
44 -
45 -// https://msdn.microsoft.com/en-us/library/windows/desktop/dn424972%28v=vs.85%29.aspx
46 -// The same as IsWindows8OrGreater, which I don't know if the function is available to lower Windows.
47 -static BOOL IthIsWindows8OrGreater() // this function is not exported
48 -{
49 - static BOOL ret = -1; // cached
50 - if (ret < 0) {
51 - // http://msdn.microsoft.com/en-us/library/windows/desktop/ms724439%28v=vs.85%29.aspx
52 - DWORD v = ::GetVersion();
53 - BYTE major = LOBYTE(LOWORD(v)),
54 - minor = HIBYTE(LOWORD(v));
55 - //DWORD minor = (DWORD)(HIBYTE(LOWORD(v)));
56 -
57 - // Windows 8/10 = 6.2
58 - ret = major > 6 || (major == 6 && minor >= 2);
59 - }
60 - return ret;
61 -}
62 -
63 -BOOL IthIsWine()
64 -{
65 - static BOOL ret = -1; // cached
66 - if (ret < 0) {
67 - const wchar_t *path;
68 - wchar_t buffer[MAX_PATH];
69 - if (UINT sz = ::GetSystemDirectoryW(buffer, MAX_PATH)) {
70 - path = buffer;
71 - ::wcscpy(buffer + sz, L"\\winecfg.exe");
72 - } else
73 - path = L"C:\\Windows\\System32\\winecfg.exe";
74 - //ITH_MSG(path);
75 - ret = ::GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES ? TRUE : FALSE;
76 - }
77 - return ret;
78 -}
79 -
80 -// jichi 9/28/2013: prevent parallelization in wine
81 -void IthCoolDown()
82 -{
83 - // http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Thread/NtDelayExecution.html
84 - //const LONGLONG timeout = -10000; // in 100ns, i.e. 1ms
85 - //NtDelayExecution(FALSE, (PLARGE_INTEGER)&timeout);
86 - //NtFlushInstructionCache(NtCurrentProcess(), (LPVOID)hp.addr, hp.recover_len);
87 - // Flush the instruction cache line, and prevent wine from rending things in parallel
88 - if (IthIsWine())
89 - IthSleep(1); // sleep for 1 ms
90 - //__asm
91 - //{
92 - // //mov eax,0x2710 // = 10000
93 - // mov ecx,time
94 - // mul ecx
95 - // neg eax
96 - // adc edx,0
97 - // neg edx
98 - // push edx
99 - // push eax
100 - // push esp
101 - // push 0
102 - // call dword ptr [NtDelayExecution]
103 - // add esp,8
104 - //}
105 -}
106 -
107 -// jichi 9/23/2013: wine deficenciy on mapping sections
108 -// Whe set to false, do not map sections.
109 -//static bool ith_has_section = true;
110 -
111 -//#ifdef ITH_WINE
112 -//# include "winddk/winddk.h"
113 -//#endif // ITH_WINE
114 -
115 -//#define SEC_BASED 0x200000 // jichi 8/24/2013: emoved
116 -
117 -// jichi 10/6/2013
118 -// See: http://stackoverflow.com/questions/557081/how-do-i-get-the-hmodule-for-the-currently-executing-code
119 -// See: http://www.codeproject.com/Articles/16598/Get-Your-DLL-s-Path-Name
120 -EXTERN_C IMAGE_DOS_HEADER __ImageBase;
121 -#define CURRENT_MODULE_HANDLE ((HINSTANCE)&__ImageBase)
122 -size_t IthGetCurrentModulePath(wchar_t *buf, size_t len)
123 -{ return ::GetModuleFileNameW(CURRENT_MODULE_HANDLE, buf, len); }
124 -
125 -// - Global variables -
126 -
127 -#ifdef ITH_HAS_HEAP
128 -HANDLE hHeap; // used in ith/common/memory.h
129 -#endif // ITH_HAS_HEAP
130 -
131 -DWORD current_process_id;
132 -DWORD debug;
133 -BYTE launch_time[0x10];
134 -LPVOID page;
135 -
136 -BYTE LeadByteTable[0x100] = {
137 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
138 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
139 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
140 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
141 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
142 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
143 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
144 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
145 - 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
146 - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
147 - 2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
148 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
149 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
150 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
151 - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
152 - 2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1
153 -};
154 -
155 -namespace { // unnamed
156 -
157 -WCHAR file_path[MAX_PATH] = L"\\??\\";
158 -LPWSTR current_dir;
159 -DWORD page_locale;
160 -HANDLE root_obj,
161 - dir_obj,
162 - codepage_section,
163 - thread_man_section;
164 -
165 -BYTE file_info[0x1000];
166 -
167 -
168 -// - Helper functions -
169 -
170 -inline DWORD GetShareMemory()
171 -{
172 - __asm
173 - {
174 - mov eax,fs:[0x30]
175 - mov eax,[eax+0x4C]
176 - }
177 -}
178 -
179 -inline LARGE_INTEGER *GetTimeBias()
180 -{ __asm mov eax,0x7ffe0020 }
181 -
182 -
183 -//Get full path of current process.
184 -//inline LPWSTR GetModulePath()
185 -//{
186 -// __asm
187 -// {
188 -// mov eax,fs:[0x30]
189 -// mov eax,[eax+0xC]
190 -// mov eax,[eax+0xC]
191 -// mov eax,[eax+0x28]
192 -// }
193 -//}
194 -
195 -// - Singleton classes -
196 -
197 -BYTE normal_routine[0x14] = {
198 - 0x51,0x52,0x64,0x89,0x23,0x55,0xff,0xd0,0x50,0x6a,0xfe,0xff,0x15,0x14,0x00,0x00,0x00
199 -};
200 -
201 -BYTE except_routine[0xe0] = {
202 - 0xba,0x08,0x00,0x00,0x00,0x8b,0xc1,0x83,0xe0,0x0f,0x83,0xf8,0x0a,0x72,0x02,0x04,
203 - 0x07,0x04,0x30,0x66,0xab,0xc1,0xc9,0x04,0x4a,0x75,0xea,0xc3,0x00,0x00,0x00,0x00,
204 - 0x8b,0x44,0xe4,0x04,0x31,0xf6,0x8b,0x28,0x8b,0x4c,0xe4,0x0c,0x8b,0x99,0xb8,0x00,
205 - 0x00,0x00,0x81,0xec,0x40,0x02,0x00,0x00,0x8d,0x7c,0xe4,0x40,0x89,0xe0,0x56,0x6a,
206 - 0x1c,0x50,0x56,0x53,0x6a,0xff,0xff,0x15,0x18,0x00,0x00,0x00,0x85,0xc0,0x75,0x98,
207 - 0x89,0xe0,0x50,0x68,0x00,0x02,0x00,0x00,0x57,0x6a,0x02,0x53,0x6a,0xff,0xff,0x15,
208 - 0x18,0x00,0x00,0x00,0x85,0xc0,0x75,0xe6,0x5e,0x0f,0xc1,0xf7,0xfd,0xb0,0x5c,0x66,
209 - 0xf2,0xaf,0x66,0xc7,0x47,0x02,0x3a,0x00,0x89,0xd9,0x2b,0x0c,0xe4,0xe8,0x7e,0xff,
210 - 0xff,0xff,0x47,0x47,0x87,0xfe,0x89,0xe9,0xe8,0x73,0xff,0xff,0xff,0x47,0x47,0x31,
211 - 0xc0,0x89,0x47,0x10,0x6a,0x00,0x57,0x56,0x6a,0x00,0xfc,0xff,0x15,0x1c,0x00,0x00,
212 - 0x00,0x83,0xc8,0xff,0xeb,0xbe
213 -};
214 -
215 -// jichi 8/24/2013: Could be initialized using NtMapViewOfSection/ZwMapViewOfSection
216 -// This class cannot have constructor / destructor
217 -struct _ThreadView {
218 - UINT_PTR mutex,
219 - count;
220 - DWORD proc_record[1];
221 -};
222 -
223 -class : private _ThreadView { // ThreadStartManager
224 -
225 - enum {
226 - ADDR0 = 0xD
227 - , ADDR1 = 0x48
228 - , ADDR2 = 0x60
229 - , ADDR3 = 0x9D
230 - };
231 -
232 -public:
233 - LPVOID GetProcAddr(HANDLE hProc)
234 - {
235 - AcquireLock();
236 - DWORD pid,addr,len;
237 - if (hProc == NtCurrentProcess())
238 - pid = ::current_process_id;
239 - else {
240 - PROCESS_BASIC_INFORMATION info;
241 - NtQueryInformationProcess(hProc, ProcessBasicInformation, &info, sizeof(info), &len);
242 - pid=info.uUniqueProcessId;
243 - }
244 - pid >>= 2;
245 - for (UINT_PTR i = 0; i < count; i++)
246 - if (pid == (proc_record[i] & 0xfff)) {
247 - addr = proc_record[i] & ~0xfff;
248 - ReleaseLock();
249 - return (LPVOID)addr;
250 - }
251 - len = 0x1000;
252 - NtAllocateVirtualMemory(hProc, (PVOID *)(proc_record + count), 0, &len,
253 - MEM_COMMIT,PAGE_EXECUTE_READWRITE);
254 - DWORD base = proc_record[count];
255 - proc_record[count] |= pid;
256 - union {
257 - LPVOID buffer;
258 - DWORD b;
259 - };
260 - b = base;
261 - LPVOID fun_table[3];
262 - *(DWORD *)(normal_routine + ADDR0) += base;
263 - NtWriteVirtualMemory(hProc, buffer, normal_routine, 0x14, 0);
264 - *(DWORD *)(normal_routine + ADDR0) -= base;
265 - b += 0x14;
266 - fun_table[0] = NtTerminateThread;
267 - fun_table[1] = NtQueryVirtualMemory;
268 - fun_table[2] = MessageBoxW;
269 - NtWriteVirtualMemory(hProc, buffer, fun_table, 0xC, 0);
270 - b += 0xc;
271 - *(DWORD *)(except_routine + ADDR1) += base;
272 - *(DWORD *)(except_routine + ADDR2) += base;
273 - *(DWORD *)(except_routine + ADDR3) += base;
274 - NtWriteVirtualMemory(hProc, buffer, except_routine, 0xE0, 0);
275 - *(DWORD *)(except_routine + ADDR1) -= base;
276 - *(DWORD *)(except_routine + ADDR2) -= base;
277 - *(DWORD *)(except_routine + ADDR3) -= base;
278 - count++;
279 - ReleaseLock();
280 - return (LPVOID)base;
281 - }
282 - void ReleaseProcessMemory(HANDLE hProc)
283 - {
284 - DWORD pid,addr,len;
285 - AcquireLock();
286 - if (hProc==NtCurrentProcess())
287 - pid = ::current_process_id;
288 - else {
289 - PROCESS_BASIC_INFORMATION info;
290 - NtQueryInformationProcess(hProc,ProcessBasicInformation,&info,sizeof(info),&len);
291 - pid = info.uUniqueProcessId;
292 - }
293 - pid >>= 2;
294 - //NtWaitForSingleObject(thread_man_mutex,0,0);
295 - for (UINT_PTR i = 0; i < count; i++) {
296 - if ((proc_record[i]&0xfff) == pid) {
297 - addr = proc_record[i] & ~0xfff;
298 - DWORD size=0x1000;
299 - NtFreeVirtualMemory(hProc, (PVOID *)&addr, &size, MEM_RELEASE);
300 - count--;
301 - for (UINT_PTR j = i; j < count; j++)
302 - proc_record[j] = proc_record[j + 1];
303 - proc_record[count] = 0;
304 - ReleaseLock();
305 - //NtReleaseMutant(thread_man_mutex,0);
306 - return;
307 - }
308 - }
309 - ReleaseLock();
310 - //NtReleaseMutant(thread_man_mutex,0);
311 - }
312 - void CheckProcessMemory()
313 - {
314 - UINT_PTR i, j, flag, addr;
315 - DWORD len;
316 - CLIENT_ID id;
317 - OBJECT_ATTRIBUTES oa = {};
318 - HANDLE hProc;
319 - BYTE buffer[8];
320 - AcquireLock();
321 - id.UniqueThread = 0;
322 - oa.uLength = sizeof(oa);
323 - for (i = 0; i < count ; i++) {
324 - id.UniqueProcess = (proc_record[i]&0xfff)<<2;
325 - addr = proc_record[i] & ~0xfff;
326 - flag = 0;
327 - if (NT_SUCCESS(NtOpenProcess(&hProc, PROCESS_VM_OPERATION|PROCESS_VM_READ, &oa, &id))) {
328 - if (NT_SUCCESS(NtReadVirtualMemory(hProc, (PVOID)addr, buffer, 8, &len)))
329 - if (::memcmp(buffer, normal_routine, 4) == 0)
330 - flag = 1;
331 - NtClose(hProc);
332 - }
333 - if (flag == 0) {
334 - for (j = i; j < count; j++)
335 - proc_record[j] = proc_record[j + 1];
336 - count--;
337 - i--;
338 - }
339 - }
340 - ReleaseLock();
341 - }
342 - void AcquireLock()
343 - {
344 - LONG *p = (LONG *)&mutex;
345 - while (_interlockedbittestandset(p,0))
346 - YieldProcessor();
347 - }
348 - void ReleaseLock()
349 - {
350 - LONG *p = (LONG*)&mutex;
351 - _interlockedbittestandreset(p, 0);
352 - }
353 -} *thread_man_ = nullptr; // global singleton
354 -
355 -} // unnamed namespace
356 -
357 -// - API functions -
358 -
359 -extern "C" {
360 -
361 -void FreeThreadStart(HANDLE hProc)
362 -{
363 - if (thread_man_)
364 - ::thread_man_->ReleaseProcessMemory(hProc);
365 -}
366 -
367 -void CheckThreadStart()
368 -{
369 - if (thread_man_)
370 - ::thread_man_->CheckProcessMemory();
371 -
372 - // jichi 2/2/2015: This function is only used to wait for injected threads vnrhost.
373 - // Sleep for 100 ms to wait for remote thread to start
374 - //IthSleep(100);
375 - //IthCoolDown();
376 -}
377 -
378 -void IthSleep(int time)
379 -{
380 - __asm
381 - {
382 - mov eax,0x2710 // jichi = 10000
383 - mov ecx,time
384 - mul ecx
385 - neg eax
386 - adc edx,0
387 - neg edx
388 - push edx
389 - push eax
390 - push esp
391 - push 0
392 - call dword ptr [NtDelayExecution]
393 - add esp,8
394 - }
395 -}
396 -
397 -void IthSystemTimeToLocalTime(LARGE_INTEGER *time)
398 -{ time->QuadPart -= GetTimeBias()->QuadPart; }
399 -
400 -int FillRange(LPCWSTR name, DWORD *lower, DWORD *upper)
401 -{
402 - PLDR_DATA_TABLE_ENTRY it;
403 - LIST_ENTRY *begin;
404 - __asm
405 - {
406 - mov eax,fs:[0x30]
407 - mov eax,[eax+0xc]
408 - mov eax,[eax+0xc]
409 - mov it,eax
410 - mov begin,eax
411 - }
412 -
413 - while (it->SizeOfImage) {
414 - if (::_wcsicmp(it->BaseDllName.Buffer, name) == 0) {
415 - *lower = *upper = (DWORD)it->DllBase;
416 - MEMORY_BASIC_INFORMATION info = {};
417 - DWORD l,size;
418 - size = 0;
419 - do {
420 - NtQueryVirtualMemory(NtCurrentProcess(), (LPVOID)(*upper), MemoryBasicInformation, &info, sizeof(info), &l);
421 - if (info.Protect&PAGE_NOACCESS) {
422 - it->SizeOfImage=size;
423 - break;
424 - }
425 - size += info.RegionSize;
426 - *upper += info.RegionSize;
427 - } while (size < it->SizeOfImage);
428 - return 1;
429 - }
430 - it = (PLDR_DATA_TABLE_ENTRY)it->InLoadOrderModuleList.Flink;
431 - if (it->InLoadOrderModuleList.Flink == begin)
432 - break;
433 - }
434 - return 0;
435 -}
436 -
437 -DWORD SearchPattern(DWORD base, DWORD base_length, LPCVOID search, DWORD search_length) // KMP
438 -{
439 - __asm
440 - {
441 - mov eax,search_length
442 -alloc:
443 - push 0
444 - sub eax,1
445 - jnz alloc
446 -
447 - mov edi,search
448 - mov edx,search_length
449 - mov ecx,1
450 - xor esi,esi
451 -build_table:
452 - mov al,byte ptr [edi+esi]
453 - cmp al,byte ptr [edi+ecx]
454 - sete al
455 - test esi,esi
456 - jz pre
457 - test al,al
458 - jnz pre
459 - mov esi,[esp+esi*4-4]
460 - jmp build_table
461 -pre:
462 - test al,al
463 - jz write_table
464 - inc esi
465 -write_table:
466 - mov [esp+ecx*4],esi
467 -
468 - inc ecx
469 - cmp ecx,edx
470 - jb build_table
471 -
472 - mov esi,base
473 - xor edx,edx
474 - mov ecx,edx
475 -matcher:
476 - mov al,byte ptr [edi+ecx]
477 - cmp al,byte ptr [esi+edx]
478 - sete al
479 - test ecx,ecx
480 - jz match
481 - test al,al
482 - jnz match
483 - mov ecx, [esp+ecx*4-4]
484 - jmp matcher
485 -match:
486 - test al,al
487 - jz pre2
488 - inc ecx
489 - cmp ecx,search_length
490 - je finish
491 -pre2:
492 - inc edx
493 - cmp edx,base_length // search_length
494 - jb matcher
495 - mov edx,search_length
496 - dec edx
497 -finish:
498 - mov ecx,search_length
499 - sub edx,ecx
500 - lea eax,[edx+1]
501 - lea ecx,[ecx*4]
502 - add esp,ecx
503 - }
504 -}
505 -
506 -// jichi 2/5/2014: '?' = 0xff
507 -// See: http://sakuradite.com/topic/124
508 -DWORD SearchPatternEx(DWORD base, DWORD base_length, LPCVOID search, DWORD search_length, BYTE wildcard) // KMP
509 -{
510 - __asm
511 - {
512 - // jichi 2/5/2014 BEGIN
513 - mov bl,wildcard
514 - // jichi 2/5/2014 END
515 - mov eax,search_length
516 -alloc:
517 - push 0
518 - sub eax,1
519 - jnz alloc // jichi 2/5/2014: this will also set %eax to zero
520 -
521 - mov edi,search
522 - mov edx,search_length
523 - mov ecx,1
524 - xor esi,esi
525 -build_table:
526 - mov al,byte ptr [edi+esi]
527 - cmp al,byte ptr [edi+ecx]
528 - sete al
529 - test esi,esi
530 - jz pre
531 - test al,al
532 - jnz pre
533 - mov esi,[esp+esi*4-4]
534 - jmp build_table
535 -pre:
536 - test al,al
537 - jz write_table
538 - inc esi
539 -write_table:
540 - mov [esp+ecx*4],esi
541 -
542 - inc ecx
543 - cmp ecx,edx
544 - jb build_table
545 -
546 - mov esi,base
547 - xor edx,edx
548 - mov ecx,edx
549 -matcher:
550 - mov al,byte ptr [edi+ecx] // search
551 - // jichi 2/5/2014 BEGIN
552 - mov bh,al // save loaded byte to reduce cache access. %ah is not used and always zero
553 - cmp al,bl // %bl is the wildcard byte
554 - sete al
555 - test al,al
556 - jnz wildcard_matched
557 - mov al,bh // restore the loaded byte
558 - // jichi 2/5/2014 END
559 - cmp al,byte ptr [esi+edx] // base
560 - sete al
561 - // jichi 2/5/2014 BEGIN
562 -wildcard_matched:
563 - // jichi 2/5/2014 END
564 - test ecx,ecx
565 - jz match
566 - test al,al
567 - jnz match
568 - mov ecx, [esp+ecx*4-4]
569 - jmp matcher
570 -match:
571 - test al,al
572 - jz pre2
573 - inc ecx
574 - cmp ecx,search_length
575 - je finish
576 -pre2:
577 - inc edx
578 - cmp edx,base_length // search_length
579 - jb matcher
580 - mov edx,search_length
581 - dec edx
582 -finish:
583 - mov ecx,search_length
584 - sub edx,ecx
585 - lea eax,[edx+1]
586 - lea ecx,[ecx*4]
587 - add esp,ecx
588 - }
589 -}
590 -
591 -DWORD IthGetMemoryRange(LPCVOID mem, DWORD *base, DWORD *size)
592 -{
593 - DWORD r;
594 - MEMORY_BASIC_INFORMATION info;
595 - NtQueryVirtualMemory(NtCurrentProcess(), const_cast<LPVOID>(mem), MemoryBasicInformation, &info, sizeof(info), &r);
596 - if (base)
597 - *base = (DWORD)info.BaseAddress;
598 - if (size)
599 - *size = info.RegionSize;
600 - return (info.Type&PAGE_NOACCESS) == 0;
601 -}
602 -
603 -// jichi 9/25/2013
604 -// See: http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.nls/doc/nlsgdrf/multi-byte_widechar_subr.htm
605 -// SJIS->Unicode. 'mb' must be null-terminated. 'wc' should have enough space ( 2*strlen(mb) is safe).
606 -//#ifdef ITH_WINE
607 -//int MB_WC(char *mb, wchar_t *wc)
608 -//{ return mbstowcs(wc, mb, 0x100); }
609 -//
610 -//#else
611 -int MB_WC(char *mb, wchar_t *wc)
612 -{
613 - __asm
614 - {
615 - mov esi,mb
616 - mov edi,wc
617 - mov edx,page
618 - lea ebx,LeadByteTable
619 - add edx,0x220
620 - push 0
621 -_mb_translate:
622 - movzx eax,word ptr [esi]
623 - test al,al
624 - jz _mb_fin
625 - movzx ecx,al
626 - xlat
627 - test al,1
628 - cmovnz cx, word ptr [ecx*2+edx-0x204]
629 - jnz _mb_next
630 - mov cx,word ptr [ecx*2+edx]
631 - mov cl,ah
632 - mov cx, word ptr [ecx*2+edx]
633 -_mb_next:
634 - mov [edi],cx
635 - add edi,2
636 - movzx eax,al
637 - add esi,eax
638 - inc dword ptr [esp]
639 - jmp _mb_translate
640 -_mb_fin:
641 - pop eax
642 - }
643 -}
644 -
645 -// Count characters of 'mb' string. 'mb_length' is max length.
646 -// jichi 9/25/2013: This function is not used
647 -//int MB_WC_count(char *mb, int mb_length)
648 -//{
649 -// __asm
650 -// {
651 -// xor eax,eax
652 -// xor edx,edx
653 -// mov esi,mb
654 -// mov edi,mb_length
655 -// lea ebx,LeadByteTable
656 -//_mbc_count:
657 -// mov dl,byte ptr [esi]
658 -// test dl,dl
659 -// jz _mbc_finish
660 -// movzx ecx, byte ptr [ebx+edx]
661 -// add esi,ecx
662 -// inc eax
663 -// sub edi,ecx
664 -// ja _mbc_count
665 -//_mbc_finish:
666 -// }
667 -//}
668 -
669 -// jichi 9/25/2013
670 -// See: http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.nls/doc/nlsgdrf/multi-byte_widechar_subr.htm
671 -// Unicode->SJIS. Analogous to MB_WC.
672 -//#ifdef ITH_WINE
673 -//int WC_MB(wchar_t *wc, char *mb)
674 -//{ return wcstombs(mb, wc, 0x100); }
675 -//
676 -//#else
677 -int WC_MB(wchar_t *wc, char *mb)
678 -{
679 - __asm
680 - {
681 - mov esi,wc
682 - mov edi,mb
683 - mov edx,page
684 - add edx,0x7C22
685 - xor ebx,ebx
686 -_wc_translate:
687 - movzx eax,word ptr [esi]
688 - test eax,eax
689 - jz _wc_fin
690 - mov cx,word ptr [eax*2+edx]
691 - test ch,ch
692 - jz _wc_single
693 - mov [edi+ebx],ch
694 - inc ebx
695 -_wc_single:
696 - mov [edi+ebx],cl
697 - inc ebx
698 - add esi,2
699 - jmp _wc_translate
700 -_wc_fin:
701 - mov eax,ebx
702 - }
703 -}
704 -
705 -//Initialize environment for NT native calls. Not thread safe so only call it once in one module.
706 -//1. Create new heap. Future memory requests are handled by this heap.
707 -//Destroying this heap will completely release all dynamically allocated memory, thus prevent memory leaks on unload.
708 -//2. Create handle to root directory of process objects (section/event/mutex/semaphore).
709 -//NtCreate* calls will use this handle as base directory.
710 -//3. Load SJIS code page. First check for Japanese locale. If not then load from 'C_932.nls' in system folder.
711 -//MB_WC & WC_MB use this code page for translation.
712 -//4. Locate current NT path (start with \??\).
713 -//NtCreateFile requires full path or a root handle. But this handle is different from object.
714 -//5. Map shared memory for ThreadStartManager into virtual address space.
715 -//This will allow IthCreateThread function properly.
716 -BOOL IthInitSystemService()
717 -{
718 - PPEB peb;
719 - //NTSTATUS status;
720 - DWORD size;
721 - ULONG LowFragmentHeap;
722 - UNICODE_STRING us;
723 - OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, 0, 0};
724 - IO_STATUS_BLOCK ios;
725 - HANDLE codepage_file;
726 - LARGE_INTEGER sec_size = {0x1000, 0};
727 - __asm
728 - {
729 - mov eax,fs:[0x18]
730 - mov ecx,[eax+0x20]
731 - mov eax,[eax+0x30]
732 - mov peb,eax
733 - mov current_process_id,ecx
734 - }
735 - debug = peb->BeingDebugged;
736 - LowFragmentHeap = 2;
737 -
738 -#ifdef ITH_HAS_HEAP
739 - ::hHeap = RtlCreateHeap(0x1002, 0, 0, 0, 0, 0);
740 - RtlSetHeapInformation(::hHeap, HeapCompatibilityInformation, &LowFragmentHeap, sizeof(LowFragmentHeap));
741 -#endif // ITH_HAS_HEAP
742 -
743 - LPWSTR t = nullptr, // jichi: path to system32, such as "c:\windows\system32"
744 - obj = nullptr; // jichi: path to current kernel session, such as "Sessions\\1\\BaseNamedObjects"
745 - // jichi 9/22/2013: This would crash wine with access violation exception.
746 - if (!IthIsWine()) {
747 - // jichi 9/22/2013: For ChuSingura46+1 on Windows 7
748 - // t = L"C:\\Windows\\system32";
749 - // obj = L"\\Sessions\\1\\BaseNamedObjects";
750 - // On Windows XP
751 - // t = L"C:\\WINDOWS\\system32";
752 - // obj = L"\\BaseNamedObjects";
753 - MEMORY_BASIC_INFORMATION info;
754 - if (!NT_SUCCESS(NtQueryVirtualMemory(NtCurrentProcess(), peb->ReadOnlySharedMemoryBase, MemoryBasicInformation, &info, sizeof(info), &size)))
755 - return FALSE;
756 - DWORD base = (DWORD)peb->ReadOnlySharedMemoryBase;
757 - DWORD end = base + info.RegionSize - 0x40;
758 - static WCHAR system32[] = L"system32";
759 - for (;base < end; base += 2)
760 - if (::memcmp((PVOID)base, system32, 0x10) == 0) {
761 - t = (LPWSTR)base;
762 - while (*t-- != L':');
763 - obj = (LPWSTR)base;
764 - while (*obj != L'\\') obj++;
765 - break;
766 - }
767 - if (base == end)
768 - return FALSE;
769 - }
770 - //ITH_MSG(t);
771 - //ITH_MSG(obj);
772 -
773 - LDR_DATA_TABLE_ENTRY *ldr_entry = (LDR_DATA_TABLE_ENTRY*)peb->Ldr->InLoadOrderModuleList.Flink;
774 - wcscpy(file_path + 4, ldr_entry->FullDllName.Buffer);
775 - current_dir = wcsrchr(file_path,L'\\') + 1;
776 - *current_dir = 0;
777 - RtlInitUnicodeString(&us, file_path);
778 - if (!NT_SUCCESS(NtOpenFile(&dir_obj,FILE_LIST_DIRECTORY|FILE_TRAVERSE|SYNCHRONIZE,
779 - &oa,&ios,FILE_SHARE_READ|FILE_SHARE_WRITE,FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT)))
780 - return FALSE;
781 -
782 - // jichi 9/22/2013: Get kernel object session ID
783 - // See: http://www.brianbondy.com/blog/id/100/
784 - // It seems that on sessionId is 0 on Windows XP, and 1 on Windows Vista and later
785 - // I assume that sessionId is in [0,9]
786 - // For ChuSingura46+1 on Windows 7
787 - // obj = L"\\Sessions\\1\\BaseNamedObjects";
788 - // On Windows XP
789 - // obj = L"\\BaseNamedObjects";
790 - //ITH_MSG(obj);
791 - {
792 - if (obj)
793 - RtlInitUnicodeString(&us, obj);
794 - else { // jichi ITH is on Wine
795 - // Get session ID in PEB
796 - // See: http://msdn.microsoft.com/en-us/library/bb432286%28v=vs.85%29.aspx
797 - DWORD sessionId = peb->SessionId;
798 - if (!sessionId) // Windows XP
799 - RtlInitUnicodeString(&us, L"\\BaseNamedObjects");
800 - else { // Windows Vista +
801 - wchar_t path[] = L"\\Sessions\\0\\BaseNamedObjects";
802 - path[10] += (wchar_t)sessionId; // replace 0 with the session ID
803 - RtlInitUnicodeString(&us, path);
804 - }
805 - }
806 - }
807 -
808 - if (!NT_SUCCESS(NtOpenDirectoryObject(&::root_obj, READ_CONTROL|0xF, &oa)))
809 - return FALSE;
810 -
811 - ::page = peb->InitAnsiCodePageData;
812 -
813 - // jichi 9/23/2013: Access violation on Wine
814 - if (IthIsWine())
815 - // One wine, there is no C_932.nls
816 - //page_locale = 0x4e4; // 1252, English
817 - //page_locale = GetACP(); // This will return 932 when LC_ALL=ja_JP.UTF-8 on wine
818 - // Always set locale to CP932 on Wine, since C_932.nls could be missing.
819 - ::page_locale = 0x3a4; // = 932
820 - else
821 - ::page_locale = *(DWORD *)page >> 16;
822 -
823 - if (::page_locale == 0x3a4) {
824 - oa.hRootDirectory = ::root_obj;
825 - oa.uAttributes |= OBJ_OPENIF;
826 - } else { // Unreachable or wine
827 -//#ifdef ITH_WINE
828 -// // jichi 9/22/2013: For ChuSingura46+1 on Windows 7
829 -// //t = L"C:\\Windows\\system32";
830 -// wchar_t buffer[MAX_PATH];
831 -// if (!t) { // jichi 9/22/2013: ITH is one wine
832 -// if (UINT sz = ::GetSystemDirectoryW(buffer, MAX_PATH)) {
833 -// buffer[sz] = 0;
834 -// t = buffer;
835 -// } else
836 -// t = L"C:\\Windows\\System32"; // jichi 9/29/2013: sth is wrong here
837 -// }
838 -//#endif // ITH_WINE
839 -
840 - ::wcscpy(file_path + 4, t);
841 - t = file_path;
842 - while(*++t);
843 - if (*(t-1)!=L'\\')
844 - *t++=L'\\';
845 - ::wcscpy(t,L"C_932.nls");
846 - RtlInitUnicodeString(&us, file_path);
847 - if (!NT_SUCCESS(NtOpenFile(&codepage_file, FILE_READ_DATA, &oa, &ios,FILE_SHARE_READ,0)))
848 - return FALSE;
849 - oa.hRootDirectory = ::root_obj;
850 - oa.uAttributes |= OBJ_OPENIF;
851 - RtlInitUnicodeString(&us, L"JPN_CodePage");
852 - if (!NT_SUCCESS(NtCreateSection(&codepage_section, SECTION_MAP_READ,
853 - &oa,0, PAGE_READONLY, SEC_COMMIT, codepage_file)))
854 - return FALSE;
855 - NtClose(codepage_file);
856 - size = 0;
857 - ::page = nullptr;
858 - if (!NT_SUCCESS(NtMapViewOfSection(::codepage_section, NtCurrentProcess(),
859 - &::page,
860 - 0, 0, 0, &size, ViewUnmap, 0,
861 - PAGE_READONLY)))
862 - return FALSE;
863 - }
864 - if (ITH_ENABLE_THREADMAN) {
865 - RtlInitUnicodeString(&us, ITH_THREADMAN_SECTION);
866 - if (!NT_SUCCESS(NtCreateSection(&thread_man_section, SECTION_ALL_ACCESS, &oa, &sec_size,
867 - PAGE_EXECUTE_READWRITE, SEC_COMMIT, 0)))
868 - return FALSE;
869 - size = 0;
870 - // http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Section/NtMapViewOfSection.html
871 - thread_man_ = nullptr;
872 - if (!NT_SUCCESS(NtMapViewOfSection(thread_man_section, NtCurrentProcess(),
873 - (LPVOID *)&thread_man_,
874 - 0,0,0, &size, ViewUnmap, 0,
875 - PAGE_EXECUTE_READWRITE)))
876 - return FALSE;
877 - }
878 - return TRUE;
879 -}
880 -
881 -//Release resources allocated by IthInitSystemService.
882 -//After destroying the heap, all memory allocated by ITH module is returned to system.
883 -void IthCloseSystemService()
884 -{
885 - if (::page_locale != 0x3a4) {
886 - NtUnmapViewOfSection(NtCurrentProcess(), ::page);
887 - NtClose(::codepage_section);
888 - }
889 - if (ITH_ENABLE_THREADMAN) {
890 - NtUnmapViewOfSection(NtCurrentProcess(), ::thread_man_);
891 - NtClose(::thread_man_section);
892 - }
893 - NtClose(::root_obj);
894 -#ifdef ITH_HAS_HEAP
895 - RtlDestroyHeap(::hHeap);
896 -#endif // ITH_HAS_HEAP
897 -}
898 -
899 -//Check for existence of a file in current folder. Thread safe after init.
900 -//For ITH main module, it's ITH folder. For target process it's the target process's current folder.
901 -BOOL IthCheckFile(LPCWSTR file)
902 -{
903 - //return PathFileExistsW(file); // jichi: need Shlwapi.lib
904 -
905 - //return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
906 - //return GetFileAttributesW(file) != INVALID_FILE_ATTRIBUTES; // jichi: does not consider the current app's path
907 -
908 - // jichi 9/22/2013: Following code does not work in Wine
909 - // See: http://stackoverflow.com/questions/3828835/how-can-we-check-if-a-file-exists-or-not-using-win32-program
910 - //WIN32_FIND_DATA FindFileData;
911 - //HANDLE handle = FindFirstFileW(file, &FindFileData);
912 - //if (handle != INVALID_HANDLE_VALUE) {
913 - // FindClose(handle);
914 - // return TRUE;
915 - //}
916 - //return FALSE;
917 - if (IthIsWine()) {
918 - HANDLE hFile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, 0);
919 - if (hFile != INVALID_HANDLE_VALUE) {
920 - CloseHandle(hFile);
921 - return TRUE;
922 - } else if (!wcschr(file, L':')) { // jichi: this is relative path
923 - // jichi 9/22/2013: Change current directory to the same as main module path
924 - // Otherwise NtFile* would not work for files with relative paths.
925 - if (const wchar_t *path = GetMainModulePath()) // path to VNR's python exe
926 - if (const wchar_t *base = wcsrchr(path, L'\\')) {
927 - size_t dirlen = base - path + 1;
928 - if (dirlen + wcslen(file) < MAX_PATH) {
929 - wchar_t buf[MAX_PATH];
930 - wcsncpy(buf, path, dirlen);
931 - wcscpy(buf + dirlen, file);
932 - return IthCheckFile(buf);
933 - }
934 - }
935 - }
936 - } else { // not wine
937 - HANDLE hFile;
938 - IO_STATUS_BLOCK isb;
939 - UNICODE_STRING us;
940 - RtlInitUnicodeString(&us, file);
941 - OBJECT_ATTRIBUTES oa = { sizeof(oa), dir_obj, &us, 0, 0, 0};
942 - // jichi 9/22/2013: Following code does not work in Wine
943 - if (NT_SUCCESS(NtCreateFile(&hFile, FILE_READ_DATA, &oa, &isb, 0, 0, FILE_SHARE_READ, FILE_OPEN, 0, 0, 0))) {
944 - NtClose(hFile);
945 - return TRUE;
946 - }
947 - }
948 - return FALSE;
949 - //return IthGetFileInfo(file,file_info);
950 - //wcscpy(current_dir,file);
951 -}
952 -
953 -//Check for existence of files in current folder.
954 -//Unlike IthCheckFile, this function allows wildcard character.
955 -BOOL IthFindFile(LPCWSTR file)
956 -{
957 - NTSTATUS status;
958 - HANDLE h;
959 - UNICODE_STRING us;
960 - OBJECT_ATTRIBUTES oa = {sizeof(oa), dir_obj, &us, OBJ_CASE_INSENSITIVE, 0, 0};
961 - us.Buffer = const_cast<LPWSTR>(file);
962 - LPCWSTR path = wcsrchr(file, L'\\');
963 - if (path) {
964 - us.Length = (path - file) << 1;
965 - us.MaximumLength = us.Length;
966 - } else {
967 - us.Length = 0;
968 - us.MaximumLength = 0;
969 - }
970 - IO_STATUS_BLOCK ios;
971 - if (NT_SUCCESS(NtOpenFile(&h,FILE_LIST_DIRECTORY|SYNCHRONIZE,
972 - &oa,&ios,FILE_SHARE_READ,FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT))) {
973 - BYTE info[0x400];
974 - if (path)
975 - RtlInitUnicodeString(&us, path + 1);
976 - else
977 - RtlInitUnicodeString(&us, file);
978 - status = NtQueryDirectoryFile(h,0,0,0,&ios,info,0x400,FileBothDirectoryInformation,TRUE,&us,TRUE);
979 - NtClose(h);
980 - return NT_SUCCESS(status);
981 - }
982 - return FALSE;
983 -}
984 -//Analogous to IthFindFile, but return detail information in 'info'.
985 -BOOL IthGetFileInfo(LPCWSTR file, LPVOID info, DWORD size)
986 -{
987 - NTSTATUS status;
988 - HANDLE h;
989 - UNICODE_STRING us;
990 - LPCWSTR path = wcsrchr(file, L'\\');
991 - us.Buffer = const_cast<LPWSTR>(file);
992 - if (path) {
993 - us.Length = (path - file) << 1;
994 - us.MaximumLength = us.Length;
995 - } else {
996 - us.Length = 0;
997 - us.MaximumLength = 0;
998 - }
999 - //RtlInitUnicodeString(&us,file);
1000 - OBJECT_ATTRIBUTES oa = {sizeof(oa), dir_obj, &us, OBJ_CASE_INSENSITIVE, 0, 0};
1001 - IO_STATUS_BLOCK ios;
1002 - if (NT_SUCCESS(NtOpenFile(&h,FILE_LIST_DIRECTORY|SYNCHRONIZE,
1003 - &oa,&ios,FILE_SHARE_READ,FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT))) {
1004 - RtlInitUnicodeString(&us,file);
1005 - status = NtQueryDirectoryFile(h,0,0,0,&ios,info,size,FileBothDirectoryInformation,0,&us,0);
1006 - status = NT_SUCCESS(status);
1007 - NtClose(h);
1008 - } else
1009 - status = FALSE;
1010 - return status;
1011 -}
1012 -
1013 -//Check for existence of a file with full NT path(start with \??\).
1014 -BOOL IthCheckFileFullPath(LPCWSTR file)
1015 -{
1016 - UNICODE_STRING us;
1017 - RtlInitUnicodeString(&us, file);
1018 - OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, 0, 0};
1019 - HANDLE hFile;
1020 - IO_STATUS_BLOCK isb;
1021 - if (NT_SUCCESS(NtCreateFile(&hFile,FILE_READ_DATA,&oa,&isb,0,0,FILE_SHARE_READ,FILE_OPEN,0,0,0))) {
1022 - NtClose(hFile);
1023 - return TRUE;
1024 - } else
1025 - return FALSE;
1026 -}
1027 -//Create or open file in current folder. Analogous to Win32 CreateFile.
1028 -//option: GENERIC_READ / GENERIC_WRITE.
1029 -//share: FILE_SHARE_READ / FILE_SHARE_WRITE / FILE_SHARE_DELETE. 0 for exclusive access.
1030 -//disposition: FILE_OPEN / FILE_OPEN_IF.
1031 -//Use FILE_OPEN instead of OPEN_EXISTING and FILE_OPEN_IF for CREATE_ALWAYS.
1032 -HANDLE IthCreateFile(LPCWSTR name, DWORD option, DWORD share, DWORD disposition)
1033 -{
1034 - UNICODE_STRING us;
1035 - RtlInitUnicodeString(&us, name);
1036 - OBJECT_ATTRIBUTES oa = { sizeof(oa), dir_obj, &us, OBJ_CASE_INSENSITIVE, 0, 0 };
1037 - HANDLE hFile;
1038 - IO_STATUS_BLOCK isb;
1039 - return NT_SUCCESS(NtCreateFile(&hFile,
1040 - option|FILE_READ_ATTRIBUTES|SYNCHRONIZE,
1041 - &oa,&isb,0,0,share,disposition,
1042 - FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE,0,0)) ?
1043 - hFile : INVALID_HANDLE_VALUE;
1044 -}
1045 -//Create a directory file in current folder.
1046 -HANDLE IthCreateDirectory(LPCWSTR name)
1047 -{
1048 - UNICODE_STRING us;
1049 - RtlInitUnicodeString(&us,name);
1050 - OBJECT_ATTRIBUTES oa = {sizeof(oa), dir_obj, &us, OBJ_CASE_INSENSITIVE, 0, 0};
1051 - HANDLE hFile;
1052 - IO_STATUS_BLOCK isb;
1053 - return NT_SUCCESS(NtCreateFile(&hFile,FILE_LIST_DIRECTORY|FILE_TRAVERSE|SYNCHRONIZE,&oa,&isb,0,0,
1054 - FILE_SHARE_READ|FILE_SHARE_WRITE,FILE_OPEN_IF,FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT,0,0)) ?
1055 - hFile : INVALID_HANDLE_VALUE;
1056 -}
1057 -
1058 -HANDLE IthCreateFileInDirectory(LPCWSTR name, HANDLE dir, DWORD option, DWORD share, DWORD disposition)
1059 -{
1060 - UNICODE_STRING us;
1061 - RtlInitUnicodeString(&us,name);
1062 - if (dir == 0) dir = dir_obj;
1063 - OBJECT_ATTRIBUTES oa = {sizeof(oa), dir, &us, OBJ_CASE_INSENSITIVE, 0, 0};
1064 - HANDLE hFile;
1065 - IO_STATUS_BLOCK isb;
1066 - return NT_SUCCESS(NtCreateFile(&hFile,
1067 - option|FILE_READ_ATTRIBUTES|SYNCHRONIZE,
1068 - &oa,&isb,0,0,share,disposition,
1069 - FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE,0,0)) ?
1070 - hFile : INVALID_HANDLE_VALUE;
1071 -}
1072 -
1073 -//Analogous to IthCreateFile, but with full NT path.
1074 -HANDLE IthCreateFileFullPath(LPCWSTR path, DWORD option, DWORD share, DWORD disposition)
1075 -{
1076 - UNICODE_STRING us;
1077 - RtlInitUnicodeString(&us,path);
1078 - OBJECT_ATTRIBUTES oa = {sizeof(oa), 0, &us, OBJ_CASE_INSENSITIVE, 0, 0};
1079 - HANDLE hFile;
1080 - IO_STATUS_BLOCK isb;
1081 - return NT_SUCCESS(NtCreateFile(&hFile,
1082 - option|FILE_READ_ATTRIBUTES|SYNCHRONIZE,
1083 - &oa,&isb,0,0,share,disposition,
1084 - FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE,0,0)) ?
1085 - hFile : INVALID_HANDLE_VALUE;
1086 -}
1087 -
1088 -//Create section object for sharing memory between processes.
1089 -//Similar to CreateFileMapping.
1090 -HANDLE IthCreateSection(LPCWSTR name, DWORD size, DWORD right)
1091 -{
1092 -// jichi 9/25/2013: GENERIC_ALL does NOT work one wine
1093 -// See ZwCreateSection: http://msdn.microsoft.com/en-us/library/windows/hardware/ff566428%28v=vs.85%29.aspx
1094 -//#ifdef ITH_WINE
1095 - enum { DesiredAccess = SECTION_ALL_ACCESS };
1096 -//#else
1097 -// enum { DesiredAccess = GENERIC_ALL }; // jichi 9/25/2013: not sure whhy ITH is usin GENERIC_ALL
1098 -//#endif // ITH_WINE
1099 -#define eval (NT_SUCCESS(NtCreateSection(&hSection, DesiredAccess, poa, &s, \
1100 - right, SEC_COMMIT, 0)) ? hSection : INVALID_HANDLE_VALUE)
1101 - HANDLE hSection;
1102 - LARGE_INTEGER s = {size, 0};
1103 - OBJECT_ATTRIBUTES *poa = nullptr;
1104 - // jichi 9/25/2013: What the fxxx?! poa in the orignal source code of ITH
1105 - // is pointed to freed object on the stack?! This will crash wine!
1106 - if (name) {
1107 - UNICODE_STRING us;
1108 - RtlInitUnicodeString(&us, name);
1109 - OBJECT_ATTRIBUTES oa = {sizeof(oa), root_obj, &us,OBJ_OPENIF,0,0};
1110 - poa = &oa;
1111 - return eval;
1112 - } else
1113 - return eval;
1114 -#undef retval
1115 -}
1116 -
1117 -//Create event object. Similar to CreateEvent.
1118 -HANDLE IthCreateEvent(LPCWSTR name, DWORD auto_reset, DWORD init_state)
1119 -{
1120 -#define eval (NT_SUCCESS(NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, poa, auto_reset, init_state)) ? \
1121 - hEvent : INVALID_HANDLE_VALUE)
1122 - HANDLE hEvent;
1123 - OBJECT_ATTRIBUTES *poa = nullptr;
1124 - // jichi 9/25/2013: What the fxxx?! poa in the orignal source code of ITH
1125 - // is pointed to freed object on the stack?! This will crash wine!
1126 - if (name) {
1127 - UNICODE_STRING us;
1128 - RtlInitUnicodeString(&us,name);
1129 - OBJECT_ATTRIBUTES oa = {sizeof(oa), root_obj, &us, OBJ_OPENIF, 0, 0};
1130 - poa = &oa;
1131 - return eval;
1132 - } else
1133 - return eval;
1134 -#undef eval
1135 -}
1136 -
1137 -HANDLE IthOpenEvent(LPCWSTR name)
1138 -{
1139 - UNICODE_STRING us;
1140 - RtlInitUnicodeString(&us, name);
1141 - OBJECT_ATTRIBUTES oa = { sizeof(oa), root_obj, &us, 0, 0, 0 };
1142 - HANDLE hEvent;
1143 - return NT_SUCCESS(NtOpenEvent(&hEvent, EVENT_ALL_ACCESS, &oa)) ?
1144 - hEvent : INVALID_HANDLE_VALUE;
1145 -}
1146 -
1147 -void IthSetEvent(HANDLE hEvent) { NtSetEvent(hEvent, 0); }
1148 -
1149 -void IthResetEvent(HANDLE hEvent) { NtClearEvent(hEvent); }
1150 -
1151 -//Create mutex object. Similar to CreateMutex.
1152 -//If 'exist' is not null, it will be written 1 if mutex exist.
1153 -HANDLE IthCreateMutex(LPCWSTR name, BOOL InitialOwner, DWORD *exist)
1154 -{
1155 -#define eval NtCreateMutant(&hMutex, MUTEX_ALL_ACCESS, poa, InitialOwner)
1156 - UNICODE_STRING us;
1157 - HANDLE hMutex;
1158 - NTSTATUS status;
1159 - OBJECT_ATTRIBUTES *poa = nullptr;
1160 - // jichi 9/25/2013: What the fxxx?! poa in the orignal source code of ITH
1161 - // is pointed to freed object on the stack?! This will crash wine!
1162 - if (name) {
1163 - RtlInitUnicodeString(&us, name);
1164 - OBJECT_ATTRIBUTES oa = {sizeof(oa), root_obj, &us, OBJ_OPENIF, 0, 0};
1165 - poa = &oa;
1166 - status = eval;
1167 - } else
1168 - status = eval;
1169 - if (NT_SUCCESS(status)) {
1170 - if (exist)
1171 - *exist = status == STATUS_OBJECT_NAME_EXISTS;
1172 - return hMutex;
1173 - } else
1174 - return INVALID_HANDLE_VALUE;
1175 -#undef eval
1176 -}
1177 -
1178 -HANDLE IthOpenMutex(LPCWSTR name)
1179 -{
1180 - UNICODE_STRING us;
1181 - RtlInitUnicodeString(&us, name);
1182 - OBJECT_ATTRIBUTES oa = {sizeof(oa), root_obj, &us, 0, 0, 0};
1183 - HANDLE hMutex;
1184 - if (NT_SUCCESS(NtOpenMutant(&hMutex, MUTEX_ALL_ACCESS, &oa)))
1185 - return hMutex;
1186 - else
1187 - return INVALID_HANDLE_VALUE;
1188 -}
1189 -
1190 -BOOL IthReleaseMutex(HANDLE hMutex)
1191 -{ return NT_SUCCESS(NtReleaseMutant(hMutex, 0)); }
1192 -
1193 -//Create new thread. 'hProc' must have following right.
1194 -//PROCESS_CREATE_THREAD, PROCESS_VM_OPERATION, PROCESS_VM_READ, PROCESS_VM_WRITE.
1195 -HANDLE IthCreateThread(LPCVOID start_addr, DWORD param, HANDLE hProc)
1196 -{
1197 - HANDLE hThread;
1198 - // jichi 9/27/2013: NtCreateThread is not implemented in Wine 1.7
1199 - if (thread_man_) { // Windows XP
1200 - // jichi 9/29/2013: Reserved && commit stack size
1201 - // See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366803%28v=vs.85%29.aspx
1202 - // See: http://msdn.microsoft.com/en-us/library/ms810627.aspx
1203 - enum { DEFAULT_STACK_LIMIT = 0x400000 };
1204 - enum { DEFAULT_STACK_COMMIT = 0x10000 };
1205 - enum { PAGE_SIZE = 0x1000 };
1206 - CLIENT_ID id;
1207 - LPVOID protect;
1208 - USER_STACK stack = {};
1209 - CONTEXT ctx = {CONTEXT_FULL};
1210 - DWORD size = DEFAULT_STACK_LIMIT,
1211 - commit = DEFAULT_STACK_COMMIT;
1212 - if (!NT_SUCCESS(NtAllocateVirtualMemory(hProc, &stack.ExpandableStackBottom, 0, &size, MEM_RESERVE, PAGE_READWRITE)))
1213 - return INVALID_HANDLE_VALUE;
1214 -
1215 - stack.ExpandableStackBase = (char *)stack.ExpandableStackBottom + size;
1216 - stack.ExpandableStackLimit = (char *)stack.ExpandableStackBase - commit;
1217 - size = PAGE_SIZE;
1218 - commit += size;
1219 - protect = (char *)stack.ExpandableStackBase - commit;
1220 - NtAllocateVirtualMemory(hProc, &protect, 0, &commit, MEM_COMMIT, PAGE_READWRITE);
1221 - DWORD oldAccess; // jichi 9/29/2013: unused
1222 - NtProtectVirtualMemory(hProc, &protect, &size, PAGE_READWRITE|PAGE_GUARD, &oldAccess);
1223 - ctx.SegGs = 0;
1224 - ctx.SegFs = 0x38;
1225 - ctx.SegEs = 0x20;
1226 - ctx.SegDs = 0x20;
1227 - ctx.SegSs = 0x20;
1228 - ctx.SegCs = 0x18;
1229 - ctx.EFlags = 0x3000;
1230 - ctx.Eip = (DWORD)thread_man_->GetProcAddr(hProc);
1231 - ctx.Eax = (DWORD)start_addr;
1232 - ctx.Ecx = ctx.Eip + 0x40;
1233 - ctx.Edx = 0xffffffff;
1234 - ctx.Esp = (DWORD)stack.ExpandableStackBase - 0x10;
1235 - ctx.Ebp = param;
1236 -
1237 - // NTSYSAPI
1238 - // NTSTATUS
1239 - // NTAPI
1240 - // NtCreateThread(
1241 - // _Out_ PHANDLE ThreadHandle,
1242 - // _In_ ACCESS_MASK DesiredAccess,
1243 - // _In_ POBJECT_ATTRIBUTES ObjectAttributes,
1244 - // _In_ HANDLE ProcessHandle,
1245 - // _Out_ PCLIENT_ID ClientId,
1246 - // _In_ PCONTEXT ThreadContext,
1247 - // _In_ PUSER_STACK UserStack,
1248 - // _In_ BOOLEAN CreateSuspended
1249 - // );
1250 - if (NT_SUCCESS(NtCreateThread(
1251 - &hThread, // _Out_ PHANDLE ThreadHandle,
1252 - THREAD_ALL_ACCESS, // _In_ ACCESS_MASK DesiredAccess,
1253 - nullptr, // _In_ POBJECT_ATTRIBUTES ObjectAttributes,
1254 - hProc, // _In_ HANDLE ProcessHandle,
1255 - &id, // _Out_ PCLIENT_ID ClientId,
1256 - &ctx, // _In_ PCONTEXT ThreadContext,
1257 - &stack, // _In_ PUSER_STACK UserStack,
1258 - TRUE // _In_ BOOLEAN CreateSuspended
1259 - ))) {
1260 - // On x64 Windows, NtCreateThread in ntdll calls NtCreateThread in ntoskrnl via WOW64,
1261 - // which maps 32-bit system call to the correspond 64-bit version.
1262 - // This layer doesn't correctly copy whole CONTEXT structure, so we must set it manually
1263 - // after the thread is created.
1264 - // On x86 Windows, this step is not necessary.
1265 - NtSetContextThread(hThread, &ctx);
1266 - NtResumeThread(hThread, 0);
1267 - } else
1268 - hThread = INVALID_HANDLE_VALUE;
1269 -
1270 - } else {
1271 - // jichi 9/27/2013: CreateRemoteThread works on both Wine and Windows 7
1272 - // Use CreateRemoteThread instead
1273 - // FIXME 10/5/2031: Though sometimes works, CreateRemoteThread randomly crashes on wine.
1274 - // See:
1275 - // - http://www.unknowncheats.me/forum/c-and-c/64775-createremotethread-dll-injection.html
1276 - // - http://source.winehq.org/WineAPI/CreateRemoteThread.html
1277 - // - http://msdn.microsoft.com/en-us/library/windows/desktop/ms682437%28v=vs.85%29.aspx
1278 - // HANDLE WINAPI CreateRemoteThread(
1279 - // _In_ HANDLE hProcess,
1280 - // _In_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
1281 - // _In_ SIZE_T dwStackSize,
1282 - // _In_ LPTHREAD_START_ROUTINE lpStartAddress,
1283 - // _In_ LPVOID lpParameter,
1284 - // _In_ DWORD dwCreationFlags,
1285 - // _Out_ LPDWORD lpThreadId
1286 - // );
1287 - //ITH_TRY {
1288 - if (hProc == INVALID_HANDLE_VALUE)
1289 - hProc = GetCurrentProcess();
1290 - //DWORD dwThreadId;
1291 - hThread = CreateRemoteThread(
1292 - hProc, // _In_ HANDLE hProcess,
1293 - nullptr, // _In_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
1294 - 0, // _In_ SIZE_T dwStackSize,
1295 - (LPTHREAD_START_ROUTINE)start_addr, // _In_ LPTHREAD_START_ROUTINE lpStartAddress,
1296 - (LPVOID)param, // _In_ LPVOID lpParameter,
1297 - 0, //STACK_SIZE_PARAM_IS_A_RESERVATION // _In_ DWORD dwCreationFlags,
1298 - nullptr // _Out_ LPDWORD lpThreadId
1299 - );
1300 - if (!hThread) // jichi: this function returns nullptr instead of -1
1301 - hThread = INVALID_HANDLE_VALUE;
1302 - //} ITH_EXCEPT {
1303 - // ITH_WARN(L"exception");
1304 - // hThread = INVALID_HANDLE_VALUE;
1305 - //}
1306 - }
1307 - /*
1308 - else {
1309 - // jichi 9/29/2013: Also work on Wine and Windows 7
1310 - // See: http://waleedassar.blogspot.com/2012/06/createremotethread-vs.html
1311 - CLIENT_ID id;
1312 - //DWORD size = DEFAULT_STACK_LIMIT,
1313 - // commit = DEFAULT_STACK_COMMIT;
1314 - DWORD reserve = 0,
1315 - commit = 0;
1316 - // http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Executable%20Images/RtlCreateUserThread.html
1317 - // NTSYSAPI
1318 - // NTSTATUS
1319 - // NTAPI
1320 - // RtlCreateUserThread(
1321 - // IN HANDLE ProcessHandle,
1322 - // IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
1323 - // IN BOOLEAN CreateSuspended,
1324 - // IN ULONG StackZeroBits,
1325 - // IN OUT PULONG StackReserved,
1326 - // IN OUT PULONG StackCommit,
1327 - // IN PVOID StartAddress,
1328 - // IN PVOID StartParameter OPTIONAL,
1329 - // OUT PHANDLE ThreadHandle,
1330 - // OUT PCLIENT_ID ClientID);
1331 - if (!NT_SUCCESS(RtlCreateUserThread(
1332 - hProc, // HANDLE hProcess,
1333 - nullptr, // IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
1334 - FALSE, // IN BOOLEAN CreateSuspended,
1335 - 0, // IN ULONG StackZeroBits,
1336 - &reserve, // IN OUT PULONG StackReserved,
1337 - &commit, // IN OUT PULONG StackCommit,
1338 - (LPVOID)start_addr, // IN PVOID StartAddress,
1339 - (LPVOID)param,// IN PVOID StartParameter OPTIONAL,
1340 - &hThread, // OUT PHANDLE ThreadHandle,
1341 - &id // OUT PCLIENT_ID ClientID
1342 - )))
1343 - hThread = INVALID_HANDLE_VALUE;
1344 - }
1345 - */
1346 - return hThread;
1347 -}
1348 -
1349 -//Query module export table. Return function address if found.
1350 -//Similar to GetProcAddress
1351 -DWORD GetExportAddress(DWORD hModule,DWORD hash)
1352 -{
1353 - IMAGE_DOS_HEADER *DosHdr;
1354 - IMAGE_NT_HEADERS *NtHdr;
1355 - IMAGE_EXPORT_DIRECTORY *ExtDir;
1356 - UINT uj;
1357 - char* pcExportAddr,*pcFuncPtr,*pcBuffer;
1358 - DWORD dwReadAddr,dwFuncAddr,dwFuncName;
1359 - WORD wOrd;
1360 - DosHdr = (IMAGE_DOS_HEADER*)hModule;
1361 - if (IMAGE_DOS_SIGNATURE==DosHdr->e_magic) {
1362 - dwReadAddr=hModule+DosHdr->e_lfanew;
1363 - NtHdr=(IMAGE_NT_HEADERS*)dwReadAddr;
1364 - if (IMAGE_NT_SIGNATURE == NtHdr->Signature) {
1365 - pcExportAddr = (char*)((DWORD)hModule+
1366 - (DWORD)NtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
1367 - if (!pcExportAddr)
1368 - return 0;
1369 - ExtDir = (IMAGE_EXPORT_DIRECTORY*)pcExportAddr;
1370 - pcExportAddr = (char*)((DWORD)hModule+(DWORD)ExtDir->AddressOfNames);
1371 -
1372 - for (uj = 0; uj < ExtDir->NumberOfNames; uj++) {
1373 - dwFuncName = *(DWORD *)pcExportAddr;
1374 - pcBuffer = (char*)((DWORD)hModule+dwFuncName);
1375 - if (GetHash(pcBuffer) == hash) {
1376 - pcFuncPtr = (char*)((DWORD)hModule+(DWORD)ExtDir->AddressOfNameOrdinals+(uj*sizeof(WORD)));
1377 - wOrd = *(WORD*)pcFuncPtr;
1378 - pcFuncPtr = (char*)((DWORD)hModule+(DWORD)ExtDir->AddressOfFunctions+(wOrd*sizeof(DWORD)));
1379 - dwFuncAddr = *(DWORD *)pcFuncPtr;
1380 - return hModule+dwFuncAddr;
1381 - }
1382 - pcExportAddr += sizeof(DWORD);
1383 - }
1384 - }
1385 - }
1386 - return 0;
1387 -}
1388 -
1389 -} // extern "C"
1390 -
1391 -// EOF
1392 -
1393 -/*__declspec(naked) void normal_asm()
1394 -{
1395 - __asm
1396 - {
1397 - push ecx
1398 - push edx
1399 - mov fs:[0],esp
1400 - push ebp
1401 - call eax
1402 -_terminate:
1403 - push eax
1404 - push -2
1405 - call dword ptr [NtTerminateThread]
1406 - }
1407 -}*/
1408 -
1409 -/*
1410 -__declspec(naked) void RegToStrAsm()
1411 -{
1412 - __asm
1413 - {
1414 - mov edx, 8
1415 -_cvt_loop:
1416 - mov eax, ecx
1417 - and eax, 0xF
1418 - cmp eax, 0xA
1419 - jb _below_ten
1420 - add al,7
1421 -_below_ten:
1422 - add al,0x30
1423 - stosw
1424 - ror ecx,4
1425 - dec edx
1426 - jne _cvt_loop
1427 - retn
1428 - }
1429 -}
1430 -__declspec(naked) void except_asm()
1431 -{
1432 - __asm
1433 - {
1434 - mov eax,[esp + 4]
1435 - xor esi,esi
1436 - mov ebp,[eax]
1437 - mov ecx,[esp + 0xC]
1438 - mov ebx,[ecx + 0xB8]
1439 - sub esp,0x240
1440 - lea edi,[esp + 0x40]
1441 - mov eax,esp
1442 - push esi
1443 - push 0x1C
1444 - push eax
1445 - push esi
1446 - push ebx
1447 - push -1
1448 - call dword ptr [NtQueryVirtualMemory]
1449 - test eax,eax
1450 - jne _terminate
1451 - mov eax,esp
1452 - push eax
1453 - push 0x200
1454 - push edi
1455 - push 2
1456 - push ebx
1457 - push -1
1458 - call dword ptr [NtQueryVirtualMemory]
1459 - test eax,eax
1460 - jne _terminate
1461 - pop esi
1462 - xadd edi,esi
1463 - std
1464 - mov al,0x5C
1465 - repen scasw
1466 - mov word ptr [edi + 2], 0x3A
1467 - mov ecx,ebx
1468 - sub ecx,[esp]
1469 - call RegToStrAsm
1470 - inc edi
1471 - inc edi
1472 - xchg esi,edi
1473 - mov ecx,ebp
1474 - call RegToStrAsm
1475 - inc edi
1476 - inc edi
1477 - xor eax,eax
1478 - mov [edi + 0x10], eax
1479 - push 0
1480 - push edi
1481 - push esi
1482 - push 0
1483 - call dword ptr [MessageBoxW]
1484 - or eax, -1
1485 - jmp _terminate
1486 - }
1487 -}
1488 -
1489 -//Prompt for file name.
1490 -HANDLE IthPromptCreateFile(DWORD option, DWORD share, DWORD disposition)
1491 -{
1492 - OPENFILENAME ofn = {sizeof(ofn)}; // common dialog box structure
1493 - WCHAR szFile[MAX_PATH]; // buffer for file name
1494 - wcscpy(current_dir,L"ITH_export.txt");
1495 - wcscpy(szFile,file_path);
1496 -
1497 - //szFile[0]=0;
1498 - ofn.lpstrFile = szFile + 4;
1499 - ofn.nMaxFile = MAX_PATH;
1500 - ofn.lpstrFilter = L"Text\0*.txt";
1501 - BOOL result;
1502 - if (disposition==FILE_OPEN)
1503 - result=GetOpenFileName(&ofn);
1504 - else
1505 - result=GetSaveFileName(&ofn);
1506 - if (result)
1507 - {
1508 - LPWSTR s=szFile+wcslen(szFile) - 4;
1509 - if (_wcsicmp(s,L".txt")!=0) wcscpy(s + 4,L".txt");
1510 - return IthCreateFileFullPath(szFile,option,share,disposition);
1511 - }
1512 - else return INVALID_HANDLE_VALUE;
1513 -}
1514 -*/
1 -#pragma once
2 -
3 -// ith/sys.h
4 -// 8/23/2013 jichi
5 -// Branch: ITH/IHF_SYS.h, rev 111
6 -
7 -#ifdef _MSC_VER
8 -# pragma warning(disable:4800) // C4800: forcing value to bool
9 -#endif // _MSC_VER
10 -
11 -#include "ntdll/ntdll.h"
12 -
13 -// jichi 8/24/2013: Why extern "C"? Any specific reason to use C instead of C++ naming?
14 -extern "C" {
15 -//int disasm(BYTE *opcode0); // jichi 8/15/2013: move disasm to separate file
16 -extern WORD *NlsAnsiCodePage;
17 -int FillRange(LPCWSTR name,DWORD *lower, DWORD *upper);
18 -int MB_WC(char *mb, wchar_t *wc);
19 -//int MB_WC_count(char *mb, int mb_length);
20 -int WC_MB(wchar_t *wc, char *mb);
21 -
22 -// jichi 10/1/2013: Return 0 if failed. So, it is ambiguous if the search pattern starts at 0
23 -DWORD SearchPattern(DWORD base, DWORD base_length, LPCVOID search, DWORD search_length); // KMP
24 -
25 -// jichi 2/5/2014: The same as SearchPattern except it uses 0xff to match everything
26 -// According to @Andys, 0xff seldom appear in the source code: http://sakuradite.com/topic/124
27 -enum : BYTE { SP_ANY = 0xff };
28 -#define SP_ANY_2 SP_ANY,SP_ANY
29 -#define SP_ANY_3 SP_ANY,SP_ANY,SP_ANY
30 -#define SP_ANY_4 SP_ANY,SP_ANY,SP_ANY,SP_ANY
31 -DWORD SearchPatternEx(DWORD base, DWORD base_length, LPCVOID search, DWORD search_length, BYTE wildcard=SP_ANY);
32 -
33 -BOOL IthInitSystemService();
34 -void IthCloseSystemService();
35 -DWORD IthGetMemoryRange(LPCVOID mem, DWORD *base, DWORD *size);
36 -BOOL IthCheckFile(LPCWSTR file);
37 -BOOL IthFindFile(LPCWSTR file);
38 -BOOL IthGetFileInfo(LPCWSTR file, LPVOID info, DWORD size = 0x1000);
39 -BOOL IthCheckFileFullPath(LPCWSTR file);
40 -HANDLE IthCreateFile(LPCWSTR name, DWORD option, DWORD share, DWORD disposition);
41 -HANDLE IthCreateFileInDirectory(LPCWSTR name, HANDLE dir, DWORD option, DWORD share, DWORD disposition);
42 -HANDLE IthCreateDirectory(LPCWSTR name);
43 -HANDLE IthCreateFileFullPath(LPCWSTR fullpath, DWORD option, DWORD share, DWORD disposition);
44 -HANDLE IthPromptCreateFile(DWORD option, DWORD share, DWORD disposition);
45 -HANDLE IthCreateSection(LPCWSTR name, DWORD size, DWORD right);
46 -HANDLE IthCreateEvent(LPCWSTR name, DWORD auto_reset=0, DWORD init_state=0);
47 -HANDLE IthOpenEvent(LPCWSTR name);
48 -void IthSetEvent(HANDLE hEvent);
49 -void IthResetEvent(HANDLE hEvent);
50 -HANDLE IthCreateMutex(LPCWSTR name, BOOL InitialOwner, DWORD *exist=0);
51 -HANDLE IthOpenMutex(LPCWSTR name);
52 -BOOL IthReleaseMutex(HANDLE hMutex);
53 -//DWORD IthWaitForSingleObject(HANDLE hObject, DWORD dwTime);
54 -HANDLE IthCreateThread(LPCVOID start_addr, DWORD param, HANDLE hProc=(HANDLE)-1);
55 -DWORD GetExportAddress(DWORD hModule,DWORD hash);
56 -void IthSleep(int time); // jichi 9/28/2013: in ms
57 -void IthSystemTimeToLocalTime(LARGE_INTEGER *ptime);
58 -void FreeThreadStart(HANDLE hProc);
59 -void CheckThreadStart();
60 -} // extern "C"
61 -
62 -#ifdef ITH_HAS_HEAP
63 -extern HANDLE hHeap; // used in ith/common/memory.h
64 -#endif // ITH_HAS_HEAP
65 -
66 -extern DWORD current_process_id;
67 -extern DWORD debug;
68 -extern BYTE LeadByteTable[];
69 -extern LPVOID page;
70 -extern BYTE launch_time[];
71 -
72 -inline DWORD GetHash(LPSTR str)
73 -{
74 - DWORD hash = 0;
75 - //for (; *str; str++)
76 - while (*str)
77 - hash = ((hash>>7) | (hash<<25)) + *str++;
78 - return hash;
79 -}
80 -
81 -inline DWORD GetHash(LPCWSTR str)
82 -{
83 - DWORD hash = 0;
84 - //for (; *str; str++)
85 - while (*str)
86 - hash = ((hash>>7) | (hash<<25)) + *str++;
87 - return hash;
88 -}
89 -
90 -inline void IthBreak()
91 -{ if (debug) __debugbreak(); }
92 -
93 -inline LPCWSTR GetMainModulePath()
94 -{
95 - __asm
96 - {
97 - mov eax, fs:[0x30]
98 - mov eax, [eax + 0xC]
99 - mov eax, [eax + 0xC]
100 - mov eax, [eax + 0x28]
101 - }
102 -}
103 -
104 -// jichi 9/28/2013: Add this to lock NtWriteFile in wine
105 -class IthMutexLocker
106 -{
107 - HANDLE m;
108 -public:
109 - explicit IthMutexLocker(HANDLE mutex) : m(mutex)
110 - { NtWaitForSingleObject(m, 0, 0); }
111 -
112 - ~IthMutexLocker() { if (m != INVALID_HANDLE_VALUE) IthReleaseMutex(m); }
113 -
114 - bool locked() const { return m != INVALID_HANDLE_VALUE; }
115 -
116 - void unlock() { if (m != INVALID_HANDLE_VALUE) { IthReleaseMutex(m); m = INVALID_HANDLE_VALUE; } }
117 -};
118 -
119 -void IthCoolDown();
120 -
121 -BOOL IthIsWine();
122 -BOOL IthIsWindowsXp();
123 -//BOOL IthIsWindows8OrGreater(); // not public
124 -
125 -/** Get current dll path.
126 - * @param buf
127 - * @param len
128 - * @return length of the path excluding \0
129 - */
130 -size_t IthGetCurrentModulePath(wchar_t *buf, size_t len);
131 -
132 -// EOF
1 -# sys.pri
2 -# 8/21/2013 jichi
3 -
4 -DEFINES += WITH_LIB_ITH_SYS
5 -LIBS += -lvnrsys
6 -DEPENDPATH += $$PWD
7 -HEADERS += $$PWD/sys.h
8 -#SOURCES += $$PWD/sys.cc
9 -
10 -#include($$LIBDIR/winddk/winddk.pri)
11 -#LIBS += -L$$WDK/lib/wxp/i386
12 -
13 -# EOF
1 -# sys.pro
2 -# 8/21/2013 jichi
3 -# Build vnrsys.lib
4 -
5 -CONFIG += noqt noeh staticlib
6 -
7 -include(../../../../config.pri)
8 -include($$LIBDIR/ntdll/ntdll.pri)
9 -
10 -#include($$LIBDIR/winddk/winddk.pri)
11 -#LIBS += -L$$WDK/lib/wxp/i386
12 -
13 -# jichi 9/22/2013: When ITH is on wine, certain NT functions are replaced
14 -#DEFINES += ITH_WINE
15 -
16 -# jichi 9/14/2013: Windows XP's msvnrt does not have except handler
17 -DEFINES -= ITH_HAS_SEH
18 -
19 -# jichi 11/24/2013: Disable manual heap
20 -DEFINES -= ITH_HAS_HEAP
21 -
22 -## Libraries
23 -
24 -#INCLUDEPATH += $$ITH_HOME/include
25 -#INCLUDEPATH += $$WDK7_HOME/inc/ddk
26 -
27 -#LIBS += -lgdi32 -luser32 -lkernel32
28 -#LIBS += -L$$WDK7_HOME/lib/wxp/i386 -lntdll
29 -#LIBS += $$WDK7_HOME/lib/crt/i386/msvcrt.lib # Override msvcrt10
30 -
31 -#DEFINES += ITH_HAS_CXX
32 -
33 -#LIBS += -lith_sys -lntdll
34 -#LIBS += -lith_tls -lntdll
35 -#LIBS += -lntoskrnl
36 -
37 -DEFINES += _CRT_NON_CONFORMING_SWPRINTFS
38 -
39 -## Sources
40 -
41 -TEMPLATE = lib
42 -TARGET = vnrsys
43 -
44 -HEADERS += sys.h
45 -SOURCES += sys.cc
46 -
47 -OTHER_FILES += sys.pri
48 -
49 -# EOF
1 -12/16/2013
2 -
3 -Differences between xp.dll and non-xp.dll for vnrhook.
4 -
5 -non-xp:
6 - CONFIG += eh
7 -
8 -xp:
9 - CONFIG += noeh
10 - CONFIG -= embed_manifest_dll # Pure dynamic determined. The manifest would break Windows XP support
11 - include($$LIBDIR/winseh/winseh_safe.pri)