チートとは何か(2)
通信が改変される
ファイルに保存する内容を暗号化するのは、それを読み込んだ際に内容が改変されているおそれを排除できるようにするためです。一般に、プログラムの外部から渡されるデータは任意の内容となりうる前提で考え、プログラムに不適切な挙動を取らせるような内容であれば拒否できるようにデータ形式を設計する必要があります。このようにプログラムの外部から渡されるデータとしては、ファイルから読み込まれるデータと並んでネットワーク通信から受信するデータがあります。オンラインゲームでは、クライアントからサーバーにはゲームのプレイ結果が送られ、サーバーからクライアントにはプレイヤーのステータス値や所持アイテムのリストといったゲームの状況が送られます。
前者が改変されると実際にはクリアしていないステージをクリアしたことにされるといったようなチートが発生し、後者が改変されると実際には所持していないアイテムを使用されるといったようなチートが発生します。通信内容を改変するためにはネットワークに関する高度な知識が必要な印象を持たれるかもしれませんが、実際にはそれほど難しい行為ではありません。特にHTTP通信の場合、GUIによる直感的な操作で通信内容を解析・改変できるようなWebアプリケーション開発用ツールが広く知られており、ツールの操作手順に従うだけで通信内容の改変をごく容易に行えます。
通信の改変についても、ファイルの改変と同じく暗号化が対策になります。通信の暗号化として真っ先に挙げられるのはHTTPSですが、一般的なHTTPSではチート対策にはなりません。ゲームサーバーのURLが「http://」から「https://」に変わっただけであれば、攻撃者が通信を改変する際の手間はほとんど変わらないのです。
通信改変を行う攻撃者は、プロクシを設置してクライアントからのHTTPリクエストを受け取り、改変したHTTPリクエストをサーバーに送ってHTTPレスポンスを受け取り、改変したHTTPレスポンスをクライアントに返します。これがHTTPSになった場合、HTTPSによる暗号化はクライアント↔︎プロクシ間と、プロクシ↔︎サーバー間のそれぞれで行われることになります。これは、クライアントがリクエストに施した暗号化とサーバーがレスポンスに施した暗号化がいずれもプロクシで解除されるという「中間者攻撃」の状態です。HTTPSには中間者攻撃を防止する仕組みがあるため、通常であればこれが問題になることはありません。HTTPSのクライアントは、サーバーに接続する際にサーバーから提示される証明書を検証し、自分が間違いなく真のサーバーとの間で暗号化通信を行っており中間者が介在していないことを検証します。
問題は、この検証というのがサーバーの証明書を発行したのが信頼できる認証局であるかの確認だということです。信頼できる認証局のリストはHTTPSクライアントが動作するOSの設定として管理者がカスタマイズできるため、攻撃者は自作の認証局を信頼できるものとして登録してある環境でプログラムを動作させることができます。これによって攻撃者は“真のサーバーの証明書”を自由に偽造できるようになり、中間者攻撃が成立することになります。仕組みを説明すると以上のように長くなりますが、ツールを使ってこれを行う際に必要な作業はツールが指定してくる証明書を信頼できるものとしてOSに登録する作業だけです。
HTTPSがそのままではチート対策にならないことについて、対処法は2つあります。1つ目の対処法はリクエストやレスポンスを独自に暗号化するようにしてHTTPSによる暗号化には頼らないようにするというもので、ファイルに保存する内容を暗号化するときのような処理をリクエストの書き出しとレスポンスの読み取りでも行うようにするというものです。2つ目の対処法はサーバー証明書が信頼できるかの検証をOSが管理する認証局リストに頼らない別の方法で行うようにするというもので、サーバーの証明書に含まれる公開鍵の値が特定の値であることを直接に検証する「公開鍵ピン留め」という手法が注目を集めるようになっています。それぞれの対処法にはメリットとデメリットがあり併用を考える場合もありますが、いずれにしろ、チート対策として行う場合はプログラム改変によって無力化されることがないよう耐タンパー性が必要になります。
2種類ある公開鍵ピン留め
公開鍵ピン留めには、期待する公開鍵の値を事前にプログラム内に含めておく静的な方式と、これをHTTPヘッダーで通知する動的な方式があります。チート対策に使えるのは前者だけで、後者は認証局が危殆化(きたいか)された場合の被害軽減という別の目的のためのものです。RFC 7469が2015年に公開されるなど公開鍵ピン留めは注目されている技術ではありますが、主に話題となっているのは後者であるため、チート対策として公開鍵ピン留めを調べる際には注意が必要です。
メモリが改変される
ファイルの読み取りや通信によってプログラムの外部から渡されるデータは攻撃者が改変できるものであるため信頼しないという考え方は、多くのセキュリティ分野に共通する考え方であり、ご存じの方も多いと思います。しかしながら、これに加えてメモリ内にあるデータも攻撃者が改変できるものであるため信頼できないというチート対策での考え方には、驚かれる方も多いのではないでしょうか。
端的にいえば、「x = y;」というプログラムであるからといってxの値がyであるとはいえない、ということです。プロセスが異なればメモリ空間が異なり、他プロセスのメモリ内容は読み書きできないという仮想メモリの仕組みは、OSが担う最も基本的な機能の1つといえます。しかし、多くのOSでは、特定の条件と手順を満たすことで他プロセスのメモリを読み書きする機能も提供されています。これは、デバッガーを使うとデバッグ中のプロセスが持つ変数の値を変更できることを思い浮かべると、イメージしやすいでしょう。また、プログラムが仮想マシン上で実行されている場合、仮想マシンの仕組みによってはその“物理メモリ”がホストOS側から容易に読み書きできることがあり、これを使ってプログラムのメモリ内容を読み書きできることもあります。
メモリ内容を読み書きできることが分かっても、メモリ内容なんてバイナリ値の羅列なのに目的の変数がどこにあるのかなんて分かるのだろうか、そもそもどの変数の値をどう書き換えると何が起こるのかなんて分かるのだろうか、といった疑問が湧くかもしれません。実は、攻撃者もそんなことが分かっているわけではなく、現在のHPは12,345だからメモリ中に39 30 00 00というバイトの並び(リトルエンディアンの32ビット整数で12,345を表します)がないかゲームのプロセスのメモリ空間全体をスキャンしてみよう、もしあれば試しに値を変えてみてHPが変わらないか見てみよう、といった程度の極めて大ざっぱな試行錯誤をしていることがほとんどです。
この種のメモリ改変は、原理が単純なためソフトウェア開発の知識を全く持たないような攻撃者でも手法が理解でき、攻撃を行うための専用ツールも広く知られていることから、攻撃者の数は相当に多いものと考えられます。実際、他の攻撃方法に比べると掲示板等で情報交換がされている様子が、国内外を問わず頻繁に観測されます。
メモリ改変に対するチート対策には、2種の方式があります。1つめの方式はメモリを読み書きするための手段を封じるものです。OSによって提供される他プロセスのメモリを読み書きする仕組みの対象外となるようにプロセスを設定する、仮想マシン上で動作している場合には何らかの方法でそれを検知して終了するようなプログラムにする、といった方法でプログラムのメモリが読み書きできないようにします。
2つめの方式は、メモリに値を格納する際のビットパターンを推測しにくいものにするものです。変数に保存する値をステータス値そのものではなく適当な値との排他的論理和を取った結果にするといった何らかのエンコーディングを施すことで、メモリがスキャンされてもステータス値を格納している変数が見つからないようにします。前者は包括的な対策として強力ではありますが、対象プラットフォームのOSや仮想マシンに関する極めて深い知識が必要とされます。また、どうやってもメモリの読み書きを阻止できないOSも存在します。後者は保護対象とする変数を洗い出す手間がかかりますが、プラットフォームに依存しない対策として有用です。
OSが改変される
チート対策の分野では、Android端末のroot化やiOS端末の脱獄(ジェイルブレイク;jailbreaking;JB)といった用語を目にすることがよくあります。AndroidやiOSはいわゆるUNIX系のOSですが、UNIXの管理者ユーザーであるrootの権限で動作するプログラムを端末の利用者が作成することはOSの仕組みとしてできないようになっています。これを種々の方法で改変しroot権限で動作するプログラムを作成できるようにする行為がroot化や脱獄です。
root化や脱獄はそれのみでチートとなるわけではありませんが、root権限を使うことで初めて使えるチートツールや攻撃手法も多いため、このような端末ではプレイを拒否する措置を取っているゲームも多くあります。この拒否処理はroot化や脱獄の際に変更されるファイルやOSの状態を検知することで行われますが、この種の検知処理を回避してroot化・脱獄されている端末でもこれらのゲームをプレイできるようにする検知回避ツールと呼ばれるものも存在しています。検知回避ツールが動作する仕組みはツールによってまちまちですが、一例を挙げると、検知処理のために発行されたシステムコールに介入することでroot化・脱獄の兆候を隠蔽するというものがあります。
例えば、su(1)コマンドの存在を検知してroot化・脱獄の判定が行われる場合、実際にはsu(1)コマンドが存在する旨の結果が得られるシステムコールが検知回避ツールによって横取りされ、su(1)コマンドは存在しない旨の誤った結果を取得させられます。システムコールやシステムAPIへの介入はより直接的なチートの手段として用いられることもあり、入力デバイスの操作イベントを捏造することで自動プレイを行う、時刻や位置情報を偽装することでこれらを利用したゲームシステムで有利な結果を得る、といったチートが発生しています。
OSが改変されていることをそのOS上で実行されているプログラムから検知するのは容易なことではありません。OSが改変されているかを調べるにはOSの現在状態を知る必要がありますが、これにはシステムコールが必要です。しかし、改変されたOSではシステムコールの結果は信用できません。いくつかのタイプのOS改変を効果的に検知する技法がある一方で、検知は原理的に不可能なのではないかと考えられるタイプのOS改変もまた知られています。検知できる場合はしっかりと検知する、各種の保護処理ではできるかぎりOSの機能に依存しないようにする、といったことでOS改変の脅威をできるだけ緩和するとともに、プレイヤーの操作内容や時刻・位置情報の値が非現実的な値となっていないかを検証できるようなゲーム設計とすることも重要かつ効果的なチート対策となります。
デバイスが改変される
OSを改変することで実際には行われていない入力操作があったかのように偽装して自動プレイを行うというチートについて、OSではなく入力デバイス自体にそのような機能を備えたものも販売されています。また、位置情報を効率的に変化させるために、スマートフォンをドローンに乗せて移動させるといった話も聞かれています。これらは言うなれば“デバイスの改変”ということになりますが、このようなデバイスが使われていることをプログラムから検知するのは、ごく一部の有名デバイスをブラックリスト的に排除するといった程度のこと以外は不可能といえます。また、どの程度の機能を備えたデバイスからをチートと見なすのかについても明確な線引きは難しいでしょう。
OS改変に対するチート対策でも触れたように、こういった特殊なデバイス・特殊なOSへの対策は、これらの環境の特殊性によってゲームが有利に進められることのないようなゲーム設計をすることであるといえます。
