[NTUSER][USER32][IMM32] Initialize pKL->piiex by using ImmLoadLayout (#4645)

To recognize IME, we have to initialize pKL->piiex.
- Add co_ClientImmLoadLayout and User32CallImmLoadLayoutFromKernel functions to call imm32!ImmLoadLayout on user mode from kernel.
- Use co_ClientImmLoadLayout in NtUserLoadKeyboardLayoutEx.
- Improve Imm32LoadIME to sanitize the IME table.
CORE-11700
This commit is contained in:
Katayama Hirofumi MZ 2022-09-05 08:34:00 +09:00 committed by GitHub
parent 15a0f7adb0
commit 85e292d58f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 161 additions and 38 deletions

View file

@ -149,6 +149,15 @@ BOOL APIENTRY Imm32InquireIme(PIMEDPI pImeDpi)
return GetClassInfoW(pImeDpi->hInst, pImeDpi->szUIClass, &wcW); return GetClassInfoW(pImeDpi->hInst, pImeDpi->szUIClass, &wcW);
} }
/* Define stub IME functions */
#define DEFINE_IME_ENTRY(type, name, params, optional) \
type APIENTRY Stub##name params { \
FIXME("%s: Why stub called?\n", #name); \
return (type)0; \
}
#include "imetable.h"
#undef DEFINE_IME_ENTRY
// Win: LoadIME // Win: LoadIME
BOOL APIENTRY Imm32LoadIME(PIMEINFOEX pImeInfoEx, PIMEDPI pImeDpi) BOOL APIENTRY Imm32LoadIME(PIMEINFOEX pImeInfoEx, PIMEDPI pImeDpi)
{ {
@ -160,18 +169,19 @@ BOOL APIENTRY Imm32LoadIME(PIMEINFOEX pImeInfoEx, PIMEDPI pImeDpi)
if (!Imm32GetSystemLibraryPath(szPath, _countof(szPath), pImeInfoEx->wszImeFile)) if (!Imm32GetSystemLibraryPath(szPath, _countof(szPath), pImeInfoEx->wszImeFile))
return FALSE; return FALSE;
hIME = GetModuleHandleW(szPath); pImeDpi->hInst = hIME = LoadLibraryW(szPath);
if (hIME == NULL) if (hIME == NULL)
{ {
hIME = LoadLibraryW(szPath); ERR("Imm32LoadIME: LoadLibraryW(%s) failed\n", debugstr_w(szPath));
if (hIME == NULL) return FALSE;
{
ERR("Imm32LoadIME: LoadLibraryW(%S) failed\n", szPath);
return FALSE;
}
} }
pImeDpi->hInst = hIME;
/* Populate the table by stub IME functions */
#define DEFINE_IME_ENTRY(type, name, params, optional) pImeDpi->name = Stub##name;
#include "imetable.h"
#undef DEFINE_IME_ENTRY
/* Populate the table by real IME functions */
#define DEFINE_IME_ENTRY(type, name, params, optional) \ #define DEFINE_IME_ENTRY(type, name, params, optional) \
do { \ do { \
fn = GetProcAddress(hIME, #name); \ fn = GetProcAddress(hIME, #name); \

View file

@ -53,57 +53,49 @@ BOOL WINAPI ImmRegisterClient(PSHAREDINFO ptr, HINSTANCE hMod)
*/ */
BOOL WINAPI ImmLoadLayout(HKL hKL, PIMEINFOEX pImeInfoEx) BOOL WINAPI ImmLoadLayout(HKL hKL, PIMEINFOEX pImeInfoEx)
{ {
DWORD cbData; DWORD cbData, dwType;
HKEY hLayoutKey = NULL, hLayoutsKey = NULL; HKEY hLayoutKey;
LONG error; LONG error;
WCHAR szLayout[MAX_PATH]; WCHAR szLayout[MAX_PATH];
TRACE("(%p, %p)\n", hKL, pImeInfoEx); TRACE("(%p, %p)\n", hKL, pImeInfoEx);
ZeroMemory(pImeInfoEx, sizeof(IMEINFOEX));
if (IS_IME_HKL(hKL) || !Imm32IsCiceroMode() || Imm32Is16BitMode()) if (IS_IME_HKL(hKL) || !Imm32IsCiceroMode() || Imm32Is16BitMode())
{ {
Imm32UIntToStr((DWORD)(DWORD_PTR)hKL, 16, szLayout, _countof(szLayout)); StringCchPrintfW(szLayout, _countof(szLayout), L"%s\\%08lX",
REGKEY_KEYBOARD_LAYOUTS, HandleToUlong(hKL));
error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hLayoutsKey); error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szLayout, 0, KEY_READ, &hLayoutKey);
if (error) if (error)
{ {
ERR("RegOpenKeyW: 0x%08lX\n", error); ERR("RegOpenKeyExW: 0x%08lX\n", error);
return FALSE;
}
error = RegOpenKeyW(hLayoutsKey, szLayout, &hLayoutKey);
if (error)
{
ERR("RegOpenKeyW: 0x%08lX\n", error);
RegCloseKey(hLayoutsKey);
return FALSE; return FALSE;
} }
} }
else else
{ {
error = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_IMM, &hLayoutKey); error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, REGKEY_IMM, 0, KEY_READ, &hLayoutKey);
if (error) if (error)
{ {
ERR("RegOpenKeyW: 0x%08lX\n", error); ERR("RegOpenKeyExW: 0x%08lX\n", error);
return FALSE; return FALSE;
} }
} }
cbData = sizeof(pImeInfoEx->wszImeFile); cbData = sizeof(pImeInfoEx->wszImeFile);
error = RegQueryValueExW(hLayoutKey, L"Ime File", 0, 0, error = RegQueryValueExW(hLayoutKey, L"Ime File", NULL, &dwType,
(LPBYTE)pImeInfoEx->wszImeFile, &cbData); (LPBYTE)pImeInfoEx->wszImeFile, &cbData);
pImeInfoEx->wszImeFile[_countof(pImeInfoEx->wszImeFile) - 1] = 0; pImeInfoEx->wszImeFile[_countof(pImeInfoEx->wszImeFile) - 1] = UNICODE_NULL;
RegCloseKey(hLayoutKey); RegCloseKey(hLayoutKey);
if (hLayoutsKey)
RegCloseKey(hLayoutsKey);
pImeInfoEx->fLoadFlag = 0; pImeInfoEx->fLoadFlag = 0;
if (error) if (error != ERROR_SUCCESS || dwType != REG_SZ)
{ {
ERR("RegQueryValueExW: 0x%08lX\n", error); ERR("RegQueryValueExW: 0x%lX, 0x%lX\n", error, dwType);
pImeInfoEx->hkl = NULL;
return FALSE; return FALSE;
} }
@ -116,7 +108,7 @@ BOOL WINAPI ImmLoadLayout(HKL hKL, PIMEINFOEX pImeInfoEx)
*/ */
BOOL WINAPI ImmFreeLayout(DWORD dwUnknown) BOOL WINAPI ImmFreeLayout(DWORD dwUnknown)
{ {
WCHAR szKBD[9]; WCHAR szKBD[KL_NAMELENGTH];
UINT iKL, cKLs; UINT iKL, cKLs;
HKL hOldKL, hNewKL, *pList; HKL hOldKL, hNewKL, *pList;
PIMEDPI pImeDpi; PIMEDPI pImeDpi;

View file

@ -776,6 +776,7 @@ BOOL APIENTRY Imm32LoadImeVerInfo(PIMEINFOEX pImeInfoEx)
hinstVersion = LoadLibraryW(szPath); hinstVersion = LoadLibraryW(szPath);
if (!hinstVersion) if (!hinstVersion)
return FALSE; return FALSE;
bLoaded = TRUE; bLoaded = TRUE;
} }

View file

@ -20,7 +20,8 @@
#define USER32_CALLBACK_LPK (16) #define USER32_CALLBACK_LPK (16)
#define USER32_CALLBACK_UMPD (17) #define USER32_CALLBACK_UMPD (17)
#define USER32_CALLBACK_IMMPROCESSKEY (18) #define USER32_CALLBACK_IMMPROCESSKEY (18)
#define USER32_CALLBACK_MAXIMUM (18) #define USER32_CALLBACK_IMMLOADLAYOUT (19)
#define USER32_CALLBACK_MAXIMUM USER32_CALLBACK_IMMLOADLAYOUT
typedef struct _WINDOWPROC_CALLBACK_ARGUMENTS typedef struct _WINDOWPROC_CALLBACK_ARGUMENTS
{ {
@ -178,6 +179,17 @@ typedef struct _IMMPROCESSKEY_CALLBACK_ARGUMENTS
DWORD dwHotKeyID; DWORD dwHotKeyID;
} IMMPROCESSKEY_CALLBACK_ARGUMENTS, *PIMMPROCESSKEY_CALLBACK_ARGUMENTS; } IMMPROCESSKEY_CALLBACK_ARGUMENTS, *PIMMPROCESSKEY_CALLBACK_ARGUMENTS;
typedef struct _IMMLOADLAYOUT_CALLBACK_ARGUMENTS
{
HKL hKL;
} IMMLOADLAYOUT_CALLBACK_ARGUMENTS, *PIMMLOADLAYOUT_CALLBACK_ARGUMENTS;
typedef struct _IMMLOADLAYOUT_CALLBACK_OUTPUT
{
BOOL ret;
IMEINFOEX iiex;
} IMMLOADLAYOUT_CALLBACK_OUTPUT, *PIMMLOADLAYOUT_CALLBACK_OUTPUT;
NTSTATUS WINAPI NTSTATUS WINAPI
User32CallCopyImageFromKernel(PVOID Arguments, ULONG ArgumentLength); User32CallCopyImageFromKernel(PVOID Arguments, ULONG ArgumentLength);
NTSTATUS WINAPI NTSTATUS WINAPI
@ -216,4 +228,7 @@ NTSTATUS WINAPI
User32CallUMPDFromKernel(PVOID Arguments, ULONG ArgumentLength); User32CallUMPDFromKernel(PVOID Arguments, ULONG ArgumentLength);
NTSTATUS WINAPI NTSTATUS WINAPI
User32CallImmProcessKeyFromKernel(PVOID Arguments, ULONG ArgumentLength); User32CallImmProcessKeyFromKernel(PVOID Arguments, ULONG ArgumentLength);
NTSTATUS WINAPI
User32CallImmLoadLayoutFromKernel(PVOID Arguments, ULONG ArgumentLength);
#endif /* __INCLUDE_USER32_CALLBACK_H */ #endif /* __INCLUDE_USER32_CALLBACK_H */

View file

@ -1272,4 +1272,50 @@ co_IntImmProcessKey(HWND hWnd, HKL hKL, UINT vKey, LPARAM lParam, DWORD dwHotKey
return ret; return ret;
} }
/* Win: ClientImmLoadLayout */
BOOL
APIENTRY
co_ClientImmLoadLayout(
_In_ HKL hKL,
_Inout_ PIMEINFOEX pImeInfoEx)
{
BOOL ret;
NTSTATUS Status;
IMMLOADLAYOUT_CALLBACK_ARGUMENTS Common = { hKL };
ULONG ResultLength = sizeof(IMMLOADLAYOUT_CALLBACK_OUTPUT);
PIMMLOADLAYOUT_CALLBACK_OUTPUT ResultPointer = NULL;
RtlZeroMemory(pImeInfoEx, sizeof(IMEINFOEX));
UserLeaveCo();
Status = KeUserModeCallback(USER32_CALLBACK_IMMLOADLAYOUT,
&Common,
sizeof(Common),
(PVOID*)&ResultPointer,
&ResultLength);
UserEnterCo();
if (!NT_SUCCESS(Status) || !ResultPointer ||
ResultLength != sizeof(IMMLOADLAYOUT_CALLBACK_OUTPUT))
{
ERR("0x%lX, %p, %lu\n", Status, ResultPointer, ResultLength);
return FALSE;
}
_SEH2_TRY
{
ProbeForRead(ResultPointer, ResultLength, 1);
ret = ResultPointer->ret;
if (ret)
RtlCopyMemory(pImeInfoEx, &ResultPointer->iiex, sizeof(IMEINFOEX));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ret = FALSE;
}
_SEH2_END;
return ret;
}
/* EOF */ /* EOF */

View file

@ -80,3 +80,9 @@ BOOL FASTCALL IntMsgCreateStructW(PWND,CREATESTRUCTW*,CREATESTRUCTW*,PVOID*,PVOI
DWORD DWORD
APIENTRY APIENTRY
co_IntImmProcessKey(HWND hWnd, HKL hKL, UINT vKey, LPARAM lParam, DWORD dwHotKeyID); co_IntImmProcessKey(HWND hWnd, HKL hKL, UINT vKey, LPARAM lParam, DWORD dwHotKeyID);
BOOL
APIENTRY
co_ClientImmLoadLayout(
_In_ HKL hKL,
_Inout_ PIMEINFOEX pImeInfoEx);

View file

@ -497,6 +497,10 @@ UserUnloadKbl(PKL pKl)
pKl->pklPrev->pklNext = pKl->pklNext; pKl->pklPrev->pklNext = pKl->pklNext;
pKl->pklNext->pklPrev = pKl->pklPrev; pKl->pklNext->pklPrev = pKl->pklPrev;
UnloadKbdFile(pKl->spkf); UnloadKbdFile(pKl->spkf);
if (pKl->piiex)
{
ExFreePoolWithTag(pKl->piiex, USERTAG_IME);
}
UserDeleteObject(pKl->head.h, TYPE_KBDLAYOUT); UserDeleteObject(pKl->head.h, TYPE_KBDLAYOUT);
return TRUE; return TRUE;
} }
@ -995,12 +999,34 @@ cleanup:
return bRet; return bRet;
} }
/* Win: xxxImmLoadLayout */
PIMEINFOEX FASTCALL co_UserImmLoadLayout(_In_ HKL hKL)
{
PIMEINFOEX piiex;
if (!IS_IME_HKL(hKL) && !IS_CICERO_MODE())
return NULL;
piiex = ExAllocatePoolWithTag(PagedPool, sizeof(IMEINFOEX), USERTAG_IME);
if (!piiex)
return NULL;
if (!co_ClientImmLoadLayout(hKL, piiex))
{
ExFreePoolWithTag(piiex, USERTAG_IME);
return NULL;
}
return piiex;
}
/* /*
* NtUserLoadKeyboardLayoutEx * NtUserLoadKeyboardLayoutEx
* *
* Loads keyboard layout with given locale id * Loads keyboard layout with given locale id
* *
* NOTE: We adopt a different design from Microsoft's one for security reason. * NOTE: We adopt a different design from Microsoft's one for security reason.
* We don't use the 1st and 3rd parameters of NtUserLoadKeyboardLayoutEx.
*/ */
HKL HKL
APIENTRY APIENTRY
@ -1015,7 +1041,7 @@ NtUserLoadKeyboardLayoutEx(
{ {
HKL hklRet = NULL; HKL hklRet = NULL;
PKL pKl = NULL, pklLast; PKL pKl = NULL, pklLast;
WCHAR Buffer[9]; WCHAR Buffer[KL_NAMELENGTH];
UNICODE_STRING ustrSafeKLID; UNICODE_STRING ustrSafeKLID;
if (Flags & ~(KLF_ACTIVATE|KLF_NOTELLSHELL|KLF_REORDER|KLF_REPLACELANG| if (Flags & ~(KLF_ACTIVATE|KLF_NOTELLSHELL|KLF_REORDER|KLF_REPLACELANG|
@ -1082,6 +1108,8 @@ NtUserLoadKeyboardLayoutEx(
pKl->pklPrev = pKl; pKl->pklPrev = pKl;
gspklBaseLayout = pKl; gspklBaseLayout = pKl;
} }
pKl->piiex = co_UserImmLoadLayout(UlongToHandle(hkl));
} }
/* If this layout was prepared to unload, undo it */ /* If this layout was prepared to unload, undo it */

View file

@ -11,6 +11,7 @@
typedef VOID (*TL_FN_FREE)(PVOID); typedef VOID (*TL_FN_FREE)(PVOID);
/* Thread Lock structure */
typedef struct _TL typedef struct _TL
{ {
struct _TL* next; struct _TL* next;

View file

@ -224,6 +224,7 @@ PVOID apfnDispatch[USER32_CALLBACK_MAXIMUM + 1] =
User32CallLPKFromKernel, User32CallLPKFromKernel,
User32CallUMPDFromKernel, User32CallUMPDFromKernel,
User32CallImmProcessKeyFromKernel, User32CallImmProcessKeyFromKernel,
User32CallImmLoadLayoutFromKernel,
}; };
@ -725,3 +726,12 @@ User32CallImmProcessKeyFromKernel(PVOID Arguments, ULONG ArgumentLength)
return ZwCallbackReturn(&Result, sizeof(DWORD), STATUS_SUCCESS); return ZwCallbackReturn(&Result, sizeof(DWORD), STATUS_SUCCESS);
} }
NTSTATUS WINAPI
User32CallImmLoadLayoutFromKernel(PVOID Arguments, ULONG ArgumentLength)
{
PIMMLOADLAYOUT_CALLBACK_ARGUMENTS Common = Arguments;
IMMLOADLAYOUT_CALLBACK_OUTPUT Result;
Result.ret = IMM_FN(ImmLoadLayout)(Common->hKL, &Result.iiex);
return ZwCallbackReturn(&Result, sizeof(Result), STATUS_SUCCESS);
}

View file

@ -638,6 +638,13 @@ LoadKeyboardLayoutA(LPCSTR pszKLID,
return LoadKeyboardLayoutW(wszKLID, Flags); return LoadKeyboardLayoutW(wszKLID, Flags);
} }
inline BOOL IsValidKLID(_In_ LPCWSTR pwszKLID)
{
return (pwszKLID != NULL) && (wcsspn(pwszKLID, L"0123456789ABCDEFabcdef") == (KL_NAMELENGTH - 1));
}
#define ENGLISH_US MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)
/* /*
* @unimplemented * @unimplemented
* *
@ -656,12 +663,20 @@ IntLoadKeyboardLayout(
UNICODE_STRING ustrKbdName; UNICODE_STRING ustrKbdName;
UNICODE_STRING ustrKLID; UNICODE_STRING ustrKLID;
WCHAR wszRegKey[256] = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\"; WCHAR wszRegKey[256] = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\";
WCHAR wszLayoutId[10], wszNewKLID[10], szImeFileName[80]; WCHAR wszLayoutId[10], wszNewKLID[KL_NAMELENGTH], szImeFileName[80];
PWCHAR endptr;
HKL hNewKL; HKL hNewKL;
HKEY hKey; HKEY hKey;
BOOL bIsIME; BOOL bIsIME;
dwhkl = wcstoul(pwszKLID, NULL, 16); if (!IsValidKLID(pwszKLID))
{
ERR("pwszKLID: %s\n", debugstr_w(pwszKLID));
return UlongToHandle(MAKELONG(ENGLISH_US, ENGLISH_US));
}
dwhkl = wcstoul(pwszKLID, &endptr, 16);
bIsIME = IS_IME_HKL(UlongToHandle(dwhkl)); bIsIME = IS_IME_HKL(UlongToHandle(dwhkl));
if (!bIsIME) /* Not IME? */ if (!bIsIME) /* Not IME? */
{ {
@ -690,8 +705,7 @@ IntLoadKeyboardLayout(
StringCbCatW(wszRegKey, sizeof(wszRegKey), pwszKLID); StringCbCatW(wszRegKey, sizeof(wszRegKey), pwszKLID);
/* Open layout registry key for read */ /* Open layout registry key for read */
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegKey, 0, if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
KEY_READ, &hKey) == ERROR_SUCCESS)
{ {
dwSize = sizeof(wszLayoutId); dwSize = sizeof(wszLayoutId);
if (RegQueryValueExW(hKey, L"Layout Id", NULL, &dwType, (LPBYTE)wszLayoutId, &dwSize) == ERROR_SUCCESS) if (RegQueryValueExW(hKey, L"Layout Id", NULL, &dwType, (LPBYTE)wszLayoutId, &dwSize) == ERROR_SUCCESS)
@ -744,7 +758,7 @@ HKL WINAPI
LoadKeyboardLayoutW(LPCWSTR pwszKLID, LoadKeyboardLayoutW(LPCWSTR pwszKLID,
UINT Flags) UINT Flags)
{ {
TRACE("(%s, 0x%X)", debugstr_w(pwszKLID), Flags); TRACE("(%s, 0x%X)\n", debugstr_w(pwszKLID), Flags);
return IntLoadKeyboardLayout(NULL, pwszKLID, 0, Flags, FALSE); return IntLoadKeyboardLayout(NULL, pwszKLID, 0, Flags, FALSE);
} }