
BlackLotus-Z2A-Challenge、今はここには何もありません。どうぞ通り過ぎてください
まず最初に

美的な目的のためだけに、プロっぽく見せるために、@darthmaulware(Ryan “DM” Smith) のソリューションからyara検出ルールを恥知らずにも借り(盗み)ます :)) 彼のツイッターをチェックしてみて。彼はマジでクールな人だよ! 追伸:ライアン、それを盗んだことで怒らないでね :))) ディスコードでのサポートありがとう :)
彼の作品もぜひチェックしてみて :)
https://gitlab.com/malre-rcs/zero2automated/-/blob/main/solutions/bi_weekly_challenge/BlackLotus_20230321/BlackLotus_HTTP_Downloader.ipynb``` rule Blacklotus_HTTP_Downloader { meta: description = "Rule to detect Blacklotus HTTP Downloader" author = "Darth Maulware" sha256 = "d68f668b4240f9518e4f80499d93d8c5a1eddece0771658c33ae916cc54f5a66"
strings:
$opcode1 = {48 89 4C 24 08 48 89 54 24 10 4C}
$opcode2 = {89 44 24 18 4C 89 4C 24 20 48 83}
$opcode3 = {EC 28 B9 31 62 D7 2E 90 90 E8 ??}
$opcode4 = {?? ?? ?? 48 83 C4 28 48 8B 4C 24}
$opcode5 = {08 48 8B 54 24 10 4C 8B 44 24 18}
$opcode6 = {4C 8B 4C 24 20 4C 8B D1 90 90}
condition:
(uint16(0) == 0x5a4d and filesize < 500KB and all of them)
}
また、美的な理由から、これもかっこいいので盗用します :) 繰り返しになりますが、ごめんね ryan、怒らないでください :)```
C:\\Users\\REM\\Desktop>capa.exe -f pe -r capa-rules-5.0.0 d68f668b4240f9518e4f80499d93d8c5a1eddece0771658c33ae916cc54f5a66.exe
matching: 100%|████████| 124/124 [00:02<00:00, 46.96 functions/s, skipped 1 library functions (0%)]
+------------------------+------------------------------------------------------------------------------------+
| ATT&CK Tactic | ATT&CK Technique |
|------------------------+------------------------------------------------------------------------------------|
| DEFENSE EVASION | Obfuscated Files or Information T1027 |
| DISCOVERY | Process Discovery T1057 |
| EXECUTION | Shared Modules T1129 |
+------------------------+------------------------------------------------------------------------------------+
+-----------------------------+-------------------------------------------------------------------------------+
| MBC Objective | MBC Behavior |
|-----------------------------+-------------------------------------------------------------------------------|
| ANTI-BEHAVIORAL ANALYSIS | Debugger Detection::Process Environment Block BeingDebugged [B0001.035] |
| | Debugger Detection::Process Environment Block NtGlobalFlag [B0001.036] |
| CRYPTOGRAPHY | Encrypt Data::RC4 [C0027.009] |
| | Generate Pseudo-random Sequence::RC4 PRGA [C0021.004] |
| DATA | Encode Data::XOR [C0026.002] |
| DEFENSE EVASION | Obfuscated Files or Information::Encoding-Standard Algorithm [E1027.m02] |
+-----------------------------+-------------------------------------------------------------------------------+
+------------------------------------------------------+------------------------------------------------------+
| CAPABILITY | NAMESPACE |
|------------------------------------------------------+------------------------------------------------------|
| execute syscall instruction (35 matches) | anti-analysis |
| check for PEB BeingDebugged flag (2 matches) | anti-analysis/anti-debugging/debugger-detection |
| check for PEB NtGlobalFlag flag | anti-analysis/anti-debugging/debugger-detection |
| encode data using XOR (2 matches) | data-manipulation/encoding/xor |
| encrypt data using RC4 PRGA (2 matches) | data-manipulation/encryption/rc4 |
| get process heap flags | host-interaction/process |
| get ntdll base address (3 matches) | linking/runtime-linking |
| parse PE header (2 matches) | load-code/pe |
| resolve function by parsing PE exports (2 matches) | load-code/pe |
+------------------------------------------------------+------------------------------------------------------+
tbh 正直言うと、もし私があなたの立場なら、capa を100%信頼しないでしょう(少なくともこの特定のケースでは)。なぜなら、ここではサンプルが RC4 を使用していると表示されていますが、実際にはサンプルは AES を使用しているからです。しかし、とにかく、前述の通りこれは厳密に見た目のためのものです :)
始める前に、このレポートを通じてたくさんの

に出くわすでしょう。
これは無視してください。ida がこれをアセンブリで正しく逆アセンブルできないためです。これは

そして、これによりデバッガがクラッシュしますか?なぜでしょうか?
なぜなら、アドレス0に書き込もうとするからです。これはハッカーの間ではヌルポインタアドレスへの書き込みとして知られており、CE(コード実行)を取得するために広く悪用されていたもので、当然ながら緩和されています。
そして、現在の緩和策では、0に書き込もうとすると、そのプロセス(この場合はマルウェア)がクラッシュし、結果としてデバッガもクラッシュします。
次に、これを IDA で開くと

すべての関数に、それが行うロジックを示す名前を付けました。最初の関数 do_syscall() から始めましょう。

すぐに syscall の使用に気づきます。これは動的解析の際にアナリストの生活を困難にする既知の手法です。
Windows の syscall に詳しくない方のために、oalabs による素晴らしいビデオがあります(https://www.youtube.com/watch?v=Uba3SQH2jNE)。私も見ましたが、この関数で何が起こっているのかを理解するのに大いに役立ったので、ぜひ見てください。
IDA が解決した「擬似コード」を調べると、次のようになります。

solve_hash を静的に調べると、次のようになります。


擬似コードの観点から見ると、次のようになります。

この「エミュレーション」を見たい場合、または syscall がハッシュルックアップアルゴリズムによってどのように解決されるかを知りたい場合は、solve_hash.py を参照してください。とはいえ、これは SysWhispers2 というプロジェクトの一部です。少なくとも、マルウェアの作者がインスピレーションとして使用したのはそれだと思います。理解を深めるには、上記の oalabs のビデオクリップを参照してください。
とにかく、anti_debug 関数は簡単にバイパス可能で、よく知られています(https://anti-debug.checkpoint.com/techniques/debug-flags.html#manual-checks-ntglobalflag)。バイパスする方法は、scyllahide をインストールし、NtGlobalFlag にチェックを入れることです(x86dbg を使用している場合はデフォルトでオンになっているはずです)。とはいえ、これが確認すべき項目です。

そして、これが anti-debug の「擬似関数」の外観です。

私から言わせれば、とてもシンプルです。
次に、check_inmemory_ldr 関数があります。次のようになります。


さて、関数解析の目的で、x86dbg に丁寧に頼めば、syscall 命令まで実行すると、x86dbg が実行しようとしている syscall を返してくれます。私たちの場合、

現在のコンテキストに基づくと、Ntsetinformationthread が何らかのアンチ解析トリックとして使用されていると推測できます。確かに、簡単に Google 検索すると、これが見つかります: https://ntquery.wordpress.com/tag/ntqueryinformationthread/
幸いなことに、簡単にバイパス可能で、nop+ret パッチを当てるだけです :)
=============================================================================
実行順序に従うと、この次の関数の後は

もう一度、それが何をするのか調べると

これは単に TEB 内のフラグをチェックして、現在のプロセス(この場合は exe)がデバッグされているかどうかを確認します。これも既知の方法(https://anti-debug.checkpoint.com/techniques/debug-flags.html#manual-checks-peb-beingdebugged-flag)なので、やはり簡単にバイパスできます。前回 scyllahide を使用したのと同じ方法で、今回はこれにチェックを入れている必要があります。

これはデフォルトでオンになっているはずです。
=============================================================================
次に、custom_hash2_and_aplib_possible です。次のようになります。

そして、グラフの観点から見ると

この関数の「エミュレーション」を見るには、decompress_aplib.py を参照してください。
get_ntdll_and_unhook2 を調べると、次のようになります。


グラフビューでは、次のようになります。

なかなかやりますね :))
少し遡ると、aplib_decompress があります。今回、それは次のようになっています。

静的コード解析では、次のようになります。




うーん、少し大きいですが、ここで心配することは何もありません。皆さん、実行可能です :)
aplib_decompress.py エミュレーションスクリプトを使用すると、次のような結果になるはずです。

他のブログや分析では気づかなかった素晴らしい点はこれです。ntdll_and_unhook2 の IDA の擬似コードをもう一度見てみると

興味深い memcpy が表示されます。
動的解析を行っていたとき、別の DLL がロードされていることに気づきました。それは別のバージョンの ntdll でした。

デバッガで見ると、次のようになります。

何がフック/パッチされているかを検出することはできませんでしたが、もし知っている人がいれば、プルリクエストを送ってこのドキュメントを編集してください。また、何がフックされるのかを見つける試みとして、2つの ntdll 間で bindiff を取ろうとしましたが、残念ながら何も見つかりませんでした。ただし、それは、すでに感染したシステム DLL に対して差分を取っていたためかもしれません。クリーンな実行ではなかったので、それが理由かもしれません ¯_(ツ)_/¯

=============================================================================
解析プロセスをさらに進めると、未説明の関数として some_hasing と ntquertyinformationprocess_anti_debug があります。これらはまだ説明されていません。check_if_being_debug_through_teb と anti_debug は、上記の関数で使用されていたため、幸い既に説明しました。それらの知識を復習したい場合は、上のセクションを読んでください。最初に ntquertyinformationprocess_anti_debug から始め、その後 some_hasing で締めくくりたいと思います。
それを調べると、同じ関数が3回呼び出されているのがわかります。

そして、アセンブリの観点から見ると


便利なように、私はすでにそれに名前を付けました。それが ntquertyinformationprocess_ProcessDebugPort です。呼び出された関数が ntquertyinformationprocess_ProcessDebugPort であることをどうやって知ったのか?それらを調べると、すでに見た関数呼び出し/既知のアルゴリズムが明らかになります。

IDA で付けられたコメントはどうでしょうか? Google で ntqueryinformationprocess を検索すると、アンチデバッグに関する良いリソースが見つかります(https://anti-debug.checkpoint.com/techniques/debug-flags.html)。それに沿って進むと、この関数にパラメータとして渡される特定の値に基づいて、アンチデバッグ手法として使用できることが説明されているのがわかります。
例えば、最初の呼び出しでは、デバッガで次のスタック引数を見ることができます。

次に、ntqueryinformationprocess の MSDN ページを確認してみましょう。

次の2つの syscall でも同じプロセスが繰り返されます。

ここで、0x1e は ProcessDebugObjectHandle アンチデバッグ手法に固有のものです(https://www.apriorit.com/dev-blog/367-anti-reverse-engineering-protection-techniques-to-use-before-releasing-software)
そして最後に ProcessDebugFlags

では、どうやってそれらをバイパスするのか?! 落ち着け、相棒。ScyllaHide が君の面倒を見てくれるから。

ご覧のとおり

だから安全だ! いや、そうでもない。ScyllaHide は最初の2つの syscall では私たちを守ってくれますが、最後の syscall は手動でやらなければなりません! で、一体どうすればいいの??? 簡単な解決策があります! この関数、つまり ntquertyinformationprocess_anti_debug 全体から return し、eax を 0 に設定します。通常の状況では、次のようになります。

そして、私たちの「助け」を入れると、次のようになり、実行を安全に続行させることができます :)

=============================================================================
次は some_hasing です。手順はもうお分かりでしょう。

そして、擬似コードは次のとおりです。

ここで奇妙なことに気づきます。IDA の擬似コードはここでは失敗しています... なぜなら、call_syscall の後のグラフをたどると、逆アセンブルすべき命令がまだあるからです。では、ここでどうするのでしょうか? ここではデバッガに頼って、このコードを動的に解析します...
そして、それが実行する syscall は次のとおりです。

さて、ntquerydefaultlocale を調べると、Google はこれが2つの引数を取る非公開 API であることを示しています(http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FLocale%2FNtQueryDefaultLocale.html)。で、それは何をするのか? 現在の Locale Identifier を返します。では、Locale Identifier とは一体何なのでしょうか? MSDN(https://learn.microsoft.com/en-us/windows/win32/intl/locale-identifiers)によると、言語識別子と並べ替え順序識別子から構成される32ビット値です。要するに、その PC で話されている言語です :)
その後、API の実行が失敗しなかったかどうかを確認し、失敗しなかった場合は ntquerydefaultlocale によって返された値を取得し、0x419 を減算して 0x26(おそらく定数)と比較します。下の画像で確認できます。

0x26 以下でない場合は 0x818 と比較し、それ以外の場合は 0x819 と同じ比較を行います。明確に確認できます。

で、ここで一体何が起こっているのか? そしてなぜこれらの特定の定数なのか? 率直に言います。さまざまな定数を検索しているときに、この記事(https://www.cnblogs.com/DirWang/p/17281690.html#autoid-8-0-0)に出会いました。そこでは、ある研究者が私よりもはるかに上手く blacklotus を分析しています。そして、かつて誰かが言ったように、「マルウェア解析でズルはできない。ただ作業を楽にすることはできるだけだ」。研究者が言ったのは、基本的にこの関数は、コンピュータ上で話されている言語を識別する特定の定数をチェックしているということです。彼の記事では、すべての言語識別子が載っている Microsoft の標準文書のようなものへのリンク(https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-LCID/[MS-LCID].pdf)を提供しています。
さて、ハッカー風のクールな論理を使えば、おそらく 0x26 はオフセットのようなものだと推測できます。つまり、0x419 の後の任意の 0x26 個の言語識別子、次のようなものです。

その文書も調べると、0x818 が次に対応していることがわかります。

そして 0x819 は

そして、以前の「調査」やオンラインレポートから、このマルウェアが世界の特定の地域の特定の PC では実行されなかったことを知っています。したがって、この関数が感染したマシンの地域を確認していると結論付けることができます。
=============================================================================
ここまでクレイジーなハンバーガーだな、相棒。次は何だ? some_more_syscall 関数をお届けしよう。よし! で、何がそこにあるんだ、あっ! これだ。

もっと欲しい? もちろんさ、相棒!



ふむ

つまり、カーネルデバッガが存在するかどうかをチェックしています(https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi/system_information_class.htm)(0x23)。チェック、チェック!
で、何だって、あっ! 我々は PCR(山と組み合わせのパーティー)を手に入れた。

=============================================================================
次に、iterate_over_modules() 関数を調べると、次のようになります。

「擬似コード」の観点から見ると、次のようになります。

単独の観点から見ると、アセンブリと IDA の擬似コードは一致しているように見えます。では、この関数のロジックは何をするのでしょうか? とても簡単です。メモリ内のモジュール(DLL)を反復処理し、ハッシュのリストと照合します :) v4[0] = 0x1E7EACEF; v4[1] = 0x4468A620; v4[2] = 0x68536B95; v4[3] = 0x73EBBB53; v4[4] = 0xDA165168; v4[5] = 0xB24D33A7; v4[6] = 0xB1E2CEC6; v4[7] = 0x5136992; v4[8] = 0x98C500D9; v4[9] = 0x3E0169B6;
そして、同じハッシュを持つメモリ内 DLL が見つからなければ 0 を返し、見つかれば 1 を返してデバッガをクラッシュさせます。したがって、これは別のアンチ解析方法であると言えます。正しいですが、各ハッシュ値についてはどうでしょうか? またズルをします(かつて誰かが言ったように、マルウェア解析ではズルはできず、ただ自分の生活を楽にするだけです :))。上で述べたアジア人研究者は、値の導出元となるリストを親切にも提供してくれました。
sbiedll.dll dbghelp.dll api_log.dll dir_watch.dll pstorec.dll vmcheck.dll wpespy.dll cmdvrt64.dll avghookx.dll snxhk.dll
次に、これらの値が前述のいずれかの DLL に対応するかどうかを動的に確認します。

そして、案の定、対応しています :)
しかし、どうやってこのアルゴリズムがこれらの値をチェックしているという結論に至ったのでしょうか? このマルウェアの一部をエミュレートしたとき、iterate_over_module_name_and_hash(solve_hash_syscalls.py ファイル内)を再実装する必要がありました。この関数には次のものがあります。

ここで、x(渡される引数)はこの場合 v2 であり、これは値の配列(ポインタ)です。上で述べた値のいずれにも一致しない限り、配列内のどこを指すかがインクリメントされます。いやー、長ったらしいな :P
クールだね! 次へ
=============================================================================
iterate_over_modules2 もほぼ同じ話です。

そして擬似コード

ほぼ同じ話で、ハッシュだけが異なります :)
v5[0] = 0x7D73878E; v5[1] = 0xEF36424B; v5[2] = 0xAF64BC2B; v5[3] = 0x1DBBC879; v5[4] = 0xAE6D1D56; v5[5] = 0x7B3242F2; v5[6] = 0x14D922B9; v5[7] = 0x4C92DF53;
これらは次に対応します
sample.exe bot.exe sandbox.exe malware.exe test.exe klavme.exe myapp.exe testapp.exe
=============================================================================
iterate_over_modules3 もここでは同じ話です。

そして擬似コード

同じ話で、ハッシュが異なるだけです :)v4[0] = 0x42D12D59; v4[1] = 0xEC5D7AA; v4[2] = 0x861E460F; v4[3] = 0x84BCC8DB; v4[4] = 0x6474D72B; v4[5] = 0xB8B9C504; v4[6] = 0x69A0620E; v4[7] = 0x6017EE43; v4[8] = 0xE93BE2E0; v4[9] = 0x149EFC55; v4[10] = 0xE3FA84A4; v4[11] = 0x7CFDD7AF; v4[12] = 0x5B098C67; v4[13] = 0x2F1FB18E; v4[14] = 0xFE8F2B18;
これは以下に対応します
prl_cc.exe prl_tools.exe qemu-ga.exe vmtoolsd.exe vmwaretray.exe vmwareuser.exe VGAuthService.exe vmacthlp.exe vboxservice.exe vboxtray.exe VMSrvc.exe VMUSrvc.exe xenservice.exe
=============================================================================
Anti_debug_measure_1 は、結局 anti_debug_measure2_RtlAddVectoredExceptionHandler_int3 にリネームしました。なぜかは、すぐに分かります。このようになっています。

そして擬似コードの観点から見ると、このようになります。

で、これは一体何なのか?基本的には __debugbreak(int 3) 用の例外ハンドラを作成しており、int3 が発生するたびにコードを実行する仕組みです。さらに調べていくと、この記事にたどり着きました。
(https://blog.lexfo.fr/dridex-malware.html) これはクールなリソースで、これが単なるアンチデバッグ機構であることを教えてくれます。このケースでは、この関数を実行するだけで、int3 を実行するたびにトリガーされる sub_13F2820D0 を無視して、eax を 0 にパッチします :) つまり、メモリ上での実行は次のようになります :)
パッチ前

パッチ後

その後、関数を終了し、rax/eax も 0 に書き換えて、デバッガをクラッシュさせる jne をスキップします。

=============================================================================
Anti_debug_measure_2 は、後で anti_debug_measure2_RtlAddVectoredExceptionHandler_int2 に変更しました。


またまた目新しいことは何もなく、同じ仕組みで、今度は別の int/syscall、つまり int2 をフックしているだけです。バイパスのトリックも同じで、戻り値を動的にパッチして回避します :)
Google で「anti analysis 2dh」を検索すれば、たくさんの情報が出てくるので、それを参考にしてもっと詳しく学べます。私はこれにはあまり時間をかけませんでした :)
これについては、ステップオーバーしようとしても、結局ここにあるように ret に到達します。

これをバイパスするには、単純に return まで実行すればそれで大丈夫です :)
=============================================================================
さて、次は anti_debug measure heap です。これは後で iterate_over_current_process_and_check_again_hases にリネームしました。

この関数のクールな特徴は、iterate_over_current_process_and_hash_check 内で ntquerysysteminformation を使って、実行中のすべてのプロセスを一覧表示していることです。iterate_over_current_process_and_hash_check は次のようになります。


クールな豆だ。でも、どうやって iterate_over_current_process_and_hash_check が名前の通りのことをしていると結論付けたのか?まず、ntquerysysteminformation 呼び出しがある。Google で検索すれば、実行中のプロセスの一覧を取得するために使われることが分かる。そして、次のコードスニペットに基づいて、知識に基づいた推測をしただけだ。 LODWORD(v4) = RtlAllocateHeap(NtCurrentPeb()->ProcessHeap, 8u, v10); v3 = v4; v5 = ntquerysysteminformation(); v6 = v3; .... memcpy(v9, v6[8], *(v6 + 28)); v9[*(v6 + 28) >> 1] = 0; if ( some_hash_0x1003F(v9) == a1 ) つまり、プロセスの一覧をコピーし、それぞれを反復処理して、以前の配列の各ハッシュと、実行中のプロセスを比較するということです。ここでもまた、アジア系の研究者のブログに感謝します。彼がどうやって v4 配列の値の実際の名前を取得したのか、まったく謎です。これをどうエミュレートしたか見たい場合は、iterate_over_modules.py を参照してください。
追記: この関数を動的にデバッグすると、また int 2d に当たります。解決策は上記と同じで、基本的に return まで 0xf 回実行します。これは基本的にヒープを走査します。その後、iterate_over_current_process_and_check_again_hases からの return を確実にヒットさせたい場合は、この関数の最後にブレークポイントを置けば安全です :)
============================================================================= anti_debug_measure_heap



それで、幸運なことにこれはそれほど大きくありません。さらに、すでに demangle_strings を実装しています。今回はこれをより大きな配列向けに再実装したので、anti_debug_measure.py を見てください。
これは基本的に、次のものと照合します。``` \Registry\Machine\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters \Registry\Machine\SYSTEM\ControlSet001\Services\vioscsi \Registry\Machine\SYSTEM\ControlSet001\Services\VirtIO-FS Service \Registry\Machine\SYSTEM\ControlSet001\Services\VirtioSerial \Registry\Machine\SYSTEM\ControlSet001\Services\BALLOON \Registry\Machine\SYSTEM\ControlSet001\Services\BalloonService \Registry\Machine\SYSTEM\ControlSet001\Services\netkvm \Registry\Machine\SOFTWARE\VMware, Inc.\VMware Tools \Registry\Machine\HARDWARE\ACPI\DSDT\VBOX__ \Registry\Machine\HARDWARE\ACPI\FADT\VBOX__ \Registry\Machine\HARDWARE\ACPI\RSDT\VBOX__ \Registry\Machine\SOFTWARE\Oracle\VirtualBox Guest Additions \Registry\Machine\SYSTEM\ControlSet001\Services\VBoxGuest \Registry\Machine\SYSTEM\ControlSet001\Services\VBoxMouse \Registry\Machine\SYSTEM\ControlSet001\Services\VBoxService \Registry\Machine\SYSTEM\ControlSet001\Services\VBoxSF \Registry\Machine\SYSTEM\ControlSet001\Services\VBoxVideo
次に get_oem_key







まず、文字列をデマングルして```
\Registry\Machine\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0
\Registry\Machine\SYSTEM\ControlSet001\Control\SystemInformation
\Registry\Machine\HARDWARE\Description\System
Identifier
SystemManufacturer
SystemBiosVersion
VMWARE
QEMU
VBOX
そして、以下のクエリを実行し
\Registry\Machine\HARDWARE\DEVICEMAP\Scsi\Scsi Port 0\Scsi Bus 0\Target Id 0\Logical Unit Id 0
\Registry\Machine\SYSTEM\ControlSet001\Control\SystemInformation
\Registry\Machine\HARDWARE\Description\System
これらの値を qemu、vbox、VMWARE と照合します。IDA スニペットと x86 ウィンドウで確認できるとおりです :)


最初のスニペットでわかるように、分析時に私のVMに保存されていた任意の値と vmware を照合しています :)
大したことではなく、この関数を ret まで実行し、戻るときに eax を 0 に変更するだけです :) このアンチ解析手法を回避するには :)
=============================================================================
次に get_oem_from_firmware





さて、興味深いことに、この関数は sub_13F267288() から始まり、0x52534D42 がパラメータとして渡されています。この値をGoogleで検索すると、さまざまなフォーラムで多くの興味深い質問が見つかります。例:(https://ru.stackoverflow.com/questions/778618/c-%D0%9A%D0%B0%D0%BA-%D0%B4%D0%BE%D1%81%D1%82%D0%B0%D1%82%D1%8C-%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D1%8E-%D0%BE%D0%B1-%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B9%D1%81%D1%82%D0%B2%D0%B0%D1%85-%D0%BA%D0%BE%D0%BC%D0%BF%D1%8C%D1%8E%D1%82%D0%B5%D1%80%D0%B0-%D0%BD%D0%B5-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D1%83%D1%8F-wmi) (https://msdn-whiteknight.github.io/answers/html/tools/html/ru.stackoverflow.com/posts/780170.html) (https://www.maldun.com/analysis/YXNkZmRzZmFkc2Y2NDEwNjlkc2Zhc2RmYXNkZg==/) あるいはこれ (https://github.com/digitalocean/go-smbios/blob/master/smbios/stream_windows.go)。しかし最も興味深いのは、これを読んで RSMB を検索すると、https://evasions.checkpoint.com/techniques/firmware-tables.html にたどり着くことです。そこでは、これがアンチ解析手法であると説明されています :) で、これは一体何をするのでしょうか?
まず SMBIOS ファームウェアテーブルをダンプし、次に文字列をデマングルします。最初の文字列は qemu で、その後、デマングルされた文字列とファームウェアテーブルをパラメータとして sub_13F2655E0 を呼び出します。静的解析によると


正確には、if ( v4 != v5) という条件から、これは strcmp 的な実装だと結論づけました。ファームウェアテーブル内の値をデマングルされた文字列と照合します。デバッガで確認できるとおりです
r8 はファームウェアテーブルへのポインタで、さらに興味深いことに、ファームウェアテーブル内には virtualbox という名前があり、rcx は qemu です。うんぬん... つまり、これは strcmp 的な実装と言って差し支えありません。そして、見てのとおり、このチェックは無事通過できます :)

次に、この処理は VirtualBox、vbox、VBOX、VMware という文字列に対しても繰り返されます :) 一般的に、この関数のチェックを回避する方法は、ret まで実行して eax をパッチし、解析を続行することです :)
============================================================================
では次に check_oem_key()






で、これは何をするのか? まあ、前に説明したのと同じトリックですが、今回は ACPI テーブルを使います。どういう意味かって? この14枚のスライド (https://dc4420.org/slides/2015-11-24/acpi_vm_detect.pdf) を読むとよくわかりますが、同じ安直なトリックです :)) 今回は BOCHS、BXPC、VMWARE に対してです。


============================================================================
まず anti_debug_processor_Timing() 関数から始めて、最後に check_for_flags() を確認します。では

これはこのような見た目です。で、これは何をするのか? プロセッサのタイムスタンプの現在値を読み取り、プロセッサの名前(この場合は GenuineIntel)を取得し、プロセッサ名から取得したタイムスタンプを引き算し、その結果が 19999 より大きいかどうかを確認するだけです。
rdtsc の後

cpuid の後

見てわかるように、文字列は3つのレジスタに分割されています

そしてこのケースでは、このチェックに「失敗」し、eax を 1 に設定しているのがわかります

このアンチチェックの解決策は、単純に関数から戻り、eax を 0 にパッチすることです :)
============================================================================
次に entry_to_peb()







擬似コードの観点から見ると



ここで、if チェックまでの部分には新しいものはありません。この種のアルゴリズムは既に見ました。で、それがどうしたのか? 既に言及したアジアのリサーチの記事を見ると、Windows のバージョンが win7/server 2008 r2 より新しいかどうかを確認していると書かれています。しかし、どうやってそのアイデアに至ったのでしょうか? http://waleedassar.blogspot.com/2012/08/major-minorsubsystemversion.html を読むと、彼はこう言っています

また、これも読むと :)
そして、ここに書かれている内容を適用すると、KUSER_SHARED_DATA 構造体に自動的にキャストされます。ただし、ここでは分析中に IDA がバグっていたので、まあそんなところです :)
同じようなアルゴリズムの繰り返しで退屈させないために、最終的に取得されデマングルされた文字列をここに示します :) これはデバッガで実行したため、かなり骨の折れる作業でした :) エミュレートするのが面倒だったのです``` user32.dll advapi32.dll Rpcrt4.dll bcrypt.dll ole32.dll Cabinet.dll
CreateWindowExW
ShutdownBlockReasonCreate
ShutdownBlockReasonDestroy
DestroyWindow
CloseHandle
CreateProcessW
InitializeProcThreadAttributeList
UpdateProcThreadAttribute
LoadAppInitDlls
Sleep
GetExitCodeProcess
MoveFileExW
OpenSCManagerW
OpenServiceW
QueryServiceStatus
StartServiceW
CloseServiceHandle
GetUserNameW
ConvertSidToStringSidW
LookupAccountNameW
CreateWellKnownSid
LookupPrivilegeValueW
ConvertStringSecurityDescriptorToSecurityDescriptorW
RpcStringBindingComposeW
RpcBindingFromStringBindingW
RpcStringFreeW
RpcBindingSetOption
RpcBindingSetAuthInfoExW
RpcBindingFree
NdrClientCall2
NdrClientCall3
BCryptOpenAlgorithmProvider
BCryptSetProperty
BCryptGenerateSymmetricKey
BCryptDecrypt
BCryptDestroyKey
BCryptCloseAlgorithmProvider
BCryptGetProperty
BCryptGenRandom
CoCreateInstance
CoInitializeEx
CoUninitialize
CoInitializeSecurity
CoSetProxyBlanket
if >win7/server 2008 r2
{
CreateDecompressor
CloseDecompressor
Decompress
}
これにて、blacklotus 解析チャレンジの前半が終了となります。
============================================================================
後半については
アセンブリの観点

疑似コードの観点

some_hash() 関数から解析を始めます。
============================================================================
グラフの観点

アセンブリの観点



疑似コードの観点
