Successfully reported this slideshow.
Your SlideShare is downloading. ×

[cb22] Wslinkのマルチレイヤーな仮想環境について by Vladislav Hrčka

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Loading in …3
×

Check these out next

1 of 54 Ad

[cb22] Wslinkのマルチレイヤーな仮想環境について by Vladislav Hrčka

Download to read offline

2021年10月、Lazarusグループに関連する可能性が高いユニークなローダーであるWSLinkの最初の分析を公開。ほとんどのサンプルは難読化され、高度な仮想マシン(VM)難読化機能で保護されている。サンプルには明確なアーティファクトが含まれておらず、当初は難読化を公的に知られているVMと関連付けなかったが、後にそれをCodevirtualizerに接続することに成功。このVMは、ジャンクコードの挿入、仮想オペランドの暗号化、仮想オペコードの重複、難読化手法仮想命令のマージ、ネストされたVMなど、いくつかの追加の難読化技術を導入する。
本発表では、VMの内部を分析し、合理的な時間で難読化技術を「見抜く」ための半自動化されたアプローチについて説明する。また、難読化されたバイトコードと難読化されていないバイトコードを比較し、本手法の有効性を紹介する。われわれの手法は、仮想オペコードのセマンティクスを抽出する既知の難読化解除手法に基づいており、単純化規則によるシンボリック実行を使用。さらに、バイトコードチャンクとVMの内部構成を記号ではなく、具体的な値として扱い、既知の難読化手法で追加の難読化技術を自動的に処理できるようにする。

2021年10月、Lazarusグループに関連する可能性が高いユニークなローダーであるWSLinkの最初の分析を公開。ほとんどのサンプルは難読化され、高度な仮想マシン(VM)難読化機能で保護されている。サンプルには明確なアーティファクトが含まれておらず、当初は難読化を公的に知られているVMと関連付けなかったが、後にそれをCodevirtualizerに接続することに成功。このVMは、ジャンクコードの挿入、仮想オペランドの暗号化、仮想オペコードの重複、難読化手法仮想命令のマージ、ネストされたVMなど、いくつかの追加の難読化技術を導入する。
本発表では、VMの内部を分析し、合理的な時間で難読化技術を「見抜く」ための半自動化されたアプローチについて説明する。また、難読化されたバイトコードと難読化されていないバイトコードを比較し、本手法の有効性を紹介する。われわれの手法は、仮想オペコードのセマンティクスを抽出する既知の難読化解除手法に基づいており、単純化規則によるシンボリック実行を使用。さらに、バイトコードチャンクとVMの内部構成を記号ではなく、具体的な値として扱い、既知の難読化手法で追加の難読化技術を自動的に処理できるようにする。

Advertisement
Advertisement

More Related Content

Similar to [cb22] Wslinkのマルチレイヤーな仮想環境について by Vladislav Hrčka (20)

More from CODE BLUE (20)

Advertisement

Recently uploaded (20)

[cb22] Wslinkのマルチレイヤーな仮想環境について by Vladislav Hrčka

  1. 1. Under the hood of Wslink’s multilayered virtual machine Vladislav Hrčka | Malware Researcher
  2. 2. Vladislav Hrčka Malware Researcher at ESET @HrckaVladislav
  3. 3. アジェンダ •仮想マシン一般とシンボリック実行の紹介 •Wslinkで使用する仮想マシンの内部構造 •難読化に対応するためのアプローチ •アプローチのデモンストレーション
  4. 4. プロセス仮想マシンの基本 • インタプリタがバ イトコードを実行 する • バイトコードには 命令が含まれてい ます。 • オペコード • オペランド • ハンドラが個々の オペコードを定義
  5. 5. 仮想マシンベースの難読化
  6. 6. 仮想マシンベースの難読化
  7. 7. Miasmにおけるシンボリックな実行 • コードを数式で表現する • レジスタやメモリはシンボル値として扱われる • シンボル値に対するコードの効果をまとめる • 頻繁に使用することになる • オリジナルのASM。 MOV EAX, EBX MOV ECX, DWORD PTR [EDX] XOR ECX, 0x123 MOV AX, WORD PTR [ESI] JMP ECX • シンボリック実行を行った。 EAX = {@16[ESI] 0 16, EBX[16:32] 16 32} ECX = @32[EDX] ^ 0x123 zf = @32[EDX] == 0x123 nf = (@32[EDX] ^ 0x123)[31:32] ... EIP = @32[EDX] ^ 0x123 IRDst = @32[EDX] ^ 0x123
  8. 8. Miasmにおけるシンボリックな実行 • 既知の具体的な数値を単純に適用することができる • 具体的な値によって、式を簡略化することができます • シンボリック実行を行った。 EAX = {@16[ESI] 0 16, EBX[16:3… ECX = @32[EDX] ^ 0x123 zf = @32[EDX] == 0x123 nf = (@32[EDX] ^ 0x123)[31:32] ... EIP = @32[EDX] ^ 0x123 IRDst = @32[EDX] ^ 0x123 • 応用編 EDX = 0x96 と @32[0x96] = 0xFEED: EAX = {@16[ESI] 0 16, EBX[16:3… ECX = 0xFFCE zf = 0x0 nf = 0x0 ... EIP = 0xFFCE IRDst = 0xFFCE EDX = 0x96 @32[0x96] = 0xFEED
  9. 9. 紹介終了
  10. 10. • 仮想化された機能 • 仮想化された機能 が含まれます。 • プロローグ • 仮想マシンのエントリー を呼び出す • ギボシコード Wslink ファーストコンタクト
  11. 11. Junk code
  12. 12. 仮想マシンの構成概要
  13. 13. 仮想マシンの構成概要
  14. 14. • 次の仮想命令を準備する • 仮想プログラムカウンタを増加させる • レジスタをゼロにする • RBP_init はコンテキストポ インタ • オフセット 0xA4 の命令表 • 仮想プログラムカウンタ(オ フセット0x28 VM2: 最初に実行された仮想命令
  15. 15. •バーチャル・インストラクション 2 • 複数の仮想レジスタをゼロにする •バーチャル・インストラクション 3 • RSPを仮想レジスタに格納 VM2: 仮想インストラクション2、3
  16. 16. VM2: 仮想インストラクション 4 • 複数の基本ブロック。
  17. 17. • 複数の基本ブロック。 VM2: 仮想インストラクション 4 • 第1ブロックの概要 – メモリアサインとIRDst
  18. 18. • 複数の基本ブロック。 VM2: 仮想インストラクション 4 • 第1ブロックの概要 – メモリアサインとIRDst
  19. 19. • 複数の基本ブロック。 VM2: 仮想インストラクション 4 • 第1ブロックの概要 – メモリアサインとIRDst • ローリングデクリプション – オペランドの暗号化 • オフセット0x0Bと0x70の仮想レジスタの値が先に設 定されていた
  20. 20. VM2: 仮想命令4 - 難読化解除 • 最初のオリジナルブロック
  21. 21. VM2: 仮想命令4 - 難読化解除 • 最初のオリジナルブロック
  22. 22. VM2: 仮想命令4 - 難読化解除 • 最初のオリジナルブロック • ローリングデクリプションレジスタの既知の値の適用 • 既知のバイトコード値を適用するとPOPが判明 IRDst = (-@16[@64[RBP_init + 0x28] + 0x4] ^ 0x3038 == @16[@64[RBP_init + 0x28] + 0x6])?(0x7FEC91ABD1C,0x7FEC91ABCF6) @64[RBP_init + {-@16[@64[RBP_init + 0x28] + 0x4] ^ 0x3038, 0, 16, 0x0, 16, 64}] = @64[RSP_init] IRDst = @64[@64[RBP_init + 0xA4] + 0x5A8] @64[RBP_init + 0x28] = @64[RBP_init + 0x28] + 0x8 @64[RBP_init + 0x141] = @64[RBP_init + 0x141] + 0x8 @64[RBP_init + 0x12A] = @64[RSP_init]
  23. 23. • バーチャルインストラクション4まとめ。 VM2: バイトコードチャンクの難読化を解除する IRDst = @64[@64[RBP_init + 0xA4] + 0x5A8] @64[RBP_init + 0x28] = @64[RBP_init + 0x28] + 0x8 @64[RBP_init + 0x141] = @64[RBP_init + 0x141] + 0x8 @64[RBP_init + 0x12A] = @64[RSP_init]
  24. 24. • サマリーからグラフを作成 • 一部の値を具象値として扱う。 • ローリングデクリプションレジスタ • バイトコードポインタからの相対的なメモリアクセス • ブロック間で復号化レジスタの値のみを保持する VM2: バイトコードチャンクの難読化を解除する IRDst = @64[@64[RBP_init + 0xA4] + 0x5A8] @64[RBP_init + 0x28] = @64[RBP_init + 0x28] + 0x8 @64[RBP_init + 0x141] = @64[RBP_init + 0x141] + 0x8 @64[RBP_init + 0x12A] = @64[RSP_init] virtual_instruction2_1(vpc) virtual_instruction2_2(vpc) virtual_instruction2_1(vpc) virtual_instruction2_3(vpc) virtual_instruction2_4(vpc) • バーチャルインストラクション4まとめ。
  25. 25. VM1: 難読化を解除した仮想命令構造 CFG
  26. 26. VM1: 難読化を解除した仮想命令構造 OUTRO CFG INTRO
  27. 27. OUTRO CFG INTRO
  28. 28. CFG INTRO レジェンダ Yellow – 仮想レジスタをプッシュ Red – 仮想レジスタのポップアップ、コ ンテキストの切り替え Green – アキュムレータレジスタへジャ ンプ OUTRO
  29. 29. • 仮想命令1、2、3 • VM2と同じ動作 VM1: 最初に実行される仮想命令
  30. 30. VM1: 最初に実行される仮想命令
  31. 31. VM1: 最初に実行される仮想命令 • 命令のマージ - POPとPUSHの操作などを含む • オペランドは、どの命令を実行するかを決定する • PUSH:
  32. 32. VM1: 最初に実行される仮想命令 • 命令のマージ - POPとPUSHの操作などを含む • オペランドは、どの命令を実行するかを決定する • POP:
  33. 33. • 命令のマージ - POPとPUSHの操作などを含む • オペランドは、どの命令を実行するかを決定する • PUSH/POP • オペランドを具象化することで単純化できる VM1: 最初に実行される仮想命令
  34. 34. VM1: バイトコードチャンクの難読化を解除する • VM2 と同じ方法を使用します。 • サマリーからグラフを構築する • 特定の値を具体的な値として扱う • ブロック間で特定の値を保持する • 両方の仮想マシンを一度に処理する。 • さらにVM2全体をコンクリート化す る • VM2 コンテキストへの割り当てを無 視する virtual_instruction2_1(vpc) virtual_instruction2_2(vpc) virtual_instruction2_1(vpc) virtual_instruction2_3(vpc) virtual_instruction2_4(vpc)
  35. 35. POPの連続ではなく、予期せぬ分岐 を含むグラフになった VM1: 難読化解除時の不透明な述語に関する問題
  36. 36. VM1: 難読化解除時の不透明な述語に関する問題 •ブランチは既知の値をチェックする • 値を適用して簡略化することができる • これは一種の不透明述語である
  37. 37. その手法は有効か?
  38. 38. 結果の分析 バイトコードブロック VM1 VM2 サイズ(バイト) 695 1,145 処理された仮想インストラクションの総数 62 109 基礎となるネイティブ命令の総数 3,536,427 17,406 IR命令(IRDstsを含む)の総数 192 307 実行時間(秒) 382 10
  39. 39. NON-OBFUSCATED SAMPLE* 処理されたServiceMainバイトコード OBFUSCATED
  40. 40. DEOBFUSCATED
  41. 41. ORIGINAL SAMPLE DEOBFUSCATED SIMPLIFIED mov R0, [R0] mov R1, 28
  42. 42. lea R2, BASE+0xE3808 ORIGINAL SAMPLE DEOBFUSCATED SIMPLIFIED
  43. 43. ORIGINAL SAMPLE DEOBFUSCATED
  44. 44. ORIGINAL SAMPLE DEOBFUSCATED
  45. 45. ORIGINAL SAMPLE DEOBFUSCATED lea R2, BASE+0x2FB0 mov R3, R0 SIMPLIFIED
  46. 46. ORIGINAL SAMPLE DEOBFUSCATED SIMPLIFIED lea Rdest, BASE+0x8C038
  47. 47. ORIGINAL SAMPLE DEOBFUSCATED lea Rdest, BASE+0x8C038 ... jmp Rdest RETaddr = &vm_pre_initX()
  48. 48. •シンボリック実行では、非束縛ループを 処理できない 制限事項 • このようなループを使用する命令は、他の手段 で対処する必要があります。
  49. 49. シンボリック実行は、正しい値を具体的なも のとして扱えば、高度で未知の仮想マシンを 合理的な時間でデヴァーチャライズするのに 役立つ テイクアウェイ
  50. 50. リンク集 ホワイトペーパーは、以下のサイトで 読むことができます。 WeLiveSecurity.com ソースコードの全文はこちら ESET git repository
  51. 51. www.eset.com | www.welivesecurity.com | @ESETresearch Vladislav Hrčka Malware Researcher vladislav.hrcka@eset.com | @HrckaVladislav 質問はありますか?

Editor's Notes

  • Subsequently to starting our analysis found a non-obfuscated sample – we weren’t motivated to fully deobfuscate the code
  • Since 2017 been focusing on reverse engineering challenging malware samples
    Computer Science student at the Comenius University in the first years of master’s degree
    BlackHat Arsenal, AVAR
  • Work like standard machines – machine code is bytecode here
    PC is offset to the bytecode here – not necessary
    Transfer of control from one virtual instruction to the next during interpretation needs to be performed by every VM. This process is generally known as dispatching
    Centralized interpreter – dispatcher – called direct call threading; can be also simple switch case
    Can be also inside of handlers – direct threading
  • Stored in sep.arate section
    Need context switch

    Bytecode is generated from a function
    Original function starts interpreter
    Interpreter is embedded in the executable
    Context switch needs to be performed
    Stored in a separate section
    Need context switch

    Bytecode is generated from a function
    Original function starts interpreter
    Interpreter is embedded in the executable
    Context switch needs to be performed



  • The strength of this obfuscation technique resides in the fact that the ISA of the VM is unknown to any prospective reverse engineer – a thorough analysis of the VM, which can be very time-consuming;
    Additionally, obfuscating VMs usually virtualize only certain “interesting” functions
  • SE in IR
    IRDst 1. stands for 2. is IR instruction pointer, e.g. cmov multiple blocks
    X bit value dereference
    Self explainable dereference
  • SE engine in Miasm automatically performs common optimization techniques
  • The VM used in the Wslink is a variant of CV (themida) that supports multiple VMs and polymorphic layers of obfuscation techniques. We found this out subsequently to publishing our research
  • The right side contains a part of the function
  • Why 1071? They are duplicated!
    Vm_init – Sync – shared virtual context in the memory
    Virtual program counter (VPC) register
    Base address register
    Instruction table register
  • Zdorazni nested VM – zacneme VM2
  • Rolling decryption – present in a blog about VM Protect’s structure
  • Make values relative to the bytecode ptr concrete
  • We’ve just deobfuscated one of the VM1 instructions
  • Let’s start with CFG
  • Reminder – atomic operations in blocks
  • Laser point – These IR blocks are effects of VM2 virtual instructions, they represent one VM1 virtual instruction together
  • Zeroes out a register, stores the RSP, initializes rolling decryption registers
  • A part of the instruction. When we inspected the code, we realized what the problem is
  • Memory range of the VMs is known – separate section
  • Let’s take a closer look at one of the branches

    <CLICK>
  • The branches check a known value
    We can apply the value and simplify it
    This is a sort of opaque predicates
  • We will show the results on the first executed bytecode, but before that show statistics
  • Before we look at the devirtualized bytecode, let’s see what the execution time is approximately like

    Let’s look at the deobfuscated bytecode block of VM1 <CLICK>

  • *We discovered the sample after starting our analysis
  • No ARM R0! – pseudocode close to assembly
  • Advanced – use junk code, duplicate and merge handlers, encrypt operands
    Right values – operands and registers for encryption

×