windows_指定したexeに対してDLLインジェクションでコピペを検出する

前回は自分自身のプロセスに対してDLLインジェクションを実行しメッセージボックスの表示内容を変更しました。今回は指定したEXEに対してコピー&ペーストを検出できるようにしたいと思います。

それではDLL側のプロジェクトをまず作成していきます。

DLLプロジェクトの作成

DLLが読み込まれたときに実行する処理は以下の様になります。文字セットはマルチバイト文字セットを指定しています。

dllmain.cpp

// dllmain.cpp : DLL アプリケーションのエントリ ポイントを定義します。
#include "stdafx.h"
#include "dllmain.h"
#include <string>
#include <process.h>  
#include <Windows.h>
#include <psapi.h>

void logWrite(std::string content);
std::string getLogHeader();
std::string getCurrentName();

BOOL APIENTRY DllMain( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    HANDLE hThread;
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        hThread = CreateThread(NULL, 0, apiHook, (LPVOID)NULL, 0, NULL);
        if (hThread == NULL) {
            MessageBox(NULL, _TEXT("CreateThread"), _TEXT("Error"), MB_OK);
            return FALSE;
        }
        CloseHandle(hThread);
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

DWORD WINAPI apiHook(LPVOID pData)
{
    std::string logContent;
    HMODULE baseAddr = GetModuleHandle(NULL);
    DWORD dwIdataSize;
    PIMAGE_IMPORT_DESCRIPTOR pImgDesc = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(baseAddr, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &dwIdataSize);

    while (pImgDesc->Name) {
        char* lpModule = (char*)(baseAddr)+pImgDesc->Name;
        if (!_stricmp(lpModule, MODULE_DLL)) {
            break;
        }
        pImgDesc++;
    }

    if (!pImgDesc->Name) {
        return -1;
    }

    PIMAGE_THUNK_DATA pIAT, pINT;
    pIAT = (PIMAGE_THUNK_DATA)((char*)baseAddr + pImgDesc->FirstThunk);
    pINT = (PIMAGE_THUNK_DATA)((char*)baseAddr + pImgDesc->OriginalFirstThunk);


    logContent += getLogHeader() + "use32.dll\n";
    while (pIAT->u1.Function)
    {
        if (IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal))continue;
        PIMAGE_IMPORT_BY_NAME pImportName = (PIMAGE_IMPORT_BY_NAME)((char*)baseAddr + (DWORD)pINT->u1.AddressOfData);

        logContent += "    ";
        logContent += ((const char*)pImportName->Name);
        logContent += "\n";

        DWORD dwOldProtect;
        if (!_stricmp((const char*)pImportName->Name, "MessageBoxA"))
        {
            VirtualProtect(&pIAT->u1.Function, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect);
            pIAT->u1.Function = (ULONGLONG)Hook_MessageBoxA;
            VirtualProtect(&pIAT->u1.Function, sizeof(DWORD), dwOldProtect, &dwOldProtect);
        }
        else if (!_stricmp((const char*)pImportName->Name, "MessageBoxW"))
        {
            VirtualProtect(&pIAT->u1.Function, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect);
            pIAT->u1.Function = (ULONGLONG)Hook_MessageBoxW;
            VirtualProtect(&pIAT->u1.Function, sizeof(DWORD), dwOldProtect, &dwOldProtect);
        }
        else if (!_stricmp((const char*)pImportName->Name, "SetClipboardData"))
        {
            VirtualProtect(&pIAT->u1.Function, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect);
            pIAT->u1.Function = (ULONGLONG)Hook_SetClipboardData;
            VirtualProtect(&pIAT->u1.Function, sizeof(DWORD), dwOldProtect, &dwOldProtect);
        }
        else if (!_stricmp((const char*)pImportName->Name, "GetClipboardData"))
        {
            VirtualProtect(&pIAT->u1.Function, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect);
            pIAT->u1.Function = (ULONGLONG)Hook_GetClipboardData;
            VirtualProtect(&pIAT->u1.Function, sizeof(DWORD), dwOldProtect, &dwOldProtect);
        }
        pIAT++;
        pINT++;
    }
    logWrite(logContent);
    return 0;
}

int WINAPI Hook_MessageBoxA( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
    MESSAGEBOXA_FUNC MsgBoxAProc;
    if ((MsgBoxAProc = (MESSAGEBOXA_FUNC)GetProcAddress(GetModuleHandle(_T("user32")), "MessageBoxA")) == NULL) {
        //GetProcAddress Error
    }
    return MsgBoxAProc(hWnd, "hook", "hook", uType);
}
int WINAPI Hook_MessageBoxW( HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)
{
    MESSAGEBOXW_FUNC MsgBoxWProc;
    if ((MsgBoxWProc = (MESSAGEBOXW_FUNC)GetProcAddress(GetModuleHandle(_T("user32")), "MessageBoxW")) == NULL) {
        //GetProcAddress Error
    }
    return MsgBoxWProc(hWnd,L"hook" , L"hook", uType);
}

HANDLE WINAPI Hook_SetClipboardData(UINT uFormat, HANDLE hMem)
{
    SETCLIPBOARD_FUNC SetClipBoardFunc;
    if ((SetClipBoardFunc = (SETCLIPBOARD_FUNC)GetProcAddress(GetModuleHandle(_T("user32")), "SetClipboardData")) == NULL) {
        //GetProcAddress Error
    }
    if (uFormat == CF_TEXT || uFormat == CF_OEMTEXT) {
        std::string logContent = getLogHeader() + " setClipBoardData : ";
        LPCSTR lpStr = (LPSTR)GlobalLock(hMem);
        logContent.append(lpStr);
        logWrite(logContent);
    }

    HANDLE nResult = SetClipBoardFunc(uFormat, hMem);
    return nResult;
}

HANDLE WINAPI Hook_GetClipboardData(UINT uFormat)
{
    GETCLIPBOARD_FUNC GetClipBoardFunc;
    if ((GetClipBoardFunc = (GETCLIPBOARD_FUNC)GetProcAddress(GetModuleHandle(_T("user32")), "GetClipboardData")) == NULL) {
        //GetProcAddress Error
    }
    std::string logContent = getLogHeader() + " getClipBoardData : ";
    HANDLE resultForLog = GetClipBoardFunc(CF_TEXT);
    LPCSTR lpStr = (LPSTR)GlobalLock(resultForLog);
    logContent.append(lpStr);
    logWrite(logContent);

    HANDLE nResult = GetClipBoardFunc(uFormat);
    return nResult;
}

void logWrite(std::string content)
{
    FILE*  file;
    fopen_s(&file, "C:\\Users\\**********\\Desktop\\hook_report.txt", "a");
    content += "\n";
    fprintf(file, content.c_str());
    fclose(file);
}

std::string getLogHeader()
{
    return "プロセスID : " + std::to_string(_getpid()) + " ウィンドウ名: " + getCurrentName();
}
std::string getCurrentName()
{
    std::string ret = "";
    // プロセスハンドルをオープン
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, _getpid());
    if (NULL != hProcess) {

        // プロセス名の受け取り場所
        TCHAR waBaseName[MAX_PATH];

        // プロセスハンドルからプロセス名を取得します。
        ::GetModuleBaseName(hProcess, NULL, waBaseName, _countof(waBaseName));
        // プロセス名の表示
        ret = std::string(waBaseName);
        // プロセスハンドルのクローズ
        ::CloseHandle(hProcess);
    }
    return ret;
}

それから、これのヘッダファイルは以下になります。

dllmain.h

#pragma once

#include <windows.h>
#include <tchar.h>
#include <dbghelp.h>

#pragma comment(lib, "dbghelp.lib")

#define MODULE_DLL "user32.dll"

typedef int (WINAPI *MESSAGEBOXA_FUNC)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
typedef int (WINAPI *MESSAGEBOXW_FUNC)(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType);
typedef HANDLE (WINAPI *SETCLIPBOARD_FUNC)(UINT uFormat, HANDLE hMem);
typedef HANDLE (WINAPI *GETCLIPBOARD_FUNC)(UINT uFormat);

DWORD WINAPI apiHook(LPVOID pData);
int WINAPI Hook_MessageBoxA( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
int WINAPI Hook_MessageBoxW( HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType);
HANDLE WINAPI Hook_SetClipboardData(UINT uFormat, HANDLE hMem);
HANDLE WINAPI Hook_GetClipboardData(UINT uFormat);

各処理について、前回はメッセージボックス表示用の関数をフックさせていましたが、今回はコピー&ペーストをフックさせるということでsetClipboardDataとgetClipboardDataに対してIATフックしています。setClipboardDataとgetClipboardData関数のインターフェースは以下の公式のドキュメントを参照し、関数ポインタの型に反映させます。
https://msdn.microsoft.com/ja-jp/library/cc430086.aspx
https://msdn.microsoft.com/ja-jp/library/cc429794.aspx

今回は動作確認のためにuser32.dllのインポートアドレステーブル上にある関数名とコピペを実行したときの内容を出力するようにしています。 setClipboardDataをフックしたときに呼び出す処理としてHook_SetClipboardData関数を実装しています、ここではコピーしたデータのタイプがCF_TEXT, CF_OEMTEXTの時のみ内容をファイルに書き込むようにしています。 それからgetClipboardDataをフックしたときに呼び出す処理としてHook_GetClipboardData関数を実装していますが、ここではその時点のクリップボードのテキストデータをログファイルに書き込んでいるのですが実際は画像の貼り付けもあり得るので正しくはデータのフォーマットも気にする必要があります。

DLLのプロジェクトはこの2つのファイルを作成したらあとはビルドして大丈夫です。

次にEXE指定でDLLを読み込ませるプロジェクトを作成したいと思います。文字セットはマルチバイト文字セットを指定しています。

DLLを読み込ませるプロジェクトの作成

DLLを読み込ませる処理の実装は以下になります。

DllInject2.cpp

#include "stdafx.h"
#include "DllInject2.h"
#include <tchar.h>
#include <tlhelp32.h>
#include <string>

TCHAR dllPath[256] = "C:\\Users\\****\\source\\repos\\dll_inject\\Release\\dll_inject.dll";
int dllPathLen = (lstrlen(dllPath) + 1) * sizeof(TCHAR);
bool injectByProcessId(HWND hWnd, int targetProcId);

bool DllInject2HookStart(HWND hWnd, LPCSTR targetExe)
{
    int processIdCounter = 0;

    //search target process
    HANDLE hSnapShot;
    if ((hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) == INVALID_HANDLE_VALUE) {
        //CreateToolhelp32Snapshot Error
        MessageBox(NULL, _T("CreateToolhelp32Snapshot"), _T("Error"), MB_OK);
        return false;
    }

    PROCESSENTRY32 pEntry;
    pEntry.dwSize = sizeof(pEntry);
    BOOL result = Process32First(hSnapShot, &pEntry);
    while (result) {
        if (lstrcmp(_T(targetExe), pEntry.szExeFile) == 0) {
            injectByProcessId(hWnd, pEntry.th32ProcessID);
            processIdCounter++;
        }
        result = Process32Next(hSnapShot, &pEntry);
    }
    CloseHandle(hSnapShot);

    if (processIdCounter == 0) {
        MessageBox(NULL, _T("Process Not Found."), _T("Error"), MB_OK);
        return false;
    }
}


bool injectByProcessId(HWND hWnd, int targetProcId)
{

    //open target process
    HANDLE hTargetProc;
    if ((hTargetProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetProcId)) == NULL) {
        //OpenProcess Error
        MessageBox(NULL, _T("OpenProcess"), _T("Error"), MB_OK);
        return false;
    }

    //VirtualAlloc
    PWSTR memAddr;
    if ((memAddr = (PWSTR)VirtualAllocEx(hTargetProc, NULL, dllPathLen, MEM_COMMIT, PAGE_READWRITE)) == NULL) {
        //VirtualAllocEX Error
        MessageBox(NULL, _T("VirtualAllocEx"), _T("Error"), MB_OK);
        return false;
    }

    //WriteProcessMemory
    if (WriteProcessMemory(hTargetProc, memAddr, (PVOID)dllPath, dllPathLen, NULL) == 0) {
        //WriteProcessMemory Error
        MessageBox(NULL, _T("WriteProcessMemory"), _T("Error"), MB_OK);
        return false;
    }

    FARPROC LoadLibFunc;
    if ((LoadLibFunc = GetProcAddress(GetModuleHandle(_T("Kernel32")), "LoadLibraryA")) == NULL) {
        //GetProcAddress Error
        MessageBox(NULL, _T("GetProcAddress"), _T("Error"), MB_OK);
        return false;
    }

    //CreateRemoteThread
    HANDLE hThread;
    if ((hThread = CreateRemoteThread(hTargetProc, NULL, 0, (PTHREAD_START_ROUTINE)LoadLibFunc, memAddr, 0, NULL)) == NULL) {
        //CreateRemoteThread Error
        MessageBox(NULL, _T("CreateRemoteThread"), _T("Error"), MB_OK);
        return false;
    }

    std::string message = "success process_id:";
    message.append(std::to_string(targetProcId));
    MessageBox(hWnd, message.c_str(), "dll atach", MB_OK);
    return true;
}

それから、これのヘッダファイルは以下になります。

DllInject2.h

#pragma once
#include<Windows.h>

bool DllInject2HookStart(HWND hWnd, LPCSTR text);

DLLインジェクションはDllInject2HookStart関数で開始されており、自分自身のハンドルとEXE名を受け取っていまして、自分自身のハンドルはエラーメッセージ表示のために使い、EXE名はフックする対象のものを受け取っています。 DllInject2HookStart関数ではすべてのプロセスでループさせてEXE名が指定したものであればinjectByProcessId関数を実行するようにしています。injectByProcessId関数はプロセスID指定でDLLを読み込ませています。大まかな処理としては以下のようになっています。
- OpenProcess対象のプロセスのアクセス権を取得
- VirtualAllocExで対象のプロセスのメモリに対して書き込み領域を確保
- WriteProcessMemoryでDLLプロジェクトが生成したDLLを書き込んでいます。
- GetProcAddressでLoadLibraryを実行したときに最初に実行されるDllMain関数のアドレスを取得しています(WriteProcessMemoryを実行した場合は、DllMainが自動で開始されません)
- CreateRemoteThreadでLoadLibraryを実行しています、これがうまく行けばDLLインジェクションは成功です。

それから、このソフトのフォームですがEXE名を入力するテキストエリアとDLLインジェクションを開始させるボタンがあれば良いので以下のようにしています。

Form1.h

#pragma once
#include "DllInject2.h"
#include <msclr\marshal.h>

#include <random>
#include <string>
#include <process.h>  
#include<iostream>
#include<fstream>

#pragma comment(lib, "User32.lib")

namespace CppCLR_WinformsProjekt {

    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;
    using namespace msclr::interop;

    /// <summary>
    /// Zusammenfassung f・ Form1
    /// </summary>
    public ref class Form1 : public System::Windows::Forms::Form
    {
    public:
        Form1(void)
        {
            InitializeComponent();
            //
            //TODO: Konstruktorcode hier hinzuf・en.
            //
        }

    protected:
        /// <summary>
        /// Verwendete Ressourcen bereinigen.
        /// </summary>
        ~Form1()
        {
            if (components)
            {
                delete components;
            }
        }
    private: System::Windows::Forms::Button^  button1;
    private: System::Windows::Forms::Button^  button2;
    private: System::Windows::Forms::Label^  label1;
    private: System::Windows::Forms::Button^  button3;
    private: System::Windows::Forms::TextBox^  textBox1;


    protected:

    private:
        /// <summary>
        /// Erforderliche Designervariable.
        /// </summary>
        System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
        /// <summary>
        /// Erforderliche Methode f・ die Designerunterst・zung.
        /// Der Inhalt der Methode darf nicht mit dem Code-Editor ge舅dert werden.
        /// </summary>
        void InitializeComponent(void)
        {
            this->button1 = (gcnew System::Windows::Forms::Button());
            this->button2 = (gcnew System::Windows::Forms::Button());
            this->label1 = (gcnew System::Windows::Forms::Label());
            this->button3 = (gcnew System::Windows::Forms::Button());
            this->textBox1 = (gcnew System::Windows::Forms::TextBox());
            this->SuspendLayout();
            //
            // button1
            //
            this->button1->Location = System::Drawing::Point(33, 53);
            this->button1->Name = L"button1";
            this->button1->Size = System::Drawing::Size(101, 40);
            this->button1->TabIndex = 0;
            this->button1->Text = L"start";
            this->button1->UseVisualStyleBackColor = true;
            this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
            //
            // button2
            //
            this->button2->Location = System::Drawing::Point(152, 53);
            this->button2->Name = L"button2";
            this->button2->Size = System::Drawing::Size(101, 40);
            this->button2->TabIndex = 1;
            this->button2->Text = L"stop";
            this->button2->UseVisualStyleBackColor = true;
            this->button2->Click += gcnew System::EventHandler(this, &Form1::button2_Click);
            //
            // label1
            //
            this->label1->AutoSize = true;
            this->label1->Font = (gcnew System::Drawing::Font(L"MS UI Gothic", 22));
            this->label1->Location = System::Drawing::Point(37, 9);
            this->label1->Name = L"label1";
            this->label1->Size = System::Drawing::Size(156, 30);
            this->label1->TabIndex = 2;
            this->label1->Text = L"HOOK OFF";
            this->label1->Click += gcnew System::EventHandler(this, &Form1::label1_Click);
            //
            // button3
            //
            this->button3->Location = System::Drawing::Point(33, 100);
            this->button3->Name = L"button3";
            this->button3->Size = System::Drawing::Size(220, 48);
            this->button3->TabIndex = 3;
            this->button3->Text = L"click";
            this->button3->UseVisualStyleBackColor = true;
            this->button3->Click += gcnew System::EventHandler(this, &Form1::button3_Click_1);
            //
            // textBox1
            //
            this->textBox1->Location = System::Drawing::Point(39, 161);
            this->textBox1->Name = L"textBox1";
            this->textBox1->Size = System::Drawing::Size(213, 19);
            this->textBox1->TabIndex = 4;
            this->textBox1->TextChanged += gcnew System::EventHandler(this, &Form1::textBox1_TextChanged);
            //
            // Form1
            //
            this->AutoScaleDimensions = System::Drawing::SizeF(6, 12);
            this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
            this->ClientSize = System::Drawing::Size(283, 189);
            this->Controls->Add(this->textBox1);
            this->Controls->Add(this->button3);
            this->Controls->Add(this->label1);
            this->Controls->Add(this->button2);
            this->Controls->Add(this->button1);
            this->Name = L"Form1";
            this->Text = L"Form1";
            this->ResumeLayout(false);
            this->PerformLayout();

        }
#pragma endregion
    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
        System::String^ text = static_cast<System::String^>(this->textBox1->Text);
        marshal_context context;
        LPCTSTR lpcstr = context.marshal_as<const TCHAR*>(text);

        HWND hWnd = static_cast<HWND>(this->Handle.ToPointer());
        if( DllInject2HookStart(hWnd, lpcstr)) {
            this->label1->Text = L"HOOK ON";
        }
    }
    private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) {
        HANDLE resultForLog = GetClipboardData(CF_TEXT);
        //HWND hWnd = static_cast<HWND>(this->Handle.ToPointer());
        //if (DllInjectHookEnd(hWnd)) {
        //  this->label1->Text = L"HOOK OFF";
        //}
    }
    private: System::Void richTextBox1_TextChanged(System::Object^  sender, System::EventArgs^  e) {
    }
private: System::Void label1_Click(System::Object^  sender, System::EventArgs^  e) {
}
private: System::Void button3_Click_1(System::Object^  sender, System::EventArgs^  e) {
    MessageBoxW(NULL, L"not hook", L"not hook", MB_OK);
    //MessageBox::Show("not hook",
    //  "not hook", MessageBoxButtons::OKCancel,
    //  MessageBoxIcon::Asterisk);
}
private: System::Void textBox1_TextChanged(System::Object^  sender, System::EventArgs^  e) {
}
};
}

これで動かすと以下のように、フックしたソフトのiatテーブルに存在するuser32.dll内の関数とコピペの内容を確認することができます。
f:id:steavevaivai:20180727221834g:plain

また、今回のDLLインジェクションをメモ帳など64bitのソフトウエアに実行してみると失敗してしまいますが、64bitようにビルドし直せばDLLインジェクションには成功します。
- DLL生成プロジェクトにてプロジェクトのプロパティ -> 構成マネージャ の画面でアクティブソリューションプラットフォームにx64を指定して、ソリューションをビルドし直す
- DLLを読み込ませるプロジェクトでは読み込ませるDLLとして↑で生成したものを指定する
- DLLを読み込ませるプロジェクトでも同様にアクティブソリューションプラットフォームにx64を指定して、ソリューションをビルドし直す

これで64bitのソフトでもDLLインジェクションができるようになります。試しにメモ帳で実行したらDLLインジェクションは成功するのですがコピペの検出には失敗しています。ログを確認したところどうやらインポートアドレステーブル上にuser32.dllのsetClipBoardData, getClipboardDataの関数が存在しないためiatフックは行えていないことが確認できます。このような場合はシステムのプロセス自体にDLLインジェクションを実行すれば良いのでしょうか。

プロセスID : 18280 ウィンドウ名: notepad.exeuse32.dll
    SetDlgItemTextW
    GetDlgItemTextW
    EndDialog
    SendDlgItemMessageW
    GetDlgCtrlID
    WinHelpW
    GetCursorPos
    ScreenToClient
    ChildWindowFromPoint
    GetParent
    GetWindowPlacement
    CharUpperW
    GetSystemMenu
    LoadAcceleratorsW
    SetWindowLongW
    RegisterWindowMessageW
    LoadCursorW
    CreateWindowExW
    SetWindowPlacement
    LoadImageW
    RegisterClassExW
    SetScrollPos
    InvalidateRect
    UpdateWindow
    GetWindowTextLengthW
    GetWindowLongW
    CloseClipboard
    GetWindowTextW
    EnableWindow
    CreateDialogParamW
    DrawTextExW
    GetSystemMetrics
    SetWindowPos
    GetAncestor
    FindWindowW
    SetForegroundWindow
    GetMenuState
    SetWindowTextW
    UnhookWinEvent
    DispatchMessageW
    TranslateMessage
    TranslateAcceleratorW
    IsDialogMessageW
    GetMessageW
    SetWinEventHook
    CharNextW
    GetKeyboardLayout
    GetForegroundWindow
    MessageBeep
    DestroyWindow
    PostQuitMessage
    IsIconic
    DefWindowProcW
    IsClipboardFormatAvailable
    PeekMessageW
    OpenClipboard
    LoadStringW
    SetActiveWindow
    SetCursor
    ReleaseDC
    GetDC
    ShowWindow
    GetClientRect
    MessageBoxW
    GetFocus
    LoadIconW
    DialogBoxParamW
    SetFocus
    GetSubMenu
    EnableMenuItem
    GetMenu
    PostMessageW
    MoveWindow
    SendMessageW
    CheckMenuItem