Do yêu cầu phổ biến, tôi đang bắt đầu một loạt bài viết về kỹ thuật đảo ngược mới sẽ trình bày chi tiết cách tôi phân tích các mẫu khác nhau, thay vì chỉ trình bày những phát hiện của tôi như tôi thường làm. Hầu hết các bài viết sẽ tập trung vào IDA Pro (phiên bản đánh giá cũng nên hoạt động) với WinDbg như một phần phụ trợ (bạn có thể sử dụng bất kỳ phần phụ trợ nào mà bạn cảm thấy thoải mái). Nếu bạn đang sử dụng thứ gì đó như Immunity hoặc OllyDbg để phân tích phần mềm độc hại, tôi khuyên bạn nên theo dõi các bài đăng này vì bạn sẽ sớm biết lý do tại sao IDA đáng học hỏi. Tôi cũng nên nói thêm rằng tôi không phải là một chuyên gia, vì vậy nếu bạn có cách nào tốt hơn để làm điều gì đó, vui lòng để lại bình luận giải thích phương pháp của bạn.
Bắt đầu tắt
Tôi thực sự đã lấy nhị phân trình nạp từ virustotal để không phải xử lý macro, nhưng nếu bạn thấy mình bắt đầu với một trong các tài liệu từ độc hại đặc trưng của Dridex, bạn có thể làm theo hướng dẫn này để truy xuất nhị phân của trình tải.Dridex không có bất kỳ tính năng chống gỡ lỗi hoặc chống máy ảo nào trong bất kỳ mã nào ngoài macro, vì vậy chúng tôi đã có một số công việc cần giải quyết. Giai đoạn đầu tiên trong phân tích ban đầu của tôi là chỉ đơn giản là chạy phần mềm độc hại trên một máy ảo (tôi thực sự sử dụng VPS Windows vì chúng ít có khả năng bị phát hiện bởi VM vì nó thường nhắm mục tiêu VMware hoặc VirtualBox, nhưng VM thì tốt. .). Ngày nay, hầu hết phần mềm độc hại đều kiểm tra C&C, vì vậy cách dễ nhất để tìm quy trình chính là tìm kiếm các kết nối gửi đi, với Dridex, việc này dễ dàng như mở Process Hacker và chuyển đến tab “Mạng” khi chạy tệp nhị phân.
| Dridex đăng ký C&C |
Như chúng ta có thể thấy ở trên, explorer thực hiện một kết nối đi đến một IP dân cư trên cổng 443 (trong lần thực thi đầu tiên, nó cũng sẽ liên kết cổng 443 hoặc 8443). Đây là chỉ báo khá tốt về sự thỏa hiệp (IoC) do trình thám hiểm thực tế hầu như không bao giờ tạo kết nối; nhưng, vì đây là nơi ưa thích để phần mềm độc hại ẩn náu, nó thường có thể được nhìn thấy đang đăng nhập vào các máy chủ C&C của mạng botnet.
Bây giờ chúng ta biết mã đang ở trong trình thám hiểm, chúng ta cần tìm nó và lấy nó ra. Một cách để tìm mã được chèn là mở quy trình trong Process Hacker và truy cập trang “Bộ nhớ”.

Điều nổi bật ở đây là khối bộ nhớ 200 mb RWX (có thể đọc, ghi, thực thi), đây là một IoC phổ biến khác. Các nhà phát triển thậm chí sẽ hiếm khi để lại các trang có thể thực thi và ghi được vì nó thường có nghĩa là bữa trưa sớm cho những nhà phát triển khai thác; hơn nữa, không có thực tiễn lập trình phổ biến nào dẫn đến các trang RWX lớn (Windows tải các tệp DLL bằng cách phân bổ một khối các trang có bảo vệ Copy-on-Write, ghi DLL, sau đó đặt các vùng thực thi là có thể thực thi được nhưng không thể ghi). Các nhà phát triển phần mềm độc hại có xu hướng lười biếng và chỉ phân bổ một loạt các trang RWX và đổ mã vào đó, vì vậy các khối lớn các trang RWX thường thấy trong phần mềm độc hại, nhưng hầu như không bao giờ có trong phần mềm.Một cách khác mà chúng tôi có thể tìm thấy bộ nhớ của phần mềm độc hại là bằng một chút tư duy phản biện. Trong trường hợp này, tôi đã tuyên bố rằng explorer thường không tạo kết nối đi nhưng phần mềm độc hại này thì có, vì vậy chúng tôi có thể đính kèm trình gỡ lỗi và đặt điểm ngắt trên ws2_32! Connect. Khi điểm ngắt được nhấn, chúng ta có thể sử dụng lệnh “k” WinDbg để hiển thị ngăn xếp cuộc gọi và xem cuộc gọi đến từ đâu.

Điều thú vị là địa chỉ trả lại không nằm trong vùng RWX khổng lồ, nhưng nó nằm trong vùng gần với nó (có khả năng cũng thuộc về phần mềm độc hại). Chúng ta có thể sử dụng lệnh WinDbg “! Vprot” trên địa chỉ để truy xuất các thông tin khác nhau về nó, quan trọng nhất là “Cơ sở phân bổ” cần một số giải thích.Khi sử dụng các chức năng như VirtualAlloc (Ex) hoặc NtAllocateVirtualMemory để cấp phát bộ nhớ, hạt nhân sẽ phân bổ theo các trang. Một trang là một khối bộ nhớ 4 KB, nếu bạn phân bổ 1 Byte bộ nhớ bằng một trong các chức năng trên, bạn sẽ nhận được 4 KB, nếu bạn phân bổ 6 KB, bạn nhận được hai trang 4 KB liên tiếp, bạn sẽ có ý tưởng. Khi một phân bổ lớn hơn 4 KB được thực hiện (nhiều trang), “Cơ sở phân bổ” cho mọi trang trong phân bổ sẽ được đặt thành địa chỉ bắt đầu của trang đầu tiên, nếu một số phần mềm độc hại đã phân bổ một loạt các trang và viết một tệp PE ở đó, cơ sở phân bổ sẽ là phần bắt đầu của tiêu đề DOS.

Nó là.Bây giờ chúng tôi biết kết nối () đã được gọi từ một địa chỉ thuộc một khối trang bắt đầu từ 0x10000000 và 0x10000000 là phần bắt đầu của tệp PE, chúng tôi có thể giả định rằng phần mềm độc hại là và được đưa vào EXE hoặc DLL, vì vậy tất cả những gì chúng tôi cần làm là đổ nó đi.Đối với điều này, tôi sử dụng một công cụ có tên là pd (Process Dump), bạn có thể tải xuống tại đây . Tất cả những gì chúng ta cần làm là chạy nó với các tham số “-pid <explorer pid> -a <address where PE started>” và chúng ta có tệp nhị phân phần mềm độc hại chính, được giải nén.
Một lưu ý hữu ích: nếu các phương pháp trên không thành công, bạn chỉ có thể chạy pd với tham số “-pid <explorer pid>”, tham số này sẽ kết xuất tất cả các mô-đun trong explorer, đánh dấu bất kỳ mô-đun nào không có trong bảng LDR (Được đưa vào qua PE tiêm) bằng _hiised_ trong tên tệp.

Bây giờ chúng ta có thể mở PE trong IDA Pro.
Đảo ngược mã đã tiêm
Chúng tôi không thực sự muốn đảo ngược mã trong khi nó được đưa vào explorer vì mỗi lần chúng tôi tạm dừng hoặc đạt điểm ngắt, thanh tác vụ sẽ đóng băng, may mắn là có một giải pháp thực sự dễ dàng cho Dridex. Tất cả những gì chúng ta cần làm là sao chép một số chương trình như cmd.exe vào một thư mục và đổi tên nó thành explorer.exe, giết trình thám hiểm thực, sau đó chạy mẫu bằng cmd.exe. Khi chúng tôi thấy mã đã được đưa vào cmdsplorer của chúng tôi (bắt đầu tạo kết nối với C&C), chúng tôi có thể chạy trình khám phá thực.Điều mà bạn có thể biết hoặc không biết là bạn có thể mở một DLL trong IDA và nếu địa chỉ cơ sở ưa thích của DLL giống với địa chỉ của DLL được tải vào một quy trình, bạn có thể đính kèm IDA vào quy trình đó và nó sẽ liên kết. up DLL trong cơ sở dữ liệu IDA với DLL trong bộ nhớ, sao chép bất kỳ thay đổi nào như nhận xét và tên hàm. Với Dridex, có vẻ như DLL luôn được tải ở cùng một địa chỉ (trong trường hợp này là 0x10000000), đây cũng là địa chỉ cơ sở ưa thích của nó. Chúng tôi không cần thay đổi bất cứ điều gì, chỉ cần đặt IDA để sử dụng trình gỡ lỗi WinDbg và đính kèm vào quy trình cmdsplorer của chúng tôi.Điều đầu tiên tôi thường làm là tìm kiếm trang nhập khẩu các hàm như connect () hoặc InternetOpen () vì chúng được sử dụng cho giao tiếp C&C, đây là nơi đầu tiên tôi bắt đầu đảo ngược.

Sau khi đọc qua danh sách nhập khẩu cực kỳ dài, chúng ta có thể suy ra rằng không có cái nào trong số 3 cái là quan tâm thực sự và không tệp thực thi nào có thể chạy chỉ trên những cái đó, vì vậy các chức năng chính có thể được tải động trong thời gian chạy. May mắn thay, chúng ta không phải thực hiện nhiều thao tác vì chúng ta đã biết nơi một trong các hàm được tải động được gọi từ (địa chỉ trả về connect () từ trước đó), sẽ có một nơi tốt để bắt đầu.

Chúng ta có thể thấy rằng hàm chắc chắn được nhập động (gọi edx) và giá trị trong thanh ghi edx bắt nguồn từ loc_10030F34 vì eax được đặt thành 0x10E ngay trước cuộc gọi và đó không phải là địa chỉ hợp lệ. Như tôi đã thấy kỹ thuật này trong phần mềm độc hại trước đây, giả định đầu tiên của tôi là loc_10030F34 giải quyết hàm mỗi khi nó cần được gọi và giá trị trong eax trước cuộc gọi là thứ tự xuất hoặc một số loại id nội bộ cho hàm nó cần phải giải quyết. Nếu chúng ta nhấp chuột phải vào tên hàm và nhấp vào “nhảy tới xrefs để toán hạng”, chúng ta có thể thấy danh sách mọi nơi mà nó được gọi từ đó.

Thực tế là hàm được gọi từ hàng nghìn nơi khác nhau làm tăng thêm lý thuyết rằng nó được gọi mỗi khi cần một hàm, không chỉ được sử dụng để giải quyết tất cả chúng khi khởi động. Chúng tôi có thể đảo ngược chức năng theo cách thủ công để xem nó hoạt động như thế nào rồi viết ra id nào tương ứng với chức năng nào, hoặc chúng tôi có thể gian lận.
IDA Python
IDA python là lý do tại sao tôi chọn IDA thay vì một trình gỡ lỗi đơn giản, bạn có sự linh hoạt của python với sức mạnh của API của IDA, cho phép bạn làm rất nhiều điều bạn có thể muốn. Đối với các tài liệu tham khảo trong tương lai, đây là trang tài liệu cho API.
nhập idc nhập idautils function_names = [] def DumpNames (): cho tên trong function_names: in (tên) def BreakpointHandler (): target = GetRegValue ("EAX") name = NameEx (target, target) call_loc = PrevHead (GetRegValue ("EIP"), 0) nếu tên == "": name = atoa (target) nếu tên không có trong function_names: function_names.append (tên) MakeComm (call_loc, tên) AddCodeXref (call_loc, target, fl_CN) print ("Điểm ngắt lần truy cập:% x, gọi tới:% s"% (GetRegValue ("EIP"), tên)) DelBpt (GetRegValue ("EIP")) def main (): xref = 0 func = 0x10040F34 # Phải là địa chỉ của hàm phân giải # Cho phép sử dụng các hàm python cho các điều kiện điểm ngắt RunPlugin ("python", 3) cho xref trong idautils.XrefsTo (func): nếu xref.type == fl_CN: bpaddr = NextHead (xref.frm, 4294967295) AddBpt (bpaddr) SetBptCnd (bpaddr, "BreakpointHandler ()") print ("Điểm ngắt tại:% x"% bpaddr) nếu __name__ == '__main__': chủ yếu()
Đây là tập lệnh tôi đã viết để lấy tên của mọi chức năng được giải quyết và lệnh gọi giải quyết nó đến từ đâu, tôi sẽ giải thích cách hoạt động của từng phần.
cho xref trong idautils.XrefsTo (func):
Lặp qua từng XrefTo loc_10040F34 (nơi mà loc_10040F34 được tham chiếu từ).
nếu xref.type == fl_CN:
Đảm bảo xref là một cuộc gọi luồng ở gần (một lệnh gọi tới loc_10040F34).
bpaddr = NextHead (xref.frm, 4294967295)
Nhận địa chỉ của lệnh sau xref (sau lệnh gọi tới loc_10040F34 nơi eax đã được đặt thành hàm đã phân giải).
AddBpt (bpaddr) SetBptCnd (bpaddr, "BreakpointHandler ()")
Thêm một điểm ngắt của phần mềm và đặt “điều kiện điểm ngắt” thành BreakpointHandler, điều này có nghĩa là hàm đó sẽ được gọi mỗi khi điểm ngắt được nhấn.
Bây giờ đến với BreakpointHandler:
target = GetRegValue ("EAX")
Lấy giá trị trong thanh ghi eax (chức năng đã giải quyết).
name = NameEx (target, target)
Lấy tên của hàm (giống như ws2_32_connect).
call_loc = PrevHead (GetRegValue ("EIP"), 0)
Nhận hướng dẫn trước điểm ngắt (lệnh gọi tới loc_10040F34).
nếu tên == "": name = atoa (target)
Nếu tên của hàm không thể được giải quyết (nó không phải là một xuất), hãy chuyển đổi địa chỉ của nó thành một chuỗi.
nếu tên không có trong function_names: function_names.append (tên)
Nếu chức năng đã giải quyết chưa được chúng tôi xử lý, hãy thêm nó vào danh sách các chức năng mà chúng tôi đã xử lý.
MakeComm (call_loc, tên)
Nhận xét phiên bản của “call loc_10040F34” với tên của hàm mà nó giải quyết.
AddCodeXref (call_loc, target, fl_CN)
Thêm một Xref vào hàm đã giải quyết để nếu chúng ta nói ws2_32! Connect và nhấp chuột phải vào “Chuyển tới xrefs đến toán hạng”, chúng ta sẽ thấy tất cả các vị trí trong mã nơi loc_10040F34 được sử dụng để giải quyết ws2_32! Connect.
DelBpt (GetRegValue ("EIP"))
Xóa điểm ngắt này để chúng ta không bị gọi đi gọi lại một cách vô ích.
Tất cả những gì chúng ta cần làm là đi tới “File> Scripts” và dán script, đặt trường “Ngôn ngữ kịch bản” thành python, sau đó nhấp vào chạy.

Khi chúng tôi chạy tập lệnh, chúng tôi sẽ thấy đầu ra trong hộp đầu ra IDA và một tải các điểm ngắt mới.

Sau khi nhấp vào chạy và để trình gỡ lỗi chạy trong 20 phút (kiểm tra C&C là 20 phút), hầu hết các chức năng chính sẽ được giải quyết. Chúng tôi có thể thấy rằng cuộc gọi kết nối của chúng tôi đã được nhận xét tự động, giúp việc phân tích trở nên dễ dàng hơn nhiều.

Nếu chúng tôi đặt chế độ bảng điều khiển thành python (nhấp vào nút có nội dung WINDBG), chúng tôi có thể sử dụng hàm DumpNames () trong tập lệnh của mình để có được danh sách đẹp về mọi hàm được gọi trong khi tập lệnh đang chạy.

Tuyệt vời!
Trước đây tôi đã cố gắng thực hiện bước tập lệnh và tìm hướng dẫn “call <reg>” và nhận xét + xref đó, nhưng nó được chứng minh là cực kỳ chậm và khá lỗi, vì vậy tôi quyết định chỉ nhận xét lệnh gọi tới trình giải quyết (đó là khá dễ dàng để tìm cuộc gọi tương ứng nếu bạn cần). Cũng như sử dụng xrefs, bạn có thể tìm thấy các nhận xét bằng cách nhấn ALT + T (văn bản tìm kiếm) và nhập tên nhận xét (ví dụ: ws2_32_connect).
Đó là tất cả cho ngày hôm nay, trong phần tiếp theo tôi sẽ trình bày cách sử dụng một kỹ thuật tương tự để định vị và kết xuất tất cả các chuỗi được mã hóa.