Re: Joseph's Thread---The how I solved it Tuesday, 20-Apr-99 03:34:19
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:
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:
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.
OK, Here we are at the top of the divide function, let us step further
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.
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.
The actual checking for length of 9 digits takes place some instructions after the return from the __vabLenVar function, at this location:
As I said earlier after all this is done we end up at:
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:
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:
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:
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:
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.
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:
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.
Happy reversing, Joseph Joseph |
Joseph's Thread---Zap the Zapper (Joseph) (12-Apr-99 02:42:27) |