多くの Win32 API は、特定のレイアウトを持つ構造体へのポインターを取ります。これらのうち、大きなサブセットは、呼び出される前に最初の DWORD を構造体のサイズに初期化する必要がある一般的なパターンに従います。場合によっては、構造体を書き込むメモリ ブロックを渡す必要があります。メモリ ブロックは、最初に NULL ポインターを使用して同じ API を呼び出し、戻り値を読み取って正しい値を検出することによって決定されるサイズでなければなりません。サイズ。一部の API は、構造体を割り当て、それへのポインターを返すため、2 回目の呼び出しでポインターの割り当てを解除する必要があります。
単純な文字列表現から変換可能な個々の引数を使用して、ワンショットで便利に呼び出すことができる API のセットが非常に小さい場合でも、それほど驚くことではありません。
この考えを一般的に適用できるようにするには、かなり極端に行かなければなりません。
typedef void DynamicFunction(size_t argumentCount, const wchar_t *arguments[],
size_t maxReturnValueSize, wchar_t *returnValue);
DynamicFunction *GenerateDynamicFunction(const wchar_t *code);
コードの簡単なスニペットを GenerateDynamicFunction に渡すと、そのコードが標準的なボイラープレートでラップされ、C コンパイラ/リンカーが呼び出されて、関数を含む DLL が作成されます (利用可能な無料のオプションがかなりあります)。次に、LoadLibrary
その DLL を使用GetProcAddress
して関数を検索し、それを返します。これにはコストがかかりますが、一度実行すると、結果の DynamicFunctionPtr をキャッシュして繰り返し使用できます。これを動的に行うには、ポインターをハッシュテーブルに保持し、コード スニペット自体をキーにします。
定型文は次のようになります。
#include <windows.h>
// and anything else that might be handy
void DynamicFunctionWrapper(size_t argumentCount, const wchar_t *arguments[],
size_t maxReturnValueSize, wchar_t *returnValue)
{
// --- insert code snipped here
}
したがって、このシステムの使用例は次のようになります。
DynamicFunction *getUserName = GenerateDynamicFunction(
"GetUserNameW(returnValue, (LPDWORD)(&maxReturnValueSize))");
wchar_t userName[100];
getUserName(0, NULL, sizeof(userName) / sizeof(wchar_t), userName);
引数の数を受け入れるようにすることでこれを強化できるためGenerateDynamicFunction
、ラッパーの開始時に正しい数の引数が渡されたことを確認できます。そこにハッシュテーブルを配置して、遭遇したコードニペットごとに関数をキャッシュすると、元の例に近づくことができます。Call 関数は、API 名だけでなくコード スニペットを使用しますが、それ以外は同じです。ハッシュテーブルでコード スニペットを検索し、存在しない場合は GenerateDynamicFunction を呼び出し、次回のために結果をハッシュ テーブルに格納します。次に、関数の呼び出しを実行します。使用例:
wchar_t userName[100];
Call("GetUserNameW(returnValue, (LPDWORD)(&maxReturnValueSize))",
0, NULL, sizeof(userName) / sizeof(wchar_t), userName);
もちろん、ある種の一般的なセキュリティ ホールを開くことが目的でない限り、これを行ってもあまり意味がありません。たとえば、Web サービスとして公開Call
します。元のアイデアにはセキュリティへの影響が存在しますが、提案した元のアプローチがそれほど効果的ではないという理由だけで、それほど明白ではありません。一般的に強力にすればするほど、セキュリティ上の問題が大きくなります。
コメントに基づく更新:
.NET フレームワークには p/invoke と呼ばれる機能があり、これはまさに問題を解決するために存在します。したがって、何かを学ぶためのプロジェクトとしてこれを行っている場合は、 p/invoke を見て、それがどれほど複雑かを知ることができます。スクリプトをリアルタイムで解釈したり、スクリプトを独自のバイトコードにコンパイルしたりする代わりに、スクリプト言語で .NET フレームワークをターゲットにすることができます。IL にコンパイルすることができます。または、.NET で既に利用可能な多くのスクリプト言語から、既存のスクリプト言語をホストすることもできます。