見出し画像

ネットワークゲームとチートについて

前置き

今回はチートの方法・対策について書きます。
チートの方法や対策を書いてゲーム開発者の方の目に触れる形で置く事で、チートに遭うゲームがなくなる事を望んでいます。
チートを助長したくないので、具体的なチートの詳しいやり方などは一切 記述しませんので、その点についてご理解ください。

チートについて

チートとは、不正な操作をしてゲームを優位に進めることです。
チートはユーザーのモチベーションや、コミュニティへの悪影響があるだけでなく、種類によっては開発・運営を行っている会社の利益を直接損ねるものもあります。

さて、チートと一言で言っても色々なチートがあります。列挙すると例えば下記のように色々と出てきます。

■マルチプレイでの対戦のないゲームでも起こりえるチート
・本来所持していないはずのキャラクターを所持した扱いにしてしまうチート、または不正にゲットしてしまうチート
・ゲームキャラのステータスを弄り、とても強い状況になってしまうチート
・課金したと騙して、課金アイテムを不正にゲットしてしまうチート
・ランキングなどで不正なスコアを送り、不正に順位を上げるチート
・チートではないですが、先に予定している未公開のイベントなどをデータ解析等で知り、サイト等で情報を公開し、PVの荒稼ぎしてしまう行為
FPSやTPSと言った対戦ゲームの場合
・自動的に狙いをつけるオートエイム
・本来 壁に遮られていて見えないはずのキャラが見えるようになるウォールハック
・壁に遮られて本来は当たらないはずなのに、当たってしまう壁抜きチート
・ダメージを無効化してしまうチート
・移動速度や跳躍などを無理やり上げてしまうチート

ざっと紹介いたしましたが、どれも困ったものになります。
不正な課金やアイテムを不正にゲットされてしまっては、開発・運営の収益に直接ダメージがありますし、こういったところで不正に得たアイテムを持つアカウントをRMT(リアルマネートレード)をされてしまったりと様々な弊害が生まれてきてしまいます。
そして、対戦ゲームでも不正に強いキャラクターで溢れかえってしまっては、ユーザーも楽しくなくなり、ユーザー離れが進んでいってしまい、最終的には開発・運営の収益にダメージを与えてしまいます。

これらのチートを出来るだけ防いで、楽しく遊べるゲームを提供できるように…という事で、チートを分類してそれぞれに対策を行っていきましょう。

チートの方法の分類

チートの分類をする時ですが、チートによる影響ではなく、チートされる箇所で分類していきたいと思います。

まずはネットゲームが動いている環境を分解してみます。

画像1

チーターは上記の図で言うと、クライアント側・サーバーとの通信に関与が出来ますが、サーバー自体は直接弄ることは出来ません。
※サーバー自体を乗っ取るという例外がありえますが、その例外は基本的によっぽどの事がない限り起こりえないので、除外させてもらいます。

そして、クライアント側はもう少し分解してみましょう。

画像2

このようにストレージに保存されたプログラム本体やゲームデータをメモリに読み込んで、それをCPUが処理する事でゲームが進行していきます。
(ゲームデータがどんなのかは、コチラの記事も参照ください)

ストレージにあるデータは書き換え出来ますし、メモリも実はアプリ実行中に別のアプリから書き換え等が出来てしまいます。
なので、図のCPU以外は全てチート攻撃の対象として起こりえます。

ですので、下記5つがチート攻撃をする対象という分類になります。
1.クライアント端末にインストールしたプログラム本体そのもの
2.クライアント端末のストレージに保存しているゲームのデータ
3.クライアント端末上でゲームデータが保持されているメモリ領域
4.クライアント端末から通信で送出するデータ
5.クライアント端末が通信で受信するデータ

1.実行ファイルそのものを書き換える

実行ファイルも結局 0と1の塊です。書き換える事そのものは可能です。
ただ、もともとのプログラムの挙動を理解して、特定の箇所だけ書き換えないとチートのように都合の良い処理にすることは出来ません。

では実行ファイルを書き換えるというためにも、どのようなプロセスを経て実行ファイルが出来るかを見てみましょう。

画像3

※ここは人が書いたのをプログラマーの絵にして、機械が書き出して人が読むにはツライ部分をプログラム君(?)の絵にしています。

図のように、通常C++でプログラマーが書いた処理はアセンブリ言語に変換、それを更にマシン語に変換する事で実際のゲームで動く事になります。マシン語からアセンブリに戻すことは出来ますが、C++には戻りません。

またC++言語で書いたときのコードを見てください。中身は理解しなくても大丈夫です。ここには Characterや hpなど人に取ってわかりやすい名前が出てきます。プログラムを書くときにはこういったわかりやすい名前をプログラマーがつけることで処理を理解してやすい状況にして開発を進めていきます。
しかし、マシン語からアセンブリに戻したときにはこの名前は失われてしまいます。この状況から処理内容を理解するのは、とてつもなく困難な作業になります。都合の良いように書き換える処ではありません。

■C#を使うUnityでは注意が必要(Monoビルドしてはいけないです)
C#やJavaの言語で書く場合は注意が必要です。C#やJavaでは先の図と少し異なる形になります。Unityでも、C#でプログラムを書く形になっていますので、この対象になります。

では、C#の流れを見てみましょう。

画像4

C#で書いたプログラムはILという中間言語になったDLLファイルになります。これをアプリに埋め込んで処理する事になります。

実はこのC#→ILに変換するときに、Characterや hpと言った人間にわかりやすい名前が残った状態で変換されます。そして、ILからC#にも変換が出来ます。つまり、DLLファイルからC#プログラムをかなりの再現度で復元できるのです。
オリジナルのプログラムに使いものが復元できるので、これを都合の良い所だけ書き換えて、それを再度DLLに戻されてしまう事で、実行プログラムにされてしまうのです。

■UnityではIL2CPPビルドをしましょう!
しかしUnityではこれをもう少し複雑にしてチートされにくい手段があります。それがIL2CPPビルドをする事です。

IL2CPPビルドを選択すると、下記の図のようにC++への変換を経由されるので、解読困難な形になります。

画像5

IL2CPPビルドはWindowsなどのPC向けでも使えるようになったので、こちらを選択しましょう!

Monoビルドほど気軽にチート出来ないのですが、IL2CPPビルドも完全ではないです。

それ以上の対策を求める場合、CrackProofなどバイナリレベルの難読化を支援するツールがありますので、こういったところも検討してみてください。

2.ゲームのデータを書き換えてしまう

次にストレージにあるゲームのデータを書き換えられてしまうケースです。
ゲーム中のキャラクターの強さなどの情報は全て実行ファイルに含まれるのではありません。
ゲーム実行中に、別のファイルからメモリに読み込んで実行していたりします。(運営があるゲームでは、通信で直接取得する実装も多いですが、ここでは別ファイルにあるケースとしましょう。)

画像7

例えばこのような情報を別ファイルとして持っておきます。
キャラクターが3種類あって、弱いキャラはLV1の時はHP10で、最大LVで100、普通のキャラはLV1の時はHP30で、最大LVで300と言った形です。

もしこのファイルを書き換えてしまったらどうなるでしょう?
そうキャラの強さが変わってしまいます。

画像7

上記のような形にファイルを書き換えてしまえば、弱いキャラが最初からHP999の超強いキャラになってしまいます。

これを防ぐためには、ファイルが改ざんされていないかチェックする機構が必要になります。これは後述するハッシュによる改ざんチェックを行う事で検出することが出来るようになります。

■ハッシュ値チェックについて

ハッシュ値とは、データを渡すとそのデータからユニークな短いデータを作る技術です。
同じデータを渡せば、常に同じハッシュ値が出てきますが、違うデータになれば違うハッシュ値になります。

画像11

このデータとハッシュをペアにしてしまって持っておきます。
そして、もしデータが改ざんされてしまった時は、データから計算するハッシュ値とあらかじめ覚えておいたハッシュ値と違うのでデータ改ざんを防ぐことが出来るというわけです。

画像12

しかし、データとセットを両方を書き換えられてしまう可能性があります。
そのため、このハッシュ値を出すための情報はチーターにばれないように気を付けないといけません。そのためCRCなどのハッシュ計算ではなく、HMac-SHA1など鍵を利用するアルゴリズムを選択しましょう。

※暗号化と改ざんチェックは別物です。
暗号化をしていても、中身がわからないまま適当に書き換えてうまく行ってしまうという事も十分に考えられます。そのため、攻撃に対して有効ではありません。

3.メモリ領域の書き換え・参照

ゲーム進行中のHP値などはメモリ上にあります。このメモリ上にあるHPの数字を増減をしていくことでダメージや回復などを行っています。

画像8

図のメモリイメージでは16進数で表記しています。右側の数字が私たちが良く知っている10進数になります。
そして、メモリのどこかに最大HPの212、現在のHPの160が入っていることになります。
もしここのメモリ上の160を212に書き換えてしまったらどうなってしまうでしょう…?

画像10

もしHPのメモリを212に書き換えられてしまった場合には、HPが全回復してしまいます。

チートを行う人は、まずHPの値である160という数値がメモリ上にあるかを探していき、ヒットしたら任意の値に書き換えてしまうといった手順で攻撃してきます。

対策としては、大事な数字などはメモリ中に直接置かず、メモリ上に暗号化した形で置き、使うたびに復元して利用するという形です。
その時に XORと言った演算を使うだけでも十分な効果があります。

例えば下記のようなコードです。

class EncryptInt{
 const int key = 0x2f4f7fe5;
 int value;
 public int setValue(int v){ value = v^key;}
 public int getValue(){ return value ^ key; }
}

■XORについて
XORは排他的論理和という演算なのですが、2進数にして行われる演算になります。 
これの面白い性質が xorでグチャグチャにした値に対して、再度同じ値でXOR演算をすると元の値に戻るのです。

画像10

この性質を利用する事で、簡易的な暗号化・複合化が速い処理で実現可能です。

4.クライアントが送出するデータを書き換え・クライアントが送信していないデータを送信

インターネットに送るデータというのは、実は様々な装置を経由して相手先に届けられる形になっています。
例えば家からどこかのサーバーに送られるデータは、家のルーターを経由してからインターネットの外にデータを送信されます。

もし普通のルーターじゃなくて、カスタムなルーターであればデータ中継をそのまませずに中のデータを閲覧したり、書き換えたりと言ったことが行われてしまいます。
昨今ではHTTPは通信できずにHTTPSで通信させるようにするのは、フリーWifiスポットを装った悪いルーターを置いて、通信データ閲覧・書き換えを防ぐためにセキュアなHTTPS通信を強制させています。

話が少し逸れてしまいましたが、インターネットに流れるデータは閲覧もされるし書き換えもされる可能性がある事を考慮しないといけません。

ハイスコア送信するときにもデータを書き換えられるなどが想像できますが、この攻撃色々な所に使えます。
マルチプレイゲームの対戦でもこの不正は利用できます。

作り方によっても異なりますが…、クライアント側でキャラクターの移動処理や状態の管理をしているケースの場合、下記の図のようにサーバーに対して自身のキャラクターの位置情報やステータスを送信しています。
他プレイヤーを攻撃したときにもサーバーに「この人攻撃しました」というメッセージを投げて、そのプレイヤーに実際の処理をしてもらうという事をやったりします。

画像14

この時にサーバー側に「この人攻撃しました」というデータを送るのですが、ここのデータ送信を悪用されてしまう可能性があります。

この時にダメージ量なんかをつけていた時に、そのダメージ量のデータを書き換えてしまうといった悪用の可能性があります。
データ改ざんされてしまう事が問題ですので、ハッシュ値などの改ざんチェックを行う事で対策になります。

■同じデータを何度も送ってしまう可能性を考慮
しかし、他の可能性も考慮する必要があります。
それはゲームじゃないアプリケーションからネットワークにデータが送信されてしまう可能性です。
中継機がデータを保持して置いて、それをまた後で送信しなおすといった形で実現できてしまいます。

例えば、「この人攻撃しました」というメッセージをそのまま何回かサーバーに送信してしまう事が出来ます。
そのようにすると手元で攻撃していないのに、攻撃されたと認識されてしまったりします。
データの改ざんを防ぐだけでなく、同じデータを何度も送信された事に対しての対策も行わないと、こういった攻撃を受けてしまいます。

■課金のチート周り

他にも送信の過程でデータを弄れるので、課金回りで悪いことをたくらむ人もいます。

モバイルゲームの課金では、AppleやGoogleから購入を証明するレシートが発行されて、そのレシートと購入内容をサーバーに伝える事でアイテムを付与を実現しています。

画像16

しかし、この部分でも悪いことをする人はいるものです。
石100個しか買っていないレシートや、他のアプリ向けに使ったレシートとセットにして石1000個購入したと伝えてくる事で、石1000個を不正に入手しようとしてきます。

レシートには購入した製品が何であるかも書いていますので、「レシートとして正しいか?」というチェックだけで通さずに、購入した内容物についてもちゃんと確認する事で防げます。サーバー側の作りが弱いとこのチートが行われてしまい、不正に課金されてしまう事になってしまいます。

5.クライアント端末が受信するデータを書き換え・参照

送信と同じように、サーバーから受信するデータも閲覧・改ざんの機器にさらされています。

サーバーから受信したデータを書き換えることが出来ます。例えばモバイルのゲームではユーザーのセーブデータをサーバーから取り寄せます。
この取り寄せ中のデータを書き換えてしまう事で持っていないはずのデータを持つことも出来てしまいます。

画像14

こういったことの対策のためにも、やはりハッシュ値による改ざんチェックが有効です

また、他にも途中の経路データが閲覧されている可能性があります。
例えばFPSやTPSなどの対戦ゲームでデータを閲覧することで、壁に隠れて見えないはずのプレイヤーの位置情報がわかるなどが起こってしまいます。

画像15

覗かれてもわからないように暗号化をする等の対策をする形にはなります。

ここまでのまとめ

クライアントの実行ファイル・メモリ・ストレージに保存された内容・通信と言った形で様々な箇所が狙われてきました。
そして、データを見られないための暗号化、書き換えられたことを検知するためのハッシュ値による整合性チェックなどが有効というお話をさせていただきました。

しかし、結局…

このようにクライアントと通信は攻撃されてしまうので、計算処理をサーバー側に寄せてしまうの一番の対策になります。
例えばガチャ何かは抽選処理がサーバーで全て行われるのも、クライアント側で処理してしまっては、攻撃のリスクがあるという事も大きな要因の一つになっています。

また対戦ゲームなんかの場合もコストとの相談ですが、クライアントはキー操作だけ送信してしまい、キャラクターの移動処理、当たり判定、ダメージ計算処理などを全て行ってしまうサーバーに処理を集約させる方法もあります。(こちらのマルチプレイに関する記事も参照してください)

基本的に、端末側にあるものはいじられるもの、通信ものぞかれる、弄られるものと言う形になってしまいます。

ある意味チート対策の究極系はStadiaのようなクラウドゲームです。
クラウドゲームでなら、手元の端末はキーを送るのと、サーバーでレンダリングされた映像を出すだけです。チートの余地は殆どありません。

チート周り珍事件

チート周りで起きたチョット珍しいニュースとかを紹介したいと思います。

■チート疑惑を配信で晴らす!

あまりに上手過ぎたプレイヤーがチート疑惑が浮上しました。
しかし、実際にプレイする様子を映像で配信して疑惑を晴らしました。

■最強のチーターは誰だ!チーターしかマッチングしない地獄

チーターをゲームから追放(BAN)するのが、チーターへの対策として有効な手段ですが、このゲームではチーターをBANを保留して、チーター同士しかマッチングしないようにしました。
チーター同士で最強のチーターを決める戦い…まるで蟲毒ですね。

■チートは止めましょう!by 警視庁

チートツールを提供する業者がいたりします。ツール提供する業者だけでなくRMT(リアルマネートレード)を目的にチートを行う業者もいます。
そういった業者やチートをした本人が訴えられたり、時には逮捕・罰金がある等の事件にもなります。そういう事で警視庁からもお知らせが出ました。
チート!ダメ絶対!

最後に

チートは色々な所を攻撃してきます。基本的に弱い所を見せるとソコをつくという感じで嫌らしくやってきます。また一部防ぐのが技術的な困難なモノもあります。(本当にうまくて、壁の隙間から見えるキャラを見逃さないのか、それともウォールハックしているのかは判別しがたいです…)
とは言え、ノーガード戦法なんてものはないので、地道に対策していくしかないです。

あとチートはダメ!!!!

実は昔 全ゲ連という所で話した内容を少しアップデートして記事化した感じでした。
スライドはコチラ。




この記事が気に入ったらサポートをしてみませんか?