0day in {REA_TEAM}

Kĩ thuật Internal Keygen_Ví dụ 2 March 9, 2009

Filed under: Keygen Tutorials, Kĩ thuật Internal Keygen_Ví dụ 2 — kienmanowar @ 2:33 am

b. Ví dụ 2 :

Phần tiếp theo , chúng ta sẽ làm thêm một ví dụ nữa. Ở ví dụ này chúng ta sẽ thực hành trên một crackme. Cách thức thực hiện trên crackme cũng hoàn toàn tương tự như khi chúng ta thực hiện đối với Software ở trên. Oki, chúng ta bắt đầu : ).
Chạy thử Crackme, tiến hành nhập thông tin và nhấn nút “Check It!”. Chằng thấy có Nag nào bắn ra cả.

ex1

Nhấn nút “Give Up!” để exit .Mở Ollydbg lên và load crackme vào (crackme này được code bằng Microsoft Visual C++ 6.0).
Sau khi load xong , dùng chức năng Search For \ All referenced text strings để tìm kiếm thông tin. Chúng ta có được kết quả như sau :

ex2

Double Click tại 00401639 chúng ta sẽ quay trở lại màn hình chính của Ollydbg. Dịch lên một chút , ta đặt BP tại 004015BC. Nhấn F9 để Run , tiến hành nhập lại Fake Information. Sau đó nhấn “Check It!”, Ollydbg sẽ Ice tại điểm đặt BP. Nhấn F8 để Trace, chúng ta sẽ có như sau :

ex3

Như mọi người nhìn thấy thì Crackme này sẽ tiến hành một số quá trình kiểm tra như sau : Độ dài của UserName mà chúng ta nhập vào phải thỏa mãn điều kiện là 5 < Length(FakeUser) < 20. Bên cạnh đó thì chiều dài của FakeSerial mà chúng ta nhập vào cũng phải bằng với chiều dài của FakeUser. Nếu như chúng ta nhập đúng các thông tin thỏa mãn tất cả các điều kiện trên thì chúng ta sẽ vượt qua được quá trình check này. Sau đoạn check ở trên chúng ta sẽ gặp một vòng lặp tính toán ra Real Serial của Crackme . Cụ thể như sau :

ex4

Do đặc thù của kĩ thuật Internal Keygen như đã nói ở trên , ở đây ta không cần quan tâm đến quá trình tính toán Serial như thế nào. Ta chỉ cần biết rằng đây chính là vòng lặp dùng cho việc tính ra Real Serial và giá trị trong thanh ghi AL tại địa chỉ 00401629 chính là giá trị RealSerial sau mỗi quá trình tính toán của vòng lặp . Vòng lặp này có số lần lặp phụ thuộc vào chiều dài của chuỗi UserName mà chúng ta nhập vào.
Nhưng mọi người để ý rằng, ngay tại lần lặp đầu tiên giá trị thứ nhất của RealSerial sẽ được tính toán , sau đó giá trị này được lưu vào thanh ghi AL. Tiếp theo , tại địa chỉ 00401629 là quá trình so sánh kí tự đầu tiên trong chuỗi Fake Serial mà chúng ta nhập vào với giá trị Real Serial lưu trong thanh ghi AL. Nếu 2 giá trị này khác nhau thì ngay lập tức sẽ có một lệnh nhảy thoát ra khỏi vòng lặp tính toán. Vậy tức là nếu như ngay từ đầu kết quả so sánh này đã sai thì chúng ta luôn bị out khỏi vòng lặp và sẽ không thể biết hểt được giá trị tiếp theo sẽ sinh ra của chuỗi Real Serial. Đây là điều mà chúng ta không muốn! Vậy hướng giải quyết ở đây là thế nào?

Để ý rằng dưới câu lệnh :

00401629 . 38040A CMP BYTE PTR DS:[EDX+ECX], AL ; <== FakeSerial[i] = Temp ?

là một lệnh nhảy làm cho chúng ta out ra khỏi vòng lặp tính toán :

0040162C . /75 1C JNZ SHORT Rith_Cra.0040164A ; <== If not, Jump to Bad boy

nhưng chúng ta thấy rằng, chuỗi FakeSerial của chúng ta được đưa vào thanh ghi EDX. Mà giá trị trong BYTE PTR DS:[EDX+ECX] chính là kí tự đầu tiên của chuỗi Fake Serial(lúc đầu ECX = 0). Quan sát thấy , ngay dưới lệnh nhảy ở trên là lệnh :

0040162E . 41 INC ECX ; <== i ++

Vậy ta có thể kết luận một điều rất quan trọng như sau : Nếu như giá trị trong BYTE PTR DS:[EDX+ECX] = AL (tức là giá trị đầu tiên của chuỗi FakeSerial mà chúng ta nhập vào bằng với giá trị RealSerial của quá trình tính toán) thì chúng ta sẽ không bị out khỏi vòng lặp tại lệnh nhảy , do đó giá trị ECX sẽ tăng lên để trỏ tới vị trí tiếp theo trong chuỗi FakeSerial. Vậy thì ngay tại chỗ này , chúng ta nảy ra một ý tưởng là , chúng ta sẽ dùng chính chuỗi FakeSerial này để lưu chuỗi Serial của quá trình tính toán.

Để thực hiện được điều này chúng ta chỉ việc thay đổi câu lệnh so sánh tại 00401629. Tại địa chỉ này, nhấn Space để mở cửa sổ Assemble , chúng ta edit lại như sau :

ex6

Tiếp theo chúng ta sẽ NOP câu lệnh nhảy tại 0040162C. Ta sẽ có được như sau :

ex7

Oki , tiến hành Run thử và Dump tại thanh ghi EDX , chúng ta sẽ có được kết quả mà chúng ta mong muốn . Vậy là qua bước thứ nhất tìm ra nơi tính toán RealSerial và nơi lưu trữ giá trị RealSerial :

ex8

Bước tiếp theo chúng ta sẽ cho hiện cái RealSerial này thông qua cái MessageBox. Công việc này hết sức đơn giản. Chúng ta chỉ việc trỏ tới vị trí của dòng :

0040163E 68 20304000 PUSH Rith_Cra.00403020 ; ASCII "Well done cracker!"

sau đó nhấn Space và sửa thành :

PUSH EDX

Cuối cùng chúng ta Save thành quả của chúng ta thành một file exe. Chạy file này lên, nhập thông tin vào nhớ là chiều dài UserName phải bằng với chiều dài Serial nhập vào : ). Chúng ta sẽ có được kết quả như sau :

ex10

Vậy là thành công rồi !!!

Best Regards
_[Kienmanowar]_

–++–==[ Greatz Thanks To ]==–++–
My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina, QHQCrker,
the_Lighthouse, Merc, Hoadongnoi, Nini … all REA‘s members, TQN, HacNho, RongChauA,
Deux, tlandn, light.phoenix, dqtln, ARTEAM …. all my friend, and YOU.

–++–==[ Thanks To ]==–++–
iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl v..v..

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially haggar),
Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on crackmes.de, thank
to all members of unpack.cn (especially fly and linhanshi). Great thanks to lena151(I like
your tutorials). And finally, thanks to RICARDO NARVAJA and all members on
CRACKSLATINOS.

>>>> If you have any suggestions, comments or corrections email me: kienmanowar[at]reaonline.net

 

Kĩ thuật Internal Keygen March 7, 2009

Filed under: Keygen Tutorials, Kĩ thuật Internal Keygen, My Tutorials — kienmanowar @ 3:33 am

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 :



kg1

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 :

kg2

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 :

kg3

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 :

kg4

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 :

kg5

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 :

kg7

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 :

kg8

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 !!

kg9

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
smilie

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. : )

 

Phân tích ASM và code Keygen March 7, 2009

Filed under: Keygen Tutorials, My Tutorials, Phân tích ASM và code Keygen — kienmanowar @ 3:13 am
Tags:

Phân tích ASM và code Keygen

Lời nói đầu :

Sau khi có được cái Keygen Form như trong bài viết trước đã hướng dẫn xây dựng. Trong bài viết tiếp theo này chúng ta sẽ tiến hành việc phân tích ASM của một soft để từ đó tiến hành công việc code keygen :”đầy gian nan nhưng cũng vô cùng thú vị” . Trong bài viết này, chúng ta sẽ sử dụng soft Wallpaper v1.2 mà chú đèn đã viết trong box Newbie (http://www.reaonline.net/forum/showthread.php?t=884) để phục vụ cho việc Keygen. Bài viết này sẽ đối chiếu từng đoạn code tương ứng được nói trong bài viết của chú đèn để mọi người tiện theo dõi. Oki , giờ chúng ta bắt tay vào làm việc.

1. Phân tích ASM của soft trong Ollydbg :

- Để có thể phân tích được ASM của một soft chúng ta cần một chương trình Debug mà cụ thể ở đây là Ollydbg. Chúng ta mở Olly lên và load file Wallpaper.exe vào trong Olly. Tìm và set BP như trong bài viết của chú đèn đã nói. Sau khi đã có được điểm đặt BP tại 00404A35 , chúng ta Run chương trình bằng cách nhấn F9. Tiếp theo chúng tiến hành công việc nhập FU và FS vào trong màn hình Register của chương trình. Ở đây mình nhập như sau : FU : kienmanowar và FS : 11111982. Sau đó nhấn OK , chúng ta sẽ Ice tại điểm mà chúng ta đã set BP. Bước tiếp theo đây sẽ liên quan chặt chẽ tới bài của chú đèn. Chúng ta chú ý tới đoạn code sau :


00404A35 . 8B3B MOV EDI,DWORD PTR DS:[EBX] ; <== FU
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

/* Đoạn code này sẽ kiểm tra xem chúng ta có nhập Username không, nếu như không nhập (tức là Length = 0) thì sẽ nhảy tới Nag */

- Đoạn code tiếp theo :

00404A49 . 8B7E 5C MOV EDI,DWORD PTR DS:[ESI+5C] ; <== FS
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

/* Cũng tương tự đoạn code trên , đoạn này dùng để kiểm tra xem chúng ta có nhập Serial vào không */

- Oki , chúng ta đã nhập FU và FS vào rùi nên chúng ta sẽ vượt qua được hai đoạn kiểm tra này. Chúng ta sẽ đến một đoạn code hết sức quan trọng . Đó chính là đoạn Calculation :

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(trace into)

- Sau khi Trace Into vào trong hàm trên chúng ta sẽ găp một đoạn code như sau :


00404B90 /$ 83EC 2C SUB ESP,2C
00404B93 |. C74424 00 050>MOV DWORD PTR SS:[ESP],5 ; <== Default1 = 5
00404B9B |. C74424 04 030>MOV DWORD PTR SS:[ESP+4],3 ; <== Default2 = 3
00404BA3 |. C74424 08 070>MOV DWORD PTR SS:[ESP+8],7 ; <== Default3 = 7
00404BAB |. C74424 0C 010>MOV DWORD PTR SS:[ESP+C],1 ; <== Default4 = 1
00404BB3 |. 53 PUSH EBX
00404BB4 |. 56 PUSH ESI
00404BB5 |. 57 PUSH EDI
00404BB6 |. BB 88583422 MOV EBX,22345888 ; <== Temp = 0x22345888
00404BBB |. C74424 20 020>MOV DWORD PTR SS:[ESP+20],2 ; <== Default5 = 2
00404BC3 |. C74424 24 060>MOV DWORD PTR SS:[ESP+24],6 ; <== Default6 = 6
00404BCB |. 55 PUSH EBP
00404BCC |. 6A 09 PUSH 9
00404BCE |. C74424 30 040>MOV DWORD PTR SS:[ESP+30],4 ; <== Default7 = 4
00404BD6 |. 33ED XOR EBP,EBP ; <== i = 0
00404BD8 |. 896C24 24 MOV DWORD PTR SS:[ESP+24],EBP ; <== Default8 = 0

/* Chúng ta thấy rằng đây chính là một quá trình khởi tạo giá trị ban đầu sẽ sử dụng để tính toán về sau. Việc đầu tiên nó sẽ khởi tạo các giá trị mặc định là 5 , 3, 7, 1, 0, 2, 6, 4 vào trong một mảng. Để cho tiện chúng ta sẽ gọi mảng chứa những phần tử này là reaDefault [COLOR=Red](int reaDefault[9] = {0×5, 0×3, 0×7, 0×1, 0×0, 0×2, 0×6, 0×4}; ). Tiếp theo chúng ta sẽ thấy chương trình khởi tạo một giá trị khác là 0×22345888 được cất giữ trong thanh ghi EBX , vậy chúng ta gọi một biến là Temp sẽ chứa giá trị này (unsigned long int Temp = 0×22345888smilie . Cuối cùng chúng ta để ý thấy có một lệnh XOR EBP, EBP , lệnh này làm cho giá trị của thanh ghi EBP = 0×0, cho nên ta khai báo một biến i và khởi gán là 0 (i = 0) . Việc tại sao lại đặt tên biến là i sẽ nói ngay dưới đây thôi */[/COLOR]

- Sau khi trace qua đoạn code này, chúng ta sẽ đến một đoạn code tiếp theo:

00404BE1 |. 8B5424 44 MOV EDX,DWORD PTR SS:[ESP+44] ; <== FU
00404BE5 |. 83C4 04 ADD ESP,4
00404BE8 |. 8BF0 MOV ESI,EAX
00404BEA |. 8BFA MOV EDI,EDX ; <== FU
00404BEC |. B9 FFFFFFFF MOV ECX,-1
00404BF1 |. 2BC0 SUB EAX,EAX
00404BF3 |. F2:AE REPNE SCAS BYTE PTR ES:[EDI]
00404BF5 |. F7D1 NOT ECX
00404BF7 |. 49 DEC ECX ; <== Length (FU)
00404BF8 |. 74 1A JE SHORT Wallpape.00404C14

/* Đoạn code này chỉ là việc tính toán lại chiều dài của chuỗi FU mà chúng nhập vào , Length(FU) này sẽ được sử dụng trong quá trình lặp để tính toán tiếp phía dưới */

- Qua đoạn tính toán Length ở trên chúng ta sẽ đến đoạn code tính toán như sau :

00404BFA |> /45 /INC EBP ; <== i = i + 1
00404BFB |. |8BFA |MOV EDI,EDX ; <== FU
00404BFD |. |0FBE442A FF |MOVSX EAX,BYTE PTR DS:[EDX+EBP-1] ; <== FU[i]
00404C02 |. |03D8 |ADD EBX,EAX ; <== Temp = Temp + Fu[i]
00404C04 |. |B9 FFFFFFFF |MOV ECX,-1
00404C09 |. |2BC0 |SUB EAX,EAX
00404C0B |. |F2:AE |REPNE SCAS BYTE PTR ES:[EDI]
00404C0D |. |F7D1 |NOT ECX
00404C0F |. |49 |DEC ECX ; <== Length (FU)
00404C10 |. |3BCD |CMP ECX,EBP ; <== While (Length(FU) > i)
00404C12 |.^\77 E6 \JA SHORT Wallpape.00404BFA ; <== Continue Loop

/* Tại đoạn code trên, chúng ta quan sát thấy quá trình tăng dần của thanh ghi EBP , sau đó giá trị này sẽ được đem đi so sánh với với chiều dài của FU đã đựơc cất trong ECX trong đoạn code tính Length ở trên.Đó chính là lí do tại sao chúng ta lại khai báo một biến [COLOR=Red]i . Vòng lặp này sẽ thực hiện công việc như sau , nó sẽ lấy từng kí tự trong FU sau đó thực hiện một phép cộng dồn với biến Temp (Biến Temp lúc này đang lưu giá trị là 0×22345888). Vòng lặp này sẽ thực hiện bao nhiêu lần là tùy thuộc vào vào chiều dài của chuỗi FU. Kết quả sau khi tính toán được sẽ được biến Temp lưu giữ */

Trong VC++ vòng lặp tính toán cộng dồn trên được viết như sau :

//Caculation
i = 0;
while ( i < LenUser )
{
Temp = Temp + (reaName[i] & 0xFF);
i++;
}

- Sau khi qua khỏi vòng lăp này chúng ta sẽ đến đoạn code sau :


00404C18 |. 53 PUSH EBX ; <== Temp
00404C19 |. 68 D0044400 PUSH Wallpape.004404D0 ; ASCII "%08X"
00404C1E |. 50 PUSH EAX
00404C1F |. E8 AC6B0100 CALL Wallpape.0041B7D0 ; <== TempString = Convert(Temp) to String

/* Đoạn code trên đây làm công việc chuyển đổi giá trị chứa trong biến Temp . Cụ thể là nó sẽ chuyển giá trị trong biến Temp sang chuỗi ở dạng Hexa như định dạng mà nó đã đưa ra trong lệnh [COLOR=Red]PUSH (ASCII “%08X”) . Ví dụ như sau : với chuỗi FU là kienmanowar , sau vòng lặp cộng dồn chúng ta có được biến Temp chứa giá trị sau : 0×22345D24 , sau quá trình chuyển đổi này ta sẽ có một chuỗi là “22345D24″. Chuỗi này chúng ta lưu trữ trong một biến là TempString (char reaTempString[64] = {0}; ) */

Đoạn code chuyển đổi được viết lại trong VC++ như sau :
//Convert Temp value to Hex String
wsprintf(reaTempString, "%08X",Temp);

- Trace tiếp chúng ta sẽ đến đoạn code dưới đây :


00404C27 |. 33C0 XOR EAX,EAX ; <== i = 0
00404C29 |> 8B4C84 10 /MOV ECX,DWORD PTR SS:[ESP+EAX*4+10]; <== j = Default [i]
00404C2D |. 40 |INC EAX ; <== i = i + 1
00404C2E |. 83F8 08 |CMP EAX,8
00404C31 |. 8A4C0C 30 |MOV CL,BYTE PTR SS:[ESP+ECX+30] ; <== TempString[j]
00404C35 |. 884C06 FF |MOV BYTE PTR DS:[ESI+EAX-1],CL ; <== reaTempSerial[i] = TempString[j]
00404C39 |.^ 72 EE \JB SHORT Wallpape.00404C29

/* Trong đoạn code trên chúng ta nhận thấy lại có quá trình tăng dần của EAX cho nên ta lại khởi gán biến i = 0 . Vòng lặp này làm nhiệm vụ như sau, nó sẽ lấy các giá trị trong biến reaTempString theo những vị trị đã được khai báo trong biến reaDefault. Mà để lấy được các giá trị trong biến reaDefault chúng cần một biến j . Do đó ta khai báo thêm một biến j . Vòng lặp này sẽ được thực hiện [COLOR=Red]8 lần , để cho ra một chuỗi chứa trong reaTempSerial , mà thực chất chuỗi này chỉ là xáo trộn các vị trí trong reaTempString mà thôi. Thực ra sau quá trình này thì reaTempSerial chính là Real Serial , nhưng để dễ hiểu ta cứ gọi là reaTempSerial */

Đoạn code tương ứng được viết lại trong VC++ :

//Creat reaTempSerial
i = 0;
while (i < 8)
{
j = reaDefault[i];
reaTempSerial[i] = reaTempString[j];
i++;
}

- Cuối cùng sau khi chúng ta qua khỏi vòng lặp này chúng ta sẽ đi đến đích cuối cùng :


00404C3B |. 8BC6 MOV EAX,ESI ; <== Right Serial

/* Chúng ta sẽ thấy được Right Serial ngay tại câu lệnh trên */

Đoạn code tương ứng trong VC++ :

wsprintf(reaSerial,reaTempSerial);

2. Code Keygen trong VC++ :

Dựa vào tất cả những gì đã phân tích rất chi tiết ở trên , chúng ta chỉ việc ghép lại để có một đoạn code Keygen hoàn chỉnh như sau :


void CKEYGENDlg::OnGenerate()
{
// TODO: Add your control notification handler code here

char reaName[64]={0};
char reaSerial[64]={0};
char reaTempString[64] = {0};
char reaTempSerial[64] = {0};

unsigned long int Temp = 0×22345888;
int reaDefault[9] = {0×5, 0×3, 0×7, 0×1, 0×0, 0×2, 0×6, 0×4};
int i=0,j=0, LenUser=0;

LenUser=GetDlgItemText(IDC_NAME,reaName,128);
if (LenUser < 1 || LenUser > 64)
{
MessageBox(” ———-===== Your name atleast 1 chart =====———- \n\n———-===== But not over than 64 charts =====———- “,”Hey !! Please input your name again !! “);
}
else
{

// Calculation
i = 0;
while ( i < LenUser )
{
Temp = Temp + (reaName[i] & 0xFF);
i++;
}

//Convert Temp value to Hex String
wsprintf(reaTempString, “%08X”,Temp);

//Creat reaTempSerial
i = 0;
while (i < 8)
{
j = reaDefault[i];
reaTempSerial[i] = reaTempString[j];
i++;
}

wsprintf(reaSerial,reaTempSerial);
}

SetDlgItemText(IDC_SERIAL,reaSerial);

}

Trên đây một trong số các cách thức để một cracker thực hiện công việc code keygen . Sau khi bạn đọc xong bài viết này , bạn có cảm thấy dễ dàng hơn không? smilie . Thực sự Keygen nhiều lúc không đơn giản , nó đòi hỏi cả một nghệ thuật để làm sao đoạn code ngắn gọn , trong sáng nhất. Trong 4room này thì anh Moon là người có khả năng đó (và còn nhiều người khác nữa trong đội ngũ BQT của REA :wub: ). Em chỉ là Super Newbie học đòi theo anh Moon mà thôi. Hi vọng với bài viết với tinh thần truyền tải những gì hết sức basic như trên , các bạn sẽ định hình được phần nào công việc code Keygen của mình.

03/03/2005

Best Regards

kienmanowar

 

Đưa ảnh vào Keygen Fomr March 7, 2009

Filed under: Keygen Tutorials, My Tutorials, Đưa ảnh vào Keygen Form — kienmanowar @ 2:57 am

..::[Cách đưa một file ảnh vào trong Keygen Form]::..

===========================================

_\\|//_

(‘ * * ‘)

_____________________________ooO_(_)_Ooo_____________________________

_”Đồ nghề” mà chúng ta cần phải chuẩn bị là 1 form cần đưa ảnh vào và một ảnh bất kì dạng .bmp.

_Giả sử chúng ta có một Keygen Form như sau (Bác nào chưa biết cách tạo thì đọc bài viết cũ của tôi) :

_Ngày trước mới theo sư phụ Moon tập tọe code Keygen , hiii cũng muốn làm cho cái Keygen của mình đẹp bằng anh bằng em nhưng khổ nỗi lúc đó trình độ có hạn, có muốn cũng chẳng được. Sau mấy buổi học Coding online cùng sư phụ cuối cùng thì cũng tạo được form và code được keygen cho một em. Hic lúc đó có được cái form , cộng thêm vừa viết được keygen cho soft là đã thấy “phê” lắm rồi. Cứ thế là crack + code hùng hục như trâu :) , chẳng để ý gì đến cái “Interface” của Keygen. Hic nhân tiện có chú Merc hỏi cách đưa ảnh vào Form như thế nào, về nhà lục lọi lại “em yêu” ngày xưa. Hic trông em tàn tạ quá :) , đành lôi ra vọc thử xem để đưa cái ảnh vào cho nó hoành tráng.

_Hic như các bác đã nhìn thấy dung nhan của “em yêu” ở trên thì thấy không còn hợp thời nữa rùi. Cần chỉnh sửa “nhan sắc” lại một chút. Bây giờ tôi muốn thay thế cái Label : Reversing Engineering Association thành một bức ảnh mang phong cách của REA thì làm thế nào? Hii có lời giải đáp ngay đây thôi, chẳng có gì là cao siêu cả , đọc xong các bác lại nói tôi cần gì phải viết lách cho nó dài dòng :) .

_Oki để có thể đưa ảnh vào trong Form , ta làm như sau: đầu tiên chúng ta xóa cái Label mà chúng ta muốn thay thế đi.Chuyển qua ResourceView, tại đây chúng ta sẽ Import một file ảnh dạng bimap vào trong Resource. Đế có thể Import được các bạn làm như hình minh họa dưới đây :

………

Download toàn bộ bài viết tại đây :

http://kienmanowar.files.wordpress.com/2009/03/import_image_into_keygen_form.doc

Best Regards

kienmanowar

 

Xây dựng Keygen Form trong VC++ March 7, 2009

Xây dựng Keygen Form trong VC++

Lời nói đầu :

Bài viết này không nhắm tới mục đích ép buộc mọi người phải tạo dựng một Form theo chuẩn mà chỉ cung cấp những kiến thức tối thiểu……hiii chỉ là tối thiểu thôi nhé (basic) để Newbie mới tiếp cận với VC++ có thể dễ dàng xây dựng một Form dùng cho việc học code keygen sau này. Lý do tại sao em lại viết bài viết này , đó là vì muốn chia sẻ những kiến thức mà em biết được . Cũng giống như các bác Newbie bây giờ thôi, lần đầu tiên khi tiếp xúc với VC++ thấy rất khó khăn nhưng nhờ có sự giúp đỡ của anh Moon cộng với “mưa dầm thấm lâu” nên cái đầu ngu muội của tôi cũng mở mang ra chút ít. Hi vọng với bài viết này sẽ giúp cho các bác phần nào trong việc học VC++

1. Tạo dựng vùng làm việc (Project WorkSpace) :

Nếu như các bác đã từng lập trình trên một ngôn ngữ nào đó thì điều đầu tiên cần phải làm là tạo dựng một dự án hay một không gian làm việc. Đối với VC++ cũng vậy , mọi ứng dụng trên VC++ muốn phát triển phải có một dự án (project).Một không gian làm việc trong VC++ là nơi bao gồm các thư mục lưu trữ mã nguồn của ứng dụng , cũng như các file cấu hình v..v.. Để tạo một project chúng ta làm như sau :

Chọn File > New để mở cửa sổ New Wizards tương tự như hình minh họa dưới đây :

vc1

Tại đây, trong Projects tab chọn kiểu Project mà chúng ta muốn phát triển . Do như đã nói ở phần tiêu đề trên , ở đây chúng ta chọn kiểu Projects là MFC AppWizard(exe) . Trong textbox Project name chúng ta nhập vào là Keygen . Mặc định Project này sẽ được lưu theo đường dẫn sau : E:\Program Files\Microsoft Visual Studio\MyProjects\. Nếu muốn có thể hoàn toàn đổi thư mục lưu trữ Project. Sau khi hoàn tất công việc này nhấn OK để chuyển sang bước tiếp theo.

Oki sau khi nhấn OK , một màn hình khác sẽ hiện ra đó chính là MFC Wizards . Màn hình này sẽ cung cấp cho chúng ta những lựa chọn theo từng Step với những câu hỏi lựa chọn , qua đó chúng ta chọn kiểu ứng dụng mà chúng ta sẽ xây dựng , các đặc điểm cũng như những chức năng mà chúng ta cần. Quá trình này bao gồm 6 Step như sau :

a. Step 1 cho phép chúng ta chọn kiểu ứng dụng mà chúng ta muốn xây dựng . Cụ thể ở đây ta chọn là Dialog Based. Language để mặc định là English (United States). Sau đó nhấn Next .

b. Step 2 cho phép chúng ta chọn các Features cho ứng dụng . Tại bước này chúng ta uncheck ô ActiveX Controls . Còn Tile của Dialog cứ để nguyên hoặc nhập gì tùy thích , không quan trọng.

c. Step 3 , do chúng ta chọn kiểu Project là MFC cho nên ở bước này style của project mặc định là MFC Standard . Nếu bạn muốn tạo các file chú thích thì có thể chọn Yes còn không thì chọn No tùy mọi người. Còn trong phần Library chúng ta nên chọn ô As a statically linked library. Sau đó nhấn Next.

d. Step 4 cho chúng ta biết sẽ tạo các Class cho ứng dụng của chúng ta. Nhấn Finish để hoàn tất

e. Một màn hình mới hiện lên thông báo cho chúng ta biết về thông tin của Project .


vc2

f. Nhấn OK , Form của ứng dụng sẽ xuất hiện như hình minh họa dưới đây :


vc3

Oki , như các bác thấy việc xây dựng Project rất đơn giản và trực quan. Thông qua một sổ Step chúng ta đã có một Project dùng cho công việc Keygen rồi .

2. Thiết kế giao diện :

Trước tiên , chúng ta xóa bỏ cái Label : TODO… trên form đi. Thậm chí xóa bỏ 2 nút OK và Cancel đi . Chúng ta sẽ xây dựng lại từ đầu .
Để đổi tên cho form , ta click chuột phải trên form chọn Properties , trong phần Caption này chúng ta sẽ gõ vào tên bất kì mà bạn muốn chẳng hạn tên soft và version của soft mà chúng ta định Keygen.
Sau đó chúng ta sẽ đưa các điều khiển lên Form , tương tự như hình minh họa dưới đây :


vc4

Object Property Setting
Static Text ID IDC_STATIC
Caption REVERSE ENGINEERING ASSOCIATION

Static Text ID IDC_STATIC
Caption ------==Copyright (C) 2004 - REA - cRaCkErTeAm ==------

Static Text ID IDC_STATIC
Caption Name :

Static Text ID IDC_STATIC
Caption Serial :

Edit Box ID IDC_NAME

Edit Box ID IDC_SERIAL

Button ID IDC_GENERATE
Caption ---==Generate==---

Button ID IDC_REA
Caption ---==REA==---

Button ID IDC_EXIT
Caption ---==Exit==---

Cách thêm các điều khiển vào Form hết sức dễ dàng và đơn giản nhờ vào thanh Control của VC++ .


vc5

Ngoài ra sau khi thêm các điều khiển vào Form , các bạn có thể tùy biến các thuộc tính của các điều khiển như canh lề cho đoạn text gõ vào text box hoặc chọn các kiểu Styles cho điều khiển . Việc này được thực hiện thông qua việc Click chuột phải vào điều khiển và chọn Properties. Cài này xin nhường cho các bạn tự khám phá.

Trên đây chỉ là những gì cơ bản nhất trong quá trình làm việc với VC++ mà thôi. Nếu muốn tìm hiểu kĩ hơn các bạn nên tìm đọc quyển VC++ 21days để có được những kiến thức cơ bản và đầy đủ hơn.

Have Fun ! :D

 

PE Tutorials March 7, 2009

Filed under: My Tutorials, OllyDbg Tutorials, PE Tutorials — kienmanowar @ 2:31 am
Tags:

PE (Portable Executable) là định dạng file riêng của Win32. Tất cả các file thực thi được trên Win32 (ngoại trừ các tập tin VxDs và các file Dlls 16bit) đều sử dụng định dạng PE. Các file Dlls 32bit, các file COMs, các điều khiển OCX, các chương trình ứng dụng nhỏ trong Control Pannel (.CPL files) và các ứng dụng .NET tất cả đều sử dụng định dạng PE. Thậm chí các chương trình điều khiển kernel mode của các hệ điều hành NT cũng sử dụng định dạng PE.

Bài viết này đã được tôi dịch và biên soạn lại tut về PE file Format do tác giả Goppit bên ARTEAM release, nó đã được public trên REA khá lâu, nay tôi muốn chia sẻ nó cho mọi người. Theo tôi đánh giá sau khi tìm hiểu xong thì đây là một tut rất cần thiết cho những ai muốn nghiên cứu về Cracking, Reverse Engineering và Manual Unpacking , tài liệu này dày 75 trang , bao gồm các kiến thức cơ bản cũng như chuyên sâu về PE file, Packer, Loader, cách add code v..v.. mặc dù đã rất cố gắng để thực hiện nhưng trong quá trình làm không thể không tránh khỏi sai sót , mong mọi người bỏ quá cho smilie .

Link Download :

http://rapidshare.com/files/15293633/PE_Tutorials.rar

or here (change to rar file):

pe_tutorials.rar

Pass to unrar : REA-cRaCkErTeAm

—————————————————–

–++–==[ Greatz Thanks To ]==–++–
My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina, QHQCrker,
the_Lighthouse, Merc, Hoadongnoi, Nini … all REA‘s members, TQN, HacNho, RongChauA,
Deux, tlandn, light.phoenix, dqtln, ARTEAM …. all my friend, and YOU.

–++–==[ Thanks To ]==–++–
iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl v..v..

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially haggar),
Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on crackmes.de, thank to
all members of unpack.cn (especially fly and linhanshi). Great thanks to lena151(I like your tutorials).
And finally, thanks to RICARDO NARVAJA and all members on CRACKSLATINOS.

>>>> If you have any suggestions, comments or corrections email me: kienmanowar[at]reaonline.net

 

Solution for Zart’s mishka tribute September 22, 2008

Filed under: My Tutorials, Solution for Zart's mishka tribute — kienmanowar @ 2:11 am

One of my first keygenme’s in a long time. Was made to let newbies have a chance at getting into keygenning and hopefully lead into harder and harder ones.

make a keygen, do whatever you need to for this, just submit solution and keygen

serial fishing should be extremely easy, but then again – that wasn’t the point was it?

Difficulty: 1 – Very easy, for newbies
Platform: Windows
Language: C/C++

Download keygenme : http://www.crackmes.de/users/zart/mishka_tribute

————–
Solution :
///////////////////////////////////////////////////////////////////////////////////////////
Program : Zart’s Keygenme
Description : make a keygen, do whatever you need to for this, just submit solution and keygen.
Tools : IDA, OllyDbg
Difficult : Easy
Packer/Protector/Compiler : N/A
Objective : Keygen
Cracker : kienmanowar{REATEAM}
///////////////////////////////////////////////////////////////////////////////////////////

1. First, run this keygenme, wow i here the nice tune :) . Input Name and Serial then press Enter, blah blah the crackme disappear.Without Nag :(

2. Load to Olly and search all Ref text strings…..nothing special. Okie, fire up IDA,anaylize this keygenme and open Strings (Shift-F12). I found the Good Boy :D

.data:00407028 szSerialcheckedout-nowrightakeygen_ db 0Ah ; DATA XREF: _main+15Ao_main
.data:00407028 db 'Serial checked out - now right a keygen.',0Ah,0

3.Double click to _main+15Ao we will back to the asm code.

.text:00401246 push offset szSerialcheckedout-nowrightakeygen_ ; "\nSerial checked out - now right a keyge"...
.text:0040124B jmp short loc_401252 ; Jump
.text:0040124B
.text:0040124D ; ---------------------------------------------------------------------------
.text:0040124D
.text:0040124D loc_40124D: ; CODE XREF: _main+158j
.text:0040124D push offset szSerialfailedcheck ; "\nSerial failed check!\n"
.text:0040124D

4. Ok reload this keygenme in Olly and press Ctrl+G to go to 0×00401246.Scroll up and set BP at the beginning of this sub.

004010EC >/$ B8 69414000 MOV EAX, ; _main <== set BP here
004010F1 |. E8 DA2E0000 CALL
004010F6 |. 83EC 24 SUB ESP, 24
004010F9 |. 53 PUSH EBX

5. Press F9 to run and we stop at the BP, trace down until we reach the asm code that gets characters from UserName and Serial. In this asm code,
i relize that it gets each char from Username, append char and store it in another buffer.Here it is :

0040119A >|> /FF15 9C604000 /CALL NEAR DWORD PTR DS:[] ; [loc_40119A
004011A0 |. |85C0 |TEST EAX, EAX
004011A2 |.^ 74 F6 |JE SHORT
004011A4 |. |FF15 98604000 |CALL NEAR DWORD PTR DS:[] ; [_getch
004011AA |. |837D E4 00 |CMP DWORD PTR SS:[EBP-1C], 0
004011AE |. |8845 E8 |MOV BYTE PTR SS:[EBP-18], AL
004011B1 |. |75 5E |JNZ SHORT
004011B3 |. |3C 0D |CMP AL, 0D
004011B5 |. |75 33 |JNZ SHORT
004011B7 |. |837D EC 00 |CMP DWORD PTR SS:[EBP-14], 0
004011BB |. |75 0F |JNZ SHORT
004011BD |. |8B0D 10604000 |MOV ECX, DWORD PTR DS:[] ; MSVCIRT.cout
004011C3 |. |68 60704000 |PUSH keygenme.00407060 ; ASCII 0A,"You must enter a name!\n Name: "
004011C8 |. |FFD6 |CALL NEAR ESI
004011CA |.^ EB CE |JMP SHORT
004011CC >|> |8B0D 10604000 |MOV ECX, DWORD PTR DS:[] ; loc_4011CC
004011D2 |. |68 54704000 |PUSH keygenme.00407054 ; ASCII "Serial: "
004011D7 |. |C745 E4 01000000 |MOV DWORD PTR SS:[EBP-1C], 1
004011DE |. |FFD6 |CALL NEAR ESI
004011E0 |. |50 |PUSH EAX
004011E1 |. |FF15 18604000 |CALL NEAR DWORD PTR DS:[] ; MSVCIRT.flush
004011E7 |. |59 |POP ECX
004011E8 |.^ EB B0 |JMP SHORT
004011EA >|> |FF75 E8 |PUSH DWORD PTR SS:[EBP-18] ; loc_4011EA
004011ED |. |8B0D 10604000 |MOV ECX, DWORD PTR DS:[] ; MSVCIRT.cout
004011F3 |. |FFD7 |CALL NEAR EDI
004011F5 |. |50 |PUSH EAX
004011F6 |. |FF15 18604000 |CALL NEAR DWORD PTR DS:[] ; MSVCIRT.flush
004011FC |. |59 |POP ECX
004011FD |. |FF75 E8 |PUSH DWORD PTR SS:[EBP-18]
00401200 |. |8D4D D0 |LEA ECX, DWORD PTR SS:[EBP-30]
00401203 |. |FF75 EC |PUSH DWORD PTR SS:[EBP-14]
00401206 |. |FF15 24604000 |CALL NEAR DWORD PTR DS:[<&MSVCP60.std::basic_string; MSVCP60.std::basic_string<char,std::char_traits,std::allocator >::append
0040120C |. |FF45 EC |INC DWORD PTR SS:[EBP-14]
0040120F |.^ EB 89 |JMP SHORT
00401211 >|> |3C 0D |CMP AL, 0D ; loc_401211
00401213 |. |74 23 |JE SHORT
00401215 |. |FF75 E8 |PUSH DWORD PTR SS:[EBP-18]
00401218 |. |8B0D 10604000 |MOV ECX, DWORD PTR DS:[] ; MSVCIRT.cout
0040121E |. |FFD7 |CALL NEAR EDI
00401220 |. |50 |PUSH EAX
00401221 |. |FF15 18604000 |CALL NEAR DWORD PTR DS:[] ; MSVCIRT.flush
00401227 |. |59 |POP ECX
00401228 |. |8D049B |LEA EAX, DWORD PTR DS:[EBX+EBX*4]
0040122B |. |0FBE4D E8 |MOVSX ECX, BYTE PTR SS:[EBP-18]
0040122F |. |8D5C41 D0 |LEA EBX, DWORD PTR DS:[ECX+EAX*2-30]
00401233 |.^\E9 62FFFFFF \JMP

analyze and build the pseudocode in IDA :

while ( TRUE )
{
while ( TRUE )
{
while ( !kbhit() )
;
iKeyInput = getch();
LOBYTE(iTempChar) = iKeyInput;
if ( v18 )
break;
if ( iKeyInput == Enter_key )
{
if ( iSize )
{
v18 = 1;
szStr = ostream__operator__(cout, "\nSerial: ");
flush(szStr);
}
else
{
ostream__operator__(cout, "\nYou must enter a name!\nName: ");
}
}
else
{
v11 = ostream__operator__(cout, iTempChar);
flush(v11);
std__basic_string_char_std__char_traits_char__std__allocator_char____append(&szStrBuffer, iSize++, iTempChar); //Append String
}
}
if ( iKeyInput == Enter_key )
break;
v12 = ostream__operator__(cout, iTempChar);
flush(v12);
szSerial = (char)iTempChar + 10 * szSerial - 48;
}

6. Continue trace and analyze asm code, i stop here ;

00401238 >|> \8D45 D0 LEA EAX, DWORD PTR SS:[EBP-30] ; loc_401238
0040123B |. 50 PUSH EAX ;
0040123C |. E8 BFFDFFFF CALL ; <== Trace Into

7. Trace into sub_calculate_serial() :

00401005 |. 33C0 XOR EAX, EAX ; <== eax = 0
00401007 |. 33F6 XOR ESI, ESI ; <== esi = 0
00401009 |. 8B51 08 MOV EDX, DWORD PTR DS:[ECX+8] ; <== Length(szTempString)
0040100C |. 57 PUSH EDI
0040100D |. 85D2 TEST EDX, EDX
0040100F |. BF BA430000 MOV EDI, 43BA ; <== edi = 0x43BA
00401014 |. 76 25 JBE SHORT
00401016 |. 53 PUSH EBX
00401017 |. 8B59 04 MOV EBX, DWORD PTR DS:[ECX+4] ; |> 8B0D 2C604000 /MOV ECX, DWORD PTR DS:[<&MSVCP60.`std::basic_string; loc_40101A
00401020 |. 85DB |TEST EBX, EBX
00401022 |. 74 03 |JE SHORT
00401024 |. 8D0C33 |LEA ECX, DWORD PTR DS:[EBX+ESI]
00401027 >|> 0FBE09 |MOVSX ECX, BYTE PTR DS:[ECX] ; <== ecx = szTempString[i]
0040102A |. 0FAFC7 |IMUL EAX, EDI ; <== eax = eax * edi
0040102D |. 03C1 |ADD EAX, ECX ; <== eax = eax + ecx
0040102F |. 69FF FAE60600 |IMUL EDI, EDI, 6E6FA
00401035 |. 46 |INC ESI ; <== esi++
00401036 |. 3BF2 |CMP ESI, EDX ; <== while esi < Length(szTempString)
00401038 |.^ 72 E0 \JB SHORT ; <== Then continue

build pseudocode :

int iReaKey; // eax@1
unsigned int iLenszStrBuffer; // edx@1
unsigned int iInit; // edi@1
unsigned int iIndex; // esi@1
int v5; // ebx@2
void *szChar; // ecx@3

iReaKey = 0;
iIndex = 0;
iLenszStrBuffer = *(_DWORD *)(a1 + 8); // Length of szStrBuffer
iInit = 0x43BAu;
if ( iLenszStrBuffer )
{
v5 = *(_DWORD *)(a1 + 4); // Point to szStrBuffer
do
{
szChar = _C;
if ( v5 )
szChar = (void *)(v5 + iIndex); // Get char for szStrBuffer
iReaKey = *(_BYTE *)szChar + iInit * iReaKey;
iInit *= 0x6E6FAu;
++iIndex;
}
while ( iIndex < iLenszStrBuffer );
}
return iReaKey;

8. After trace and analyze all the asm code, the soucre keygen for this keygenme :

char szName[64]={0};
char szSerial[64]={0};
char szTempString[128]={0};
char szTemp[64]={0};
int i=0,j=0,LenUser=0,iRealKey=0,iValue=0;

LenUser=GetDlgItemText(IDC_Name,szName,70);
if (LenUser 14)
{
MessageBox("----------===== Your name atleast 1 chart ====---------- \n\n ----------===== But not over 14 charts ====---------- ",
"Hey !! Please input your name again !! ");
}
else
{
i = 0;
while (i 0;j--)
{
szTemp[j-1] = szName[i];
}
strncat(szTempString,szTemp,i);
}

LenUser = strlen(szTempString);
i = 0;
_asm
{
xor eax,eax
xor esi,esi
xor edx,edx
mov edi,0x43BA
}
while (i < LenUser)
{
_asm
{
mov eax, iRealKey
lea ecx, dword ptr[szTempString]
movsx ecx,byte ptr[ecx+esi]
imul eax, edi
add eax, ecx
imul edi, edi, 0x6E6FA
inc esi
mov iRealKey,eax
}
i++;
}
wsprintf(szSerial,"%d",iRealKey);
}

SetDlgItemText(IDC_Serial,szSerial);

********************************
Right key
UserName: kienmanowar
Serial : 114
********************************

That's all. Thanx for reading my tutor.
Sorry for my bad English!!! :|

--++--==[ Greatz Thanks To ]==--++--
My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina, QHQCrker,
the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN, HacNho, RongChauA,
Deux, tlandn, light.phoenix, dqtln, ARTEAM .... all my friend, and YOU.

--++--==[ Thanks To ]==--++--
iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl, moth, XIANUA, nhc1987 v..v..

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially haggar),
Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on crackmes.de, thank
to all members of unpack.cn (especially fly and linhanshi). Great thanks to lena151(I like your tutorials).
And finally, thanks to RICARDO NARVAJA and all members on CRACKSLATINOS.

>>>> If you have any suggestions, comments or corrections email me: kienmanowar[at]reaonline.net

 

Solution for NrZ0e1’s CrackMe #1 September 22, 2008

Filed under: My Tutorials, Solution for NrZ0e1's CrackMe #1 — kienmanowar @ 2:05 am

It’s very simple:
Just solve the program will end after pressing ‘enter’.
Enjoy! :-)

Additional ( no must ):
Write a patch!

Difficulty: 1 – Very easy, for newbies
Platform: Windows
Language: C/C++

Download crackme : http://www.crackmes.de/users/nrz0e1/crackme_1

———

Solution :

///////////////////////////////////////////////////////////////////////////////////////////
Program : NrZ0e1’s CrackMe #1
Description : It’s very simple:Just solve the program will end after pressing ‘enter’.Enjoy! :-)
Tools       : OllyDbg
Difficult   :  Easy
Packer/Protector/Compiler : N/A
Objective : Patch
Cracker   :  kienmanowar
///////////////////////////////////////////////////////////////////////////////////////////

1. First, run this crackme and press Enter, blah blah the crackme disappear.

2. Okie, Load to Olly. Scroll down and i find the start point of this crackme here :

00401150  /.  55                          PUSH    EBP
00401151  |.  8BEC                        MOV     EBP, ESP
00401153  |.  68 28A14000                 PUSH    CrackMe.0040A128  ; /Arg1 = 0040A128 ASCII " CrackMe #1 by NrZ0e1
;14/09/2007
Solve the program is stopping from now!
[Enter]"
00401158  |.  E8 A32B0000                 CALL    CrackMe.00403D00  ; \CrackMe.00403D00

3. Look down, we will see the Good boy :

00401184  |.  68 84A14000                 PUSH    CrackMe.0040A184   ; /Arg1 = 0040A184 ASCII
;"You solved the problem !!!! I am proud of you ! ;-) "
00401189  |.  E8 722B0000                 CALL    CrackMe.00403D00   ; \CrackMe.00403D00

4. Ok now, i set bp at 00401150, F9 to run and stop at the bp. Use F8 key to trace downward, after trace over this call

00401176  |.  E8 75290000                 CALL    CrackMe.00403AF0

The crackeme run, back to Crackme and press Enter, blah we return to OllyDbg. Continue to trace downward and stop at this call :

0040117C  |> \6A 01                       PUSH    1                  ; /Arg1 = 00000001
0040117E  |.  E8 C1610000                 CALL    CrackMe.00407344   ; \CrackMe.00407344 <== Stop here
00401183  |.  59                          POP     ECX
00401184  |.  68 84A14000                 PUSH    CrackMe.0040A184   ; /Arg1 = 0040A184 ASCII
;"You solved the problem !!!! I am proud of you ! ;-) "
00401189  |.  E8 722B0000                 CALL    CrackMe.00403D00   ; \CrackMe.00403D00

5. The Call at 0040117E will call ExitProcess Api to terminate this crackme, so i nop this call like this :

0040117C  |> \6A 01                       PUSH    1                                 ; /Arg1 = 00000001
0040117E      90                          NOP                                       ; \CrackMe.00407344
0040117F      90                          NOP
00401180      90                          NOP
00401181      90                          NOP
00401182      90                          NOP

6. Press F9 to Run, wow the Good boy appear!!!

That’s all. Thanx for reading my tutor.
Sorry for my bad English!!! :|

–++–==[ Greatz Thanks To ]==–++–
My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina, QHQCrker,
the_Lighthouse, Merc, Hoadongnoi, Nini … all REA‘s members, TQN, HacNho, RongChauA,
Deux, tlandn, light.phoenix, dqtln, ARTEAM …. all my friend, and YOU.

–++–==[ Thanks To ]==–++–
iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl, moth, XIANUA, nhc1987 v..v..

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially haggar),
Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on crackmes.de, thank
to all members of unpack.cn (especially fly and linhanshi). Great thanks to lena151(I like your tutorials).
And finally, thanks to RICARDO NARVAJA and all members on CRACKSLATINOS.

>>>> If you have any suggestions, comments or corrections email me: kienmanowar[at]reaonline.net

 

Solution for KeyGenMe_by_ZeroTen_#1 September 19, 2008

Filed under: My Tutorials, Solution for KeyGenMe_by_ZeroTen_#1 — kienmanowar @ 9:15 am

Easy Crackme//KeyGenme.
=======================
Try to find a valid Key for your name.
NO PATCHING!

ZeroTen

Difficulty: 1 – Very easy, for newbies
Platform: Windows
Language: C/C++

Download crackme here: http://www.crackmes.de/users/zeroten/crackme_keygenme_by_zeroten_1
—————————-
Solution :

///////////////////////////////////////////////////////////////////////////////////////////
Program : CrackMe_KeyGenMe_by_ZeroTen_#1.exe
Description : Easy Crackme//KeyGenme.Try to find a valid Key for your name.NO PATCHING!
Tools : OllyDbg
Difficult : Easy (but not for newbies :D )
Packer/Protector/Compiler : N/A
Objective : Keygen
Cracker : kienmanowar
///////////////////////////////////////////////////////////////////////////////////////////

1. First, run this keygenme and input Name, Password and Serial then click Login. Hola, the keygenme terminate without Nag.
Retry to test with one char in Name textbox, blah blah i get the Nag : “At least, more than 4 letters”.

2. Okie, Load to Olly and search all ref strings. I find it here :

Text strings referenced in CrackMe_:.text, item 10
Address=00401C88
Disassembly=PUSH CrackMe_.004871A6
Text string=ASCII "At least, more than 4 letters"

3. Double click to this line, and scroll up to find the start point of this routine.And then set a BP :

00401A18 >/. 55 PUSH EBP ; _TForm1_Button1Click <== Set BP
00401A19 |. 8BEC MOV EBP, ESP
00401A1B |. 83C4 94 ADD ESP, -6C
00401A1E |. 53 PUSH EBX
00401A1F |. 56 PUSH ESI
00401A20 |. 57 PUSH EDI
00401A21 |. 8BD8 MOV EBX, EAX

4. F9 to run and input data (ex: kienmanowar / 1234 / 56789) then press Log in.Wow, stop at BP that i set.Trace downward i get the
the first point. That code will use the Lenght of szName to calculate and store the result in edi reg :

00401A43 >|. 8B83 64030000 MOV EAX, DWORD PTR DS:[EBX+364] ; *TForm1.Edit1:TEdit (szUserName)
00401A49 |. E8 42B40400 CALL ; <== eax : Length(szName)
00401A4E |. 837D FC 00 CMP DWORD PTR SS:[EBP-4], 0 ; <== Length(szName) != 0
00401A52 |. 74 08 JE SHORT
00401A54 |. 8B55 FC MOV EDX, DWORD PTR SS:[EBP-4] ; <== edx : szName
00401A57 |. 8B4A FC MOV ECX, DWORD PTR DS:[EDX-4] ; <== ecx : Length(szName)
00401A5A |. EB 02 JMP SHORT
00401A5C >|> 33C9 XOR ECX, ECX ; |> 8D3C89 LEA EDI, DWORD PTR DS:[ECX+ECX*4] ; <== edi = ecx + ecx*4 (LengthIsNotZero__)
00401A61 |. 8D45 FC LEA EAX, DWORD PTR SS:[EBP-4]
00401A64 |. BA 02000000 MOV EDX, 2 ; <== edx = 0x2
00401A69 |. 8D3CB9 LEA EDI, DWORD PTR DS:[ECX+EDI*4] ; <== edi = ecx + edi*4
00401A6C |. C1E7 03 SHL EDI, 3 ; <== edi = edi * 2^3
00401A6F |. 2BF9 SUB EDI, ECX ; <== edi = edi - ecx
00401A71 |. 8D3CF9 LEA EDI, DWORD PTR DS:[ECX+EDI*8] ; <== edi = ecx + edi*8
00401A74 |. 81C7 A31C0000 ADD EDI, 1CA3 ; <== edi = edi + 0x1CA3

5. Continue trace downward and analyze, i find 4 same forged codes to cheat my thinkin’ and one of them like this below :) :

00401A9B >|. 8B83 70030000 MOV EAX, DWORD PTR DS:[EBX+370] ; *TForm1.Edit2:TEdit (szPassWord)
00401AA1 |. E8 EAB30400 CALL ; <== eax : Length(szPassWord)
00401AA6 |. 8D55 F8 LEA EDX, DWORD PTR SS:[EBP-8]
00401AA9 |. 52 PUSH EDX
00401AAA |. 8D45 F4 LEA EAX, DWORD PTR SS:[EBP-C]
00401AAD |. 8B55 A0 MOV EDX, DWORD PTR SS:[EBP-60] ;
00401AB0 |. E8 5B110700 CALL ; <== Convert int to string
00401AB5 |. FF46 1C INC DWORD PTR DS:[ESI+1C] ;
00401AB8 |. 8D55 F4 LEA EDX, DWORD PTR SS:[EBP-C]
00401ABB |. 58 POP EAX
00401ABC |. E8 D7110700 CALL ;
00401AC1 |. 50 PUSH EAX
00401AC2 |. FF4E 1C DEC DWORD PTR DS:[ESI+1C]
00401AC5 |. 8D45 F4 LEA EAX, DWORD PTR SS:[EBP-C]
00401AC8 |. BA 02000000 MOV EDX, 2
00401ACD |. E8 82110700 CALL
00401AD2 |. FF4E 1C DEC DWORD PTR DS:[ESI+1C] ; |
00401AD5 |. 8D45 F8 LEA EAX, DWORD PTR SS:[EBP-8] ; |
00401AD8 |. BA 02000000 MOV EDX, 2 ; |
00401ADD |. E8 72110700 CALL ; \CrackMe_.00472C54
00401AE2 |. 59 POP ECX
00401AE3 |. 84C9 TEST CL, CL
00401AE5 |. 74 0C JE SHORT
00401AE7 |. A1 CCF44800 MOV EAX, DWORD PTR DS:[48F4CC]
00401AEC |. 8B00 MOV EAX, DWORD PTR DS:[EAX]
00401AEE >|. E8 9D260400 CALL ; ->:TApplication._Terminate()

6. By pass all of this code, i land here :

00401C47 >|. 8B83 64030000 MOV EAX, DWORD PTR DS:[EBX+364] ; *TForm1.Edit1:TEdit (szName)
00401C4D |. E8 3EB20400 CALL ; <== eax = Length(szName)
00401C52 |. 837D D8 00 CMP DWORD PTR SS:[EBP-28], 0
00401C56 |. 74 08 JE SHORT
00401C58 |. 8B55 D8 MOV EDX, DWORD PTR SS:[EBP-28] ; <== edx : szName
00401C5B |. 8B4A FC MOV ECX, DWORD PTR DS:[EDX-4] ; <== ecx : Length(szName)
00401C5E |. EB 02 JMP SHORT
00401C60 >|> 33C9 XOR ECX, ECX ; loc_401C60
00401C62 >|> 83F9 04 CMP ECX, 4 ; loc_401C62
00401C65 |. BA 02000000 MOV EDX, 2
00401C6A |. 0F9CC0 SETL AL
00401C6D |. 83E0 01 AND EAX, 1
00401C70 |. 50 PUSH EAX ; /Arg1
00401C71 |. 8D45 D8 LEA EAX, DWORD PTR SS:[EBP-28] ; |
00401C74 |. FF4E 1C DEC DWORD PTR DS:[ESI+1C] ; |
00401C77 |. E8 D80F0700 CALL ; \CrackMe_.00472C54
00401C7C |. 59 POP ECX
00401C7D |. 84C9 TEST CL, CL
00401C7F |. 74 18 JE SHORT
00401C81 |. 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
00401C83 |. 68 C4714800 PUSH CrackMe_.004871C4 ; |Title = "BEEP!"
00401C88 |. 68 A6714800 PUSH CrackMe_.004871A6 ; |Text = "At least, more than 4 letters"
00401C8D |. 6A 00 PUSH 0 ; |hOwner = NULL
00401C8F >|. E8 204D0800 CALL ; \->UnrealizeObject.MessageBoxA()
00401C94 |. E9 F6000000 JMP

7. Ok my UserName has the length greater than 4 letters so that i bypass this check.After bypass, hola i land at the second important point.
The edx = edi + 0×1CA3 and will be converted to String and save into the szTruePassWord :

00401CAC >|. 8B83 70030000 MOV EAX, DWORD PTR DS:[EBX+370] ; *TForm1.Edit2:TEdit (szPassWord)
00401CB2 |. E8 D9B10400 CALL ; <== eax : Length(szPassWord)
00401CB7 |. 8D55 D4 LEA EDX, DWORD PTR SS:[EBP-2C]
00401CBA |. 52 PUSH EDX
00401CBB |. 8D97 A31C0000 LEA EDX, DWORD PTR DS:[EDI+1CA3] ; <== edx = edi + 0x1CA3
00401CC1 |. 8D45 D0 LEA EAX, DWORD PTR SS:[EBP-30] ; <== szTruePassWord
00401CC4 |. E8 470F0700 CALL ; <== ConvertIntToString (&szTruePassWord, edx)
00401CC9 |. FF46 1C INC DWORD PTR DS:[ESI+1C]
00401CCC |. 8D55 D0 LEA EDX, DWORD PTR SS:[EBP-30]
00401CCF |. 58 POP EAX
00401CD0 |. E8 C30F0700 CALL
00401CD5 |. 50 PUSH EAX
00401CD6 |. FF4E 1C DEC DWORD PTR DS:[ESI+1C]
00401CD9 |. 8D45 D0 LEA EAX, DWORD PTR SS:[EBP-30]
00401CDC |. BA 02000000 MOV EDX, 2
00401CE1 |. E8 6E0F0700 CALL
00401CE6 |. FF4E 1C DEC DWORD PTR DS:[ESI+1C] ; |
00401CE9 |. 8D45 D4 LEA EAX, DWORD PTR SS:[EBP-2C] ; |
00401CEC |. BA 02000000 MOV EDX, 2 ; |
00401CF1 |. E8 5E0F0700 CALL ; \CrackMe_.00472C54
00401CF6 |. 59 POP ECX
00401CF7 |. 84C9 TEST CL, CL
00401CF9 |. 0F84 83000000 JE

8. Lets continue, i found the last important point.The edx = edi – 0×1CA3 and will be converted to String and save into the szTrueSerial :

00401D12 >|. 8B83 78030000 MOV EAX, DWORD PTR DS:[EBX+378] ; *TForm1.Edit3:TEdit (szSerial)
00401D18 |. E8 73B10400 CALL ; <== eax = Length(szSerial)
00401D1D |. 8D55 CC LEA EDX, DWORD PTR SS:[EBP-34]
00401D20 |. 52 PUSH EDX
00401D21 |. 8D97 5DE3FFFF LEA EDX, DWORD PTR DS:[EDI-1CA3] ; <== edx = edi - 0x1CA3
00401D27 |. 8D45 C8 LEA EAX, DWORD PTR SS:[EBP-38] ; <== szTrueSerial
00401D2A |. E8 E10E0700 CALL ; <== ConvertIntToString (&szTruePassWord, edx)
00401D2F |. FF46 1C INC DWORD PTR DS:[ESI+1C]
00401D32 |. 8D55 C8 LEA EDX, DWORD PTR SS:[EBP-38]
00401D35 |. 58 POP EAX
00401D36 |. E8 5D0F0700 CALL
00401D3B |. 50 PUSH EAX
00401D3C |. FF4E 1C DEC DWORD PTR DS:[ESI+1C]
00401D3F |. 8D45 C8 LEA EAX, DWORD PTR SS:[EBP-38]
00401D42 |. BA 02000000 MOV EDX, 2
00401D47 |. E8 080F0700 CALL
00401D4C |. FF4E 1C DEC DWORD PTR DS:[ESI+1C] ; |
00401D4F |. 8D45 CC LEA EAX, DWORD PTR SS:[EBP-34] ; |
00401D52 |. BA 02000000 MOV EDX, 2 ; |
00401D57 |. E8 F80E0700 CALL ; \CrackMe_.00472C54
00401D5C |. 59 POP ECX
00401D5D |. 84C9 TEST CL, CL
00401D5F |. 74 13 JE SHORT

9. And finally we have the Good boy :

00401D61 |. 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
00401D63 |. 68 EB714800 PUSH CrackMe_.004871EB ; |Title = "Correct!!by ZeroTen"
00401D68 |. 68 CA714800 PUSH CrackMe_.004871CA ; |Text = "Now post your solution/KeyGen ;) "
00401D6D |. 6A 00 PUSH 0 ; |hOwner = NULL
00401D6F >|. E8 404C0800 CALL ; \->UnrealizeObject.MessageBoxA()

/

//////////////////////////////////
// Keygen source code //
//////////////////////////////////
int iDefault = 0×1CA3;

// Calculate Value
Value=0;
Value = LenUser + LenUser*4;
Value = LenUser + Value*4;
Value = Value * 8;
Value = Value – LenUser;
Value = LenUser + Value*8;
Value = Value + iDefault;

//Calculate szPassWord
iTemp = Value + iDefault;
wsprintf(szPassWord,”%i”,iTemp);

//Calculate szSerial
iTemp = Value – iDefault;
wsprintf(szSerial,”%i”,iTemp);

SetDlgItemText(IDC_PassWord,szPassWord);
SetDlgItemText(IDC_Serial,szSerial);

///////////////////////
The realkey for my username :
Username : kienmanowar
Password : 29369
Serial : 14707
///////////////////////

That’s all. Thanx for reading my tutor.
Sorry for my bad English!!! :|

–++–==[ Greatz Thanks To ]==–++–
My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina, QHQCrker,
the_Lighthouse, Merc, Hoadongnoi, Nini … all REA‘s members, TQN, HacNho, RongChauA,
Deux, tlandn, light.phoenix, dqtln, ARTEAM …. all my friend, and YOU.

–++–==[ Thanks To ]==–++–
iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl, moth, XIANUA, nhc1987 v..v..

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially haggar),
Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on crackmes.de, thank
to all members of unpack.cn (especially fly and linhanshi). Great thanks to lena151(I like your tutorials).
And finally, thanks to RICARDO NARVAJA and all members on CRACKSLATINOS.

If you have any suggestions, comments or corrections email me: kienmanowar[at]reaonline.net

 

Solution for KLiZMA’s UnpackMe #1 September 19, 2008

Filed under: My Tutorials, Solution for KLiZMA's UnpackMe #1 — kienmanowar @ 8:48 am

After 2 months…
KLiZMA wrote another unpackme for you.

Rulz:

1. Unpack it maliciously…
2. Change “UNREGISTERED” to “REGISTERED”
3. Write tutorial about…

Download unpackme here: http://www.crackmes.de/users/klizma/unpackme_1

——

Solution by me:

+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| Solution:     UnpackMe#1_by_KLiZMA           |
| Author:     kienmanowar                    |
| Protection:    Unknown packer (like Upx)      |
| Language:      Borland Delphi                 |
| Date:        05/13/06               |
| Great thanx to iamidiot for give me your hint |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+

Tools: Ollydbg, PEid v0.94, RDG Packer Detector v0.6.3 Beta, ImpRec v1.6

ÛÛÛ [ Manual Unpacking ] ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

Try to detect this Unpackme with PEid and RDG, i get some information :

PEiD :
+ Normal Scan : Nothing found *
+ Hardcore Scan : UPolyX v0.5 *

RDG :
+ Normal Scan : UG2002 Cruncher v0.3b3
+ Advanced Scan : UPX v0.8x (UPX Heuristico Scrambler)

With these information, i don’t know what exactly packer in which this UnpackMe used. So I use PEid plugin (Generic OEP Finder)to find OEP of UnpackMe, It gives me : 00463C80. Okie :) may be this is the right OEP!!!

Close PeID and open Ollydbg to load this UnpackMe in. A messagebox apears, choose No. I have :

0047E000 >  60              pushad            <== Stop here (EP)
0047E001    E8 00000000     call    unpackme.0047E006
0047E006    5D              pop     ebp
0047E007    81ED 48124000   sub     ebp, unpackme.00401248
0047E00D    60              pushad
0047E00E    E8 2B030000     call    unpackme.0047E33E
0047E013    61              popad
0047E014    8A7D 60         mov     bh, byte ptr ss:[ebp+60]
0047E017    6262 DB         bound   esp, qword ptr ds:[edx-25]
0047E01A    6A 62           push    62
0047E01C    6262 EF         bound   esp, qword ptr ds:[edx-11]
0047E01F    D7              xlat    byte ptr ds:[ebx+al]
0047E020    EA 7022628A 496>jmp     far 6049:8A622270
0047E027    6262 9D         bound   esp, qword ptr ds:[edx-63]
0047E02A    F7              ???                                      ; Unknown command
0047E02B    8D70 22         lea     esi, dword ptr ds:[eax+22]
0047E02E    62E9            bound   ebp, ecx                         ; Illegal use of register
0047E030    BA F2F29DF7     mov     edx, F79DF2F2

Oh !! I see Pushad signature, like UPX. Press Alt + M to open Memory map Window.

Memory map
Address    Size     (  Owner       Section    Contains      Type   Access    Initial   Mapped as
................................................................................................
00370000   00003000 (           0                           Map    R         R
00400000   00001000 (  unpackme 0             PE header     Imag   R         RWE
00401000   0004B000 (  unpackme 0  .KLiZMA                  Imag   R         RWE
0044C000   00031000 (  unpackme 0  .KLiZMA    code          Imag   R         RWE
0047D000   00001000 (  unpackme 0  .rsrc      data,imports  Imag   R         RWE
0047E000   00001000 (  unpackme 0  .KLiZMA    SFX           Imag   R         RWE
00480000   00004000 (           0                           Map    R E       R E
00540000   00002000 (           0                           Map    R E       R E
00550000   00103000 (           0                           Map    R         R
00660000   0006A000 (           0                           Map    R E       R E
.................................................................................................

In this Window, select section :

00401000   0004B000 (  unpackme 0  .KLiZMA                  Imag   R         RWE

And Right click and set a Memory Breakpoint on Access.And then Press F9 to Run, Olly breaks here :

0047CCA3    8807            mov     byte ptr ds:[edi], al    <== Stop here after Press F9 (1st)
0047CCA5    47              inc     edi
0047CCA6    01DB            add     ebx, ebx
0047CCA8    75 07           jnz     short unpackme.0047CCB1
0047CCAA    8B1E            mov     ebx, dword ptr ds:[esi]
0047CCAC    83EE FC         sub     esi, -4
0047CCAF    11DB            adc     ebx, ebx
0047CCB1  ^ 72 ED           jb      short unpackme.0047CCA0

Come back Memory Map Window and clear Memory BP.And then back to CPU Window, scroll down to find the signature :) :

0047CDEB    83C3 04         add     ebx, 4
0047CDEE  ^ EB E1           jmp     short unpackme.0047CDD1
0047CDF0    FF96 84CE0700   call    near dword ptr ds:[esi+7CE84]
0047CDF6    61              popad                <=== Aha Popad
0047CDF7  ^ E9 846EFEFF     jmp     unpackme.00463C80        <=== Jmp to OEP (Like OEP found in Peid)

As you see, this signature like UPX. And now, set BP at : 0047CDF7  ^ E9 846EFEFF     jmp     unpackme.00463C80
Press F9 to Run, Break at this BP, remove this and Press F8 , kaka we stop at OEP of UnpackMe :

00463C80    55              push    ebp                <=== Right OEP
00463C81    8BEC            mov     ebp, esp
00463C83    83C4 F0         add     esp, -10
00463C86    B8 903A4600     mov     eax, unpackme.00463A90
00463C8B    E8 A41FFAFF     call    unpackme.00405C34
00463C90    A1 F8584600     mov     eax, dword ptr ds:[4658F8]
00463C95    8B00            mov     eax, dword ptr ds:[eax]
00463C97    E8 14B2FEFF     call    unpackme.0044EEB0

Now, dump with Ollydump Plugin, not check Rebuilt Import. Press Dump and Save as : dumped.exe. Fire up ImportRec, select Process, write OEP , Press IAT Auto Search, Get Imports and finally Fix Dump.We have dumped_.exe. Test it: kaka it runs before i double click :) lol and detect again by PEid : Borland Delphi 6.0 – 7.0.

ÛÛÛ [ Cracking ] ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

After MUP this UnpackMe, come to part 2 to change “UNREGISTERED” to “REGISTERED”. To do this task, Load dumped_.exe into Ollydbg. Press F9 to Run it, we’ll see a beautiful girl with “UNREGISTERED” string below. Back to Ollydbg, Press Alt+M to open Memory map Window, here we select :

Memory map, item 0
Address=00010000
Size=00001000 (4096.)
Owner=         00010000 (itself)
Section=
Type=Priv 00021004
Access=RW
Initial access=RW

Right click and select Search (or Ctrl+B),then type : UNREGISTERED in Ascii textbox and Press OK to Search this string.After that Olly break at :

Memory map, item 25
Address=0047D000
Size=00001000 (4096.)
Owner=dumped_  00400000
Section=.rsrc
Contains=data,resources
Type=Imag 01001002
Access=R
Initial access=RWE

and we have in Dump window :
00479140  55 4E 52 45 47 49 53 54 45 52 45 44 0C 46 6F 6E  UNREGISTERED.Fon
00479150  74 2E 43 68 61 72 73 65 74 07 0F 44 45 46 41 55  t.CharsetDEFAU
00479160  4C 54 5F 43 48 41 52 53 45 54 0A 46 6F 6E 74 2E  LT_CHARSET.Font.
00479170  43 6F 6C 6F 72 07 08 63 6C 57 69 6E 64 6F 77 0B  ColorclWindow

Okies, the string which we want to find is in Section : .rsrc (resource). So back to CPU Window, right click in Dump Window and Select Go to (Ctrl+G), we type the address of string : 00479140. Select UNREGISTERED string and edit this to REGISTERED. Finally, Save this edited file : dumped_edited.exe. Ok, Run this and see the result :) .

Finish!
Best Regards
_[Kienmanowar]_

ÛÛÛ [ Thanz ] ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

–++–==[ Greatz Thanks To ]==–++–
My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina, QHQCrker, the_Lighthouse, Merc, Hoadongnoi, Nini … all REA’s members, TQN, HacNho, RongChauA, Deux, tlandn, light.phoenix, dqtln, ARTEAM …. all my friend, and YOU.

–++–==[ Thanks To ]==–++–
iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl v..v..

–++–==[ Special Thanks  ]==–++–
And then thanx to the Author : KLiZMA and all the people read my tutor!

If you have any suggestions, comments or corrections email me: kienbigmummy[at]gmail.com

Sorry in my bad English. Because English is not my mother language, I’m VietNamese.

Welcome all to : reaonline.net

ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
³    °±²Û CONTACT INFORMATION                                                ³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

URL : http://www.reaonline.net
contact me : kienbigmummy@gmail.com