rundll32 が関数に渡す引数は何なのか
概要
Windows 付属の rundll32.exe コマンドを利用して、指定した DLL 内の関数を呼び出すことができます。このとき rundll32 が関数に渡す引数について、やや詳しく説明します。
動作確認環境
- Windows 10 Home 21H1, 64bit
(ただし、今回は 32bit の C:\Windows\SysWOW64\rundll32.exe モジュールについて扱います) - Visual Studio Community 2019
rundll32 の使い方
rundll32.exe の使い方は次の通りです。オプションは省略可能です。
rundll32 DLL名,関数名 [オプション]
たとえば次のように入力すると、MyDll.dll がエクスポートしている MyFunc 関数がオプション Hello で呼び出されます。
rundll32 MyDll.dll,MyFunc Hello
コマンドラインを見ると MyFunc 関数が引数 Hello で呼び出される、言い換えると「MyFunc(“Hello”);」が実行されるように見えますが、違います。
引数 1. ウィンドウハンドル
関数の第 1 引数には「rundll32 が内部で生成したウィンドウのハンドル」が渡されます。ウィンドウハンドルですので固定値ではなく、たとえば 0x001805EA になったり 0x009E0558 になったりします。
このウィンドウは画面には表示されませんが、次のようにすると見ることができます。
- 第 1 引数で指定されたウィンドウを表示するプログラムを、DLL のエクスポート関数として書きます。
// MyDll.c
#include <windows.h>
int __stdcall MyFunc(HWND hwnd, HINSTANCE hinst, char *pcCmdLine, int nCmdShow)
{
MoveWindow(hwnd, 0, 0, 300, 200, TRUE);
ShowWindow(hwnd, SW_SHOW);
MessageBox(0, "test", "yaya-Low-Layer Lab.", MB_OK);
return 0;
}
// MyDll.def
EXPORTS
MyFunc
- コンパイルして DLL を作ります。
cl /LD MyDll.c MyDll.def user32.lib
- rundll32 を利用して、この関数を呼び出します。
rundll32 MyDll.dll,MyFunc
- ほとんどの人が見たことのないであろう、rundll32 が内部で生成したウィンドウが表示されました。
引数 2. インスタンスハンドル
関数の第 2 引数には「rundll32 のインスタンスハンドル」、言い換えると「rundll32.exe モジュールがロードされたアドレス」が渡されます。
モジュールのロードアドレスは OS の ASLR 機能によりランダム化されるので、たとえば 0x00940000 になったり 0x00C20000 になったりします。
引数 3. オプションへのポインタ
関数の第 3 引数には「rundll32 の実行時に指定したオプションへのポインタ」が渡されます。
オプションとして次のように「Hello」を指定すると、文字列 “Hello” へのポインタが渡されます。
rundll32 MyDll.dll,MyFunc Hello
数字「123」を指定しても、数として解釈されることはなく、文字列 “123” へのポインタが渡されます。
rundll32 MyDll.dll,MyFunc 123
空白を含むオプション「Hello 123」を指定しても、空白で分離されることはなく、単に文字列 “Hello 123” へのポインタが渡されます。
undll32 MyDll.dll,MyFunc Hello 123
オプションを指定しなかった場合は、長さ 0 の文字列へのポインタが渡されます。NULL ポインタが渡されるわけではありません。
rundll32 MyDll.dll,MyFunc
これらのオプションは rundll32 が内部で確保したヒープメモリに格納され、アドレスは不定です。
引数 4. ウィンドウの表示状態
関数の第 4 引数には、「ウィンドウの表示状態」が渡されます。
rundll32 を普通に実行すると、10 (SW_SHOWDEFAULT) が渡されます。
rundll32 MyDll.dll,MyFunc
次のように start /min を指定して実行すると、7 (SW_SHOWMINNOACTIVE) が渡されます。
start /min c:\windows\syswow64\rundll32 MyDll.dll,MyFunc
(※ 「start /min rundll32 MyDll.dll,MyFunc」とすると、64bit の rundll32.exe 経由で 32bit の rundll32.exe が実行される関係で /min の指定が無視されるようです)
次のように start /max を指定して実行すると、3 (SW_SHOWMAXIMIZED) が渡されます。
start /max c:\windows\syswow64\rundll32 MyDll.dll,MyFunc
おわりに
rundll32 が関数に渡す引数をまとめると、次のようになります。
- 第 1 引数 : ウィンドウハンドル(rundll32 が内部で生成したウィンドウのハンドル)
- 第 2 引数 : インスタンスハンドル(rundll32.exe モジュールがロードされたアドレス)
- 第 3 引数 : オプションへのポインタ(rundll32 のオプション文字列へのポインタ)
- 第 4 引数 : ウィンドウの表示状態(通常は 10)
次のコマンドを実行すると、
rundll32 MyDll.dll,MyFunc Hello
「MyFunc(“Hello”);」ではなく、「MyFunc(<ウィンドウハンドル>, <インスタンスハンドル>, “Hello”, <ウィンドウの表示状態>);」が実行されることになります。
次のコマンドを実行しても、
rundll32 kernel32.dll,Beep 1500 500
「Beep(1500, 500);」が実行されて 1500Hz の音が 500 ミリ秒間鳴ることはありません。「Beep(<ウィンドウハンドル>, <インスタンスハンドル>);」が実行され、不定の周波数の音が不定の時間鳴るだけです。