OSDN Git Service

prototype of UpdatePerUserSystemParameters differ by vista or earlier
[yamy/yamy.git] / fixscancodemap.cpp
1 #include "fixscancodemap.h"\r
2 #include "misc.h"\r
3 #include "windowstool.h"\r
4 #include <tchar.h>\r
5 #include <tlhelp32.h>\r
6 \r
7 #pragma runtime_checks( "", off )\r
8 static DWORD WINAPI invokeFunc(InjectInfo *info)\r
9 {\r
10         BOOL ret;\r
11         HANDLE hToken;\r
12         HMODULE hAdvapi32;\r
13         DWORD result = 0;\r
14 \r
15         FpImpersonateLoggedOnUser pImpersonateLoggedOnUser;\r
16         FpRevertToSelf pRevertToSelf;\r
17         FpOpenProcessToken pOpenProcessToken;\r
18 \r
19         hAdvapi32 = info->pGetModuleHandle(info->advapi32_);\r
20 \r
21         pImpersonateLoggedOnUser = (FpImpersonateLoggedOnUser)info->pGetProcAddress(hAdvapi32, info->impersonateLoggedOnUser_);\r
22         pRevertToSelf = (FpRevertToSelf)info->pGetProcAddress(hAdvapi32, info->revertToSelf_);\r
23         pOpenProcessToken = (FpOpenProcessToken)info->pGetProcAddress(hAdvapi32, info->openProcessToken_);\r
24 \r
25         HANDLE hProcess = info->pOpenProcess(PROCESS_QUERY_INFORMATION, FALSE, info->pid_);\r
26         if (hProcess == NULL) {\r
27                 result = 1;\r
28                 goto exit;\r
29         }\r
30 \r
31         ret = pOpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_DUPLICATE , &hToken);\r
32         if (ret == FALSE) {\r
33                 result = 2;\r
34                 goto exit;\r
35         }\r
36 \r
37         ret = pImpersonateLoggedOnUser(hToken);\r
38         if (ret == FALSE) {\r
39                 result = 3;\r
40                 goto exit;\r
41         }\r
42 \r
43         if (info->isVistaOrLater_) {\r
44                 info->pUpdate4(1);\r
45         } else {\r
46                 info->pUpdate8(0, 1);\r
47         }\r
48 \r
49         ret = pRevertToSelf();\r
50         if (ret == FALSE) {\r
51                 result = 4;\r
52                 goto exit;\r
53         }\r
54 \r
55 exit:\r
56         if (hToken != NULL) {\r
57                 info->pCloseHandle(hToken);\r
58         }\r
59 \r
60         if (hProcess != NULL) {\r
61                 info->pCloseHandle(hProcess);\r
62         }\r
63 \r
64         return result;\r
65 }\r
66 static int afterFunc(int arg)\r
67 {\r
68         // dummy operation\r
69         // if this function empty, optimizer unify this with other empty functions.\r
70         // following code avoid it.\r
71         arg *= 710810; // non-sense operation\r
72         return arg;\r
73 }\r
74 #pragma runtime_checks( "", restore )\r
75 \r
76 const DWORD FixScancodeMap::s_fixEntryNum = 4;\r
77 const DWORD FixScancodeMap::s_fixEntry[] = {\r
78         0x003ae03a,\r
79         0x0029e029,\r
80         0x0070e070,\r
81         0x007be07b,\r
82 };\r
83 \r
84 int FixScancodeMap::acquirePrivileges()\r
85 {\r
86         int ret = 0;\r
87         HANDLE hToken = NULL;\r
88 \r
89         if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {\r
90                 ret = 5;\r
91                 goto exit;\r
92         }\r
93 \r
94         LUID luid;\r
95         if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {\r
96                 ret = 6;\r
97                 goto exit;\r
98         }\r
99 \r
100         TOKEN_PRIVILEGES tk_priv;\r
101         tk_priv.PrivilegeCount = 1;\r
102         tk_priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;\r
103         tk_priv.Privileges[0].Luid = luid;\r
104 \r
105         if (!AdjustTokenPrivileges(hToken, FALSE, &tk_priv, 0, NULL, NULL)) {\r
106                 ret = 7;\r
107                 goto exit;\r
108         }\r
109 \r
110 exit:\r
111         if (hToken != NULL) {\r
112             CloseHandle(hToken);\r
113         }\r
114         return ret;\r
115 }\r
116 \r
117 \r
118 DWORD FixScancodeMap::getWinLogonPid()\r
119 {\r
120     DWORD pid = 0;\r
121         DWORD mySessionId = 0;\r
122 \r
123         if (ProcessIdToSessionId(GetCurrentProcessId(), &mySessionId) == FALSE) {\r
124                 return 0;\r
125         }\r
126 \r
127         HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);\r
128         if (hSnap == INVALID_HANDLE_VALUE) {\r
129                 return 0;\r
130         }\r
131 \r
132         PROCESSENTRY32 pe;\r
133         pe.dwSize = sizeof(pe);\r
134 \r
135     BOOL bResult = Process32First(hSnap, &pe);\r
136         while (bResult){\r
137                 if (!_tcsicmp(pe.szExeFile, _T("winlogon.exe"))) {\r
138                         DWORD sessionId;\r
139 \r
140                         if (ProcessIdToSessionId(pe.th32ProcessID, &sessionId) != FALSE) {\r
141                                 if (sessionId == mySessionId) {\r
142                                         pid = pe.th32ProcessID;\r
143                                         break;\r
144                                 }\r
145                         }\r
146                 }\r
147                 bResult = Process32Next(hSnap, &pe);\r
148         }\r
149 \r
150         CloseHandle(hSnap);\r
151         return pid;\r
152 }\r
153 \r
154 \r
155 bool FixScancodeMap::clean(WlInfo wl)\r
156 {\r
157         int ret = 0;\r
158 \r
159         if (wl.m_hThread != NULL) {\r
160                 DWORD result;\r
161 \r
162                 if (WaitForSingleObject(wl.m_hThread, 5000) == WAIT_TIMEOUT) {\r
163                         return false;\r
164                 }\r
165 \r
166                 GetExitCodeThread(wl.m_hThread, &result);\r
167                 CloseHandle(wl.m_hThread);\r
168 \r
169                 if (wl.m_remoteMem != NULL && wl.m_hProcess != NULL) {\r
170                         VirtualFreeEx(wl.m_hProcess, wl.m_remoteMem, 0, MEM_RELEASE);\r
171                 }\r
172 \r
173                 if (wl.m_remoteInfo != NULL && wl.m_hProcess != NULL) {\r
174                         VirtualFreeEx(wl.m_hProcess, wl.m_remoteInfo, 0, MEM_RELEASE);\r
175                 }\r
176 \r
177                 if (wl.m_hProcess != NULL) {\r
178                         CloseHandle(wl.m_hProcess);\r
179                 }\r
180         }\r
181 \r
182         return true;\r
183 }\r
184 \r
185 \r
186 int FixScancodeMap::injectThread(DWORD dwPID)\r
187 {\r
188         int ret = 0;\r
189         DWORD err = 0;\r
190         BOOL wFlag;\r
191         WlInfo wi;\r
192 \r
193         wi.m_hProcess = NULL;\r
194         wi.m_remoteMem = NULL;\r
195         wi.m_remoteInfo = NULL;\r
196         wi.m_hThread = NULL;\r
197 \r
198         DWORD invokeFuncAddr = (DWORD)invokeFunc;\r
199         DWORD afterFuncAddr = (DWORD)afterFunc;\r
200         DWORD memSize =  afterFuncAddr - invokeFuncAddr;\r
201 \r
202         if ((wi.m_hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID)) == NULL) {\r
203                 ret = 8;\r
204                 goto exit;\r
205         }\r
206 \r
207         wi.m_remoteMem = VirtualAllocEx(wi.m_hProcess, NULL, memSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
208         if (wi.m_remoteMem == NULL) {\r
209                 ret = 9;\r
210                 err = GetLastError();\r
211                 goto exit;\r
212         }\r
213 \r
214         wFlag = WriteProcessMemory(wi.m_hProcess, wi.m_remoteMem, (char*)invokeFunc, memSize, (SIZE_T*)0);\r
215         if (wFlag == FALSE) {\r
216                 ret = 10;\r
217                 goto exit;\r
218         }\r
219 \r
220         wi.m_remoteInfo = VirtualAllocEx(wi.m_hProcess, NULL, sizeof(m_info), MEM_COMMIT, PAGE_READWRITE);\r
221         if (wi.m_remoteInfo == NULL) {\r
222                 ret = 11;\r
223                 err = GetLastError();\r
224                 goto exit;\r
225         }\r
226 \r
227         wFlag = WriteProcessMemory(wi.m_hProcess, wi.m_remoteInfo, (char*)&m_info, sizeof(m_info), (SIZE_T*)0);\r
228         if (wFlag == FALSE) {\r
229                 ret = 12;\r
230                 goto exit;\r
231         }\r
232 \r
233 #if 0\r
234         TCHAR buf[1024];\r
235 \r
236         _stprintf_s(buf, sizeof(buf)/sizeof(buf[0]),\r
237                 _T("execute UpdatePerUserSystemParameters(), inject code to winlogon.exe?\r\n")\r
238                 _T("invokeFunc=0x%p\r\n")\r
239                 _T("afterFunc=0x%p\r\n")\r
240                 _T("afterFunc - invokeFunc=%d\r\n")\r
241                 _T("remoteMem=0x%p\r\n")\r
242                 _T("remoteInfo=0x%p(size: %d)\r\n"),\r
243                 invokeFunc, afterFunc, memSize, m_remoteMem, m_remoteInfo, sizeof(m_info));\r
244         if (MessageBox((HWND)NULL, buf, _T("upusp"), MB_OKCANCEL | MB_ICONSTOP) == IDCANCEL) {\r
245                 (m_info.pUpdate)(0, 1);\r
246                 goto exit;\r
247         }\r
248 #endif\r
249 \r
250         wi.m_hThread = CreateRemoteThread(wi.m_hProcess, NULL, 0, \r
251                 (LPTHREAD_START_ROUTINE)wi.m_remoteMem, wi.m_remoteInfo, 0, NULL);\r
252         if (wi.m_hThread == NULL) {\r
253                 ret = 13;\r
254                 goto exit;\r
255         }\r
256 \r
257         if (WaitForSingleObject(wi.m_hThread, 5000) == WAIT_TIMEOUT) {\r
258                 ret = 14;\r
259                 m_wlTrash.push_back(wi);\r
260                 goto dirty_exit;\r
261         }\r
262         DWORD result = -1;\r
263         GetExitCodeThread(wi.m_hThread, &result);\r
264         ret = result;\r
265         CloseHandle(wi.m_hThread);\r
266         wi.m_hThread = NULL;\r
267 \r
268 exit:\r
269         if (wi.m_remoteMem != NULL && wi.m_hProcess != NULL) {\r
270                 VirtualFreeEx(wi.m_hProcess, wi.m_remoteMem, 0, MEM_RELEASE);\r
271                 wi.m_remoteMem = NULL;\r
272         }\r
273 \r
274         if (wi.m_remoteInfo != NULL && wi.m_hProcess != NULL) {\r
275                 VirtualFreeEx(wi.m_hProcess, wi.m_remoteInfo, 0, MEM_RELEASE);\r
276                 wi.m_remoteInfo = NULL;\r
277         }\r
278 \r
279         if (wi.m_hProcess != NULL) {\r
280                 CloseHandle(wi.m_hProcess);\r
281                 wi.m_hProcess = NULL;\r
282         }\r
283 \r
284 dirty_exit:\r
285         return ret;\r
286 }\r
287 \r
288 int FixScancodeMap::update()\r
289 {\r
290         MINIMIZEDMETRICS mm;\r
291         int result = 0;\r
292 \r
293         if (m_errorOnConstruct) {\r
294                 result = m_errorOnConstruct;\r
295                 goto exit;\r
296         }\r
297 \r
298         m_wlTrash.erase(remove_if(m_wlTrash.begin(), m_wlTrash.end(), FixScancodeMap::clean), m_wlTrash.end());\r
299 \r
300         memset(&mm, 0, sizeof(mm));\r
301         mm.cbSize = sizeof(mm);\r
302         SystemParametersInfo(SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0);\r
303 \r
304         result = injectThread(m_winlogonPid);\r
305         if (result == 14) {\r
306                 // retry once\r
307                 result = injectThread(m_winlogonPid);\r
308                 if (result == 0) {\r
309                         result = 22;\r
310                 }\r
311         }\r
312 \r
313         SystemParametersInfo(SPI_SETMINIMIZEDMETRICS, sizeof(mm), &mm, 0);\r
314 \r
315 exit:\r
316         return result;\r
317 }\r
318 \r
319 int FixScancodeMap::fix()\r
320 {\r
321         ScancodeMap *origMap, *fixMap;\r
322         DWORD origSize, fixSize;\r
323         bool ret;\r
324         int result = 0;\r
325 \r
326         // save original Scancode Map\r
327         ret = m_pReg->read(_T("Scancode Map"), NULL, &origSize, NULL, 0);\r
328         if (ret) {\r
329                 origMap = reinterpret_cast<ScancodeMap*>(malloc(origSize));\r
330                 if (origMap == NULL) {\r
331                         result = 16;\r
332                         goto exit;\r
333                 }\r
334 \r
335                 ret = m_pReg->read(_T("Scancode Map"), reinterpret_cast<BYTE*>(origMap), &origSize, NULL, 0);\r
336                 if (ret == false) {\r
337                         result = 17;\r
338                         goto exit;\r
339                 }\r
340 \r
341                 fixSize = origSize;\r
342                 fixMap = reinterpret_cast<ScancodeMap*>(malloc(origSize + s_fixEntryNum * sizeof(s_fixEntry[0])));\r
343                 if (fixMap == NULL) {\r
344                         result = 18;\r
345                         goto exit;\r
346                 }\r
347 \r
348                 memcpy_s(fixMap, origSize + s_fixEntryNum, origMap, origSize);\r
349         } else {\r
350                 origSize = 0;\r
351                 origMap = NULL;\r
352 \r
353                 fixSize = sizeof(ScancodeMap);\r
354                 fixMap = reinterpret_cast<ScancodeMap*>(malloc(sizeof(ScancodeMap) + s_fixEntryNum * sizeof(s_fixEntry[0])));\r
355                 if (fixMap == NULL) {\r
356                         result = 19;\r
357                         goto exit;\r
358                 }\r
359 \r
360                 fixMap->header1 = 0;\r
361                 fixMap->header2 = 0;\r
362                 fixMap->count = 1;\r
363                 fixMap->entry[0] = 0;\r
364         }\r
365 \r
366         for (DWORD i = 0; i < s_fixEntryNum; i++) {\r
367                 bool skip = false;\r
368 \r
369                 if (origMap) {\r
370                         for (DWORD j = 0; j < origMap->count; j++) {\r
371                                 if (HIWORD(s_fixEntry[i]) == HIWORD(origMap->entry[j])) {\r
372                                         skip = true;\r
373                                 }\r
374                         }\r
375                 }\r
376 \r
377                 if (skip) {\r
378                         // s_fixEntry[i] found in original Scancode Map, so don't fix it\r
379                         continue;\r
380                 }\r
381 \r
382                 // add fix entry to fixMap\r
383                 fixMap->entry[fixMap->count - 1] = s_fixEntry[i];\r
384                 fixMap->entry[fixMap->count] = 0;\r
385                 fixMap->count++;\r
386                 fixSize += 4;\r
387         }\r
388 \r
389         ret = m_pReg->write(_T("Scancode Map"), reinterpret_cast<BYTE*>(fixMap), fixSize);\r
390         if (ret == false) {\r
391                 result = 20;\r
392                 goto exit;\r
393         }\r
394 \r
395         result = update();\r
396 \r
397         if (origMap) {\r
398                 ret = m_pReg->write(_T("Scancode Map"), reinterpret_cast<BYTE*>(origMap), origSize);\r
399         } else {\r
400                 ret = m_pReg->remove(_T("Scancode Map"));\r
401         }\r
402         if (ret == false) {\r
403                 result = 21;\r
404                 goto exit;\r
405         }\r
406 \r
407 exit:\r
408         free(origMap);\r
409         origMap = NULL;\r
410 \r
411         free(fixMap);\r
412         fixMap = NULL;\r
413 \r
414         return result;\r
415 }\r
416 \r
417 int FixScancodeMap::restore()\r
418 {\r
419         return update();\r
420 }\r
421 \r
422 FixScancodeMap::FixScancodeMap() :\r
423         m_errorOnConstruct(0),\r
424         m_winlogonPid(0),\r
425         m_regHKCU(HKEY_CURRENT_USER, _T("Keyboard Layout")),\r
426         m_regHKLM(HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout")),\r
427         m_pReg(NULL)\r
428 {\r
429         HMODULE hMod;\r
430 \r
431         m_info.pid_ = GetCurrentProcessId();\r
432 \r
433         memcpy(&m_info.advapi32_, _T("advapi32.dll"), sizeof(m_info.advapi32_));\r
434         memcpy(&m_info.impersonateLoggedOnUser_, "ImpersonateLoggedOnUser", sizeof(m_info.impersonateLoggedOnUser_));\r
435         memcpy(&m_info.revertToSelf_, "RevertToSelf", sizeof(m_info.revertToSelf_));\r
436         memcpy(&m_info.openProcessToken_, "OpenProcessToken", sizeof(m_info.openProcessToken_));\r
437 \r
438         hMod = GetModuleHandle(_T("user32.dll"));\r
439         if (hMod != NULL) {\r
440                 m_info.pUpdate4 = (FpUpdatePerUserSystemParameters4)GetProcAddress(hMod, "UpdatePerUserSystemParameters");\r
441                 m_info.pUpdate8 = (FpUpdatePerUserSystemParameters8)m_info.pUpdate4;\r
442                 if (m_info.pUpdate4 == NULL) {\r
443                         return;\r
444                 }\r
445         }\r
446 \r
447         hMod = GetModuleHandle(_T("kernel32.dll"));\r
448         if (hMod != NULL) {\r
449                 m_info.pGetModuleHandle = (FpGetModuleHandleW)GetProcAddress(hMod, "GetModuleHandleW");\r
450                 if (m_info.pGetModuleHandle == NULL) {\r
451                         return;\r
452                 }\r
453 \r
454                 m_info.pGetProcAddress = (FpGetProcAddress)GetProcAddress(hMod, "GetProcAddress");\r
455                 if (m_info.pGetProcAddress == NULL) {\r
456                         return;\r
457                 }\r
458 \r
459                 m_info.pOpenProcess = (FpOpenProcess)GetProcAddress(hMod, "OpenProcess");\r
460                 if (m_info.pOpenProcess == NULL) {\r
461                         return;\r
462                 }\r
463 \r
464                 m_info.pCloseHandle = (FpCloseHandle)GetProcAddress(hMod, "CloseHandle");\r
465                 if (m_info.pCloseHandle == NULL) {\r
466                         return;\r
467                 }\r
468         }\r
469 \r
470         // Windows7 RC not support Scancode Map on HKCU?\r
471         if (checkWindowsVersion(6, 1) == FALSE) {\r
472                 m_pReg = &m_regHKCU; // Vista or earlier\r
473         } else {\r
474                 m_pReg = &m_regHKLM; // Windows7 or later\r
475         }\r
476 \r
477         // prototype of UpdatePerUserSystemParameters() differ vista or earlier\r
478         if (checkWindowsVersion(6, 0) == FALSE) {\r
479                 m_info.isVistaOrLater_ = 0; // before Vista\r
480         } else {\r
481                 m_info.isVistaOrLater_ = 1; // Vista or later\r
482         }\r
483 \r
484         m_errorOnConstruct = acquirePrivileges();\r
485         if (m_errorOnConstruct) {\r
486                 goto exit;\r
487         }\r
488 \r
489         if ((m_winlogonPid = getWinLogonPid()) == 0) {\r
490                 m_errorOnConstruct = 15;\r
491                 goto exit;\r
492         }\r
493 \r
494 exit:\r
495         ;\r
496 }\r
497 \r
498 FixScancodeMap::~FixScancodeMap()\r
499 {\r
500 }\r