[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);
}
/* 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
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))
return FALSE;
hIME = GetModuleHandleW(szPath);
pImeDpi->hInst = hIME = LoadLibraryW(szPath);
if (hIME == NULL)
{
hIME = LoadLibraryW(szPath);
if (hIME == NULL)
{
ERR("Imm32LoadIME: LoadLibraryW(%S) failed\n", szPath);
return FALSE;
}
ERR("Imm32LoadIME: LoadLibraryW(%s) failed\n", debugstr_w(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) \
do { \
fn = GetProcAddress(hIME, #name); \

View file

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

View file

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

View file

@ -20,7 +20,8 @@
#define USER32_CALLBACK_LPK (16)
#define USER32_CALLBACK_UMPD (17)
#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
{
@ -178,6 +179,17 @@ typedef struct _IMMPROCESSKEY_CALLBACK_ARGUMENTS
DWORD dwHotKeyID;
} 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
User32CallCopyImageFromKernel(PVOID Arguments, ULONG ArgumentLength);
NTSTATUS WINAPI
@ -216,4 +228,7 @@ NTSTATUS WINAPI
User32CallUMPDFromKernel(PVOID Arguments, ULONG ArgumentLength);
NTSTATUS WINAPI
User32CallImmProcessKeyFromKernel(PVOID Arguments, ULONG ArgumentLength);
NTSTATUS WINAPI
User32CallImmLoadLayoutFromKernel(PVOID Arguments, ULONG ArgumentLength);
#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;
}
/* 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 */

View file

@ -80,3 +80,9 @@ BOOL FASTCALL IntMsgCreateStructW(PWND,CREATESTRUCTW*,CREATESTRUCTW*,PVOID*,PVOI
DWORD
APIENTRY
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->pklNext->pklPrev = pKl->pklPrev;
UnloadKbdFile(pKl->spkf);
if (pKl->piiex)
{
ExFreePoolWithTag(pKl->piiex, USERTAG_IME);
}
UserDeleteObject(pKl->head.h, TYPE_KBDLAYOUT);
return TRUE;
}
@ -995,12 +999,34 @@ cleanup:
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
*
* Loads keyboard layout with given locale id
*
* 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
APIENTRY
@ -1015,7 +1041,7 @@ NtUserLoadKeyboardLayoutEx(
{
HKL hklRet = NULL;
PKL pKl = NULL, pklLast;
WCHAR Buffer[9];
WCHAR Buffer[KL_NAMELENGTH];
UNICODE_STRING ustrSafeKLID;
if (Flags & ~(KLF_ACTIVATE|KLF_NOTELLSHELL|KLF_REORDER|KLF_REPLACELANG|
@ -1082,6 +1108,8 @@ NtUserLoadKeyboardLayoutEx(
pKl->pklPrev = pKl;
gspklBaseLayout = pKl;
}
pKl->piiex = co_UserImmLoadLayout(UlongToHandle(hkl));
}
/* If this layout was prepared to unload, undo it */

View file

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

View file

@ -224,6 +224,7 @@ PVOID apfnDispatch[USER32_CALLBACK_MAXIMUM + 1] =
User32CallLPKFromKernel,
User32CallUMPDFromKernel,
User32CallImmProcessKeyFromKernel,
User32CallImmLoadLayoutFromKernel,
};
@ -725,3 +726,12 @@ User32CallImmProcessKeyFromKernel(PVOID Arguments, ULONG ArgumentLength)
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);
}
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
*
@ -656,12 +663,20 @@ IntLoadKeyboardLayout(
UNICODE_STRING ustrKbdName;
UNICODE_STRING ustrKLID;
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;
HKEY hKey;
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));
if (!bIsIME) /* Not IME? */
{
@ -690,8 +705,7 @@ IntLoadKeyboardLayout(
StringCbCatW(wszRegKey, sizeof(wszRegKey), pwszKLID);
/* Open layout registry key for read */
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegKey, 0,
KEY_READ, &hKey) == ERROR_SUCCESS)
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszRegKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
dwSize = sizeof(wszLayoutId);
if (RegQueryValueExW(hKey, L"Layout Id", NULL, &dwType, (LPBYTE)wszLayoutId, &dwSize) == ERROR_SUCCESS)
@ -744,7 +758,7 @@ HKL WINAPI
LoadKeyboardLayoutW(LPCWSTR pwszKLID,
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);
}