MixVibes: Reversing A Menu Disabled Target (and more)... by Clandestiny published by +Tsehp Oct 2001 |
Target: mixvibespro223.zip | Location: http://www.mixvibes.com/mixvibes/download/mixvibespro223.zip | Size: 853 KB |
Introduction: |
The Project: |
Tools: |
The Essay |
+++++++++++++++++++ MENU INFORMATION ++++++++++++++++++ Number of Menus = 4 (decimal) MenuID_0064 File {Popup} New Ctrl+N [ID=E100h] Open... Ctrl+O [ID=E101h] Save Ctrl+S [ID=E103h] Save As... [ID=E104h] Import file [ID=1F40h] Export file [ID=1F41h] Scan [ID=1F49h] Create Autorun [ID=7D2Ch] Recent File [ID=E110h]Note:
00114A90 0000 0000 1000 2600 4600 6900 6C00 6500 ......&.F.i.l.e. 00114AA0 0000 0000 00E1 2600 4E00 6500 7700 0900 ......&.N.e.w... 00114AB0 4300 7400 7200 6C00 2B00 4E00 0000 0000 C.t.r.l.+.N..... 00114AC0 01E1 2600 4F00 7000 6500 6E00 2E00 2E00 ..&.O.p.e.n..... 00114AD0 2E00 0900 4300 7400 7200 6C00 2B00 4F00 ....C.t.r.l.+.O. 00114AE0 0000 0000 03E1 2600 5300 6100 7600 6500 ......&.S.a.v.e. 00114AF0 0900 4300 7400 7200 6C00 2B00 5300 0000 ..C.t.r.l.+.S... 00114B00 0000 04E1 2600 5300 6100 7600 6500 2000 ....&.S.a.v.e. . 00114B10 4100 7300 2E00 2E00 2E00 0000 0000 401F A.s...........@. 00114B20 2600 4900 6D00 7000 6F00 7200 7400 2000 &.I.m.p.o.r.t. . 00114B30 6600 6900 6C00 6500 0000 0000 411F 2600 f.i.l.e.....A.&. 00114B40 4500 7800 7000 6F00 7200 7400 2000 6600 E.x.p.o.r.t. .f.Note:
From the Win32 Programmers API Reference: The EnableMenuItem function enables, disables, or grays the specified menu item. BOOL EnableMenuItem( HMENU hMenu, // handle to menu UINT uIDEnableItem, // menu item to enable, disable, or gray UINT uEnable // menu item flags Menu Item Flags: MF_ENABLED (00h) - Indicates that the menu item is enabled and restored from a grayed state so that it can be selected. MF_DISABLED (03h) - Indicates that the menu item is disabled, but not grayed, so it cannot be selected. MF_GRAYED (01h) - Indicates that the menu item is disabled and grayed so that it cannot be selected. |
:0049A76A 8B4C240C mov ecx, dword ptr [esp+0C] :0049A76E F7D9 neg ecx :0049A770 1BC9 sbb ecx, ecx :0049A772 83E1FD and ecx, FFFFFFFD :0049A775 83C103 add ecx, 00000003 :0049A778 80CD04 or ch, 04 :0049A77B 51 push ecx //save the menu item flags :0049A77C FF7608 push [esi+08] //save the menu item location :0049A77F FF7004 push [eax+04] //save handle to menu * Reference To: USER32.EnableMenuItem, Ord:00B0h | :0049A782 FF150C264C00 Call dword ptr [004C260C] //call EnableMenuItem :0049A788 EB53 jmp 0049A7DDLooking at this code and tracing through it in SoftIce a couple of times you can see the menu item flag in ecx is 403 for disabled and 400 for enabled menu items. For the items to be enabled, this flag should always be 400 (our flag is only the lower 2 bytes) and we can do a patch at:
:0049A778 mov cl,0
:0049A77A nop
:0049A77B push ecx
Now the program will always pass 400 (the active flag) to the EnableMenuItem API. If you go back and check the target, all of the menu items are ungreyed and active. Unfortunately, this is the point where we make the distinction between an "active" menu item and an "enabled" menu item since clicking on our newly activated menu items does nothing at all. Having explored the simple options and done the preliminary work with EnableMenuItem, we get to the hard part of function enabling our menu items. Once again, we can choose to rule out all simple solutions by doing a search in Wdasm for the MenuItem ID's hoping perhaps it will turn up some type of direct comparison. And though it is a valid approach, this type search won't turn up anything for MixVibes which seems to reference all of its menu items indirectly using the GetMenuID function. Having exhausted the obvious, we are now going to make use of the Windows message WM_COMMAND. Basically, Windows sits in an infinite loop waiting for various messages. The message, WM_COMMAND is the message sent when a menu item is clicked and we need to intercept it so we can find out where the program branches in response to a specific menu item being clicked.
First, find the class name of the window using a utility like Windowse. In this case the class is Afx:400000:b:1466. Now type TASK in SoftIce to see the task list. You will find the taskname of mixvibespro.exe to be MIXVIBES. Now type HWND MIXVIBES. From the list you need to pick out the hwnd of the Afx:400000:b:1466 class. Once you have this, set a message breakpoint in Sice: BMSG (hwnd class) WM_COMMAND where (hwnd class) is the hwnd you just found. SoftIce will break when you attempt to select a menu item. Now, in order to get back into MixVibe's code, we'll borrow Lord Soth's trick of setting a breakpoint on K32Thk1632Prolog: BPX K32THK1632PROLOG. Press F5 and you'll land inside the K32THK1632PROLOG function. Press F11 to return and you'll be inside of some Kernel32 dll code here:
:BFF94402 CALL KERNEL32!K32THK1632PROLOG
:BFF94407 CALL BFF735FD
:BFF9440C CALL KERNEL32!K32THK1632EPILOG
F8 step into the middle funcion CALL BFF735FD. You'll now be looking for a far call so trace forward a bit until you come to CALL GS:[esi + 08]. Trace into this call and you'll be back in our target's code.
Now, that we are back into MixVibes code after a menu item has been selected, we are looking for a type of reg / unreg flag comparison that will determine weather or not to enable our menu item. Unfortunately for the cracker, the code from here on out becomes a jumbled maze of jumps and calls possessing very few "landmarks" to ease our search. And though the exact path to this critical flag will be different for every menu disabled target, we will borrow from Kayaker's experience in our approach. Indeed, he has concluded several interesting tips for finding ones way to this point in a menu disabled target.
Tips for finding the critical flag:
:004969A0 55 push ebp :004969A1 8BEC mov ebp, esp :004969A3 817D0C60030000 cmp dword ptr [ebp+0C], 00000360 :004969AA 7505 jne 004969B1 :004969AC 6A01 push 00000001 :004969AE 58 pop eax :004969AF EB1A jmp 004969CB * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004969AA(C) | :004969B1 FF7508 push [ebp+08] :004969B4 E863FFFFFF call 0049691C :004969B9 FF7514 push [ebp+14] :004969BC FF7510 push [ebp+10] :004969BF FF750C push [ebp+0C] :004969C2 FF7508 push [ebp+08] :004969C5 50 push eax :004969C6 E8BDFCFFFF call 00496688 //step into direct call before ret * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004969AF(U) | :004969CB 5D pop ebp :004969CC C21000 ret 0010Now, trace until you see the first indirect call, [eax+A0] and then F8 step into it.
:00496688 B840F94B00 mov eax, 004BF940 :0049668D E8FE92FEFF call 0047F990 :00496692 51 push ecx :00496693 83EC30 sub esp, 00000030 : : : * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:004966F4(C) | :00496704 FF7518 push [ebp+18] :00496707 8B07 mov eax, dword ptr [edi] :00496709 8BCF mov ecx, edi :0049670B FF7514 push [ebp+14] :0049670E 56 push esi :0049670F FF90A0000000 call dword ptr [eax+000000A0] //step into first indirect callYou get the idea... As you continue to trace through the code you will step into each of the following calls:
:004978C1 CALL [eax + A4]
:00497912 CALL [eax + 80]
:004AC153 CALL 00497E88
:00497EC1 CALL [eax + 14]
:004ACB03 CALL [edx + 14]
:0049DDDE CALL [eax + 14]
:0049FDB9 CALL [eax + 14]
:004A183A CALL 0049A449
:0049A51B CALL [eax + 30]
:0049A54E CALL 0049A561
:0049A628 CALL [ebp + 14] // the magic location !!!
Finally after you F8 step into 0049A54E CALL 0049A561, you will notice a notice a bunch of indirect parameters being pushed:
:0049A53B push [ebp+14]
:0049A53E push [eax+10]
:0049A541 push [ebp+10]
:0049A544 push [eax+14]
:0049A547 push [ebp+0C]
:0049A54A push [ebp+08]
:0049A54D push edi
:0049A54E call 0049A561
:0045AF20 8B8134080000 mov eax, dword ptr [ecx+00000834] // reg flag :0045AF26 85C0 test eax, eax // is the flag == 0 ? :0045AF28 750A jne 0045AF34 // regged if eax != 0 :0045AF2A 8B4C2404 mov ecx, dword ptr [esp+04] //not regged if eax=0 :0045AF2E 6A00 push 00000000 :0045AF30 8B01 mov eax, dword ptr [ecx] :0045AF32 FF10 call dword ptr [eax] * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0045AF28(C) | :0045AF34 C20400 ret 0004From the above code you can see eax holds the flag that determines weather or not our program is registered. If this flag = 0 (unregistered), the program will proceed to disable and grey the selected menu item. However, if the flag is not zero the program will ret and continue on to the correct menu item function. Now knowing that we want this flag not equal to 0, we need only to apply the patch in our favorite hex editor.
Well, there you have it: how to crack MixVibes using windows messages. This was my first approach to cracking this target and there is much to learn from it. Nevertheless, in retrospect, it was not the best approach. Unless you are *very* familiar with the windows message structures, there is way too much unmarked code to trace and it becomes very easy to get lost. Fortunately, there is another way to crack this target and IMO, it's a lot easier to follow than the WM_COMMAND route...
Now, just a couple of quick notes about this feature:
004AC599:LoadMenuA(HANDLE:00400000,LPSTR:00000064) 004AC59F:LoadMenuA = 5A4 004A82AF:GetSystemMenu(HWND:00001250,BOOL:00000000) 004A82B5:GetSystemMenu = 638 004AC831:GetMenu(HWND:00000438) 004AC837:GetMenu = 5A4 : : : 004AD239:GetMenuItemID(HANDLE:00000440,DWORD:00000002) 004AD23B:GetMenuItemID E103 0049A782:EnableMenuItem(HANDLE:00000440,DWORD:00000002,DWORD:00000000) 0049A788:EnableMenuItem = FFFFFFFF 004AD2A4:GetMenuItemCount(HANDLE:00000440)We'll use the log to choose our breakpoints for the backtrace. Right off, EnableMenuItem stands out as a good choice since we know there must be some prior condition which determines whether or not to disable our menu item. It will be the 1st boundary of our trap and we now look at the API calls above EnableMenuItem in order to define the second boundary. Directly above is the GetMenuItemID API. Like its name implies, this function retrieves the menu ID so the program can determine what item was selected. Thinking about the functions of these 2 API's, it seems likely that the program performs a check sometime *after* GetMenuItemID determines which item was selected, but *before* EnableMenuItem disables the selection. Therefore, we can conclude that GetMenuItemID would be a good choice for the second boundary of the trap. Having determined this, we'll go ahead and set the breakpoints:
BPX GETMENUITEMID IF *(ss:esp+8) == 2
BPX ENABLEMENUITEM IF *(ss:esp+8) == 2
Both of these functions accept the menu item position as their second parameter hence we can pinpoint the exact menu item for Sice to break on (ie. if the 2nd parameter pushed on the stack = the position of the menu item (for Save=2 and remember we start counting @ 0).
After setting the breakpoints, we'll set up the trace. First get the module handle for mixvibes using the MOD command in Sice.
MOD MIXVIBES (task name)
You'll find the module handle to be MIXVIBESPRO. Now, set a range breakpoint of the form:
BPRW MIXVIBESPRO T
This sets up the backtrace. Now, exit SoftIce and select the Save menu item. Sice will break at our first breakpoint (the GetMenuItemID). Press F5 and it will break again at the second EnableMenuItem API. This fills up the backtrace range buffer with the program instructions between these 2 API's and hopefully trapped the flag that determines whether the menu items are enabled. You can see the results of the backtrace using the SHOW command in Sice but before doing so it is a good idea turn off the register, code, and data windows using the WC, WR, and WD commands.
SHOW 1 will display the last command executed in the trace and you may use the arow keys to scrool up through the instructions.
Note: If you have IceDump 6 installed, you can do a nice screendump of your trace using /SCREENDUMP "path".txt where "path" specifies the path to the filename on your hard drive.
Here is an excerpt from my trace:
000020 017F:0049A5CE 0F878E000000 JA 0049A662 00001F 017F:0049A5D4 FF248568A64900 JMP [EAX*4+0049A668] 00001E 017F:0049A621 8B7518 MOV ESI,[EBP+18] 00001D 017F:0049A624 8B4D08 MOV ECX,[EBP+08] 00001C 017F:0049A627 56 PUSH ESI 00001B 017F:0049A628 FF5514 CALL [EBP+14] 00001A 017F:0045AF20 8B8134080000 MOV EAX,[ECX+00000834] 000019 017F:0045AF26 85C0 TEST EAX,EAX // the magic flag !!! 000018 017F:0045AF28 750A JNZ 0045AF34 000017 017F:0045AF2A 8B4C2404 MOV ECX,[ESP+04] 000016 017F:0045AF2E 6A00 PUSH 00 000015 017F:0045AF30 8B01 MOV EAX,[ECX] 000014 017F:0045AF32 FF10 CALL [EAX] 000013 017F:0049A759 56 PUSH ESI 000012 017F:0049A75A 8BF1 MOV ESI,ECX 000011 017F:0049A75C 57 PUSH EDI 000010 017F:0049A75D 8B460C MOV EAX,[ESI+0C] 00000F 017F:0049A760 85C0 TEST EAX,EAX 00000E 017F:0049A762 7426 JZ 0049A78A 00000D 017F:0049A764 837E1000 CMP DWORD PTR [ESI+10],00 00000C 017F:0049A768 757A JNZ 0049A7E4 00000B 017F:0049A76A 8B4C240C MOV ECX,[ESP+0C] 00000A 017F:0049A76E F7D9 NEG ECX 000009 017F:0049A770 1BC9 SBB ECX,ECX 000008 017F:0049A772 83E1FD AND ECX,-03 000007 017F:0049A775 83C103 ADD ECX,03 000006 017F:0049A778 B100 MOV CL,00 000005 017F:0049A77A 90 NOP 000004 017F:0049A77B 51 PUSH ECX 000003 017F:0049A77C FF7608 PUSH DWORD PTR [ESI+08] 000002 017F:0049A77F FF7004 PUSH DWORD PTR [EAX+04] 000001 017F:0049A782 FF150C264C00 CALL [USER32!EnableMenuItem]Looking backwards from the EnableMenuItem function, you'll quickly see 2 compare / jumps :
:and
00001A 017F:0045AF20 8B8134080000 MOV EAX,[ECX+00000834]
00000D 017F:0049A764 837E1000 CMP DWORD PTR [ESI+10],00
00000C 017F:0049A768 757A JNZ 0049A7E4
000019 017F:0045AF26 85C0 TEST EAX,EAX // the magic reg / unreg flag !!!
Both being so close to the EnableMenuItem function and being of the form cmp memory location, 0 makes them suspect. Having already cracked this once before we know that the test eax,eax is the magic flag. Nevertheless, even if you didn't know this you could easily set bpx's on both instructions and bpm's on the memory locations being compared to narrow it down. IMO, the uses of Sice's backtrace range function cannot be overestimated...and it goes to show that RTFM about your tools is good advice :-)
BPMD 0050F8A4 Press F5 and SoftIce will break for the first out of a total of 4 times.
Break # 1:
:00459A33 89BE34080000 mov dword ptr [esi+00000834], edi // reg flag :00459A39 89BE3C080000 mov dword ptr [esi+0000083C], edi :00459A3F 89BE44080000 mov dword ptr [esi+00000844], edi :00459A45 89864C080000 mov dword ptr [esi+0000084C], eax :00459A4B 898650080000 mov dword ptr [esi+00000850], eax :00459A51 89BEC0080000 mov dword ptr [esi+000008C0], edi :00459A57 89BE34090000 mov dword ptr [esi+00000934], ediHere it appears to be loading the flag into memory. Well, lets continue and see what else we find...Press F5. Break #2:
:00459DA6 83BA3408000000 cmp dword ptr [edx+00000834], 00000000 //reg flag :00459DAD 0F8560010000 jne 00459F13 :00459DB3 6A00 push 00000000 : : : :00459E41 E8BA0B0000 call 0045AA00 :00459E46 8B55A0 mov edx, dword ptr [ebp-60] :00459E49 895584 mov dword ptr [ebp-7C], edx :00459E4C 8D4D90 lea ecx, dword ptr [ebp-70] :00459E4F E82C0B0000 call 0045A980 :00459E54 894588 mov dword ptr [ebp-78], eax :00459E57 8D8D28FFFFFF lea ecx, dword ptr [ebp+FFFFFF28] :00459E5D E8D5FD0300 call 00499C37 //show nag screenContinue tracing a little bit after the second break and you'll see the nag screen pop up at call 00499C37. Once again, we want the flag [edx + 834] != to 0 in order to bypass it. Change the jne to jmp and the nag removal mission is acomplished, but we'll still examine the other locations where this flag is checked for curiosity's sake. F5 again and you'll be at the third break.
Break #3:
:00459EDF 83B83408000000 cmp dword ptr [eax+00000834], 00000000b //reg flag :00459EE6 751C jne 00459F04 :00459EE8 8B4DA0 mov ecx, dword ptr [ebp-60] :00459EEB 83C101 add ecx, 00000001 :00459EEE 51 push ecx * Possible StringData Ref from Data Obj ->"uTu" | :00459EEF 680CED4F00 push 004FED0C * Possible StringData Ref from Data Obj ->"Settings" | :00459EF4 680CD14F00 push 004FD10C :00459EF9 8B8D88FDFFFF mov ecx, dword ptr [ebp+FFFFFD88] :00459EFF E851930400 call 004A3255The function of this one isn't obvious, but for consistancy we should patch it too!
Break #4:
:0045AF20 8B8134080000 mov eax, dword ptr [ecx+00000834] // reg flag :0045AF26 85C0 test eax, eax // is the flag == 0 ? :0045AF28 750A jne 0045AF34 // regged if eax != 0 :0045AF2A 8B4C2404 mov ecx, dword ptr [esp+04] //not regged if eax=0 :0045AF2E 6A00 push 00000000 :0045AF30 8B01 mov eax, dword ptr [ecx] :0045AF32 FF10 call dword ptr [eax]This little snippet of code should look familiar :-) It's just the first flag we found and used to reenable the menu items. Interestingly, we don't get to the time limit reg flag this way. Possibly this is because it doesn't check until the 30 minutes have elapsed. Rather than wait around to see if Sice breaks in the next 30 minutes, we'll find it another way...
String Resource ID=61219: "unregistred version 30'' limited time thanks for trying MixV"
Clicking on this reference will land you at 004256E in MixVibes code:
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:00442528(C), :0044252C(C) | :0044253F 8B86A0000000 mov eax, dword ptr [esi+000000A0] :00442545 85C0 test eax, eax :00442547 7540 jne 00442589 :00442549 8B8134080000 mov eax, dword ptr [ecx+00000834] :0044254F 85C0 test eax, eax :00442551 7536 jne 00442589 :00442553 8B8E18080000 mov ecx, dword ptr [esi+00000818] :00442559 81C140771B00 add ecx, 001B7740 :0044255F 3BE9 cmp ebp, ecx :00442561 7626 jbe 00442589 :00442563 8BCE mov ecx, esi :00442565 E8F68DFFFF call 0043B360 :0044256A 6AFF push FFFFFFFF :0044256C 6A10 push 00000010 * Possible Reference to String Resource ID=61219: "unregistred version 30'' limited time thanks for trying MixV" | :0044256E 6823EF0000 push 0000EF23 :00442573 E866F40500 call 004A19DELooking above this reference, you'll see several suspicious jumps (which all bypass the time limit message, BTW). The 1st one (jbe 00442589) will clearly bypass the time limit message if ecx is less than or equal to ebp...which makes perfect sense...since if the time is less than or equal to 30 minutes, we'll bypass the time limit. We could patch the program here, but looking a little further up you'll see our infamous reg / unreg flag comparison:
mov eax, dword ptr [ecx+00000834]
test eax, eax
jne 00442589
Change this jne to a jmp like we did to remove the nag and you'll automatically take care of the time limit since the reg / unreg comparison is above the time limit comparison. Really, you could do a patch at either of these locations with the same effect, but IMHO it seems like patching all of the reg flag locations is a bit more elegant :-)
Last But NOT Least: A Special Thanks |