← All Articles

Shellcodeの解析_ROR13

Posted on

今回はシェルコードの解析を進めていきます。

この記事の手法を使うとROR13で難読化されたインポート関数を特定することができるようになります。

解析するバイナリは前の記事「Process Injectionを解析する」でiexplore.exeにInjectionされたコードです。そちらもぜひ読んでみてください。

iexplore.exeにInjectionされたシェルコードの動作


1. Kernel32.dllのベースアドレス取得

まず、シェルコードの\x00から始まるアドレスを6つpushする動きをします。これは目的の値を6つ分スタックに配置するための処理です。

loop は、ecxが0になるまでjmpを繰り返す。

LOOP


シェルコード上でWin32APIを呼び出すための前処理を行います。

loc_50B007Dではfs:30hのProcess Environment Block (PEB)からkernell32.dllのベースイメージ (先頭アドレス)をebxに取得する動作を行っています。

callの引数はさきほどの6つのアドレスになっています。

Kernel32.dllのベースアドレス入手の図


2. LoadLibraryA()のスタートアドレス取得

先ほどのcallでスタックに積んだReturn-eipをすぐさまpop esiで取り出します。つまりesiには050B0095の直後のアドレスが入ります。

kernel32.dllのベースアドレスが入ったebxと、Return-eipの入ったesiの指す値を引数に関数を呼び出します。ここではその関数をaa_ror13と名付けているのでaa_ror13(ebx, [esi])という状態で、引数[esi]には4B1E5ADBhが入っています。これはROR13ハッシュです。

aa_ror13(ebx, [esi])は始めにlstrcmpiA()のスタートアドレスを戻り値eaxに返します。このようにROR13ハッシュ[esi]を+4ずつ進めaa_ror13(ebx, [esi])を繰り返し呼び出すことよって、[esi]が0になるまでROR13ハッシュに対応するkernel32.dll内の関数のスタートアドレスeaxをpushしてスタックに積むことを繰り返します。

ROR13の呼び出し部の図

以下は、インポート関数を積まれたスタックの様子です。最後に取得したインポート関数のスタートアドレスはLoadLibraryA();のものです。

スタックの図


ここで、aa_ror13();の引数[esi]はReturn-eipだったことを思い出してください。callの直後のアドレスであるReturn-eipには以下の様にfistp dword ptr [edx+1Eh]などが続いていました。しかし、

callの後ろの図

callの後ろからドラッグして右クリックでUndefinedし、dキーで4バイトのdd表示にすると、実は、Return-eip以降+4ごとにROR13ハッシュが隠されていました。

デバッガの表示をddに変更した図


ちなみに、C言語でROR13ハッシュの計算を行う処理を載せておくので理解の足しにどうぞ。

ROR13ハッシュ計算
#include <stdio.h>

typedef unsigned int DWORD;

int ror13_hash(const char *string)
{
    DWORD hash = 0;

    while (*string) {
        DWORD val = (DWORD) *string++;
        hash = (hash >> 13)|(hash << 19);
        hash += val;
    }
    return hash;
}

int main(void)
{
    printf("%x", ror13_hash("LoadLibraryA"));
    return 0;
}

3. LoadLibraryA()で関数をインポート

2. LoadLibraryA()のスタートアドレス取得050B00D4にあるcallを実行するところに話を戻します。同じ画像を再掲しておきます。

ROR13の呼び出し部の図


call near ptr loc_50B00E1+1となっていた箇所が実行に伴いcall loc_50B00E2に変わっています。単純に足し算しただけですが、+1で1バイト分呼び出し先をずらすことでデバッガに間違ってアセンブラを表示させることができる難読化テクニックです。

呼び出し先を見ていくと、call eaxつまり、aa_ror13()の最後の戻り値であるLoadLibraryA();を呼び出しています。

LoadLibraryA()の呼び出しの図

LoadLibraryA();の引数は、直前のcall loc_50B00E2でスタックに積まれたReturn-eipなので、そのアドレスの表示を文字列へ変換すると、advapi32であることが分かります。

LoadLibraryA()の引数の図


ここからはadvapi32.dll内からROR13ハッシュでインポート関数のスタートアドレスを取得し、スタックに積んでいきます。マルウェアがレジストリを操作しようとしているということが分かってきますね。

画像一番下のcall dword ptr [ebp-20h]は実際にROR13で取得した関数を呼び出しているところです。

ROR13の呼び出し部の図2


最後に


呼び出す関数名をROR13によって隠しているシェルコードの解析手順を紹介しました。 今回登場したROR13と関数名の対応表を以下に記載しておきます。


ROR13ハッシュ


今回の記事に登場したROR13ハッシュと関数名の対応表です。


ROR13 関数
4B1E5ADB lstrcmpiA
4DC9D5A0 FreeLibrary
7C0DFCAA GetProcAddress
73E2D87E ExitProcess
99EC895E CopyFileA
C2FFB025 DeleteFileA
56F7396A SetFileAttributesA
DD434738 lstrlen
EC0E4E8E LoadLibraryA
2D1C9ADD RegSetValueExA
A84AEB81 RegOpenKeyExA
2D1C9ADD RegSetValueExA
B4CEEAB6 RegDeleteValueA
2D1C9ADD RegCloseKey

reversingshellcodeida pro