Showing
20 changed files
with
2162 additions
and
0 deletions
gui/PointerTable.h
0 → 100644
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 | +}; |
gui/ProcessWindow.cpp
0 → 100644
1 | +#include "ProcessWindow.h" | ||
2 | +#include "resource.h" | ||
3 | +#include "ith/host/srv.h" | ||
4 | +#include "ith/host/hookman.h" | ||
5 | +#include "ProfileManager.h" | ||
6 | +#include "Profile.h" | ||
7 | + | ||
8 | +extern HookManager* man; // main.cpp | ||
9 | +extern ProfileManager* pfman; // ProfileManager.cpp | ||
10 | + | ||
11 | +ProcessWindow::ProcessWindow(HWND hDialog) : hDlg(hDialog) | ||
12 | +{ | ||
13 | + hbRefresh = GetDlgItem(hDlg, IDC_BUTTON1); | ||
14 | + hbAttach = GetDlgItem(hDlg, IDC_BUTTON2); | ||
15 | + hbDetach = GetDlgItem(hDlg, IDC_BUTTON3); | ||
16 | + hbAddProfile = GetDlgItem(hDlg, IDC_BUTTON5); | ||
17 | + hbRemoveProfile = GetDlgItem(hDlg, IDC_BUTTON6); | ||
18 | + EnableWindow(hbAddProfile, FALSE); | ||
19 | + EnableWindow(hbRemoveProfile, FALSE); | ||
20 | + hlProcess = GetDlgItem(hDlg, IDC_LIST1); | ||
21 | + heOutput = GetDlgItem(hDlg, IDC_EDIT1); | ||
22 | + ListView_SetExtendedListViewStyleEx(hlProcess, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); | ||
23 | + InitProcessDlg(); | ||
24 | + RefreshProcess(); | ||
25 | +} | ||
26 | + | ||
27 | +void ProcessWindow::InitProcessDlg() | ||
28 | +{ | ||
29 | + LVCOLUMN lvc = {}; | ||
30 | + lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; | ||
31 | + lvc.fmt = LVCFMT_RIGHT; // left-aligned column | ||
32 | + lvc.cx = 40; | ||
33 | + lvc.pszText = L"PID"; | ||
34 | + ListView_InsertColumn(hlProcess, 0, &lvc); | ||
35 | + lvc.cx = 100; | ||
36 | + lvc.fmt = LVCFMT_LEFT; // left-aligned column | ||
37 | + lvc.pszText = L"Name"; | ||
38 | + ListView_InsertColumn(hlProcess, 1, &lvc); | ||
39 | +} | ||
40 | + | ||
41 | +void ProcessWindow::RefreshProcess() | ||
42 | +{ | ||
43 | + ListView_DeleteAllItems(hlProcess); | ||
44 | + LVITEM item = {}; | ||
45 | + item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; | ||
46 | + DWORD idProcess[1024], cbNeeded; | ||
47 | + WCHAR path[MAX_PATH]; | ||
48 | + | ||
49 | + if (EnumProcesses(idProcess, sizeof(idProcess), &cbNeeded)) | ||
50 | + { | ||
51 | + DWORD len = cbNeeded / sizeof(DWORD); | ||
52 | + for (DWORD i = 0; i < len; ++i) | ||
53 | + { | ||
54 | + DWORD pid = idProcess[i]; | ||
55 | + UniqueHandle hProcess(OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid)); | ||
56 | + if (hProcess) | ||
57 | + { | ||
58 | + if (GetProcessImageFileName(hProcess.get(), path, MAX_PATH)) | ||
59 | + { | ||
60 | + WCHAR buffer[256]; | ||
61 | + std::swprintf(buffer, L"%d", pid); | ||
62 | + PWCHAR name = wcsrchr(path, L'\\') + 1; | ||
63 | + item.pszText = buffer; | ||
64 | + item.lParam = pid; | ||
65 | + ListView_InsertItem(hlProcess, &item); | ||
66 | + ListView_SetItemText(hlProcess, item.iItem, 1, name); | ||
67 | + } | ||
68 | + } | ||
69 | + } | ||
70 | + } | ||
71 | +} | ||
72 | + | ||
73 | +void ProcessWindow::AttachProcess() | ||
74 | +{ | ||
75 | + DWORD pid = GetSelectedPID(); | ||
76 | + if (IHF_InjectByPID(pid) != -1) | ||
77 | + RefreshThreadWithPID(pid, true); | ||
78 | +} | ||
79 | + | ||
80 | +void ProcessWindow::DetachProcess() | ||
81 | +{ | ||
82 | + DWORD pid = GetSelectedPID(); | ||
83 | + if (IHF_ActiveDetachProcess(pid) == 0) | ||
84 | + RefreshThreadWithPID(pid, false); | ||
85 | +} | ||
86 | + | ||
87 | +void ProcessWindow::AddCurrentToProfile() | ||
88 | +{ | ||
89 | + DWORD pid = GetSelectedPID(); | ||
90 | + auto path = GetProcessPath(pid); | ||
91 | + if (!path.empty()) | ||
92 | + { | ||
93 | + Profile* pf = pfman->AddProfile(path, pid); | ||
94 | + pfman->FindProfileAndUpdateHookAddresses(pid, path); | ||
95 | + RefreshThread(ListView_GetSelectionMark(hlProcess)); | ||
96 | + } | ||
97 | +} | ||
98 | + | ||
99 | +void ProcessWindow::RemoveCurrentFromProfile() | ||
100 | +{ | ||
101 | + DWORD pid = GetSelectedPID(); | ||
102 | + auto path = GetProcessPath(pid); | ||
103 | + if (!path.empty()) | ||
104 | + { | ||
105 | + pfman->DeleteProfile(path); | ||
106 | + RefreshThread(ListView_GetSelectionMark(hlProcess)); | ||
107 | + } | ||
108 | +} | ||
109 | + | ||
110 | +void ProcessWindow::RefreshThread(int index) | ||
111 | +{ | ||
112 | + LVITEM item = {}; | ||
113 | + item.mask = LVIF_PARAM; | ||
114 | + item.iItem = index; | ||
115 | + ListView_GetItem(hlProcess, &item); | ||
116 | + DWORD pid = item.lParam; | ||
117 | + bool isAttached = man->GetProcessRecord(pid) != NULL; | ||
118 | + RefreshThreadWithPID(pid, isAttached); | ||
119 | +} | ||
120 | + | ||
121 | +void ProcessWindow::RefreshThreadWithPID(DWORD pid, bool isAttached) | ||
122 | +{ | ||
123 | + EnableWindow(hbDetach, isAttached); | ||
124 | + EnableWindow(hbAttach, !isAttached); | ||
125 | + auto path = GetProcessPath(pid); | ||
126 | + bool hasProfile = !path.empty() && pfman->HasProfile(path); | ||
127 | + EnableWindow(hbAddProfile, isAttached && !hasProfile); | ||
128 | + EnableWindow(hbRemoveProfile, hasProfile); | ||
129 | + if (pid == GetCurrentProcessId()) | ||
130 | + EnableWindow(hbAttach, FALSE); | ||
131 | +} | ||
132 | + | ||
133 | +DWORD ProcessWindow::GetSelectedPID() | ||
134 | +{ | ||
135 | + LVITEM item={}; | ||
136 | + item.mask = LVIF_PARAM; | ||
137 | + item.iItem = ListView_GetSelectionMark(hlProcess); | ||
138 | + ListView_GetItem(hlProcess, &item); | ||
139 | + return item.lParam; | ||
140 | +} |
gui/ProcessWindow.h
0 → 100644
1 | +#pragma once | ||
2 | +#include "ITH.h" | ||
3 | + | ||
4 | +class ProcessWindow | ||
5 | +{ | ||
6 | +public: | ||
7 | + ProcessWindow(HWND hDialog); | ||
8 | + void InitProcessDlg(); | ||
9 | + void RefreshProcess(); | ||
10 | + void AttachProcess(); | ||
11 | + void DetachProcess(); | ||
12 | + void AddCurrentToProfile(); | ||
13 | + void RemoveCurrentFromProfile(); | ||
14 | + void RefreshThread(int index); | ||
15 | +private: | ||
16 | + void RefreshThreadWithPID(DWORD pid, bool isAttached); | ||
17 | + DWORD GetSelectedPID(); | ||
18 | + HWND hDlg; | ||
19 | + HWND hlProcess; | ||
20 | + HWND hbRefresh,hbAttach,hbDetach,hbAddProfile,hbRemoveProfile; | ||
21 | + HWND heOutput; | ||
22 | +}; |
gui/Profile.cpp
0 → 100644
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 | +} |
gui/Profile.h
0 → 100644
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 | +}; |
gui/ProfileManager.cpp
0 → 100644
1 | +#include "ProfileManager.h" | ||
2 | +#include "Profile.h" | ||
3 | +#include "ith/host/srv.h" | ||
4 | +#include "ith/host/hookman.h" | ||
5 | +#include "ith/common/types.h" | ||
6 | +#include "ith/common/const.h" | ||
7 | + | ||
8 | +extern HookManager* man; // main.cpp | ||
9 | +extern LONG auto_inject, auto_insert, inject_delay; // main.cpp | ||
10 | +extern LONG insert_delay, process_time; // main.cpp | ||
11 | +bool MonitorFlag; | ||
12 | +ProfileManager* pfman; | ||
13 | + | ||
14 | +DWORD WINAPI MonitorThread(LPVOID lpThreadParameter); | ||
15 | +void AddHooksToProfile(Profile& pf, const ProcessRecord& pr); | ||
16 | +void AddThreadsToProfile(Profile& pf, const ProcessRecord& pr, DWORD pid); | ||
17 | +DWORD AddThreadToProfile(Profile& pf, const ProcessRecord& pr, TextThread& thread); | ||
18 | +void MakeHookRelative(const ProcessRecord& pr, HookParam& hp); | ||
19 | +std::wstring GetHookNameByAddress(const ProcessRecord& pr, DWORD hook_address); | ||
20 | +void GetHookNameToAddressMap(const ProcessRecord& pr, std::map<std::wstring, DWORD>& hookNameToAddress); | ||
21 | + | ||
22 | +ProfileManager::ProfileManager(): | ||
23 | +hMonitorThread(IthCreateThread(MonitorThread, 0)) | ||
24 | +{ | ||
25 | + LoadProfile(); | ||
26 | +} | ||
27 | +ProfileManager::~ProfileManager() | ||
28 | +{ | ||
29 | + SaveProfile(); | ||
30 | + WaitForSingleObject(hMonitorThread.get(), 0); | ||
31 | +} | ||
32 | + | ||
33 | +Profile* ProfileManager::GetProfile(DWORD pid) | ||
34 | +{ | ||
35 | + std::wstring path = GetProcessPath(pid); | ||
36 | + if (!path.empty()) | ||
37 | + { | ||
38 | + auto node = profile_tree.find(path); | ||
39 | + if (node != profile_tree.end()) | ||
40 | + return node->second.get(); | ||
41 | + } | ||
42 | + return NULL; | ||
43 | +} | ||
44 | + | ||
45 | +bool ProfileManager::AddProfile(pugi::xml_node game) | ||
46 | +{ | ||
47 | + auto file = game.child(L"File"); | ||
48 | + auto profile = game.child(L"Profile"); | ||
49 | + if (!file || !profile) | ||
50 | + return false; | ||
51 | + auto path = file.attribute(L"Path"); | ||
52 | + if (!path) | ||
53 | + return false; | ||
54 | + auto profile_title = game.attribute(L"Title"); | ||
55 | + auto title = profile_title ? profile_title.value() : L""; | ||
56 | + auto pf = new Profile(title); | ||
57 | + if (!pf->XmlReadProfile(profile)) | ||
58 | + return false; | ||
59 | + AddProfile(path.value(), profile_ptr(pf)); | ||
60 | + return true; | ||
61 | +} | ||
62 | + | ||
63 | +Profile* ProfileManager::AddProfile(const std::wstring& path, DWORD pid) | ||
64 | +{ | ||
65 | + CSLock lock(cs); | ||
66 | + auto& pf = profile_tree[path]; | ||
67 | + if (!pf) | ||
68 | + { | ||
69 | + std::wstring title = GetProcessTitle(pid); | ||
70 | + pf.reset(new Profile(title)); | ||
71 | + } | ||
72 | + return pf.get(); | ||
73 | +} | ||
74 | + | ||
75 | +Profile* ProfileManager::AddProfile(const std::wstring& path, profile_ptr new_profile) | ||
76 | +{ | ||
77 | + CSLock lock(cs); | ||
78 | + auto& pf = profile_tree[path]; | ||
79 | + if (!pf) | ||
80 | + pf.swap(new_profile); | ||
81 | + return pf.get(); | ||
82 | +} | ||
83 | + | ||
84 | +void ProfileManager::WriteProfileXml(const std::wstring& path, Profile& pf, pugi::xml_node root) | ||
85 | +{ | ||
86 | + auto game = root.append_child(L"Game"); | ||
87 | + auto file_node = game.append_child(L"File"); | ||
88 | + file_node.append_attribute(L"Path") = path.c_str(); | ||
89 | + auto profile_node = game.append_child(L"Profile"); | ||
90 | + pf.XmlWriteProfile(profile_node); | ||
91 | + if (!pf.Title().empty()) | ||
92 | + { | ||
93 | + if (!game.attribute(L"Title")) | ||
94 | + game.append_attribute(L"Title"); | ||
95 | + game.attribute(L"Title") = pf.Title().c_str(); | ||
96 | + } | ||
97 | +} | ||
98 | + | ||
99 | +void ProfileManager::LoadProfile() | ||
100 | +{ | ||
101 | + pugi::xml_document doc; | ||
102 | + UniqueHandle hFile(IthCreateFile(L"ITH_Profile.xml", GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING)); | ||
103 | + if (hFile.get() == INVALID_HANDLE_VALUE) | ||
104 | + return; | ||
105 | + DWORD size = GetFileSize(hFile.get(), NULL); | ||
106 | + std::unique_ptr<char[]> buffer(new char[size]); | ||
107 | + ReadFile(hFile.get(), buffer.get(), size, &size, NULL); | ||
108 | + auto result = doc.load_buffer(buffer.get(), size); | ||
109 | + if (!result) | ||
110 | + return; | ||
111 | + auto root = doc.root().child(L"ITH_Profile"); | ||
112 | + if (!root) | ||
113 | + return; | ||
114 | + for (auto game = root.begin(); game != root.end(); ++game) | ||
115 | + AddProfile(*game); | ||
116 | +} | ||
117 | + | ||
118 | +void ProfileManager::SaveProfile() | ||
119 | +{ | ||
120 | + pugi::xml_document doc; | ||
121 | + auto root = doc.append_child(L"ITH_Profile"); | ||
122 | + for (auto it = profile_tree.begin(); it != profile_tree.end(); ++it) { | ||
123 | + auto& path = it->first; | ||
124 | + auto& profile = it->second; | ||
125 | + WriteProfileXml(path, *profile, root); | ||
126 | + } | ||
127 | + UniqueHandle hFile(IthCreateFile(L"ITH_Profile.xml", GENERIC_WRITE, 0, CREATE_ALWAYS)); | ||
128 | + if (hFile.get() != INVALID_HANDLE_VALUE) | ||
129 | + { | ||
130 | + FileWriter fw(hFile.get()); | ||
131 | + doc.save(fw); | ||
132 | + } | ||
133 | +} | ||
134 | + | ||
135 | +void ProfileManager::DeleteProfile(const std::wstring& path) | ||
136 | +{ | ||
137 | + CSLock lock(cs); | ||
138 | + profile_tree.erase(profile_tree.find(path)); | ||
139 | +} | ||
140 | + | ||
141 | +void ProfileManager::FindProfileAndUpdateHookAddresses(DWORD pid, const std::wstring& path) | ||
142 | +{ | ||
143 | + if (path.empty()) | ||
144 | + return; | ||
145 | + auto it = profile_tree.find(path); | ||
146 | + if (it == profile_tree.end()) | ||
147 | + return; | ||
148 | + auto& pf = it->second; | ||
149 | + const ProcessRecord* pr = man->GetProcessRecord(pid); | ||
150 | + if (pr == NULL) | ||
151 | + return; | ||
152 | + // hook name -> hook address | ||
153 | + std::map<std::wstring, DWORD> hookNameToAddress; | ||
154 | + GetHookNameToAddressMap(*pr, hookNameToAddress); | ||
155 | + for (auto thread_profile = pf->Threads().begin(); thread_profile != pf->Threads().end(); | ||
156 | + ++thread_profile) | ||
157 | + { | ||
158 | + auto it = hookNameToAddress.find((*thread_profile)->HookName()); | ||
159 | + if (it != hookNameToAddress.end()) | ||
160 | + (*thread_profile)->HookAddress() = it->second; | ||
161 | + } | ||
162 | +} | ||
163 | + | ||
164 | +void GetHookNameToAddressMap(const ProcessRecord& pr, | ||
165 | + std::map<std::wstring, DWORD>& hookNameToAddress) | ||
166 | +{ | ||
167 | + WaitForSingleObject(pr.hookman_mutex, 0); | ||
168 | + auto hooks = (const Hook*)pr.hookman_map; | ||
169 | + for (DWORD i = 0; i < MAX_HOOK; ++i) | ||
170 | + { | ||
171 | + if (hooks[i].Address() == 0) | ||
172 | + continue; | ||
173 | + auto& hook = hooks[i]; | ||
174 | + std::unique_ptr<WCHAR[]> name(new WCHAR[hook.NameLength() * 2]); | ||
175 | + if (ReadProcessMemory(pr.process_handle, hook.Name(), name.get(), hook.NameLength() * 2, NULL)) | ||
176 | + hookNameToAddress[name.get()] = hook.Address(); | ||
177 | + } | ||
178 | + ReleaseMutex(pr.hookman_mutex); | ||
179 | +} | ||
180 | + | ||
181 | +bool ProfileManager::HasProfile(const std::wstring& path) | ||
182 | +{ | ||
183 | + return profile_tree.find(path) != profile_tree.end(); | ||
184 | +} | ||
185 | + | ||
186 | +DWORD ProfileManager::ProfileCount() | ||
187 | +{ | ||
188 | + return profile_tree.size(); | ||
189 | +} | ||
190 | + | ||
191 | +DWORD WINAPI InjectThread(LPVOID lpThreadParameter) | ||
192 | +{ | ||
193 | + DWORD pid = (DWORD)lpThreadParameter; | ||
194 | + Sleep(inject_delay); | ||
195 | + if (man == NULL) | ||
196 | + return 0; | ||
197 | + DWORD status = IHF_InjectByPID(pid); | ||
198 | + if (!auto_insert) | ||
199 | + return status; | ||
200 | + if (status == -1) | ||
201 | + return status; | ||
202 | + Sleep(insert_delay); | ||
203 | + const Profile* pf = pfman->GetProfile(pid); | ||
204 | + if (pf) | ||
205 | + { | ||
206 | + SendParam sp; | ||
207 | + sp.type = 0; | ||
208 | + for (auto hp = pf->Hooks().begin(); hp != pf->Hooks().end(); ++hp) | ||
209 | + IHF_InsertHook(pid, const_cast<HookParam*>(&(*hp)->HP()), (*hp)->Name().c_str()); | ||
210 | + } | ||
211 | + return status; | ||
212 | +} | ||
213 | + | ||
214 | +DWORD WINAPI MonitorThread(LPVOID lpThreadParameter) | ||
215 | +{ | ||
216 | + while (MonitorFlag) | ||
217 | + { | ||
218 | + DWORD aProcesses[1024], cbNeeded, cProcesses; | ||
219 | + if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) | ||
220 | + break; | ||
221 | + cProcesses = cbNeeded / sizeof(DWORD); | ||
222 | + for (size_t i = 0; i < cProcesses; ++i) | ||
223 | + { | ||
224 | + Sleep(process_time); | ||
225 | + if (!auto_inject || man == NULL || man->GetProcessRecord(aProcesses[i])) | ||
226 | + continue; | ||
227 | + std::wstring process_path = GetProcessPath(aProcesses[i]); | ||
228 | + if (!process_path.empty() && pfman->HasProfile(process_path)) | ||
229 | + { | ||
230 | + UniqueHandle hThread(IthCreateThread(InjectThread, aProcesses[i])); | ||
231 | + WaitForSingleObject(hThread.get(), 0); | ||
232 | + } | ||
233 | + } | ||
234 | + } | ||
235 | + return 0; | ||
236 | +} | ||
237 | + | ||
238 | +DWORD SaveProcessProfile(DWORD pid) | ||
239 | +{ | ||
240 | + const ProcessRecord* pr = man->GetProcessRecord(pid); | ||
241 | + if (pr == NULL) | ||
242 | + return 0; | ||
243 | + std::wstring path = GetProcessPath(pid); | ||
244 | + if (path.empty()) | ||
245 | + return 0; | ||
246 | + Profile* pf = pfman->GetProfile(pid); | ||
247 | + if (pf != NULL) | ||
248 | + pf->Clear(); | ||
249 | + else | ||
250 | + pf = pfman->AddProfile(path, pid); | ||
251 | + AddHooksToProfile(*pf, *pr); | ||
252 | + AddThreadsToProfile(*pf, *pr, pid); | ||
253 | + return 0; | ||
254 | +} | ||
255 | + | ||
256 | +void AddHooksToProfile(Profile& pf, const ProcessRecord& pr) | ||
257 | +{ | ||
258 | + WaitForSingleObject(pr.hookman_mutex, 0); | ||
259 | + auto hooks = (const Hook*)pr.hookman_map; | ||
260 | + for (DWORD i = 0; i < MAX_HOOK; ++i) | ||
261 | + { | ||
262 | + if (hooks[i].Address() == 0) | ||
263 | + continue; | ||
264 | + auto& hook = hooks[i]; | ||
265 | + DWORD type = hook.Type(); | ||
266 | + if ((type & HOOK_ADDITIONAL) && (type & HOOK_ENGINE) == 0) | ||
267 | + { | ||
268 | + std::unique_ptr<WCHAR[]> name(new WCHAR[hook.NameLength() * 2]); | ||
269 | + if (ReadProcessMemory(pr.process_handle, hook.Name(), name.get(), hook.NameLength() * 2, NULL)) | ||
270 | + { | ||
271 | + if (hook.hp.module) | ||
272 | + { | ||
273 | + HookParam hp = hook.hp; | ||
274 | + MakeHookRelative(pr, hp); | ||
275 | + pf.AddHook(hp, name.get()); | ||
276 | + } | ||
277 | + else | ||
278 | + pf.AddHook(hook.hp, name.get()); | ||
279 | + } | ||
280 | + } | ||
281 | + } | ||
282 | + ReleaseMutex(pr.hookman_mutex); | ||
283 | +} | ||
284 | + | ||
285 | +void MakeHookRelative(const ProcessRecord& pr, HookParam& hp) | ||
286 | +{ | ||
287 | + MEMORY_BASIC_INFORMATION info; | ||
288 | + VirtualQueryEx(pr.process_handle, (LPCVOID)hp.addr, &info, sizeof(info)); | ||
289 | + hp.addr -= (DWORD)info.AllocationBase; | ||
290 | + hp.function = 0; | ||
291 | +} | ||
292 | + | ||
293 | +void AddThreadsToProfile(Profile& pf, const ProcessRecord& pr, DWORD pid) | ||
294 | +{ | ||
295 | + man->LockHookman(); | ||
296 | + ThreadTable* table = man->Table(); | ||
297 | + for (int i = 0; i < table->Used(); ++i) | ||
298 | + { | ||
299 | + TextThread* tt = table->FindThread(i); | ||
300 | + if (tt == NULL || tt->GetThreadParameter()->pid != pid) | ||
301 | + continue; | ||
302 | + //if (tt->Status() & CURRENT_SELECT || tt->Link() || tt->GetComment()) | ||
303 | + if (tt->Status() & CURRENT_SELECT || tt->Link()) | ||
304 | + AddThreadToProfile(pf, pr, *tt); | ||
305 | + } | ||
306 | + man->UnlockHookman(); | ||
307 | +} | ||
308 | + | ||
309 | +DWORD AddThreadToProfile(Profile& pf, const ProcessRecord& pr, TextThread& thread) | ||
310 | +{ | ||
311 | + const ThreadParameter* tp = thread.GetThreadParameter(); | ||
312 | + std::wstring hook_name = GetHookNameByAddress(pr, tp->hook); | ||
313 | + if (hook_name.empty()) | ||
314 | + return -1; | ||
315 | + auto thread_profile = new ThreadProfile(hook_name, tp->retn, tp->spl, 0, 0, | ||
316 | + THREAD_MASK_RETN | THREAD_MASK_SPLIT, L""); | ||
317 | + DWORD threads_size = pf.Threads().size(); | ||
318 | + int thread_profile_index = pf.AddThread(thread_ptr(thread_profile)); | ||
319 | + if (thread_profile_index == threads_size) // new thread | ||
320 | + { | ||
321 | + WORD iw = thread_profile_index & 0xFFFF; | ||
322 | + if (thread.Status() & CURRENT_SELECT) | ||
323 | + pf.SelectedIndex() = iw; | ||
324 | + if (thread.Link()) | ||
325 | + { | ||
326 | + WORD to_index = AddThreadToProfile(pf, pr, *(thread.Link())) & 0xFFFF; | ||
327 | + if (iw >= 0) | ||
328 | + pf.AddLink(link_ptr(new LinkProfile(iw, to_index))); | ||
329 | + } | ||
330 | + } | ||
331 | + return thread_profile_index; // in case more than one thread links to the same thread. | ||
332 | +} | ||
333 | + | ||
334 | +std::wstring GetHookNameByAddress(const ProcessRecord& pr, DWORD hook_address) | ||
335 | +{ | ||
336 | + std::wstring hook_name; | ||
337 | + WaitForSingleObject(pr.hookman_mutex, 0); | ||
338 | + auto hooks = (const Hook*)pr.hookman_map; | ||
339 | + for (int i = 0; i < MAX_HOOK; ++i) | ||
340 | + { | ||
341 | + auto& hook = hooks[i]; | ||
342 | + if (hook.Address() == hook_address) | ||
343 | + { | ||
344 | + std::unique_ptr<WCHAR[]> name(new WCHAR[hook.NameLength() * 2]); | ||
345 | + if (ReadProcessMemory(pr.process_handle, hooks[i].Name(), name.get(), hook.NameLength() * 2, NULL)) | ||
346 | + hook_name = name.get(); | ||
347 | + break; | ||
348 | + } | ||
349 | + } | ||
350 | + ReleaseMutex(pr.hookman_mutex); | ||
351 | + return hook_name; | ||
352 | +} |
gui/ProfileManager.h
0 → 100644
1 | +#pragma once | ||
2 | +#include "ITH.h" | ||
3 | +#include "utility.h" // UniqueHandle, CriticalSection | ||
4 | + | ||
5 | +class Profile; | ||
6 | + | ||
7 | +class ProfileManager | ||
8 | +{ | ||
9 | +public: | ||
10 | + ProfileManager(); | ||
11 | + ~ProfileManager(); | ||
12 | + Profile* AddProfile(const std::wstring& path, DWORD pid); | ||
13 | + void DeleteProfile(const std::wstring& path); | ||
14 | + void LoadProfile(); | ||
15 | + void SaveProfile(); | ||
16 | + void FindProfileAndUpdateHookAddresses(DWORD pid, const std::wstring& path); | ||
17 | + bool HasProfile(const std::wstring& path); | ||
18 | + Profile* GetProfile(DWORD pid); | ||
19 | + DWORD ProfileCount(); | ||
20 | +private: | ||
21 | + typedef std::unique_ptr<Profile> profile_ptr; | ||
22 | + typedef std::map<std::wstring, profile_ptr> profile_map; | ||
23 | + | ||
24 | + ProfileManager(const ProfileManager&); | ||
25 | + ProfileManager operator=(const ProfileManager&); | ||
26 | + | ||
27 | + bool AddProfile(pugi::xml_node game); | ||
28 | + Profile* AddProfile(const std::wstring& path, profile_ptr new_profile); | ||
29 | + void WriteProfileXml(const std::wstring& path, Profile& pf, pugi::xml_node doc); | ||
30 | + // locate profile with executable path | ||
31 | + profile_map profile_tree; | ||
32 | + CriticalSection cs; | ||
33 | + UniqueHandle hMonitorThread; | ||
34 | +}; |
gui/TextBuffer.cpp
0 → 100644
1 | +#include "TextBuffer.h" | ||
2 | + | ||
3 | +DWORD WINAPI FlushThread(LPVOID lParam); // window.cpp | ||
4 | + | ||
5 | +TextBuffer::TextBuffer(HWND edit) : hThread(IthCreateThread(FlushThread, (DWORD)this)), | ||
6 | + hEdit(edit), | ||
7 | + running(true) | ||
8 | +{ | ||
9 | +} | ||
10 | + | ||
11 | +TextBuffer::~TextBuffer() | ||
12 | +{ | ||
13 | + running = false; | ||
14 | + WaitForSingleObject(hThread.get(), 0); | ||
15 | +} | ||
16 | + | ||
17 | +void TextBuffer::AddText(LPCWSTR str, int len, bool line) | ||
18 | +{ | ||
19 | + CSLock lock(cs); | ||
20 | + if (len > 0) | ||
21 | + this->str.append(str, len); | ||
22 | + line_break = line; | ||
23 | +} | ||
24 | + | ||
25 | +void TextBuffer::Flush() | ||
26 | +{ | ||
27 | + CSLock lock(cs); | ||
28 | + if (line_break || str.empty()) | ||
29 | + return; | ||
30 | + DWORD t = Edit_GetTextLength(hEdit); | ||
31 | + Edit_SetSel(hEdit, t, -1); | ||
32 | + Edit_ReplaceSel(hEdit, str.c_str()); | ||
33 | + str.clear(); | ||
34 | +} | ||
35 | + | ||
36 | +void TextBuffer::ClearBuffer() | ||
37 | +{ | ||
38 | + CSLock lock(cs); | ||
39 | + str.clear(); | ||
40 | + line_break = false; | ||
41 | +} |
gui/TextBuffer.h
0 → 100644
1 | +#pragma once | ||
2 | +#include "ITH.h" | ||
3 | +#include "utility.h" // UniqueHandle, CriticalSection | ||
4 | + | ||
5 | +class TextBuffer | ||
6 | +{ | ||
7 | +public: | ||
8 | + TextBuffer(HWND edit); | ||
9 | + ~TextBuffer(); | ||
10 | + void Flush(); | ||
11 | + void AddText(LPCWSTR str, int len, bool line); | ||
12 | + void ClearBuffer(); | ||
13 | + bool Running() { return running; } | ||
14 | +private: | ||
15 | + CriticalSection cs; | ||
16 | + bool line_break, running; | ||
17 | + UniqueHandle hThread; | ||
18 | + HWND hEdit; | ||
19 | + std::wstring str; | ||
20 | +}; |
gui/language.cpp
0 → 100644
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 | +const wchar_t* Warning=L"Warning!"; | ||
18 | +//command.cpp | ||
19 | +const wchar_t* ErrorSyntax=L"Syntax error"; | ||
20 | +const wchar_t* Usage = L"Syntax:\r\n\ | ||
21 | +\r\n\ | ||
22 | +:H[ELP] - print help\r\n\ | ||
23 | +:Lfrom-to - link from thread 'from' to thread 'to'\r\n\ | ||
24 | +:Ufrom - unlink link from thread 'from'\r\n\ | ||
25 | +\r\n\ | ||
26 | +'from' and 'to' and hexadecimal thread numbers. The thread number is the first number in the combo box.\r\n\ | ||
27 | +\r\n\ | ||
28 | +Loader options:\r\n\ | ||
29 | +/P[{process_id|Nprocess_name}] - attach to process\r\n\ | ||
30 | +\r\n\ | ||
31 | +Hook options:\r\n\ | ||
32 | +/H[X]{A|B|W|S|Q}[N][data_offset[*drdo]][:sub_offset[*drso]]@addr[:module[:{name|#ordinal}]]\r\n\ | ||
33 | +\r\n\ | ||
34 | +All numbers in /H (except ordinal) are hexadecimal without any prefixes"; | ||
35 | + | ||
36 | +const wchar_t* ExtendedUsage = L"/H[X]{A|B|W|S|Q}[N][data_offset[*drdo]][:sub_offset[*drso]]@addr[:[module[:{name|#ordinal}]]]\r\n\ | ||
37 | +\r\n\ | ||
38 | +Set additional custom hook\r\n\ | ||
39 | +\r\n\ | ||
40 | +Hook types :\r\n\ | ||
41 | +A - DBCS char\r\n\ | ||
42 | +B - DBCS char(big-endian)\r\n\ | ||
43 | +W - UCS2 char\r\n\ | ||
44 | +S - MBCS string\r\n\ | ||
45 | +Q - UTF-16 string\r\n\ | ||
46 | +\r\n\ | ||
47 | +Parameters:\r\n\ | ||
48 | +X - use hardware breakpoints\r\n\ | ||
49 | +N - don't use contexts\r\n\ | ||
50 | +data_offset - stack offset to char / string pointer\r\n\ | ||
51 | +drdo - add a level of indirection to data_offset\r\n\ | ||
52 | +sub_offset - stack offset to subcontext\r\n\ | ||
53 | +drso - add a level of indirection to sub_offset\r\n\ | ||
54 | +addr - address of the hook\r\n\ | ||
55 | +module - name of the module to use as base for 'addr'\r\n\ | ||
56 | +name - name of the 'module' export to use as base for 'addr'\r\n\ | ||
57 | +ordinal - number of the 'module' export ordinal to use as base for 'addr'\r\n\ | ||
58 | +\r\n\ | ||
59 | +Negative values of 'data_offset' and 'sub_offset' refer to registers: \r\n\ | ||
60 | +- 4 for EAX, -8 for ECX, -C for EDX, -10 for EBX, -14 for ESP, -18 for EBP, -1C for ESI, -20 for EDI\r\n\ | ||
61 | +\r\n\ | ||
62 | +\"Add a level of indirection\" means in C/C++ style: (*(ESP+data_offset)+drdo) instead of (ESP+data_offset)\r\n\ | ||
63 | +\r\n\ | ||
64 | +All numbers except ordinal are hexadecimal without any prefixes"; | ||
65 | + | ||
66 | +//inject.cpp | ||
67 | +const wchar_t* ErrorRemoteThread=L"Can't create remote thread."; | ||
68 | +const wchar_t* ErrorOpenProcess=L"Can't open process."; | ||
69 | +const wchar_t* ErrorNoProcess=L"Process not found"; | ||
70 | +const wchar_t* SelfAttach=L"Please do not attach to ITH.exe"; | ||
71 | +const wchar_t* AlreadyAttach=L"Process already attached."; | ||
72 | +const wchar_t* FormatInject=L"Inject process %d. Module base %.8X"; | ||
73 | +//main.cpp | ||
74 | +const wchar_t* NotAdmin=L"Can't enable SeDebugPrevilege. ITH might malfunction.\r\n\ | ||
75 | +Please run ITH as administrator or turn off UAC."; | ||
76 | +//pipe.cpp | ||
77 | +const wchar_t* ErrorCreatePipe=L"Can't create text pipe or too many instance."; | ||
78 | +const wchar_t* FormatDetach=L"Process %d detached."; | ||
79 | +const wchar_t* ErrorCmdQueueFull=L"Command queue full."; | ||
80 | +const wchar_t* ErrorNoAttach=L"No process attached."; | ||
81 | + | ||
82 | +//profile.cpp | ||
83 | +const wchar_t* ErrorMonitor=L"Can't monitor process."; | ||
84 | +//utility.cpp | ||
85 | +const wchar_t* InitMessage=L"Copyright (C) 2010-2012 kaosu <qiupf2000@gmail.com>\r\n\ | ||
86 | +Copyright (C) 2015 zorkzero <zorkzero@hotmail.com>\r\n\ | ||
87 | +Source code <https://code.google.com/p/interactive-text-hooker/>\r\n\ | ||
88 | +General discussion <https://groups.google.com/forum/?fromgroups#!forum/interactive-text-hooker>"; | ||
89 | +const wchar_t* BackgroundMsg=L"Type \":h\" or \":help\" for help."; | ||
90 | +const wchar_t* ErrorLinkExist=L"Link exist."; | ||
91 | +const wchar_t* ErrorCylicLink=L"Link failed. No cyclic link allowed."; | ||
92 | +const wchar_t* FormatLink=L"Link from thread%.4x to thread%.4x."; | ||
93 | +const wchar_t* ErrorLink=L"Link failed. Source or/and destination thread not found."; | ||
94 | +const wchar_t* ErrorDeleteCombo=L"Error delete from combo."; | ||
95 | + | ||
96 | +//window.cpp | ||
97 | +const wchar_t* ClassName=L"ITH"; | ||
98 | +const wchar_t* ClassNameAdmin=L"ITH (Administrator)"; | ||
99 | +const wchar_t* ErrorNotSplit=L"Need to enable split first!"; | ||
100 | +const wchar_t* ErrorNotModule=L"Need to enable module first!"; | ||
101 | +//Main window buttons | ||
102 | +const wchar_t* ButtonTitleProcess=L"Process"; | ||
103 | +const wchar_t* ButtonTitleThread=L"Thread"; | ||
104 | +const wchar_t* ButtonTitleHook=L"Hook"; | ||
105 | +const wchar_t* ButtonTitleProfile=L"Profile"; | ||
106 | +const wchar_t* ButtonTitleOption=L"Option"; | ||
107 | +const wchar_t* ButtonTitleClear=L"Clear"; | ||
108 | +const wchar_t* ButtonTitleSave=L"Save"; | ||
109 | +const wchar_t* ButtonTitleTop=L"Top"; | ||
110 | +//Hook window | ||
111 | +const wchar_t* SpecialHook=L"Special hook, no AGTH equivalent."; | ||
112 | +//Process window | ||
113 | +const wchar_t* TabTitlePID=L"PID"; | ||
114 | +const wchar_t* TabTitleMemory=L"Memory"; | ||
115 | +const wchar_t* TabTitleName=L"Name"; | ||
116 | +const wchar_t* TabTitleTID=L"TID"; | ||
117 | +const wchar_t* TabTitleStart=L"Start"; | ||
118 | +const wchar_t* TabTitleModule=L"Module"; | ||
119 | +const wchar_t* TabTitleState=L"State"; | ||
120 | +const wchar_t* SuccessAttach=L"Attach ITH to process successfully."; | ||
121 | +const wchar_t* FailAttach=L"Failed to attach ITH to process."; | ||
122 | +const wchar_t* SuccessDetach=L"ITH detach from process."; | ||
123 | +const wchar_t* FailDetach=L"Detach failed."; | ||
124 | +//Profile window | ||
125 | +const wchar_t* ProfileExist=L"Profile already exists."; | ||
126 | +const wchar_t* SuccessAddProfile=L"Profile added."; | ||
127 | +const wchar_t* FailAddProfile=L"Fail to add profile"; | ||
128 | +const wchar_t* TabTitleNumber=L"No."; | ||
129 | +const wchar_t* NoFile=L"Can't find file."; | ||
130 | +const wchar_t* PathDismatch=L"Process name dismatch, continue?"; | ||
131 | +const wchar_t* SuccessImportProfile=L"Import profile success"; | ||
132 | +//const wchar_t* SuccessAddProfile=L"Profile added."; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
gui/language.h
0 → 100644
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 | +#pragma once | ||
18 | + | ||
19 | +extern const wchar_t* Warning; | ||
20 | +//command.cpp | ||
21 | +extern const wchar_t* ErrorSyntax; | ||
22 | +extern const wchar_t* Usage; | ||
23 | +extern const wchar_t* ExtendedUsage; | ||
24 | +//inject.cpp | ||
25 | +extern const wchar_t* ErrorRemoteThread; | ||
26 | +extern const wchar_t* ErrorOpenProcess; | ||
27 | +extern const wchar_t* ErrorNoProcess; | ||
28 | +extern const wchar_t* SelfAttach; | ||
29 | +extern const wchar_t* AlreadyAttach; | ||
30 | +extern const wchar_t* FormatInject; | ||
31 | +//main.cpp | ||
32 | +extern const wchar_t* NotAdmin; | ||
33 | +//pipe.cpp | ||
34 | +extern const wchar_t* ErrorCreatePipe; | ||
35 | +extern const wchar_t* FormatDetach; | ||
36 | +extern const wchar_t* ErrorCmdQueueFull; | ||
37 | +extern const wchar_t* ErrorNoAttach; | ||
38 | + | ||
39 | +//profile.cpp | ||
40 | +extern const wchar_t* ErrorMonitor; | ||
41 | + | ||
42 | +//utility.cpp | ||
43 | +extern const wchar_t* InitMessage; | ||
44 | +extern const wchar_t* BackgroundMsg; | ||
45 | +extern const wchar_t* ErrorLinkExist; | ||
46 | +extern const wchar_t* ErrorCylicLink; | ||
47 | +extern const wchar_t* FormatLink; | ||
48 | +extern const wchar_t* ErrorLink; | ||
49 | +extern const wchar_t* ErrorDeleteCombo; | ||
50 | + | ||
51 | +//window.cpp | ||
52 | +extern const wchar_t* ClassName; | ||
53 | +extern const wchar_t* ClassNameAdmin; | ||
54 | +extern const wchar_t* ErrorNotSplit; | ||
55 | +extern const wchar_t* ErrorNotModule; | ||
56 | +//Main window buttons | ||
57 | +extern const wchar_t* ButtonTitleProcess; | ||
58 | +extern const wchar_t* ButtonTitleThread; | ||
59 | +extern const wchar_t* ButtonTitleHook; | ||
60 | +extern const wchar_t* ButtonTitleProfile; | ||
61 | +extern const wchar_t* ButtonTitleOption; | ||
62 | +extern const wchar_t* ButtonTitleClear; | ||
63 | +extern const wchar_t* ButtonTitleSave; | ||
64 | +extern const wchar_t* ButtonTitleTop; | ||
65 | +//Hook window | ||
66 | +extern const wchar_t* SpecialHook; | ||
67 | +//Process window | ||
68 | +extern const wchar_t* TabTitlePID; | ||
69 | +extern const wchar_t* TabTitleMemory; | ||
70 | +extern const wchar_t* TabTitleName; | ||
71 | +extern const wchar_t* TabTitleTID; | ||
72 | +extern const wchar_t* TabTitleStart; | ||
73 | +extern const wchar_t* TabTitleModule; | ||
74 | +extern const wchar_t* TabTitleState; | ||
75 | +extern const wchar_t* SuccessAttach; | ||
76 | +extern const wchar_t* FailAttach; | ||
77 | +extern const wchar_t* SuccessDetach; | ||
78 | +extern const wchar_t* FailDetach; | ||
79 | +//Profile window | ||
80 | +extern const wchar_t* ProfileExist; | ||
81 | +extern const wchar_t* SuccessAddProfile; | ||
82 | +extern const wchar_t* FailAddProfile; | ||
83 | +extern const wchar_t* TabTitleNumber; | ||
84 | +extern const wchar_t* NoFile; | ||
85 | +extern const wchar_t* PathDismatch; | ||
86 | +extern const wchar_t* SuccessImportProfile; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
gui/main.cpp
0 → 100644
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 | +#include "ITH.h" | ||
19 | +#include "ith/host/srv.h" | ||
20 | +#include "ith/host/hookman.h" | ||
21 | +#include "ith/host/SettingManager.h" | ||
22 | +#include "CustomFilter.h" | ||
23 | +#include "profile.h" | ||
24 | +#include "ProfileManager.h" | ||
25 | + | ||
26 | +HINSTANCE hIns; | ||
27 | +ATOM MyRegisterClass(HINSTANCE hInstance); | ||
28 | +BOOL InitInstance(HINSTANCE hInstance, DWORD nCmdShow, RECT *rc); | ||
29 | +RECT window; | ||
30 | +extern HWND hMainWnd; // windows.cpp | ||
31 | +extern bool MonitorFlag; // ProfileManager.cpp | ||
32 | +extern ProfileManager* pfman; // ProfileManager.cpp | ||
33 | + | ||
34 | +extern "C" { | ||
35 | + BOOL IthInitSystemService(); | ||
36 | + void IthCloseSystemService(); | ||
37 | +} | ||
38 | + | ||
39 | +CustomFilter* uni_filter; | ||
40 | +CustomFilter* mb_filter; | ||
41 | +HookManager* man; | ||
42 | +SettingManager* setman; | ||
43 | +LONG split_time, cyclic_remove, global_filter; | ||
44 | +LONG process_time, inject_delay, insert_delay, | ||
45 | + auto_inject, auto_insert, clipboard_flag; | ||
46 | + | ||
47 | +std::map<std::wstring, long> setting; | ||
48 | + | ||
49 | +void RecordMBChar(WORD mb, PVOID f) | ||
50 | +{ | ||
51 | + auto filter = (pugi::xml_node*)f; | ||
52 | + DWORD m = mb; | ||
53 | + WCHAR buffer[16]; | ||
54 | + std::swprintf(buffer, L"m%04X", m); | ||
55 | + filter->append_attribute(buffer) = L"0"; | ||
56 | +} | ||
57 | + | ||
58 | +void RecordUniChar(WORD uni, PVOID f) | ||
59 | +{ | ||
60 | + auto filter = (pugi::xml_node*)f; | ||
61 | + DWORD m = uni; | ||
62 | + WCHAR buffer[16]; | ||
63 | + std::swprintf(buffer, L"u%04X", m); | ||
64 | + filter->append_attribute(buffer) = L"0"; | ||
65 | + std::wstring text = filter->text().get(); | ||
66 | + text += (wchar_t)m; | ||
67 | + filter->text().set(text.c_str()); | ||
68 | +} | ||
69 | + | ||
70 | +void SaveSettings() | ||
71 | +{ | ||
72 | + GetWindowRect(hMainWnd, &window); | ||
73 | + setting[L"window_left"] = window.left; | ||
74 | + setting[L"window_right"] = window.right; | ||
75 | + setting[L"window_top"] = window.top; | ||
76 | + setting[L"window_bottom"] = window.bottom; | ||
77 | + setting[L"split_time"] = split_time; | ||
78 | + setting[L"process_time"] = process_time; | ||
79 | + setting[L"inject_delay"] = inject_delay; | ||
80 | + setting[L"insert_delay"] = insert_delay; | ||
81 | + setting[L"auto_inject"] = auto_inject; | ||
82 | + setting[L"auto_insert"] = auto_insert; | ||
83 | + setting[L"auto_copy"] = clipboard_flag; | ||
84 | + setting[L"auto_suppress"] = cyclic_remove; | ||
85 | + setting[L"global_filter"] = global_filter; | ||
86 | + | ||
87 | + UniqueHandle hFile(IthCreateFile(L"ITH.xml", GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS)); | ||
88 | + if (hFile.get() != INVALID_HANDLE_VALUE) | ||
89 | + { | ||
90 | + FileWriter fw(hFile.get()); | ||
91 | + pugi::xml_document doc; | ||
92 | + auto root = doc.root().append_child(L"ITH_Setting"); | ||
93 | + for (auto it = setting.begin(); it != setting.end(); ++it) | ||
94 | + root.append_attribute(it->first.c_str()).set_value(it->second); | ||
95 | + auto filter = root.append_child(L"SingleCharFilter"); | ||
96 | + filter.append_child(pugi::xml_node_type::node_pcdata); | ||
97 | + mb_filter->Traverse(RecordMBChar, &filter); | ||
98 | + uni_filter->Traverse(RecordUniChar, &filter); | ||
99 | + doc.save(fw); | ||
100 | + } | ||
101 | +} | ||
102 | + | ||
103 | +void DefaultSettings() | ||
104 | +{ | ||
105 | + setting[L"split_time"] = 200; | ||
106 | + setting[L"process_time"] = 50; | ||
107 | + setting[L"inject_delay"] = 3000; | ||
108 | + setting[L"insert_delay"] = 500; | ||
109 | + setting[L"auto_inject"] = 1; | ||
110 | + setting[L"auto_insert"] = 1; | ||
111 | + setting[L"auto_copy"] = 0; | ||
112 | + setting[L"auto_suppress"] = 0; | ||
113 | + setting[L"global_filter"] = 0; | ||
114 | + setting[L"window_left"] = 100; | ||
115 | + setting[L"window_right"] = 800; | ||
116 | + setting[L"window_top"] = 100; | ||
117 | + setting[L"window_bottom"] = 600; | ||
118 | +} | ||
119 | + | ||
120 | +void InitializeSettings() | ||
121 | +{ | ||
122 | + split_time = setting[L"split_time"]; | ||
123 | + process_time = setting[L"process_time"]; | ||
124 | + inject_delay = setting[L"inject_delay"]; | ||
125 | + insert_delay = setting[L"insert_delay"]; | ||
126 | + auto_inject = setting[L"auto_inject"]; | ||
127 | + auto_insert = setting[L"auto_insert"]; | ||
128 | + clipboard_flag = setting[L"auto_copy"]; | ||
129 | + cyclic_remove = setting[L"auto_suppress"]; | ||
130 | + global_filter = setting[L"global_filter"]; | ||
131 | + window.left = setting[L"window_left"]; | ||
132 | + window.right = setting[L"window_right"]; | ||
133 | + window.top = setting[L"window_top"]; | ||
134 | + window.bottom = setting[L"window_bottom"]; | ||
135 | + | ||
136 | + if (auto_inject > 1) | ||
137 | + auto_inject = 1; | ||
138 | + if (auto_insert > 1) | ||
139 | + auto_insert = 1; | ||
140 | + if (clipboard_flag > 1) | ||
141 | + clipboard_flag = 1; | ||
142 | + if (cyclic_remove > 1) | ||
143 | + cyclic_remove = 1; | ||
144 | + | ||
145 | + if (window.right < window.left || window.right - window.left < 600) | ||
146 | + window.right = window.left + 600; | ||
147 | + if (window.bottom < window.top || window.bottom - window.top < 200) | ||
148 | + window.bottom = window.top + 200; | ||
149 | +} | ||
150 | + | ||
151 | +void LoadSettings() | ||
152 | +{ | ||
153 | + UniqueHandle hFile(IthCreateFile(L"ITH.xml", GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING)); | ||
154 | + if (hFile.get() != INVALID_HANDLE_VALUE) | ||
155 | + { | ||
156 | + DWORD size = GetFileSize(hFile.get(), NULL); | ||
157 | + std::unique_ptr<char[]> buffer(new char[size]); | ||
158 | + ReadFile(hFile.get(), buffer.get(), size, &size, NULL); | ||
159 | + pugi::xml_document doc; | ||
160 | + auto result = doc.load_buffer_inplace(buffer.get(), size); | ||
161 | + if (!result) | ||
162 | + return; | ||
163 | + auto root = doc.root().child(L"ITH_Setting"); | ||
164 | + for (auto attr = root.attributes_begin(); attr != root.attributes_end(); ++attr) | ||
165 | + { | ||
166 | + auto it = setting.find(attr->name()); | ||
167 | + if (it != setting.end()) | ||
168 | + it->second = std::stoul(attr->value()); | ||
169 | + } | ||
170 | + auto filter = root.child(L"SingleCharFilter"); | ||
171 | + if (filter) | ||
172 | + { | ||
173 | + for (auto attr = filter.attributes_begin(); attr != filter.attributes_end(); ++attr) | ||
174 | + { | ||
175 | + if (attr->name()[0] == L'm') | ||
176 | + { | ||
177 | + DWORD c = std::stoul(attr->name() + 1, NULL, 16); | ||
178 | + mb_filter->Insert(c & 0xFFFF); | ||
179 | + } | ||
180 | + else if (attr->name()[0] == L'u') | ||
181 | + { | ||
182 | + DWORD c = std::stoul(attr->name() + 1, NULL, 16); | ||
183 | + uni_filter->Insert(c & 0xFFFF); | ||
184 | + } | ||
185 | + } | ||
186 | + std::wstring filter_value = filter.text().get(); | ||
187 | + for (auto it = filter_value.begin(); it != filter_value.end(); ++it) | ||
188 | + { | ||
189 | + WCHAR filter_unichar[2] = { *it, L'\0' }; | ||
190 | + char filter_mbchar[4]; | ||
191 | + WC_MB(filter_unichar, filter_mbchar, 4); | ||
192 | + mb_filter->Insert(*(WORD*)filter_mbchar); | ||
193 | + uni_filter->Insert(*it); | ||
194 | + } | ||
195 | + } | ||
196 | + } | ||
197 | +} | ||
198 | + | ||
199 | +extern LPCWSTR ClassName, ClassNameAdmin; | ||
200 | +static WCHAR mutex[] = L"ITH_RUNNING"; | ||
201 | +DWORD FindITH() | ||
202 | +{ | ||
203 | + HWND hwnd = FindWindow(ClassName, ClassName); | ||
204 | + if (hwnd == NULL) | ||
205 | + hwnd = FindWindow(ClassName, ClassNameAdmin); | ||
206 | + if (hwnd) | ||
207 | + { | ||
208 | + ShowWindow(hwnd, SW_SHOWNORMAL); | ||
209 | + SetForegroundWindow(hwnd); | ||
210 | + return 0; | ||
211 | + } | ||
212 | + return 1; | ||
213 | +} | ||
214 | +LONG WINAPI UnhandledExcept(_EXCEPTION_POINTERS *ExceptionInfo) | ||
215 | +{ | ||
216 | + wchar_t path_name[512]; // fully qualified path name | ||
217 | + WCHAR code[16]; | ||
218 | + EXCEPTION_RECORD* rec = ExceptionInfo->ExceptionRecord; | ||
219 | + std::swprintf(code, L"%08X", rec->ExceptionCode); | ||
220 | + MEMORY_BASIC_INFORMATION info; | ||
221 | + if (VirtualQuery(rec->ExceptionAddress, &info, sizeof(info))) | ||
222 | + { | ||
223 | + if (GetModuleFileName((HMODULE)info.AllocationBase, path_name, 512)) | ||
224 | + { | ||
225 | + LPWSTR name = wcsrchr(path_name, L'\\'); | ||
226 | + if (name) | ||
227 | + { | ||
228 | + DWORD addr = (DWORD)rec->ExceptionAddress; | ||
229 | + std::swprintf(name, L"%s:%08X", name + 1, addr - (DWORD)info.AllocationBase); | ||
230 | + MessageBox(NULL, name, code, MB_OK); | ||
231 | + TerminateProcess(GetCurrentProcess(), 0); | ||
232 | + } | ||
233 | + } | ||
234 | + } | ||
235 | + std::swprintf(path_name, L"%08X", rec->ExceptionAddress); | ||
236 | + MessageBox(NULL, path_name, code, MB_OK); | ||
237 | + TerminateProcess(GetCurrentProcess(), 0); | ||
238 | + return 0; | ||
239 | +} | ||
240 | + | ||
241 | +int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) | ||
242 | +{ | ||
243 | + if (!IthInitSystemService()) | ||
244 | + TerminateProcess(GetCurrentProcess(), 0); | ||
245 | + CreateMutex(NULL, TRUE, L"ITH_MAIN_RUNNING"); | ||
246 | + if (IHF_Init()) | ||
247 | + { | ||
248 | + SetUnhandledExceptionFilter(UnhandledExcept); | ||
249 | + IHF_GetHookManager(&man); | ||
250 | + IHF_GetSettingManager(&setman); | ||
251 | + setman->SetValue(SETTING_SPLIT_TIME, 200); | ||
252 | + MonitorFlag = true; | ||
253 | + pfman = new ProfileManager(); | ||
254 | + mb_filter = new CustomFilter(); | ||
255 | + uni_filter = new CustomFilter(); | ||
256 | + DefaultSettings(); | ||
257 | + LoadSettings(); | ||
258 | + InitializeSettings(); | ||
259 | + setman->SetValue(SETTING_SPLIT_TIME, split_time); | ||
260 | + setman->SetValue(SETTING_CLIPFLAG, clipboard_flag); | ||
261 | + hIns = hInstance; | ||
262 | + MyRegisterClass(hIns); | ||
263 | + InitInstance(hIns, IHF_IsAdmin(), &window); | ||
264 | + MSG msg; | ||
265 | + while (GetMessage(&msg, NULL, 0, 0)) | ||
266 | + { | ||
267 | + TranslateMessage(&msg); | ||
268 | + DispatchMessage(&msg); | ||
269 | + } | ||
270 | + //delete mb_filter; | ||
271 | + //delete uni_filter; | ||
272 | + delete pfman; | ||
273 | + MonitorFlag = false; | ||
274 | + man = NULL; | ||
275 | + } | ||
276 | + else | ||
277 | + { | ||
278 | + FindITH(); | ||
279 | + } | ||
280 | + IHF_Cleanup(); | ||
281 | + IthCloseSystemService(); | ||
282 | + TerminateProcess(GetCurrentProcess(), 0); | ||
283 | +} |
gui/pugixml.cpp
0 → 100644
This diff could not be displayed because it is too large.
gui/pugixml.hpp
0 → 100644
This diff is collapsed. Click to expand it.
gui/resource.h
0 → 100644
1 | +#ifndef IDC_STATIC | ||
2 | +#define IDC_STATIC (-1) | ||
3 | +#endif | ||
4 | + | ||
5 | +#define IDD_DIALOG2 102 | ||
6 | +#define IDD_DIALOG4 104 | ||
7 | +#define IDI_ICON1 110 | ||
8 | +#define IDC_CHECK1 1000 | ||
9 | +#define IDC_CHECK2 1001 | ||
10 | +#define IDC_CHECK3 1002 | ||
11 | +#define IDC_CHECK4 1003 | ||
12 | +#define IDC_CHECK5 1004 | ||
13 | +#define IDC_EDIT1 1011 | ||
14 | +#define IDC_EDIT2 1012 | ||
15 | +#define IDC_EDIT3 1013 | ||
16 | +#define IDC_EDIT4 1014 | ||
17 | +#define IDC_BUTTON1 1020 | ||
18 | +#define IDC_BUTTON2 1021 | ||
19 | +#define IDC_BUTTON3 1022 | ||
20 | +#define IDC_BUTTON5 1024 | ||
21 | +#define IDC_LIST1 1028 | ||
22 | +#define IDC_BUTTON6 40000 | ||
23 | +#define IDC_CHECK6 40001 |
gui/utility.cpp
0 → 100644
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 | +#include "utility.h" | ||
19 | +#include "ith/host/srv.h" | ||
20 | +#include "ith/host/hookman.h" | ||
21 | +#include "ith/common/types.h" | ||
22 | +#include "ith/common/const.h" | ||
23 | + | ||
24 | +extern HookManager* man; // main.cpp | ||
25 | + | ||
26 | +std::wstring GetDriveLetter(const std::wstring& devicePath); | ||
27 | +std::wstring GetWindowsPath(const std::wstring& fileObjectPath); | ||
28 | +PVOID GetAllocationBase(DWORD pid, LPCVOID); | ||
29 | +std::wstring GetModuleFileNameAsString(DWORD pid, PVOID allocationBase); | ||
30 | +std::wstring GetModuleFileNameAsString(); | ||
31 | +std::wstring GetProcessPath(HANDLE hProc); | ||
32 | + | ||
33 | +void ConsoleOutput(LPCWSTR text) | ||
34 | +{ | ||
35 | + man->AddConsoleOutput(text); | ||
36 | +} | ||
37 | + | ||
38 | +void ConsoleOutput(LPCSTR text) | ||
39 | +{ | ||
40 | + int wc_length = MB_WC_count(text, -1); | ||
41 | + LPWSTR wc = new WCHAR[wc_length]; | ||
42 | + MB_WC(text, wc, wc_length); | ||
43 | + man->AddConsoleOutput(wc); | ||
44 | + delete wc; | ||
45 | +} | ||
46 | + | ||
47 | +std::wstring GetProcessPath(DWORD pid) | ||
48 | +{ | ||
49 | + UniqueHandle hProc(OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid)); | ||
50 | + if (hProc) | ||
51 | + return GetProcessPath(hProc.get()); | ||
52 | + else | ||
53 | + return L""; | ||
54 | +} | ||
55 | + | ||
56 | +std::wstring GetProcessPath(HANDLE hProc) | ||
57 | +{ | ||
58 | + wchar_t path[MAX_PATH]; | ||
59 | + GetProcessImageFileName(hProc, path, MAX_PATH); | ||
60 | + return GetWindowsPath(path); | ||
61 | +} | ||
62 | + | ||
63 | +std::wstring GetWindowsPath(const std::wstring& path) | ||
64 | +{ | ||
65 | + // path is in device form | ||
66 | + // \Device\HarddiskVolume2\Windows\System32\taskhost.exe | ||
67 | + auto pathOffset = path.find(L'\\', 1) + 1; | ||
68 | + pathOffset = path.find(L'\\', pathOffset); | ||
69 | + std::wstring devicePath = path.substr(0, pathOffset); // \Device\HarddiskVolume2 | ||
70 | + std::wstring dosDrive = GetDriveLetter(devicePath); // C: | ||
71 | + if (dosDrive.empty()) | ||
72 | + return L""; | ||
73 | + std::wstring dosPath = dosDrive; // C: | ||
74 | + dosPath += path.substr(pathOffset); // C:\Windows\System32\taskhost.exe | ||
75 | + return dosPath; | ||
76 | +} | ||
77 | + | ||
78 | +std::wstring GetDriveLetter(const std::wstring& devicePath) | ||
79 | +{ | ||
80 | + for (wchar_t drive = L'A'; drive <= L'Z'; drive++) | ||
81 | + { | ||
82 | + wchar_t szDriveName[3] = { drive, L':', L'\0' }; | ||
83 | + wchar_t szTarget[512]; | ||
84 | + if (QueryDosDevice(szDriveName, szTarget, 512)) | ||
85 | + if (devicePath.compare(szTarget) == 0) | ||
86 | + return szDriveName; | ||
87 | + } | ||
88 | + return L""; | ||
89 | +} | ||
90 | + | ||
91 | +std::wstring GetCode(const HookParam& hp, DWORD pid) | ||
92 | +{ | ||
93 | + std::wstring code(L"/H"); | ||
94 | + WCHAR c; | ||
95 | + if (hp.type & PRINT_DWORD) | ||
96 | + c = L'H'; | ||
97 | + else if (hp.type & USING_UNICODE) | ||
98 | + { | ||
99 | + if (hp.type & USING_STRING) | ||
100 | + c = L'Q'; | ||
101 | + else if (hp.type & STRING_LAST_CHAR) | ||
102 | + c = L'L'; | ||
103 | + else | ||
104 | + c = L'W'; | ||
105 | + } | ||
106 | + else | ||
107 | + { | ||
108 | + if (hp.type & USING_STRING) | ||
109 | + c = L'S'; | ||
110 | + else if (hp.type & BIG_ENDIAN) | ||
111 | + c = L'A'; | ||
112 | + else if (hp.type & STRING_LAST_CHAR) | ||
113 | + c = L'E'; | ||
114 | + else | ||
115 | + c = L'B'; | ||
116 | + } | ||
117 | + code += c; | ||
118 | + if (hp.type & NO_CONTEXT) | ||
119 | + code += L'N'; | ||
120 | + if (hp.off >> 31) | ||
121 | + code += L"-" + ToHexString(-(hp.off + 4)); | ||
122 | + else | ||
123 | + code += ToHexString(hp.off); | ||
124 | + if (hp.type & DATA_INDIRECT) | ||
125 | + { | ||
126 | + if (hp.ind >> 31) | ||
127 | + code += L"*-" + ToHexString(-hp.ind); | ||
128 | + else | ||
129 | + code += L"*" + ToHexString(hp.ind); | ||
130 | + } | ||
131 | + if (hp.type & USING_SPLIT) | ||
132 | + { | ||
133 | + if (hp.split >> 31) | ||
134 | + code += L":-" + ToHexString(-(4 + hp.split)); | ||
135 | + else | ||
136 | + code += L":" + ToHexString(hp.split); | ||
137 | + } | ||
138 | + if (hp.type & SPLIT_INDIRECT) | ||
139 | + { | ||
140 | + if (hp.split_ind >> 31) | ||
141 | + code += L"*-" + ToHexString(-hp.split_ind); | ||
142 | + else | ||
143 | + code += L"*" + ToHexString(hp.split_ind); | ||
144 | + } | ||
145 | + if (pid) | ||
146 | + { | ||
147 | + PVOID allocationBase = GetAllocationBase(pid, (LPCVOID)hp.addr); | ||
148 | + if (allocationBase) | ||
149 | + { | ||
150 | + std::wstring path = GetModuleFileNameAsString(pid, allocationBase); | ||
151 | + if (!path.empty()) | ||
152 | + { | ||
153 | + auto fileName = path.substr(path.rfind(L'\\') + 1); | ||
154 | + DWORD relativeHookAddress = hp.addr - (DWORD)allocationBase; | ||
155 | + code += L"@" + ToHexString(relativeHookAddress) + L":" + fileName; | ||
156 | + return code; | ||
157 | + } | ||
158 | + } | ||
159 | + } | ||
160 | + if (hp.module) | ||
161 | + { | ||
162 | + code += L"@" + ToHexString(hp.addr) + L"!" + ToHexString(hp.module); | ||
163 | + if (hp.function) | ||
164 | + code += L"!" + ToHexString(hp.function); | ||
165 | + } | ||
166 | + else | ||
167 | + { | ||
168 | + // hack, the original address is stored in the function field | ||
169 | + // if (module == NULL && function != NULL) | ||
170 | + // in TextHook::UnsafeInsertHookCode() MODULE_OFFSET and FUNCTION_OFFSET are removed from | ||
171 | + // HookParam.type | ||
172 | + if (hp.function) | ||
173 | + code += L"@" + ToHexString(hp.function); | ||
174 | + else | ||
175 | + code += L"@" + ToHexString(hp.addr) + L":"; | ||
176 | + } | ||
177 | + return code; | ||
178 | +} | ||
179 | + | ||
180 | +std::wstring GetModuleFileNameAsString(DWORD pid, PVOID allocationBase) | ||
181 | +{ | ||
182 | + const ProcessRecord* pr = man->GetProcessRecord(pid); | ||
183 | + if (pr) | ||
184 | + { | ||
185 | + HANDLE hProc = pr->process_handle; | ||
186 | + WCHAR path[MAX_PATH]; | ||
187 | + if (GetModuleFileNameEx(hProc, (HMODULE)allocationBase, path, MAX_PATH)) | ||
188 | + return path; | ||
189 | + } | ||
190 | + return L""; | ||
191 | +} | ||
192 | + | ||
193 | +PVOID GetAllocationBase(DWORD pid, LPCVOID addr) | ||
194 | +{ | ||
195 | + const ProcessRecord *pr = man->GetProcessRecord(pid); | ||
196 | + if (pr) | ||
197 | + { | ||
198 | + MEMORY_BASIC_INFORMATION info; | ||
199 | + HANDLE hProc = pr->process_handle; | ||
200 | + if (VirtualQueryEx(hProc, addr, &info, sizeof(info))) | ||
201 | + { | ||
202 | + if (info.Type & MEM_IMAGE) | ||
203 | + return info.AllocationBase; | ||
204 | + } | ||
205 | + } | ||
206 | + return NULL; | ||
207 | +} | ||
208 | + | ||
209 | +struct TitleParam | ||
210 | +{ | ||
211 | + DWORD pid, buffer_len, retn_len; | ||
212 | + std::wstring buffer; | ||
213 | +}; | ||
214 | + | ||
215 | +BOOL CALLBACK EnumProc(HWND hwnd, LPARAM lParam) | ||
216 | +{ | ||
217 | + TitleParam* p = (TitleParam*)lParam; | ||
218 | + DWORD pid; | ||
219 | + GetWindowThreadProcessId(hwnd, &pid); | ||
220 | + if (pid == p->pid) | ||
221 | + { | ||
222 | + if (GetWindowLong(hwnd, GWL_STYLE) & WS_VISIBLE) | ||
223 | + { | ||
224 | + int len = GetWindowTextLength(hwnd); | ||
225 | + std::unique_ptr<wchar_t[]> result(new wchar_t[len + 1]); | ||
226 | + GetWindowText(hwnd, result.get(), len + 1); | ||
227 | + p->buffer = result.get(); | ||
228 | + p->retn_len = p->buffer.size(); | ||
229 | + if (!p->buffer.empty()) | ||
230 | + return FALSE; | ||
231 | + } | ||
232 | + } | ||
233 | + return TRUE; | ||
234 | +} | ||
235 | + | ||
236 | +std::wstring GetProcessTitle(DWORD pid) | ||
237 | +{ | ||
238 | + TitleParam p; | ||
239 | + p.pid = pid; | ||
240 | + p.buffer_len = 0; | ||
241 | + p.retn_len = 0; | ||
242 | + EnumWindows(EnumProc, (LPARAM)&p); | ||
243 | + return p.buffer; | ||
244 | +} | ||
245 | + | ||
246 | +WindowsError::WindowsError(DWORD error_code) : error_code(error_code), msg("") | ||
247 | +{ | ||
248 | + CHAR str[512]; | ||
249 | + std::sprintf(str, "error code 0x%8x", error_code); | ||
250 | + msg = str; | ||
251 | +} | ||
252 | + | ||
253 | +const char *WindowsError::what() const | ||
254 | +{ | ||
255 | + return msg.c_str(); | ||
256 | +} | ||
257 | + | ||
258 | +HANDLE IthCreateThread(LPVOID start_addr, DWORD param) | ||
259 | +{ | ||
260 | + return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start_addr, (LPVOID)param, 0, NULL); | ||
261 | +} | ||
262 | + | ||
263 | +std::wstring GetModuleFileNameAsString() | ||
264 | +{ | ||
265 | + WCHAR path[MAX_PATH]; | ||
266 | + GetModuleFileName(NULL, path, MAX_PATH); | ||
267 | + return path; | ||
268 | +} | ||
269 | + | ||
270 | +bool IthCreateDirectory(LPCWSTR name) | ||
271 | +{ | ||
272 | + std::wstring path = GetModuleFileNameAsString(); | ||
273 | + path = path.substr(0, path.rfind(L'\\') + 1) + name; | ||
274 | + BOOL error_code = CreateDirectory(path.c_str(), NULL); | ||
275 | + return error_code != 0 || GetLastError() == ERROR_ALREADY_EXISTS; | ||
276 | +} | ||
277 | + | ||
278 | +HANDLE IthCreateFile(LPCWSTR name, DWORD option, DWORD share, DWORD disposition) | ||
279 | +{ | ||
280 | + std::wstring path = GetModuleFileNameAsString(); | ||
281 | + path = path.substr(0, path.rfind(L'\\') + 1) + name; | ||
282 | + return CreateFile(path.c_str(), option, share, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL); | ||
283 | +} | ||
284 | + | ||
285 | +//SJIS->Unicode. 'mb' must be null-terminated. 'wc_length' is the length of 'wc' in characters. | ||
286 | +int MB_WC(const char* mb, wchar_t* wc, int wc_length) | ||
287 | +{ | ||
288 | + return MultiByteToWideChar(932, 0, mb, -1, wc, wc_length); | ||
289 | +} | ||
290 | + | ||
291 | +// Count characters in wide string. 'mb_length' is the number of bytes from 'mb' to convert or | ||
292 | +// -1 if the string is null terminated. | ||
293 | +int MB_WC_count(const char* mb, int mb_length) | ||
294 | +{ | ||
295 | + return MultiByteToWideChar(932, 0, mb, mb_length, NULL, 0); | ||
296 | +} | ||
297 | + | ||
298 | +// Unicode->SJIS. Analogous to MB_WC. | ||
299 | +int WC_MB(const wchar_t *wc, char* mb, int mb_length) | ||
300 | +{ | ||
301 | + return WideCharToMultiByte(932, 0, wc, -1, mb, mb_length, NULL, NULL); | ||
302 | +} | ||
303 | + | ||
304 | +DWORD Hash(const std::wstring& module, int length) | ||
305 | +{ | ||
306 | + DWORD hash = 0; | ||
307 | + auto end = length < 0 || static_cast<std::size_t>(length) > module.length() ? module.end() : module.begin() + length; | ||
308 | + for (auto it = module.begin(); it != end; ++it) | ||
309 | + hash = _rotr(hash, 7) + *it; | ||
310 | + return hash; | ||
311 | +} |
gui/utility.h
0 → 100644
1 | +#pragma once | ||
2 | +#include "ITH.h" | ||
3 | + | ||
4 | +struct HookParam; | ||
5 | +struct ProcessRecord; | ||
6 | + | ||
7 | +DWORD Hash(const std::wstring& module, int length = -1); | ||
8 | +DWORD ProcessCommand(const std::wstring& cmd, DWORD pid); | ||
9 | +std::wstring GetProcessPath(DWORD pid); | ||
10 | +void ConsoleOutput(LPCWSTR); | ||
11 | +void ConsoleOutput(LPCSTR text); | ||
12 | +std::wstring GetProcessTitle(DWORD pid); | ||
13 | +std::wstring GetCode(const HookParam& hp, DWORD pid = 0); | ||
14 | + | ||
15 | +// http://codesequoia.wordpress.com/2012/08/26/stdunique_ptr-for-windows-handles/ | ||
16 | +struct HandleDeleter | ||
17 | +{ | ||
18 | + typedef HANDLE pointer; | ||
19 | + void operator() (HANDLE h) | ||
20 | + { | ||
21 | + if (h != INVALID_HANDLE_VALUE) { | ||
22 | + CloseHandle(h); | ||
23 | + } | ||
24 | + } | ||
25 | +}; | ||
26 | + | ||
27 | +typedef std::unique_ptr<HANDLE, HandleDeleter> UniqueHandle; | ||
28 | + | ||
29 | +class FileWriter : public pugi::xml_writer | ||
30 | +{ | ||
31 | + HANDLE hFile; | ||
32 | +public: | ||
33 | + FileWriter(HANDLE hFile) : hFile(hFile) {}; | ||
34 | + ~FileWriter() {}; | ||
35 | + | ||
36 | + virtual void write(const void* data, size_t size) | ||
37 | + { | ||
38 | + DWORD dwNumberOfBytesWritten; | ||
39 | + WriteFile(hFile, data, size, &dwNumberOfBytesWritten, NULL); | ||
40 | + } | ||
41 | +}; | ||
42 | + | ||
43 | +class WindowsError : public std::exception | ||
44 | +{ | ||
45 | +private: | ||
46 | + std::string msg; | ||
47 | + DWORD error_code; | ||
48 | +public: | ||
49 | + WindowsError(DWORD error_code); | ||
50 | + virtual const char *what() const; | ||
51 | +}; | ||
52 | + | ||
53 | +HANDLE IthCreateThread(LPVOID start_addr, DWORD param); | ||
54 | +bool IthCreateDirectory(LPCWSTR name); | ||
55 | +HANDLE IthCreateFile(LPCWSTR name, DWORD option, DWORD share, DWORD disposition); | ||
56 | +int MB_WC(const char* mb, wchar_t* wc, int wc_length); | ||
57 | +int MB_WC_count(const char* mb, int mb_length); | ||
58 | +int WC_MB(const wchar_t *wc, char* mb, int mb_length); | ||
59 | +bool Parse(const std::wstring& cmd, HookParam& hp); | ||
60 | + | ||
61 | +template <typename T> | ||
62 | +std::wstring ToHexString(T i) { | ||
63 | + std::wstringstream ss; | ||
64 | + ss << std::uppercase << std::hex << i; | ||
65 | + return ss.str(); | ||
66 | +} | ||
67 | + | ||
68 | +// http://jrdodds.blogs.com/blog/2004/08/raii_in_c.html | ||
69 | +class CriticalSection | ||
70 | +{ | ||
71 | +public: | ||
72 | + CriticalSection() | ||
73 | + { | ||
74 | + ::InitializeCriticalSection(&m_rep); | ||
75 | + } | ||
76 | + ~CriticalSection() | ||
77 | + { | ||
78 | + ::DeleteCriticalSection(&m_rep); | ||
79 | + } | ||
80 | + void Enter() | ||
81 | + { | ||
82 | + ::EnterCriticalSection(&m_rep); | ||
83 | + } | ||
84 | + void Leave() | ||
85 | + { | ||
86 | + ::LeaveCriticalSection(&m_rep); | ||
87 | + } | ||
88 | +private: | ||
89 | + CriticalSection(const CriticalSection&); | ||
90 | + CriticalSection& operator=(const CriticalSection&); | ||
91 | + | ||
92 | + CRITICAL_SECTION m_rep; | ||
93 | +}; | ||
94 | + | ||
95 | +class CSLock | ||
96 | +{ | ||
97 | +public: | ||
98 | + CSLock(CriticalSection& a_section) | ||
99 | + : m_section(a_section) | ||
100 | + { | ||
101 | + m_section.Enter(); | ||
102 | + } | ||
103 | + ~CSLock() | ||
104 | + { | ||
105 | + m_section.Leave(); | ||
106 | + } | ||
107 | +private: | ||
108 | + CSLock(const CSLock&); | ||
109 | + CSLock& operator=(const CSLock&); | ||
110 | + | ||
111 | + CriticalSection& m_section; | ||
112 | +}; |
gui/version.h.in
0 → 100644
gui/window.cpp
0 → 100644
This diff is collapsed. Click to expand it.
gui/window.h
0 → 100644
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" |
-
Please register or login to post a comment