Skip to content

Latest commit

 

History

History
287 lines (241 loc) · 6.94 KB

2022-07-24.md

File metadata and controls

287 lines (241 loc) · 6.94 KB

2022-07-24

こんにちは!

こんにちは!

構造体の定義は終わりましたか?

はい

前回の課題のNtUserUnloadKeyboardLayoutを見ていこう。 エクスポートでもエントリーポイントでもない関数には頭に''が付く。 [Functions]→[]→[_NtUser]→[_NtUserUnloadKeyboardLayout]のようにたどる。

undefined4 _NtUserUnloadKeyboardLayout@4(uint param_1)
{
  int iVar1;
  undefined4 uVar2;
  
  _EnterCrit@0();
  iVar1 = __GetProcessWindowStation@4((undefined4 *)0x0);
  uVar2 = _xxxUnloadKeyboardLayout@8(iVar1,param_1);
  _LeaveCrit@0();
  return uVar2;
}

ReactOSの「NtUserUnloadKeyboardLayout」のプロトタイプを見ると、 「BOOL APIENTRY NtUserUnloadKeyboardLayout(HKL hKl)」 になっているので、「undefined4」をBOOLとし、「uint param_1」をHKL hKlとする。 これらに合わせて_xxxUnloadKeyboardLayoutのプロトタイプも修正。

「__GetProcessWindowStation@4((undefined4 *)0x0)」 の部分は、どうみてもReactOSの「UserGetProcessWindowStation()」だろう。

解析結果は次のようになる。

BOOL _NtUserUnloadKeyboardLayout@4(HKL hKl)
{
  HWINSTA hWinSta;
  BOOL ret;
  
  _EnterCrit@0();
  hWinSta = __GetProcessWindowStation@4((undefined4 *)0x0);
  ret = _xxxUnloadKeyboardLayout@8(hWinSta,hKl);
  _LeaveCrit@0();
  return ret;
}

WinのEnterCrit();はReactOSのUserEnterExclusive();に相当する。 WinのLeaveCrit();はReactOSのUserLeave();に相当する。

清書すると

BOOL NTAPI NtUserUnloadKeyboardLayout(HKL hKl)
{
    BOOL ret;
    HWINSTA hWinSta;
    UserEnterExclusive();
    hWinSta = UserGetProcessWindowStation();
    ret = xxxUnloadKeyboardLayout(hWinSta, hKl);
    UserLeave();
    return ret;
}

次は_xxxUnloadKeyboardLayoutを見よう。 _xxxUnloadKeyboardLayoutをダブルクリック。

BOOL _xxxUnloadKeyboardLayout@8(HWINSTA hWinSta,HKL hKL)
{
  uint *puVar1;
  puVar1 = (uint *)_HKLtoPKL@8((int)_gptiCurrent,(uint)hKL);
  if (puVar1 != (uint *)0x0) {
    puVar1 = (uint *)_xxxInternalUnloadKeyboardLayout@12((int)hWinSta,puVar1,0);
  }
  return (BOOL)puVar1;
}

_gptiCurrentは、PTHREADINFO型らしい。 HKLtoPKLの名前からしてその戻り値はおそらくPKL型。PKLは、KL構造体へのポインタ型だ。 win32ss/user/ntuser/input.hによると:

typedef struct tagKL
{
    HEAD head;
    struct tagKL *pklNext; // PVOIDを代用。
    struct tagKL *pklPrev; // PVOIDを代用。
    DWORD dwKL_Flags;
    HKL hkl;
    PKBDFILE spkf; // PVOIDを代用。
    DWORD dwFontSigs;
    UINT iBaseCharset;
    USHORT CodePage;
    WCHAR wchDiacritic;
    PIMEINFOEX piiex; // PVOIDを代用。
} KL, *PKL;

解析結果は次のようになる。

BOOL _xxxUnloadKeyboardLayout@8(HWINSTA hWinSta,HKL hKL)
{
  PKL pKL;
  pKL = (PKL)_HKLtoPKL@8(_gptiCurrent,hKL);
  if (pKL != (PKL)0x0) {
    pKL = (PKL)_xxxInternalUnloadKeyboardLayout@12(hWinSta,pKL,0);
  }
  return (BOOL)pKL;
}

変数pKLをBOOL型の戻り値の格納場所として再利用しているので、ちょっとキャストが汚いことになっている。

清書すると

BOOL xxxUnloadKeyboardLayout(HWINSTA hWinSta, HKL hKL)
{
    PKL pKL = HKLtoPKL(gptiCurrent, hKL);
    if (!pKL)
        return FALSE;
    return xxxInternalUnloadKeyboardLayout(hWinSta, pKL, 0);
}

次は_HKLtoPKLと_xxxInternalUnloadKeyboardLayout。 THREADINFO構造体の型情報が必要だ。

typedef struct _THREADINFO
{
    W32THREAD;
    PTL                 ptl; // PVOIDを代用。
    PPROCESSINFO        ppi; // PVOIDを代用。
    struct _USER_MESSAGE_QUEUE* MessageQueue; // PVOIDを代用。
    struct tagKL*       KeyboardLayout;
    // ...以下略。
} THREADINFO;
typedef struct _THREADINFO *PTHREADINFO;

typedef struct _W32THREAD
{
    PETHREAD pEThread; // PVOIDを代用。
    LONG RefCount;
    PTL ptlW32; // PVOIDを代用。
    PVOID pgdiDcattr;
    PVOID pgdiBrushAttr;
    PVOID pUMPDObjs;
    PVOID pUMPDHeap;
    DWORD dwEngAcquireCount;
    PVOID pSemTable;
    PVOID pUMPDObj;
} W32THREAD, *PW32THREAD;

色々やると次が得られる。

PKL _HKLtoPKL@8(PTHREADINFO pti,HKL hKL)
{
  PKL pKVar1;
  PKL psVar2;
  PKL pvVar1;
  
  pvVar1 = pti->KeyboardLayout;
  if (pvVar1 != (PKL)0x0) {
    pKVar1 = pvVar1;
    if (hKL == (HKL)0x0) {
      do {
        pKVar1 = pKVar1->pklPrev;
        if ((*(byte *)((int)&pKVar1->dwKL_Flags + 3) & 0x20) == 0) {
          return pKVar1;
        }
      } while (pKVar1 != pvVar1);
    }
    else {
      psVar2 = pvVar1;
      if (hKL == (HKL)&DAT_00000001) {
        do {
          psVar2 = psVar2->pklNext;
          if ((*(byte *)((int)&psVar2->dwKL_Flags + 3) & 0x20) == 0) {
            return psVar2;
          }
        } while (psVar2 != pvVar1);
      }
      else if (((uint)hKL & 0xffff0000) == 0) {
        do {
          if (*(short *)&pKVar1->hkl == (short)hKL) {
            return pKVar1;
          }
          pKVar1 = pKVar1->pklNext;
        } while (pKVar1 != pvVar1);
      }
      else {
        do {
          if (pKVar1->hkl == hKL) {
            return pKVar1;
          }
          pKVar1 = pKVar1->pklNext;
        } while (pKVar1 != pvVar1);
      }
    }
  }
  return (PKL)0x0;
}

「(HKL)&DAT_00000001」はおそらく「(HKL)HKL_NEXT」だろうと思われる。

「*(short *)&pKVar1->hkl == (short)hKL」は、「LOWORD(pKVar1->hkl) == LOWORD(hKL)」と同じ。 LOWORDマクロは下位ワードを取得する。

「((uint)hKL & 0xffff0000) == 0」は、「HIWORD(hKL) == 0」と同じ。 HIWORDマクロは上位ワードを取得する。

「(*(byte *)((int)&pKVar1->dwKL_Flags + 3) & 0x20) == 0」は、「(pKVar1->dwKL_Flags & 0x20000000) == 0」と同じ。

清書すると

PKL HKLtoPKL(PTHREADINFO pti, HKL hKL)
{
    PKL pklFirst, pKL;

    pklFirst = pti->KeyboardLayout;
    if (!pklFirst)
        return NULL;

    pKL = pklFirst;

    if (hKL == (HKL)(INT_PTR)HKL_PREV)
    {
        do {
            pKL = pKL->pklPrev;
            if ((pKL->dwKL_Flags & 0x20000000) == 0)
                return pKL;
        } while (pKL != pklFirst);
    }
    else if (hKL == (HKL)(INT_PTR)HKL_NEXT)
    {
        do {
            pKL = pKL->pklNext;
            if ((pKL->dwKL_Flags & 0x20000000) == 0)
                return pKL;
        } while (pKL != pklFirst);
    }
    else if (HIWORD(hKL) == 0)
    {
        do {
            if (LOWORD(pKL->hkl) == LOWORD(hKL))
                return pKL;
            pKL = pKL->pklNext;
        } while (pKL != pklFirst);
    }
    else
    {
        do {
            if (pKL->hkl == hKL)
                return pKL;
            pKL = pKL->pklNext;
        } while (pKL != pklFirst);
    }

    return NULL;
}

【課題】_xxxInternalUnloadKeyboardLayoutを解析せよ。

今日はここまで。

ありがとうございました

訂正。__GetProcessWindowStationの戻り値は、HWINSTAではなくPWINSTATION_OBJECTでした。お詫びします。


戻る | 次へ