台差と時間差
2019.04.13
さてわりといきなりガチなDIVA Arcadeのお話になりますが、
このゲーム、
「台差」 と 「時間差」
と言われるものの存在が(ほぼ確定事項として)噂されています。
詳しくはこの辺の超プロい人の説明参照。
Project DIVA Arcadeの正しい遊び方と間違った遊び方 Part 2 - こすでぃ~さんと音の出るゲーム
http://cosdivalove.hatenablog.com/entry/2017/12/20/085017
まあつまりどういうことかというと、
・台差=筐体によって点数が変わる
・時間差=なんと、同じ筐体でもやるたびに点数が変わる
というような話です。
っていうか条件が同じだからってプレイするたびに同じ点数出る方が人としておかしいだろ!
これを突き詰めるためにDIVAのコードを見たかった・・・。
で、いきなりコードですが、
14012D7DB: movss xmm8,dword ptr [rbx+012A6Ch] ;[rbx+012A6Ch]=0.03
14012D7E4: comiss xmm6,xmm8
14012D7E8: ja 014012DAAB ;xmm6が0.03より大きかったらjmp
14012D7EE: comiss xmm6,dword ptr [rbx+012A70h] ;[rbx+012A70h]=-0.03
14012D7F5: jb 014012DAAB ;xmm6が-0.03より小さかったらjmp
14012D7FB: mov r14d,ecx ;COOL(r14d=ecx=0)
14012D7FE: jmp 014012DAF8 ;判定確定
-----
14012DAAB: comiss xmm6,dword ptr [rbx+012A74h] ;[rbx+12a74]=0.07
14012DAB2: ja 014012DAC5 ;xmm6が0.07より大きかったらjmp
14012DAB4: comiss xmm6,dword ptr [rbx+012A78h] ;[rbx+12a78]=-0.07
14012DABB: jb 014012DAC5 ;xmm6が-0.07より小さかったらjmp
14012DABD: mov r14d,1 ;FINE(1)
14012DAC3: jmp 014012DAF8 ;判定確定
-----
14012DAC5: comiss xmm6,dword ptr [rbx+012A7Ch] ;[rbx+012A7Ch]=0.1
14012DACC: ja 014012DADF ;xmm6が0.1より大きかったらjmp
14012DACE: comiss xmm6,dword ptr [rbx+012A80h] ;[rbx+012A80h]=-0.1
14012DAD5: jb 014012DADF ;xmm6が-0.1より小さかったらjmp
14012DAD7: mov r14d,2 ;SAFE(2)
14012DADD: jmp 014012DAF8 ;判定確定
-----
14012DADF: comiss xmm6,dword ptr [rbx+012A84h] ;[rbx+012A84h]=0.13
14012DAE6: ja 014012DAF8 ;xmm6が0.13より大きかったらjmp
14012DAE8: comiss xmm6,dword ptr [rbx+012A88h] ;[rbx+012A88h]=-0.13
14012DAEF: mov eax,3 ;SAD(3)
14012DAF4: cmovae r14d,eax ;xmm6が-0.13以上なら代入
14012DAF8: 判定確定
と、なっています。
ここの処理に来る前段階として、xmm6にジャストタイミングとボタンを押したタイミングの差分が秒単位で入っているようです。
いや、単位が秒ってのを間違いなく確定できるほど解析してませんがまあおそらくあってるでしょう。
つまり、こう。
COOL: -0.03≦xmm6≦0.03
FINE: -0.07≦xmm6≦0.07
SAFE: -0.1 ≦xmm6≦0.1
SAD: -0.13≦xmm6≦0.13
※スライドは別判定
とりあえず重要なことは、VSYNCは判定には一切関係ないということ。
うむ、それは解った。ではなぜ台差とか時間差なんて物が発生するのか。
(1)ポーリングのタイミング
判定の基準クロックとポーリングの基準クロックが同じクロック源の場合に起こりえる。
どういうことかというと、ジャストタイミングに対して、いつポーリングするかにより、
筐体Aの場合、緑矢印で示された区間(1ポーリングタイム)にボタンを押した場合にしかCOOL判定にしかならない。
それに対し、筐体Bの場合、2ポーリングタイム分の間にボタンを押すと、COOLとなる。
この図であれば、COOL判定時間は2倍となる。実際にはポーリングはもっと細かいはず。
これはあくまでジャストタイミングに対してのポーリングタイミングのずれなので、曲の開始とポーリング開始が同期していれば、毎回同じ結果になる、
なので、「この曲のここは広い」というような現象が毎回確定で発生する可能性が高い。
※あくまで「曲の開始とポーリング開始が同期していれば」である。ここが同期しているかどうかは解析できていない。
(2)ポーリング周期
判定の基準クロックとポーリングの基準クロックが別クロック源の場合、そこには多少なりとも誤差が発生する。
これもどういう事かというと、筐体AではCOOL期間にどういうタイミングでもポーリングが3回行われないが、
筐体Bでは3回行われる場合がある。ということ。
なので、微妙な誤差でCOOL判定となる時間が1ポーリングタイム分変動する可能性がある。
この現象は(1)で説明した事象も考慮すると、必ず3回になるわけでもない。
つまり、「この曲のここは広い」というような現象が発生しうる、ということ。
どこが広いか、というのは、2つのクロックの誤差に依存する。
原発振クロックはだいたいマザーボードとかIOボードとかの水晶発振子なので、
こういう情報が参考になるかと。
[水晶振動子の基礎講座] 水晶振動子の電気的特性に関する用語説明
マクニカオンラインサービス
https://service.macnica.co.jp/library/127525
これもつまり何が言いたいかというと、
一般的な製造誤差は±30ppmとか。
それに対し、温度などでの特性変化は常温なら±3ppm。つまり、一桁違う。
なので、この誤差の挙動は、筐体(ボード)製造時に決定的に決まり、温特などでの変化は少ない。
この辺が筐体差の原因可能性が高そう。
温特での変化が時間差といわれる挙動になるんだろうか。
というわけで、ポーリング周期は誰が主導権を持っているのか。Nu側であればどのクロック基準なのか。
IOボード側に主導権がある可能性もある。
あと、プレイ開始とポーリングタイミングの開始は固定なのか。アドバタイズでもボタンの読み込みはしているが、プレイ開始時に一旦リセットされるのだろうか。
とか。
うん、その辺をもうちょっと詰めたい。
まあ正直言うと、ここを気にするほどのプレイヤースキルはありません。
ってか★10クリアできてない曲とかあるしね。
DIVAの1フレ以下の挙動を体感できて、ミドルとかファームレベルのソフトの心得があって、こういうローレベルな挙動とか理論的に考えらる人材とかどっかに居ませんかね・・・。(そんな奴イネーヨ
後日に続く
このゲーム、
「台差」 と 「時間差」
と言われるものの存在が(ほぼ確定事項として)噂されています。
詳しくはこの辺の超プロい人の説明参照。
Project DIVA Arcadeの正しい遊び方と間違った遊び方 Part 2 - こすでぃ~さんと音の出るゲーム
http://cosdivalove.hatenablog.com/entry/2017/12/20/085017
まあつまりどういうことかというと、
・台差=筐体によって点数が変わる
・時間差=なんと、同じ筐体でもやるたびに点数が変わる
というような話です。
これを突き詰めるためにDIVAのコードを見たかった・・・。
で、いきなりコードですが、
14012D7DB: movss xmm8,dword ptr [rbx+012A6Ch] ;[rbx+012A6Ch]=0.03
14012D7E4: comiss xmm6,xmm8
14012D7E8: ja 014012DAAB ;xmm6が0.03より大きかったらjmp
14012D7EE: comiss xmm6,dword ptr [rbx+012A70h] ;[rbx+012A70h]=-0.03
14012D7F5: jb 014012DAAB ;xmm6が-0.03より小さかったらjmp
14012D7FB: mov r14d,ecx ;COOL(r14d=ecx=0)
14012D7FE: jmp 014012DAF8 ;判定確定
-----
14012DAAB: comiss xmm6,dword ptr [rbx+012A74h] ;[rbx+12a74]=0.07
14012DAB2: ja 014012DAC5 ;xmm6が0.07より大きかったらjmp
14012DAB4: comiss xmm6,dword ptr [rbx+012A78h] ;[rbx+12a78]=-0.07
14012DABB: jb 014012DAC5 ;xmm6が-0.07より小さかったらjmp
14012DABD: mov r14d,1 ;FINE(1)
14012DAC3: jmp 014012DAF8 ;判定確定
-----
14012DAC5: comiss xmm6,dword ptr [rbx+012A7Ch] ;[rbx+012A7Ch]=0.1
14012DACC: ja 014012DADF ;xmm6が0.1より大きかったらjmp
14012DACE: comiss xmm6,dword ptr [rbx+012A80h] ;[rbx+012A80h]=-0.1
14012DAD5: jb 014012DADF ;xmm6が-0.1より小さかったらjmp
14012DAD7: mov r14d,2 ;SAFE(2)
14012DADD: jmp 014012DAF8 ;判定確定
-----
14012DADF: comiss xmm6,dword ptr [rbx+012A84h] ;[rbx+012A84h]=0.13
14012DAE6: ja 014012DAF8 ;xmm6が0.13より大きかったらjmp
14012DAE8: comiss xmm6,dword ptr [rbx+012A88h] ;[rbx+012A88h]=-0.13
14012DAEF: mov eax,3 ;SAD(3)
14012DAF4: cmovae r14d,eax ;xmm6が-0.13以上なら代入
14012DAF8: 判定確定
と、なっています。
ここの処理に来る前段階として、xmm6にジャストタイミングとボタンを押したタイミングの差分が秒単位で入っているようです。
いや、単位が秒ってのを間違いなく確定できるほど解析してませんがまあおそらくあってるでしょう。
つまり、こう。
COOL: -0.03≦xmm6≦0.03
FINE: -0.07≦xmm6≦0.07
SAFE: -0.1 ≦xmm6≦0.1
SAD: -0.13≦xmm6≦0.13
※スライドは別判定
とりあえず重要なことは、VSYNCは判定には一切関係ないということ。
うむ、それは解った。ではなぜ台差とか時間差なんて物が発生するのか。
(1)ポーリングのタイミング
判定の基準クロックとポーリングの基準クロックが同じクロック源の場合に起こりえる。
どういうことかというと、ジャストタイミングに対して、いつポーリングするかにより、
筐体Aの場合、緑矢印で示された区間(1ポーリングタイム)にボタンを押した場合にしかCOOL判定にしかならない。
それに対し、筐体Bの場合、2ポーリングタイム分の間にボタンを押すと、COOLとなる。
この図であれば、COOL判定時間は2倍となる。実際にはポーリングはもっと細かいはず。
これはあくまでジャストタイミングに対してのポーリングタイミングのずれなので、曲の開始とポーリング開始が同期していれば、毎回同じ結果になる、
なので、「この曲のここは広い」というような現象が毎回確定で発生する可能性が高い。
※あくまで「曲の開始とポーリング開始が同期していれば」である。ここが同期しているかどうかは解析できていない。
(2)ポーリング周期
判定の基準クロックとポーリングの基準クロックが別クロック源の場合、そこには多少なりとも誤差が発生する。
これもどういう事かというと、筐体AではCOOL期間にどういうタイミングでもポーリングが3回行われないが、
筐体Bでは3回行われる場合がある。ということ。
なので、微妙な誤差でCOOL判定となる時間が1ポーリングタイム分変動する可能性がある。
この現象は(1)で説明した事象も考慮すると、必ず3回になるわけでもない。
つまり、「この曲のここは広い」というような現象が発生しうる、ということ。
どこが広いか、というのは、2つのクロックの誤差に依存する。
原発振クロックはだいたいマザーボードとかIOボードとかの水晶発振子なので、
こういう情報が参考になるかと。
[水晶振動子の基礎講座] 水晶振動子の電気的特性に関する用語説明
マクニカオンラインサービス
https://service.macnica.co.jp/library/127525
これもつまり何が言いたいかというと、
一般的な製造誤差は±30ppmとか。
それに対し、温度などでの特性変化は常温なら±3ppm。つまり、一桁違う。
なので、この誤差の挙動は、筐体(ボード)製造時に決定的に決まり、温特などでの変化は少ない。
この辺が筐体差の原因可能性が高そう。
温特での変化が時間差といわれる挙動になるんだろうか。
というわけで、ポーリング周期は誰が主導権を持っているのか。Nu側であればどのクロック基準なのか。
IOボード側に主導権がある可能性もある。
あと、プレイ開始とポーリングタイミングの開始は固定なのか。アドバタイズでもボタンの読み込みはしているが、プレイ開始時に一旦リセットされるのだろうか。
とか。
うん、その辺をもうちょっと詰めたい。
まあ正直言うと、ここを気にするほどのプレイヤースキルはありません。
ってか★10クリアできてない曲とかあるしね。
DIVAの1フレ以下の挙動を体感できて、ミドルとかファームレベルのソフトの心得があって、こういうローレベルな挙動とか理論的に考えらる人材とかどっかに居ませんかね・・・。(そんな奴イネーヨ
後日に続く
blogの仕様
2019.03.31
ところで、メールくださいってコメントが何件かあるけど、
正直なところ、
だったら最初からメールしろよ!!!
と思っていたのですが、
このblogってTOPへのリンクもないし、メールアドレスの記載もないんですね・・・。
そりゃわざわざ手打ちでTOPに戻ってメールするとか面倒なことしないわ。
ってかTOPの存在すら気づかないわ。
あー、そのうち修正しますそのうち。
あと、フォームに入力されたリンクに正しく飛べないってのもそのうちなんとかします。
正直なところ、
だったら最初からメールしろよ!!!
と思っていたのですが、
このblogってTOPへのリンクもないし、メールアドレスの記載もないんですね・・・。
そりゃわざわざ手打ちでTOPに戻ってメールするとか面倒なことしないわ。
ってかTOPの存在すら気づかないわ。
あー、そのうち修正しますそのうち。
あと、フォームに入力されたリンクに正しく飛べないってのもそのうちなんとかします。
BitLockerのお話
2019.03.30
なんというかNuに限った話では全然ないのだが、この辺興味ある人が多いようで。
基本的にはコールドブートアタックといわれる技法。
既にセキュリティホールとして報告も上がっている話。
https://www.itmedia.co.jp/enterprise/articles/0802/22/news094.html
ディスク暗号化技術にセキュリティホール、研究者が指摘
さらに詳細はリンク先の論文読むべし。英語わかんないからちらっとしか読んでないけど。
結局のところ、稼働している状態のメモリの中身を覗ければ、そこからFVEKは導き出せるという話。
※というのが脆弱性。この脆弱性って回避できんの?って話は後で。
じゃあどうやって稼働してる状態のメモリの中身を見ようかというところ。
MSX2とか酷使したことある人なら(っていきなりそこか)、メインRAMにROMイメージを読み込んで、ハードリセットしてもイメージが起動するとか、電源を切っても数分は残ってるとか経験はあるはず。
ほら、そういう経験が役に立つわけですよ。
まあつまりリセットしただけではメモリ内容はほとんど失われない訳ですよ。
起動シーケンスで使われる部分は上書きされるけど、それはごく一部。
なので、起動中にSSDを差し替えてリセットすると、メモリ内にFVEKが残った状態で、メモリダンプツールとか起動できる。
この時点でSSDの変更が検出されてTPMのデータが消えて、次回以降正規のSSDは起動出来なくなるので一発勝負。
ちなみに、世の中にそんなツールがあるのかは知らない。
ただ、一つ言えることは、再起動後にOS(特にWindows)を起動した場合、デバイスドライバが読み込まれるメモリ上の場所というのは、ほぼ毎回変わらない。よって、OSを起動してしまうと高確率でFVEKは上書きされて消えてしまう。
なので、MBRにダンプツールを仕組むとかしないとまず無理。
あとはメモリダンプからどうやってFVEKを探し当てるかという話。
この辺も論文にわりと書いてあるけど、仮に実装メモリが1ギガだとすると、総当たりしても(FVEKは全バイト連続して格納されてると仮定して)たったの1ギガ個=10億個のキーを試すだけ。256bit鍵=2の256乗(10進数で78桁)個とは比較にならないくらい少ない。
さらに、検証機で事前にBitLockerの動きとかを解析しておけば、どのあたりが怪しいかってのも見当を付けられるから、実際に試行するキーの数はもっと絞れる。たとえば00が連続してる場所とか明らかにキーじゃないでしょ。
ただこれはおそらく経験と勘。バイナリデータを眺めてなんか目印になりそうなものが見つけられるかどうか。
昔のROMカセット時代とかのファイルシステムの無いゲーム機とかのダンプを見て、ここはプログラムっぽいとかここはデータっぽいとか、そういうのを見分けられる経験と勘。
ほら、やっぱそういうどうでもよさそうな経験って役に立つわけですよ。
とまあ、そんな感じで稼働機からFVEKは取得できます。はい、論文から情報が1㍉も増えてない気もしますがわざとです。
FVEKの取得に関してはこれ以上深いことを書くつもりはありませんし、ツール公開もしません。
さて、ではこれを踏まえた上で、どうすることで安全にセキュリティを確保することができるか。
まず、現状のようにメモリ上に平文でキーが置かれること、これは確実にNGです。
少し難易度を上げると、メモリ上にも平文でキーを置かないこと、もしくは連続で置かないことです。
ただ、これもデバイスドライバの解析でアルゴリズムが解ってしまうので、手間増えるくらいで解析不可能ではありません。
きちんと対応するなら、ハードウェア対応でしょう。
鍵の生成自体をTPMチップで行って、SATA制御チップに暗号解除アルゴリズムを搭載するとか。
もしくは、SSD自体に高度な暗号機能を搭載するとか。
ちなみに、現状でもSSDに暗号化機能はATAの仕様としてありますが(RINGEDGEで採用されている奴です)、バス上にキーが平文で流れるので、ATAのプロトコルアナライザを使うと簡単に解除できます。
これをDH鍵交換みたいな手順でホストと交換したりするようになるとどうしようもないですね。
ハードウェアとしては仕様が決まればそんなにコストがかかる物では無いでしょうから、いずれはこんな感じになるんでしょうか。
もしかしたら最新に仕様を知らないだけで、すでにそういう物があるのかもしれませんが。
ところで仕事先のノートPCが最近Windows10にリプレイスされたときに、TPM+BitLocker(PIN無し)になったんですが、盗まれたりすると全然安心できないってことですね!!!
Windows7のときはサードパーティーの暗号化ソフトでかつ解除キーは毎回手入力だったんですが・・・。
いいのかこれ?
基本的にはコールドブートアタックといわれる技法。
既にセキュリティホールとして報告も上がっている話。
https://www.itmedia.co.jp/enterprise/articles/0802/22/news094.html
ディスク暗号化技術にセキュリティホール、研究者が指摘
さらに詳細はリンク先の論文読むべし。英語わかんないからちらっとしか読んでないけど。
結局のところ、稼働している状態のメモリの中身を覗ければ、そこからFVEKは導き出せるという話。
※というのが脆弱性。この脆弱性って回避できんの?って話は後で。
じゃあどうやって稼働してる状態のメモリの中身を見ようかというところ。
MSX2とか酷使したことある人なら(っていきなりそこか)、メインRAMにROMイメージを読み込んで、ハードリセットしてもイメージが起動するとか、電源を切っても数分は残ってるとか経験はあるはず。
ほら、そういう経験が役に立つわけですよ。
まあつまりリセットしただけではメモリ内容はほとんど失われない訳ですよ。
起動シーケンスで使われる部分は上書きされるけど、それはごく一部。
なので、起動中にSSDを差し替えてリセットすると、メモリ内にFVEKが残った状態で、メモリダンプツールとか起動できる。
この時点でSSDの変更が検出されてTPMのデータが消えて、次回以降正規のSSDは起動出来なくなるので一発勝負。
ちなみに、世の中にそんなツールがあるのかは知らない。
ただ、一つ言えることは、再起動後にOS(特にWindows)を起動した場合、デバイスドライバが読み込まれるメモリ上の場所というのは、ほぼ毎回変わらない。よって、OSを起動してしまうと高確率でFVEKは上書きされて消えてしまう。
なので、MBRにダンプツールを仕組むとかしないとまず無理。
あとはメモリダンプからどうやってFVEKを探し当てるかという話。
この辺も論文にわりと書いてあるけど、仮に実装メモリが1ギガだとすると、総当たりしても(FVEKは全バイト連続して格納されてると仮定して)たったの1ギガ個=10億個のキーを試すだけ。256bit鍵=2の256乗(10進数で78桁)個とは比較にならないくらい少ない。
さらに、検証機で事前にBitLockerの動きとかを解析しておけば、どのあたりが怪しいかってのも見当を付けられるから、実際に試行するキーの数はもっと絞れる。たとえば00が連続してる場所とか明らかにキーじゃないでしょ。
ただこれはおそらく経験と勘。バイナリデータを眺めてなんか目印になりそうなものが見つけられるかどうか。
昔のROMカセット時代とかのファイルシステムの無いゲーム機とかのダンプを見て、ここはプログラムっぽいとかここはデータっぽいとか、そういうのを見分けられる経験と勘。
ほら、やっぱそういうどうでもよさそうな経験って役に立つわけですよ。
とまあ、そんな感じで稼働機からFVEKは取得できます。はい、論文から情報が1㍉も増えてない気もしますがわざとです。
FVEKの取得に関してはこれ以上深いことを書くつもりはありませんし、ツール公開もしません。
さて、ではこれを踏まえた上で、どうすることで安全にセキュリティを確保することができるか。
まず、現状のようにメモリ上に平文でキーが置かれること、これは確実にNGです。
少し難易度を上げると、メモリ上にも平文でキーを置かないこと、もしくは連続で置かないことです。
ただ、これもデバイスドライバの解析でアルゴリズムが解ってしまうので、手間増えるくらいで解析不可能ではありません。
きちんと対応するなら、ハードウェア対応でしょう。
鍵の生成自体をTPMチップで行って、SATA制御チップに暗号解除アルゴリズムを搭載するとか。
もしくは、SSD自体に高度な暗号機能を搭載するとか。
ちなみに、現状でもSSDに暗号化機能はATAの仕様としてありますが(RINGEDGEで採用されている奴です)、バス上にキーが平文で流れるので、ATAのプロトコルアナライザを使うと簡単に解除できます。
これをDH鍵交換みたいな手順でホストと交換したりするようになるとどうしようもないですね。
ハードウェアとしては仕様が決まればそんなにコストがかかる物では無いでしょうから、いずれはこんな感じになるんでしょうか。
もしかしたら最新に仕様を知らないだけで、すでにそういう物があるのかもしれませんが。
ところで仕事先のノートPCが最近Windows10にリプレイスされたときに、TPM+BitLocker(PIN無し)になったんですが、盗まれたりすると全然安心できないってことですね!!!
Windows7のときはサードパーティーの暗号化ソフトでかつ解除キーは毎回手入力だったんですが・・・。
いいのかこれ?