19/09/2018, 09:46

Sử dụng OllyDbg trong phân tích mã độc Phần 1

Trước khi trở nên trứ danh trong giới phân tích mã độc, OllyDbg được dùng chủ yếu để crack phần mềm. OllyDbg từng là lựa chọn debugger hàng đầu đối với các chuyên gia phân tích mã độc và chuyên gia khai thác lỗ hổng phần mềm cho đến khi mã nguồn của OllyDbg 1.1 được mua lại bởi ...

Trước khi trở nên trứ danh trong giới phân tích mã độc, OllyDbg được dùng chủ yếu để crack phần mềm. OllyDbg từng là lựa chọn debugger hàng đầu đối với các chuyên gia phân tích mã độc và chuyên gia khai thác lỗ hổng phần mềm cho đến khi mã nguồn của OllyDbg 1.1 được mua lại bởi Immunity và đổi tên thành ImmDbg. ImmDbg được phát triển nhằm vá các lỗi trong OllyDbg, thêm vào một trình thông dịch Python và hướng đến các chuyên gia khai thác lỗ hổng phần mềm, nhiều người ưa chuộng ImmDbg hơn OllyDbg. Như vậy tức là OllyDbg 1.1 không hơn gì ImmDbg, các thao tác cơ bản trên OllyDbg trong chương này cũng có thể áp dụng tương tự trên ImmDbg, nhưng một số plug-in trên OllyDbg sẽ không thể sử dụng dễ dàng trên ImmDbg. ImmDbg có ưu điểm riêng của nó, chẳng hạn hỗ trợ tốt các Python API.

Đừng ngại sử dụng OllyDbg phiên bản mới nhất. Chuyên gia an ninh mạng Nguyễn Việt Anh của SecurityBox đã thực hiện một bài viết ngắn hướng dẫn các bạn làm quen và sử dụng OllyDbg trong phân tích mã độc.

Nạp một mã độc vào OllyDbg

Có nhiều cách để nạp một mã độc vào OllyDbg. Ta có thể nạp trực tiếp file thực thi hoặc DLL. Trong trường hợp mã độc đang chạy trên hệ thống, ta có thể gán tiến trình của nó vào OllyDbg..

Mở một file thực thi

Cách tốt nhất để debug một mã độc là tạo một tiến trình mới cho nó. Chọn File > Open và điền tham số đầu vào nếu cần thiết. Ta chỉ có thể truyền tham số dòng lệnh tại bước này.

ảnh 1

Sau đó, loader của OllyDbg sẽ nạp file thực thi tương tự như OS loader. Mặc định, OllyDbg sẽ dừng tại entry point chỉ định bởi lập trình viên, như WinMain chẳng hạn, nếu nó xác định được vị trí của entry point đó. Nếu không, OllyDbg sẽ dừng tại entry point định nghĩa trong PE header. Ta có thể thiết lập một số tùy chọn khởi động trong bảng chọn Debuggin Option (Options > Debugging Options). Chẳng hạn, để ngắt ngay trước khi thực thi bất kì dòng code nào nào chương trình, ta chọn System Breakpoint…

ảnh 2

Gán một tiến trình đang chạy vào OllyDbg

File > Attach và chọn process để attach. Nếu có hơn một process có cùng một tên, cần phân biệt qua PID. OllyDbg sau đó sẽ ngắt và dừng chương trình cùng mọi thread của nó.

ảnh 3

Code của thread đang được thực thi sẽ được hiển thị trên màn hình OllyDbg. Ta rất dễ dừng thread đúng vào lúc nó đang thực thi code từ một DLL hệ thống. Tất nhiên, ta không bao giờ muốn phân tích một thư viện Windows làm gì và cách đơn giản để tránh trường hợp này là đặt một breakpoint tại code section. Chương trình sẽ được ngắt tại lần tới khi nó truy cập code section.

Giao diện của OllyDbg

Sau khi nạp một chương trình, giao diện chính của OllyDbg như hình bên dưới.

ảnh 5

Cửa sổ dịch ngược – góc trái-trên – hiển thị con trỏ lệnh và vùng lệnh thực thi của chương trình được debug xung quanh vị trí con trỏ. Để sửa đổi lệnh hoặc dữ liệu hay thêm lệnh mới, click vào dòng lệnh và nhấn dấu spacebar.

ảnh 6

Cửa sổ thanh ghi – góc phải-trên – hiển thị trạng thái hiện tại của các thanh ghi mà chương trình được debug đang sử dụng. Các thanh ghi này sẽ chuyển màu từ đen sang đỏ nếu lệnh vừa thực thi sửa đổi giá trị của thanh ghi.Ta có thể sửa đổi dữ liệu trong cửa sổ thanh ghi bằng cách double click vào giá trị của thanh ghi tương ứng.

ảnh 7

Cửa sổ stack – góc phải-dưới – thể hiện trạng thái hiện tại của stack trong bộ nhớ. Cửa sổ này luôn hiển thị đỉnh stack của một thread nhất định. Ta có thể quản lý stack bằng cách click phải vào vị trí hoặc giá trị của vùng nhớ và chọn Modify. OllyDbg cũng tự động thêm comment (cột bên phải giá trị vùng nhớ) cho một số giá trị stack để mô tả các tham số trước khi chúng được truyền qua một lời gọi hàm.

ảnh8

Cửa sổ memory dump – góc trái-dưới – thể hiện trạng thái bộ nhớ của process đang được debug. Để sửa đổi giá trị một ô nhớ, click phải vào giá trị ô nhớ đó và chọn Edit (Ctr+E). Cách này hữu ích khi cần sửa đổi giá trị một biến toàn cục hoặc dữ liệu mà mã độc chỉ lưu trữ trên RAM.

ảnh 9

Memory Map

View > Memory (Alt+M), hiển thị mọi memory block cấp phát cho chương trình được debug.

Memory map giúp ta quan sát cách chương trình được bố trí trên bộ nhớ. Trong hình, trình thực thi được gán nhãn với các code section và data section. Mọi DLL và các section của chúng cũng được thể hiện trong memory map. Ta chỉ cần double click tại bất cứ dòng nào để trong memory map để xem memory dump của section đó. Ta cũng có thể chuyển hướng đến section đó trên cửa sổ dịch ngược bằng cách click phải và chọn View in Disassembler.

ảnh 11

Năm 2018 xu hướng tấn công thông qua phần mềm độc hại không tập tin lên ngôi

Rebasing

Memory map có thể giúp ta hiểu một PE file được rebase trong lúc thực thi như thế nào. Rebasing là thao tác xảy ra khi một module trong Windows không được nạp vào địa chỉ base address chỉ định của nó.

Base Address

Mọi file PE trong Windows đều có một base address chỉ định, được định nghĩa là giá trị image base trong PE header.

Image base không phải là địa chỉ mà mã độc nhất thiết phải được nạp vào đó, mã độc chỉ ưu tiên địa chỉ đó. Đa số các trình thực thi được thiết kế để nạp vào bộ nhớ tại địa chỉ 0x00400000, là địa chỉ mặc định được sử dụng mởi nhiều trình biên dịch trên Windows. Developer có thể chọn một địa chỉ khác làm base image.

ASLR (address space layout randomization – bố trí không gian nhớ ngẫu nhiên)

Cấp phát lại (relocation) vùng nhớ là cần thiết vì một ứng dụng có thể import nhiều DLL, mỗi DLL lại dùng một base address chỉ định mà nó muốn được nạp vào bộ nhớ tại địa chỉ đó. Nếu 2 DLL được nạp và chúng đều chỉ định ưu tiên nạp vào địa chỉ 0x10000000, chúng không thể cùng được nạp vào địa chỉ đó. Windows sẽ nạp một DLL vào địa chỉ đó và sau đó cấp phát lại một vùng nhớ khác cho DLL còn lại.

Hầu hết các DLL có sẵn trong Windows OS đều có base address chỉ định khác nhau và chúng sẽ không bị xung đột. Tuy nhiên, các ứng dụng bên thứ ba thường chỉ định chung một base address.

Địa chỉ tuyệt đối và Địa chỉ tương đối (Absolute-Relative)

Thủ tục cấp phát lại phức tạp hơn là chỉ việc nạp đoạn code vào một địa chỉ khác. Nhiều lệnh chỉ định tới những địa chỉ nhớ tương đối nhưng một số lệnh lại làm việc với những địa chỉ nhớ cụ thể.

anhe 12

3 lệnh trên đều được thực thi trơn tru mà không quan tâm chúng được nạp vào bộ nhớ ra sao vì chúng dùng địa chỉ tương đối. Nhưng lệnh truy cập dữ liệu tại 0x40120C sẽ không thể thực hiện được vì nó dùng địa chỉ tuyệt đối để truy cập tới một vùng nhớ. Nếu file thực thi được nạp vào bộ nhớ tại một vùng nhớ khác với base location chỉ định, lệnh 0x40120C sẽ chạy sai. Đa số DLL được đóng gói với một danh sách vùng nhớ hiệu chỉnh trong .reloc section của PE header.

Các DLL được nạp sau .exe và không cần theo một trình tự nào khác. Như vậy ta không thể dự đoán trước được DLL nào sẽ được rebase trong bộ nhớ ra sao. Nếu một DLL vừa bị thiếu relocation section vừa được nạp không đúng với base address chỉ định của nó, DLL sẽ không được nạp.

Thủ tục cấp phát lại bộ nhớ cho các DLL có hiệu suất thấp và làm kéo dài thời gian nạp DLL. Trình biên dịch thường dùng chung một địa chỉ làm base address mặc định cho mọi DLL khiến việc cấp phát lại vùng nhớ gần như là điều tất yếu. Một lập trình viên giỏi cần chú ý tới điều này và chỉ định một base address riêng cho DLL của mình để hạn chế việc phải cấp phát lại vùng nhớ mỗi khi DLL được nạp.

Hình bên dưới minh họa cơ chế cấp phát lại vùng nhớ, quan sát qua Memory map của OllyDbg đối với file QUnpack.exe. Ở đây ta có một file thực thi và hai DLL. QUnpack sử dụng địa chỉ nạp chỉ định là 0x00400000, nó được nạp vào bộ nhớ trước tiên. PEiDLL cũng được chỉ định địa chỉ nạp 0x00400000 trong khi vùng nhớ bắt đầu bằng địa chỉ 0x00400000 đã được cấp phát cho QUnpack, nên DLL này sẽ được cấp phát lại vùng nhớ bắt đầu bằng địa chỉ 0x00630000. DLL PESniffe sử dụng địa chỉ nạp chỉ định là 0x10000000 và tại thời điểm nó được nạp, vùng nhớ bắt đầu bằng địa chỉ này chưa được cấp phát cho DLL nào khác nên nó được nạp vào vùng nhớ đúng với base address chỉ định (0x10000000). Trong trường hợp này, tất cả địa chỉ tuyệt đối được sử dụng trong PEiDLL phải được hiệu chỉnh lại để các hàm trong nó chạy đúng.

ảnh 15

Nếu quan sát PEiDLL trong IDA trong khi đang debug chương trình QUnpack, các địa chỉ trong PEiDLL là không thống nhất giữa IDA và debugger vì IDA không có cơ chế phân tích hiện tượng rebasing trong thời gian thực thi. Để tránh phải thường xuyên hiệu chỉnh lại các địa chỉ tuyệt đối của PEiDLL trong IDA, ta cần thực hiện nạp thủ công (manual load) tại bước nạp DLL này vào IDA.

ĐÓN ĐỌC: Chuyên đề phân tích mã độc của chuyên gia Nguyễn Việt Anh  TẠI ĐÂY

XEM THÊM: Sử dụng OllyDbg trong phân tích mã độc Phần 2

0