CrackMe® Practices for Newbies
CrackMe 2 by CyberBlade [ReFleXZ '99]

Re: Joseph's Thread---The how I solved it
Tuesday, 20-Apr-99 03:34:19


    A solution to CyberBlade's Crackme2
    By
    Joseph
    April 19, 1999


    Introduction
    After finishing the first task for this project which was to find a way to defeat the SmartCheck zapping feature of this crackme, I turned my attention to the next and more difficult task, cracking the program, but where to start?
    Examining the program with W32asm I found reference to some interesting imported functions and they were: MSVBVM50!rtcMidCharVar and MSVBVM50!rtcAnsiValueBstr so I fired SoftIce, placed a bpx on each of these functions then exited SoftIce with Ctrl D and ran the target.

    Creating a big number
    Using Joseph for a user name and 123123 for a serial number I clicked the Check button to continue. As expected, SoftIce obligingly stopped at address 0f04306e which is the start of the function rtcMidCharVar. From there on I stepped through the program using F10 until I reached the top of the other function where I placed the second bpx, MSVBVM50!rtcAnsiValueBstr at address 0f03c89b. Obviously the program was bringing one character from the username at a time and doing some thing with it, a fact which did not concerned me very much at this point, thus I cleared the break point at MSVBVM50!rtcMidCharVar and kept the one I was at the moment. As before I stepped through the code F10 and continued to do so until I arrived at the top of the first function, MSVBVM50!rtcMidChaVar.

    Reducing the big number by division
    Now I have completed a full circle and learned that the program was bringing each character from the username and extracting the ASCII value and doing something with it. What was done with these numbers I was unable to determine thus far, so I decided to move on. With only one break point in place, and it is at the function called last, I continued to run the program using X or F5 counting the number of time the program stops at the break point. When the number of stops equaled the number of character in the username I entered, I continued with F10 until I reached a place that looked very interesting:

    :0F0FE0C3 8D1D7B13100F lea ebx, [MSVBVM50!__vbaVarDiv]
    :0F0FE0C9 EB16 jmp 0F0FE0E1

    It looks like some division is going to be done. Let us find out. So I single stepped and jumped to 0f0fe01 which looked very promising:

    :0F0FE0E1 0FBF3E movsx edi, word ptr [esi]
    :0F0FE0E4 03FD add edi, ebp
    :0F0FE0E6 57 push edi
    :0F0FE0E7 FFD3 call ebx
    :0F0FE0E9 57 push edi

    Ah! There is a call ebx. EBX was loaded with the address for vbaVarDiv, so let us go into this call and find out what is going on.

    MSVBVM50!__vbaVarDiv

    :0F10137B 55 push ebp
    :0F10137C 33C0 xor eax, eax

    OK, Here we are at the top of the divide function, let us step further

    :0F107FB9 E83770F1FF call MSVBVM50!__vbaR8Var
    :0F107FBE DD5DF4 fstp qword ptr [ebp-0C]
    :0F107FC1 57 push edi
    :0F107FC2 E82E70F1FF call MSVBVM50!__vbaR8Var
    :0F107FC7 DC7DF4 fdivr qword ptr [ebp-0C]
    :0F107FCA DD5E08 fstp qword ptr [esi+08]

    Lets of action is going on here, let us F10 through the call to MSVBVM50!__vbaR8Var and turn the WF on since we are dealing with real number. OH! Oh! What is this big number 74111115101112104 (the last 3 digits 104 are truncated to 096, but this should not concern us). This is the number which was extracted from the username Joseph with the ASCII value of each character appended to the one before it in this fashion: J = 74, o = 111, s = 115, e = 101, p = 112, and h = 104; thus our number is 74 111 115 101 112 104. The spaces are for clarity only. From now on I will refer to this number and its evolution as ‘BigNum'. Let us move on to the next call MSVBVM50!__vbaR8Var and notice a second number pop up. This number is 3.141592654. From now on let us refer to this number by its name ‘PI'. Immediately after the call there is an fdivr instruction which divides BigNum by PI and stores the result, so we have BigNum = BigNum / PI.
    Following the flow of the program will the same place from where the call was made, but before that 20 things happen to BigNum:
    First it goes through a fixing function which drops the fraction part and keeps the whole part of the number.
    Second, the number of digits in the number or its length is fetched and checked against the number 9. If the length of the BigNum is more then 9 more division will take place. Below is the fix function followed by the Len function.

    MSVBVM50!__vbaVarFix
    :0F10A43C 55 push ebp
    :0F10A43D 8B4C240C mov ecx, dword ptr [esp+0C]
    :0F10A441 8BEC mov ebp, esp

    This function finally ends at 0f0e1093 where the actual rounding or fixing takes place. Notice the instruction at 0f0e109c frndint where the actual action takes place.

    :0F0E1093 9B wait
    :0F0E1094 DFE0 fstsw ax
    :0F0E1096 D92D066A100F fldcw [0F106A06]
    :0F0E109C D9FC frndint
    :0F0E109E D92DB81F100F fldcw [0F101FB8]
    :0F0E10A4 C3 ret

    MSVBVM50!__vbaLenVar

    :0F106896 E85583FDFF call 0F0DEBF0
    :0F10689B 50 push eax
    :0F10689C 33C0 xor eax, eax

    The actual checking for length of 9 digits takes place some instructions after the return from the __vabLenVar function, at this location:

    :0F100580 8B550C mov edx, dword ptr [ebp+0C]
    :0F100583 8B4B08 mov ecx, dword ptr [ebx+08] ;Length of BigNum
    :0F100586 0FBF5208 movsx edx, word ptr [edx+08]; 9
    :0F10058A 3BD1 cmp edx, ecx
    :0F10058C 7F0F jg 0F10059D


    As I said earlier after all this is done we end up at:

    :0F0FE0E1 0FBF3E movsx edi, word ptr [esi]
    :0F0FE0E4 03FD add edi, ebp
    :0F0FE0E6 57 push edi
    :0F0FE0E7 FFD3 call ebx
    :0F0FE0E9 57 push edi

    Now is the time, if it was not done earlier, to place a bpx at 0ffe0e1 and another one at 0f0fe0e9, because we will be coming here many more time. We need to follow the call to the div function one more time and we will come to this location:

    :0F10145B DD4308 fld qword ptr [ebx+08]
    :0F10145E DC7708 fdiv qword ptr [edi+08]
    :0F101461 DD5E08 fstp qword ptr [esi+08]

    When we come here BigNum will be in the location pointed to by ebx+08, PI will be in location pointed to by edi+08 and the result of the division will be stored at location pointed to be esi+08.
    Once you came here and noticed what is going on continue by hitting F5 and the program will stop at 0f0fe0e9 where we place a break point, and another F5 will bring us to 0f0fe0e1 ready to make another call. Several calls will be made to the div function and by observing the ebx register you will be able to tell which function will be called. By the time the last call to the div function has been competed BigNum for the username Joseph will be 823162132 or 31107514h.

    Encode BigNum by Exoring it with another number:
    The last call to the div function will be immediately followed by a call to an Xor function where BigNum will be exored with 30f85678h resulting in BigNum 31990636. Here where this action takes place:

    MSVBVM50!__vbaVarXor

    :0F10B5FF 55 push ebp
    :0F10B600 8BEC mov ebp, esp
    :0F10B602 83EC08 sub esp, 00000008

    :0F10B63D 8B55F8 mov edx, dword ptr [ebp-08]
    :0F10B640 3355FC xor edx, dword ptr [ebp-04]

    Edx = 30f85678 and ebp-04 points to the location where BigNum is stored.

    Further encoding of BigNum by subtraction
    As if all this attempt to get us lost was not enough there is more action to be done to our BigNum. Now another number D8B3h 55475 will be subtracted from it to bring it to its final value, Here where that takes place:

    MSVBVM50!__vbaVarSub

    :0F1024CD 55 push ebp
    :0F1024CE 33C0 xor eax, eax
    :
    :0F102565 8BD6 mov edx, esi
    :0F102567 8BF9 mov edi, ecx
    :0F102569 2BD1 sub edx, ecx

    Here Ecx = 55475 and Edx = 31990636 and after this subtraction BigNum will equal 31935161.
    Is this the serial number we need? Almost but we have to find out, don't we? So let us hit F5 and go on.

    Another subtraction
    What is going on? Ebx has the address of the subtract function not a compare function as one would expect. OK. This is where CyberBlade plaid his biggest trick on the unaware. He does his comparison by subtraction. Let us go on and trace into the subtract function once more, and we will end at the location below:

    MSVBVM50!__vbaVarSub

    :0F1024CD 55 push ebp
    :0F1024CE 33C0 xor eax, eax

    :0F108B64 E88C64F1FF call MSVBVM50.__vbaR8Var
    :0F108B69 DD5DF4 fstp qword ptr [ebp-0C]
    :0F108B6C 66BE0500 mov si, 0005
    :0F108B70 57 push edi
    :0F108B71 E87F64F1FF call MSVBVM50.__vbaR8Var
    :0F108B76 DC6DF4 fsubr qword ptr [ebp-0C]
    :0F108B79 DD5B08 fstp qword ptr [ebx+08]

    Oh! Look what is taking place. The first call to MSVBVM50!__vbaR8Var brought the fake number I entered 123123 and the second call to the same function brought BigNum and they are subtracted at 0f08b76 fsubr qword ptr [ebp-0C] and the result if any is stored at [ebx+08]. Remember the fake number was stored at [ebp-0C] after it was fetched. Now we have found a fake number being compared with a real number using subtraction, so we must have a real number for username Joseph = 31935161. Let us go and try it.

    No dice yet
    Run the target enter Joseph as a username and 31935161 as a serial number and click the check Button. What? Sorry, wrong key. Something must be missing. Back to where we left.

    The final check
    Let us quickly come back to where we left at the end of the last subtraction and hit F5 which will bring us for the last time to the place where we have a break point following the call ebx.

    :0F0FE0E9 57 push edi

    And from there on let us step carefully through the code.

    This stepping will finally lead us to the place where an actual compare takes place, and here you have it:

    0F10719B 8B550C mov edx, dword ptr [ebp+0C]
    :0F10719E DB4208 fild dword ptr [edx+08]
    :0F1071A1 DC5308 fcom qword ptr [ebx+08]
    :0F1071A4 DD5DF8 fstp qword ptr [ebp-08]
    :0F1071A7 DFE0 fstsw ax
    :0F1071A9 9E sahf

    Here [EDX+08] contains a number equal the length of the username, and [EBX +8] contains the difference between the two numbers, the real and the fake, which were subtracted earlier. These 2 numbers are compared and if equal EAX will be mad = 00000000 otherwise EAX will = either FFFFFFFF which is -1 or 1 and both of these are no good.
    So what is the real serial number? It should be equal the final value of BigNum + a number = the number of characters in the username. Thus for Joseph the real serial number is 31935161 + 6 = 31935167.


    Translating all the above to simple Basic routines we may have the following:
    For x = 1 To Len(usrename$)
    BigNum = BigNum & Asc(Mid$(username$, x, 1))
    Next x

    While Len(BigNum) > 9
    BigNum = Int(BigNum / 3.141592654)
    Wend

    BigNum = (BigNum Xor &h30f85678) - 55475 + Len(username$)


    Happy reversing,

    Joseph


    Joseph


Message thread:

Joseph's Thread---Zap the Zapper (Joseph) (12-Apr-99 02:42:27)

Back to main board