2010年2月 のアーカイブ

解析手法的な

2010年2月24日 水曜日

0は偉大です、そりゃあもう0なしでは生きていけないぐらい偉大です。
ありとあらゆる法則で0だけ例外なんて日常茶飯事、むしろ例外じゃない事柄の方が少ないぐらいなんじゃないですかね。
というわけで、フル0による暗号化もしくは圧縮の解析手法について。

前提:ファイル読み書きアプリがあり、ファイルフォーマットが不明で、圧縮か暗号が施されているが、、かけているだろう場所が大雑把にでも判明している。
ぶっちゃけここまで着てたら丸1日も頭捻れば大抵のフォーマットなら展開方法が出てきますが、まぁ少しでも楽するための手法です。

まず全Byteが0x00で埋まったファイルを用意します。
このファイルを読み込ませ、ちょうど圧縮なり暗号なりを終えたところでブレイクし、メモリー上に展開されている変換後のデータを覗き見ます。

ここでありえるのは大抵以下のパターン
・0xC7とか、特定の数値が延々とファイルサイズ分並んでる。
・ランダムっぽいバイト列が出ている
・ただ0x00で埋まってる
・メモリー確保した直後のままで、0xCCとか不定っぽい値が並んでる
・数バイトだけ何か出ているが後は手付かず
・それ以前にクラッシュした

特定の数値が並んでいるだけならすぐわかるとは思いますが、単なるxorもしくは加算か減算暗号です。
全byteにその数値でxorか、最上位bitか最下位bitがローテーションする加算や減算を試してみましょう、たぶん復元できます。

ランダムっぽいバイト列が出た場合は乱数xor法(私的命名)か、X次xor法(私的命名)です。
乱数xor法は種から生成できる乱数(有名どころはメルセンヌツイスター)をひたすらxorしている暗号化で、一度だけ見た事があります。
単に一つの数値でxorしないだけマシですが、該当するコードの逆アセンブリから種とアルゴリズムを洗えばすぐ解けると思います。
X次xor法は意外とよく見る手法で(なので、何か正式名前あるかも)


for(int i = 0; i < size; i++){
  data[i] ^= a;
  a += b;
  b += c;
  c += d;
  i++;
}

大体こんな感じのコードによる暗号化です。
簡単に言えばサイズ1byteの乱数を作り出す簡易アルゴリズムによる乱数xor法で、+=している変数(上記の例ではabcdの四つ)が増えれば増えるだけ判別が難しくなります。
が、所詮は簡易アルゴリズムなので、出てきたデータから逆算するか適当に逆アセンブリした物から生の値を拾ってくれば解けます。
実装が容易でxor暗号なので暗号化と展開で別に実装する必要が無く実行速度も速く、変数の数と初期値を弄ることで容易に生成数値を変更できる事が利点です。
この辺が好まれて良く使われている理由なんですかね? 正直mtによる乱数xorの方が楽で強度も高いと思うのですが。

0x00もしくは不定値で埋まっている。
(不定な値の判別が付かなければ、メモリーの確保を捕まえてそこから内容が変わっていないかを見ます)
これはフォーマットの足がかりとなるべき部分がファイル先頭に埋まっていることを意味します。
たとえばファイルサイズといった情報がファイル内に保持されており、それらの情報を元に展開を行う予定だったが読み取れなかったために展開作業を行えずに終了した、という事になります。
これにに明確な対応方法はありません。
ただ、明らかに暗号化ではなく圧縮の傾向があります。 少なくとも素の暗号データではなく暗号化データを含むコンテナファイルでしょう。
バイナリを眺める作業に戻る、逆アセンブリコードから初期の処理だけでも読み取るなど、何かしらの手は打たないといけません。
自分だったらとりあえず0x0F、0xF0、0x7F、0x80、0x01、0xFFなどで埋めたデータを読み込ませてみてその挙動を見てから考えます。

数バイトだけ何かが出ているが手付かず。
これは大分絞り込めます。
おそらくは圧縮で、なおかつ位置情報か長さ情報を含むタイプのデータが連続するタイプです。
たとえばLZSSが実装によってはこういう挙動を示します。
先頭1byteだけ弄って再読み込みなどしてみると大まかな挙動は掴める筈。
その時点でたとえ思い当たるアルゴリズムは無くともなんとなく概要はつかめているはずなので、後は適当に細部を詰めていけば理解可能です。

クラッシュした場合は多少傾向は変わりますが、0x00不定値数バイトのどれかです。
ただ先頭付近に埋まっているだろうデータが位置でも距離でもサイズでもなく、何かしらの通し番号である可能性が高いです。
(たとえば使用する圧縮アルゴリズムのIDなど)
そこが仕様上使えるようには残してあるが完全に想定外な数値である為、どのようにも扱う事が出来ず、なおかつエラーチェックが不足しているためクラッシュ。
これがよくあるパターンです。
ぶっちゃけこれに遭遇したらちまちま逆アセンブリを追う位しか手がありません、何か暴走してデータ壊れても困りますしね。

それと、上記には述べませんでしたが。
0x01,0x02,0x03,0x04と連番を仕込んだデータを読ませたり、途中まで元データと同じであとは0x00のデータなど読ませても特徴的な挙動を見つけられる事が多いのでお勧めです。
どちらにしろ、データを読ませてその結果を見れる状況になれれば後はトライアンドエラーでサクサク進みます。
逆に言えば、解析を阻止したいならここが最終ラインです。
createfileとreadfileのAPIさえ押えればここまでたどり着けますので、論文にでも載りそうな高度な物を使わない限り
呼び出しAPIリストがばれる=ファイルフォーマットまではばれると覚悟しておくべきでしょう。
問題は、そこまでして隠す必要があるのか、ということですが。

余裕が無い時ほど

2010年2月24日 水曜日

余計な事したくなるよね。

むっちゃ空腹だとか、帰宅が午前2時半だとか、明日も大変だとわかっているとか、そもそも今日は睡眠不足だったとか。
そんなの色々あって、すぐさまご飯食べて寝るべきだと体も理性もわかっているのに、なぜか自分はこれを書いています。

なんていうんだろうね、締め切り間近で現実逃避的に部屋の掃除始めるなら判るんだけど、ただ疲れ果てて~な時でも現実逃避とかあるのかしら。
それとも、精神的ストレスの解消とか?
人間って必要最低限のことしかやらないで居ると無駄なことをしたくなる生き物なのかしら。

まぁいいや、無事ご飯の準備できたら、友人に勧められて買った普段の倍高い卵で卵かけご飯を食べるんだ……

某ゲームサークルのテストプレイヤー募集とか

2010年2月21日 日曜日

ルナティック級に縛りプレイがうまい人、なんて条件が無ければ応募したのに……

またタイトルが危ないとか、条件付けが高すぎるとか、荒れるかもしれない要素が合って不安。
別に他のサークルさんであれば何の問題もないけど、あそこは性質の悪いクレーマーが付いちゃってるから批判されうる文言つくだけで危険に思えてならない。
どうか杞憂でありますように。

テストプレイが出来ない腹いせに
一時期公開されてたソースコードでも読んでみて、バグでも見つけて送ってみようかねぇ
問題は、そんな趣味に割いてる時間が無いぐらい忙しいって事だが


プロジェクトマネージャーさん達って本当に大変だと思う。
例えば、○○をAさんにやってもらうというだけでも、ただお願いするだけでは全然足りない。
もちろん、Aさんが自力でマネージメントして、全て最善にこなしてくれうる人材ならそれでも回るけれど
そんな人はフリーランスでそれなりに経験を積んだような人だけで、普通は内容忘れるし期限過ぎるし依頼内容とはずれたものを上げてしまう。

ならマネージャーはどうすればいいかというと
まずは、Aさんがうまく行かなくても回るようにスケジュールを組む、最低でも期限を過ぎた上で2~3度差し戻しても間に合う程度のスケジュールを組む。
自分の上司曰く、最低プログラマーの自己申告の2倍、普通は3倍ぐらいとる、ってぐらい余裕を持たないと回らないらしい。
自分はプログラマーなので他の業種は知らないけど、たぶん人間って皆そんな感じだと思う(そうじゃない方々にはすいません)

そして、内容に齟齬が発生しないように、なおかつ気軽に情報を交わせるように、できるだけ密接に連絡を取る。
一般的に指示を受ける側は受身でいるので、何かあれば連絡が上がってくるだろうでは、致命的でもうどうしようもなくなるかその一歩手前ぐらいまで連絡が来ないことも多い。
何か困っている事は無い?と聞かれたら答える事があるが、聞かれない限り言いもしなかったという経験なら誰しもがあると思う、要するにそれだ。
なので、気軽に情報を上げられる空気を作りつつも、作業に意識が向く程度には空気を引き締める、たぶんこれが一番重要。
といっても厳しくするとか、露骨に急かすのはダメ、あくまで連絡を密にとるのが目的であって、プレッシャーをかけるのは逆効果だから。
これまた上司の言葉だが、「過失が無いもしくはしょうがない過失であっても、怒れば言わなくなり、その結果何とかなる問題が何とかならなくなるまで表面化しなくなる事がある」だとかなんとか。
具体例を挙げると
「すいません、○○を想定しないで××を作ってしまったので××が丸々使えないことに……」
「あー、××って必須部分のか。 もし君が作り直したらどれぐらいかかる?」
「がんばれば大体3日ぐらいかと」
「なら作り直してもらえる? わるいけどプロジェクトの都合もあるから多少急いでもらえると助かる」
こんな空気だと問題もすぐマネージャーまで上がってくるのでやりやすいみたいです。
もちろん、怒らないといけない場面というのは当然あるので、怒るなという意味ではなく
問題にもランク付けを行って、本当に直して欲しいことだけを怒ることが大事なよう。

意見のすり合わせ、ぶっちゃけここはよくわかってない。
要するに、マネージメントされる側からは見えないところでいつも魔法のように解決してしまっているから。
これがもう、違うマネージャーさんの下で仕事を請けたら愕然とするぐらいに違う。
他はある意味でマネージメントされる側の意識改革にも近いものがあって、どちらかがそれを意識していれば最悪何とかなるのだが、これだけはもうどうにもならない。
まず全体像を把握しないといけないし、その上でのスケジュールを暫定であろうと脳内に描けていて、どれはどこまで自由に出来て、それは絶対にこの範囲に抑えなければいけないのか、
責任の所在や、関係する全員の人間関係に、お互いがお互いに持っている印象などなど。
それらをだいたい把握した上で、全体で見て最良と思える着地点を決めて何とかそこに調整し、その上で全員から確実にOKを取る。
そこまでやってようやく個々の人材を回せるようになる。
本当にあれはもう特別な才能でもないとこなすのは無理だと思う、事実上の二点はできてもこれがうまく行かずにgdgdするマネージャーさんを良く見る、会議とか話し合いだけ無駄に長い状況とかまさにこれです。
「船頭多くて船、山に登る」という状況で太平洋横断を果たすようなもの、といえば通じるだろうか。
可能な対策は、それが上手な人を見つけ出して、その人から生のノウハウを手に入れるぐらいしか手がない気がする。
少なくとも自分はいつも知らぬ間に恩恵にあずかっているだけでまったく知らない、関わる時はいつもそんな人が居ない時だけだし。

まずマネージャーがいるのにエターなるのは2番目の連絡がうまくいっておらず、マネージャーの知らないところで要らぬコストが発生しまくっている時。
次に、プロジェクトが上手く回らないのは3番目の意見のすり合わせが上手くいっておらず、皆雲を掴むような気分のまま作業が進んでいるせい。
最後に、期日に間に合わないのは1番目のスケジューリングが上手くいっておらず、取れるはずのマージンをとり損ねたから。

全部マネージメントされる側に過ぎない自分の経験からくる主観なので、十中八九合っていないのだけれど
まぁなんか上の文書いていたら書きたくなった。
最初の話の流れがどこか言っているとか、勘違いしているとわかっているのに断言調だとか、そこまでわかってても書いちゃう。

にしても、これだけの作業をこなさなきゃいけないマネージャーの人って本当にお疲れ様といわざるを得ない。
一つでも出来ているならたとえ他がズタボロでも自分は尊敬する(それすらも出来ないので)
ただし、全部放棄してる上、来た情報を誰にも言わずに忘れるを繰り返すマネージャーは死んでいい。
(自分が知らないだけでIT土方周辺ではこれ以前の問題らしい。 IT土方コワイ)

LZSS圧縮

2010年2月19日 金曜日

LZSSとは、直近Xバイトのデータを辞書とし、その辞書中の位置と長さの形で表現する事で圧縮を行うアルゴリズム。
理解しやすく実装が簡単ながらそれなりに効果が高いアルゴリズムだと有名で、様々な方面で取り入れられているのを見る事が出来る。

個人的な感想として、LZSSの弱点はビット演算が必須な所だと思う。
そういう意味では、表のブログで解析した某アプリで使われていたバイト単位で処理できるLZSS実装は非常に優れていたと思う。
ただ、あれは辞書位置と長さの合計が8の倍数ビットで無ければいけない制約があり、辞書サイズが制限される問題があったように見えた。
そこで、位置と長さをバイト単位に制限せずに、他は出来る限りバイト単位で入出力できるLZSS実装を考えてみる。

まず最初に思いつくのが、実データおよびフラグと、位置長さデータの分離案。
例えば、最初に位置長さデータをまとめて持っておき、実データの先頭アドレスも持っておく
一致不一致フラグは8個分まとめて1byteとして実データ上に配置する。
そして実データ先頭アドレスから不一致フラグ1bitごとに1byteずつ展開していき、一致フラグがあったら位置長さデータの先頭から順に参照していく。
この方法の利点は、位置長さデータのbit数は制限されず、しかし実データは必ずバイト単位で扱えるので余分な演算が発生しない事。
欠点は、位置長さデータが完全に別の位置にあるので、まとめてメモリー上に読んでおけるサイズを超えていた場合にランダムアクセスが発生する事と
圧縮結果を出力しつつ圧縮といった手法が非常にとり辛いこと(位置長さデータが全て判明しないと、実格納位置が判明しない。 逆に位置長さデータを後ろ側においても同じ)
欠点では無いがある意味でのデメリットとして、実データが他の圧縮方式に比べてかなり生に近い形で配置されるので、解析行為に弱いこと
(現に自分はバイト単位LZSS実装において、バイナリエディタだけにも関わらず非常に短時間で展開コードまで辿りつけている)
位置長さデータを全てメモリー上に展開できるサイズならって条件付なら、バイト単位LZSSと同等の速度で位置長さデータの制限からは開放されると思う。

他には、位置長さデータ長を変動させるのはどうだろう。
一致不一致フラグを8個まとめるなどバイト単位LZSSを元にするのは同じ。
その上で、位置長さデータが現れるたびにバイト数を変えてやる。
具体的には、位置長さデータが合計18bitであれば3,2,2,2バイト、といったようにだ。
要するに、位置長さデータにおいてバイト単位にならなかった場合は、その余白に次の位置長さデータを格納していく形で表現するわけだ。
利点は、上記と同じく位置長さデータのbit数が制限されない事と、上記案の欠点であったランダムアクセスも発生しない事。
欠点は、圧縮時にメモリー上に保持しておけるバイト数を超えるぐらい一致せずにいた場合に、位置長さデータを書き込むためのランダムアクセスが必須である事。
それと、上記に比べると多少はマシだが、やはり解析に弱いこと。
圧縮に問題があるのは上の案でも同じだし、こちらの問題の方が遥かにどうにかなるので、たぶんこちらの方が優秀。
展開性能は条件なしでバイト単位LZSSとほぼ同じコスト、圧縮は上記のとおり若干高コスト。

うーん、これぐらいしか思いつかん(一応、一致不一致フラグと同じように8個まとめるとかも考えたけど、明らかに下位互換なので)
ぶっちゃけ、展開コードだけで圧縮コードは書いた事無いし(dat作成コードでは全て不一致フラグという暴挙に出ている)
一度真面目に組んでみれば、もっと色々見えてくるものがあるかもしれないなー

C言語ってきもい

2010年2月16日 火曜日

仮に、こんなコードがあったとします。


//a.c
int a(void){
  return 1;
}
int b(void){
  return a();
}

//b.c
int c(void){
  return a();
}

このとき、b()==c()が真にならない可能性はあるか? というと、あります。
具体的にはx86系CPU上で*(int*)a = 0xCCC3C033;とコードを書き、その上で最適化を最高にしてコンパイルするなど。
(実際にはメモリーに書き込み属性付与など色々必要です)

なぜかというと、関数bは関数aの中身まで見えており、なおかつインライン展開した方がコストが低いと判るのでインライン展開し、実際に関数aにはアクセスしません。
ですが、関数cは関数aの存在は知っていても別ファイルなのでインライン展開できず、関数aにアクセスする機械語を生成します。
そこで、直接関数aをフックするなどして動作を変更した場合、関数cのみ動作が代わり、b()==c()は成立しなくなるというわけです。

これは完全にコンパイラ依存な上(関数cにもインライン展開されたり、関数bもインライン展開されなかったり)、まったく持って役に立たない知識ですが、一応手軽な改造対策に使えます。
たとえば、それなりに重要で、まず改造の標的となり得る関数を上記手法で別々に分けます。
そうすると、完全に同じ動作をする別の関数となるため、両者の結果を比較して同一であることを検証するようにすることで、簡易的かつ信頼性には欠けますが改造対策となります(絶対に誰もやらないだろうけど)

ただ思いついたことをだらだら書いていたらわけがわからなくなったが気にしない!

カテゴリーつけるの面倒くさい

2010年2月16日 火曜日

誰か代わりに付けてくれたりしないかしら?
最初の方こそ多少はつけていたものの、今では全部未分類という有様。

というか、カテゴリーとか一々選んでいる暇などない。
趣味プログラミングと、ストレス発散用に文章書きなぐったらその時点で午前二時過ぎるんだもん。
もっと自分に余暇をくれ!

ファイルフォーマットとか

2010年2月14日 日曜日

アプリケーション独自のファイルフォーマットを、独力で調査しフォーマット文章として起こして公開することは合法か否か。

特許:
使用するのは権利者の許可がない限り違法ですが、単なる情報を含んだままの公開は違法か?
特許自体公開しなきゃ取れない物なので、情報の公開は問題なさそうだが詳細は見つからず。

著作権:
ファイルフォーマットには著作権は発生しない。
ただし、プログラムAをリバースエンジニアリングしてフォーマットAの情報を得た場合、その情報を元に作成したプログラムBはプログラムAの翻案物であるとされ違法になりうる。
とはあるものの、フォーマットAの情報公開については言及されているものを見つけられなかった。
見た感じ、情報公開だけならば問題が無いように読み取れる。

規約:
リバースエンジニアリングを禁ずるとの規約が存在している場合、リバースエンジニアリングによって得た情報を公開した場合は規約違反となる。

リバースエンジニアリング:
>リバースエンジニアリング(Reverse engineering)とは、機械を分解したり、製品の動作を観察したり、ソフトウェアの動作を解析するなどして、製品の構造を分析し、そこから製造方法や動作原理、設計図、ソースコードなどを調査する事である。(WikiPediaより引用)
とあるので、逆アセンブラやリソースエディタやメモリーエディターやデバッガーでの解析、また実際に使用したことによる動作の推測はリバースエンジニアリングの範疇に含まれると思われる。
が、例えば付属しているファイルを、ただバイナリエディタで開くなどして観察するだけでフォーマット情報を得た場合
それはリバースエンジニアリングに含まれるのか否か。
もし含まれなかった場合、規約にてリバースエンジニアリングを禁止していても問題が無い事になり、得た情報を元にプログラムを作った場合でも翻案物として扱われない事になる。

長々書きましたが、ぶっちゃけぐぐっただけなので信憑性はありません。
とりあえず、バイナリエディタでこねこねした情報を公開するだけなら合法と思っておきます

非想天則のストーリーモード

2010年2月13日 土曜日

非想天則の幽々子ストーリーモードなる動画が上がっているらしいと聞いて、動画を見ないで適当に改造方法を書いてみる。

非想天則で新キャラ3人以外でストーリーモードをプレイできます。
方法は簡単、ストーリーモード選択画面で1PのキャラIDを任意のキャラID(0x00886CF0)にメモリーエディターで書き換えるだけ
といっても、ストーリーモード用スペルが一部上書きされているため、相手が突然「符蝕薬」なんて宣言して落ちたりもします。
まぁ、それもdatのscenarioの中身書き換えれば何とかできるわけですが。

たぶん一生に一度あるかどうかという経験

2010年2月12日 金曜日

約一年近くも通い続けた自転車で10分の道の途中で迷いました。

帰りに家の近くのコンビニによろうと思ったのですが
普段の道では遠回りになるため別の道を行く事に。
目的のコンビニは大通りに面しているため、とりあえず大通りにぶつかるまで直進すればたどり着く”はず”でした。
ですがいくら進んでも見当たらず、さすがに通り過ぎただろう距離進んでも次だったら嫌だなと進み続け
普段は遠くにチラリと見える程度の高層建築が目前に迫るに至り、ようやく通り過ぎたと認めたのが21頃の自分。

ここまでならまだ直進し続けただけなのでまっすぐ戻れば帰れたはずでした。
ですが、変な意地から少しでも帰り道を短縮しようと横道に入ります。
微妙に歪曲した道、90度の倍数では無い角度の曲がり道しかない突き当たり、まったく見分けつかない町並み。
当然迷います、元々10分未満の目的地を求めて30分も直進し続けるぐらい距離感の無い自分です、そりゃあ迷います。
そして、例の高層建築が以前より近くに見えた時点で再び間違いを認めざるを得なくなり、近くのコンビニで道を聞きました。
優しい店員さんのやたらアバウトな説明を不安がりながらも道を進み、見覚えのある道に出た時の感動は忘れられない……

ちなみに、出発が20:20、帰り着いたのは22:30。
一応、最後に意地を通して目的のコンビニには寄ったので20分ぐらいは使ったはず。
つまり1時間半ぐらい迷っていた計算、馬鹿みたいだ。

最低限、自宅から自転車で10分ぐらいの範囲は大まかにでも道把握しようと思いました。
少なくとも、安易な気持ちで見ず知らずの道を延々つき進のはやめましょう、うん。

ばれた!ばれたよ!

2010年2月8日 月曜日

こっちがリンク張られただけで気づいた以上、こっちがリンク張った時点で気づかれて当然だよってお話なんですが。
正直ばれないと思って好き勝手書いていた、記事では上から目線で非常にうざいがそんなつもりはなかった、今は反省している。
いや、ほんと、ごめんなさい。