Archive

Archive for 2013年5月

FedoraでISC-DHCPDのリーステーブルを表示する

ちゃんと調べればすぐ分かりそうなのに面倒になってログファイルから切り出したりしていましたが、
/var/lib/dhcpd/dhcpd.leases
に書いてあります。大雑把に見るだけなら
$ grep 192.168.1. dhcpd.leases | sort | uniq
とかやるといい感じでアドレスの部分だけとれます。(時間切れのものも載っている?)
MACアドレスとか表示するならちゃんとパースする処理が必要か。
{}がネストされないのでパーサは雑に書いても大丈夫そうですが。

カテゴリー:GNU/Linux

サブ機をFedora18にしようとした

fedupでアップグレードした結果まるごとぶっ壊れた。
fedora17時代にtexlive2012のリポジトリを追加していると一部依存関係がおかしくなったりするのは知っていたのだが・・・

・gnome3が上がってこなくなった
  どっかの依存関係が引っ張ってきたライブラリのバージョン不整合。
  というか、思いっきりfc20って書いてあるんですがそのパッケージ。
・firefox、chrome限定でなぜか日本語入力が効かなくなった
  *_IM_MODULEを確認したりibusに設定したが駄目。
  新しくnirendaのアカウントを作ったがやっぱり駄目。
・いろいろアイコンがおかしい
  gnomeのicon関係パッケージを入れなおしたらちょっと良くなった
  ええ、一回gnomeまるごと消して入れなおしても駄目でしたとも。
・extensions.gnome.orgからextensionが入らなくなった
  バージョンが古いと言われた。クリーンインストールしたら治った。なぜだ。

というわけでhome以下を一晩かけてまるごとeevee(メインサーバー)にrsyncしてからサブ機クリーンインストール。
ノートPCの時は特に問題なかったんだけどなぁ。

ちなみに、旧環境ではclearlooksの枠を使っていたのですが、再インストールしたらなくなりました。
gnome-themes-legacyをインストールすると復活します。

カテゴリー:GNU/Linux

「ポケモンを呼ぶ笛」でイーブイを出してみたかった

ので検証してみた。
やり方は雫月さんのとこを見てください。
画像付きで詳しい説明があります。

まずは原理から。とはいえ完全には把握できていないので推測もかなり。
例によって文字列系バッファオーバーフローです。内部的にやってることは完全にミュウを釣るバグと同じ。

1.名前のむちゃくちゃ長いアイテムを使う
2.使おうとした時に(?)名前のデータがどこかにコピーされる
3.勢い余って「メニューを開いた時に後から戻すために保持しておいた本来のマップデータ」までコピーし始める(?)
→0xCE59(画面の特定マスにおけるチップ情報)の内容が0xD036(ここに書くと該当番号の戦闘がはじまる)にコピーされる
4. うまいこと0x50で終端していれば止まり、メニューを閉じると戦闘が始まるが、終端していないとそのまま壊し続けて死ぬ
(セーフのチップと呼ばれている物が0x50に該当するもの。「木の左下」など。)

が、0xCE5A以降に0x50があっても死ぬ場合があります。何かしらの条件でjmp先が変わり、未定義のオペコードに行ってしまう模様。(フリーズするパターン)
0x50のチップが0xCE5Aよりも前にある場合も当然失敗します。(何も起こらないパターン)

さて、肝心のチップデータを覗いてみた結果、
0x00-0x5Fまではだいたい普通のマップチップなのですが、
0x60-0x7Fまでは ABCDEFGHIVSLM:いう「」『』 などと文字が並んでいる。
さて、気になるイーブイの番号は?
→0x66
理論上可能、現実的には不可能といったところか。

・名前の長いアイテムを使ってフリーズせず
・66 50の順にマップチップが並んでいる
条件を満たすバグマップに入ることができれば可能かもしれませんが。
道具の31番目で座標をいじくって飛ばせばあるいは。

・・・うん、普通にイーブイの化石作るわ。

カテゴリー:その他, セレクトバグ

13番目あたりは怪しい

完全にメモです。
なんかおかしいなーとは思っていたけれども、やはり道具の13番目セレクトあたりの挙動は実際と異なっていたようです。
1回目は確かに似たような挙動をしますが2回目はただ戻るだけでなく、ステータスだけ戻して種族が戻らなかったりするので何らかの力が働いている模様。
要調査。

カテゴリー:セレクトバグ, 未分類

状態異常フラグと設定フラグ

手持ち状態異常フラグ

  • 下3bit: ねむり 同時に残ターン数も示す
  • 4bit目: どく
  • 5bit目: やけど
  • 6bit目: こおり
  • 7bit目: まひ
  • 8bit目: 未使用? ポケセンで回復する、戦闘開始時のボールは黒くなる、表記上は「ふつう」になる。

謎の8bit目。戦闘中は何かに使っているのかもしれないと思ってステータスフラグを0x80にして戦闘に入ったらボールが黒いけど状態が「ふつう」、
ターン経過でも何もおこらない状態となりました。

今わかっている設定関係フラグ

  • 下4bit: はなしのはやさ 0001:はやい 0011:ふつう 0101: おそい
  • 6,5bit目: サウンド設定(ピカチュウ限定) 00: モノラル 01: イヤホン1 10: イヤホン2 11: イヤホン3
  • 7bit目: 戦闘タイプ 0: いれかえ 1:かちぬき
  • 8bit目: 戦闘アニメ 0: みる 1:みない

5bit目と6bit目は不明。今のところずっと00なので未使用なのか?

面白いのが下4bitを使っている「はなしのはやさ」設定。
本来3段階なので2bitあればいいのですが、これはどうやら「文字ごとのウェイトを入れる時間」のようです。
なので、ここを0000にしてやるとすべての文字が一瞬で表示されるようになる超高速モードになります。逆に1111に設定すると超低速に入ります。鬱陶しいわ。
ただしその状態で「設定」を開いた瞬間に0011の「ふつう」にリセットされてしまいますが。
メモリとしてはバッジ所持フラグの一つ前なので、下4bitが0になるようなアイテムの「種類」をバッジ所持フラグ個数分おいてやれば良いのではないかと。
多分どうぐの26番目に回復の薬255個(みる、いれかえ、全バッジ所持)を置いたりするとセレクトバグで再現できるはず。
設定を「みない、いれかえ、超高速」の組は普通に手に入らないアイテムなので一工夫必要です。

追記: 2013/7/27
ピカチュウ版では設定の5,6番目のbitがサウンド設定に該当するようです。追加しました。
モノラル、イヤホン1、2、3がそれぞれ00、01、10、11になります。
よって、青まで?(実は緑とピカチュウしかやっていないので青にサウンド設定があるかは知らない)では、bit5,6は未使用ということで良さそうです。
ピカチュウ版のプリント設定に関しては、設定をいじってもここの数値が変わらないので別の場所にありそう。

「ボックスから引き出したレベル」とは

初代ポケモンの手持ちポケモン領域には頭から3byte目に「ボックスから引き出したレベル」のデータが入っています。
これとは別に後ろから11byte目には「現在のレベル」のデータを保持しています。おそらく使われていない前者はなんのためのものなのかずっと疑問だったのですが、ボックス領域のデータ構造をみていて納得。
実際にプログラムを読んだわけではないので裏は取っていません。そのうちやりたい。

まず手持ちデータ44byteをCの構造体であらわしたものがこれ。

unsigned char species; // 種族
unsigned char current_hp[2]; // 現在HP
unsigned char box_level; // 引き取りレベル
unsigned char status; // 状態フラグ
unsigned char type[2]; // タイプ
unsigned char item; // 初代のレア度 金銀の持ち物
unsigned char waza[4]; // わざ
unsigned char trainerid[2]; // ID
unsigned char exp[3]; // 経験値
unsigned char hp_exp[2]; // HP努力値
unsigned char atk_exp[2]; // 攻撃努力値
unsigned char def_exp[2]; // 防御努力値
unsigned char spd_exp[2]; // 素早さ努力値
unsigned char spc_exp[2]; // 特殊努力値
unsigned char ab_pot; // AB個体値
unsigned char sc_pot; // SC個体値
unsigned char pp[4]; // 上位2bitはポイントアップ使用回数 下位6bitが実際のPP
unsigned char level;
unsigned char max_hp[2]; // 最大HP
unsigned char atk[2]; // 攻撃
unsigned char def[2]; // 防御
unsigned char spd[2]; // 素早さ
unsigned char spc[2]; // 特殊

つぎにボックスデータ33byteを同様にCの構造体であらわしたものがこれ。

unsigned char species; // ポケモンの中身の種別
unsigned char current_hp[2]; // HP現在値
unsigned char level; // レベル
unsigned char status; // ステータス異常フラグ
unsigned char type[2]; // タイプ
unsigned char item; // 持ち物
unsigned char waza[4]; // 技
unsigned char trainerid[2]; // ID
unsigned char exp[3]; // 経験値
unsigned char hp_exp[2]; // HP努力値
unsigned char atk_exp[2]; // 攻撃努力値
unsigned char def_exp[2]; // 防御努力値
unsigned char spd_exp[2]; // 素早さ努力値
unsigned char spc_exp[2]; // 特殊努力値
unsigned char ab_pot; // AB個体値
unsigned char sc_pot; // SC個体値
unsigned char pp[4]; // PP

名前や親名は一番最後にまとめて入っています。なぜだろう。

ほぼ同じ構造ですがボックスデータはレベル、最大HP、各ステータス実数値の合計11byteが削られています。これらはボックス内では必要ないデータなので1匹でも多くボックスに入れるために削られているのでしょう。
(セーブ容量に関してはポケモンストーリーという本に苦労話が書かれていたと思います。読んだのが10年くらい前なのでよく覚えていませんが。今度また借りてこよう。)

さて、この構造はほぼかぶっているので手持ちからボックスへは頭から33byteをコピーすればよさそうです。
この時現在のレベルは失われますが、経験値から再計算できるので問題あり・・・ました。
ボックスから引き出す時の一覧にはレベルもあわせて表示されます。
おそらくこのために預けたレベルを頭から3byte目に記録します。

引き出す時は逆に、ボックス側から33byteをコピーして、破棄したステータスを再計算して残り11byteを埋めます。これが「バグったステータスのポケモンをボックスに預けると正常化される」理由でしょう。
ボックス内でのレベルは放置され、そのまま残ったままになるわけです。

・・・どーしてそこをレベル領域にはしなかったんだろうなー

余談:容量とボックス
ボックスにも手持ちと同じように「見かけ上の種族」領域が別にあります。なので見た目と中身が一致していなくても両方が保持されます。
(育て屋のデータ領域はまだ見ていませんが、挙動から推測すると多分育て屋領域には見かけ上の種族領域はないと思います。)
ところでその見かけ上の種別領域1byteと現在HP2byte、残りPPの数値部分6bit x 4(上位2bitだけはポイントアップ領域なので技4つ分をまとめて1byteにおしこむ)、状態異常領域1byte、タイプ領域2byteを削れば一匹当たり8byte、ボックスあたり240byteあくのであと6匹くらい入ったんじゃないかな・・・
きりよく30にしたかったのかもしれませんが。

5/9追記:タイトルを書き忘れていたのを修正

2015/5/25追記

ようやく実証実験しました。というのは簡単で、経験値とレベルが一致していないポケモンを作ってボックスに預けて引き出すだけ。
経験値的にはLv100のポケモンのレベルをLv99に書き変え、ボックスに預けるとレベル表示は「Lv99」となります。
そのポケモンを引き出すとレベル表示は「100」になります。データの3バイト目は99(0x63)でした。

よって、3byte目については以下の通りです。
・ボックスに預けるとき、現在ステータスのレベル情報を3byte目にコピーする。
・ボックス中でのレベル表示時は再計算せずに3byte目のデータをそのまま表示する。
・ボックスから引き出すとき、レベルは経験値を元に再計算される。3byte目はそのまま取り残される。
・3byte目は実は「ボックスから引き出した時のレベル」ではなく「ボックスに預けた時のレベル」だった。(通常はこれらは一致する。)

セレクトバグでセーブが壊れる理由を推測

Memory mapped IOでセーブ領域がメモリの一部になってるため、そこに書き込んじゃってるんじゃないかなーと思ってます。
Pokémon Bug Litchesゲームボーイの仕様によれば、
初代ポケモンではメモリアドレス0xA000から0xBFFFまではカートリッジRAMらしいので、この範囲に書き込んでやればセーブ領域に書かれるわけです。

ただ、セレクトバグでいじるアドレスは主に0xD124(手持ちの見かけの種族)以降なので、
普通にセレクトバグを起こすだけでは「これより後ろ」の領域にしか書くことはできないはずです。
バッファオーバーフローの最後の良心というべきところでしょうか。
あふれたところより前に書き込むためにはもう一手間かけてやる必要があります。x86ではたまたま「スタックに確保したバッファの後ろにリターンアドレスがある」ため任意のコードが実行できてしまったわけです。
今回のような場合、x86のようにリターンアドレスを変えてやりたい放題、というわけにもいかないため0xD123以前を書き換えることは「道具の-1番目」ということができない以上不可能なのです。
ちなみに、道具名やニックネームの作業用メモリもセーブデータ領域より前にあるので、「道具の名前がオーバーフローしてセーブデータ領域を上書きする」ということもなさそうです。
(原理上、主人公の名前はセレクトバグで書き換えることはできないはず。できる方法を知っている方は教えて下さい。)

そこで終わらなかったのがバグアイテム。
ほぼ推測ですが、アイテムの種類とサブルーチンの飛び先のエントリポイントの対応表があり、
正常なアイテムは正常なサブルーチンのある場所を指しているのですが、
バグアイテムはそのエントリポイントのアドレスが妙なところを指していて、そこを実行すると例の領域に書き込んでフアイルのデータがこわれてしまうのではないかな、と。
例えば、セーブルーチンの途中に飛んでしまうような事があれば間違い無く壊れるでしょう。ただし確率としてはけっこう厳しいのでよっぽど運が悪くないとそんなことにはならないと思います。

可能性が高いのは、VRAMはセーブデータ領域の直前にあるので、描画関係のプログラムが行きすぎてセーブデータ領域を上書きするということ。
・マップ範囲外に出たり妙なマップに飛んだりするとありえないマップを描画しようとして画面外=セーブデータ領域に書き込むことがありえる?
・文字列の描画処理で(それこそx86のgetsのように)書きたい放題してVRAMからはみ出た位置に文字を書いてしまうことがありえる? ・・・あれ、バグった文字列表示したりするの実はやばいんじゃ・・・
どちらにせよ、現在進行形で画面が乱れつつあるうちに電源を切ればセーブは無事という可能性も。目視で確認できるんだろうか。

というわけで誰かデバッガで追ってみてください。