問題の本質
Xerox 3220 MFPは、このMFPがIPアドレスで登録されているネットワーク上のコンピューターの1つにインストールされたネットワークスキャンアプリケーションを介したネットワークスキャンをサポートします。 しかし、このコンピューター(Cisco VPN ClientおよびOpenVPN)でVPN接続を使用するために実稼働が必要になったら。 また、接続のいずれかを接続した瞬間に、アプリケーションからのスキャナーとの接続が即座に失われました。 私の研究プロセスとこの問題の解決策についてさらに説明します。
初見
デフォルトゲートウェイを置き換えることを考えた場合、VPN内のすべてのトラフィックをラップする可能性があるため、すぐに動作不能として破棄されます。 これは、使用されている接続のいずれにもありません。 スキャナーのWebベースのインターフェイスは引き続き使用できますが、最終的にはささいな応答をします。 それから、そもそもネットワークエンジニアとして、ネットワーク上でスキャナーがどのように検出されたかに興味を持ちました。
これを行うために、Wiresharkを使用し、ローカルネットワークインターフェイスでVPN接続なしで実行しました。 アプリケーションがポート1124にブロードキャストudpパケットを送信し、スキャナーが応答することがわかりました。 これで、VPNを接続し、ローカルインターフェイスで完全に無音になり、発信パケットもありません。
しかし、中身は何ですか?
まあ、何らかの理由でプログラムが間違ったインターフェイスにパケットを送信し始め、もちろん誰もそれに応答しないことは明らかです。 これを修正する方法、それは私には完全に理解できませんでした、なぜなら アプリケーションがスキャナのアドレスまたは他の正気なものと一緒にルーティングテーブルによってガイドされる場合、すべては正常であるはずでしたが、これはそうではありませんでした。 したがって、少なくともインターフェースを選択するためのアルゴリズムを理解する必要がありますが、私はOllyDbgを使用してこれを実装することにしました。
NSCSysUI_XEROX.exe(* .dllシリーズが接続されたネットワークスキャンアプリケーション自体)をデバッガーの下で実行すると、予想どおり、何も理解できませんでした。 これは私の最初のリバースエンジニアリングの経験ではありませんが、以前のものは特に成功しませんでした。
スキャナーの検出は、[更新]ボタンをクリックした後でもはっきりと発生し、OllyDbgでは、その時点で何らかのデバッグ文字列出力が発生していることに気付きました。 最後のメッセージは、インターフェイスの選択されたIPアドレスの種類に関するものでした。
「Selected NIC IP」のこの行について、私は理解することにしました。 Search For-すべての参照文字列を使用してすぐに検索しようとしましたが、見つかりませんでした。そのため、エントリポイントから.exeファイルへの長い失望と長いF7に陥りました。 その結果、探していた行がないのは驚くことではないことがわかりました。 このデバッグ出力は、NSCProtocol_XEROX.dllからの呼び出しに属します。この呼び出しでは、行は既に正常に配置されています。メッセージ出力を伴うこの手順は次のとおりです。
003B737D |. FF75 DC PUSH DWORD PTR SS:[EBP-24] ; /<%s> 003B7380 |. 8D45 F0 LEA EAX,[EBP-10] ; | 003B7383 |. C645 FC 12 MOV BYTE PTR SS:[EBP-4],12 ; | 003B7387 |. 68 04A13D00 PUSH OFFSET 003DA104 ; |Format = "Selected NIC IP : %s" 003B738C |. 50 PUSH EAX ; |Arg1 003B738D |. E8 D6F70000 CALL 003C6B68 ; \NSCProtocol_XEROX.003C6B68
しかし、これはまだ面白くありません。この手順で一般的に何があるかを探しています。 まず、gethostbyname()関数の呼び出しを目に留まりました。これは、MSDNが言うように、指定されたシンボリック名のIPアドレスのリスト全体を返します。
003B6FCA |. 50 PUSH EAX ; /Arg1, EAX 003B6FCB |. E8 1EF70000 CALL <JMP.&WSOCK32.#52> ; \WS2_32.gethostbyname 003B6FD0 |. 8BF8 MOV EDI,EAX ; EDI hostbyname ( EAX) 003B6FD2 |. 3BFE CMP EDI,ESI ; hostbyname 003B6FD4 |.- 74 34 JE SHORT 003B700A 003B6FD6 |. 8B47 0C MOV EAX,DWORD PTR DS:[EDI+0C] ; IP 003B6FD9 |. 8B00 MOV EAX,DWORD PTR DS:[EAX] ; IP 003B6FDB |. FF30 PUSH DWORD PTR DS:[EAX] ; /Arg1 003B6FDD |. E8 06F70000 CALL <JMP.&WSOCK32.#11> ; \WS2_32.inet_ntoa 003B6FE2 |. 50 PUSH EAX ; /Arg1, - 003B6FE3 |. 8D4D D4 LEA ECX,[EBP-2C] ; | 003B6FE6 |. E8 FD050100 CALL 003C75E8 ; \NSCProtocol_XEROX.003C75E8 003B6FEB |. 8B47 0C MOV EAX,DWORD PTR DS:[EDI+0C] ; IP 003B6FEE |. 8B00 MOV EAX,DWORD PTR DS:[EAX] ; IP 003B6FF0 |. 3BC6 CMP EAX,ESI 003B6FF2 |.- 74 16 JE SHORT 003B700A 003B6FF4 |. 33DB XOR EBX,EBX ; EBX IP 003B6FF6 |> FF30 /PUSH DWORD PTR DS:[EAX] ; /Arg1, IP 003B6FF8 |. E8 EBF60000 |CALL <JMP.&WSOCK32.#11> ; \WS2_32.inet_ntoa 003B6FFD |. 8B47 0C |MOV EAX,DWORD PTR DS:[EDI+0C] 003B7000 |. 83C3 04 |ADD EBX,4 003B7003 |. 8B0418 |MOV EAX,DWORD PTR DS:[EBX+EAX] 003B7006 |. 3BC6 |CMP EAX,ESI 003B7008 |.- 75 EC \JNE SHORT 003B6FF6 ; ! 003B700A |> E8 D3F60000 CALL <JMP.&WSOCK32.#116> ; [WS2_32.WSACleanup, IP , -
コメントはそれ自体を物語っています。 アプリケーションのそのような奇妙なロジックを見て、私はここが鍵だと思いました-プログラムは単にIPアドレスの配列の最初を使用し、残りを無駄に実行します。 この信頼性は、getcallbyname()というテストコールによって強化されました。この構造の返された構造には、最初のアドレス配列にVPN接続のIPアドレスが常に表示されていました。 そして、2つの解決策がありました。 1つ目は、指定されたプロセスのgethostbyname()をインターセプトし、返されるか、目的のIPアドレスを最初に配置するブートローダーを記述することです。 しかし、以来 以前はこれをやったことがありましたが、スポーツではありませんでした。2つ目-少なくともプリミティブレベルでDLLにパッチを適用することにしました。
私の意見では、示されているすべてのコードを自分の場合により適切なものに置き換えて(私は認めなければなりませんが、アプリケーションのアプローチと違いはありません)、唯一の呼び出しを実行しました(何らかの種類の非常に有用であると仮定して)上記のコードには参加していません最初のIPアドレスでのみ、ただしそれらすべてで:
003B6FD6 8B47 0C MOV EAX,DWORD PTR DS:[EDI+0C] ; IP 003B6FD9 8B00 MOV EAX,DWORD PTR DS:[EAX] ; IP 003B6FDB 33DB XOR EBX,EBX 003B6FDD FF30 PUSH DWORD PTR DS:[EAX] 003B6FDF E8 04F70000 CALL <JMP.&WSOCK32.#11> ; Jump to WS2_32.inet_ntoa 003B6FE4 50 PUSH EAX 003B6FE5 8D4D D4 LEA ECX,[EBP-2C] 003B6FE8 E8 FB050100 CALL 003C75E8 003B6FED 8B47 0C MOV EAX,DWORD PTR DS:[EDI+0C] 003B6FF0 83C3 04 ADD EBX,4 003B6FF3 8B0418 MOV EAX,DWORD PTR DS:[EBX+EAX] 003B6FF6 3BC6 CMP EAX,ESI ; IP 003B6FF8 ^ 75 E3 JNE SHORT 003B6FDD 003B6FFA 90 NOP ... 003B7009 90 NOP 003B700A |> E8 D3F60000 CALL <JMP.&WSOCK32.#116>
私の仮定によれば、これはアプリケーションに最初のIPアドレスではなく最後のIPアドレスを選択させることになっていた。 まあ、または一度に。
ただし、アプリケーションの動作では、これにより何も変更されていません。 この結果は、そのデバッグ行の出力が、記録が行われなかったメモリ領域を使用したという事実も示唆しました。 さて、さらに見てください。
真実の瞬間
次に、リストの少し下に行き、GetAdaptersInfo()の呼び出しを見て、その後に多くの行のループがあり、関数によって返されたリストの各レコードを調べようとしているようです。 このコードを2日間瞑想しました。 まだロジックを完全には理解していませんが、私のバージョンは次のとおりです:ゲートウェイの最初のレコードが取得され、インターフェースのタイプ、ゼロ以外のIPアドレス、および文字表現の長さ(?このチェックは私にとって最も神秘的です)がチェックされますこのインターフェースのデフォルト。 タイプが適切で、アドレスがあり、ゲートウェイのシンボリック表現がゼロでない場合、ループを終了し、このアダプターを選択します。 そして、ここにニュアンスがあります。 私のVPN接続の場合、デフォルトゲートウェイはまったくありませんが、MSDNのコードを使用したC ++のGetAdaptersInfo()へのテストコールは、それを不在値としてではなく、それぞれ「0.0.0.0」として返し、長さはゼロではなく、このインターフェイスはすべての点で合う。 そして以来 彼はリストの最初で、それから彼が選択されます。
それから私は完全に悲しかった、そして私は正しい操作のためにこのコードを修正する方法を理解しなかった。 ただし、ドキュメントを注意深く読む必要があります。 関数の説明は次のとおりです。
GetAdaptersInfo関数は、IPv4アドレスの情報のみを取得できます。
この関数によって返されるリストに表示されるアダプターの順序は、[ネットワーク接続]フォルダーから制御できます。[詳細設定]メニューから[詳細設定]メニュー項目を選択します。
私のように(そしてwin2000サーバーから始まるWindows管理に遭遇する)あなたが以前にこのメニューを見たことがないなら、これはWin7の場所です:
もちろん、VPNアダプターがすべてローカルネットワーク接続の上にあり、最上位に移動していることがわかりましたが、元の問題を解決しました。
PSしかし、Xeroxの開発者は、最初に遭遇したインターフェイスだけでなく、すべてのインターフェイスにテストリクエストを送信できました。