467 words
2 minutes
FLARE Learning Hub - Chapter 2: The Stack

Tiếp tục series ghi chú từ “Malware Analysis Crash Course” (FLARE/Mandiant) — Chapter 2 nói về Stack, một cấu trúc cực kỳ nền tảng vì gần như mọi function call đều đụng tới nó.

mandiant
/
flare-learning-hub
Waiting for api.github.com...
00K
0K
0K
Waiting...

The Stack#

Stack là một vùng bộ nhớ hoạt động theo kiểu LIFO (Last In, First Out) — tạm giữ dữ liệu riêng cho từng lần gọi hàm: biến cục bộ, tham số, và địa chỉ trả về. Trên x86, stack phát triển về phía địa chỉ thấp hơn (dù khi vẽ hình người ta hay quy ước vẽ “đỉnh” ở trên).

ESP (Extended Stack Pointer) luôn tự động trỏ tới đỉnh hiện tại của stack. Toàn bộ thao tác với stack quy về 2 việc: đẩy giá trị vào (PUSH) và lấy giá trị ra (POP).

PUSH Instruction#

PUSH chạy đúng theo trình tự 2 bước, thứ tự rất quan trọng:

  1. Giảm ESP đi 4 trước (cấp phát chỗ trống)
  2. Rồi mới ghi giá trị operand vào đúng chỗ ESP vừa trỏ tới

Tương đương với:

sub esp, 4
mov [esp], <operand>

Operand của PUSH có thể là immediate, thanh ghi, hoặc giá trị từ bộ nhớ. Nếu đẩy liên tiếp 1, 2, 3, thì 3 (giá trị đẩy sau cùng) sẽ nằm trên đỉnh stack. Muốn truy cập các giá trị đẩy trước đó thì dùng offset dương từ ESP (ví dụ [esp+4] là phần tử đẩy thứ nhì tính từ đỉnh).

POP Instruction#

POP làm ngược lại, cũng đúng 2 bước theo thứ tự:

  1. Đọc giá trị tại vị trí ESP hiện tại, ghi vào đích
  2. Tăng ESP lên 4 (coi như đã “giải phóng” phần tử đó)

Tương đương với:

mov <đích>, [esp]
add esp, 4

Đích của POP có thể là bất kỳ thanh ghi hay vị trí bộ nhớ nào. Nếu đẩy 1, 2, 3 rồi pop liên tiếp, thứ tự lấy ra sẽ là 3, 2, 1 — đúng bản chất LIFO.

Vì sao điều này quan trọng khi đọc RE#

Nắm chắc PUSH/POP (giảm trước-ghi sau, đọc trước-tăng sau) là điều kiện bắt buộc để hiểu 2 thứ lớn hơn ở các chapter sau:

  1. Function call (Chapter 3): CALL thực chất tự PUSH địa chỉ lệnh kế tiếp (return address) lên stack trước khi nhảy tới hàm; RET thì POP địa chỉ đó ra rồi nhảy tới.
  2. Stack frame (Chapter 4): tham số hàm và biến cục bộ đều được định vị tương đối theo ESP/EBP — hiểu đúng PUSH/POP làm ESP di chuyển thế nào mới tính đúng offset nào trỏ tới biến nào.

Một lỗi khá hay gặp khi mới học: nhầm hướng phát triển của stack dẫn tới tính sai offset khi đọc [ebp-8] hay [ebp+8] (âm là biến cục bộ, dương là tham số — nói kỹ hơn ở Chapter 4).


Chapter tới mình sẽ ghi về Flow Control — JMP, CALL, RET và cách hàm gọi lẫn nhau được thể hiện trong assembly.

FLARE Learning Hub - Chapter 2: The Stack
https://stewmalwarehunter.id.vn/posts/flare-macc-ch2---the-stack/
Author
Stew
Published at
2026-08-19
License
CC BY-NC-SA 4.0