固定されない正解


さて、それでは今回も素材となるプログラムを…。
base64->rar
UmFyIRoHAM+QcwAADQAAAAAAAAArV3Qggi8AEwMAAAAMAAACJGCMzAAAcjgdNQ8AIAAAAGNya21l
MDQuZXhlAAHACQgllQ0Mo83BJ9N/B/tuu23UtqUeNmjagiukGqCi0Nrd1tRtLpWvFrw2Xdjs23d2
UmyFtaobbo8G0EogiCCCCC8ajwaFpXg0afyWgvBF4vOg8Y1vBB/IHhqTJI2u1ck2Wtarxeu+kye9
PZ732fjJ9mf819+GfemQ+hPH3+99nvTwZmBnDOGBLTlYoNQ+o2HSbNEskFMPgFwZqhSVWVSBj0Xk
eZJFnpFubGlE3h50U8uQTDLkyTkCbkwk9GSTG+s/teQTIOiGPaOjc1bIP09OoP7ftwHi1bnRNeYw
13HmjPO0nC9/PE7aNDNXr/63LBgLKzI/AuDTX9itWeFKRsyG7oGihshS7VklnFF2x17YFrLODP9P
R4GK6fPHevXrKYQkYbw9XL6QCvYJY7U3vUDL5BYcEBrYKDb9gUJ6fELQLEvgy4/TJf512+ez4wNy
tBTMeOBZ5eofKPhgzir5WXKugKHkF7l0CXzUOySU+G2bunbCkhkKm79d2kP79CCl5VTk4mjiQHVd
tB65RuNMu671NREI2WoG1Y4pugvOIuEuqqTPk3RqkoCx0M5DajFgvBdFPhPAEeusG9biioFJgopZ
2XaLm6YcWQity87wu9Jzu+vYuZg8KwPR3cvAaFH7hQ4N6SJNSz9sI5t7T4dg0mJFfHPmZ//TMsrg
WDZEivzPHNrKkkdgrKdRu03SbZMBFCqecZBfEyTDGGvrDp0k+cy7N1xP9lKDpU5al0iWTS/4DcMH
8YuOdF4h19BLHsZrw7gQJMSe8D3BYmIP48XjIGSLcZdz7b1yLQyVKLimDkadRlGH1u9exI8dZS51
76MhBPOhjgBREDn20OiIxzLIuSojJzAu05JkfVjaHkF9i97o+wOpKYUv4wv/wshn3YaoeQX6yAbq
FSv+o2D9fYSUppomwkudSEM0XY/kJX5LFcP3GbitAcj6PCmUcMbN2EgDBjd8Mky5C/B6FsBYXgRg
iBKC/1eD/y95NrZs4OOVkFZhXdK2Fkg2Y+WTbhRgvtL1MfvNahxxWaL3+zhtRHFT0BPBCh5BH0TE
PXsAQAcA
そろそろこういう解析以外も入れていこうと思うのですが、なかなか案が浮かばず結局コレに。(笑

それではいつもどおりの方法で正解文字列が5Byteということを確認して、チェックルーチンへ入ります。
4010A8hからですね。
ecx=0、ebx=403024h(入力文字列の先頭アドレス)と、ここまではいつもどおりで。
次に出てくるCmp命令は以前ちょこっと書いたWORDサイズでの比較ですね。
ここで知っておいて欲しい概念がリトルエンディアンという概念です。
これはその名の通り、リトル(小さい)値がエンディアンになる(最後にくる)という意味です。
具体的にどういう意味か、といいますと、CMP WORD PTR DS:[EBX],7243における7243hは、BYTEサイズの比較に直すと、
CMP BYTE PTR DS:[EBX],43
CMP BYTE PTR DS:[EBX+1],72
となるわけです。
要するに1Byteずつ反転させるんですね。

次のアドレスへ移動しますが、[EBX+2]の比較が2回行われていますね。
それではここの比較について詳しく見ていきましょう。
まず最初に比較しているのは30hです。
このCmp命令の後にきているのはJb命令という新出ニーモニックですね。
これは直前のCmp命令の第一オペランドが第二オペランドより小さければジャンプ、という命令です。
ジャンプ先は前回同様不正解処理になってしまうので、3Byte目は30h以上であることが判明しました。

それでは次の比較を見ていきます。
次は39hと比較し、Ja命令がでてきていますね。
これはJb命令の逆で、直前のCmp命令の第一オペランドが第二オペランドより大きければジャンプ、という命令です。
先ほどの条件も加えて考えると、3Byte目は30h〜39h、ということになります。

全く同じような考え方で4Byte目が61h〜7Ahということが判明します。
さて、この時点で3Byte目と4Byte目はどの値が当てはまるのか限定ができませんね。
なので、次のアドレスからの処理の具体性が失われる可能性が高いので、3Byte目の値を"3xh"と見立てて解説していきます。
(実際は'x'というのは16進数ではないので有り得ませんが、便宜上…)

4010CEhでMov命令によって3Byte目の値がal(eax)に代入されました。
先ほど書いたようにこの値は"3xh"とします。
次のアドレスでは30hを減算しているようですので、eaxはxhとなります。
そして乗算処理…ここで値はxの二乗になります。

さて、ここで今までは簡単な説明で終わらせてきた論理処理で回避できないものがでてきました。
このAnd命令は論理積、と呼ばれる処理です。
まず言葉で書いておきますが、第一オペランドと第二オペランドを2進数化し、各桁を掛け合わせた結果を第一オペランドに代入する、という命令です。
何やら面倒くさいことをやっている、と思われそうですが、やっていることは得てして単純です。
第一オペランドのeaxは数値が確定していないので、確定する桁のみ数値を書き記します。

それでは電卓を起動し、7と入力して、2進のラジオボックスをクリックしましょう。
まだ2乗されたときの数値は確定していませんので、各桁を'?'で記します。
この時2進数化された数値の桁数は多い方にそろえるので、111bの前にはxの二乗と同じ桁数に揃えるだけの0がつきます。

…00111
…?????

ここまでできてしまえばあとは簡単、これを一桁ずつ縦に掛け算します。

00111
xxxxx
?????
00???

その先に何桁あろうと、0を掛けられた数値は0になりますので、関係はないです。
つまりこの場合、2進数化したときの下3桁以外を切り捨て、というわけですね。
よってこの時点でのeaxは7以下となります。

そして次の行はなんとも平和にeaxに30hを加算するというもの。
これと5Byte目を比較していますので、5Byte目は3Byte目によって決まり、その範囲は30h〜37hとなります。

さて、解析自体はここまでで済んだわけですが…腑に落ちませんよね?(笑
折角内部の処理を解析し、理解したにも関わらず肝心の正解メッセージが拝めないなんて。
ということで、条件に合った文字列を適当に作ってみましょう。
今回の条件は以下の通りです。

1Byte目:'C'
2Byte目:'r'
3Byte目:'0'〜'9'
4Byte目:'a'〜'z'
5Byte目:上記の処理の結果

コレに則っていればどんなものであっても良いはずですので、適当に…。
ex)"Cr9b1"

このように固定されていない正解文字列を自動で生成するプログラムをKeyGenerator(キージェネレーター)といいます。
略称はkeygen、ですね。
巷にはこういったプログラムが流通し、それによってシェアウェアの製作者はクラック対策なり何なりしていくものです。
そして対応されればクラッカーは新たにkeygenを作る。
するとシェアウェア作者はさらに強固なアンチクラック技術を編み出し、対策をする。
このような繰り返しで昨今のような強固なアンチクラック技術は生まれてきたのです。
そう考えると、クラッカーなくしてプログラム界がここまでに技術を研ぎ澄ますことはなかったのですから、クラッカーも随分な社会貢献をしている、と言えるのではないでしょうか?
まぁ市場発展の妨害云々と言われてしまうと閉口せざるを得ないのですがね。

base64->rar
UmFyIRoHAM+QcwAADQAAAAAAAAAFe3QggjMAmgIAAAAIAAACVkqkZI0igzgdNRMAIAAAAGtleWdl
bjA0X3JlLmV4ZQABwA2nGE0Psy1t5ix6Z3l0xOWaF9uBTGwtgAgnqro/n/Wb1C+MIqZhT0j0au+T
QfBMyfwbZ3k21zXbo6ZxAroDnryWpZhnlDueOQG4HUlOZNVL4WfZI9tAhcPAkmCzAuZp1brGRh2y
W4PAGAnqP6+5AQ096W7xsQQD4TxOf9av9Z9nnh8j9pkTF6824S5CS1c8KhCy2NZBsKbrBL9fKD2v
64ir8vasA3+EfblH61ZsfzGxarvqo0xImLqAXqlniOIt8OgPZ4/XkIW53aQ+k7sPIO5f6hf4lNLr
UIi1AGGtPA2alQ3FZQieJWRbd0qrZgbnJABpRuNCQD/OoB0RIRFS9u926bKp2m+lYJLQHpWcfQGg
yoD3PEJssqV0WuQs4JcRDzSeVKjgoyOZWpCl4cOoVRC+WP9Q+esxx7+zSpnTZ1K35Ozq3buxrrqL
NVQbRHN2Q6MbkOhAFDbAyP7YOwgtUSib8LTOg/r+ADuARd+XGS3bnCOYuHdtkejDQ2eEDO93sIxU
2xNy5v8oUOge/tPGuNAOlwz5DpQHhIR+x5UpU/vVKeACnxRtcGVHq5PYIGVnByIJSMdrmynlzpg/
OBI+hymEh0ng4ojA87WHcQEvxAQg4K560YOut0ABeJbtHG44lKKNdypHIV+4ZSENdcQPzKmyu079
hFYmyvCRDZbFmXNNwdbmPiHBg8jme4IZieDfcWn7SqGkhVbMZlObUSxoQiuQjj0N9DjpT+NrkJS7
7dwooRf5FsA+F6em4kkeaA7oOivO0UXiXQCC8VoG1VVi+154TDGTkdSpD92s3MqeY7zdgbuxc5G7
Zo32A58aDIx2UrHJeNICl49PqrCxFarFgmJ8aOwcnd41XSQR++E3t1hw5AqTAL+IZ/ap/9TEPXsA
QAcA
今回のcrackme04用の拙作keygenです。
ブログで公開しているkeygen for crkme ver 1.0.0のkeygen04.exeより処理を最適化し、ビルド方法も最適化してみました。
所謂書下ろし版、というやつでしょうか。
使い方は簡単、Generateボタンを押せば何度でも正解となる文字列を生成します。
完全なランダムではないのですが、まぁその点についてはご了承ください。
それにしても展開後のサイズが2,048Bytes…。
やはりアセンブリ言語は美しいですが、リソースを付加する都合上これが限界ですかね。

作り方はとても簡単なので、みなさんもプログラミング言語を問わず、作ってみてはいかがでしょうか。
世界で一番簡単と言われているHSPを用いれば、何もわからないところから1時間ほどでこのくらいは作れるようになると思います。


Copyright © 2008 Rapidsy. All Rights Reserved.