ローダー(Loader)とパッカー(Packer)とカスタムリソースの話 〜解答編〜

Last modified: 2006/05/27 18:10:24

はじめに

この文章ではローダー(Loader)とパッカー(Packer)とカスタムリソースの話で扱ったcarckme.zipの解析を、実際に解説しながら行います。よって前記事であるローダー(Loader)とパッカー(Packer)とカスタムリソースの話を読んでいない場合は、そちらから読むことをお勧めします。ちなみに、解説するにあたってソースコードやパスワード(実際の答え)を書いていますので、もし「まだ俺はcrackをあきらめていないぜ!」と考えている方は読まない方が良いと思います。動作確認はWindowsXP SP2で行っています。

解析

./crackme.zip

crackme.exeをOllyDbgで開くと、まずは以下のコードが出力されます。

-----  crackme.exe
00401070 >/$ 81EC 04040000  SUB ESP,404
00401076  |. A1 88934000    MOV EAX,DWORD PTR DS:[__security_cookie]
0040107B  |. 338424 0404000>XOR EAX,DWORD PTR SS:[ESP+404]
00401082  |. 53             PUSH EBX
00401083  |. 8B9C24 0C04000>MOV EBX,DWORD PTR SS:[ESP+40C]
0040108A  |. 56             PUSH ESI
0040108B  |. 68 C0714000    PUSH OFFSET crackme.??_C@_07COOAMMHI@EXE_BIN?$AA@
00401090  |. 6A 65          PUSH 65
00401092  |. 53             PUSH EBX
00401093  |. 898424 1404000>MOV DWORD PTR SS:[ESP+414],EAX
0040109A  |. FF15 18704000  CALL DWORD PTR DS:[<&KERNEL32.FindResourceA>]
004010A0  |. 8BF0           MOV ESI,EAX
004010A2  |. 85F6           TEST ESI,ESI
004010A4  |. 75 12          JNZ SHORT crackme.004010B8
004010A6  |. 68 AC714000    PUSH OFFSET crackme.??_C@_0BE@JFFMEGDH@Error?3?5Find
004010AB  |. E8 50FFFFFF    CALL crackme.PopMsg
004010B0  |. 83C4 04        ADD ESP,4
004010B3  |. E9 F2000000    JMP crackme.004011AA
004010B8  |> 57             PUSH EDI
004010B9  |. 56             PUSH ESI
004010BA  |. 53             PUSH EBX
004010BB  |. FF15 14704000  CALL DWORD PTR DS:[<&KERNEL32.SizeofResource>]
004010C1  |. 8BF8           MOV EDI,EAX
004010C3  |. 85FF           TEST EDI,EDI
004010C5  |. 75 12          JNZ SHORT crackme.004010D9
004010C7  |. 68 94714000    PUSH OFFSET crackme.??_C@_0BG@DHCIIEPK@Error?3?5Size
004010CC  |. E8 2FFFFFFF    CALL crackme.PopMsg
004010D1  |. 83C4 04        ADD ESP,4
004010D4  |. E9 D0000000    JMP crackme.004011A9
004010D9  |> 56             PUSH ESI
004010DA  |. 53             PUSH EBX
004010DB  |. FF15 10704000  CALL DWORD PTR DS:[<&KERNEL32.LoadResource>]
-----

詳細なプログラムはともかくとして、とりあえず、FindResource関数やLoadResource関数が呼び出されていることが確認できます。これらはつまり、実行ファイル内のリソースにアクセスしていることを意味します。

-----  crackme.exe
00401116  |> 6A 40          PUSH 40
00401118  |. 68 00100000    PUSH 1000
0040111D  |. 57             PUSH EDI
0040111E  |. 6A 00          PUSH 0
00401120  |. FF15 08704000  CALL DWORD PTR DS:[<&KERNEL32.VirtualAlloc>]
-----

次にVirtualAlloc関数を呼び出し適当なメモリ領域を確保。そして、リソース内にあるデータをVirtualAlloc関数で確保した領域へコピーしています。これらはマシン語を読んでいけば用意に理解できるはずです。さて、問題はここからです。メモリ領域にコピーした怪しげなデータは、このままではただの怪しげなデータです。というのも、このデータは実は暗号化されています。よって、このデータを復号化することが必要であり、その復号化処理をReverseData関数が受け持っています。

-----  crackme.exe
0040115D  |. E8 3E050000    CALL crackme.ReverseData
-----

この関数が呼び出されると、メモリ内にある怪しげなデータを復号化します。そして、復号化されたデータは、PEフォーマットに従った実行ファイルのバイナリとなっていることが分かります。そして、この実行ファイルのバイナリを実行してくれる関数(loader)が、CreateExeProcess関数です。

-----  crackme.exe
0040117D  |. 56             PUSH ESI
0040117E  |. E8 7D040000    CALL crackme.CreateExeProcess

この関数には、実行ファイルのバイナリのアドレスを渡さなければならないため、ESIレジスタにそれが格納されているのが分かります。私の環境ではESIレジスタは「003D0000」となっています。よって、このアドレスのデータが実行ファイルのバイナリデータというわけです。

あとは、アドレス「003D0000」以降のデータを取得して、実行ファイルとして保存してやれば、無事、パッキング前のファイルとなります。あとは、この実行ファイルを解析すれば(これはとても簡単)、無事パスワード取得となります。ちなみにパスワードは、実行ファイルの方は「2006020515」で、ZIPファイルの方は「200602051500yen」です。

さいごに

とりあえず、「解答編」ということで、アンパッキング(?)に的を絞って解説させていただきました。詳細な動作説明や仕組みについては、本編のローダー(Loader)とパッカー(Packer)とカスタムリソースの話にて解説しているので、そちらと合わせて読んでもらえたらと思います。


Copyright (C) 2003-2006 Kenji Aiko All Rights Reserved