Professional Documents
Culture Documents
Reverse .NET Software IV
Reverse .NET Software IV
Reverse .NET Software IV
9 Rongchaua
www.reaonline.net
1 Giới thiệu_____________________________________________________________________ 2
2 Strong name (Định danh) ___________________________________________________ 3
2.1 Giới thiệu________________________________________________________________________ 3
2.2 Ứng dụng _______________________________________________________________________ 4
2.2.1 Chống giả mạo ___________________________________________________________________________ 4
2.2.2 Bảo mật _________________________________________________________________________________ 4
2.2.3 Khuyết điểm _____________________________________________________________________________ 5
2.3 Khởi động cùng strong name __________________________________________________ 5
2.4 Cách tạo strong name __________________________________________________________ 6
2.5 Bẻ khóa strong name của một assembly đơn _________________________________ 9
2.6 Kết luận ________________________________________________________________________ 10
3 Xóa strong name từ PE Header ____________________________________________ 11
3.1 Ý tưởng_________________________________________________________________________ 11
3.2 .NET file format ________________________________________________________________ 11
3.3 Kết luận ________________________________________________________________________ 16
4 Xóa strong name từ các assembly phụ thuộc _____________________________ 17
5 Xóa strong name bằng Tool________________________________________________ 22
6 Tổng kết_____________________________________________________________________ 23
7 Kiến thức bổ sung __________________________________________________________ 23
7.1 Import Table___________________________________________________________________ 24
7.1.1 Cấu trúc________________________________________________________________________________ 24
7.1.2 Ý nghĩa ________________________________________________________________________________ 27
7.2 Base Relocations Section _____________________________________________________ 27
8 Tài liệu tham khảo__________________________________________________________ 28
9 Lời kết _______________________________________________________________________ 29
Trang 1 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
1 Giới thiệu
• Trong phần III chúng ta đã tìm hiểu các phương pháp patch căn bản cũng như
một số loại bảo vệ thường gặp. Khi chúng ta thực hiện patch, chúng ta gần
như không gặp một khó khăn hoặc trở ngại nào, dù chúng ta thay đổi mã
nguồn, chỉnh sửa source code hoặc thậm chí xóa cả một đoạn code đi chăng
nữa.
• Sở dĩ chúng ta có thể thực hiện việc patch dễ dàng như vậy là do tác giả
không sử dụng một biện pháp phòng ngự nào cho phần mềm. Vì vậy công
việc patch diễn ra rất dễ dàng.
• Nếu như các bạn đã có kinh nghiệm hoặc cơ hội được làm quen các kiểu anti-
patch thế hệ ASM thì chắc cũng có biết qua về CRC Check hoặc MD5 Check.
Các giải thuật check này nhằm đảm bảo tính toàn vẹn và chính xác của một
tập tin. Thực tế, ban đầu các giải thuật check này được đưa vào ứng dụng ở
hệ thống thông tin và truyền tải dữ liệu nhằm để kiểm tra xem một gói dữ liệu
khi gởi đi có bị lỗi trên đường truyển tải hay không. Sau này, các nhà lập trình
đưa phương pháp này vào trong lĩnh vực kỹ thuật phần mềm nhằm chống lại
các cracker sử dụng kỹ thuật patch để patch sản phẩm của họ.
• Trong phần IV này chúng ta sẽ tìm hiểu một phương pháp để anti-patch cho
.NET. Tức là không cho các cracker có thể dễ dàng patch được các sản phẩm
.NET của chúng ta. Phương pháp này còn được ứng dụng trong các lĩnh vực
khác. Tuy nhiên ở đây chúng ta chỉ quan tâm đến khả năng anti-patch của
phương pháp này: đó là phương pháp dùng strong name.
• Tool strong name được tích hợp sẵn ngay trong bộ Visual Studio, cho nên
chúng ta cần cài đặt bộ Microsoft Visual Studio để sử dụng.
• Trước khi xem phần IV này tôi đề nghị các bạn nên xem lại phần III cũng như
các phần trước để nắm vững cách sử dụng các Tool và ôn lại kiến thức cơ sở.
Tôi sẽ không lặp lại các bước nếu như các bước này đã được nêu ở các phần
trước.
• Phần mềm sử dụng trong ví dụ này là (đã đính kèm):
o Sample Crackme with Strong name coded by rongchaua.
o Sample Crackme with Strong name in DLL coded by rongchaua.
• Tool sử dụng :
o Reflector : http://www.aisto.com/roeder/dotnet/
o ILASM và ILDASM: có sẵn khi cài bộ Microsoft Visual Studio .NET.
o IDA: http://www.idapro.com/
o UltraEdit: http://www.ultraedit.com/
o CFF Explorer http://ntcore.com/Files/Explorer_Suite_Setup.zip
o Strong Name Remove Tool: link down xem phần tham khảo.
• LƯU Ý: Do phiên bản Windows mà tôi sử dụng là tiếng Đức nên các bạn chịu
khó so sánh và đọc hướng dẫn. Hình chỉ mang tính chất minh họa.
Trang 2 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Strong name (Định danh) là một dạng chữ ký kỹ thuật số. Nó cho phép chúng
ta “đánh dấu” một assembly sao cho assembly này là duy nhất.
• Một định danh cho assembly bao gồm có 5 phần:
o Một khóa chung: khóa chung của giải thuật RSA.
o Một tên đơn giản: là một chuỗi. Thông thường nó sẽ chứa tên của file
chứa assembly (không có phần mở rộng).
o Phiên bản: số phiên bản. Bao gồm 4 phần có dạng là
Major.Minor.Build.Revision
o Tùy chọn Culture (optional culture)
o Tùy chọn cấu trúc processor ( optional processor architectur)
• Cấu trúc của định danh được thể hiện thông qua hình sau
Version
Cấu trúc
processor,
Khóa chung,
Tên,
Culture
• Các bạn nên xem bài mã hóa RSA của rongchaua để hiểu thêm về chữ ký kỹ
thuật số cũng như cách kiểm tra một chữ ký kỹ thuật số để có được kiến thức
căn bản trước khi đọc tiếp các phần bên dưới. Nếu không các bạn sẽ cảm thấy
khó hiểu vì phần này khá rắc rối.
• Để quá trình định danh được chính xác, thông thường một assembly sẽ được
định danh trong quá trình xây dựng (build). Trong quá trình xây dựng này,
khóa riêng tương ứng với khóa chung ở trong định danh sẽ được sử dụng để
tạo ra chữ ký kỹ thuật số cho assembly (gọi là chữ ký định danh), và chữ ký
định danh này có thể được kiểm tra tính đúng đắn thông qua khóa chung ở
trong định danh.
• Có nhiều cách cũng như có nhiều kỹ thuật khác nhau để tạo một chữ ký định
danh cũng như để quản lý các khóa riêng dùng để ký này. Chúng ta sẽ làm
quen với kỹ thuật ký định danh trong các phần tiếp theo bên dưới.
• Để dễ hiểu chúng ta sẽ tìm hiểu cách thức hoạt động của chữ ký định danh
này.
• Ví dụ: khi một assembly A tham khảo một assembly B đã được định danh, thì
assembly A này sẽ có thông tin định danh từ assembly B (tức là có chữ ký
định danh khi build). Sau đó, nếu assembly A muốn khởi động assembly B,
Trang 3 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
.NET Framework sẽ nạp định danh của assembly B, kiểm tra thông tin về chữ
ký định danh (dùng khóa chung nằm trong định danh của assembly B để tính
ra chữ ký định danh). Nếu chữ ký định danh là hợp lệ (tức là chữ ký định danh
mà assembly A có phải giống chữ ký định danh .NET Framework vừa tính) thì
assembly B sẽ được load. Nếu không thì assembly B sẽ không được load.
Trang 4 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
Trang 5 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
ký được tạo ra khi build chương trình và kết quả là chúng ta không thể thực
thi chương trình này được nữa.
• Do đó bây giờ chúng ta nên tìm hiểu làm thế nào để tạo một chữ ký định danh
để có thể gỡ bỏ hoặc nhảy qua chữ ký định danh này.
Trang 6 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Ta gõ vào “sn -k strongname.snk”, nếu kết quả như hình dưới là ta đã tạo
được 1 cặp khóa thành công.
• Dùng Windows Explorer browse đến thư mục “…\SDK\v2.0\Bin” ta thấy xuất
hiện một file mới là strongname.snk.
• Bây giờ ta sẽ dùng định danh này để ký định danh một assembly.
• Các bạn có thể tự tạo cho mình một project bất kỳ để thực tập. Các bước dưới
đây chỉ mang tính hướng dẫn.
• Sau khi tạo được một Project. Chúng ta vào Menu Project -> Chọn Properties
như hình.
Trang 7 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Ta chọn Tab Signing, sau đó Browse đến file strongname.snk mà ta đã tạo ra.
• Ở đây chúng ta thấy rằng ngoài việc tạo strong name key file bằng console
chúng ta có thể tạo ngay trong Project bằng cách tại chỗ Sign the assembly,
chọn menu New và điền các thông số thích hợp. Sau khi nhấn Menu New hộp
thoại sau sẽ xuất hiện.
Trang 8 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Như trên đã nói việc bảo vệ khóa riêng rất là quan trọng cho nên ở đây ta
thấy rằng Microsoft Visual Studio .NET đã cho phép chúng ta một tùy chọn cài
đặt password cho key file nhằm tăng cường tính bảo mật cho cặp khóa này.
• Như vậy chúng ta thấy rằng có hai cách để tạo ra chữ ký định danh: console
và gui.
• Sau khi ký định danh xong, build lại chương trình. Và chúng ta thử thay đổi
bất cứ byte nào trong mã nguồn bằng một chương trình Hex Editor nào,
chúng ta đều sẽ gặp một thông báo lỗi như ban đầu đã đưa.
Trang 9 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Kéo xuống 1 chút ta sẽ thấy được thông tin của assembly SampleCrackme. Ở
đây ta thấy dạng khóa .publickeytoken của SampleCrackme khác biệt hơn
nhiều so với các assembly ở trên. Nó sử dụng khóa RSA để ký định dạng.
• Bây giờ chúng ta hãy disable chức năng kiểm tra strong name bằng cách đơn
giản là … xóa đoạn code đại diện cho định danh đi, tức là từ .publickey cho
đến hết .ver.
• Sau khi xóa chúng ta có hình như sau.
• Compile lại bằng ilasm, rồi chạy file vừa recompile, ta thấy chương trình chạy
tốt.
• Bây giờ chúng ta thực hiện lại các bước Remove Nag như ở bài III thì chương
trình sẽ chạy tốt và không còn bị crash nữa.
Trang 10 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
3.1 Ý tưởng
• Bây giờ chúng ta sẽ xem qua sự khác biệt giữa một assembly bị định danh và
một assembly không bị định danh dưới góc nhìn về thông tin của PE Header.
Sau đó chúng ta sẽ chỉnh sửa các khác biệt này để assembly trở nên giống
nhau, để đạt được mục đích là chúng ta sẽ xóa được chữ ký định danh.
• Đầu tiên chúng ta nên xem qua một chút về cấu trúc PE của một file .NET.
Trang 11 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Các thành phần của cấu trúc trên có ý nghĩa như sau:
o cb: Kích thước của cấu trúc.
o MajorRuntimeVersion và MinorRuntimeVersion: Phiên bản của CLR
Runtime.
o MetaData: Một thư mục dữ liệu (Data Directory) giữ thông tin về RVA và
kích thước của MetaData.
o Flags : Cờ, hỗ trợ các cờ sau:
Trang 12 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
o Resources: Thư mục dữ liệu cho Resources. MetaData sẽ tham khảo đến
các Resources này.
o StrongNameSignature: Thư mục dữ liệu cho chữ ký định danh. Section
này chỉ được sử dụng khi cờ COMIMAGE_FLAGS_STRONGNAMESIGNED
được set. Nó cũng ảnh hưởng đến một số vùng trong MetaData.
o CodeManagerTable: Lúc nào cũng bằng 0.
o VtableFixups: Một vài ngôn ngữ không tuân theo mô hình System
Runtime chung. Các ngôn ngữ vì vậy sẽ có một vài hàm ảo và các hàm
ảo này cần được liệt kê ở bảng v-table.
o ExportAddressTableJumps: lúc nào cũng bằng 0.
o ManagedNativeHeader: Lúc nào cũng bằng 0, chỉ tồn tại trong thế hệ
ASM.
• Bây giờ ta dùng tool CFF Explorer để mở 2 file SampleCrackme.exe và
SampleCrackmewithStrongname.exe để so sánh.
• Không định danh
• Có định danh
Trang 13 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
Trang 14 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Thư mục Assembly bao gồm một bảng. Bảng này chứa các thông tin về
o HashAlgId: Một hằng số 4 byte thể hiện cho giải thuật dùng để tạo Hash
cho Assembly.
o MajorVersion, Minor Version, BuildNumber, RevisionNumber: hằng số 2
bytes.
o Flags: Một cờ 4 bít.
o PublicKey: khác 0 khi và chỉ khi assembly bị ký định danh và afPublickey
được set
• Cờ có thể có các giá trị sau:
• Như vậy chúng ta đã thấy được sự khác biệt giữa một file bị ký định danh và
một file không bị ký định danh. Bây giờ chúng ta cần sửa đổi tất cả các giá trị
sao cho PE Header của 2 file là giống nhau.
• Đối với file SampleCrackmewithStrongName chúng ta cần phải thay đổi các
giá trị tại những offset như sau:
• Việc chỉnh sửa chúng ta có thể thực hiện bằng CFF Explorer. Click thẳng vào
các giá trị cần sửa, chỉnh sửa giá trị. Sau khi chỉnh sửa xong ta chọn Save As
dưới một tên khác.
Trang 15 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Thực hiện lại các bước Remove Nag như ở bài trước, ta thấy chúng ta có thể
patch mà không bị kiểm tra chữ ký định danh nữa.
Trang 16 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Ta thấy cách check của Crackme hiện tại đã khác hơn so với crackme trước.
Chương trình sẽ gọi method Check của lớp IsRegistered, method này thuộc
assembly Registration.dll. Click vào hàm Check để xem mã nguồn.
• Các kiểm tra khá đơn giản, serial chính là “rongchauawadeptrai”. Tuy nhiên
chúng ta thử patch xem sao.
• Dùng ILDASM để dump file Registration.dll.
• Tại dòng lệnh IL_000b, chúng ta sửa lại thành brtrue.s như hình
Trang 17 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Phải chăng file này bị ký định danh. Oki, dùng CFF Explorer mở file
Registration.dll lên chỉnh lại các thuộc tính như sau
Trang 18 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Lưu lại đè lên tập tin cũ bằng cách click Save. Chọn Yes trong hộp thoại sau:
Trang 19 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Các bước thay đổi giống như ở một assembly đơn. Bây giờ có một phần khác
biệt. Click vào AssemblyRef trong mục MetaData Tables. Chọn Registration,
ta sửa lại giá trị PublicKeyOrToken như hình bên dưới.
Trang 20 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Chọn Save và lưu đè lên file cũ. Bây giờ hãy chạy file và check.
• Như vậy là chúng ta đã hoàn thành việc xóa định danh từ các assembly phụ
thuộc. Tốn nhiều thời gian hơn như thực chất chỉ là xóa định danh của các
assembly đơn và mối quan hệ của chúng.
Trang 21 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Click chọn nút Patch nếu có kết quả sau đây là đúng.
Trang 22 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Kết quả cho chúng ta thấy thực chất chương trình cũng thực hiện những sửa
đổi giống như chúng ta.
• Để check chúng ta thực hiện các bước Remove Nag như ở bài 3. And it works.
6 Tổng kết
• Như vậy chúng ta đã tìm hiểu các cách để xóa chữ ký định danh. Có thể bằng
tay hay bằng tool nhưng quan trọng là chúng ta hiểu được phần nào cách hoạt
động của strong name.
• Có nhiều cách khác để xóa định danh nhưng tôi không đề cập ở đây vì thời
lượng có hạn và cũng không thật sự cần thiết. Vì thật sự trong thực tế việc sử
dụng Tool Strong Name Remove cũng đạt được gần như 100% mục đích.
Trang 23 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Signature là một DWORD chứa giá trị như sau: 0x50, 0x45, 0x00, 0x00. Giá
trị DWORD này đánh dấu phần bắt đầu định dạng của file trong windows.
• FileHeader có kiểu là IMAGE_FILE_HEADER có độ lớn 20 bytes chứa thông tin
về sơ đồ bố trí vật lý và những đặc tính của file.
• OptionalHeader có kiểu là IMAGE_OPTIONAL_HEADER32 có độ lớn 224 bytes.
• Dùng một HexEditor mở một file (thế hệ ASM) bất kỳ lên ta sẽ thấy như sau
• Ở đây chúng ta không đề cập đến phần FileHeader mà sẽ đi nhanh đến phần
ImportTable. Để hiểu rõ hơn các bạn nên đọc tài liệu về PE File Format của
Goppit hoặc bản dịch tiếng Việt của kienmanofwar (xem phần tham khảo bên
dưới).
• IMAGE_OPTIONAL_HEADER32 là kiểu của OptionalHeader có dạng như sau:
Trang 24 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
IMAGE_NUMBEROF_DIRECTORY_ENTRIES equ 16
…
DataDirectory IMAGE_DATA_DIRECTORY IMAGE_NUMBEROF_DIRECTORY_ENTRIES dup(<>)
• Lưu ý tại dòng lệnh khai báo của DataDirectory ta thấy, DataDirectory là một
mảng có độ lớn 16 có cấu trúc IMAGE_DATA_DIRECTORY.
• Các phần tử này được liệt kê bên dưới đây
Trang 25 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
o Virtual Address là địa chỉ ảo tương đối (RVA : Relative Virtaul Address)
của cấu trúc dữ liệu
o isize: chứa kích thước của cấu trúc dữ liệu.
• Dùng LordPE xem một file bất kỳ ta thấy được như sau
Trang 26 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
• Ta thấy ở đây 16 phần tử của mảng đã được liệt kê cùng với RVA và kích
thước của nó. Phần tử ImportTable cũng vậy. Tất cả đều có RVA và kích thước
như đã được định nghĩa trong cấu trúc IMAGE_DATA_DIRECTORY.
• Như vậy ta đã nắm được cấu trúc và ý nghĩa của ImportTable.
7.1.2 Ý nghĩa
• Xét về ý nghĩa thì Import Table là nơi tập trung các câu lệnh để import các
hàm từ các DLL.
• Khi viết một chương trình, chúng ta thông thường sử dụng các hàm có sẵn
trong các DLL của Windows hoặc tự tạo ra các DLL dùng chung. Khi chúng ta
sử dụng các hàm trong các DLL này thì các thông tin (vị trí, tên hàm) sẽ được
đưa vào Import Table. Như vậy khi chúng ta chạy chương trình thì dựa vào
Import Table, Loader sẽ tìm kiếm và nạp các hàm cần thiết vào trong bộ nhớ
để chương trình chúng ta có thể chạy được.
Trang 27 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
đó sẽ không còn đúng nữa. Trong tình huống này trình loader sẽ sử dụng các
thông tin trong .reloc section để sửa chữa lại các thông tin đã bị sai lệch.
• Trong trường hợp nếu mọi chuyện tốt đẹp, tức là trình loader có thể nạp
chương trình tại Base Address mà linker đã giả định trước đó thì các thông tin
trong .reloc section sẽ được bỏ qua.
• Ví dụ:
o Khi chúng ta biên dịch chương trình của chúng ta thì linker sẽ giả định
địa chỉ ánh xạ tại Base Address 0x400000.
o Khi chương trình chạy, tại offset 0x11CC là một con trỏ trỏ đến một
chuỗi “rongchauawadeptrai”.
o Chuỗi “rongchauawadeptrai” này được lưu tại offset là 0x303F.
o Như vậy con trỏ sẽ chứa giá trị là 0x40303F.
o Khi chương trình được thực thi ở máy của tôi, vì một lý do nào đó loader
của máy tôi quyết định rằng nó cần phải ánh xạ chương trình từ Base
Address 0x600000. Như vậy ta thấy rằng có một sự khác biệt giữa giả
định và thực tế về địa chỉ Base Address này.
o Độ khác biệt là ∆ = 0x600000 – 0x400000 = 0x200000
o Như vậy ta thấy rằng con trỏ hiện trỏ tới giá trị là 0x40303F sẽ không
còn đúng nữa vì hiện tại chuỗi được lưu tại địa chỉ là 0x60303F.
o Lúc này, để giải quyết vấn đề trên thì loader sẽ tự động cộng thêm đoạn
khác biệt trên cho giá trị của con trỏ. Tức là giá trị của con trỏ sẽ là
0x40303F + 0x200000 = 0x60303F.
• Những mục trong .reloc section gọi là Base relocations bởi vì những mục này
dựa trên địa chỉ Base Address đã được linker giả định. Base relocations là một
list của những địa chỉ (offset) của dữ liệu và những đoạn mã. Mỗi một mục
Base relocation được đóng gói thành một chuỗi của nhiều đoạn có chiều dài
khác nhau. Mỗi đoạn này sẽ mô tả relocation cho một trang 4KB bộ nhớ ánh
xạ.
Trang 28 của 29
Bài lưu trữ về Reverse .NET Software III 1.0.2.9 Rongchaua
9 Lời kết
• Tôi viết bài lưu trữ này nhằm lưu lại một chút kiến thức mà tôi có được trong
quá trình reverse phần mềm. Bài lưu trữ này chỉ mang tính tham khảo và tôi
không có ý định viết nó như một tài liệu tham khảo thật sự. Vì vậy trong một
số mục tôi chỉ nêu lên những ý chính thật cần thiết và dĩ nhiên sẽ còn nhiều
thiếu sót. Tôi hi vọng các bạn sẽ thông cảm cho những thiếu sót của tôi.
• Do những suy nghĩ trên mang đầy tính chủ quan vì vậy nếu có những sai sót
xin các bạn vui long liên hệ với tôi để tôi kịp thời sửa chữa.
• Bài lưu trữ này được viết như một tài liệu tham khảo cho các anh, em ở REA vì
vậy tôi xin tặng bài viết này cho anh, em trong REA.
• Bài viết ở trên chỉ mang tính học tập, tôi không chịu trách nhiệm khi các bạn
sử dụng các kiến thức ở trên vào việc của các bạn.
Trang 29 của 29