Phân tích Confuser 1.9.0.0 - Anti-tamper protection - Bản dịch
1. Phân tích Confuser 1.9.0.0
Anti-tamper Protection
Tác giả: ubbelol (http://ubbecode.wordpress.com)
Người dịch: Levis Nickaster (http://ltops9.wordpress.com)
Đây là tài liệu MIỄN PHÍ, nhằm phục vụ mục đích nghiên cứu và chia sẻ kiến thức. Khi copy và đăng tải ở bất kì đâu cần ghi rõ nguồn để tôn
trọng tác giả cũng như tôn trọng người dịch, cảm ơn. Đề xuất, đóng góp để bản dịch tốt hơn, hãy gửi email cho tôi:
levintaeyeon[at]live[dot]com.
Anti-tamper là gì?
Trong Confuser 1.9.0.0 có 2 kiểu Anti-tamper protection, nhưng theo những gì tôi biết thì Confuser chỉ sử dụng 1 trong 2 kiểu
đó. Hai kiểu anti-tamper là Anti-tamper JIT và Anti-tamper Mem (Confuser chỉ sử dụng loại này). Tôi sẽ không giải thích về
Anti-tamper JIT, bởi vì nó không được sử dụng (hoặc là chưa được sử dụng, tính đến thời điểm này). Một phần do tôi cũng
chưa hiểu hết về anti-tamper JIT cho nên cũng chưa thể giải thích một cách rõ rang được. Vậy nên, trong bài viết này tôi sẽ
nói về Memory Anti-tamper (Anti-tamper mem)
Mục đích của Anti-tamper là đảm bảo tính tương thích của từng method trong file bị obfuscate, nhưng trong Confuser nó còn
kèm thêm nhiều chức năng khác nữa. Nó sẽ tiến hành encrypt code trong các method, chuyển tất cả thành các byte rỗng, và
method sẽ chỉ được decrypt ra khi chương trình hoạt động. Điều này sẽ khiến các trình decompiler trở nên vô dụng khi chúng
sẽ chỉ đưa ra các method với phần code trống rỗng.
Đây là code của một method được bảo về bởi anti-tamper, phàn code bên trong method hoàn toàn bị biến mất
Dịch ngược bằng cách nào?
Việc phục hồi code cho từng method thực sự là cực hình, và sẽ gần như là vô tận nếu như bạn gặp phải 1 file lớn, với nhiều
class và nhiều method. Thế nên, tốt nhất là hãy xây dựng 1 chương trình để làm việc này một cách tự động. Nhưng để xây
dựng được 1 chương trình kiểu như vậy, bạn cần phải hiểu được nguyên lý để thực hiện trước.
Những công cụ cần thiết để bắt đầu nghiên cứu:
- CFF Explorer suite (http://ntcore.com/exsuite.php)
- Một trình chuyển qua lại giữa thập phân và thập lục phân (http://www.statman.info/conversions/hexadecimal.html)
- Visual Studio (để viết chương trình giúp chúng ta decrypt code)
Như tôi đã nói ở trên, cơ chế obfuscation này giấu tất cả code trong method đi và thay vào đó là các byte rỗng (0x00). Nếu
muốn kiểm tra xem chương trình bạn đang nghiên cứu có được bảo vệ bởi anti-tamper hay không, thì hãy kiểm tra phần
code của mỗi method trong CFF explorer, nếu chứa toàn các byte 00, có nghĩa là anti-tamper đã được sử dụng. Mở file cần
nghiên cứu trong CFF Explorer, chuyển đến .NET Directory -> Metadata Streams -> #~ -> Tables, mở vào “Method” để lấy
danh sách tất cả các method có trong file. Chọn bất kì 1 method nào đó, ghi lại RVA address ghi trong cột đầu tiên. Sau đó vào
phần “Address Converter”, điền RVA vừa ghi được và bấm enter, nhìn ở phía dưới khung hex editor:
2. Như trong hình này, có nghĩa là anti-tamper đã được sử dụng.
Tôi cũng đã nói từ trước, Confuser chuyển tất cả code gốc trong method đến một khu vực khác trong file, và chúng ta phải
tìm ra khu vực đó nằm ở đâu. Ta có thể xem file AntitamperConfusion.Mem.cs trong mã nguồn của Confuser
(http://confuser.codeplex.com/SourceControl/latest#Confuser.Core/Confusions/AntiTamperConfusion.Mem.cs ) . File này rất
nhiều code, cho nên tôi sẽ không giải thích hết toàn bộ, chúng ta chỉ cần chú ý vào phần code này:
Confuser tạo 1 PE Section mới trong file. Nhưng tại sao lại cần phải chú ý ở phần code này? Bởi vì section mới tạo này sẽ là
nơi chứa phần code gốc đã được encrypt, theo những gì ta thấy trong đoạn code sau:
Bây giờ ta đã biết được phần code được giấu ở đâu, tuy nhiên cần phải tìm ra cách để decrypt phần code đó
3. Chúng ta đã biết là phần code của các method sẽ được decrypt trong lúc chương trình đang hoạt động. Có nghĩa là chúng ta
có thể xem code của các method làm công việc decrypt này trong file đã bị obfuscate. Nếu chúng ta xem method
<Module>.cctor trong file, ta sẽ nhìn thấy một lệnh call đến 1 hàm public static unsafe void(). Và nếu ta xem code của hàm
này, sẽ biết rằng hàm này chứa code của quá trình decrypt. Tôi sẽ không giải thích toàn bộ code của hàm này, mà sẽ chỉ tóm
gọn lại chức năng và cách hoạt động của hạm:
- Thực hiện 1 số việc kiểm tra để đảm bảo tính tương thích
- Đọc toàn bộ metadata streams và lưu vào 1 buffer
- Đọc section mới được tạo để lấy phần data chứa code bị encrypt
- Tiến hành decrypt code và thay vào phần byte rỗng có trong các method của chương trình.
Chúng ta cần phải xem cách mà chương trình decrypt code như thế nào. Xem code sau (reader2 chứa vị trí bắt đầu của
section chứa code bị encrypt):
Chữ nhật màu xanh lục là nơi mà chương trình sẽ đọc 1 giá trị checksum kiểu long.
Chữ nhật màu đỏ là để lấy độ dài của IV (luôn bằng 167) và giá trị thực tế của IV
Chữ nhật màu xanh dương là lấy tất cả các phần code bị encrypt và tổng độ dài của chúng.
Chữ nhật màu da cam là để gọi method decrypt, với tham số đưa vào là 3 mảng kiểu byte buffer7 chứa IV, buffer2 chứa code
bị encrypt, vậy buffer4 chứa cái gì? Kiểm tra phần code ở phía trên ta sẽ thấy như sau:
4. Chữ nhật màu xanh lục là chương trình sẽ bỏ qua 8 cột đầu tiên trong Metadata header và sẽ gán giá trị của
NumberofStreams vào biến num9. Sau đó sẽ có 1 vòng lặp để thao tác với từng stream.
Hai dòng code đầu tiên trong chữ nhật màu đỏ đọc offset address và độ dài của stream mà chương trình đang thao tác.
Chữ nhật màu xanh dương là chương trình sẽ ghi toàn bộ dữ liệu trong stream đang thao tác, vào trong biến stream2
(num10 chứa độ dài của stream).
Chữ nhật màu da cam lưu tổng hợp dữ liệu của của tất cả các stream (đã được lưu tại stream2) vào trong buffer4.
Như vậy ta đã biết được những tham số được dùng để decrypt code:
Buffer4 chứa toàn bộ dữ liệu của các stream
Buffer7 chứa IV
Buffer2 chứa phần code bị encrypt.
Bây giờ chúng ta sẽ thử phục hồi lại 1 vài method. Mở CFF Explorer lên, chuyển đến .NET Directory -> Metadata Streams,
chuyển đến từng metadata stream và dump lần lượt dữ liệu của chúng, lưu lại file trên đĩa cứng. bằng cách bấm chuột phải
bên trong Hex Editor và chọn Copy -> Into new file. Tôi sẽ đặt chúng là “streamdump1”,”streamdump2”,vv…
Sau khi đã dump xong tất cả các stream, chyển sang chọn phần Section Header. Bạn sẽ nhìn thấy 3 section cơ bản, mặc định
của .NET (.text, .rsrc, .reloc), và 1 section mới với tên rất lạ.
Section này
5. Đây chính là section được Confuser thêm vào để chứa phần code bị encrypt. Dump luôn section này thành 1 file khác, cùng
thư mục với các stream bạn dump được lúc nãy. Tôi đặt tên cho file này là “sectiondump”. Thư mục của bạn nhìn sẽ giống thế
này:
Bây giờ chúng ta đã có đủ dữ liệu cần thiết để tiến hành decrypt. Chúng ta sẽ tạo 1 chương trình C# để thực hiện việc decrypt
này. Vậy nên hãy mở Visual Studio, tạo 1 project C# Console. Tôi đặt tên cho nó là BodyDecryptor.
Tôi tạo code này(http://pastebin.com/ZWkG0Ewd ) để load từng streamdump và nối chúng lại, lưu vào 1 buffer, sau đó sử
dụng một vài phần trong code của Confuser để thực hiện việc decrypt. Bạn cần phải chỉnh giá trị của biến path và các key từ 1
đến 4 cho phù hợp với file của bạn đang làm. Thêm luôn code của phần decryptor vào chương trình
(http://pastebin.com/YnDMdcD3) Nếu bạn không biết cách lấy các key như thế nào, hãy nhìn đoạn code dưới đây (lấy ra từ
method anti-tamper của một file bị obfuscate):
6. Sauk hi bạn viết code và chạy chương trình, chương trình sẽ tạo ra 1 file mới với tên “method*RVA+_dump” trong folder của
bạn. Tất cả code đã được decrypt. Bây giờ chúng ta phải ghi phần code đã được decrypt này vào phần byte 00 ở trong các
method của file bị obfuscate.
Mở CFF Explorer và chuyển đến .NET Directory -> Metadata Streams -> #~ -> Tables. Chọn 1 method bất kì mà bạn muốn
phục hồi, ghi lấy RVA Address của method đó, chuyển RVA từ hệ thập lục phân về hệ thập phân ( có thể sử dụng công cụ dec-
hex ở đây: http://www.statman.info/conversions/hexadecimal.html). Tìm file có tên chứa RVA Address tương ứng trong
folder chứa các file được tạo ra sau khi chạy chương trình chúng ta viết lúc nãy, mở file đó lên trong 1 CFF Explorer nữa. Bôi
đen tất cả những gì có ở trong phần hex editor của file methodXXXX_dump (XXXX là RVA chúng ta đã biết), bấm chuột phải,
chọn Copy -> Normal:
Chuyển sang file bị obfuscate, chuyển đến phần Address Converter và điền RVA bạn đã biết và ấn Enter. Bấm chuột phải ngay
tại nơi mà bạn được đưa đến trong hex editor , chọn “Write”
Save lại, bây giờ mở thử file đó trong decompiler và xem thử code của method bạn vừa khôi phục. Bây giờ bạn đã có thể nhìn
thấy code thật. Tiến hành làm tương tự với những method còn lại.
Sauk hi khôi phục toàn bộ các method thì vẫn còn một việc cần phải làm nữa. Chương trình đó vẫn sẽ thực hiện code Anti-
tamper khi bạn chạy chương trình. Việc này được thực hiện bằng lệnh call ở trong method <Module>.cctor, chúng ta phải
loại bỏ lệnh call này. Bạn có thể dùng .NET Reflector + plugin Reflexil hoặc CFF để làm.
Nếu bạn dùng CFF
Chuyển đến .NET Directory -> Metadata streams -> #~ -> Tables -> Methods. Tìm method đầu tiên có tên .cctor. Ghi lấy RVA
của method này, chuyển dến phàn Address Converter và điền RVA đó vào để lấy offset address.
7. Khi làm xong bạn sẽ ở đây:
Bỏ qua byte 1A đầu tiên, ta nhìn thấy byte 28. Đây chính là bytecode của lệnh call. 4 byte tiếp theo là MethodDesc, byte 2A
cuối cùng là lệnh RET. Chỉ cần thanh đổi 28 0B 00 00 06 thành 2A 00 00 00 00 (hoặc 00 00 00 00 00). Thế là đã loại bỏ được
anti-tamper.
Nếu bạn sử dụng Reflector + Reflexil:
Tìm <Module>.cctor:
Mở method đó ra và bật Reflexil. Tìm lệnh call đầu tiên trong method đó và bấm chuột phải trong Reflexil, chọn Delete và lưu
lại.
Như vậy là bạn đã hoàn toàn loại bỏ được Anti-tamper protection của Confuser.
This article is originally created by ubbelol, and has been translated into Vietnamese by me (Levis), so I’m not the author of
it. All credits go to him. Any suggests for better translation in future, feel free to contact me: lvintaeyeon[at]live[dot]com or
my personal blog: http://ltops9.wordpress.com
Enjoy and best regards
Levis
Created Aug 10 2014