仲介DLL(Proxy DLL)ソースコード出力機能について
概要
下記「API関数呼び出し」の仕組みについては、当ヘルプの「基礎用語解説」内「逆アセンブルコードリスト」を参照願います。この解説は、当ソフトウェア『うさみみハリケーン』同梱のPEダンパー兼PEエディタ 「UMPE」に実装した、「仲介DLL(Proxy DLL)ソースコード出力機能」の活用補助を主目的として執筆しました。仲介DLLとは、EXEファイルといった実行ファイルが、API関数など特定DLLが提供する関数を呼び出す処理を、変更や監視などができるようにするためのDLLです。これは「プロキシーDLL」や「ラッパーDLL」と表記されることもあります。一般的な使用例では、EXEファイルからシステムDLL提供のAPI関数を呼び出す処理を、EXEファイルから仲介DLLを経由して呼び出すように変更します。この際、仲介DLLでは任意の処理を追加した上で本来のAPI関数を呼び出します。このようなAPI関数呼び出し処理への介入と操作は、「APIフック」と呼ばれています。『うさみみハリケーン』には、プロセスメモリ上で動的にAPI関数の呼び出し処理等を変更可能な「パラサイトルーチン作成」機能を実装していますが、仲介DLLを用いる方法はパラサイトルーチン作成と同種のアプローチといえます。
なお、『うさみみハリケーン』には、仲介DLLや動的なAPIフックとは全く異なる仕組みを用いて、プロセス作成や、スレッド作成、DLLインジェクションを含むDLL読み込み、メモリ確保、ファイル操作、レジストリ操作、ネットワーク送受信などの実行情報を取得する、プロセスモニターを同梱しています。必要に応じて、当機能と使い分けてください。
仲介DLLはプログラム解析において、APIフックの一手法として古くから用いられてきた手法です。そのため、日本では以下の代表的なものを含む、優れた仲介DLLソースコード出力ツールが複数公開されてきました。
ちよクロ氏製作「listexp.exe / listexp2.exe」
saw@SFB7氏製作「ラッパーテンプレートメーカー」
愛甲健二氏製作「仲介DLL生成補助ツール」および作者不明の派生版
また、海外の方が製作された仲介DLL(Proxy DLL)ソースコード出力ツールも、古くから少なからず公開されており、プログラム解析等に活用されてきました。
APIフックの他のアプローチに関しては、下記の解説が考察の一助になると考えられます。
「ホットパッチ型APIフックがうまくいきません」
「IAT書き換え型APIフックの注意点を知りたい」
「DLLのロードとアンロード」(うさみみハリケーンでメニュー「デバッグ」から「DLLのロードとアンロード」)
基本操作と注意点
●基本操作 手順出力対象仲介DLLが32ビットか64ビットかに応じて、32ビット版の「UMPE.exe」あるいは64ビット版の「UMPE64.exe」を起動します。
仲介DLLのソースコードは元DLLと同じフォルダに出力します。そのため、あらかじめ「C:\APP\ProxyDLL」といったコンパイル専用フォルダを作成し、仲介DLLの元DLLをコピーしておくことをお勧めします。この場合、出力ソースコードCPPファイル内で元DLLのパスを修正(下記にソースコード修正例あり)することになるものの、使用ファイルを単一フォルダに集約化することができます。なお、Windowsのセキュリティ上の制約を受けないよう、コンパイル専用フォルダは「Program Files」、「Program Files (x86)」、「Windows」以下には作らないでください。もし、元DLLがこれらのフォルダ内にある場合は、そのフォルダ外にコンパイル専用フォルダを作成して元DLLをコピーした方が安全です。
コンパイル専用フォルダに仲介DLLの元DLLをコピーする際、仲介DLL適用対象の実行ファイルが起動中であれば、「UMPE」でコピー処理を簡易化できます。「UMPE」の右上プロセスリストでそのプロセスを選択し、さらに右下モジュールリストで仲介DLLの元DLLを選択してから、「エクスプローラのメニュー」ボタンでポップアップメニューを表示して「コピー」を選択します。さらに作成済みコンパイル専用フォルダ内で、エクスプローラの右クリックからポップアップメニュー「貼り付け」で、同フォルダ内に元DLLをコピーします。なお、Windows 8や10といった新しいWindows OSの64ビット版では、「C:\Windows\syswow64\USER32.dll」など32ビット版システムDLLのパスが、各種API関数による取得時に「C:\Windows\system32\USER32.dll」という実際とは異なるパスに変換されますが、「UMPE」の32ビット版では、この変換を元に戻したモジュールリストを表示します。
仲介DLLの元となるDLLを指定します。そのまま「PEエディタを起動して編集」ボタンを押し、表示された「PEファイル」の画面で、仲介DLLの元DLLをオープンすることで指定します。ドラッグ・アンド・ドロップを用いた元DLLのオープンも可能です。
仲介DLL適用対象の実行ファイルが起動中かつ、コピーしていない元DLLと同じフォルダ内に仲介DLLソースコードを出力してよいのであれば、上記の起動中プロセスのモジュールリストから元DLLを選択後、ラジオボタン[モジュール(読取専用)]を選択し「PEエディタを起動して編集」ボタンを押します。
PEエディタの画面が表示されているので、左側ツリービューでカテゴリ「エクスポート」を選択し、表示される画面でエクスポート関数一覧内に操作対象の関数が存在することを確認します。
同じく左側ツリービューでカテゴリ「補助ツール」を選択し、表示される画面で「仲介DLL(Proxy DLL)ソースコード出力」欄の「ソースファイル出力実行」ボタンを押します。これで指定された元DLLと同じフォルダにソースコードのファイル群が出力されます。さらに、「プロジェクトファイル出力実行」ボタンで、Visual C++ でコンパイルするためのslnファイルとvcxprojファイルを出力します。
●基本的な注意点
当機能は、パッカー適用などの操作が加えられ、内部構成が異常となっているDLLに使用することはできません。「UMPE」が判別して表示するパッカー・コンパイラの情報に注意してください。なお、同梱ファイルアナライザ「青い空を見上げればいつもそこに白い猫」は、ファイルアナライザ『Detect It Easy』の各種ファイル形式/パッカー/コンパイラ判別エンジンに対応していますので、必要に応じて併用されることをお勧めします。
色々な用途に対応するため、実体のない関数すなわち、エントリーポイント(RVA)がゼロとなっている関数も出力ソースコード中で列挙しています。このような関数は、出力したCPPファイル内の関数アドレス取得箇所にコメント「//No EntryPoint」を付記しています。なお、「UMPE」のエクスポート関数一覧表示機能では、このような実体がなくかつ名前もない、序数のみの関数は表示しません。
DLLのエクスポート関数が別の関数を実体とする「関数フォワーダ」の場合は、CPPファイル内の関数アドレス取得箇所に、コメント「//Forwarder: 」で実体である関数の名前と提供DLL名を付記しています。
仲介DLL適用対象の実行ファイルに設定された各種セキュリティ関連設定(CFG:Control Flow Guardなど)により、仲介DLLが正常に機能しないケースが想定されます。CFGやプロセスに設定された各種ポリシーの状況は、うさみみハリケーンでメニュー「ファイル」→「プロセスの各種情報を表示」の「実行状況」カテゴリで確認可能です。同様に、Windows 10で2017年10月に実装された、UWPアプリのPCゲーム用チート行為検出・抑制機能「TruePlay」の適用状況は、「アクセストークン」カテゴリで「Capability」として確認可能と見られますが、当該Capabilityの名称「gameMonitor」が表示されない可能性もあります。なお、「TruePlay」でのチート行為検出時には、Microsoft Defender(Windows Defender)イベントを加工したものがクラウドサービスにアップロードされます。
使用しているセキュリティソフトが原因で、仲介DLLの動作不具合を招く可能性もあります。
Windows 10では、一部の付属DLLにおいて、エクスポート関数の名前がマングリング(名前修飾)され380文字という異常に長いケースも見られます。このような特殊なケースにおける、当機能での適切なソースコードの出力は確認済みですが、仲介DLLのコンパイルや動作確認までは行っていません。
当機能で出力するソースコードは、32ビット版と64ビット版で内容が異なります。32ビット版のソースコードを64ビット版仲介DLLの製作に流用することはできません。逆に、64ビット版のソースコードを32ビット版仲介DLLの製作に流用することもできません。
コンパイルと仲介DLL適用
当機能で出力する仲介DLLのソースコードは、統合開発環境「Visual C++」の、2010以降のバージョンでのコンパイルを想定しています。「Visual C++」は、Microsoft社が無償で提供している統合開発環境「Visual Studio Community」(当ソフトウェア作者Webサイトから入手先にリンク)に含まれています。コンパイルすなわち仲介DLL出力の動作確認は、「Visual C++ 2017」と「Visual C++ 2010」で行いました。実際には、Visual C++ に含まれる2つ(PEファイル解析手法によっては3つ)のファイルを同梱すれば、Visual C++ が無くともDLLの出力が可能です。しかし、これらのファイルの再配布は著作権の侵害になると見られるため、当仲介DLLソースコード出力ツールとしては同梱を見送りました。
Visual C++ は、うさみみハリケーンのプラグイン製作にも活用できます。そのため、作者WebサイトのTools欄で配布している、プラグインサンプルのソースコード集をベースに、基本的なプラグインを試作されることをお勧めします。この試作の経験は、C++言語やプログラム解析を学ぶ上で参考になります。
●Visual C++ 2017 インストール時の注意事項
Visual Studio Community のインストール時に、Visual C++ 2017 を併せてインストールする際には、初期設定に以下の項目を追加で選択します。
「ワークロード」画面で「C++によるデスクトップ開発」
「個別のコンポーネント」画面で「MFCとATLのサポート (x86とx64)」
「個別のコンポーネント」画面で「Windows 8.1 SDK」(Windows 10のSDKがあれば必須ではない)
「個別のコンポーネント」画面で「Windows XP Support for C++」
「個別のコンポーネント」画面で「Windows Universal CRT SDK」
「個別のコンポーネント」画面で「標準ライブラリモジュール」
●[自動設定] 32ビット/64ビットDLL共通 プロジェクトの設定手順
当機能では、コンパイルに必要な設定を格納した、slnファイルとvcxprojファイルを出力可能です。これにより、コンパイルのための煩雑な設定を行う必要はありません。下記「手動設定」は読み飛ばしてください。もし、設定を自分でカスタマイズしたいならば、以下の「手動設定」を参考にしてください。
Visual C++を起動します。
メニューの「ファイル」下の「開く」から「プロジェクト/ソリューション」で、当機能が出力したvcxprojファイルを選択し、プロジェクトを開きます。
当機能が出力したvcxprojファイルは、Visual C++ 2010 をベースとしたプロジェクトの設定を格納しています。そのため、Visual C++ の他のバージョン使用時には、プラットフォームツールセットのバージョンとSDKのバージョンを、開発環境にインストール済のものに再設定する必要があります。Visual C++のバージョンによっては、プロジェクトを開くと「ソリューションの再ターゲット」を促す画面が表示されますが、ここではSDKの方の設定が行われません。後述するように、コンパイル時に再度メニューから「ソリューションの再ターゲット」を行ってください。使用する特定バージョンVisual C++で標準とされるSDKのバージョンと、インストールされているSDKのバージョンが一致しないケースが想定されるため、プラットフォームツールセットおよびSDKはユーザーの方に指定してもらうようにしました。
プロジェクトの初期設定では開発用のデバッグモードになっています。特にデバッグモードが必要でなければ、そのまま公開用のリリースモードに変更します。メニュー「ビルド」の「構成マネージャ」で、「アクティブソリューション構成」を「Release」に変更です。また、64ビットDLLの出力ならば、「アクティブソリューション プラットフォーム」に「x64」を指定します。
●[手動設定] 32ビット/64ビットDLL共通 プロジェクトの設定手順(上記自動設定時は不要)
Visual C++を起動します。
メニューの「ファイル」下の「新規作成」から「既存のコードからプロジェクトを作成」でウィザードを開きます。
ウィザードの「プロジェクトの場所とソースファイルの指定」画面で出力ファイル群を格納した専用フォルダやプロジェクト名(「user32」など)を指定し、さらに 「プロジェクト設定の指定」画面ではプロジェクトの種類に「ダイナミック リンク ライブラリ(DLL)」を指定して、「完了」です。
メニュー「ビルド」の「構成マネージャ」で、「アクティブソリューション構成」を「Release」に変更します。
64ビット版DLLを出力する場合は、この「構成マネージャ」で、「アクティブソリューション プラットフォーム」に「x64」を新規作成して指定しておきます。
メニュー「プロジェクト」下の「プロパティ」を開き、「構成プロパティ」直下にある下層カテゴリ「全般」で、項目「MFCの使用」に「標準Windowsライブラリを使用する」を指定し、項目「文字セット」にはマルチバイト文字セットを指定します。
同上「C/C++」の下層カテゴリ「コード生成」で、項目「ランタイムライブラリ」には「マルチスレッド(/MT)」を選択します。
同上「リンカー」の下層カテゴリ「入力」で、項目「モジュール定義ファイル」に出力されたDEFファイル名を指定します。
●[手動設定] 64ビット版DLLの追加手順(上記自動設定時は不要)
64ビット版の仲介DLLを出力するならば、上記手順に加えて、コンパイル設定および、プロジェクト内.asmファイルのコンパイル設定を行う必要があります。
クラスビューでクラスを選択して右クリックから「ビルドのカスタマイズ」を開き、MASMにチェックして「OK」です。
ソリューションエクスプローラーから「Source Files」内のASMファイルを右クリックして「プロパティ」を開き、「項目の種類」で「Microsoft Macro Assembler」を指定して「OK」です。
●設定終了後のソースコード修正・コンパイル手順
CPPファイル内の、LoadLibrary関数でロードするDLLのパスが正しいか確認します。特に64ビット版Windows環境では、システムDLLの指定先が下記のようになるため注意が必要です。なお、WindowsのシステムDLLが格納されるシステムフォルダは、GetSystemDirectory関数やGetSystemWow64Directory関数あるいはSHGetFolderPath関数で取得可能です(下記ソースコード修正例参照)。ここでのパスの指定では、パス内「\」を「\\」と記述することに注意してください。
32ビットDLLでの指定例:C:\\Windows\\syswow64\\USER32.dll
64ビットDLLでの指定例:C:\\Windows\\system32\\USER32.dll
下記ソースコード修正例のMessageBoxA/MessageBoxW関数の書き換え例を参考に、特定API関数の呼び出し処理に任意の処理を追加して、特定API関数の挙動を変更します。
プロジェクトをマルチバイト(ANSI)文字列の使用に設定しているので、Unicode(Wide)文字列を使用するAPI関数が対象ならば引数の定義「LPCTSTR → LPCWSTR」等の書き換えが必要です(下記ソースコード修正例参照)。
必要に応じてOutputDebugString関数で情報文字列を出力し、うさみみハリケーンのメニュー「デバッグ」から「デバッグ文字列出力を監視」で、文字列出力をモニターしログ化します。このデバッグ文字列出力監視機能は、デバッガとしてのアタッチは行いません。
メニュー「ビルド」下の「ソリューションのリビルド」でコンパイルを実行し、DLLファイルを出力します。もしここでエラーが生じたならば、プラットフォームツールセットあるいはSDKを、開発環境にインストール済みのものに変更してください。この変更は、メニューの「プロジェクト」から「ソリューションの再ターゲット」で行います。基本的に、この設定変更操作は、プラットフォームツールセット分とSDK分の2回必要です。
「UMPE」で元DLLのエクスポート関数一覧を確認し、関数名に「??2@YAPAXI@Z」といった「@」が含まれているものがあるならば、DEFファイルの仕様上の制約から関数名内「@」を「*」に置き換えているため、出力DLLファイル内のエクスポート関数名にある「*」を「@」に書き換えます。エクスポート関数名文字列のオフセットは、「UMPE」のPEエディタからカテゴリ「エクスポート」画面で確認可能です。
●仲介DLLの適用手順
出来上がったDLLの名前の1~3文字を変更します(例:abcd.dll -> zbcd.dll)。プロジェクトのプロパティで、「構成プロパティ」の「全般」から出力名「ターゲット名」を変更しておく方法もあります。「kernel32」を「_ernel32」や「lernel32」にといった既知の名前変更パターンは、マルウェアとみなされる可能性からお勧めしません。
対象EXEファイルのバックアップを作成してから、同EXEファイル内の、インポート関数を提供するDLL名文字列すなわち、上記例でいえば「abcd.dll」を「zbcd.dll」に書き換えます。対象EXEファイル内の、インポート関数を提供するDLL名文字列のオフセットは、「UMPE」のPEエディタからカテゴリ「インポート」画面で確認可能です。この書き換えは、「UMPE」が実装しているヘキサエディタ(バイナリエディタ)を使えば簡単に行うことができます。
必要に応じて、上記「UMPE」の「ヘッダ」画面でPEヘッダ内のチェックサム(画面右下「CheckSum」)を修正しておきます。
対象EXEファイルと同じフォルダに出来上がった仲介DLLを配置します。
対象EXEファイルを起動し動作を確認します。
ちなみに、仲介DLLの元DLLが、kernel32.dllなどOS付属のシステムDLLの場合、システムDLLの多くは既知のDLLとしてレジストリに登録されていることから、EXEファイルと同じフォルダに元DLLと同名のDLLがあったとしても、通常システムフォルダにあるDLLが優先的にロードされます。
仲介DLL使用の注意点と使用例
●仲介DLL使用の注意点基本的な用途としては、私的利用における特定ソフトウェアの利便性向上、あるいはプログラム解析の学習などが挙げられます。
仲介DLLの活用は、プログラム解析の有用性と可能性を示す素晴らしいアプローチです。しかし、私的利用の枠を超えた、特定ソフト用仲介DLLの製作方法および使用方法を公開する場合は、必ずしも関わる者全員に益するとは限りません。そこで、起こりうるトラブルを回避するために、できる限り事前に仲介DLL適用対象ソフト作者へ意向を確認することや、下記注意事項の明記といった、良識ある配慮が望まれます。
例えば、特定ソフトへの仲介DLL使用の目的が、新しいWindows OSへの対応や機能追加ならば、作者が望まないケースもあります。また、開発が終了し作者による対応が見込めないように見えても、開発終了か否かの判断は、作者に確認して行うのが望ましく、自分の認識だけで行うべきではありません。特に個人製作のソフトウェアでは、直近のバージョンアップから3年~12年経って普通にバージョンアップするケースもあるためです。
仲介DLL適用が原因で不具合が生じた際に、適用対象ソフトの作者や適用対象ゲーム製作元へ苦情メールを送る方もいます。そのため、特定ソフト用仲介DLLの製作方法等の公開時には、不具合発生の原因は仲介DLLであって、適用対象ソフトやゲーム等の作者には一切責任がないことを明記してください。
Windowsのセキュリティ関連機能や使用セキュリティソフト等が原因といった、実行環境に依存する対処不能の不具合が起こる可能性もあるため、仲介DLLの製作と適用は必ず自己責任で行うよう明記されることをお勧めします。
なお、実情としては、企業がリリースした開発終了が明確な特定ソフトやゲームへの、公益や利便性向上を目的とする仲介DLL適用方法の公開ならば、開発企業へ無断であってもトラブルに発展するケースは少ないといえます。ただし、仲介DLL適用目的が脆弱性への対処の場合では、脆弱性の詳細を開発企業に無断で公開しないでください。また、法的に問題がある、技術的制限手段の回避を目的とした仲介DLLの製作・適用方法も公開しないでください。
オンラインゲームにおける描画処理等操作のための、仲介DLL製作・適用方法の公開は行わない方が良いでしょう。これは、いずれ当該仲介DLLがゲームに対する改ざん行為として検知され、アカウントを停止または抹消される可能性が高いためです。かつてオンラインゲームにおいて仲介DLLを用いたチート行為が広まり問題となったため、現在では、仲介DLLの検出・対処は基本的なチート対策のひとつとされています。また、オンラインゲームによっては、チート行為に使用したか否かを問わず、プログラム解析ツールの実行ファイルがパソコンに存在するだけで、アカウントの抹消を行います。
●特定ソフトへの仲介DLL使用例
1.特定ソフトのネットワーク送受信関連処理のログ取得
2.時間関連API関数等の処理を変更して特定ソフトの対応動作を確認
3.特定API関数の挙動を変更して古いソフトを新しいWindows OSへ対応させる
4.新しい特定API関数のダミー関数(代替処理)を実装して新しいソフトを古いWindows OS上で動作可能にする
5.特定インポート関数の処理に新しい処理を追加して古いソフトに機能追加あるいは機能改良
6.特定API関数の挙動を変更して古いソフトの脆弱性に対処
7.特定API関数の処理を別途用意したドライバに行わせて処理のカーネルモード化
8.特定ソフトの起動直後に呼ばれるAPI関数(GetModuleHandleA関数など)に初期化処理を追加して環境依存の強制終了等の不具合を回避
9.仲介DLL自動出力機能を実装する「特定ソフトウェア挙動改善ソフト」の開発
●学習目的の仲介DLL使用例
1.アセンブリ言語ベースでのAPI関数呼び出しの仕組みを学習
2.x86とx64でのAPI関数呼び出し処理の違いを学習
3.APIフック手法を学習
4.自作ソフトの不具合発生時における各種検証
5.悪意があると疑わしい特定API関数の呼び出しそのものあるいは特定引数指定を点数化する、累積点型マルウェア判別ソフトの自作(※)
(※)このような「(疑わしい)特異な要素」は、英語のプログラム解析ツールでは「Anomaly」などと表現されます。また、現在では、このような要素ベースのマルウェア判別は機械学習で行う手法が発展しつつあります。
●<参考>障害発生時の対処例
(注)仲介DLL適用対象ソフト等の作者に質問あるいは対処を依頼しないでください
1.強制終了が生じた場合は、表示されたエラーコードをWebで検索し、さらに表示されたモジュール内オフセットから原因を究明していく
2.DLLプロジェクトのセキュリティ関連設定を無効にしてみる
3.自己の責任において、セキュリティソフトを一時的に無効化してみる
4.Webで類似ケースを検索し、原因を仮定してから検証を進める
APIフック時のソースコード修正例
●32ビット版 MessageBoxA (マルチバイト文字列使用API関数、USER32.dllがエクスポート) 修正例/* //元の関数を/* */でコメントアウトして、関数の定義に書き換える //Microsoft technical documentationやWindows SDKで対象API関数(ここではMessageBoxA)の定義を調べて、戻り値や引数の定義を同じにする __declspec( naked ) void WINAPI PROXY_MessageBoxA() { __asm { jmp p[476 * 4] } }*/ __declspec( dllexport ) int WINAPI PROXY_MessageBoxA(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType); //CPPファイルの最後に関数の実体を追記 __declspec( dllexport ) int WINAPI PROXY_MessageBoxA( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType ) { OutputDebugString(lpText);//引数の出力(うさみみハリケーンでログ化可能) lpText = "MessageBoxA関数をフックしました";//引数の変更 lpCaption = "APIフック例"; uType = MB_YESNO; int Ret = MessageBoxA(hWnd, lpText, lpCaption, uType); //return MessageBoxA(hWnd, lpText, lpCaption, uType); return IDOK;//戻り値の変更 }●同上 インラインアセンブラを用いた修正例
__declspec( dllexport ) int WINAPI PROXY_MessageBoxA( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType ) { static char HookTxt[48] = "MessageBoxA関数をフックしました(ASM)"; static char HookCap[48] = "APIフック例(ASM)"; __asm{ push lpText call dword ptr [OutputDebugStringA] push MB_YESNOCANCEL|MB_ICONINFORMATION push offset HookCap push offset HookTxt push hWnd call dword ptr [MessageBoxA] mov eax, IDOK } }●64ビット版 MessageBoxW (Unicode文字列使用API関数:「LPCTSTR」を「LPCWSTR」に書き換え) 修正例
/* //元の関数を書き換え void WINAPI PROXY_MessageBoxW() { PA = p[591]; JMPtoAPI(); } */ int WINAPI PROXY_MessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType); //CPPファイルの最後に関数の実体を追記 int WINAPI PROXY_MessageBoxW( HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType ) { OutputDebugStringW(lpText);//Unicode文字列を使用するOutputDebugString"W"関数を指定 lpText = L"MessageBoxW関数をフックしました"; lpCaption = L"APIフック例"; uType = MB_YESNO; int Ret = MessageBoxW(hWnd, lpText, lpCaption, uType); //return MessageBoxW(hWnd, lpText, lpCaption, uType); return IDOK; }●序数のみの関数(32ビット版) 修正例
//元の関数を/* */でコメントアウトして、関数の定義に書き換える //関数の仕様(引数や戻り値)を調べておくか解析しておく /* __declspec( naked ) void WINAPI PROXY_NONAME42() { __asm { jmp p[864 * 4] } } */ __declspec( dllexport ) int WINAPI PROXY_NONAME42(DWORD dwVal, LPCTSTR lpText, UINT uType); //CPPファイルの最後に関数の実体を追記 __declspec( dllexport ) int WINAPI PROXY_NONAME42( DWORD dwVal, LPCTSTR lpText, UINT uType ) { static char DbgTxt[512]; wsprintf(DbgTxt, "Val:%08X Text:%s Type:%d", dwVal, lpText, uType); OutputDebugString(DbgTxt);//引数の出力(うさみみハリケーンでログ化可能) typedef int (WINAPI *LPFN_PROXY_NONAME42)(DWORD dwVal, LPCTSTR lpText, UINT uType); LPFN_PROXY_NONAME42 fnLPN42 = (LPFN_PROXY_NONAME42)GetProcAddress(hLib, MAKEINTRESOURCE(42)); //LPFN_PROXY_NONAME42 fnLPN42 = (LPFN_PROXY_NONAME42)p[864]; lpText = "PROXY_NONAME42";//引数の変更 int Ret = fnLPN42(dwVal, lpText, uType); //return fnLPN42(dwVal, lpText, uType); return 42;//戻り値の変更 }●システムDLLのパス 指定例 (64ビット版Windows用)
//hLib = LoadLibrary(... //元のパス指定箇所をコメントアウト char Path[MAX_PATH]; SHGetFolderPath(NULL, CSIDL_SYSTEMX86,//仲介DLLが64bitDLLなら CSIDL_SYSTEM を指定 NULL, 0, Path); PathAppend(Path, "WS2_32.dll"); hLib = LoadLibrary(Path);