2009年5月26日

Mafia Wars: 解析 その3 (訂正、そして...)


解析シリーズ(?)の第三回目です。
今回は、初回の解析記事前回の解析記事の訂正と、改造に関して紹介したいと思います。

初回の記事で、ゲーム上表示されないパラメータの attack, defense と attack_strength, defense_strength の説明に関して、逆に書いてしまいました。

あと、前回の記事で、V1.11 では、V1.0 にはなかったデータのやりとりがある。と書きましたが、これは間違いでした。
あの時取得したパケットは、V1.11 をインストールした直後に行われたやりとりでした。
つまり、通常やり取りしている起動時の通信は、V1.11 でも V1.0 でもほとんど変わりありません。ただニュースティッカー(動作が重い原因と疑われている、トップ画面の下の不要なニュース)だけは V1.11 から追加されたものになります。

さて、既に私を仲間に加えてくれた方はお気づきかと思いますが、一気にとんでもなくレベルが上がってしまいました...
技術的な興味からと、だんだんやることがなくなってきたので、そろそろいいかな? という気持ちから、悪魔の囁きに乗っかって、ちょっといたずらしてみた結果です。

まずは、右上のキャプチャ画面をご覧下さい。なんか普通と違いませんか?
そう、名前の後ろに数字が二つつくようになっています。これは戦闘時に重要になる、(上記で訂正した) attack, defense などのパラメータを、データを操作して名前の後ろにくっつけてみた結果です。
一つ目の数値が attack_strength と defense_strength の合算、二つ目は attack, defense の合算です。
これでパトロンがひと目でわかるようになりました。

操作できるデータは、サーバから送られてくる全てのデータになりますので、前回の解析記事の最初に列挙したデータの全てを好みの値に変更することが可能になります。

通常、この手のネットワークゲームは、データの改竄ができないようにガードをかけてあるものです。確かに Mafia Wars でも、touch からサーバに送出するデータに関してはチェックサムが付加されていて、改竄がかなり困難でした。
しかし、サーバから受信するデータに関しては何のガードもかかってないんですねぇ... これはネットワーク対応ゲームとしては致命的な気がします。
# 片側は出来てるんだから、もう片側もガードするのは大した話じゃないはずなのに...

というわけで、私が改造した仕組みを簡単に触れます。
まずは、構成ですが、

touch - proxy サーバ - 変換サーバ - オリジナルサーバ

という形で、間に二つのサーバを挟んで本物のサーバとの間に割り込みます。touch 側には proxy の設定をして、自前の proxy サーバを向くようにします。
# 実際には、二つのサーバは同じマシンで問題ありません

私の場合は、proxy サーバに delegate、変換サーバに apache を使用しました。
delegate は既に稼働中でしたし、apache も、既に動かしているサーバに virtual host 設定を追加しただけなので、一番面倒なサーバ立ち上げが省けたのはラッキーでした。
変換サーバのコンテンツは CGI だけになります。Mafia Wars では PHP をサーバに使用していましたが、個人的にあまり PHP が得意じゃなかったので、中身は Perl で書いちゃいました。
# 名前が「見習い Rubyist」なのに Perl かよ。と言われそうですが...

CGI での処理は大きく二つ。
前述の通り、touch からのデータは改竄できないので、そのままオリジナルサーバに転送する部分と、返ってきた値を(必要に応じて変換して) touch に転送する部分、になります。
サーバから送られてくるデータは JSON 形式になっていますが、JSON パッケージを使えば簡単に Perl で扱えるようになります。
# ヘッダにちゃんと text/json と書いてあったのに、データの形式が JSON であることに気づくのにだいぶかかりました。(JSON 自身も ajax にちょっと興味を示した時に見た以来で完全に忘れてました...)

例えば前述の、名前にパラメータを付加する変換は、
$res = $ua->request($req);
$dat = JSON->new->decode($res->content);
foreach $user (@{$dat->{data}->{friends}}){
$gidref = $user->{game_data}->{"gid_$gid"};
$fp = $gidref->{attack_strength}+$gidref->{defense_strength};
$ss = $gidref->{attack}+$gidref->{defense};
$gidref->{name} .= "+$fp+$ss";
$gidref->{pic_url} = "" if $gidref->{pic_url};
}
てな感じでやりました。

まぁ、簡単に書きましたが、いろいろ設定をいじったりスクリプトを書いたり、動かしてパケット見て変更してを繰り返したりして、と悪戦苦闘したので、このブログの更新も滞ってしまいました。

というわけで、全世界 2000万以上のユーザがいる人気ネットゲームの割には、見習いエンジニアが改造できてしまうくらい脆いということが露呈してしまった Mafia Wars の改造結果のご紹介でした。

4 件のコメント:

  1. ちょっと試してみたいのですが、設定等参考になるところはありませんでしょうか?

    返信削除
  2. すみません情報があまりにもありませんので追記します。。
    一番わからないのが、apacheの変換サーバについてで、HTTPリクエストは透過し、それに対するデータはperlで変換するという設定?です。CGIについての知識がなさすぎですかね?w
    iphone--無線LAN-USB--[delgate--(apache+perl)]--INTERNET
    という環境です。

    返信削除
  3. ご返答が遅くなりました。(_ _)
    まずは apache まで来てるか? ですかね。
    apache まで来ていれば、access-log や error-log にいろいろ情報が残るので参考になります。
    そこができているのであれば、次はオリジナルサーバへの転送ですが、ここはちょっと苦しみました。
    POST のリクエストなのですが、QUERY 部分(URLの?以降の部分)とデータ部分の両方を含んでいるので、それらを両方転送する必要があります。
    大ヒント:
    my $q=CGI->new;
    $body = $q->param('POSTDATA');
    $query = $ENV{'QUERY_STRING'};

    作る過程も楽しいものですから、いろいろ試してみて下さい。

    返信削除
  4. いえ、お返事ありがとうございます。
    あぅぅ、インストールはしたもののまだ何もやっておりません。。。
    wiresharkでパケット見てるだけでも楽しめましたwww
    これをiphoneの内部だけでできたら最高ですよねw
    3Gのパケットをうひゃーw
    なかなか時間がとれずすぐには実施できませんが、いろいろ試してみます。
    失礼いたします。

    返信削除