Log in

View Full Version : Save function disabled


octapus
November 23rd, 2001, 12:25
I have downloaded a program called " The VR Worx 2.0". It's creator says that save function is disabled in Demo Version. When i click on SAVE or SAVE AS menu it shows a message that "You have a Demonstration Message...." etc.

I disassembeled the program with IDA and found the point where WM_COMMAND message is passed on to the program. Therefore i found what is executed when Save button is pressed.
I found no connection in that point with any Save Dialog from Common Dialogs DLL. Only a call to MessageboxA and then return to normal DlgProc waiting for messages.

So i went for the opposite direction. I found in imports section the Call to GetSaveFileName function of commdlg32.dll. GETSAVEFILENAME ICALL IS BEING USED ONCE IN THE ENTIRE PROGRAM.
In it's parameters pushed I found the Text that Save Dialog should show in it's bar("VR WORKS 2.0 Panorama Save as"". It's for sure that that function should be called
when pressing Save in the File menu. I wrote all the references to this call (where GetSavefilename is) up to five levels. There were about 12 of them. I breakpointed all of them but when pressing Save it never breakpoints.

I tried to see how getopenfilename is called and it was very straightforward. Right where WM_COMMAND message is executed it calls a function where GetOpenFilename is and it simply works.

So i tried the following things.
1) I pushed the window handle
and called the function where GetSaveFileName is ( that function has one argument of dword size). To tell the truth i couldn't understand what should be pushed and i did it blindly. As a result when i went through the code with Softice it created a GPF and started the program's EXCEPTION HANDLING PROCEDURE before showing Windows Familiar GPF and finally it exited.
2) The part where wm_command executed the code for SAVE menu had a call. Inside it , a function pointer was being used. I edited manually the data memory location where the fuction points to with the mem loc of starting Call where GetSaveFilename is. Still i can't imagine what should be pushed.
3) I tried the two ways above but not with the call which contains the GetSaveFileName but with a call that contains the call i mentioned above( this one had to arguments of dword size). GPF again.

It seems that the programmers have removed some code from the program before compiling it. You think there could be a way to link the Save Menu with it's true code?

Maybe this looks like a crack request but all i want is some clue to continue. If anybody has the time to deal with it you are welcome.
(site where program is : h*tp://www.vrtoolbox.com/downloads.html . It's size is about 1,4 MB) .

Note : After some more searching in the Internet i found that the other demo programs this company gives in it's site have cracks for the current newest version on the Internet.Their limitation is the same.So i had the thought to see how the cracking is being implemented on those and maybe it's the same with this one two.
Maybe this works since the same company made them. I will try it in the meantime while i wait for some answers.

Kayaker
November 23rd, 2001, 14:51
Hi octapus,

What needs to pushed for GetSaveFileName is a pointer to an OPENFILENAME structure that contains information used to initialize the dialog box. You may need to find or recreate its structure. Here's a matching SI display and source code for a basic GetSaveFileName call. You should be able to find similar code if the authors haven't deleted it. It might not be a direct jump from your wm_message to the save routine, there might be some other code that needs to be run or has been removed as well.

BTW, this didn't sound like a crack request at all, your explanations of how you approached it help others learn, simple as that.

OPENFILENAME structure:
0030:10004207 0000004C 00000000 00000000 1000429C L............B.. 
0030:10004217 00000000 00000000 00000001 100042E4 .............B.. 
0030:10004227 000001FF 00000000 00000000 00000000 ................
0030:10004237 100042C4 00280006 00290024 100042E0 .B....(.$.)..B..
0030:10004247 00000000 00000000 00000000


0167:100015A0 55 PUSH EBP 
0167:100015A1 8BEC MOV EBP,ESP
0167:100015A3 81C4CCFEFFFF ADD ESP,FFFFFECC
0167:100015A9 57 PUSH EDI
0167:100015AA 56 PUSH ESI
0167:100015AB C705074200104C000000MOV DWORD PTR [10004207],0000004C
This is the pointer to the start of the structure, its size is always 4C by default
mov ofn.lStructSize, SIZEOF ofn

0167:100015B5 C705134200109C420010MOV DWORD PTR [10004213],1000429C
0167:100015BF C605E442001000 MOV BYTE PTR [100042E4],00
0167:100015C6 C70523420010E4420010MOV DWORD PTR [10004223],100042E4
0167:100015D0 C70527420010FF010000MOV DWORD PTR [10004227],000001FF
0167:100015DA C70537420010C4420010MOV DWORD PTR [10004237],100042C4
0167:100015E4 C70543420010E0420010MOV DWORD PTR [10004243],100042E0
0167:100015EE C7053B42001006002800MOV DWORD PTR [1000423B],00280006
0167:100015F8 6807420010 PUSH 10004207
0167:100015FD E82A110000 CALL comdlg32!GetSaveFileNameA
0167:10001602 83F801 CMP EAX,01
0167:10001605 0F8596010000 JNZ 100017A1

;===============SaveFile Proc============================
SaveFile proc uses edi esi

LOCAL hMemory: DWORD
LOCAL pMemory: DWORD
LOCAL SizeReadWrite: DWORD

; --------------------------------------------------------------------------
; Initialize OPENFILENAME structure associated with GetSaveFileName function
; --------------------------------------------------------------------------

mov ofn.lStructSize, SIZEOF ofn
mov ofn.lpstrFilter, OFFSET strFilterSave
mov [globalBuffer],0
mov ofn.lpstrFile, OFFSET globalBuffer
mov ofn.nMaxFile, (SIZEOF globalBuffer)-1
mov ofn.lpstrTitle, OFFSET strTitleSave
mov ofn.lpstrDefExt, OFFSET strSaveExt
mov ofn.Flags, OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY or OFN_OVERWRITEPROMPT

invoke GetSaveFileName, OFFSET ofn
.IF eax==TRUE

invoke CreateFile, OFFSET globalBuffer, GENERIC_WRITE, FILE_SHARE_WRITE,\
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL
mov hFile,eax

DO SOMETHING

invoke WriteFile, hFile, pMemory, edi, ADDR SizeReadWrite, NULL

invoke CloseHandle, hFile
invoke GlobalUnlock, pMemory
invoke GlobalFree, hMemory

.ENDIF

ret
SaveFile endp
;===============End SaveFile Proc========================

Hope this helps,
Kayaker

octapus
November 26th, 2001, 09:06
Hi Kayaker

Thank you for your answer.
Well the pointer to the OPENFILENAME
structure is right above it. And before being pushed the struture is being filled with everything needed. All these commands are inside a FUNCTION. Let's name it SAVE_FUNC. Isn't it logical that when something is going to be saved, there should be a call to SAVE_FUNC?
As i have stated above SAVE_FUNC has one parameter (argument) and also that GETSAVEFILENAME exist once in the whole program. So if something ( like a program project ) is going to be saved SAVE_FUNC should definitly be called.

Well I put breakpoints on the start of SAVE_FUNC and on the start of the function that refers to SAVE_FUNC and it never breaks.

Apparently the code executed when pressing Save is not linked at all with CALL_FUNC in any way. But still in that code ( of Save ) there is a call to a pointer in memory. And this pointer is filled everytime before the call happens.


NOTE : Since i refered to it before there is one XReference to CALL_FUNC.

+SplAj
November 26th, 2001, 09:52
Octa..
====

seems you are nearly there . Just need to relocate the pointer for 'eval' message to the real code that opens the save dlg box

for all , here is the more direct link to d/l target, don't bother wasting your time filling in the stupid boxes

h**p://vrtoolbox.com/download-demos/VRWorxDemo.exe

octapus
November 27th, 2001, 08:58
This target seems to have its own EXCEPTION HANDLING routine. So everytime i try to replace the function pointer to "bad message" ( points somewhere where MESSAGEBOXA executes ) with one that points of SAVE_PROC ( check how i define SAVE_PROC above) it always breaks with a GPF.

Maybe i am very close but i can't think of a way to finish the job.