
-
EXEファイルのマルウェアがDLLファイルのドロップ
-
EXEファイルのマルウェアと正常プロセスへの悪性コードのインジェクションを実施
-
インジェクションされた悪性コードが、ドロップされたDLLのエクスポート関数をインポートし実行
今回の時にでは、上記3番の動作について記載していきます。
なお、下記の順番で記事を読むことで、マルウェア解析の流れに沿ってマルウェア解析の一連の流れを確認することが出来ます。
Persistenceの確認
マルウェアが、自身が初めて実行されておりPersistence獲得のための処理を実行する必要があるのか、それともPersistence獲得の処理は飛ばして次の処理に移るべきなのかを確認するための処理が入っています。

lstrcmpiA();で比較する二つの文字列は一致しておらず、jz short loc_50B0152でのジャンプは発生しません。 その文字列とは、以下の2つです。 1つは、Documents直下のTMP.exeであり、もう1つはこのシェルコードをInjectionした元のマルウェアの絶対パスです。

1回目のSetFileAttributesA();はDocuments直下のTMP.exeに対してFileAttributeを設定しようとして0を返しました。呼び出しが失敗したということです。
呼び出し失敗の理由を確認するためにIDAPythonでGetLastError();を呼び出すとERROR_FILE_NOT_FOUND(2)であったため指定したファイルが存在しないことが失敗の理由だったと分かります。
IDAPythonでGetLastError();を呼び出す方法については、IDA ProでWin32API実行失敗時のエラーを取得するに説明があります。
2回目のSetFileAttributesA();はこのシェルコードをInjectionした元のマルウェアに対してFileAttributeを設定して成功しています。
- CopyFileA()で元のマルウェアをC:\Users[username]\TMP.exeとしてコピー
自身の削除
利用済みであるマルウェア自身を削除します。MITRE ATT&CKのT1107では、痕跡となるファイルを削除するという検知回避テクニックとして定義されています。
- 元のマルウェアを
DeleteFileA();で削除
Persistenceの獲得
下記の流れでRegistryを利用してPersistenceを獲得します。
-
RegOpenKeyExA();でHKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Runのハンドルを取得 -
RegOpenKeyExA();でHKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Runに、サブキー名MSUDPQPとしてデータC:\Users[username]\Documents\TMP.exeを書き込む

DLLの明示的リンク
以下の流れで悪性DLLファイルのエクスポート関数をインポートします。
LoadLibraryA();で元のマルウェアがTempフォルダにドロップした悪性DLLファイル(※)を読み込みます。
※ SHA256: d837830ed88424304686e510fd6bdac7526db863aad6efb0cd53c0670dc1b1d3
明示的リンク LoadLibraryA()の呼び出しによるDLLのリンク(明示的リンク)に際しては、LoadLibraryA()呼び出し時に呼び出し先のDLLMain()が実行される。
その後、リンクしたDLLが呼び出し元プロセスのメモリにマップされている間に呼び出し元プロセスが新規スレッドを作成 / 終了した際には、リンクしたDLLに対してDLL_THREAD_ATTACH / DLL_THREAD_DETACHの通知が行われる。

GetProcAddress()にて悪性DLLファイルから”abc”をインポートします。
以下2つの文字列ポインタを引数にabc()の呼び出します。
- “movieonline.redirectme[.]net:8080,443,1863;beersale[.]servebeer[.]com:1863,443,8080”
- “h112”

以降、悪性DLLのエクスポート関数abc()上で、マルウェアの不正な振る舞いが続きます。
ROL5 hash
Shellcodeの解析 ROR13編で紹介したROR13というインポート関数を隠すテクニックがありました。それはハッシュ化された関数名からインポート関数のスタートアドレスをスタックに積んで呼び出すというものでした。
ここでは、同じテクニックを13bit右にローテートするROR13ではなく、5bit左にローテートするROL5が使われていました。以下の表にROL5ハッシュを抜粋します。
| ROL5 | 関数名 |
|---|---|
| 10B3A830 | RtlAllocateHeap |
| 51CC8EDD | RtlFreeHeap |
| 325E49 | atoi |
今回もROL5ハッシュ計算コードを置いておきますので、これが理解の助けになるかと思います。
#include <stdio.h>
typedef unsigned int DWORD;
int rol5_hash(const char *string)
{
DWORD hash = 0;
while (*string) {
DWORD val = (DWORD) *string++;
hash = (hash << 5 )|(hash >> 27);
hash += val;
}
printf("hash: %x", hash);
return hash;
}
int main() {
printf("%x", rol5_hash("atoi"));
return 0;
}