← All posts

Article

Malware Triage: Phân Tích Tĩnh PE File Trong 30 Phút

Quy trình phân tích static một file PE nghi ngờ — PE structure, strings, imports, packing detection, và viết YARA rule từ kết quả phân tích.

Khi nhận được một file nghi ngờ, bước đầu tiên là static analysis — phân tích mà không cần chạy file. Mục tiêu là triage nhanh: file này có malicious không? Nó làm gì? Liên quan đến family nào đã biết?

Thiết lập môi trường

Thực hiện static analysis trong môi trường cô lập. Một VM không có mạng là đủ cho static analysis — file không được thực thi, nên risk thấp. Tuy nhiên vẫn nên giữ file trong thư mục riêng và không click nhầm.

Công cụ cần thiết:

  • CFF Explorer hoặc PE-bear — phân tích PE structure
  • FLOSS (FireEye Labs Obfuscated String Solver) — extract strings bao gồm obfuscated
  • pestudio — all-in-one triage tool
  • Detect-It-Easy (DIE) — packer/compiler detection
  • capa — identify capabilities

Bước 1: File Identification

# Hash để lookup trên VirusTotal/MalwareBazaar
certutil -hashfile sample.exe MD5
certutil -hashfile sample.exe SHA256

# File type — đừng tin phần mở rộng
file sample.exe

# Entropy — high entropy có thể là packed/encrypted
python -c "import math,sys; d=open(sys.argv[1],'rb').read(); freq=[d.count(bytes([i])) for i in range(256)]; e=-sum(p/len(d)*math.log2(p/len(d)) for p in freq if p); print(f'Entropy: {e:.2f}')" sample.exe

Entropy > 7.2 thường là dấu hiệu packing hoặc encryption. Entropy cao trong một section cụ thể (đặc biệt .text) nghi ngờ hơn là toàn file.

Bước 2: PE Header Analysis

# Dùng pefile Python library
python3 -c "
import pefile
pe = pefile.PE('sample.exe')
print(pe.dump_info())
"

# Hoặc pestudio — GUI với scoring tự động

Những gì cần kiểm tra:

Compilation Timestamp

import pefile, datetime
pe = pefile.PE('sample.exe')
ts = pe.FILE_HEADER.TimeDateStamp
print(datetime.datetime.utcfromtimestamp(ts))

Timestamp có thể bị forge (timestamp stomping). Timestamp năm 1970, 2037, hay trước khi OS target ra đời là dấu hiệu rõ ràng.

Sections

SectionMô tả bình thườngNghi ngờ khi
.textCode thực thiEntropy cao, size nhỏ nhưng raw size lớn
.dataData tĩnhEntropy cao
.rsrcResourcesChứa embedded PE/shellcode
.rdataRead-only data

Section tên lạ như .aaa, .xyz, hay tên chứa ký tự đặc biệt là nghi ngờ.

for section in pe.sections:
    print(f"{section.Name.decode().strip(chr(0))} | "
          f"VirtSize: {section.Misc_VirtualSize:#x} | "
          f"RawSize: {section.SizeOfRawData:#x} | "
          f"Entropy: {section.get_entropy():.2f}")

Import Table

Import table cho biết DLL và function nào được gọi — đây là nguồn thông tin capabilities tốt nhất.

for entry in pe.DIRECTORY_ENTRY_IMPORT:
    print(f"\n{entry.dll.decode()}")
    for imp in entry.imports:
        print(f"  {imp.name.decode() if imp.name else 'ordinal'}")

Imports đáng chú ý theo category:

Network:

  • WSAStartup, connect, send, recv — raw socket
  • HttpOpenRequest, InternetConnect — WinINet HTTP
  • WinHttpOpen — WinHTTP

Process injection:

  • VirtualAllocEx, WriteProcessMemory, CreateRemoteThread — classic injection
  • NtCreateSection, NtMapViewOfSection — process hollowing

Anti-analysis:

  • IsDebuggerPresent, CheckRemoteDebuggerPresent
  • GetTickCount, QueryPerformanceCounter — timing checks
  • NtQueryInformationProcess

Credential access:

  • SamQueryInformationUser, LsaRetrievePrivateData
  • CryptDecrypt, CryptImportKey

Nếu import table gần như trống (chỉ có LoadLibraryGetProcAddress) — file gần chắc chắn là packed/obfuscated, loads imports dynamically.

Bước 3: String Analysis

# Strings cơ bản
strings sample.exe | grep -iE "(http|ftp|cmd|powershell|reg|taskkill)"

# FLOSS — tìm cả stackstrings và obfuscated strings
floss sample.exe

# Output chi tiết hơn
floss --no-static-strings sample.exe  # chỉ dynamic/stack strings

Strings có giá trị cao:

Network indicators:

http://malicious.domain/gate.php
/update?id=%s&key=%s
Mozilla/5.0 (Windows NT 10.0; Win64; x64)   # custom User-Agent

File system paths:

%APPDATA%\Microsoft\Windows\
C:\Users\Public\
\AppData\Roaming\

Registry:

SOFTWARE\Microsoft\Windows\CurrentVersion\Run
SYSTEM\CurrentControlSet\Services\

Mutex names — rất hữu ích để identify family:

Global\{UUID}
\BaseNamedObjects\

Debug/PDB paths — đôi khi còn sót:

C:\Users\developer\project\malware\Release\bot.pdb

Bước 4: Packing Detection

# Detect-It-Easy
die sample.exe

# ExeinfoPE
# PEiD

DIE thường nhận diện chính xác packer: UPX, MPRESS, Themida, VMProtect, v.v.

UPX — phổ biến và dễ unpack:

# Unpack UPX
upx -d sample.exe -o unpacked.exe

# Nếu UPX header bị modify để block automatic unpack
# Restore "UPX!" magic bytes thủ công với hex editor trước

Sau khi unpack, lặp lại từ bước 1 với file đã unpack.

Bước 5: capa — Capability Detection

# capa phân tích capabilities tự động và map sang MITRE ATT&CK
capa sample.exe

# Output ví dụ:
# +-----------------------------+----------------------------------------------+
# | MBC Objective               | MBC Behavior                                 |
# +-----------------------------+----------------------------------------------+
# | COMMUNICATION               | HTTP Communication::Send Data [C0002.003]    |
# | PERSISTENCE                 | Registry::Set Registry Key [C0036.001]       |
# | DEFENSE EVASION             | Obfuscated Files or Information [F0001]      |

Bước 6: Viết YARA Rule

Từ kết quả phân tích, viết YARA rule để detect mẫu tương tự:

rule Trojan_Example_Dropper
{
    meta:
        description = "Detects dropper based on string patterns and imports"
        date = "2026-06-13"
        author = "anhnd11"
        tlp = "WHITE"

    strings:
        // Mutex name found in static analysis
        $mutex = "Global\\{4A8B2C1D-XXXX}" wide

        // C2 URL pattern
        $c2_path = "/gate.php?id=" ascii

        // Custom User-Agent
        $ua = "Mozilla/4.0 (compatible; MSIE 6.0;" ascii

        // PDB artifact
        $pdb = "\\Release\\loader.pdb" ascii nocase

        // Anti-debug import pair
        $api1 = "IsDebuggerPresent" ascii
        $api2 = "VirtualAllocEx" ascii
        $api3 = "CreateRemoteThread" ascii

    condition:
        uint16(0) == 0x5A4D   // MZ header
        and filesize < 2MB
        and (
            ($mutex and $c2_path)
            or ($pdb)
            or (all of ($api*) and $ua)
        )
}

Nguyên tắc viết YARA tốt:

  • Luôn check MZ header và filesize để giảm false positive
  • Kết hợp ít nhất 2-3 indicator độc lập
  • String từ mutex, PDB path, C2 pattern là unique hơn API names
  • Test rule trước khi deploy: yara -r rule.yar /samples/clean/ nên cho 0 kết quả

Checklist Triage 30 phút

[ ] Hash → VirusTotal lookup
[ ] File entropy + section entropy
[ ] Compilation timestamp
[ ] PE section analysis
[ ] Import table → identify capabilities
[ ] String extraction (FLOSS)
[ ] Packing detection
[ ] capa analysis
[ ] Network IOC extraction
[ ] YARA rule draft

Nếu sau 30 phút vẫn không rõ → chuyển sang dynamic analysis trong sandbox.

↗ Mở SoundCloud chọn nhạc