REVERSING WITH IDA FROM SCRATCH (P5)

LEA (LOAD EFFECTIVE ADDRESS)

Trong phần tiếp theo này chúng ta sẽ tiếp tục với lệnh LEA và cách sử dụng của lệnh này trong code của chương trình.

Cú pháp của lệnh như sau:

LEA A, B

Lệnh LEA (nạp địa chỉ hiệu dung vào thanh ghi) thực hiện chuyển một địa chỉ được chỉ định trong B (nguồn) vào A (đích). Nội dung của B không bao giờ được truy cập, nó sẽ luôn là một địa chỉ hoặc là kết quả của phép tính toán nằm trong dấu ngoặc vuông [] của toán hạng thứ hai. Lệnh LEA được sử dụng rất nhiều để lấy địa chỉ bộ nhớ của các biến hoặc các tham số.

Quan sát một ví dụ dưới đây:

Các bạn để ý, tại các hàm mà IDA phân tích ta sẽ thấy có các tham số được truyền vào cho hàm. Các tham số này được kí hiệu là arg_x. Thường thì việc truyền tham số cho một hàm sẽ thông qua lệnh PUSH trước khi thực thi hàm đó. Như chúng ta đã thấy trên hình, lệnh PUSH thực hiện lưu các giá trị vào trong ngăn xếp, các giá trị này được gọi là đối số hay tham số.

Quan sát hình, ở phần đầu của mỗi hàm, ta sẽ thấy có một danh sách liệt kê gồm có các biến cục bộ và các tham số mà hàm sử dụng. Cụ thể, tại hàm sub_401170 trên hình, ta thấy có một tham số trong ngăn xếp bởi hàm chỉ nhận duy nhất một arg, trong trường hợp này IDA đặt tên là arg_0. Bên cạnh đó, hàm cũng dành riêng không gian trong ngăn xếp để phục vụ lưu các biến cục bộ, các biến cục bộ này nằm phía trên các tham số như quan sát trên hình và bắt đầu bằng var_x.

Tôi sẽ giải thích sau về vị trí chính xác của các tham số và các biến trong stack. Còn tại thời điểm này bạn chỉ cần nhớ rằng mỗi tham số hoặc biến mà một hàm sử dụng sẽ có một địa chỉ do hệ thống cấp phát và một giá trị được lưu tại địa chỉ đó.

Quay trở lại với lệnh LEA, chương trình sử dụng một lệnh LEA tại địa chỉ 0x401191 lea     eax, [ebp+var_C], câu lệnh này sẽ thực hiện lấy địa chỉ của biến trên Stack và gán vào thanh ghi EAX. Nếu ngược lại, đây là một câu lệnh MOV thì sẽ chuyển nội dung hoặc giá trị đang được lưu giữ trong biến vào EAX.

Hay nói cách khác, lệnh LEA, mặc dù sử dụng cặp ngoặc [], nhưng nó chỉ chuyển địa chỉ đã được thực hiện tính toán bên trong ngoặc mà không truy cập vào nội dung của ô nhớ và thanh ghi EBP thường được sử dụng làm thanh ghi cơ sở cho việc truy xuất các biến và các tham số trên stack của mỗi hàm. Về bản chất, quá trình thực hiện thực ra chỉ là cộng hoặc trừ thanh ghi EBP với một giá trị hằng số để trỏ tới một địa chỉ nằm trên Stack mà thôi, tuy nhiên do IDA là công cụ hỗ trợ khả năng tương tác cao, nên nó sẽ đánh nhãn cho từng biến để ta có thể dễ dàng đặt lại tên khi phân tích.

Tại IDA, nếu ta nhấn phải chuột vào biến đó, ta sẽ thấy được cách biểu diễn toán học thuần túy là [EBP-0Ch] và ta có thể thay đổi lệnh bằng cách nhấn phím Q. Đó là lý do tại sao lệnh LEA chỉ thực hiện việc tính toán EBP-0C, vì đơn giản thanh ghi EBP đang lưu một địa chỉ trên ngăn xếp làm base (cơ sở) cho hàm, sau khi trừ đi giá trị 0C ta có được địa chỉ của biến nói trên.

Ở đây, nhiều người có thể tự hỏi sẽ dễ dàng hơn cho IDA nếu sử dụng ký hiệu toán học thuần túy cho các biến và các tham số thay vì sử dụng [EBP – hoặc + một tag]. Vấn đề là trong reversing, việc ta có thể đổi tên các biến và tham số với tên mà ta mường tượng ra khi tác giả code chương trình là rất quan trọng, như vậy sẽ giúp chúng ta dễ dàng hơn trong quá trình phân tích. Lúc đó, sẽ không còn là một biến được gọi là EBP – 0C mà có thể đổi thành EBP + SIZE, nếu lúc phân tích, tôi biết lệnh này sẽ lưu một size (Việc đổi tên được thực hiện bằng cách sử dụng phím tắt N). Nếu cần quay về câu lệnh gốc tôi có thể nhấn chuột phải lên nó để thay đổi.

Vì lý do trên, lệnh LEA cũng được sử dụng để thực hiện các tính toán nằm trong [], sau đó chuyển kết quả tính toán vào thanh ghi đích, mà không cần truy cập nội dung.

Xem xét các ví dụ:

LEA EAX, [4+5]

Lệnh trên sẽ tính toán và gán 9 vào thanh ghi EAX, nó sẽ không chuyển nội dung của địa chỉ 0x9 như lệnh MOV sẽ thực hiện: MOV EAX, [4+5]

LEA EAX, [EBP – 0C]

Lệnh trên chuyển kết quả của EBP – 0C, là địa chỉ bộ nhớ của biến thu được khi thực hiện phép tính EBP – 0C và gán cho thanh ghi EAX. Khác với lệnh này MOV EAX, [EBP – 0C], ngoài việc tính toán EBP-0C để có được kết quả địa chỉ giống như lệnh LEA, lệnh này còn tìm kiếm nội dung của một giá trị được lưu trữ tại địa chỉ đã tính toán và gán giá trị đó cho EAX.

Chốt lại vấn đề, điều rất quan trọng giúp chúng ta nhận ra sự khác biệt giữa lệnh LEA và lệnh MOV là:

  • Lệnh LEA thực hiện lấy địa chỉ biến. Tương ứng mã giả là a = &b
  • Lệnh MOV thực hiện lấy giá trị được lưu tại địa chỉ biến. Tương ứng với mã giả là a = *b

Khi phân tích ứng dụng Vewiever, chúng ta thấy trong kết quả của việc tìm kiếm lệnh LEA thì hầu như đều sử dụng lệnh này để có được địa chỉ của các biến hoặc tham số trên ngăn xếp. Có rất nhiều lệnh sử dụng [EBP + something].

Một ứng dụng khác của lệnh LEA là các phép toán kết hợp giữa các thanh ghi và các hằng số, kết quả tính được gán cho toán hạng đầu tiên có thể một số hoặc một địa chỉ phụ thuộc vào giá trị của các thanh ghi.

Trong hình trên, tại thời điểm thực hiện tính toán, giả sử nếu ESI có giá trị 400000 và EAX bằng 2, thì giá trị của thanh ghi EDX sẽ là kết quả tính toán của biểu thức 0x400000 + 2*4+0x14:

Nói cách khác, nó sẽ gán giá trị 0x40001c vào thanh ghi EDX. Cơ bản về lệnh LEA đến đây là kết thúc và cũng là kết thúc của phần 5.

Xin chào và hẹn gặp lại ở phần 6!

Xin gửi lời cảm ơn chân thành tới thầy Ricardo Narvaja!

m4n0w4r

Ủng hộ tác giả

Nếu bạn cảm thấy những gì tôi chia sẻ trong bài viết là hữu ích, bạn có thể ủng hộ bằng “bỉm sữa” hoặc “quân huy” qua địa chỉ:

Tên tài khoản: TRAN TRUNG KIEN
Số tài khoản: 0021001560963
Ngân hàng: Vietcombank

Leave a Reply