Kĩ thuật Internal Keygen[
I. Lời giới thiệu :
Nếu như các bạn đã từng đọc qua loạt tut về Olly của ARTEAM thì chắc chắn sẽ bắt gặp cụm từ “Internal Keygen” . Trong một số tài liệu khác cụm từ này có thể xuất hiện dưới các tên khác là “Keygen Injection” hay “Code Injection”. Vậy cụm từ này có nghĩa là gì ?
Thực chất thì “Internal Keygen” là một kĩ thuật giúp Cracker lợi dụng chính chương trình mà họ muốn crack , biến chương trình trở thành một Keygen. Nói như vậy vẫn có vẻ hơi mơ hồ và xa lạ !!
Như các bạn đã biết , trong quá trình crack soft mỗi User Name nhập vào thì chương trình mà chúng ta crack sẽ lại sinh ra một số Serial khác nhau ứng với User Name đó. Do đó, nếu như Serial mà chúng ta tìm được là chính xác thì việc đăng kí diễn ra hoàn toàn bình thường. Nhưng do mỗi Serial là khác nhau với mỗi User Name , do đó nếu như có một người nào đó muốn sử dụng chương trình thì bản thân họ phải tự tìm lấy Serial tương ứng với User Name của họ nhập vào. Điều này là rất bất tiện cho những người chẳng biết gì về Crack.
Khi bạn là một Cracker, thì tôi tin rằng các bạn cũng đã biết Keygen là cái gì và làm thế nào để có một Keygen. Keygen thường áp dụng cho các chương trình sử dụng cơ chế bảo vệ Name/Serial. Đối với các Cracker thì việc Keygen hoàn chỉnh được một soft đỏi hỏi họ phải biết phân tích thuật toán mà coder sử dụng để cho ra Serial (đôi khi cũng phải đoán xem ý đồ của coder, nhắm xem coder định làm gì để chặn đầu).Nhưng để phân tích và code ra một Keygen sẽ phải tốn khá nhiều thời gian và công sức, vì mỗi chương trình sẽ có những cơ chế tính toán khác nhau từ dễ đến khó để làm nản lòng các Cracker. Do đó, kĩ thuật “Internal Keygen” ra đời và được các Cracker sử dụng để tiết kiệm thời gian và công sức nhưng vẫn đem lại hiệu quả nhất định. Họ sẽ dùng kĩ thuật này để giải quyết bài toán với mỗi User Name sẽ có một Serial (tương đương với việc code một Keygen) bằng cách lợi dụng quá trình tính toán của chương trình để biến chương trình trở thành một Keygen.
Như đã nói ở trên, Cracker sẽ lợi dụng chương trình để biến nó thành Keygen ! Vậy họ sẽ lợi dụng cái gì ? Và làm thế nào để lợi dụng ?
Trong quá trình đăng kí sử dụng hợp pháp một chương trình , thì theo thường lệ chương trình sẽ yêu cầu chúng ta nhập User Name và Serial vào các text box . Khi chúng ta nhấn Register / OK thì có nghĩa là chúng ta muốn chương trình sẽ chấp nhận cho phép chúng ta đăng kí với những gì chúng ta đã nhập vào. Nếu như những gì chúng ta nhập vào là đúng thì một Message Box sẽ hiện ra thông báo đại loại như “Thank You” or “Successful” thông báo cho chúng ta biết là chương trình đồng ý với những gì chúng ta nhập vào và dĩ nhiên chúng ta đã trở thành người dùng hợp pháp : ). Nhưng trong trường hợp ngược lại , khi những gì chúng ta nhập vào là sai, thì lẽ thường tình đã có “Thank you” thì chắc chắn sẽ có một Message Box khác làm công việc ngược lại là thông báo “ Wrong Code” or “ Invalid Serial” bắn ra , báo cho ta biết đừng có mà cố gắng nữa làm gì . Càng cố càng sai thôi!! : ). Vậy cái mà Cracker lợi dụng ở đây chính là cái Message Box thông báo khi chúng ta nhập sai đó, thay vì việc nó Pop up ra thông báo “Wrong Code” or “Invalid Serial” thì Cracker sẽ cho chương trình Pop up ra cái Real Serial của chương trình sau quá trình tính toán. Mà cái Real Serial này dùng để làm gì tiếp theo chì chắc chắn không cần nói thì ai cũng biết phải làm gì .
Vậy để lợi dụng được nhược điểm này, không còn một cách nào khác là Cracker phải dùng một chương trình Debugger để Debug chương trình . Họ sẽ tìm xem chương trình sẽ sinh ra Serial ở đâu và lưu vào vị trí nào trong bộ nhớ. Song song với quá trình này thì họ cũng phải biết cái hàm Message Box thông báo sai nằm ở đâu. Khi đã có được 2 điều kiện cần ở trên , họ sẽ tiến hành sửa code để cho chương trình sẽ không bắn ra thông báo sai mà sẽ bắn ra cái Real Serial mà lẽ ra phải nhập vào tương ứng với User Name chứ không phải là một Fake Serial nào đó mà chúng ta nhập vào …
Để dễ hình dung hơn, các bạn hãy quan sát một đoạn code đơn giản sau đây :
Original code:
CMP EAX, EBX ; EAX=our serial | EBX=correct serial
JNZ WrongCode ; Not the same? Then display "Wrong Code"
.... ; This is where the "Thank You" stuff is.
....
WrongCode:
.. ; Shoot Nag “Wrong Code”
Code after change:
CMP EAX, EBX ; EAX=our serial | EBX=correct serial
JNZ WrongCode ; Not the same? Then run the built-in keygen.
.. ; This is where the "Thank You" stuff is.
..
.. ; All the other code of the program.
..
WrongCode: ; We place our keygen at a convenient location.
.. ;
.. ; Push Right serial
Call xxxx ; Display the RIGHT serial.
... ; Continue the program Normal
...
Như các bạn đã thấy trên đây , mọi việc diễn ra rất đơn giản không có gì là phức tạp cả. Vậy tóm lại để có được một “Internal Keygen” chúng ta sẽ phải trải qua các bước sau đây :
1. Chúng ta phải biết được Real Serial được tạo ra ở đâu và được lưu vào vị trí nào trong bộ nhớ.
2. Chúng ta phải biết vị trí của hàm Message Box bắn ra thông báo sai ở đâu.
3. Cuối cùng chúng ta phải chỉnh sửa hàm Message Box thế nào khiến cho nó hiện ra Real Serial thay vì hiện ra thông báo sai.
Oki , tổng quát về kĩ thuật “Internal Keygen” là như thế, không có gì là “cao siêu” cả. Bước tiếp theo trong bài viết này tôi sẽ hướng dẫn các bạn một làm một ví dụ nho nhỏ để các bạn hiểu rõ hơn về kĩ thuật này.
II. Thực hành :
Trong phần giới thiệu ở trên, tôi đã chỉ cho các bạn các bước cơ bản nhất để tiến hành áp dụng kĩ thuật “Internal Keygen”. Trong phần tiếp theo này, tôi sẽ cùng với các bạn làm một ví dụ nho nhỏ để áp dụng kĩ thuật này. Một phần là để thay đổi không khí, một phần là để các bạn có cái nhìn trực quan hơn về cách thực hiện cũng như hiểu rõ thêm về các bước phải làm. Oki, chúng ta bắt đầu nhé!.
Ví dụ mà tôi sẽ sử dụng sau đây chính là file Wallpaper.exe (Down load here : http://www.reaonline.net/forum/showthread.php?t=884) đã được đề cập trong tut “Phân tích ASM và Code Keygen”(Link to this tut : http://www.reaonline.net/forum/showthread.php?t=921). Oki, chúng ta sẽ tiến hành phân tích chương trình này.
Đầu tiên chúng ta chạy thử chương trình, ngay lập tức chương trình sẽ hiện ra một hộp thoại “Wallpaper Registration” yêu cầu chúng ta nhập User Name và Serial vào. Chúng ta chưa có gì trong tay cả nên cứ việc nhập đại vào hai text box đó ( Vd : kienmanowar & 11111982 ). Sau đó nhấn OK, khi chúng ta nhấn vào nút này thì ngay lập tức chương trình sẽ tính toán lại Serial dựa trên User Name mà chúng ta đưa vào , sau đó so sánh Serial mà nó tính toán được với cái Serial mà chúng ta nhập vào (quá trình này xảy ra rất nhanh). Nếu trùng thì Ok , còn không nó sẽ Pop up ra thông báo sau :
Như những gì tôi đã nói với các bạn ở trên về kĩ thuật “Internal Keygen”, chúng ta sẽ biến chương trình này thành một Keygen để thay vì việc nó hiện ra cái thông báo sai như các bạn nhìn thấy ở trên, nó sẽ phải hiện ra cái Serial thật mà nó tạo ra cho chúng ta thấy. Oki , mục đích và ý tưởng là như thế , tiếp theo chúng ta sẽ hiện thực hóa ý tưởng của chúng ta.
Đầu tiên mở Olly lên , load file Wallpaper.exe vào Olly, việc tìm ra điểm đặt BP của chương trình này đã được tôi nói tới trong tut “Phân tích ASM và Code Keygen” rồi , các bạn có thể xem lại hoặc tự làm. Việc tìm ra điểm đặt BP của soft này hết sức dễ dàng. Oki, khi có được BP, nhấn F9 để run chương trình, tiến hành nhập thông tin đăng kí gồm FU & FS và nhấn Ok . Olly sẽ Ice tại điểm mà chúng ta đặt BP. Tiến hành Trace(F8) chúng ta sẽ có như sau :
00404A35 . 8B3B MOV EDI, DWORD PTR DS:[EBX] ; <== Fake User
00404A37 . B9 FFFFFFFF MOV ECX, -1
00404A3C . 2BC0 SUB EAX, EAX
00404A3E . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
00404A40 . F7D1 NOT ECX
00404A42 . 49 DEC ECX ; <== Length(FU)
00404A43 . 0F84 08010000 JE Wallpape.00404B51 ; <== If Length(FU) == 0 then Jump to Nag
Tiếp tục :
00404A49 . 8B7E 5C MOV EDI, DWORD PTR DS:[ESI+5C] ; <== Fake Serial
00404A4C . B9 FFFFFFFF MOV ECX, -1
00404A51 . 2BC0 SUB EAX, EAX
00404A53 . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
00404A55 . F7D1 NOT ECX
00404A57 . 49 DEC ECX ; <== Length(FS)
00404A58 . 0F84 F3000000 JE Wallpape.00404B51 ; <== If Length(FS)==0 then Jump to Nag
Oki, do chúng ta đã nhập đầy đủ các thông số mà chương trình yêu cầu , nên chúng ta đã vượt qua được đoạn code này. Tiếp theo chúng ta sẽ đến một đoạn code rất quan trọng , đó chính là đoạn code tạo ra Real Serial của chương trình :
00404A5E . 6A 00 PUSH 0 ; /Arg1 = 00000000
00404A60 . 8BCB MOV ECX, EBX ; |
00404A62 . E8 24D40200 CALL Wallpape.00431E8B ; \Wallpape.00431E8B
00404A67 . 50 PUSH EAX ; /Arg1
00404A68 . 8BCE MOV ECX, ESI ; |
00404A6A . E8 21010000 CALL Wallpape.00404B90 ; \Wallpape.00404B90 ;<==(Calculation)
Do đặc thù của kĩ thuật Internal Keygen cho nên chúng ta không cần phải biết và không cần quan tâm tới giải thuật hay thuật toán mà chương trình dùng để tính toán ra Real Serial, mà chúng ta chỉ cần biết vị trí của hàm tính toán ra Real Serial mà thôi. Như vậy , theo yêu cầu này thì chúng ta đã tìm ra được vị trí của hàm này rồi đó, chính là ở 00404A6A. Nhấn F8 tiếp tục cho tới hàm này và Trace qua hàm này. Sau khi Trace qua hàm này thì ngay lập tức chúng ta sẽ nhìn thấy Real Serial hiện ra trong cửa sổ Registers :
Cụ thể ở đây , chúng ta sẽ thấy Real Serial mà chương trình sinh ra sau hàm CALL ở 00404A6A được lưu vào thanh ghi EAX, cụ thể là tại địa chỉ 008E1210. Right Click lên thanh ghi EAX và chọn Follow In Dump chúng ta có được như sau :
Khà khà …Như vậy bước đầu tiên trong 3 bước của kĩ thuật “Internal Keygen” đã được chúng ta thực hiện xong. Bước thứ 2 là chúng ta phải tìm ra chỗ của hàm Message Box “Invalid Key” ở đâu ? Để thực hiện được điều này, chúng ta nhìn xuống dưới đoạn code tính toán Serial :
00404A6A . E8 21010000 CALL Wallpape.00404B90 ; \Wallpape.00404B90 ;<==(Calculation)
chúng ta sẽ thấy như sau :
00404A97 > \85C0 TEST EAX, EAX
00404A99 . 0F85 B2000000 JNZ Wallpape.00404B51
Click chuột vào hàm JNZ này , là lần theo hướng mũi tên mà nó chỉ chúng ta sẽ tới được vị trí mà chúng ta cần tìm. (Thực ra khi các bạn đi tìm điểm đặt BP thì các bạn cũng đã phải thông qua bước tìm thông báo này rồi) :
00404B5A . 68 09040000 PUSH 409
00404B5F . 68 00000400 PUSH 40000
00404B64 68 B8024400 PUSH Wallpape.004402B8 ; ASCII "ERROR"
00404B69 68 C4044400 PUSH Wallpape.004404C4 ; ASCII "Invalid key"
00404B6E > 6A 00 PUSH 0 ; |hOwner = NULL
00404B70 . FF15 84994400 CALL NEAR DWORD PTR DS:[<&USER32.>; \MessageBoxExA
Vậy là bước thứ 2 trong cũng đã được thực hiện xong một cách rất dễ dàng . Tiếp theo tôi muốn nói với bạn một chút về hàm MessageBox:
int MessageBox(
HWND hWnd, // handle of owner window
LPCTSTR lpText, // address of text in message box
LPCTSTR lpCaption, // address of title of message box
UINT uType // style of message box
);
Hàm MessageBox là một hàm nội tại của Windows. Điều này có nghĩa là , khi bạn là người lập trình , bạn viết một chương trình và thay vì việc bạn phải tự thân vận động để ngồi code ra một MessageBox của riêng chúng ta thì chúng ta có thể dùng hàm MessageBox sẵn có của Windows . Hàm MessageBox này sẽ tạo , hiển thị và thi hành một message box. Hàm MessageBox sẽ được gọi giống như bất cứ một hàm nào , và để sử dụng được hàm này thì điều đầu tiên chúng ta cần phải truyền biến cho nó hay còn gọi là đối số. Các đối số này đã được liệt kê như các bạn đã thấy ở trên. Việc tìm hiểu thêm về việc làm thế nào một MessageBox được tạo ra sẽ giúp cho chúng ta có những hiểu biết cơ bản để vận dụng nó vào công việc. (Để biết thêm chi tiết về hàm này các bạn có thể tham khảo trong tài liệu MSDN hoặc trong file win32.hlp ).
Như trên đã nói , chúng ta vừa trải qua hai bước : bước thứ nhất là tìm vị trí của hàm tạo ra Serial và vị trí của Serial được lưu tại thanh ghi EAX, bước thứ 2 là tìm ra vị trí của hàm MessageBox thông báo sai. Công việc tiếp theo và cũng quan trọng không kém 2 bước trước là bước thứ 3 : Edit code.
Như các bạn thấy, trong hàm MessageBox ở trên các đối số sẽ lần lượt được truyền vào theo cơ chế của Stack . Tức là đối số nào ở vị trí đầu tiên thì sẽ được truyền vào cuối cùng để khi lời gọi hàm MessageBox xuất hiện thì các đối số này sẽ được lấy ra lần lượt theo thứ tự ngược lại. Và trong ví dụ trên các bạn sẽ quan sát rất rõ điều này thông qua các lệnh Push. Để có cái nhìn thực tế hơn nữa các bạn có thể Trace để tới đoạn code bắt đầu của quá trình truyền đối số cho hàm MessageBox, trong cửa sổ Stack Window các bạn sẽ thấy như sau :
Khà khà…. các bạn có thấy gì không , khi chúng ta nhập thông tin đăng kí vào. Chương trình tiến hành tính toán và sẽ kiểm tra Serial ta nhập vào với Serial mà nó tính toán. Do chúng ta nhập Serial sai, nên sau vài bước kiểm tra chương trình sẽ Jump tới đoạn code để Pop up ra thông báo như chúng ta thấy . Các đối số được đưa vào ở đây cho phép chúng ta hiểu được có những thông tin như sau :
Tiêu đề của hộp thoại là : “ERROR”
Dòng text sẽ hiển thị trên hộp thoại là : “Invalid key”
v…v..
Vậy chúng ta sẽ phải làm gì ? Việc chúng ta phải làm là ép hàm MessageBox này thay vì nó sẽ hiện ra thông báo “Invalid key” thì ta buộc nó phải hiện Real Serial. Chúng ta đã biết địa chỉ của hàm tính toán Serial là tại 00404A6A và khi Trace qua hàm này ta nhận được Real Serial nắm ở thanh ghi EAX . Ta cũng đã biết được điểm bắt đầu của hàm MessageBox là ở địa chỉ 00404B5A. Vậy ta sẽ sửa câu lệnh ngay phía dưới của hàm tính toán để cho chương trình sẽ nhảy tới điểm bắt đầu của hàm MessageBox. Do đó tại câu lệnh :
00404A6F 8B56 5C MOV EDX, DWORD PTR DS:[ESI+5C] ; <== Fake Serial
chúng ta nhấn Space hoặc Right Click và chọn Assemble. Olly sẽ hiện ra hộp thoại Assemble cho phép chúng ta Edit lại đoạn code. Chúng ta sẽ thay lệnh trên bằng lệnh nhảy tới điểm bắt đầu của hàm MessageBox như sau, trong hộp thoại chúng ta gõ :
JMP 00404B5A
nhấn Enter , màn hình Olly sẽ hiện như sau :
Nhấn F8 để thực hiện lệnh này , nó sẽ nhảy tới điểm bắt đầu của hàm MessageBox. Để ý rằng lúc này giá trị Real Serial vẫn nằm tại thanh ghi EAX. Tiếp theo chúng ta sẽ thay đổi câu lệnh Push mà đẩy dòng text “Invalid Key” thành câu lệnh Push đẩy giá trị Real Serial. Do đó tại dòng :
00404B69 68 C4044400 PUSH Wallpape.004404C4 ; ASCII "Invalid key"
Chúng cũng thao tác tương tự và sửa nó thành :
00404B69 50 PUSH EAX
Nhấn Enter, màn hình Olly sẽ hiện như sau :
Nhấn F8 để Trace đến hàm gọi MessageBox, quan sát cửa sổ Stack các bạn sẽ thấy như sau :
Ke..Ke.. Nhìn vào đây các bạn có thể biết được khi chúng ta Trace qua hàm MessageBox thì nó sẽ hiển thị cho chúng ta cái gì rồi phải không. Đó chính là thứ mà từ đầu đến giờ chúng ta đã phải tốn nhiều giấy mực để thực hiện. Thật đáng đồng tiền bát gạo !!
Cuối cùng một công việc không thể thiếu đó là chúng ta hãy lưu lại tất cả những gì chúng ta vừa mới thực hiện . Ngay tai màn hình Olly , Right Click vào một vị trí bất kì trên màn hình Code Window và chọn Copy to Executable –> All modifications. Một hộp thọai hiện ra , ta chọn Copy All. Một màn hình mới xuất hiện , tại màn hình này chúng ta Right Click và chọn Save file. Đặt một cái tên bất kì mà chúng ta muốn và nhấn Save. Vậy là chúng ta đã có được một Internal Keygen rồi đó , đem phân phát cho mọi người thôi. : )
PS : Tại sao lại phải lưu vào , là vì trong trường hợp file chúng ta crack và save lại có kích thước nhỏ thì việc phát tán nó cho người khác rất dễ dàng. Nhưng nếu như file đó có dung lượng lớn thì chúng ta sẽ dùng file gốc và file đã được chỉnh sửa này để tạo ra một Patch file có kích thước nhỏ hơn để phân phát cho User.
III. Tổng kết :
Qua tất cả những gì tôi vừa trình bày ở trên , các bạn đã hiểu được phần nào kĩ thuật Internal Keygen là gì? Thực chất nó là kĩ thuật cho phép Cracker không phải ngồi lọ mọ nghiền ngẫm thuật toán để code ra một Keygen hoàn chỉnh , nó cho phép Cracker lợi dụng chính hàm MessageBox thông báo sai của chương trình , biến hàm này thành một hàm phục vụ cho việc hiển thị Real Serial mà chương trình đã tính toán ra. Mà để thực hiện được điều đó thì chúng ta phải biết Real Serial nằm ở đâu và hàm gọi thông báo sai nằm ở đâu để mà áp dụng kĩ thuật này một cách hợp lý và hiệu quả nhất.
Hi vọng với những gì cơ bản nhất mà tôi đã trình bày ở trên sẽ giúp ích cho các bạn phần nào trên con đường trở thành Craker
23/04/2005
-== kienmanowar ==-
– Thank to my family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina, QHQCrker, the_Lighthouse, Hoadongnoi, Nini … all REA‘s members, HacNho, RongChauA, Deux, tlandn, dqtln, Arteam …. all my friend, and YOU. : )