第 6 回 クラックルーチンの注入

第
6回
クラックルーチンの注入
文●愛甲健二
クラック手法を考える
今回は、第 5 回までの解析結果を元に crackme_
ex.exe のパスワードを突き止めます。 理論は
すでにわかっているため、あとは解析手法を選
ぶだけですが、せっかく「進め ! リバースエン
ジニアリングの道」と題して連載していますの
で、コンパイラやスクリプト言語などは使わずに、
アセンブラだけで実現したいと思います。よっ
て、crackme_ex.exe 自体をクラック用に修正
してパスワードを探し当てましょう。
OllyDbg を使ってクラック用 の 処理を追加
します。まずは HACKER JAPAN ONLINE より
ファイルをダウンロードして解凍します。アン
チウイルスソフトによっては警告が出る場合が
ありますが、除外項目にしてください。この中
の crackme_ex.exe を OllyDbg で読み込むと
00406368 以降が空いていますので、ここにク
ラックルーチンを追加します。
ただ、クラックルーチンを追加しただけでは
00406368 へ処理が進みませんので、正規ルー
チンの適当な場所から 00406368 へ処理をジャ
ンプさせる必要があります。よって、00402891
の call 命令のジャンプ先を 004019F0 から 0040
6368 へ変更します。これで、ユーザー 名とパ
変更前
正規のルーチン
00402890 PUSH EAX
00402891 CALL crackme_.004019F0
00402896 ADD ESP,4
変更後
正規のルーチン
00402890 PUSH EAX
00402891 CALL crackme_.00406368
00402896 ADD ESP,4
クラックルーチン
00406368 PUSH EBP
…
004063B4 CALL crackme_.004019F0
図 1 パスワードクラックの処理フロー
1
スワードを入力し、OK ボタンをクリックするこ
とでクラック処理が走ります(図 1 )。
では、パスワード解析のメイン処理となるク
ラックルーチンを書いていきましょう。
OllyDbgでクラックルーチン実行
パスワードクラックにはいくつかの手法があ
りますが、今回は dictionaryA.txt( DVD-ROM
にも収録しています)を使用した辞書攻撃を行
います。よって、00406368 以降に追加するク
ラック処理は以下の流れで実現しましょう。
1. 辞書ファイルを開く
2. 文字列を 1 行取得
3. 文字列をスタックへ
4. 004019F0 を呼び出す
5. 2 へ戻る(繰返し)
まずは辞書ファイルを開く処理 ですが、 こ
れは CreateFileA を使 います。 ファイルを読
み 込 み 専 用 で 開くの で、 第 1 引 数 に 対 象と
なるファイル名、第 2 引数に GENERIC_READ
( 80000000h )、第 5 引数に OPEN_EXISTING
( 3h )
、第 6 引数に FILE_ATTRIBUTE_NORMAL
( 80h )をセットします。
次に文字列を取得 する部分 で
すが、これは ReadFile を使 いま
正規のルーチン
しょう。ReadFile で 1 文字ずつ取
004019F0 PUSH EBP
得していき、改行コード「 0D0Ah 」
004019F1 MOV EBP,ESP
を見つけたら文字列として認識し、
004019F3 SUB ESP,20
次ステップへ進む、という処理に
します。文字列を取得したら、そ
れをスタックへ pushして 004019
F0 を call します。004019F0 内で
正規のルーチン
004019F0 PUSH EBP
は、渡されたパスワード
(第 1 引数)
004019F1 MOV EBP,ESP
が 正しいかどうかの 判定 が 行 わ
004019F3 SUB ESP,208
れます。
これらの処理を C 言語風に書く
と以下になります。辞書ファイル
名は dictionaryA.txt だとアセン
ブラ上 では扱 いにくいため、 便
宜上「 DIC 」としています。
func_00406368(char *s)
{
char buff[4] = "DIC";
eax = CreateFileA(
buff,80000000h,
0,0,3h,80h,0);
esi = eax;
_READ_STR:
ebx = s;
_READ_CHAR:
ReadFile(esi,ebx,1,buff,0);
al = *ebx;
ebx++;
if(al != 0x0D)
goto _READ_CHAR;
ebx--;
*ebx = '¥0';
004019F0(s);
ReadFile(esi,ebx,1,buff,0);
goto _READ_STR;
}
00406368 に記 述 するコードは、004019F0
の代わりとして call されるため、実行時にはス
タックに「入力されたパスワード」のアドレスが
格納されています。ただ、本来の処理とは異な
り、パスワードは辞書ファイルから読み込むた
め、このスタックにある
「入力されたパスワード」
は必要ないのですが、せっかくなのでメモリ領
域だけは使わせてもらいましょう。ebx レジス
タに s を格納し、この領域へ読み込んだ文字列
を格納します。
ReadFile で 1 文 字 ず つ 読 み 込 み、0Dh が
見 つ かったら 改 行 の 代 わりに 00h を 入 れ て、
004019F0 を呼び出します。Windows の 場合
は 0D0Ah が改行コードであるため、0Dh を読
み込むと次のバイトは 0Ah です。よって、0Ah
を 1 回読 み 捨 てて _READ_STR へジャンプし、
最初へ戻ります。
また、ReadFile に buff を 渡して い ます が、
buff( ="DIC" )は CreateFileA 呼び出し時にし
か使用しないため、その後は読み込 んだバイ
ト数を格納するための領域として使用します。
このコードをアセンブラにすると以下になり
ます。OllyDbg で crackme_ex.exe を読み込み、
00406368 以降に以下のコードを書き込んでく
ださい。
00406368
00406369
0040636B
00406370
00406372
00406374
00406379
0040637B
0040637D
0040637F
00406384
00406385
0040638A
0040638C
0040638F
00406391
00406393
00406396
00406398
00406399
0040639B
0040639C
PUSH EBP
MOV EBP,ESP
PUSH 434944 // "DIC"
MOV EAX,ESP
PUSH 0
PUSH 80
PUSH 3
PUSH 0
PUSH 0
PUSH 80000000
PUSH EAX
CALL kernel32.CreateFileA
MOV EBX,EBP
ADD EBX,8
MOV ESI,EAX
MOV EDI,EBP
SUB EDI,4
PUSH 0
PUSH EDI
PUSH 1
PUSH EBX
PUSH ESI
図 2 00406368 の
書き換え
図 3 00402891 の
書き換え
2
図 4 0040274Eと
0040276F の書き換
え
0040639D
004063A2
004063A4
004063A5
004063A7
004063A9
004063AA
004063AC
004063AE
004063B0
004063B3
004063B4
004063B9
004063BC
004063BE
004063BF
004063C1
004063C2
004063C3
004063C8
CALL kernel32.ReadFile
MOV AL,BYTE PTR DS:[EBX]
INC EBX
CMP AL,0D
JNZ SHORT 00406396
DEC EBX
XOR EAX,EAX
MOV BYTE PTR DS:[EBX],AL
MOV EBX,EBP
ADD EBX,8
PUSH EBX
CALL 004019F0
ADD ESP,4
PUSH 0
PUSH EDI
PUSH 1
PUSH EBX
PUSH ESI
CALL kernel32.ReadFile
JMP SHORT 00406396
以上でクラックルーチンの作成は終了です
(図
2 )。
あとは、00402891 の call 命令 のジャンプ先
を 004019F0 から 00406368 へ書き換えましょう
(図 3 )
。これで、パスワードクラックを行う実
行イメージの完成かと思えますが、実はあと 2
つ細かな修正点があります。
1 つは、エラーメッセージに関する処理です。
004019F0 は 引数 に「 入力 された パスワード」
を得る関数 で、 その パスワードが 正解 ならば
DES で復号された 200h バイトのデータ列をマ
図 5 解析成功のメッセージボックス
3
シン語として実行し、間違いならばエラーを意
味する文字列をメッセージボックスに表示しま
すが、パスワードクラック中に毎回間違いのメッ
セージボックスが表示されても困るので、あら
かじめこの処理を jmp 命令で飛ばしておきます。
もう 1 つは、0040277A で呼び出されている
VirtualFree の引数を MEM_RELEASE(8000h)、
サイズを 0 にしておくことです。 ぶっちゃけた
話 をするとただのプログラム の バグで( 汗 )、
元 々の crackme.exe はメモリを正常に解放し
ていませんでした。よって、パスワードクラック
によって何度も 004019F0 を呼び出すと、途中
で VirtualAlloc 呼び出し時に「メモリが確保で
きない」というエラーが発生します。それを防
ぐために、VirtualFree 呼び出しを問題ないコー
ドに変更します。
これら 2 つの修正を終えると、パスワードクラッ
ク用実行イメージの完成です(図 4 )。ファイル
名を「 DIC 」に変更した辞書ファイルを同じディ
レクトリに置き、OllyDbg 上で、修正後のイメー
ジを実行してください。数分ほど待った後、パ
スワードが解析されたことを意味するメッセー
ジボックスが表示されます(図 5 )。
成功のメッセージボックスが表示されている
状態で 0040276F にブレイクポイントをセットし、
メッセージボックスの OK ボタンをクリックする
と、0040276F で処理が止まります。この状態
でスタックを確認するとパスワード
「OtmPpLvQ」
が確認できます(図 6 )。
crackme.exeについて
見事 パスワードがわかり、crackme.exe の
すべてが解析されました。メッセージボックス
に 書 か れ て いる URL「 http://ruffnex.oc.to/
kenji/crackme/ 」へアクセスするとユーザー
名とパスワードを求められますので、ユーザー
名「 WizardBible 」、パスワード「 OtmPpLvQ 」
と入力すると、crackme.exe のソースコードが
ダウンロードできます。興味がある方はぜひソー
スコードを眺めてみてください。
図 6 パスワードの
確認
また、パスワードクラック用に改造した crackme_
ex_fin.exe もダウンロードファイルに含まれて
います。これは本記事にて OllyDbg 上で行っ
た 修 正 を 実 行ファイル へ 適 用したも の で す。
Windows XP SP3 Professional にて動作確認
していますが、CreateFileA と ReadFile のアド
レスを決め打 ちしていますので、 動作しない
場合 はこれらのアドレスを修正してください。
また 以前にも 書きましたが、crackme.exe は
Windows7 上では正常に動作しません。よって、
特に第 6 回目の本記事は Windows7 以外の環
境でテストしてください。
Windows7 で動作しない理由、成功時にメッ
セージボックスが表示されるメカニズムなどが
知りたい 方は、00402769 辺りにブレイクポイ
ントを仕掛け、正常なパスワードを入力し、成
功時に実行される処理を眺めてみてください。
リバースエンジニアリング技術からは少し離れ
ますが、Windows システムに関するさまざま
なことがわかるかと思います。
最後に
これで「進め ! リバースエンジニアリングの
道」は終了となります。読者の皆様、本当にお
疲れ様でした。本連載は、なるべく初心者向け
であり、かつ、普遍的な技術をテーマに書かせ
新連載予告
ていただきましたが、いかがだったでしょうか。
現在、ソフトウェア開発の現場においてはや
はり Java や .NET が主流であり、Web サービス
の世界では JavaScript、Ruby、Python といっ
たプログラミング言語が好まれています。そう
考えると、21 世紀においてアセンブラを学ぶ
意味は果たしてあるのか ? と思われる読者も
多いと思います。
はっきり言ってしまえば、アセンブラの知識
はコンピューターセキュリティの世界において
も、マルウェア解析や脆弱性監査に使われる程
度ですし、それらも近年では自動化され、人の
手で行うソフトウェア解析の活躍の場はさらに
減ってきているかもしれません。ただ、だから
といって、その技術が不必要になることは決し
てないと思 います。ビジネスに繋がる機会は
少ないかもしれませんが、ソフトウェア技術の
根幹はやはりバイナリデータであり、最終的に
CPU が解釈するのはマシン語です。そのベー
スとなるスキルを持っていることで 解決 でき
る技術的問題も多 々あります。 そして何より、
無意味かどうかよりも、楽しいかどうかでソフ
トウェア 技術を学 び 続 けたいというのが 個人
的な本音です。
読者の方々が、本連載を通して少しでもリバー
スエンジニアリングに興味を持っていただけた
なら幸いです。
実践的なリバースエンジニアリングを学ぼう !
次回から
「進め ! リバースエンジニアリングの道 Next(仮)」
と題して、改めて連載をスタートします。リバー
スエンジニアリングを扱う、という意味ではさほど変わりませんが、これまでの連載が、デバッガの使い方
やアセンブラを中心に扱ったのに対し、次回以降では、CTF( Capture the Flag )やマルウェア解析を題材
にして、より実践的なリバースエンジニアリングに関する内容がメインとなります。
マルウェア解析や脆弱性監査を行う際は、当然デバッガを使ったり、アセンブラを読む必要があるので
すが、実際はそれだけではありません。これらはあくまで基礎的な技術であり、業務を遂行するためには、
それらにプラスしてまたいくつかのベーススキルが必要になります。
よって、次回以降は、リバースエンジニアリングという技術をよりセキュリティに応用していく方向で連
載を進めていくことになります。なるべく現場レベル、業務レベルでの解析を紹介、解説していきたいと
思いますので、興味がある方は、ぜひ引き続きよろしくお願い致します。
4