1. Trang 1
Reverse Engineering Passion Team – Team REPT
Tạo 1 loader cho một chương trình .NET
Tác giả: Levis/ Team REPT
Ngày viết: Dec 05 2013 – Ngày dịch Aug 7 2014
Trang chủ của REPT: http://team-rept.com Blog cá nhân: http://ltops9.wordpress.com
LỜI MỞ ĐẦU
Xin chào các bạn,
Mấy tuần nay tôi bị cắt mạng, cho nên không thể duyệt web, chơi game giải trí, tán gấu với bạn bè (và
tất nhiên là cả với cô bé đang yêu của tôi nữa, haha). Trong mấy cái ngày tẻ nhạt này, tôi đảnh phải giết
thời gian bằng cách tìm hiểu, nghiên cứu thêm vè .NET Reversing. Tất nhiên là cũng không học gì được
nhiều lắm, bởi vì trình độ của tôi còn khá kém. Thế nhưng tôi nghĩ rằng sẽ vui hơn 1 chút khi viết một cái
gì đó, và tôi đã tạo ra bài viết này. Có thể là những gì tôi trình bày trong đây không quá mới mẻ, tuy
nhiên tôi hi vọng rằng nó sẽ có ích cho một vài người . Và rất xin lỗi vì trình độ tiếng Anh kém cỏi của
tôi.
Trong bài viết này, tôi sẽ chỉ cho các bạn cách để tạo ra một loader cho .NET crackme do tôi viết ra. Về
khái niệm loader, tôi nghĩ rằng các bạn đã viết rồi. Đối với các chương trình native (không viết bằng
.NET, thì loader khá là phổ biến Nhưng trong .NET, có thể người ta biết đến nó, nhưng không ai sử dụng
cả (tôi nghĩ là như vậy). Với 1 native app, chúng ta có rất nhiều công cụ có thể sử dụng để tạo ra 1
loader, ví dụ như dUP hay uPPP,… và rất nhiều các công cụ khác nữa. Tất cả các công cụ này đều rất dễ
sử dụng, và phù hợp với tất cả mọi người, kể cả những người mới và những cao thủ.Trong .NET, cấu trúc
file thực thi cũng khác, và chúng ta không có những công cụ tốt như dUP, vì vậy chúng ta cần phải tử tạo
ra loader. Việc lập trình ra 1 loader trong .NET không quá khó bởi vì chúng ta có 1 .NET Framework khá
mạnh mẽ, chỉ cần một chút thời gian bỏ ra và chúng ta sẽ đạt được mục đích
OK hãy bắt đầu cuộc hành trình!
Những gì chúng ta cần:
- IDA + Hex Editor. Để xem, phân tích và chỉnh sửa code
- A .NET IDE: MonoDevelop, Visual Studio, hoặc SharpDevelop hoặc công cụ nào bạn muốn. Tôi sử
dụng SharpDevelop trong bài viết này
- Một chút kiến thức về lập trình .NET . Bạn có thể sử dụng C# hay VB.NET đều được. Trong bài
viết này tôi sử dụng C#
- Và bộ não của bạn nữa, luôn là công cụ quan trong nhất.
2. Trang 2
PHÂN TÍCH FILE VÀ PATCH THỬ
File thực hành ở đây là 1 crackme nhỏ do tôi viết bằng VB.NET, bạn có thể tìm thấy ở link tải về ở ngay
dưới bài viết này của tôi trong blog. Mở lên và xem thử chương trình xem sao:
Khi tôi thử điền tên tôi vào vầ bấm vào nút “Register me”, label ở bên dưới hiện ra 1 bad boy và chuyển
thành màu đỏ. Vì bài viết này hướng đến việc tạo 1 loader, cho nên tôi không sử dụng
packer/obfuscator cho crackme này. Bây giờ ta sẽ load crackme này vào trong IDA:
3. Trang 3
Đợi 1 chút, cho đến khi IDA load file thành công, nhìn vào khung bên trái của IDA:
Có 1 method với tên là “RegbtnClick’. Method này sẽ được thực thi khi chúng ta bấm vào nút “Register
me”. Ta sẽ thử phân tích code của method này và tìm xem có thể patch vào chỗ nào: Bấm vào method
nó và IDA hiện ra như sau (dạng Graph view):
Như trong anh này, bạn có thể nhìn thấy string của badboy, và toàn bộ cấu trúc của code hiển thị rất
trực quan.Nhìn sang bên phải 1 chút bạn sẽ thấy như sau::
4. Trang 4
Ta có thể nhìn thấy string của goodboy, và ở phía trên là đoạn code kiểm tra, lấy giá trị từ một biết tên là
MyRegStatus (type Boolean), then if MyRegStatus is true (brtrue.s), the program will show Goodboy
message. Vậy nên ta có thể patch từ brtrue.s thành brfalse.s để vượt qua đoạn kiểm tra này.
Tôi đã khoanh vùng 1 con số ở trong ảnh trên (0x00000B31. Đây chính là offset address của code
brtrue.s. Bây giờ ta có thể patch crackme này bằng cách tìm đến offset ở trong file và đổi bytecode. Có
rất nhiều hex editor bạn có thể dung, trong bài viết này tôi sẽ sử dụng XVI để thực hiện việc patch này.
Mở crackme trong XVI và tìm đến offset cần patch (0x00000B31).
5. Trang 5
Chọn Gôt từ Menu, hoặc đơn giản bạn chỉ cần bấm Ctrl+G.
Một cửa sổ mới hiện ra, bạn chọn như thế này:
Chọn “Hexadecimal”, và điền vào offset address ( đừng xóa kí tự ‘$” ở đầu),Bấm OK và chúng ta đến chỗ
này:
6. Trang 6
Chính xác những gì chúng ta tần. bytecode của “brtrue.s” là 0x2D, và “brfalse.s” là 0x2C. vậy nên chúng
ta sẽ đổi từ 0x2D thành 0x2C.
Thế là đã patch xong, bây giờ tôi sẽ save lại thành 1 file mới và kiểm tra xem việc patch của chúng ta có
hiệu quả hay không:
Lưu lại dưới tên “patched.exe” và mở file này:
Thế là phương pháp patch của chúng ta hoạt động tốt rồi, bây giờ sẽ tiến hành tạo loader trong C#..
7. Trang 7
TẠO LOADER
Loader sẽ load chương trình vào và lưu trong 1 mảng các byte, sau đõ sẽ tiến hành patch tại địa chỉ
0x00000B31 và tiến hành invoked method Main() để khởi chạy chương trình trực tiếp từ trong memory
Mở SharpDevelop (hay IDE mà bạn dùng), tạo 1 C# Console Project:
Bây giờ thì viết code vào:
File Program.cs
8. Trang 8
using System;
using System.Reflection; //Sử dụng namespace Assembly
using System.IO; //Sử dụng namespace File
namespace loader_ex
{
class Program
{
public static string InttoHex(byte mybyte)
{
return "0x" + Convert.ToString(mybyte,16).ToUpper(); //Chuyển số nguyên
thành Hex String với tiền tố "0x"
}
public static void Main(string[] args)
{
byte[] tobe_loaded = File.ReadAllBytes("crackme2.exe"); //Đọc và lưu
chương trình cần tạo loader vào 1 byte array.
if(tobe_loaded != null) // Nếu việc đọc file thành công
{
Console.WriteLine("file loaded! the value at ofset 0x00000B31 is "
+ InttoHex(tobe_loaded[0xB31])); //Đưa thông báo ra màn hình về address sẽ patch
tobe_loaded[0xB31] = 0x2C; //Tiến hành patch, Thay đổi từ 0x2D
thành 0x2C (brtrue.s thành brfalse.s tại offset 0xB31;
Console.WriteLine("Now the value at offset 0x00000B31 is " +
InttoHex(tobe_loaded[0xB31]) + ", starting process..."); //đưa giá trị đã được patch ra màn hình
Assembly patched = Assembly.Load(tobe_loaded);
//Tạo 1 Assembly stream dựa trên byte array đã được patch
try
{
Object[] param = new object[1] { new string[0]}; //Tạo
parameter để invoke method main()
patched.EntryPoint.Invoke(null, param);
//invoke main() method của assembly stream
Console.WriteLine("Process Ended...");
//Khi chương trình thoát ra, hiện thông báo
}
catch(Exception ex)
//exception handler
{
Console.WriteLine("Error: " + ex.Message.ToString());
// Đưa thông báo nếu như gặp exception
9. Trang 9
}
}
else //Nếu không thể load được file
{
Console.WriteLine("Target not fount!"); //Đưa thông
báo lỗi
}
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
//Đợi người dùng bấm phím để thoát khỏ chương trình
}
}
}
Tôi đã chú thích ở những dòng quan trong.
Sau đó compile chương trình
Sauk hi compile thành công, bạn cần phải copy crackme vào thư mục chưa loader vừa mới compile xong:
10. Trang 10
Trong ví dụ của tôi là /bin/Release nằm trong thư mục chứa project của tôi. Bây giờ sẽ chạy loader:
Thế là xong, loader hoạt động rất ổn :D..
Với loader bạn có thể làm nhiều thứ hơn là chỉ patch chương trình 1 cách đơn thuần, hãy tự mình tìm
kiếm và áp dụng cho bản thân bạn.Tôi chưa thử với các chương trình bị pack hay obfuscate, Bạn có thể
thử xem sao. Rất đơn giản và vui phải không?
Thế là đã xong, cảm ơn vì đã đọc, xin chào và hẹn gặp lại các bạn trong những bài viết tiếp theo
Dec 05 2013
Levis/Team REPT