PracticalMalwareAnalysis-Labs16 WriteUp

Practical Malware Analysis (by Michael Sikorski and Andrew Honig) Lab16のWriteUp。
まずは自分の解答を載せて、最後に模範解答を載せる。不正解の解答も戒めとしてそのまま載せる事とする。
ラボはこちらからダウンロード可能。

Lab 16-1

解析対象のファイルは以下の通り。

ファイル名ファイルの種類MD5ハッシュ値
Lab16-01.exe32ビット EXE7FAAFC7E4A5C736EBFEE6ABBBC812D80

※このファイルはLab09-01.exeにアンチ・デバッグの機能が追加されたものである。

1. Which anti-debugging techniques does this malware employ?

このマルウェアはProcess Environment Block (PEB)のデータを参照して、自身がデバッグされているか判断する。

  • PEBのBeingDebuggedフラグを確認する。
  • PEBのProcessHeapのForceFlagsを確認する。
  • PEBのNTGlobalFlagを確認する。

以下のコードはPEB (fs:30h) のオフセット2に格納されている値が0と等しいか確認している。PEBのオフセット2にはBeingDebuggedフラグの値が格納されており、プログラムがデバッグされている場合はこの値が1となる。

.text:00403540 C7 85 DC E7 FF FF 00 00+mov     [ebp+var_1824], 0
.text:0040354A C7 85 D8 E7 FF FF 00 00+mov     [ebp+var_1828], 0
.text:00403554 64 A1 30 00 00 00       mov     eax, large fs:30h ; PEB moved to eax
.text:0040355A 8A 58 02                mov     bl, [eax+2]     ; copying the value at offset 2 (BeingDebugged) of PEB to bl
.text:0040355D 88 9D E0 E7 FF FF       mov     [ebp+var_1820], bl
.text:00403563 0F BE 85 E0 E7 FF FF    movsx   eax, [ebp+var_1820]
.text:0040356A 85 C0                   test    eax, eax
.text:0040356C 74 05                   jz      short loc_403573 ; check if BeingDebugged flag is set


以下のコードはPEB (fs:30h)のオフセット0x18に格納されているProcessHeapをレジスタに読み出し、ProcessHeapのオフセット0x10の値が0と等しいか確認している。ProcessHeapのオフセット0x10にはForceFlagsが格納されており、ForceFlagsの値を確認することでヒープがデバッガ内で作成されているかどうか判断する。

※ただし、Windows 7ではProcessHeapのオフセット0x10にForceFlagsは格納されていない。従ってWindows XPより後のWindowsでは、このアンチ・デバッグは機能しないかもしれない。


.text:00403573                         loc_403573:             
.text:00403573 64 A1 30 00 00 00       mov     eax, large fs:30h ; PEB moved to eax
.text:00403579 8B 40 18                mov     eax, [eax+18h]  ; copying the value at offset 0x18 (ProcessHeap) of PEB to eax
.text:0040357C                         db      3Eh             
.text:0040357C 3E 8B 40 10             mov     eax, [eax+10h]  ; copying the value at offset 0x10 (ForceFlags) of ProcessHeap to eax
.text:00403580 89 85 DC E7 FF FF       mov     [ebp+var_1824], eax
.text:00403586 83 BD DC E7 FF FF 00    cmp     [ebp+var_1824], 0
.text:0040358D 74 05                   jz      short loc_403594 ; Check ForceFlags in ProcessHeap to see if the heap was created within a debugger


以下のコードはPEB (fs:30h)のオフセット0x68に格納されている値が0x70と等しいか確認している。PEBのオフセット0x68にはNTGlobalFlagが格納されている。プログラムがデバッグされている場合、NTGlobalFlagの値が0x70となる。

.text:00403594                         loc_403594:             
.text:00403594 64 A1 30 00 00 00       mov     eax, large fs:30h ; PEB moved to eax
.text:0040359A                         db      3Eh             ; copying the value at offset 0x68 (NTGlobaFlag) of PEB to eax
.text:0040359A 3E 8B 40 68             mov     eax, [eax+68h]
.text:0040359E 83 E8 70                sub     eax, 70h
.text:004035A1 89 85 D8 E7 FF FF       mov     [ebp+var_1828], eax
.text:004035A7 83 BD D8 E7 FF FF 00    cmp     [ebp+var_1828], 0 ; check if the value of NTGlobalFlag is 0x70 by subtracting 0x70 from NTGlobalFlag and comparing the result with 0
.text:004035AE 75 05                   jnz     short loc_4035B5 ; Check NTGlobalFlag to determine the presence of debugger

2. What happens when each anti-debugging technique succeeds?

上述したアンチ・デバッグによってデバッガの存在が確認された場合、マルウェアは自身を削除する。この削除の処理はサブルーチン0x401000にて規定されている。

.text:00403540 C7 85 DC E7 FF FF 00 00+mov     [ebp+var_1824], 0
.text:0040354A C7 85 D8 E7 FF FF 00 00+mov     [ebp+var_1828], 0
.text:00403554 64 A1 30 00 00 00       mov     eax, large fs:30h ; PEB moved to eax
.text:0040355A 8A 58 02                mov     bl, [eax+2]     ; copying the value at offset 2 (BeingDebugged) of PEB to bl
.text:0040355D 88 9D E0 E7 FF FF       mov     [ebp+var_1820], bl
.text:00403563 0F BE 85 E0 E7 FF FF    movsx   eax, [ebp+var_1820]
.text:0040356A 85 C0                   test    eax, eax
.text:0040356C 74 05                   jz      short loc_403573 ; check if BeingDebugged flag is set
---
000000000040356E E8 8D DA FF FF          call    SelfDelete_401000

サブルーチン0x401000は以下のコマンドを実行してマルウェアを削除する。

cmd.exe /c del \path\to\Lab16-01.exe >> NUL

3. How can you get around these anti-debugging techniques?

アンチ・デバッグ直後のジャンプ命令を書き換えたり(jzからjnzへの書き換え)、cmp命令で比較されるレジスタの値を書き換えてアンチ・デバッグが実行された後のジャンプ先を変える。

また解析を終えた後に気がついたが、x32dbgのDebugメニュー の Advanced に Hide debugger (PEB) というオプションがあった。

4. How do you manually change the structures checked during runtime?

ブレークポイントをセットして、アンチ・デバッグの際に参照されるレジスタの値を書き換える。

以下はLab16-01.exeにブレークポイントをセットして、EAXの値を1から0に書き換えてBeingDebuggedフラグによるアンチ・デバッグを回避する様子を表している。

ジャンプ命令直前のtest命令にブレークポイントをセットしてLab16-01.exeを実行する。EAXにはBeingDebuggedフラグの値が格納されている。Lab16-01.exeはx32dbgによってデバッグされているので、BeingDebuggedの値、すなわちEAXの値は1となる。

EAXの値を1から0に書き換える。

EAXの値の書き換えが終わったらLab16-01.exeの実行を再開する。EAXの値は0なので、サブルーチン0x401000 (マルウェアの削除処理)はcallされず、アドレス0x403573へと処理が移る。その後も2回、PEBによるアンチ・デバッグが続くが、同様の手順で回避できる。

5. Which OllyDbg plug-in will protect you from the anti-debugging techniques used by this malware?

自分が使用したのはx32dbgだが、x32dbgには主要なアンチ・デバッグを検知して回避してくれるScyllaHideというプラグインがある。

また解析を終えた後に気がついたが、x32dbgのDebugメニュー の Advanced に Hide debugger (PEB) というオプションがあった。

Lab 16-2

解析対象のファイルは以下の通り。

ファイル名ファイルの種類MD5ハッシュ値
Lab16-02.exe32ビット EXEE88B0D6398970E74DE1DE457B971003F

1. What happens when you run Lab16-02.exe from the command-line?

Lab16-02.exeをコマンドプロンプトから実行したところ、パスワード4文字を引数に渡すよう促された。

>Lab16-02.exe
usage: Lab16-02.exe <4 character password>

2. What happens when you run Lab16-02.exe and guess the command-line parameter?

適当なパスワードを引数に渡したところ、Incorrect password, Try again. というメッセージが表示された。

>Lab16-02.exe abcd
Incorrect password, Try again.

3. What is the command-line password?

stringsを走らせたところp@ssという文字が見つかったが、これは正しいパスワードではなかった。

>Lab16-02.exe p@ss
Incorrect password, Try again.

4. Load Lab16-02.exe into IDA Pro. Where in the main function is strncmp found?

自分のIDAはラベリングしてくれなかったが、どうやらサブルーチン0x402110がstrncmpの模様。

.tls:0040122C 6A 04                   push    4               ; size of character to compare
.tls:0040122E 68 30 80 40 00          push    offset byte_408030
.tls:00401233 8B 45 0C                mov     eax, [ebp+arg_4]
.tls:00401236 8B 48 04                mov     ecx, [eax+4]
.tls:00401239 51                      push    ecx             ; user typed password
.tls:0040123A E8 D1 0E 00 00          call    strncmp_402110

5. What happens when you load this malware into OllyDbg using the default settings?

Lab16-02.exeをOllyDbgにロードした途端、Terminatedと表示されて終了してしまった。

6. What is unique about the PE structure of Lab16-02.exe?

Lab16-02.exeには.tlsセクションが存在する。

7. Where is the callback located? (Hint: Use CTRL-E in IDA Pro.)

TLSのコールバックはアドレス0x401060に存在する。

8. Which anti-debugging technique is the program using to terminate immediately in the debugger and how can you avoid this check?

アドレス0x401060のTLS callbackを調べたところ、2つのアンチ・デバッグを見つけた。

1つ目のアンチ・デバッグはFindWindowAを使ってOLLYDBGというウィンドウ名が存在するか確認するというもの。

.tls:00401069 6A 00                   push    0               ; lpWindowName
.tls:0040106B 68 50 80 40 00          push    offset ClassName ; "OLLYDBG"
.tls:00401070 FF 15 C0 70 40 00       call    ds:FindWindowA
.tls:00401076 85 C0                   test    eax, eax
.tls:00401078 74 07                   jz      short loc_401081

2つ目のアンチ・デバッグはOutputDebugStringAによるもの。

.tls:00401020 55                      push    ebp
.tls:00401021 8B EC                   mov     ebp, esp
.tls:00401023 51                      push    ecx
.tls:00401024 C7 45 FC 39 30 00 00    mov     [ebp+dwErrCode], 3039h
.tls:0040102B 8B 45 FC                mov     eax, [ebp+dwErrCode]
.tls:0040102E 50                      push    eax             ; dwErrCode
.tls:0040102F FF 15 08 70 40 00       call    ds:SetLastError
.tls:00401035 68 4C 80 40 00          push    offset OutputString ; "b"
.tls:0040103A FF 15 04 70 40 00       call    ds:OutputDebugStringA
.tls:00401040 FF 15 00 70 40 00       call    ds:GetLastError
.tls:00401046 3B 45 FC                cmp     eax, [ebp+dwErrCode]
.tls:00401049 75 0F                   jnz     short loc_40105A
---
.tls:0040104B 8A 0D 68 A9 40 00       mov     cl, byte_40A968
.tls:00401051 80 C1 01                add     cl, 1
.tls:00401054 88 0D 68 A9 40 00       mov     byte_40A968, cl ; cl and byte_40A968 will be set to 1 if debugger is detected

FindWindowAによるアンチ・デバッグはFindWindowA実行後のEAXの値を書き換えるか、もしくはOllyDbg以外のデバッガを使用すれば回避できる。

OutputDebugStringAによるアンチ・デバッグはGetLastError実行後のEAXの値を書き換えるか、もしくはclまたはbyte_40A968の値を書き換えれば回避できる。

9. What is the command-line password you see in the debugger after you disable the anti-debugging technique?

strncmp (サブルーチン0x402110) まで処理を進めるには、先述したFindWindowとOutputDeguStringAの他に以下のcmp命令を回避しなければならなかった。

.tls:00401081                         loc_401081:             ; change the value at ebp+arg_4 to 2
.tls:00401081 83 7D 0C 02             cmp     [ebp+arg_4], 2
.tls:00401085 75 05                   jnz     short loc_40108C

ebp+arg_4の値を2に書き換えることでチェックを突破した。

アンチ・デバッグを回避してstrncmpまで処理を進めたところ、strncmpの引数の一つにbyqrp@ssという文字が渡されていた。

10. Does the password found in the debugger work on the command line?

byqr を引数に渡してコマンドラインからLab16-02.exeを実行したが弾かれてしまった。念の為byqrp@ssも試してみたが、やはり弾かれてしまった。

>Lab16-02.exe byqr
Incorrect password, Try again.
>Lab16-02.exe byqrp@ss
Incorrect password, Try again.

しかし、Lab16-02.exeをx32dbgにロードして、FileメニューのChange Command lineからbyqrという引数付きで実行したところ、You entered correct password!というメッセージが表示された。

これらのことから、デバッガからLab16-02.exeを起動した場合と、コマンドラインからLab16-02.exeを起動した場合とでは、パスワードが異なることが判明した。

11. Which anti-debugging techniques account for the different passwords in the debugger and on the command line, and how can you protect against them?

byqrp@ss の生成元を調べたところ、strncmpのcall直前に以下の不審なCreateThreadを発見した。

.tls:0040120A                         loc_40120A:
.tls:0040120A 8D 55 F8                lea     edx, [ebp+ThreadId]
.tls:0040120D 52                      push    edx             ; lpThreadId
.tls:0040120E 6A 00                   push    0               ; dwCreationFlags
.tls:00401210 6A 00                   push    0               ; lpParameter
.tls:00401212 68 90 10 40 00          push    offset DecodePasswd_401090 ; lpStartAddress
.tls:00401217 6A 00                   push    0               ; dwStackSize
.tls:00401219 6A 00                   push    0               ; lpThreadAttributes
.tls:0040121B FF 15 10 70 40 00       call    ds:CreateThread

上記はCreateThreadによってアドレス0x401090に記述されているコードを実行する。デバッグしたところ、アドレス0x0401090にはパスワードを復号する処理が記述されていることが判明した。

復号の処理を眺めたところ、以下のコードが目についた。

.tls:0040112B 64 8B 1D 30 00 00 00    mov     ebx, large fs:30h ; BeingDebugged flag is used as part of password decryption
.tls:00401132 80 35 33 80 40 00 C5    xor     byte_408033, 0C5h
.tls:00401139 C0 0D 33 80 40 00 04    ror     byte_408033, 4
.tls:00401140 C0 05 31 80 40 00 04    rol     byte_408031, 4
.tls:00401147 C0 0D 30 80 40 00 03    ror     byte_408030, 3
.tls:0040114E 80 35 30 80 40 00 0D    xor     byte_408030, 0Dh
.tls:00401155 C0 0D 31 80 40 00 05    ror     byte_408031, 5
.tls:0040115C 80 35 32 80 40 00 AB    xor     byte_408032, 0ABh
.tls:00401163 D0 0D 33 80 40 00       ror     byte_408033, 1
.tls:00401169 C0 0D 32 80 40 00 02    ror     byte_408032, 2
.tls:00401170 D0 0D 31 80 40 00       ror     byte_408031, 1
.tls:00401176 80 35 31 80 40 00 FE    xor     byte_408031, 0FEh
.tls:0040117D C0 05 30 80 40 00 06    rol     byte_408030, 6
.tls:00401184 80 35 30 80 40 00 72    xor     byte_408030, 72h
.tls:0040118B 8A 5B 02                mov     bl, [ebx+2]     ; value of BeingDebugged flag copied to bl
.tls:0040118E D0 05 31 80 40 00       rol     byte_408031, 1
.tls:00401194 80 35 33 80 40 00 80    xor     byte_408033, 80h
.tls:0040119B C0 05 33 80 40 00 07    rol     byte_408033, 7
.tls:004011A2 00 1D 32 80 40 00       add     byte_408032, bl

上記のコードによるとパスワードを復号する過程でBeingDebuggedフラグの値を使用する模様。復号されたパスワードは配列0x408030に格納される。

プログラムをデバッグしているか否かでBeingDebuggedフラグの値は変わってくるので、デバッガからLab16-02.exeを起動した場合と、コマンドラインからLab16-02.exeを起動した場合とでは、パスワードが変化する。

アドレス0x40118Bにブレークポイントをセットしてebx+2に格納されているBeingDebuggedフラグの値を1から0に書き換えたところbyrrというパスワードが生成されたが、これは正しいパスワードではなかった。

試行錯誤を繰り返したところ、BeingDebuggedフラグの他にbyte_40A968のデータを0から1に書き換えなければいけないことが分かった。

000000000040109B 8A 1D 68 A9 40 00       mov     bl, byte_40A968 ; overwrite the value of byte_40A968 to 1

byte_40A968にはOutputDebugStringAによるアンチ・デバッグの結果が格納される。

tls:00401024 C7 45 FC 39 30 00 00    mov     [ebp+dwErrCode], 3039h
.tls:0040102B 8B 45 FC                mov     eax, [ebp+dwErrCode]
.tls:0040102E 50                      push    eax             ; dwErrCode
.tls:0040102F FF 15 08 70 40 00       call    ds:SetLastError
.tls:00401035 68 4C 80 40 00          push    offset OutputString ; "b"
.tls:0040103A FF 15 04 70 40 00       call    ds:OutputDebugStringA
.tls:00401040 FF 15 00 70 40 00       call    ds:GetLastError ; if debugger is attached, OutputDebugStringA should succeed and the value in GetLastError should not be changed.
.tls:00401046 3B 45 FC                cmp     eax, [ebp+dwErrCode]
.tls:00401049 75 0F                   jnz     short loc_40105A

---

.tls:0040104B 8A 0D 68 A9 40 00       mov     cl, byte_40A968
.tls:00401051 80 C1 01                add     cl, 1
.tls:00401054 88 0D 68 A9 40 00       mov     byte_40A968, cl ; cl and byte_40A968 will be set to 1 if debugger is detected

OutputDebugStringAによるアンチ・デバッグを回避しようとするとbyte_40A968には常に0が格納されることになる。正しいパスワードが復号されなかったのはそのためである。

アドレス0x40109Bにブレークポイントをセットしてbyte_40A968の値を1に書き換え、さらにアドレス0x40118Bにブレークポイントをセットしてebx+2 (BeingDebuggedフラグ) の値を0に書き換えたところ、bzrrp@ssという文字がstrncmpの引数に渡されることが分かった。

bzrrを引数に渡してコマンドラインからLab16-02.exeを実行したところ、You entered the correct password!というメッセージが表示された。

>Lab16-02.exe bzrr
You entered the correct password!

よってデバッガからLab16-02.exeを起動した場合のパスワードはbyqr、コマンドラインからLab16-02.exeを起動した場合のパスワードはbzrrと判明した。

パスワードを解明することはできたが、以下の (おそらくアンチ・デバッグの一部と思われる) cmp命令が何をチェックしているのかは最後まで分からなかった。

.tls:00401081                         loc_401081:             ; change the value at ebp+arg_4 to 2
.tls:00401081 83 7D 0C 02             cmp     [ebp+arg_4], 2
.tls:00401085 75 05                   jnz     short loc_40108C

Lab 16-3

解析対象のファイルは以下の通り。

ファイル名ファイルの種類MD5ハッシュ値
Lab16-03.exe32ビット EXE3612702FB6E5C1F756C116D9FCE34677

※このファイルはLab09-02.exeにアンチ・デバッグの機能が追加されたものである。

1. Which strings do you see when using static analysis on the binary?

stringsを走らせたところ、以下の文字列が目についた。

00006034  cmd.exe
0000603C   >> NUL
00006044  /c del 

2. What happens when you run this binary?

Lab16-03.exeを実行してみたが、特に目立った挙動は見つからなかった。プロセス自体もすぐに終了してしまった。

3. How must you rename the sample in order for it to run properly?

Lab16-03.exeは、自身のファイル名がpeo.exeと一致するか確認し、一致しない場合は何もせずに終了する。よってLab16-03.exeを実行するにはファイル名をpeo.exeに変更する必要がある。

Lab16-03.exeはまず、ocl.exe というファイル名を組み立てる。

.text:00401437 C6 85 64 FD FF FF 6F    mov     [ebp+var_29C], 'o'
.text:0040143E C6 85 65 FD FF FF 63    mov     [ebp+var_29B], 'c'
.text:00401445 C6 85 66 FD FF FF 6C    mov     [ebp+var_29A], 'l'
.text:0040144C C6 85 67 FD FF FF 2E    mov     [ebp+var_299], '.'
.text:00401453 C6 85 68 FD FF FF 65    mov     [ebp+var_298], 'e'
.text:0040145A C6 85 69 FD FF FF 78    mov     [ebp+var_297], 'x'
.text:00401461 C6 85 6A FD FF FF 65    mov     [ebp+var_296], 'e'
.text:00401468 C6 85 6B FD FF FF 00    mov     [ebp+var_295], 0

次にocl.exe というファイル名をサブルーチン 0x4011E0に引数として渡す。デバッグの結果、このサブルーチンはocl.exeというファイル名をpeo.exeに書き換えることが判明した。

.text:004014BC 8D 85 64 FD FF FF       lea     eax, [ebp+var_29C]
.text:004014C2 50                      push    eax             ; ocl.exe
.text:004014C3 E8 18 FD FF FF          call    sub_4011E0      ; renames ocl.exe to peo.exe

続いてLab16-03.exeは自身のファイル名がpeo.exeと一致するか確認する。一致した場合はC2サーバーとの通信を開始し、一致しなかった場合は何もせずに終了する。

.text:004014C8 83 C4 04                add     esp, 4
.text:004014CB 68 0E 01 00 00          push    10Eh            ; nSize
.text:004014D0 8D 8D 00 FC FF FF       lea     ecx, [ebp+Filename]
.text:004014D6 51                      push    ecx             ; lpFilename
.text:004014D7 6A 00                   push    0               ; hModule
.text:004014D9 FF 15 0C 50 40 00       call    ds:GetModuleFileNameA ; get the path of the current process
.text:004014DF 6A 5C                   push    5Ch
.text:004014E1 8D 95 00 FC FF FF       lea     edx, [ebp+Filename]
.text:004014E7 52                      push    edx
.text:004014E8 E8 03 03 00 00          call    strrchr_4017F0
.text:004014ED 83 C4 08                add     esp, 8
.text:004014F0 89 85 FC FE FF FF       mov     [ebp+var_104], eax
.text:004014F6 68 04 01 00 00          push    260
.text:004014FB 8B 85 FC FE FF FF       mov     eax, [ebp+var_104]
.text:00401501 83 C0 01                add     eax, 1
.text:00401504 89 85 FC FE FF FF       mov     [ebp+var_104], eax
.text:0040150A 8B 8D FC FE FF FF       mov     ecx, [ebp+var_104]
.text:00401510 51                      push    ecx             ; current filename
.text:00401511 8D 95 64 FD FF FF       lea     edx, [ebp+var_29C]
.text:00401517 52                      push    edx             ; peo.exe
.text:00401518 E8 93 02 00 00          call    strncmp_4017B0  ; check if the current filename is peo.exe
.text:0040151D 83 C4 0C                add     esp, 0Ch
.text:00401520 85 C0                   test    eax, eax
.text:00401522 74 0A                   jz      short loc_40152E ; the file will exit if the current filename is not peo.exe

4. Which anti-debugging techniques does this malware employ?

解析を進めたところ、複数のアンチ・デバッグを見つけた。

まずはQueryPerformanceCounterによるアンチ・デバッグ。QueryPerformanceCounterを2回呼び出し、最初に取得した値と後から取得した値の差を比較する。

.text:00401219 8D 45 F8                lea     eax, [ebp+PerformanceCount]
.text:0040121C 50                      push    eax             ; lpPerformanceCount
.text:0040121D FF 15 10 50 40 00       call    ds:QueryPerformanceCounter
.text:00401223 E8 00 00 00 00          call    $+5
.text:00401228 58                      pop     eax             ; pops 401228 to eax
.text:00401229 33 C9                   xor     ecx, ecx        ; ecx set to 0
.text:0040122B 8B F8                   mov     edi, eax        ; 401228 copied to edi
.text:0040122D 33 DB                   xor     ebx, ebx
.text:0040122F 83 C3 2C                add     ebx, 2Ch
.text:00401232 03 C3                   add     eax, ebx        ; 0x401228 + 0x2C = 0x401254
.text:00401234 50                      push    eax             ; pushes the address 0x401254
.text:00401235 64 FF 35 00 00 00 00    push    large dword ptr fs:0
.text:0040123C 64 89 25 00 00 00 00    mov     large fs:0, esp ; The instructions from 0x401234 to 0x40123C will modify the SEH chain so the code at 0x401254 will be executed when exception occur.
.text:00401243 F7 F1                   div     ecx             ; Division of 0 which causes exception.
.text:00401245 81 EF 6A 0D 00 00       sub     edi, 0D6Ah
.text:0040124B B9 0C 00 00 00          mov     ecx, 0Ch
.text:00401250 EB 10                   jmp     short loc_401262

---

.text:00401262                         loc_401262:
.text:00401262 64 8F 05 00 00 00 00    pop     large dword ptr fs:0
.text:00401269 58                      pop     eax
.text:0040126A 8D 8D F0 FE FF FF       lea     ecx, [ebp+var_110]
.text:00401270 51                      push    ecx             ; lpPerformanceCount
.text:00401271 FF 15 10 50 40 00       call    ds:QueryPerformanceCounter
.text:00401277 8B 95 F0 FE FF FF       mov     edx, dword ptr [ebp+var_110]
.text:0040127D 2B 55 F8                sub     edx, dword ptr [ebp+PerformanceCount]
.text:00401280 89 95 EC FE FF FF       mov     [ebp+var_114], edx
.text:00401286 81 BD EC FE FF FF B0 04+cmp     [ebp+var_114], 1200
.text:00401290 7E 0A                   jle     short loc_40129C ; Compares the time difference between 1st and 2nd call of QueryPerforamnceCounter.

1回目と2回目のQueryPerformanceCounterの間には以下の不審なSEHの書き換えを行うコードが記述されていた。

.text:00401223 E8 00 00 00 00          call    $+5
.text:00401228 58                      pop     eax             ; pops 401228 to eax
.text:00401229 33 C9                   xor     ecx, ecx        ; ecx set to 0
.text:0040122B 8B F8                   mov     edi, eax        ; 401228 copied to edi
.text:0040122D 33 DB                   xor     ebx, ebx
.text:0040122F 83 C3 2C                add     ebx, 2Ch
.text:00401232 03 C3                   add     eax, ebx        ; 0x401228 + 0x2C = 0x401254
.text:00401234 50                      push    eax             ; pushes the address 0x401254
.text:00401235 64 FF 35 00 00 00 00    push    large dword ptr fs:0
.text:0040123C 64 89 25 00 00 00 00    mov     large fs:0, esp ; The instructions from 0x401234 to 0x40123C will modify the SEH chain so the code at 0x401254 will be executed when exception occur.
.text:00401243 F7 F1                   div     ecx             ; Division of 0 which causes exception.

上記のコードはSEHのリンクトリストの先頭にアドレス0x401254へのポインタを追加して、わざと例外処理を引き起こし (この場合はゼロによる除算) 、アドレス0x401254へ処理を飛ばす。

次に見つけたのはGetTickCountによるアンチ・デバッグ。GetTickCountを2回呼び出し、最初に取得した時刻と後から取得した時刻の差を比較して、一定時間以上経過していた場合はデバッグされていると判断して処理を終了する。

.text:00401584 FF 15 18 50 40 00       call    ds:GetTickCount
.text:0040158A 89 85 4C FD FF FF       mov     [ebp+var_2B4], eax
.text:00401590 E8 6B FA FF FF          call    AntiDebug_401000 ; overwrites SEH and raise exception
.text:00401595 FF 15 18 50 40 00       call    ds:GetTickCount
.text:0040159B 89 85 44 FD FF FF       mov     [ebp+var_2BC], eax
.text:004015A1 8B 8D 44 FD FF FF       mov     ecx, [ebp+var_2BC]
.text:004015A7 2B 8D 4C FD FF FF       sub     ecx, [ebp+var_2B4]
.text:004015AD 83 F9 01                cmp     ecx, 1
.text:004015B0 76 05                   jbe     short loc_4015B7

1回目と2回目のGetTickCountの間に呼び出されているサブルーチン 0x401000の中には以下の不審なSEHの書き換えを行うコードが記述されていた。

.text:00401006 E8 00 00 00 00          call    $+5
.text:0040100B 58                      pop     eax             ; pops 40100B to eax
.text:0040100C 33 C9                   xor     ecx, ecx        ; set ecx to 0
.text:0040100E 8B F8                   mov     edi, eax
.text:00401010 33 DB                   xor     ebx, ebx
.text:00401012 83 C3 2C                add     ebx, 2Ch
.text:00401015 03 C3                   add     eax, ebx        ; 0x40100B + 0x2C = 0x401037
.text:00401017 50                      push    eax             ; pushes the address 0x401037
.text:00401018 64 FF 35 00 00 00 00    push    large dword ptr fs:0
.text:0040101F 64 89 25 00 00 00 00    mov     large fs:0, esp ; The instructions from 0x401017 to 0x40101F will modify the SEH chain so the code at 0x401037 will be executed when exception occur.
.text:00401026 F7 F1                   div     ecx             ; Division of 0 which causes exception.

上記のコードはSEHのリンクトリストの先頭にアドレス0x401037へのポインタを追加して、わざと例外処理を引き起こし(この場合はゼロによる除算) 、アドレス0x401037へ処理を飛ばす。

次にrdtscによるアンチ・デバッグを見つけた。rdtscを2回呼び出し、最初に取得した値と後から取得した値の差を比較して、その差が500000より大きい場合、マルウェアは自身を消去する。

.text:0040131F 89 4D F8                mov     [ebp+var_8], ecx
.text:00401322 50                      push    eax
.text:00401323 0F 31                   rdtsc                   ; 1st rdtsc
.text:00401325 50                      push    eax
.text:00401326 E8 00 00 00 00          call    $+5

---

.text:0040132B                         loc_40132B:             ; pops 40132B to eax
.text:0040132B 58                      pop     eax
.text:0040132C 33 C9                   xor     ecx, ecx
.text:0040132E 8B F8                   mov     edi, eax
.text:00401330 33 DB                   xor     ebx, ebx
.text:00401332 83 C3 2C                add     ebx, 2Ch
.text:00401335 03 C3                   add     eax, ebx        ; 0x40132B + 0x2C = 0x401357
.text:00401337 50                      push    eax             ; pushes the address 0x401357
.text:00401338 64 FF 35 00 00 00 00    push    large dword ptr fs:0
.text:0040133F 64 89 25 00 00 00 00    mov     large fs:0, esp ; The instructions from 0x401337 to 0x40133F will modify the SEH chain so the code at 0x401357 will be executed when exception occur.
.text:00401346 F7 F1                   div     ecx             ; Division of 0 which causes exception.
.text:00401348 81 EF 6A 0D 00 00       sub     edi, 0D6Ah
.text:0040134E B9 0C 00 00 00          mov     ecx, 0Ch
.text:00401353 EB 10                   jmp     short loc_401365

---

.text:00401365                         loc_401365:
.text:00401365 64 8F 05 00 00 00 00    pop     large dword ptr fs:0
.text:0040136C 58                      pop     eax
.text:0040136D 0F 31                   rdtsc                   ; 2nd rdtsc
.text:0040136F 2B 04 24                sub     eax, [esp+20h+var_20]
.text:00401372 89 45 FC                mov     [ebp+var_4], eax
.text:00401375 58                      pop     eax
.text:00401376 58                      pop     eax
.text:00401377 81 7D FC 20 A1 07 00    cmp     [ebp+var_4], 500000 ; Compares the difference between 1st and 2nd rdtsc.
.text:0040137E 76 05                   jbe     short loc_401385

---

0000000000401380 E8 5B FD FF FF          call    SelfDelete_4010E0

1回目と2回目のrdtscの間には以下の不審なSEHの書き換えを行うコードが記述されていた。

0000000000401326 E8 00 00 00 00          call    $+5

---

.text:0040132B                         loc_40132B:             ; pops 40132B to eax
.text:0040132B 58                      pop     eax
.text:0040132C 33 C9                   xor     ecx, ecx
.text:0040132E 8B F8                   mov     edi, eax
.text:00401330 33 DB                   xor     ebx, ebx
.text:00401332 83 C3 2C                add     ebx, 2Ch
.text:00401335 03 C3                   add     eax, ebx        ; 0x40132B + 0x2C = 0x401357
.text:00401337 50                      push    eax             ; pushes the address 0x401357
.text:00401338 64 FF 35 00 00 00 00    push    large dword ptr fs:0
.text:0040133F 64 89 25 00 00 00 00    mov     large fs:0, esp ; The instructions from 0x401337 to 0x40133F will modify the SEH chain so the code at 0x401357 will be executed when exception occur.
.text:00401346 F7 F1                   div     ecx             ; Division of 0 which causes exception.

上記のコードはSEHのリンクトリストの先頭にアドレス0x401357へのポインタを追加して、わざと例外処理を引き起こし(この場合はゼロによる除算) 、アドレス0x401357へ処理を飛ばす。

上述した3つのSEHの書き換えは、わざと例外処理を発生させてデバッガを検知することが目的である。大抵のデバッガはプログラムのデバッグ中に例外が発生すると、一旦デバッガの方でトラップし、例外をただちにプログラムに渡すようなことはしない。

この性質を利用して

  • QueryPerformanceCounter、GetTickCount、rtdscなどでタイムスタンプを取得する。
  • わざと例外処理を発生させる。(xor ecx, ecx、 div ecx、ゼロによる除算)
  • 再度、QueryPerformanceCounter、GetTickCount、rtdscなどでタイムスタンプを取得する。
  • 1回目と2回目のタイムスタンプの差を比較する。
    • 1回目と2回目のタイムスタンプの差が小さければ、デバッグされていないと判断。
    • 1回目と2回目のタイムスタンプの差が大きければ、デバッグされていると判断。

5. For each technique, what does the malware do if it determines it is running in a debugger?

QueryPerformanceCounterによるアンチ・デバッグがデバッガを検知した場合、ocl.exeから復号されるファイル名がpeo.exeではなくqgr.exeになる。ファイル名をLab16-03.exeからqgr.exeに変更して実行したところ、peo.exeの時と同様にC2サーバーと通信した。

ちなみに後述するx32dbgのRun (pass exception)でステップ実行してもQueryPerformanceCounterによるチェックは突破出来なかった。ocl.exeからpeo.exeという正しいファイル名を取得するにはデバッグ中に以下のebp+var_118の値を1に書き換えなければいけなかった。(QueryPerformanceCounterによるアンチ・デバッグが成功すると、ebp+var_118値が1から2に上書きされる。)

00000000004012C9 0F AF 8D E8 FE FF FF    imul    ecx, [ebp+var_118]


GetTickCountによるアンチ・デバッグがデバッガを検知した場合、何もせずに終了する。

rdtscによるアンチ・デバッグがデバッガを検知した場合、自身を消去する。このファイル削除の処理はサブルーチン0x4010E0で行われる。

6. Why are the anti-debugging techniques successful in this malware?

大抵のデバッガはプログラムのデバッグ中に例外が発生すると、一旦デバッガの方でトラップし、例外をただちにプログラムに渡すようなことはしない。

この性質を利用して

  • QueryPerformanceCounter、GetTickCount、rtdscなどでタイムスタンプを取得する。
  • わざと例外処理を発生させる。(xor ecx, ecx、div ecx、ゼロによる除算)
  • 再度、QueryPerformanceCounter、GetTickCount、rtdscなどでタイムスタンプを取得する。
  • 1回目と2回目のタイムスタンプの差を比較する。
    • 1回目と2回目のタイムスタンプの差が小さければ、デバッグされていないと判断。
    • 1回目と2回目のタイムスタンプの差が大きければ、デバッグされていると判断。

実際、x32dbgにマルウェアをロードして適宜ブレークポイントをセットし、F9やF8でステップ実行しようとした際、毎回 xor ecx, ecx、div ecx (ゼロによる除算)の部分で一旦マルウェアが停止し、引き続きステップ実行しようとするとマルウェアが終了してしまった。

対策としては、F9やF8でステップ実行するのではなく、Debugメニュー -> Advanced -> Run (pass exception) (またはShift + F9)でステップ実行することで、プログラムのデバッグ中に例外が発生した際、例外をトラップせずにプログラムに渡すことができる。

7. What domain name does this malware use?

動的解析の結果、adg.malwareanalysisbook[.]com と通信することが判明した。

ドメイン名は暗号化されており、サブルーチン 0x401300にて復号される。

x32dbgにpeo.exeをロードし、サブルーチン 0x401300の呼び出し部分 (アドレス 0x4015CC) とgethostbynameの呼び出し部分 (アドレス 0x4015DB) にブレークポイントをセットして、Debugメニュー -> Advanced -> Run (pass exception)でステップ実行したところ、暗号鍵 1qbz2wsx3edcがサブルーチン 0x401300 に渡されてadg.malwareanalysisbook[.]comというドメインが復号され、gethostbynameに渡されるのが確認できた。

模範解答

Lab 16-1

1. The malware checks the status of the BeingDebugged, ProcessHeap, and NTGlobalFlag flags to determine if it is being run in a debugger.

2. If any of the malware's anit-debugging techniques succeed, it will terminate and remove itself from disk.

3. You can manually change the jump flags in OllyDbg during runtime, but doing so will get tedious since this malware checks the memory structures so frequently. Instead, modify the structures the malware checks in memory either manually or by using an OllyDbg plug-in like PhantOm or the Immunity Debugger (ImmDbg) PyCommand hidedebug.

4. See the detailed analysis for a step-by-step way to dump and modify the structures in OllyDbg.

5. Both the OllyDbg plug-in PhantOm and the ImmDbg Pycommand hidedebug will thwart this malware's checks.

Lab 16-2

1. When you run Lab16-02.exe from the command line, it prints a usage string asking for a four-character password.

2. If you input an incorrect password, the program will respond "Incorrect password, Try again."

3. The correct command-line password is byrr.

4. The strncmp function is called at 0x40123A.

5. The program immediately terminates when loaded into OllyDbg using the default settings.

6. The program contains a .tls section.

7. The TLS callback starts at 0x401060.

8. The FindWindowA functions is used to terminate the malware. It looks for a window with the class name OLLYDBG and terminates the program if it is found. You can change the window class name using an OllyDbg plug-in like PhantOm, or NOP-out the call to exit at 0x40107C.

9. At first, the password appears to be bzqr when you set a break point at the strncmp call.

10. This password found in the debugger doesn't work on the command line.

11. The result of OutputDebugStringA and the BeingDebugged flag are used as inputs to the decoding algorithm. You can use the PhantOm plug-in to ensure that the BeingDebugged flag is 0, and you can NOP-out the add instruction at 0x401051.

Lab 16-3

1. There aren't many useful strings in the malware other than import functions and the strings cmd and cmd.exe.

2. When you run this malware, it appears to do nothing other than terminate.

3. You must rename the malware to peo.exe for it to run properly.

4. This malware uses three different anti-debugging timing techniques: rdtsc, GetTickCount, and QueryPerformanceCounter.

5. If the QueryPerformanceCounter check is successful, the malware modifies the string needed for the program to run properly. If the GetTickCount check is successful, the malware causes an unhandled exception that crashes the program. If the rdtsc check is successful, the malware will attempt to delete itself from disk.

6. The anti-debugger timing checks are successful because the malware causes and catches an exception that it handles by manipulating the Structured Exception Handling (SEH) mechanism to include its own exception handler n between two calls to the timing checking functions. Exceptions are handled much more slowly in a debugger than outside a debugger.

7. The malware uses the domain name adg.malwareanalysisbook.com.

答え合わせ

Lab 16-2

模範解答によると正しいコマンドライン・パスワードはbyrrだったが、自分の解析したLab16-02.exeの正しいパスワードはbzrrだった。

Practical Malware Analysisの本が出版されたのは2012年頃だが、GitHubの最初のコミットは5年後の2017年4月27日に行われているので、恐らくいくつかのラボ検体は出版当時からアップデートされており、Lab16-02.exeのパスワードが異なるのもそのためと思われる。

模範解答によると以下のコードはTLSコールバックがどのタイミングで呼び出されたか確認するためのものだった。

.tls:00401081 83 7D 0C 02             cmp     [ebp+arg_4], 2
.tls:00401085 75 05                   jnz     short loc_40108C
  • プロセス起動時に呼び出された場合、TLSコールバックのarg_4は1になる。
  • スレッド起動時に呼び出された場合、TLSコールバックのarg_4は2になる。
  • プロセス終了時に呼び出された場合、TLSコールバックのarg_4は3になる。

Leave a Reply

Your email address will not be published.