Hatena::ブログ(Diary)

Dlog 隔離館 このページをアンテナに追加 RSSフィード

2012-03-02

CODEGATE2012 Binary200 Writeup

先日のCODEGATE2012 予選。

一応、少しでも取りかかった問題については、いろいろな人の書かれたWriteupを参考に

「自分で理由をつけながら答えを導出できる」レベルまで落としこんでいたのですが、

Binary200でかなりつまずいたので、メモがてらWriteup。


使用したツール

  • OllyDbg 1.10
  • OllyDbg 2.01
  • IDA 5.0
  • PEiD 0.95
  • ImpREC 1.7c

問題

Find a printable string that the program would print ultimately. 
Download


ファイルの解析

まず、ファイルの種類を調べる。

[dolphin@siro BINARY200]$ file A1A81BBD9D2FD44FAE8013E753830464 
A1A81BBD9D2FD44FAE8013E753830464: PE32 executable for MS Windows (DLL) (GUI) Intel 80386 32-bit


WindowsのDLLだと分かるので、とりあえずOllyDbg 1.10で開く。すると、こんなメッセージが。

f:id:Dltn:20120302135509p:image

圧縮されているらしい。確かに、Pack系の目印ともいえるPUSHADが見受けられる。

1001112B   .  60            PUSHAD


パッカーを調べるため、PEiDを使う。

f:id:Dltn:20120302135707p:image

PEtiteでパックされていることが分かる。

適当なアンパッカーを試してみたが、うまくアンパックできないので、手動アンパック(manual unpacking)を行う。


手動アンパック

手動アンパックの手順は、以下の通りである。IATには、外部DLL関数のインポート情報が格納されている。

  1. 実行させる
  2. アンパックされた実行コードがメモリ上にロードされる
  3. メモリ上にロードされた実行コードをダンプする
  4. ダンプしたファイルのIAT(Import Address Table)を修正する

[実行させる]

実行させるには、EXEであればそのまま実行させればよいが、

今回はDLLなので、OllyDbg 1.10を用いて、デバッガ上で実行させる。

単純に、OllyDbg 1.10で開いて、F9(Run)を押すだけである。

その際、以下のようなメッセージが表示されるが、OKボタンを押して閉じ、Shift+F9などで例外を抜ければよい。

f:id:Dltn:20120302140238p:image


[アンパックされた実行コードがメモリ上にロードされる]

すると、OEP(Original Entry Point: プログラムの開始地点)へとJMPする命令でが現れる。

1001110F > $- E9 8414FFFF   JMP binary20.10002598

この場合、10002598がOEPとなる。このOEPがないと、IATを修正できないので、メモしておく。


[メモリ上にロードされた実行コードをダンプする]

OEPへJMPし(F8などで1命令実行させればよい)、OllyDbgのプラグインであるOllyDumpを用いてダンプする。

このとき、OEPにジャンプしても、命令が表示されない場合があるが、Ctrl+Aを押して再解析すればよい。

Dumpボタンを押して、適当にbin200.dllのような名前をつけて保存する。

f:id:Dltn:20120302140740p:image


[ダンプしたファイルのIATを修正する]

今度はImpRECでIATを修正する。

  1. ダンプしたファイルをOllyDbgで開く。(エラーが出ても、とりあえずOKを押せばよい。)
  2. ImpRECを起動し、Attach to an Active Process から loaddll.exe を選ぶ。
  3. Pick DLL ボタンを押して、問題のDLLファイルを選択する。
  4. OEPの値を、メモした値に書き変える。(10002598なら、00002598と入力する。)
  5. AutoSearch ボタンを押す。
  6. Get Imports ボタンを押す。
  7. Fix Dump ボタンを押し、ダンプしたファイルを選択する。
  8. ダンプしたファイル名に"_"がついた名前で保存される。

f:id:Dltn:20120302140741p:image

こんな感じになっていれば成功である。


以上で手動アンパックは完了となる。

実行コードの解析

アンパックしたDLLファイルをOllyDbg 1.10で開こうとしても、エラーが出る。

そこで、IDA か OllyDbg 2.01 を使って開く。

Exportされている関数が、"x" と "_c@4"(IDAで見ると"c(x)")となっている。

ここで、各関数を見ると、"SetServiceState" や "RegisterServiceCtrlHandler" などの呼び出しが見つかり、

サービスとして動作するということが分かる。

特に、IDAで見るとよく分かるが、 "x" には fopen やら fputs やらが見受けられ、怪しいことが分かる。

実際、OllyDbg等でDLLを実行してやり、適当なところで "x" を呼び出すと、

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\

にサービスが登録され、"x" が呼び出されることも分かる。


IDAで "x" を見ると、fopen やら fputs やらがあるので、

その上を見てみる。すると、いくつか CALL がある。

特に怪しい CALL が 1BC0 で、xor、shl、shrを大量に使っている。

ここが暗号化、あるいは復号化のコードだと見て間違いないだろう。


もう一つ、気になるものとして、次のコードがある。

f:id:Dltn:20120302145606p:image

localtimeで取得した値の8バイト目と 6 を比較している。

localtimeについて調べればすぐ分かるが、8バイト目は「時間」を表す。

つまり、6時かどうかをチェックしているコードである。

6時なら、var_238には6が入る、という仕組となっているようだ。

この関数は、6時に実行される必要性が高いと考えられる。

直接実行によるアプローチ

一度は成功したけど、後から再現しようとしたけれど、うまくいかなかった。

なので、ここでは記事にしていません。

下のほうに書いてある、参考サイトの3つ目を見てもらったほうが早そうなので、割愛。


静的解析によるアプローチ

暗号化アルゴリズムの特定

先にふれた、怪しいCALL先 10001BC0 を見てみる。

すると、これまた怪しい定数が現れる。

f:id:Dltn:20120307110848j:image

この定数でぐぐると、TEA(Tiny Encryption Algorithm)がヒットする。

その後の shl や shr 、add や sub などを参考にしながら、TEAのコードと比較すると、

どうもTEAではないことがわかる。

TEAのWikipediaには、See Alsoとして、RC4やXTEA等が並んでいる。

それぞれのコードを見ていくと、XTEAのコードであると分かる。


引数解析

地道に10001BC0の引数を解析していく。

x+21Eでは、復号化として10001BC0を呼び出していることが分かる。

鍵は16バイト(128ビット)、暗号化されるデータは8バイトなので、

大体こんな感じ。

f:id:Dltn:20120307110849j:image

6時に実行した場合、ecxは6なので、1000A158(hex)に48(decimal)を足して、

1000A188のValueが暗号化されたデータであると分かる。

f:id:Dltn:20120307110850j:image

ここまでくれば、もう一息。


鍵解析

鍵は、10001B40を呼び出して生成している。

見てみると、単純に、引数で渡された1000B440から読み込んでいるだけと分かる。

f:id:Dltn:20120307112441j:image

早速この鍵を使って復号化してみてもいいのだが、うまくいかない。

IDAだと親切に表示してくれるので分かるが、これらの値は実行時に若干書き換わる。

順を追って見ていこう。


IDAの場合、定数の右側にあるコメントにカーソルを当てると、

その定数に別の値を代入しようとしているコードが表示される。

ダブルクリックすることで、そのコードまで飛んでくれるので、確認する。

その一例を以下に示す。


f:id:Dltn:20120307112442j:image

これは、1000B44Fに0xDEを書き込もうとしている処理である。

分岐があり、CreateThreadの戻り値が0でなければ、書き込む。

API名でぐぐればすぐに分かるが、戻り値が0というのは、関数の実行が失敗したときである。

なので、ここは0xDEが書き込まれなければならない。


このようなトラップがいくつかあるので、全て潰していく。


復号化

適当にプログラムを書いて、復号化する。

ただし、エンディアン問題に注意する。

vは、IDA上では4バイトの整数として表示されているので、逆転する。

また、下記のプログラムで表示される結果も、逆転しなければならない。

(XTEAのコードは、Wikipediaのコピペである。num_roundsは、10001CE9から分かる。)


[dolphin@siro bin200]$ cat mofu.c
#include <stdint.h>
 
void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    unsigned int i;
    uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*0x20;
    for (i=0; i < num_rounds; i++) {
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
        sum -= delta;
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
    }
    v[0]=v0; v[1]=v1;
}

int main(int argc, char *argv[])
{
  int i, j;
  uint32_t v[2] = { 0x1EAEA1C7, 0xB3506D02 };
  uint32_t key[4] = { 0x1Ea0f5c6, 0xd9ec02f6, 0x59187c2e, 0x6f855dde };
  decipher( 0x20, v, key );
  printf("%s\n", (char*)v );
  printf("\n");
  return 0;

}

[dolphin@siro bin200]$ ./mofu
W%I&l)K=


よって答えは、"&I%W=K)l"となる。


感想

これで200かぁ・・・^^;;;


参考サイト

CodeGate 2012 Quals ? Binary 200 | More Smoked Leet Chicken

Eindbazen » CODEGATE 2012 – Binary 200

Gogil’s Blog ::

XTEA - Wikipedia

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/Dltn/20120302/1330666702
リンク元