According to the well known "kill all the competitors" marketing policy, Micro$oft often gives away for free full working betas of many of its products. The idea behind this strategy is that the users will start using them, will get used to them and then, once the betas have expired, will buy the commercial releases. How can we call this? To me it looks like "software pushing"! So, if you want to enjoy (enjoy?!?) this betas for a time longer than that guys at Micro$oft planned for you, just keep reading...Eliminating the "cinderella" protection of Micro$osft FrontPage 97 beta by ViceVersa+, August 1997 Use your brain not your fingers! Introduction
__________________________________________________________________________ * Reference To: MFC40.MFC40:NoName0221, Ord:01E6h | :00455CD8 E83D110200 Call 00476E1A :00455CDD C645FC09 mov [ebp-04], 09 :00455CE1 8D4DEC lea ecx, dword ptr [ebp-14] * Reference To: MFC40.MFC40:NoName0221, Ord:01E6h | :00455CE4 E831110200 Call 00476E1A * Possible StringData Ref from Data Obj ->"Microsoft FrontPage 97" | :00455CE9 68789B4900 push 00499B78 :00455CEE 8D45CC lea eax, dword ptr [ebp-34] :00455CF1 C645FC0A mov [ebp-04], 0A * Possible Reference to String Resource ID=02102: "Your copy of the %1 beta has expired." | :00455CF5 6836080000 push 00000836 :00455CFA 50 push eax * Reference To: MFC40.MFC40:NoName0240, Ord:03F7h | :00455CFB E88C110200 Call 00476E8C * Possible StringData Ref from Data Obj ->"http://www.microsoft.com/frontpage" | :00455D00 68549B4900 push 00499B54 :00455D05 8D45EC lea eax, dword ptr [ebp-14] * Possible StringData Ref from Data Obj ->"Microsoft FrontPage 97" | :00455D08 68789B4900 push 00499B78 * Possible Reference to String Resource ID=02103: "Please visit your local reseller to purchase a copy of %1 or" | :00455D0D 6837080000 push 00000837 :00455D12 50 push eax * Reference To: MFC40.MFC40:NoName0452, Ord:03F8h | :00455D13 E86C160200 Call 00477384 * Possible StringData Ref from Data Obj ->" " | :00455D18 68E4364900 push 004936E4 :00455D1D 8D4DCC lea ecx, dword ptr [ebp-34] * Reference To: MFC40.MFC40:NoName0229, Ord:0344h | :00455D20 E825110200 Call 00476E4A :00455D25 8D45EC lea eax, dword ptr [ebp-14] :00455D28 8D4DCC lea ecx, dword ptr [ebp-34] :00455D2B 50 push eax * Reference To: MFC40.MFC40:NoName0233, Ord:0342h | :00455D2C E831110200 Call 00476E62 :00455D31 85FF test edi, edi :00455D33 7514 jne 00455D49 :00455D35 6A01 push 00000001 :00455D37 8B4DF0 mov ecx, dword ptr [ebp-10] * Possible StringData Ref from Data Obj ->"Symbols6" | :00455D3A 689C9B4900 push 00499B9C * Possible StringData Ref from Data Obj ->"Settings" | :00455D3F 68909B4900 push 00499B90 * Reference To: MFC40.MFC40:NoName0156, Ord:1629h | :00455D44 E8771C0200 Call 004779C0 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00455D33(C) | :00455D49 6A00 push 00000000 :00455D4B 8B45CC mov eax, dword ptr [ebp-34] :00455D4E 6A00 push 00000000 :00455D50 50 push eax * Reference To: MFC40.MFC40:NoName0239, Ord:0425h | :00455D51 E830110200 Call 00476E86 :00455D56 C645FC09 mov [ebp-04], 09 :00455D5A E817000000 call 00455D76 :00455D5F C645FC01 mov [ebp-04], 01 :00455D63 E816000000 call 00455D7E :00455D68 C645FC00 mov [ebp-04], 00 :00455D6C E849000000 call 00455DBA :00455D71 E9C5FAFFFF jmp 0045583B __________________________________________________________________________The red shows a call to a MFC40.DLL function. What is it? We will come back to it after a little theory...
__________________________________________________________________________ Call to WIN32 MessageBox Call to MFC MessageBox | | | | v | Display the messsage box Get hWnd of the associated window from the class data | | Resolve into a call to WIN32 MessageBox | | v Display the messsage box __________________________________________________________________________As you can see, especially when dealing with Micro$oft Windows, asm is not "all you have to know" for an effective cracking/reverse-engineering.
__________________________________________________________________________ Parameters lpszText Points to a CString object or null-terminated string containing the message to be displayed. lpszCaption Points to a CString object or null-terminated string to be used for the message-box caption. If lpszCaption is NULL, the default caption Error is used. nType Specifies the contents and behavior of the message box. __________________________________________________________________________According to the calling stack sequence the function we have recognized should get its the parameters like this:
lpszText = "Your version of ..." etc. lpszCaption = NULL nType = 0So, according to the documentation the dialog caption should have been "Error" since lpszCaption = NULL. In fact the caption of the nasty dialog shows the application name so it can't be that function. What's wrong? Look back at the nasty dialog, what is the caption? It shows the application name... here is the hint: the application name! We have to look for a MFC function that displays a dialog box but with a different behavior than CWnd::MessageBox.
_____________________________________________________________________ int AfxMessageBox( LPCTSTR lpszText, UINT nType = MB_OK, UINT nIDHelp = 0 ); int AFXAPI AfxMessageBox( UINT nIDPrompt, UINT nType = MB_OK, UINT nIDHelp = (UINT) 1 ); ... The functions AfxFormatString1 and AfxFormatString2 can be useful in formatting text that appears in a message box. Parameters lpszText Points to a CString object or null-terminated string containing the message to be displayed in the message box. nType The style of the message box. Apply any of the message-box styles to the box. nIDHelp The Help-context ID for the message; 0 indicates no Help context. nIDPrompt A unique ID used to reference a string in the string table. Remarks Displays a message box on the screen... __________________________________________________________________________The function we are interested in is the first one of the two. This is a widely used function in MFC programming because it displays an "application" message box. The message box has the name of the application as caption and usually behaves as a modal dialog. This is exactly what our nasty dialog does. Now the two NULL parameters make sense: OK button and no help available (as in fact is). But there is more. Look at the sentence I have colored in red. What are these two text formatting functions? Let's take a look (from MFC documentation):
__________________________________________________________________________ void AfxFormatString1( CString& rString, UINT nIDS, LPCTSTR lpsz1 ); Parameters rString A reference to a CString object that will contain the resultant string after the substitution is performed. nIDS The resource ID of the template string on which the substitution will be performed. lpsz1 A string that will replace the format characters %1 in the template string. Remarks Loads the specified string resource and substitutes the characters %1 for the string pointed to by lpsz1. The newly formed string is stored in rString. For example, if the string in the string table is File %1 not found, and lpsz1 is equal to C:\MYFILE.TXT, then rString will contain the string File C:\MYFILE.TXT not found. This function is useful for formatting strings sent to message boxes and other windows. If the format characters %1 appear in the string more than once, multiple substitutions will be made. __________________________________________________________________________Bingo! Doesn't it look familiar? That %1 in particular, acting as a parameter... where did we meet it before? It's right there in the code!
__________________________________________________________________________ * Reference To: MFC40.MFC40:NoName0401, Ord:09FDh | :00455B63 E8EA160200 Call 00477252 :00455B68 50 push eax :00455B69 8D4DD4 lea ecx, dword ptr [ebp-2C] :00455B6C 56 push esi :00455B6D 51 push ecx :00455B6E 6A02 push 00000002 * Possible Reference to Dialog: DialogID_009F, CONTROL_ID:0400, "" | :00455B70 6800040000 push 00000400 * Reference To: KERNEL32.GetDateFormatA, Ord:00C8h | :00455B75 FF15B4D54900 Call dword ptr [0049D5B4] :00455B7B 6AFF push FFFFFFFF :00455B7D 8D4DCC lea ecx, dword ptr [ebp-34] * Reference To: MFC40.MFC40:NoName0398, Ord:1343h | :00455B80 E8BB160200 Call 00477240 :00455B85 8D4DE4 lea ecx, dword ptr [ebp-1C] * Reference To: MFC40.MFC40:NoName0221, Ord:01E6h | :00455B88 E88D120200 Call 00476E1A :00455B8D C645FC06 mov [ebp-04], 06 :00455B91 8B45CC mov eax, dword ptr [ebp-34] :00455B94 8D4DE4 lea ecx, dword ptr [ebp-1C] :00455B97 50 push eax __________________________________________________________________________Looks like a good starting point. Let's look to its definition (from WIN32 API reference):
__________________________________________________________________________ The GetDateFormat function formats a date as a date string for a specified locale. The function formats either a specified date or the local system date. int GetDateFormat( LCID Locale, // locale for which date is to be formatted DWORD dwFlags, // flags specifying function options CONST SYSTEMTIME *lpDate, // date to be formatted LPCTSTR lpFormat, // date format string LPTSTR lpDateStr, // buffer for storing formatted string int cchDate // size of buffer ); __________________________________________________________________________There it is! If it takes a date (pointer to a SYSTEMTIME structure) as a parameter this means that somewhere before this call the date is read. But where? The date is the 3rd parameter and must be a pointer (the address of a memory location). Remember that the parameters are pushed on the stack in reverse order. Now from the call to GetDateFormat count three pushes up. We find push ecx. Two rows before there is a lea ecx, dword ptr [ebp-2C]. So the date is stored in [ebp-2C]. Good to know. Keep going back along the code an look for the any occurrence of [ebp-2C]. You will find the following code snippet:
__________________________________________________________________________ * Reference To: MFC40.MFC40:NoName0154, Ord:0BFBh | :00455A9A E82D1F0200 Call 004779CC :00455A9F 8BF8 mov edi, eax :00455AA1 83EC04 sub esp, 00000004 :00455AA4 8D45E8 lea eax, dword ptr [ebp-18] :00455AA7 8965CC mov dword ptr [ebp-34], esp :00455AAA 50 push eax :00455AAB 8B4DCC mov ecx, dword ptr [ebp-34] :00455AAE E82D030000 call 00455DE0 :00455AB3 8D8D64FFFFFF lea ecx, dword ptr [ebp+FFFFFF64] :00455AB9 E832030000 call 00455DF0 :00455ABE 85C0 test eax, eax :00455AC0 0F850F020000 jne 00455CD5 :00455AC6 85FF test edi, edi :00455AC8 0F8507020000 jne 00455CD5 :00455ACE 83EC04 sub esp, 00000004 :00455AD1 8D45D0 lea eax, dword ptr [ebp-30] :00455AD4 8965CC mov dword ptr [ebp-34], esp :00455AD7 50 push eax :00455AD8 8B4DCC mov ecx, dword ptr [ebp-34] :00455ADB E800030000 call 00455DE0 :00455AE0 8D8D64FFFFFF lea ecx, dword ptr [ebp+FFFFFF64] :00455AE6 E805030000 call 00455DF0 :00455AEB 85C0 test eax, eax :00455AED 0F84D1000000 je 00455BC4 :00455AF3 668975D4 mov word ptr [ebp-2C], si :00455AF7 668975D6 mov word ptr [ebp-2A], si :00455AFB 668975D8 mov word ptr [ebp-28], si :00455AFF 668975DA mov word ptr [ebp-26], si :00455B03 56 push esi :00455B04 668975DC mov word ptr [ebp-24], si :00455B08 8D4DE8 lea ecx, dword ptr [ebp-18] :00455B0B 668975DE mov word ptr [ebp-22], si :00455B0F 668975E0 mov word ptr [ebp-20], si :00455B13 668975E2 mov word ptr [ebp-1E], si * Reference To: MFC40.MFC40:NoName0155, Ord:0B59h | :00455B17 E8AA1E0200 Call 004779C6 :00455B1C 8B4014 mov eax, dword ptr [eax+14] :00455B1F 56 push esi :00455B20 66056C07 add ax, 076C :00455B24 8D4DE8 lea ecx, dword ptr [ebp-18] :00455B27 668945D4 mov word ptr [ebp-2C], ax * Reference To: MFC40.MFC40:NoName0155, Ord:0B59h | :00455B2B E8961E0200 Call 004779C6 :00455B30 8B4010 mov eax, dword ptr [eax+10] :00455B33 56 push esi :00455B34 6640 inc ax :00455B36 8D4DE8 lea ecx, dword ptr [ebp-18] :00455B39 668945D6 mov word ptr [ebp-2A], ax ... there are some more lines in between ... * Reference To: MFC40.MFC40:NoName0221, Ord:01E6h | :00455B88 E88D120200 Call 00476E1A :00455B8D C645FC06 mov [ebp-04], 06 :00455B91 8B45CC mov eax, dword ptr [ebp-34] :00455B94 8D4DE4 lea ecx, dword ptr [ebp-1C] :00455B97 50 push eax * Possible StringData Ref from Data Obj ->"Microsoft FrontPage 97" | :00455B98 68789B4900 push 00499B78 * Possible Reference to String Resource ID=02104: "This beta copy of %1 will expire on %2" | :00455B9D 6838080000 push 00000838 :00455BA2 51 push ecx * Reference To: MFC40.MFC40:NoName0452, Ord:03F8h | :00455BA3 E8DC170200 Call 00477384 :00455BA8 56 push esi :00455BA9 8B4DE4 mov ecx, dword ptr [ebp-1C] :00455BAC 56 push esi :00455BAD 51 push ecx __________________________________________________________________________Look at the first occurrence from the bottom. The value in [eax+14] in moved into eax. Then the value 076C (1900 decimal) it's added to it and everything is stored back to [ebp-2C]. So it's calculating the current year on the basis of a function that returns it on as a difference from 1900. The only function I know that works like this is localtime but this function needs as input a value returned from a call to the time function.
__________________________________________________________________________ * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00455AED(C) | :00455BC4 8D8D60FEFFFF lea ecx, dword ptr [ebp+FFFFFE60] * Reference To: fp20utl.fp20utl:NoName0013, Ord:0036h | :00455BCA FF1530E44900 Call dword ptr [0049E430] :00455BD0 8B75F0 mov esi, dword ptr [ebp-10] :00455BD3 8B45EC mov eax, dword ptr [ebp-14] :00455BD6 C645FC07 mov [ebp-04], 07 :00455BDA 81C630010000 add esi, 00000130 :00455BE0 8B4820 mov ecx, dword ptr [eax+20] :00455BE3 51 push ecx :00455BE4 8D8D60FEFFFF lea ecx, dword ptr [ebp+FFFFFE60] * Reference To: fp20utl.fp20utl:NoName0014, Ord:049Bh | :00455BEA FF1534E44900 Call dword ptr [0049E434] :00455BF0 50 push eax :00455BF1 8BCE mov ecx, esi * Reference To: MFC40.MFC40:NoName0220, Ord:02FAh | :00455BF3 E81C120200 Call 00476E14 :00455BF8 8B06 mov eax, dword ptr [esi] :00455BFA 8378F800 cmp dword ptr [eax-08], 00000000 :00455BFE 7534 jne 00455C34 :00455C00 B801000000 mov eax, 00000001 :00455C05 8B4DF0 mov ecx, dword ptr [ebp-10] :00455C08 8845FC mov byte ptr [ebp-04], al :00455C0B 898134010000 mov dword ptr [ecx+00000134], eax :00455C11 E8B3000000 call 00455CC9 :00455C16 C645FC00 mov [ebp-04], 00 :00455C1A E89B010000 call 00455DBA :00455C1F E917FCFFFF jmp 0045583B * Referenced by a CALL at Address: |:00455BB6 | :00455C24 8D4DE4 lea ecx, dword ptr [ebp-1C] * Reference To: MFC40.MFC40:NoName0217, Ord:02C2h | :00455C27 E9D6110200 Jmp 00476E02 * Referenced by a CALL at Address: |:00455BBF | :00455C2C 8D4DCC lea ecx, dword ptr [ebp-34] * Reference To: MFC40.MFC40:NoName0217, Ord:02C2h | :00455C2F E9CE110200 Jmp 00476E02 _________________________________________________________________________As you can see, it leads to a section of code that does something and then jumps away from all the nasty dialog display etc. So we probably want that jump to occur. But wait a moment. If that jump is executed there is no nasty dialog at all but if it's not executed we should get a dialog saying that our copy of FrontPage will expire on such and such date. Anyway what we get is a nasty dialog saying that our copy has already expired. This portion of code has never being executed because of a previous jump that leads to the "your copy has expired" dialog. This condition should be date related too according to a scheme like this:
Get Current Date Get Expiring Date (fixed) IF Current Date > Expiring Date? THEN MessageBox( "Your copy has expired!" ); ELSE MessageBox( "Your copy will expire on such and such day" );There should also be some kind of checking for bad lamers taking their clock back. Anyway, let's look for a conditional jump "date related" that takes us to the "Your copy has expired!" dialog.
__________________________________________________________________________ :00455AA1 83EC04 sub esp, 00000004 :00455AA4 8D45E8 lea eax, dword ptr [ebp-18] :00455AA7 8965CC mov dword ptr [ebp-34], esp :00455AAA 50 push eax :00455AAB 8B4DCC mov ecx, dword ptr [ebp-34] :00455AAE E82D030000 call 00455DE0 :00455AB3 8D8D64FFFFFF lea ecx, dword ptr [ebp+FFFFFF64] :00455AB9 E832030000 call 00455DF0 :00455ABE 85C0 test eax, eax :00455AC0 0F850F020000 jne 00455CD5 :00455AC6 85FF test edi, edi :00455AC8 0F8507020000 jne 00455CD5 ... and after few lines ... :00455ACE 83EC04 sub esp, 00000004 :00455AD1 8D45D0 lea eax, dword ptr [ebp-30] :00455AD4 8965CC mov dword ptr [ebp-34], esp :00455AD7 50 push eax :00455AD8 8B4DCC mov ecx, dword ptr [ebp-34] :00455ADB E800030000 call 00455DE0 :00455AE0 8D8D64FFFFFF lea ecx, dword ptr [ebp+FFFFFF64] :00455AE6 E805030000 call 00455DF0 :00455AEB 85C0 test eax, eax :00455AED 0F84D1000000 je 00455BC4 __________________________________________________________________________Same calling sequence, same calling scheme but the pushed parameter eax is different in the two calls. At this point we should probably take a look at the two called functions:
__________________________________________________________________________ * Referenced by a CALL at Addresses: |:00455AAE , :00455ADB | :00455DE0 8B442404 mov eax, dword ptr [esp+04] :00455DE4 8B10 mov edx, dword ptr [eax] :00455DE6 8BC1 mov eax, ecx :00455DE8 8911 mov dword ptr [ecx], edx :00455DEA C20400 ret 0004 and * Referenced by a CALL at Addresses: |:00455AB9 , :00455AE6 | :00455DF0 8B442404 mov eax, dword ptr [esp+04] :00455DF4 3901 cmp dword ptr [ecx], eax :00455DF6 B801000000 mov eax, 00000001 :00455DFB 7D02 jge 00455DFF :00455DFD 33C0 xor eax, eax * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00455DFB(C) | :00455DFF C20400 ret 0004 __________________________________________________________________________So the first one is a kind of swapping function. The second one is a kind of boolean comparison function. It compares two quantities, one passed as a parameter on the stack and the other pointed by ecx and returns 1 if the first one is less than the second one, otherwise it returns 0. edi, that is tested after eax in the caller function, is not involved here so it must have been set somewhere before these calls (in fact there is mov edi,eax up there).
E832030000 85C0 0F850F020000 85FF 0F8507020000 -- -- \ \ change to 84 (je) change to 84 (je)and change the two bytes as described. Just to be sure we have also changed the jne that comes after the test edi, edi. Now let's run it and see what happens.
E805030000 85C0 0F84D1000000 -- \ change to 85 (jne)and change the byte as described. Now run the program and...
__________________________________________________________________________ :00455A54 8D8564FFFFFF lea eax, dword ptr [ebp+FFFFFF64] :00455A5A 50 push eax * Reference To: MFC40.MFC40:NoName0152, Ord:0CFEh | :00455A5B E8781F0200 Call 004779D8 :00455A60 6AFF push FFFFFFFF :00455A62 56 push esi :00455A63 56 push esi :00455A64 8D4DD0 lea ecx, dword ptr [ebp-30] :00455A67 56 push esi :00455A68 6A01 push 00000001 :00455A6A 6A01 push 00000001 :00455A6C 68CD070000 push 000007CD __________________________________________________________________________It's just few line before the test eax, eax and it involves the parameter [ebp+FFFFFF64], the same that you can see in the calls to the "comparison" function (call 00455DF0). How do I know? Well, if you trace into this call with Sice you will see that there is a call to the time function (it's part of the Micro$oft Visual C++ run time library). This function, in turn, calls GetLocalTime. There it is! It's hidden inside a double shell. Now that you know where the call to the "get time" function hides, you can try to properly decipher the code that follows it. Let me know if you find something interesting!
My "motto" is : Use your brain not your fingers! ViceVersa+ August, 8th 1997
(c) ViceVersa 1997. All rights reserved