Runescapeがボットを捕まえる方法と彼女が私を捕まえなかった理由



プレイヤーのアクションの自動化は、World ofWarcraftRunescapeなどのMMORPGでは常に大きな問題 でした。この種のゲームのハッキングは、たとえばシューティングゲームでの従来のチートとは大きく異なります。



ある週末、Runescapeがプレイヤーのアクションを自動化するのを防ぐためにJagexが使用する検出システムを調べることにしました。



植物学



過去数か月間、アカウントは sch0u



world 67サーバーで24時間再生され、暴徒の殺害やリソースの収集などの単調なタスクを実行しています。一見、このアカウントは他のプレイヤーと同じように見えますが、重要な違いが1つあり ます。それはボットです。





ボット認識システムの機能をテストするために、このボットを10月に立ち上げました。Jagexがボットボットとどのように戦うかについての情報を見つけようとした後、私は有料のボットのビデオだけを見つけました。その開発者は、マウスの動きのシステムが人間の行動と見分けがつかないと自慢していました。



したがって、私が理解できたのはマウスの動き重要性だけ でしたが、これは本当にそうですか?



経験則!



この理論を確認するために、私はRunescapeクライアントを調べることから始めhhk



ましたが、起動直後にグローバル変数が設定されていることにすぐに気付きました



const auto module_handle = GetModuleHandleA(0);
hhk = SetWindowsHookExA(WH_MOUSE_LL, rs::mouse_hook_handler, module_handle, 0);
      
      





このコードは、システムインターセプターチェーンに接続さ れているマウスに低レベルのインターセプターをインストールします 。これにより、Windowsアプリケーションは、特定のアプリケーションに関連付けられていない場合でも、すべてのマウスイベントを傍受できます。低レベルのインターセプター(フック)は、キーロガーによってよく使用され ますが、前述のマウスインターセプターのように、ヒューリスティックなどの平和的な目的で使用することもできます。 実際、Runescapeのマウスハンドラーは非常に単純です(疑似コードは手作業で美しく調整されています)。







LRESULT __fastcall rs::mouse_hook_handler(int code, WPARAM wParam, LPARAM lParam)
{
  if ( rs::client::singleton )
  {
      // Call the internal logging handler
      rs::mouse_hook_handler_internal(rs::client::singleton->window_ctx, wParam, lParam);
  }
  // Pass the information to the next hook on the system
  return CallNextHookEx(hhk, code, wParam, lParam);
}
      
      





void __fastcall rs::mouse_hook_handler_internal(rs::window_ctx *window_ctx, __int64 wparam, _DWORD *lparam)
{
  // If the mouse event happens outside of the Runescape window, don't log it.
  if (!window_ctx->event_inside_of_window(lparam))
  {
    return;
  }

  switch (wparam)
  {
    case WM_MOUSEMOVE:
      rs::heuristics::log_movement(lparam);
      break;
    
    case WM_LBUTTONDOWN:
    case WM_LBUTTONDBLCLK:
    case WM_RBUTTONDOWN:
    case WM_RBUTTONDBLCLK:
    case WM_MBUTTONDOWN:
    case WM_MBUTTONDBLCLK:
      rs::heuristics::log_button(lparam);
      break;
  }
}
      
      





リンクの負荷を軽減するために、これらの関数 rs::heuristics::log_*



は単純なアルゴリズムを使用して、以前に記録されたイベントに類似したイベントデータをスキップします。



後で、このイベントデータはrs::heuristics::process



、メインレンダリングループのすべてのフレームで呼び出される関数によって解析され ます。



void __fastcall rs::heuristics::process(rs::heuristic_engine *heuristic_engine)
{
  // Don't process any data if the player is not in a world
  auto client = heuristic_engine->client;
  if (client->state != STATE_IN_GAME)
  {
    return;
  }

  // Make sure the connection object is properly initialised
  auto connection = client->network->connection;
  if (!connection || connection->server->mode != SERVER_INITIALISED)
  {
    return;
  }

  // The following functions parse and pack the event data, and is later sent
  // by a different component related to networking that has a queue system for
  // packets.

  // Process data gathered by internal handlers
  rs::heuristics::process_source(&heuristic_engine->event_client_source);

  // Process data gathered by the low level mouse hook
  rs::heuristics::process_source(&heuristic_engine->event_hook_source);
}
      
      





キーボードから離れて?



リバースエンジニアリングの過程で、通常はそれらの関数のフックまたはパッチを作成することによって、学習した各関数の重要性を理解しようとしました。通常、機能を役に立たなくし、ソフトウェアの状態を監視することで、その機能が関連しているかどうかを判断できます。この調査方法は興味深い観察につながりました。



ゲームが関数を呼び出すことを禁止したため rs::heuristics::process



、最初は何も気づきませんでしたが、ちょうど5分後にサーバーがログアウトしました。明らかに、Runescapeは、たとえ非常に正常にプレイできたとしても、クライアントからサーバーに送信されたヒューリスティックデータによってのみプレーヤーの非アクティブを判断します。これは新しい質問を提起しました: サーバーが私がプレイしていないと思った場合、それは私がボットとしてプレイしていると思いますか? ..。



その後、ゲームのネットワークレイヤーをリバースエンジニアリングするためにさらに数日を費やしました。これにより、 ボットはネットワークパケットのみを使用してほぼすべてのことを実行できるようになりました



私の理論を検証するために、私はマウスを動かさずに、24時間年中無休で悩みました。このように何千時間も費やしてきたボット検出システムは、クライアントからサーバーに送信されたヒューリスティックイベントのデータのみを使用するか、プレーヤーが「afk」でない場合にのみ機能すると自信を持って言えます。カーソルを動かさずにプレイすることに成功したプレイヤーは、すぐに禁止する必要があります。つまり、開発者はこの欠陥に注意を払う必要があります。






All Articles