PC9801-VXと改造コード
はじめに
iPX砂子です。前回から随分と期間が空きました。当番に関係なく記事のネ タがあるなら書いたほうが良いかもしれません。
前回はEmacsネタだったわけですが、丁度その頃、未来技術遺産の発表があ りました。PC-9801も記憶遺産に選ばれました。
PC9800シリーズの思い出
私の父親がPCが好きで家にはPC9800シリーズが何台かありました。私が中学 生位の頃の話です。5インチのフロッピーディスクドライブが内蔵されてい るようなやつです。確か型式はPC-9801VXだったきがします。まあ、世間で はWindows95が発売されたころなのでその当時でさえ”旧式”ではありました。
当時はTVゲームが好きでプレイステーションでRPGを主にプレイしていまし た。なにかの雑誌で改造コードなるものをみて、プロアクションリプレイを 購入してRPGのキャラクターのステータスを改変したの覚えています。
少しすると雑誌に掲載されている改造コードを使うだけでは物足りなくなり、 自ら改造コードを作成できないと考えはじめました。プロアクションリプレ イのカタログにPCと繋ぐことでプレイ中のTVゲームの解析が行なえるような やつです。父親に相談すると家にあるPCが対応しているので設定までしてく れることになりました。
購入した拡張ボードをPCの拡張スロットに設定してもらい、拡張ボードと プロアクションリプレイをフラットケーブルで接続してプレイステーションの メモリを解析するわけです。 設定が完了したPCとゲーム機で画面上に表示されている数字を変更できない か試行錯誤していました。
なにをやっていたのか?
今の知識で当時やっていたことを説明するならば、メモリに格納された値を 番地指定で更新していたと表現できるでしょう。 改造コードとは指定した メモリアドレスにある値を編集するものだったようです。
おそらく改造コードの作成作業とはプロアクションリプレイと繋げたゲーム機 のメモリをプロセスメモリエディターで編集していたのではないでしょうか?
具体的な作業
あの頃にやっていた作業をjavaのコードで再現してみましょう。
Characterクラスで名称、HP/MPを定義する。FF7のキャラクター"クラウド" をインスタンス化する。そして、そのインスタンスをバイナリシリアライズ し、ファイルに出力する。この出力したファイルを書き替えてキャラクター “クラウド"のHPを任意に変更できないだろうか?
コマンドライン
javac FF7.java
rem シリアライズ
java FF7
rem 書き換え
rem デシリアライズ
java FF7 a
Deserialized Character...
Name: CloudStrife
CurHP: 101
MaxHP: 223
CurMP: 50
MaxMP: 80
ソースコード
参考文献にあるTutorialPointのシリアライズのページのコード参考に一部書き換え。
import java.io.*;
public class FF7 {
private static class Character implements java.io.Serializable {
public String name;
public int cur_hp;
public int max_hp;
public int cur_mp;
public int max_mp;
}
public static void main(String [] args) {
String name = "CloudStrife";
if(args.length == 0){
Character c = new Character();
c.name = name;
c.cur_hp = 101;
c.max_hp = 223;
c.cur_mp = 50;
c.max_mp = 80;
try {
FileOutputStream fileOut =
new FileOutputStream(name + ".ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(c);
out.close();
fileOut.close();
System.out.printf("Serialized data is saved in " + name + ".ser");
}catch(IOException i) {
i.printStackTrace();
}
}
else{
Character c = null;
try {
FileInputStream fileIn = new FileInputStream(name + ".ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
c = (Character) in.readObject();
in.close();
fileIn.close();
}catch(IOException i) {
i.printStackTrace();
return;
}catch(ClassNotFoundException ce) {
System.out.println("Character class not found");
ce.printStackTrace();
return;
}
System.out.println("Deserialized Character...");
System.out.println("Name: " + c.name);
System.out.println("CurHP: " + c.cur_hp);
System.out.println("MaxHP: " + c.max_hp);
System.out.println("CurMP: " + c.cur_mp);
System.out.println("MaxMP: " + c.max_mp);
}
}
}
バイナリエディタでCloudStrife.serを開きます。すると下図のような画面 になります。(図はEmacsのhexl-mode)
コードでHPは101(dex)に設定してあるため、65(hex)を探します。しかし、 65(hex)は複数あるためどれがHPを表すものかは特定できません。そこでソー スコードを編集してHPを110にして再度シリアライズしてみます。それをバイ ナリエディタで前回のシリアライズしたものと比較します。
前回65(hex)であった4箇所のうち1箇所が6e(hex)になっています。どうもこの 箇所がHPを表すアドレスのようです。この箇所をff(hex)に変更して変更して 、デシリアライズしてみます。
rem デシリアライズ
java FF7 a
Deserialized Character...
Name: CloudStrife
CurHP: 255
MaxHP: 223
CurMP: 50
MaxMP: 80
成功です!!!プログラムを編集したりせずにバイナリデータの変更が行なえま した。こんな感じでキャラクターのステータスをMaxにしたりしてましたね。
結び
上記のjavaでの作業は改造コードというより、セーブデータの書き換えに近い です。しかし、作業そのものはほとんど同じなので今回はシリアライズしたデー タの編集で代用しました。プロセスメモリエディタのインストールなどが煩わ しかったという理由もありますが。。。
子供時代にやったことに限らず、過去の作業を振り替えり現在知っている知識 で当時の疑問などを解決できるかを試してみると発見があるやもしれませんね。
しかし、こんなことやってたからプログラマーになったんだろうな。。。