TracePlus32

Implementing an Inline Patch from the Menu (for no good reason)

by Kayaker

Published by Tsehp sept 2000

Target: TracePlus/Win32 API monitor, version 1.44.002
              http://www.sstinc.com/demos.html 1.15Mb

Tools Used: SoftIce, W32Dasm, ExeScope, Procdump, HIEW, WinFrog, Win32 Programmer's Reference

Preamble:

Greetings Reversers! TracePlus/Win32 is an API monitor which includes some very nice features, such as sorted listings of all Calls made, Parameter values before and after each Call, modules used, SQL statements executed, logging to file, etc. At least they would be nice features if they were all enabled ;-)

In all, there were 18 patch points necessary to enable the various functions. Rather than just patch jumps in the file, I decided to have a bit of fun and create an inline patch which is called by a Menu item and then gives you a Message Box congratulating you on the fact. I had absolutely no good reason for doing it this way except to make a routine patch job into a fun learning experience. I hope you agree.

If you check out the String Resources with ExeScope there are some tantalizing clues that this demo can be registered, such as:
String Table Entry 105, "Turn the TracePlus demo into a fully working product."
String Table Entry 1127, "The user authorization file is damaged or is missing."

But after much poking around I couldn't figure out a way to register it, so I decided to treat it as a pure demo and deal with it from there. My Thanks go to TOTEU for some clues that the patching wasn't as hard as it first appeared. The first thing to do is check out what the limitations are.

Limitations in Demo:

A.     The program opens up with 3 tiled windows, API View, Status View and SQL View. If you run a trace on say, Notepad, you see that in API View, though all the API Calls are listed, there is no Parameter information. There are a few exceptions, such as GetProcAddress and ShowWindow, but not on ones like RegOpenKeyExA and RegQueryValueExA. Where the Parameter values should be is the word "(DEMO)". Well, you know how useless this is from a Fravia's standpoint ;)

The Status View shows something similar, this time with the words "(Version # N/A in demo)". I don't know about the SQL View as I don't have ODBC connectivity and couldn't test it.

Also, the nice sortable API Performance feature has #Calls and Total entries filled with the word "(DEMO)" again.

B.     Several options are disabled under Trace Options, including logging to file and buffer size as number of records logged. SQL Options also have some disabled features.

C.     Opening and Closing nags.

D.     Various Save features are disabled and I'll touch on that a bit later. It doesn't really matter too much because after our patch is made, we can still log to a file.

Pre-Patch Antics:

So what we want to do is find the various patch points (all 18 of them!), assemble the patch instructions, find a location to place the inline patch, short-circuit some Menu item to call our patch, and produce a Message Box with full fanfare telling you Hurrah. Since we'll be using this Menu item in the reversing process, we might as well make the various Resource changes with ExeScope (BRW, Restorator, Resource Hacker) now.

You can certainly make your own refinements, I'll just list what I did. Under Resource/Menu/MAINMENU select the Help popup menu and change "112,SST Home Page" to "112,PATCH". Don't change the MenuItem ID 112, just the caption. You should also delete at least the "113,SST Support on the Web" entry since that would jump into the middle of our inline patch.

The other thing we're going to want is a Message Box message, so go to String Resource 105, "Turn the TracePlus demo into a fully working product." and change the message to your own version of "Patch completed. Enjoy!!" Remember the ID value of 105 (69hex) for later.

Important! One last thing you NEED to do is use Procdump or similar and change the Code Characteristics of the .text section from 60000020 to E0000020. This will change the Flag for the section to "Writeable", which is necessary for the inline patch to change bytes without crashing. I thought I was going crazy until I figured this one out ;)

One point about playing with a program like this, written in MS Visual C++ v6.0. If you edit a line with the 'a' command in SoftIce, the change is more often than not hardwritten to the file. Also, if you exit the program without disabling all breakpoints, a CC (Int03) may be written at the BP addresses. So it's very important that you make backup copies of the original and any patched versions you have of the program. If it suddenly starts crashing on you, this may be the reason. I'm still not sure what the real cause of it is, some weird paging fault or something, but I've also seen it in VC++ v5.0. Caveat Reversi.

Finding the Patch points:

A.
As it turns out, the word "(DEMO)" is simply overwritten on the various listings before they are printed out. The actual parameter details have been received by the main program from the API hooking dlls. You can view the contents of the addresses in SoftIce before "(DEMO)" is written to confirm this.

If you do a String Reference search in W32Dasm for "(DEMO)" you find 7 occurrences at
40EEAF, 40EF1B, 41D47E, 41D4B1, 41D4E4, 41D589 and 41D5FB
The code around the first 2 are almost identical:

* Reference To: KERNEL32.lstrcmpA, Ord:02FCh
|
:0040EEA5 FF1520D14200 Call dword ptr [0042D120]
:0040EEAB 85C0 test eax, eax
:0040EEAD 741A je 0040EEC9

* Possible StringData Ref from Data Obj ->"(DEMO)"
|
:0040EEAF 6898264300 push 00432698
:0040EEB4 8B15FC174400 mov edx, dword ptr [004417FC]
:0040EEBA 8B4220 mov eax, dword ptr [edx+20]
:0040EEBD 50 push eax

* Reference To: KERNEL32.lstrcpyA, Ord:0302h
|
:0040EEBE FF1588D14200 Call dword ptr [0042D188]
:0040EEC4 E905020000 jmp 0040F0CE

With the help of the Win32 Programmer's Reference definition of lstrcpy, you can see that if you don't jump at 40EEAD, lpString2 (the word "(DEMO)" in the 'push 00432698' statement) will be copied into EAX, which up to this point (at 40EEBD) contains a perfectly good Parameter value which we'd kinda like to see.

LPTSTR lstrcpy(

LPTSTR lpString1 // address of buffer
LPCTSTR lpString2 // address of string to copy

There is a similar jump with the 2nd String Reference occurrence at:
          :0040EF19 741A je 0040EF35

The next 3 fall in a group, with a single suspicious jump (41D478) leading the way:

:0041D463 E885F9FEFF call 0040CDED
:0041D468 83C408 add esp, 00000008
:0041D46B 8985D8FDFFFF mov dword ptr [ebp+FFFFFDD8], eax
:0041D471 83BDD8FDFFFF00 cmp dword ptr [ebp+FFFFFDD8], 00000000
:0041D478 0F8499000000 je 0041D517

* Possible StringData Ref from Data Obj ->"(DEMO)"
 |   
:0041D47E 6820C04300 push 0043C020

And the last 2 have similar jump statements at:
      :0041D587 7412 je 0041D59B and
       :0041D5F9 7514 jne 0041D60F

By setting breakpoints in SoftIce at or before these jump addresses and using R FL Z, you find that the first 2 jumps determine if "(DEMO)" is written in the API Performance listing feature, and the last 3 for the entries in the main API View window.

P1. :0040EEAD 741A je 0040EEC9
P2. :0040EF19 741A je 0040EF35
P3. :0041D478 0F8499000000 je 0041D517
P4. :0041D587 7412 je 0041D59B
P5. :0041D5F9 7514 jne 0041D60F

You can follow the exact same procedure with "(Version # N/A in demo)" to find a jump that will fix up the Status View window:

P6. :0041DD35 7412 je 0041DD49

In all cases we WANT to code to jump to the indicated address. Great! We've got 6 of the 18 patch points already dusted off.

B.
If you select Trace/Options you see that several items are disabled, yet Exescope shows that the Style attribute for the TRACEOPTIONS Dialog Resource is set to enabled for all of them. Since they must be being disabled at run-time, BPX EnableWindow can be used to break into the heart of the matter.

Select Trace/Options with EnableWindow set, F11, and you break into a set of 7 calls starting at:

:0040DFA5 6A00 PUSH 00
:0040DFA7 6A16 PUSH 16
:0040DFA9 8B4508 MOV EAX,[EBP+08]
:0040DFAC 50 PUSH EAX
:0040DFAD FF156CD54200 CALL [USER32!GetDlgItem]
:0040DFB3 50 PUSH EAX
:0040DFB4 FF1570D54200 CALL [USER32!EnableWindow]

The PUSH 00 statement is the 2nd stack parameter of EnableWindow, which you can see from the description, should be 01 (or TRUE) to enable the window. So all we have to do is change the PUSH 00 to PUSH 01 for each EnableWindow statement.

The PUSH 16 statement is the control ID of GetDlgItem. If you use Exescope you can see that this control refers to the Monochrome Display checkbox (16h = 22dec = ID).

The EnableWindow function enables or disables mouse and keyboard input to the specified window or control.

BOOL EnableWindow(
     HWND hWnd // handle to window
     BOOL bEnable // flag for enabling or disabling input

Parameters
     hWnd: Identifies the window to be enabled or disabled.
     bEnable: Specifies whether to enable or disable the window. If this parameter is TRUE, the window is enabled. If the parameter is FALSE, the window is disabled.

The GetDlgItem function retrieves the handle of a control in the specified dialog box.

HWND GetDlgItem(
     HWND hDlg // handle of dialog box
     int nIDDlgItem // identifier of control

Parameters
     hDlg: Identifies the dialog box that contains the control.
     nIDDlgItem: Specifies the identifier of the control to be retrieved.

Now remember the problem with making code changes in SoftIce with MS Visual C++. If you are on the PUSH 00 statement and use the SI 'a' command to change this to PUSH 01, then that change will be hardwritten to the file. While this may actually be kind of handy, it's not what we want. But you still want to see the effect that the change will have.

So what you can do to make a temporary change is to F8 until you are ON the Call EnableWindow line (0040DFB4 in the above example) and type 'dd esp'. You'll get something like the following in the Data window, where the 2nd DWORD value from the left is the 2nd stack parameter of EnableWindow that you want to change:

016F:0075EC3C 000003D0 00000000 0E900EA0 001F0E90

Then you can Edit that value by clicking on it with the mouse, or more directly by typing 'db' (this changes the Data window from a DWORD display (dd) to a BYTE display (db)), and then typing 'e esp+4', where you can just type in "01" in that first byte and the change is made.

016F:0075EC40 01 00 00 00 A0 0E 90 0E-90 0E 1F 00 10 01 00 00

Out of the 7 EnableWindow calls only 6 really need to be changed. The one corresponding to DlgItem 46 doesn't actually seem to exist in the Resources, which you can confirm with Exescope. So the next 6 patch points are:

P7. :0040DFA5 6A00 push 00000000
P8. :0040DFBA 6A00 push 00000000
P9. :0040DFCF 6A00 push 00000000
P10. :0040DFE4 6A00 push 00000000
P11 :0040DFF9 6A00 push 00000000
P12 :0040E023 6A00 push 00000000

The exact same procedure can be followed to enable the SQL Options items:

P13. :004021FB 6A00 push 00000000
P14. :00402504 6A00 push 00000000
P15. :00402519 6A00 push 00000000
P16. :0040252E 6A00 push 00000000

C.
Opening Nag.  Finding the opening nag is fairly straightforward. There is a unique call to a single DialogBoxParamA which you can find by; F10 stepping from the start of the program code until the nag opens; by noticing the suspicious W32Dasm String Reference to "LOGO"; or by breaking directly on DialogBoxParamA in SoftIce and examining the code around there. Either way should get you to the following code:

* Reference To: KERNEL32.lstrlenA, Ord:0308h
|
:00416B9B FF15B4D14200 Call dword ptr [0042D1B4]
:00416BA1 85C0 test eax, eax
:00416BA3 7546 jne 00416BEB
.
* Reference To: USER32.DialogBoxParamA, Ord:0093h
|
:00416BD0 FF1550D54200 Call dword ptr [0042D550]

Now this is the only change that can't be part of our inline patch since at this point, while the main program has opened, we can't access the Menu to apply our patch. So get rid of the opening nag by changing

:00416BA3 7546 jne 00416BEB  to
:00416BA3 EB46 jmp 00416BEB


Closing Nag.  The closing nag is a bit more complicated because its DialogBoxParamA call is also referenced by every other Dialog Box in the program. To home in on it we need to be able to trace from the selection of any Menu item to the unique branch point which directs the program to the code for the selected feature, after all the initial processing has gone on (i.e "which Menu item was selected and where do we send it now?")

This branch point is in the form of an indirect jump statement that leads to whatever code section will process the function. This is going to be a very important process because we also need to find this branch point to get to the section where we'll insert the inline patch, as well as exploring the possibilities of enabling some Save functions, so bear with me.

Start by finding out the Hwnd of the Menu bar. It's easiest to use a windows class utility such as Winfrog or Windowse. Once you've found out once that the Class is called SSTWin32Class, you can use 'TASK' in SoftIce to get the taskname (Tplus32), then 'HWND taskname' to get the Hwnd of the Menu bar from then on.

Then set a
BMSG Hwnd WM_COMMAND
on the Hwnd of the Menu bar. Select any Menu item from the program and SoftIce breaks in Kernel32.dll with something like:

Break due to BMSG 0720 WM_COMMAND (ET=2.32 seconds)
hWnd=0720 wParam=0009 lParam=00000000 msg=0111 WM_COMMAND

The WM_COMMAND message is sent when the user selects a command item from a menu, when a control sends a notification message to its parent window, or when an accelerator keystroke is translated.

WM_COMMAND
     wNotifyCode = HIWORD(wParam); // notification code
     wID = LOWORD(wParam); // item, control, or accelerator identifier
     hwndCtl = (HWND) lParam; // handle of control

Parameters
wNotifyCode: Value of the high-order word of wParam. Specifies the notification code if the message is from a control. If the message is from an accelerator, this parameter is 1. If the message is from a menu, this parameter is 0.
wID: Value of the low-order word of wParam. Specifies the identifier of the menu item, control, or accelerator.
hwndCtl: Value of lParam. Identifies the control sending the message if the message is from a control. Otherwise, this parameter is NULL.

Now rather than F8 stepping through a s***load of Kernel32 and User32 code to get back into program code, we'll borrow Lord Soth's shortcut of setting a

BPX K32Thk1632Prolog
and pressing F5

After SoftIce breaks press F11 and you should be at:

:BFF943FD CALL KERNEL32!K32Thk1632Prolog
:BFF94402 CALL BFF735FD
:BFF94407 CALL KERNEL32!K32Thk1632Epilog

Step INTO the middle call with F8 and you'll see:

:BFF735FD PUSH EBP
.
:BFF7361F SHR DWORD PTR GS:[ESI+04],1
:BFF73623 JB BFF73647
:BFF73625 PUSH DWORD PTR GS:[EDX]
:BFF73628 LEA EDX,[EDX+04]
:BFF7362B LOOP BFF7361F
:BFF7362D MOV EDI,ESP
:BFF7362F XOR EAX,EAX
:BFF73631 CMP GS:[ESI+08],EAX
:BFF73635 JZ BFF7363B
:BFF73637 CALL GS:[ESI+08]

The last Call at :BFF73637 will be back into program code at 417665. As you step down to there you'll see the parameters from WM_COMMAND being PUSHed in the LOOP. It doesn't matter which Menu item you select, you'll always end up back at 417665 in program code. The WM_COMMAND / K32Thk1632Prolog trick just gets us there.

Now I'll try to minimize the amount of code I put here, but finding the branch points and understanding the code flow is actually quite easy after you've stepped through it once or twice. There are 3 important jumps which guide the program to the proper address for the Menu item we selected:

Jump 1- :004176CB JMP [EDX*4+00419663]
Jump 2- :0041771B JMP [EDX*4+00419694]
Jump 3- :00418223 JMP [EDX*4+004197AA]

If you leave K32Thk1632Prolog enabled and keep pressing F5, you'll see that SoftIce breaks many many times and the addresses pointed to in the above jumps may change. That's OK. It may take more than 1 iteration to find the CMP routine we're looking for (if it's there!) which will bypass the nag, enable the Save feature, or whatever we're looking for.

To find the code for the Closing nag, triggered by selecting File/Exit, we need 2 iterations of K32Thk1632Prolog. The code flow goes something like this:

WM_COMMAND -> K32Thk1632Prolog -> 417665 -> Jump 2 -> Jump 3 -> DefFrameProc ->
K32Thk1632Prolog -> 417665 -> Jump 1 -> 4192F0 (Our code!!)

The DefFrameProc function provides default processing for any window messages that the window procedure of a multiple document interface (MDI) frame window does not process. All window messages that are not explicitly processed by the window procedure must be passed to the DefFrameProc function.

It's a simple trace from 4192F0 to find:

:004193D5 6A00 PUSH 00
:004193D7 68ED9E4100 PUSH 00419EED
:004193DC 68FCB84300 PUSH 0043B8FC
:004193E1 8B0D18204400 MOV ECX,[00442018]
:004193E7 51 PUSH ECX
:004193E8 E85F21FFFF CALL 0040B54C; Closing Nag / DialogBoxParamA call
:004193ED 83C410 ADD ESP,10
:004193F0 E930020000 JMP 00419625

What I did was to bypass the Call by changing

P17. :004193D5 6A00 PUSH 00  to
:004193D5 EB19 JMP 004193F0

Yeah I know, you coulda figgered this out from the W32Dasm references to 'DEMO', 'TERMINATEPROCESS' and the DialogBoxParamA call, but I wanted to demonstrate the process.

And that's our final patch point!! Now we need to assemble the Inline Patch and figure out where to put it.

Finding the Inline Patch point:

You've probably heard about finding "caves", or areas with no code, in files to put an inline patch? Well we're gonna dig our own cave!

Here's where all that garbage we just went through with the Closing nag comes in handy. Remember those 3 jumps that I emphasized? Keep the breakpoints on jumps 2 and 3 set, but disabled (bd) for now. Now find out the Hwnd of the Menu bar again and set another BMSG Hwnd WM_COMMAND. We don't have to use K32Thk1632Prolog this time since we know where it will lead to from our previous efforts.

Select the Menu item we called "PATCH" and SoftIce breaks on WM_COMMAND. Immediately ENABLE (be) the 2 jumps and press F5. Now you can F10 step until the 2nd Jump:

:00418223 JMP [EDX*4+004197AA]

which will address code location 418DF1. This will be the start of our inline patch, or hex location 18DF1 in the exe file.

There's a ton of garbage code here similar to that below that we can overwrite. We can use JMP 00419184 safely to end our inline patch as it's called several times to exit the section. BTW, the CALL [0042D3B4] statement opens up your browser and tries to connect to the SST home page, so that's why we don't mind overwriting it!

:00418DF1 PUSH 01
:00418DF3 PUSH 00441A6C
:00418DF8 PUSH 00
:00418DFA PUSH 0043B7F4
:00418DFF PUSH 0043B80C
:00418E04 CALL [USER32!GetDesktopWindow]
:00418E0A PUSH EAX
:00418E0B CALL [0042D3B4]
:00418E11 JMP 00419184

So all we need to do is start typing up our patch with a hex editor at address 418DF1 in the file, ending always with a JMP 00419184 statement.

Assembling the Patch:

Here's all the places we need to patch put together with the changes we want to make:

Patch Address Original Code Patched Code
P1 40EEAD 741A je 40EEC9 EB1A jmp 40EEC9
P2 40EF19 741A je 40EF35 EB1A jmp 40EF35
P3 41D478 0F8499000000 je 41D517 E99A00000000 jmp 41D517
P4 41D587 7412 je 41D59B EB12 jmp 41D59B
P5 41D5F9 7514 jne 41D60F EB14 jmp 41D60F
P6 41DD35 7412 je 41DD49 EB12 jmp 41DD49
P7 40DFA5 6A00 push 00000000 6A01 push 00000001
P8 40DFBA 6A00 push 00000000 6A01 push 00000001
P9 40DFCF 6A00 push 00000000 6A01 push 00000001
P10 40DFE4 6A00 push 00000000 6A01 push 00000001
P11 40DFF9 6A00 push 00000000 6A01 push 00000001
P12 40E023 6A00 push 00000000 6A01 push 00000001
P13 4021FB 6A00 push 00000000 6A01 push 00000001
P14 402504 6A00 push 00000000 6A01 push 00000001
P15 402519 6A00 push 00000000 6A01 push 00000001
P16 40252E 6A00 push 00000000 6A01 push 00000001
P17 4193D5 PUSH 00 EB19 jmp 004193F0
Plus the opening nag patch, which won't be part of our inline patch:
416BA3 7546 jne 416BEB EB46 jmp 416BEB

Entering the inline patch:

You may have your own way of doing this. You could type the changes directly in SoftIce, writing down or dumping the byte opcode patterns (IceDump's '/DUMP address length filename' command is handy for this), and then inserting them at address 18DF1h in a hex editor. I like using HIEW because I can easily make a few changes and then test them to see if they work.

In HIEW open the file, press F4 and F3 for decode mode, then F5 for GoTo and enter 18DF1. There are a couple of peculiarities with HIEW. The Opcodes BYTE PTR, WORD PTR and DWORD PTR must be entered as "b", "w" and "d" or you get an error. Also, the bytes you enter (as byte, word or dword) MUST start with a "0", i.e. EB must be entered as 0EB. Don't know why this is but you get an error if you don't.

Now press F3 and F2 to start editing in ASM mode and start typing the changes, saving every few for safety. Always end with a "jmp 19184" (to correspond with the JMP 00419184 we need to exit the section).

**Don't forget about changing the Code Characteristics of the .text section from 60000020 to E0000020 before running the program!**

Here is my patch as input into HIEW

.00418DF1: C605ADEE4000EB mov b,[00040EEAD],0EB
.00418DF8: C60519EF4000EB mov b,[00040EF19],0EB
.00418DFF: C70578D44100E99A0000 mov d,[00041D478],000009AE9
.00418E09: C60587D54100EB mov b,[00041D587],0EB
.00418E10: C605F9D54100EB mov b,[00041D5F9],0EB
.00418E17: C60535DD4100EB mov b,[00041DD35],0EB
.00418E1E: C605A6DF400001 mov b,[00040DFA6],001
.00418E25: C605BBDF400001 mov b,[00040DFBB],001
.00418E2C: C605D0DF400001 mov b,[00040DFD0],001
.00418E33: C605E5DF400001 mov b,[00040DFE5],001
.00418E3A: C605FADF400001 mov b,[00040DFFA],001
.00418E41: C60524E0400001 mov b,[00040E024],001
.00418E48: C605FC21400001 mov b,[0004021FC],001
.00418E4F: C6050525400001 mov b,[000402505],001
.00418E56: C6051A25400001 mov b,[00040251A],001
.00418E5D: C6052F25400001 mov b,[00040252F],001
.00418E64: 66C705D5934100EB19 mov w,[0004193D5],019EB
.00418E6D: E912030000 jmp .000419184 -------- (1)

And how it looks in SoftIce:

:00418DF1 C605ADEE4000EB MOV BYTE PTR [0040EEAD],EB
:00418DF8 C60519EF4000EB MOV BYTE PTR [0040EF19],EB
:00418DFF C70578D44100E99A0000MOV DWORD PTR [0041D478],00009AE9
:00418E09 C60587D54100EB MOV BYTE PTR [0041D587],EB
:00418E10 C605F9D54100EB MOV BYTE PTR [0041D5F9],EB
:00418E17 C60535DD4100EB MOV BYTE PTR [0041DD35],EB
:00418E1E C605A6DF400001 MOV BYTE PTR [0040DFA6],01
:00418E25 C605BBDF400001 MOV BYTE PTR [0040DFBB],01
:00418E2C C605D0DF400001 MOV BYTE PTR [0040DFD0],01
:00418E33 C605E5DF400001 MOV BYTE PTR [0040DFE5],01
:00418E3A C605FADF400001 MOV BYTE PTR [0040DFFA],01
:00418E41 C60524E0400001 MOV BYTE PTR [0040E024],01
:00418E48 C605FC21400001 MOV BYTE PTR [004021FC],01
:00418E4F C6050525400001 MOV BYTE PTR [00402505],01
:00418E56 C6051A25400001 MOV BYTE PTR [0040251A],01
:00418E5D C6052F25400001 MOV BYTE PTR [0040252F],01
:00418E64 66C705D5934100EB19 MOV WORD PTR [004193D5],19EB
:00418E6D E912030000 JMP 00419184

Adding the Message Box:

OK, so adding a Message Box isn't necessary, heck, none of this is really necessary, but besides being kinda fun it'll get us into the possibility of enabling the various other Save features. Same routine as used for the closing nag and finding the starting address of the inline patch - WM_COMMAND on the Hwnd of the Menu bar and have that critical branch point BPX at

:00418223 JMP [EDX*4+004197AA]

set but disabled.  Now select some disabled Save feature, such as Export Trace, enable BPX 418223, F5, break and trace from the jump with F8 until

:00406FF2 PUSH 00000466
:00406FF7 CALL 0040B628

Notice the PUSH 466 statement. This is the String Resource ID in hex (1126 dec) for "This feature is not enabled in the demonstration version." which is PUSHed into ESP of the Call, and will become [EBP+08], loaded with LoadStringA, and used in the MessageBoxA call.

:0040B655 8B4508 MOV EAX,[EBP+08]
:0040B658 50 PUSH EAX
:0040B659 8B0D58354400 MOV ECX,[00443558]
:0040B65F 51 PUSH ECX
:0040B660 FF1588D54200 CALL [USER32!LoadStringA]
:0040B666 6A30 PUSH 30
:0040B668 8D55AC LEA EDX,[EBP-54]
:0040B66B 52 PUSH EDX
:0040B66C 8D8568FEFFFF LEA EAX,[EBP-0198]
:0040B672 50 PUSH EAX
:0040B673 8B0D18204400 MOV ECX,[00442018]
:0040B679 51 PUSH ECX
:0040B67A FF15D0D44200 CALL [USER32!MessageBoxA]

So all we have to do is make our own version of the call to the LoadStringA / MessageBoxA routine, PUSHing our personalized String Resource with the hex value of 69 (remember changing the text of Resource ID 105?)

Add the following code (as entered in HIEW) at the very last line of our inline patch, remembering to replace the JMP 00419184 statement as the final line.

Push 69
Call 0B628
Add ESP,4 ; repair the stack after the Call
Jmp 19184

Thas' be it! You should now be able to run the program in disabled demo mode (not sure why you'd want to, but...), and then select your own Menu item to install your patch to run it your way. And you get a nice Message Box from the program to boot!

PostAmble:

As for enabling the various Save features, that's a work still in progress, but by using the WM_COMMAND technique outlined here you can start exploring the code at the proper location for each feature to see if they actually can be enabled. The first step would be to trace from that pivotal :00418223 JMP [EDX*4+004197AA] statement and see if you can avoid the call to MessageBox.

Please, Please do not use this information to make a lame crack for distribution. I would dearly hate to see my effort to give a little something back to the Reversing community, from which I've learned so much, end up hurting the programmers who wrote the program.

I hope this has helped someone gain a little bit of understanding and I'd love to hear from you if it did. Greetz to everyone on +Sandman's Newbies Forum ;-)

Cheers,

Kayaker