Let's crack TrickSoft Level2 CrackMe with ManKind Author: ManKind Target: TrickSoft Level2 CrackMe -> http://www.tricksoft.net Date : Author's e-mail: mankind001@bigfoot.com Dedication: To crackers who wish to learn more about cracking Visual Basic programs... Difficulty Level: (1..7) 2-3 Tools Required: SoftICE 3.2x, SmartCheck(optional) ----------------------------------------------------------------------- Introduction =============== Not much to be said here because I have pointed out quite a sum of things in the previous essay. However, I really want to assure you that SoftICE is currently the most powerful tool available for cracking Microsoft Visual Basic Native Code programs, and particularly wonderful and spectacular when it is used together with SmartCheck, W32Dasm/IDA, ExDec(for pseudo code VB programs) and a hexeditor(need I mention HIEW?)... In this essay, I will dive straight into the keygenneration routine of this crackme and no useless things will be included. Oh, by the way, you shall at first get the overview of the protection first in SmartCheck to understand why I do something the way I did in this essay...(and btw, the listing in SmartCheck also helps by telling me the sequence of APIs that is being called and that enable me to set appropriate breakpoints... :D ) Tutorial ======== To follow this tutorial, you have to make sure that you have loaded both msvbvm50.dll and msvbvm60.dll symbols(though msvbvm50.dll's symbol is not necessarily be loaded for this tutorial, I strongly recommend you to load both the symbols...). For information on how to do so, do visit http://crfb.cjb.net and/or http://zencrack2.cjb.net and search for essays on how to configure SoftICE and its winice.dat file...(of course, make full use of other great resources you can find in the two sites too) As usual, the very first thing we do when we start to crack is enter some fake registration information to the text fields that we have. There are 3 in this crackme, first name, last name and serial. The register button will only be enabled when the both the first and last names' are at least 1 in length. I don't have any last name(probably I shall start to think 1 soon) so, after a little thinking, I fill in the following registration information: First name:ManKind Last name :KindMan Serial :23199981 (of course, you can fill in different information but my explanation in this essay will be based on the above) Before pressing the Register button, set a breakpoint on msvbvm60!__vbaVarForNext in SoftICE. Why this breakpoint? At the very first time when I try to crack this crackme, I have used SmartCheck on it realized that some APIs are used on every characters of my name and I quickly figured out that to achieve that, a loop must have been used(and __vbaVarForNext is the API used to loop)(but be sure that this is the first or one of the first few APIs used or else you may have left out some important calculation) but it is not necessary for you to use SmartCheck(but on every first time of cracking VB programs, I recommend you to use SmartCheck to get an overview of the protection). Even if SmartCheck is not used on this crackme, you can almost always assume that this API will be used as most name/serial protection will somehow generate the real registration code from the ascii values of the characters in the user's name(and usually they don't just use a character of the name, the use at least a few characters of name and that may require loop)... You can press the Register button now and SoftICE will pop up almost immediately, you are currently in msvbvm60.dll's code, press F11 once to return to the caller of the API and you will land inside the crackme's code(just where we want to be)(disable your breakpoint!). At this point you are at the first line of code of 1st loop out of length(first name) loop: (my comment is preceeded by <-- ) * Reference To: MSVBVM60.__vbaVarForNext, Ord:0000h | :004061E2 FF15C8104000 Call dword ptr [004010C8] :004061E8 8985BCFEFFFF mov dword ptr [ebp+FFFFFEBC], eax <-- you land here * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004060F8(U) | :004061EE 83BDBCFEFFFF00 cmp dword ptr [ebp+FFFFFEBC], 00000000 <-- compare if all the loops have been completed :004061F5 0F8502FFFFFF jne 004060FD <-- jump if not to 004060FD As this is only the first loop, we will of course jump to address 004060FD: * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004061F5(C) | :004060FD C745FC05000000 mov [ebp-04], 00000005 :00406104 8B4D08 mov ecx, dword ptr [ebp+08] : : (left out some unimportant code to save space) * Reference To: MSVBVM60.__vbaObjSet, Ord:0000h | :00406118 : (left out some unimportant code to save space) * Reference To: MSVBVM60.__vbaI4Var, Ord:0000h | :00406154 : (left out some unimportant code to save space) * Reference To: MSVBVM60.rtcMidCharVar, Ord:0278h <-- extract a character from a string, in this case, our first name | :00406166 : (left out some unimportant code to save space) * Reference To: MSVBVM60.__vbaStrVarMove, Ord:0000h | :00406173 : (left out some unimportant code to save space) * Reference To: MSVBVM60.__vbaStrMove, Ord:0000h | :0040617E : (left out some unimportant code to save space) * Reference To: MSVBVM60.__vbaFreeObj, Ord:0000h | :00406187 : (left out some unimportant code to save space) * Reference To: MSVBVM60.__vbaFreeVarList, Ord:0000h | :0040619E : (left out some unimportant code to save space) * Reference To: MSVBVM60.rtcAnsiValueBstr, Ord:0204h <-- obtain the ascii value of a character, in this case, the current character which has been extracted from our first name using MSVBVM60.rtcMidCharVar API function | :004061B2 FF1524104000 Call dword ptr [00401024] <-- ax contains the ascii value of the current character after returning from MSVBVM60.rtcAnsiValueBstr API function :004061B8 0FBFC8 movsx ecx, ax <-- move ax's value to ecx :004061BB 8B55C8 mov edx, dword ptr [ebp-38] <-- move the value of a temporary memory location([ebp-38]) to edx :004061BE 03D1 add edx, ecx <-- add ecx to edx :004061C0 0F800D060000 jo 004067D3 :004061C6 8955C8 mov dword ptr [ebp-38], edx <-- move the new value back to the temporary memory location :004061C9 C745FC07000000 mov [ebp-04], 00000007 :004061D0 8D85F4FEFFFF lea eax, dword ptr [ebp+FFFFFEF4] :004061D6 50 push eax :004061D7 8D8D04FFFFFF lea ecx, dword ptr [ebp+FFFFFF04] :004061DD 51 push ecx :004061DE 8D55D0 lea edx, dword ptr [ebp-30] :004061E1 52 push edx (after this, it will go back to the MSVBVM60.__vbaVarForNext API function which will continue to loop until length(first name) times) Lots of code, but actually the above loop is very, very simple. Basically, it just add up all the ascii values of all the characters of our first name. Below is what it will look like in Visual Basic language: '(assuming Text1.Text as the text field for our first name) temp1 = 0 For i = 1 to Len(Text1.Text) temp1 = temp1 + Asc(Mid(Text1.Text, i, 1)) Next i Well, let's see what else it does after the loop finishes: * Reference To: MSVBVM60.__vbaVarForNext, Ord:0000h | :004061E2 FF15C8104000 Call dword ptr [004010C8] :004061E8 8985BCFEFFFF mov dword ptr [ebp+FFFFFEBC], eax * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004060F8(U) | :004061EE 83BDBCFEFFFF00 cmp dword ptr [ebp+FFFFFEBC], 00000000 :004061F5 0F8502FFFFFF jne 004060FD <-- this should not jump when you have completed the loop, so continue with the code below :004061FB C745FC08000000 mov [ebp-04], 00000008 :00406202 8B45C8 mov eax, dword ptr [ebp-38] <-- move the value of all the added ascii values to eax :00406205 05697A0000 add eax, 00007A69 <-- add 31337 decimal to eax ("LEETO"?) :0040620A 0F80C3050000 jo 004067D3 :00406210 6BC002 imul eax, 00000002 <-- multiply eax with 2 :00406213 0F80BA050000 jo 004067D3 :00406219 8945C8 mov dword ptr [ebp-38], eax <-- move back the new value of eax to the temporary memory location More investigation shows that it does nothing more to this temporary value. So, we just add a little things to our own copy of VB code according to the above code: '(assuming Text1.Text as the text field for our first name) temp1 = 0 For i = 1 to Len(Text1.Text) temp1 = temp1 + Asc(Mid(Text1.Text, i, 1)) Next i temp1 = (temp1 + 31337) * 2 You can trace to the next piece of important code using F10 but I suggest you again set a breakpoint on msvbvm60!__vbaVarForNext(just make sure that there is no other calculation before this API is called, I am sure because I have investigated in SmartCheck where after the above temporary value has been calculated another loop using our last name immediately ran). Another break will bring you here: * Reference To: MSVBVM60.__vbaVarForNext, Ord:0000h | :00406423 FF15C8104000 Call dword ptr [004010C8] :00406429 8985B4FEFFFF mov dword ptr [ebp+FFFFFEB4], eax * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00406339(U) | :0040642F 83BDB4FEFFFF00 cmp dword ptr [ebp+FFFFFEB4], 00000000 <-- check if all the loops have been completed :00406436 0F8502FFFFFF jne 0040633E <-- jump if not to 0040633E What will be done after we jump there? Let's take a look: * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00406436(C) | :0040633E : (left out some unimportant code to save space) * Reference To: MSVBVM60.__vbaObjSet, Ord:0000h | :00406359 : (left out some unimportant code to save space) * Reference To: MSVBVM60.__vbaI4Var, Ord:0000h | :00406395 : (left out some unimportant code to save space) * Reference To: MSVBVM60.rtcMidCharVar, Ord:0278h <-- extract a character from a string, in this case, from our last name | :004063A7 : (left out some unimportant code to save space) * Reference To: MSVBVM60.__vbaStrVarMove, Ord:0000h | :004063B4 : (left out some unimportant code to save space) * Reference To: MSVBVM60.__vbaStrMove, Ord:0000h | :004063BF : (left out some unimportant code to save space) * Reference To: MSVBVM60.__vbaFreeObj, Ord:0000h | :004063C8 : (left out some unimportant code to save space) * Reference To: MSVBVM60.__vbaFreeVarList, Ord:0000h | :004063DF : (left out some unimportant code to save space) * Reference To: MSVBVM60.rtcAnsiValueBstr, Ord:0204h <-- obtain the ascii value of a character | :004063F3 FF1524104000 Call dword ptr [00401024] <-- ax contains ascii value of current character of last name after returning from this call :004063F9 0FBFC0 movsx eax, ax <-- move value of ax to eax :004063FC 8B4DB4 mov ecx, dword ptr [ebp-4C] <-- move value of a temporary memory location([ebp-4C]) to ecx :004063FF 03C8 add ecx, eax <-- add the ascii value of current character to the existing temporary value :00406401 0F80CC030000 jo 004067D3 :00406407 894DB4 mov dword ptr [ebp-4C], ecx <-- move the new value back to the temporary memory location :0040640A C745FC0D000000 mov [ebp-04], 0000000D :00406411 8D95D4FEFFFF lea edx, dword ptr [ebp+FFFFFED4] :00406417 52 push edx :00406418 8D85E4FEFFFF lea eax, dword ptr [ebp+FFFFFEE4] :0040641E 50 push eax :0040641F 8D4DB8 lea ecx, dword ptr [ebp-48] :00406422 51 push ecx That will again add up all the ascii values of all the characters of our last name. Let's see what else it does to the temporary value after the loops finish before we try to recode the same routine: * Reference To: MSVBVM60.__vbaVarForNext, Ord:0000h | :00406423 FF15C8104000 Call dword ptr [004010C8] :00406429 8985B4FEFFFF mov dword ptr [ebp+FFFFFEB4], eax * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00406339(U) | :0040642F 83BDB4FEFFFF00 cmp dword ptr [ebp+FFFFFEB4], 00000000 :00406436 0F8502FFFFFF jne 0040633E <-- this should not jump when the loops have finished, so continue with the following code :0040643C C745FC0E000000 mov [ebp-04], 0000000E :00406443 8B55B4 mov edx, dword ptr [ebp-4C] <-- move the temporary value to edx :00406446 81C2697A0000 add edx, 00007A69 <-- again, add 31337 decimal to edx :0040644C 0F8081030000 jo 004067D3 :00406452 6BD205 imul edx, 00000005 <-- multiply edx with 5 :00406455 0F8078030000 jo 004067D3 :0040645B 8955B4 mov dword ptr [ebp-4C], edx <-- move the new value of edx back to temporary memory location :0040645E C745FC0F000000 mov [ebp-04], 0000000F :00406465 8B45C8 mov eax, dword ptr [ebp-38] :00406468 50 push eax Easy, no? The code for the second loop and the above code could have been like this is Visual Basic language: '(assuming Text2.Text as the text field for our last name) temp2 = 0 For i = 1 to Len(Text2.Text) temp2 = temp2 + Asc(Mid(Text2.Text, i, 1)) Next i temp2 = (temp2 + 31337) * 5 Now we have two temporary values. What are they for? Trace on and you will come to the following code: * Reference To: MSVBVM60.__vbaStrI4, Ord:0000h | :00406469 FF1508104000 Call dword ptr [00401008] :0040646F 8BD0 mov edx, eax :00406471 8D4DAC lea ecx, dword ptr [ebp-54] * Reference To: MSVBVM60.__vbaStrMove, Ord:0000h | :00406474 FF15BC104000 Call dword ptr [004010BC] :0040647A 50 push eax :0040647B 68A04F4000 push 00404FA0 * Reference To: MSVBVM60.__vbaStrCat, Ord:0000h | :00406480 FF152C104000 Call dword ptr [0040102C] :00406486 8BD0 mov edx, eax :00406488 8D4DA8 lea ecx, dword ptr [ebp-58] * Reference To: MSVBVM60.__vbaStrMove, Ord:0000h | :0040648B FF15BC104000 Call dword ptr [004010BC] :00406491 50 push eax :00406492 8B4DB4 mov ecx, dword ptr [ebp-4C] :00406495 51 push ecx * Reference To: MSVBVM60.__vbaStrI4, Ord:0000h | :00406496 FF1508104000 Call dword ptr [00401008] :0040649C 8BD0 mov edx, eax :0040649E 8D4DA4 lea ecx, dword ptr [ebp-5C] * Reference To: MSVBVM60.__vbaStrMove, Ord:0000h | :004064A1 FF15BC104000 Call dword ptr [004010BC] :004064A7 50 push eax * Reference To: MSVBVM60.__vbaStrCat, Ord:0000h | :004064A8 FF152C104000 Call dword ptr [0040102C] :004064AE 8BD0 mov edx, eax :004064B0 8D4DCC lea ecx, dword ptr [ebp-34] Basically, what all the above does is turn both the temporary values into wide char string and the two __vbaStrCat is used to concatenate the two temporary values with a hypen(-) in between them. The format of the concatenation is: temp1-temp2 String concatenation in VB is very easy, so I will not even show you how to do it. Let's trace further and you will come to this: :00406589 51 push ecx <-- our fake serial in wide char :0040658A 8B55CC mov edx, dword ptr [ebp-34] <-- move the concatenated string to edx :0040658D 52 push edx <-- push it for the __vbaStrCmp API function to use * Reference To: MSVBVM60.__vbaStrCmp, Ord:0000h | :0040658E FF1564104000 Call dword ptr [00401064] <-- compare two strings :00406594 85C0 test eax, eax <-- if equal eax=0, else eax=1 :00406596 0F85B9000000 jne 00406655 <-- jump to bad_boy if the two strings are not equal Oh, so the concatenated string is actually the valid serial. Good, we have got the full calculation routine now...(my example keygens and its sources for TrickSoft Level1 and Level2 CrackMes should be included together with this file, else mail me for it :) ... ) ------------------------------------------------------------------------- Final Thoughts ================ This is a very long essay. I don't want to include any useless text to waste your time anymore but there a few key things which I really need to paste in here. First, looking at the size of this essay, there will definitely be errors, so, do point out to me if there are serious flaws or just put up with it if it is a minor problem, ok? :D Secondly, as you have seen, to crack VB programs(at least for all Native code ones), you have to go inside the program's codes and not inside the VB dlls, you don't even(most of the time) have to go inside the dll as all parameters/arguments will be pushed from the program's code before the (almost)self-explainary VB APIs are called(only in some situation you need to really dive into the dll's codes :D ). Thirdly, you may not be very satisfied as to crack this I have used SmartCheck a little, I apologize for that and don't you worry, in the next essay I promise you a 100% crack using just SoftICE as our main tool... Well, whether or not we crack this crackme is not important at all here. I just want you to understand the approaches I have taken and the reasons for doing so and to learn from the methods I have shown you. However you must be clever enough to take other approaches and methods(based on our logics) when dealing with other targets. Ability to do so will make you a great cracker as tutorials I believe are not used to teach you how to crack only a specific target, they show you the methods, approaches and logics available while cracking and expect you to apply them on other targets with your own intelligence... Greetings to... Personal Messages: Hellforge:I'm back and is starting to rock again! :D TrickSoft:Nice crackmes, hope to crack new ones as soon as they are available. Btw, nice apps too on your site. :) +ORC, +HCU, Sandman, HarvestR, tKC, ytc_, Punisher, Kwai_Lo, TORN@DO, CrackZ, cLUSTER, LaZaRuS, mISTER fANATIC, yes123, BlackB, WhizKiD, Volatility, ACiD BuRN/analyst, Eternal Bliss, R!SC, Kwazy Webbit, +Mammon, Aesculapius, MisterE, Flu[x], Shadow, Falcon, ^tCM^, WaJ, egis, Borna Janes, CyberBlade, Sheep140/Reclaim, josephCo, Kathras, +tsehp, Predator, tscube, Carpathia, AB4DS(Death), douby, Steinowitz, Lord Soth, tHE EGOiSTE, seifer666, shade, Latigo, Dawai, Hypnoticz, Lucifer48, NoodleSpa, Bengaly, Mercution, NeuRaL_NoiSE, Fravia+, [dshadow], yAtEs, Duelist, Alpine, defiler, hutch, flag eRRatum, Nitrus, LiQUiD8, +Frog's Print, Muad`Dib, webmasta, Acid_Cool_178, Iczelion, nchanta, Razzia, wOODY^dRN, Warezpup, Bomber Monkey, XMen, Crudd, the snake, llama and other crackers, individuals and organisations who have helped me, either directly or indirectly. ManKind mankind001@bigfoot.com