コサックのリバヌス゚ンゞニアリング、パヌト3LANの指ぬき







2016幎の終わりの庭で、぀いにファンの間で熱狂の嵐が起こり 、「コサック」の3番目の郚分が出おきたした...しかし、私はただ最初の郚分のネットワヌクコンポヌネントの奇劙な間違いに悩たされおいたした。 奇劙なこずは、ロヌカルネットワヌク䞊でゲヌムを䜜成するずき、通垞2人しかゲヌムを起動できないこずでした。 プレむダヌが3人いるず、負荷むンゞケヌタは非垞にゆっくりず成長し、4人からは党䜓で0のたたでした。 さあ、調査を始めたしょう



゚ラヌ衚瀺



問題の症状はいく぀かありたす。 ゲヌムルヌムに衚瀺される「最倧ping」倀が高すぎお、プレヌダヌの数に比䟋しお増加したす。 すべおのプレむダヌが同じスむッチに接続され、通垞のicmp pingが䞀貫しお1ミリ秒未満を生成したすが、ゲヌムルヌムでは最倧350ミリ秒の遅延が衚瀺されたす。 郚屋にプレむダヌが2人しかいない堎合、「最倧ping」は最初に玄90ミリ秒で、1秒あたりに玄10ミリ秒に䜎䞋したす。



2番目の症状は、「 プレヌダヌ名で盎接接続が確立されおいたせん」ずいう譊告です。 私たち3人は玄50の堎所でそれを獲埗する機䌚があり、郚屋に4人のプレむダヌがいる堎合、垞に衚瀺されたす。 Ctrlキヌを抌しながら「開始」をクリックするこずでこの譊告は無芖できたすが、これはゲヌムの偎面からの接続品質の「認識の問題」を瀺しおいたす。



3番目の症状は、ダりンロヌド速床が遅いこずです。 すべおのプレむダヌが[開始]をクリックするず、割合のむンゞケヌタヌがゲヌムのホストに衚瀺されたす。 〜8ず぀増加し、100に達し、その埌のみゲヌムを開始できたす。 このむンゞケヌタは、ランダムに生成されたカヌドのファむルをホストからプレヌダヌに転送する進行状況を䞻に瀺しおおり、通垞のカヌドのこのファむルのサむズは玄3.5 MBであるため、ギガビットLANでの5秒のダりンロヌドでも問題になりたす。 たた、3人のプレヌダヌを「ダりンロヌド」するのにかかる時間は、ゲヌムずずもにフォルダヌ党䜓をコピヌできたす。



最埌から開始



あなたの蚱可を埗お、私はあなたにこの逆転の始たりの詳现ず生じた問題を解攟したす。 ネットワヌクコンポヌネントを分解するのは楜しいだろうず思っお間違えたずしか蚀えたせん。 ポむンタヌを介した関数の呌び出し。 マルチスレッド。 DirectPlayを䜿甚しお、sendtoずrecvfromを同時に䜿甚したす。 デバッグ情報は蚀うたでもなく、この恐竜に関するわかりやすいドキュメントの欠劂。 私のカンフヌはここでは明らかに䞍十分でした。



したがっお、通垞どおり動䜜したす。 みんなのお気に入りの最も矎しいプログラムを開き、Alt + Tを抌しお「盎接接続なし」を探したす。 文字列を含むメモリの領域を芋぀け、 xrefを介しお盎接ポむンタヌに移動し、次にサむズが32キロバむトの䜓積関数に移動したす。 ずりわけ、ゲヌムルヌムのむンタヌフェむスの芁玠はその䞭で初期化され、メッセヌゞが凊理され、衚瀺される前に行が構成されたす。 圌女をLanLobbyず呌びたしょう。 以䞋に、プレヌダヌに譊告を衚瀺しお「開始」キヌを無効にするかどうかを決定するアルゎリズムを瀺したす。



泚蚘事に瀺されおいる逆アセンブラヌのリストは、読みやすくするために凊理されおいたす。



  1. SomeIterationず呌ばれる小さな関数が呌び出されたす。 今埌、圌女の䜓内で同様の関数ぞの呌び出しがあり、ImportantIterationず呌びたす。 埌者が少なくずも1回れロを返す堎合、SomeIterationはすぐにルヌプを終了し、れロも返したす。 この堎合、移行は行われず、譊告を受けるリスクがありたす。



  2. 次に、Ctrlボタンのステヌタスがチェックされたす。 クランプされおいる堎合、「開始」ボタンは無効になりたせん。



  3. 「開始」ボタンの無効化。 hStartButton倉数は、「addVideoButton」ずいう名前の関数の結果で䞊蚘で初期化されたす。



  4. タむマヌは2秒経過したかどうかチェックされたす。 PreviousTick倉数の䞊に、珟圚のGetTickCount倀が、ルヌム内のプレヌダヌの数が倉わるたびに割り圓おられたす。 それから2秒未満が経過するず、移行が行われ、譊告は衚瀺されたせん。



  5. 最終的に、譊告行は、ゲヌムルヌムのステヌタスバヌずしお画面に衚瀺するための行にコピヌされたす。



結論プレむダヌを郚屋に連れお行った埌、ゲヌムは接続を確立するのに2秒かかりたす。 その埌、ImportantIterationがただれロを返す堎合、盎接接続の欠劂に関する譊告が衚瀺されたす。



぀たずきブロック



リバヌスのこの段階では、ImportantIterationで䜕が起こっおいるのかただ理解できおいなかったので、ロヌディングむンゞケヌタヌラむンのレむアりトを芋぀けお、そこから䜜業を続けるこずにしたした。 以前、「最倧ping」蚈算アルゎリズムを分析する無駄な詊みで、数倀倉数を持぀すべおの文字列が最初にsprintfを介しおコンパむルされ、次にタヌゲット文字列に配眮されるこずに気付きたした。 フォヌマット文字列の構文が䞎えられたら、テキスト「%%」を探し、LanLobbyで䞀臎するものを芋぀けたす。 これは、コヌドの断片がどのように芋えるかであり、ダりンロヌドむンゞケヌタヌのフィヌルドにパヌセンテヌゞの数字を衚瀺するか、ゲヌムの「準備」を瀺すチェックマヌクを衚瀺するかを決定したす。









GetLoadPercentage関数の結果は、100未満の堎合、1぀ず぀画面に転送されるこずがわかりたす。 2番目のブランチは目盛りを描画する必芁がありたす。 この関数で䜕が蚈算されるのだろうか GetLoadPercentageは、プレヌダヌのデヌタを䜿甚しお配列を通過するルヌプで構成されおいたす。



そしお、ここで重芁な反埩は問題を解決したす。 はい、名前ず間違われおいたせん。 算術挔算を行うず、ImportantIterationは0x00から0x0Cの範囲でプレヌダヌのダりンロヌドステヌタスを返したす。぀たり、この「スケヌル」には12ステップしかありたせん。 パヌセンテヌゞむンゞケヌタが8ず぀増加する理由が明らかになりたした。



ImportantIterationが䜕をすべきかを理解したので、それがただ䜿甚されおいる堎所を芋おみたしょう。


接続品質をチェックし、関心を蚈算するずきに知っおいる呌び出しに加えお、ImportantIterationは2぀の堎合に呌び出されたす接続䞍良に぀いおの譊告が定匏化されるずき-ステヌタスバヌのプレヌダヌのリストをコンパむルするために䜿甚され、すべおのプレヌダヌが準備ができおいるかどうかをチェックするために䜿甚されたす。 埌者は、すべおのプレむダヌを通過し、ロヌドの床合いを0x0Cず比范する小さなサむクルの関数で実行されたす。 少なくずも1人のプレむダヌが少ない堎合、サむクルはれロを返したす。 最埌の関数の結果は、ホストの[スタヌト]ボタンのアクティブ化ずゲヌムを開始する機胜に盎接圱響するず想定できたす。



解決策



したがっお、最も簡単な解決策は、ImportantIterationの結果に応じお、ロゞックを修正するこずです。 幞いなこずに、すべおの堎合においお、移行は肯定的な結果で実行されたす。぀たり、すべおの移行を条件付きから無条件に倉曎するだけです。 dmcr.exeファむルのいわゆる「Windows 7バヌゞョン」の堎合、パッチ党䜓は次のように説明できたす。



 |  |  |  ---------+-----------+-----------+----------------------------- 0x00CEEA | 0x7D | 0xEB |      0x098792 | 0x0F 0x8D | 0x90 0xE9 |     100% 0x09C389 | 0x0F 0x85 | 0x90 0xE9 |   
      
      





そしお、すべおの倉曎はロヌカルネットワヌク䞊のゲヌムのゲヌムルヌムのロゞックのみに関係し、ネットワヌクメッセヌゞ自䜓は䞊行しお発生し、それに䟝存しないため、副䜜甚を恐れるこずはできたせん。 ランダムに䜜成されたカヌドのファむルは、ほが瞬時にネットワヌク䞊に配垃され、郚屋を䜿甚するず、遅滞なくゲヌムを開始できたす。 ここでは手を掗うこずができたすが...



の䞭には䜕がありたすか



結局のずころ、ゲヌムルヌムがプレむダヌの読み蟌み状態をどのように刀断するのかが䞍思議です。 今日の蚘事の䞻人公、ImportantIterationをご芧ください。









ここで、いく぀かの興味深いこずがわかりたす。





瀺されたメモリ領域で䜕が起こっおいるかを理解しようずしお、構造の配列に䌌たものが発芋されたした。 各芁玠のサむズは0x84バむトで、内郚には、ずりわけ、プレヌダヌの名前、䜿甚されたランダムカヌドファむルの名前、ゲヌムクラむアントのバヌゞョン、ping倀、ブヌル型のいく぀かの倉数、およびいく぀かの敎数倀および/たたはポむンタヌが栌玍されたす。 この領域のレコヌドを远跡しようずするすべおの詊みは、他のスレッドからのmemcpy呌び出しによっお制限され、静的に分析するのはかなり困難です-xrefは82個のリンクを生成し、倀0x12345678での初期化に加えお、それらすべおが読み取られたす。 ぀たり 構造䜓のアドレスがレゞスタにロヌドされ、目的の芁玠のアドレスが蚈算されたす。その埌、読み取り、曞き蟌み、倉数ずしおのポむンタヌを䜿甚した他の関数の呌び出し、たたは䞊蚘のすべおが盎ちに実行されたす。



最埌に、この構造の特定の郚分に曞き蟌み远跡を蚭定し、ImportantIterationの本文にいく぀かの条件付きブレヌクポむントを远加したした。 実際、デバッガヌの停止をオフにし、条件ずしお、メッセヌゞりィンドりにレゞスタヌの内容を衚瀺する小さなIDC関数を指定したした。



 Message("EDX: %08X\n", EDX), 0
      
      





その埌、ゲヌムを開始し、ロヌカルネットワヌク䞊のホストに数秒間接続したした。 次に、デバッガヌを停止し、远跡結果ずメッセヌゞボックス「トレヌスりィンドり」ず「出力りィンドり」の内容を確認した埌、次の結論に達したした。



デヌタの抜出元ずなるメモリ領域、および重芁な反埩は、垞に倉化しおいたす。 同時に、新しいデヌタが曞き蟌たれる前に、いく぀かの倀が最初にリセットされたす。 おそらく、新しい情報を保存する前のネットワヌクメッセヌゞの凊理のどこかで、このメモリ領域が最初に再初期化されたす。 たた、DirectPlayずマルチスレッドを䜿甚しおいるため、これらのれロはサむクルの実行䞭にのみ存圚する可胜性があり、蚘事の冒頭で説明した動䜜に぀ながりたす。



あずがき



それでは、このf話からどのような道埳を匕き出すこずができたすか ダクザに電話するためにダクザである必芁はありたせん。問題を解決するために問題の根本を掘り䞋げる必芁はありたせん。 ちなみに、リバヌスの過皋で、数秒以䞊ゲヌムを最小化する際に「自動損倱」の原因ずなったコヌドが偶然に完党に目に留たりたした。 これで、ゲヌム䞭に音楜を安党に倉曎できたす。 確かに、サヌドパヌティのプログラムを䜿甚しおゲヌムの操䜜を容易にする可胜性があるため、ゲヌムコミュニティに察するこのようなパッチの利点に぀いおはわかりたせん。



最埌に、 最初の蚘事で取り䞊げたゲヌムのタむミングの問題に戻りたいず思いたす 。 その埌、関数QueryPerformanceFrequencyおよびQueryPerformanceCounterの圹割を完党に理解しおいたせんでした。 Andrey Smi1eが正しく指摘したように、それらがタむミングに圱響を䞎えるずは思われたせんでした。 これで、これらの関数は、最初の「コサック」のゲヌムルヌムで擬䌌乱数ゞェネレヌタヌずしお䜿甚され、ランダムマップファむルおよび/たたはこのファむルの名前を䜜成し、ゲヌムの実際のタむミングはGetTickCountによっお排他的に実行されたす。



それだけです、すぐに䌚いたしょう



参照資料






All Articles