W32Dasm Version 8.0 Save re-enabling
(How to get our dialogs and our routines inside our targets)

by PNA

(31 August 1997)


Target:  W32Dasm Version 8.0 - I got mine through ftp-search (w32dasm8.zip)

Protection:  Save-disabled (among other protections)



This essay will show you how to integrate a save-function to W32Dasm

including a save-dialog.



Studying the following articles will be helpful (or essential):



 +HCU's Project0: W32Dasm Cracking (look at the "w32dsm00.tmp"-file stuff)

 +HCU's Project6: Crippleware Cracking (razzia's tutorial (!!!) including

                  the information about the PE-file structure !)





Tools used:

 - SoftIce 3.01  (everywhere regged, else trial at http://www.nu-mega.com)

 - UltraEdit-32 (?, search for uedit32.zip)

 - quickview.exe (in your windows\system\viewers directory)

 - the target itself



Please have a look at these Win32 API-functions/structs in your Help:



KERNEL32:

 - CreateFile

 - GetTempPath

 - GetModuleHandle

 - GetProcAdress

 - CopyFile



COMDLG32:

 - GetOpenFileName

 - OPENFILENAME (struct)





Please Note: All disassembly listings assume 0x00400000 as the

ImageBase.





General Approach:



 1. Bypass the "Save disabled"-message box ...

 2. ... with your code that brings up the save-dialog ...

 3. ... and copies the "W32dsm00.tmp"-file with the name and in the

       directory you chose



1. Bypass the "Save disabled"-message box:

 The fastest way to find that code is to "BPX MessageBeep" in SoftIce.

 Run the target, load something and press the save-button.

 When SoftIce comes up press F12 and you land at 445485.



:445477 55                      push ebp

:445478 8BEC                    mov ebp, esp

:44547A 53                      push ebx

:44547B 8B5D08             **mov ebx, [ebp+08]  ; will be changed to a jump to our bypass

:44547E 6AFF                    push FFFFFFFF     

:445480 E8F38E0300              Call 0047E378      ;USER32.MessageBeep

:445485 8B8391585400            mov eax, [ebx+00545891]

:44548B 6A40                    push 00000040

:44548D 6822EA4800              push 0048EA22     ;->"Demo Version Message"

:445492 686AE94800              push 0048E96A     ;->"Save to Text File 

                                                  ;   Function is Disabled

:445497 FF700C                  push [eax+0C]

:44549A FF7068                  push [eax+68]

:44549D E816940300              Call 0047E8B8     ;OWL50f.TApplication::MessageBox(...)

:4454A2 83C414                  add esp, 00000014

:4454A5 5B                 **pop ebx           ;reentry from bypass

:4454A6 5D                      pop ebp

:4454A7 C3                      ret





 Now we know where to place the jmp to our bypass-routine. But where

 will the jmp point to? Let's check the PE-header of our target...





2. Integrate Code for the save-dialog



 As we want to integrate code in the first place, we check the CODE-

 section (usually called .text) in the target's PE-dump (with

 quickview):



 Section Name:  CODE

 Virtual Size:  0007e000

 Virtual Addres:  00001000

 Size of raw data: 0007da00 ;*

 Pointer to raw data: 00000600

 ...



 Note that * fits exactly the file alignment specified in the Image

 Optional Header (not shown here). As the probability that in the code-section 

 no bytes have been wasted is 1 to 512, we better check the data using UEdit.

 Once we do, as assumed, we discover that this value was rounded to the 

 next alignment by the linker. 

 This becomes obvious when you look at 0007e000 (0007da00+0600)

 in the target-file and scroll back a few lines. All zeros. The very

 last instruction is a jmp at 0007dee2 which gives us nice free code space

 from 0007dee8 to 0007dfff, enough for our purpose.

 The jmp at 0007dee2 is the last entry in a jump-table of all imported

 functions. As I did all coding with SoftIce, I had to do a call to

 an entry of this table to use an imported function. SoftIce creates

 the wrong code if you type e.g "call GetModuleHandle". You have to

 search for "jmp [KERNEL32!GetModuleHandleA]" in that table (I simply

 scrolled through the code window) and use its address.

 By the way, we have a nice Copyright message from Borland at 0007e000

 (beginning of DATA-section... check the PE-header!). This will be used to

 store some strings needed in part 3. Thanks Borland.



 Now we know the entry-point of our bypass-routine and we can put a

 jmp 0047e8e8 (virtual address of 0007dee8) at 0044547b back in SoftIce.



 I will now show you the first part of the added code which brings

 up the save-dialog (actually it is an open-dialog from the COMDLG32

 library, because it does the same job and was already imported by

 the target):



:47E8E8 55                    push ebp            ;create stackframe

:47E8E9 8BEC                  mov ebp, esp        ;for local vars,

:47E8EB 33C0                  xor eax, eax        ;buffers, structs

:47E8ED 81ECF0010000          sub esp, 000001F0   ;...

:47E8F3 B9F0010000            mov ecx, 000001F0   ;fill it with 0s

:47E8F8 8BFC                  mov edi, esp        ;...

:47E8FA F3                    repz                ;...

:47E8FB AA                    stosb               ;...

:47E8FC C78514FFFFFF4C000000  mov dword ptr [ebp-EC], 4C   ;insert our values

:47E906 8D4580                lea eax, [ebp-80]            ;for the OPENFILENAME

:47E909 898530FFFFFF          mov [ebp-D0], eax            ;struct starting at

:47E90F C78534FFFFFF70000000  mov dword ptr [ebp-CC], 70   ;[ebp-ec]

:47E919 C78548FFFFFF04000000  mov dword ptr [ebp-B8], 4    ;...

:47E923 8D8514FFFFFF          lea eax, [ebp-EC]   ;offset of OPENFILENAME struct

:47E929 50                    push eax            ;given to GetOpenFileNameA

:47E92A E863FBFFFF            Call 0047E492       ;call jmp-table-entry (COMDLG32.GetOpenFileNameA)

:47E92F 85C0                  test eax, eax       ;anything wrong?

:47E931 0F8469000000          je 0047E9A0         ;yes, jmp to end of routine



 Remarks: First we create a stack frame to store some data in. Its

 size and the location of the OPENFILENAME struct at [esp-EC] are

 more or less arbitrary and my choice is not very efficient due to

 historical reasons. The fields I filled in the OPENFILENAME struct are:





 - DWORD  lStructSize; size of struct, always 0x4c.

 - LPTSTR lpstrFile; points to the buffer which contains the

          initial filename and receives the full

          pathname of the selected file.

 - DWORD  nMaxFile; length of lpstrFile buffer (should be at

          least 260 characters long, I know, I know)

 - DWORD  Flags;  I used OFN_HIDEREADONLY only. Value for

          OFN_OVERWRITEPROMPT is 2 if you want to use that instead.



 After the call you will see the common windoze dialog for opening

 files. Don't blame me for this as the whole crack doesn't require

 a single change of the PE-header, which keeps it simpler.



 Before we proceed with our code we have to get rid of the problem

 which occurs when we try to copy an opened file (see project0-

 essays). Remember that we planned to copy the w32dsm00.tmp file.

 My approach is to change the dwShareMode upon its creation. (I

 didn't read all essays, so please be indulgent if I repeat

 something here).

 This is the part which creates w32dsm00.tmp:



:464F0C 6A00                    push 00000000

:464F0E 6802010000              push 00000102

:464F13 6A02                    push 00000002

:464F15 8D93604D4900            lea edx, [ebx+00494D60]

:464F1B 52                      push edx

:464F1C 6A00                   **push 00000000   ;put a 0x01 in this push

:464F1E 68000000C0              push C0000000   ;instead and dwShareMode will

:464F23 8D8BE0504900            lea ecx, [ebx+004950E0] ;be set to FILE_SHARE_READ

:464F29 51                      push ecx



* Reference To: KERNEL32.CreateFileA

                                  |

:464F2A E8E7920100              Call 0047E216



 Now the file is readable for Windows.





3. Copy the file to our destination



 The last problem we encounter is the missing CopyFile function

 in the target's import table. But as we all know, GetModuleHandle

 and GetProcAddress solve this problem. We can highly assume

 that both are imported (at least GetModuleHandle) and we are

 lucky. Both show up in the import table. This was the last

 obstacle.

 Do you remember the nice guys at Borland's? They provided us with

 a little DATA space at 0047f000 (virtual address). We can put two

 strings there. "KERNEL32" followed by null (0007e000, raw) and

 "CopyFileA" followed by null (0007e009, raw). For educational

 pourpose OF COURSE, I implemented two ways of dealing with constants:

 One is to include them in your code (0047e955-0047e962), the other

 one is to store them in a DATA section (vital if you need many).

 The latter method requires a little stack trick to retrieve the actual

 ImageBase probably known to most programmers from the old days.

 Others may refer to razzias excellent tutorial in project 6.

 Now enjoy the rest of the crack's implementation:



* Reference To: COMDLG32.GetOpenFileNameA

                                  |

:47E92A E863FBFFFF         Call 0047E492        ;see part 1 of listing

:47E92F 85C0               test eax, eax        ;...

:47E931 0F8469000000       je 0047E9A0          ;...

:47E937 8D8514FEFFFF       lea eax, [ebp-01EC]  ;points to buffer in stackframe

:47E93D 50                 push eax             ;push it

:47E93E 6A80               push 80              ;push max length of buffer



* Reference To: KERNEL32.GetTempPathA

                                  |

:47E940 E879F9FFFF         Call 0047E2BE        ;get Windows Temp Path



:47E945 85C0               test eax, eax        ;OK?

:47E947 0F8453000000       je 0047E9A0          ;no, jump to end of routine

:47E94D 8D9D14FEFFFF       lea ebx, [ebp-01EC]  ;ebx now points to Temp Path

:47E953 03D8               add ebx, eax         ;add (returned) stringlength

:47E955 C70377333264       mov dword ptr [ebx], 64323377 ;append "w32d"

:47E95B C74304736D3030     mov [ebx+04], 30306D73 ;append "sm00"

:47E962 C743082E746D70     mov [ebx+08], 706D742E ;append ".tmp"

:47E969 E800000000         call 0047E96E        ;call next instruction

:47E96E 5B                 pop ebx   ;get eip(=0047E96E here) in ebx

:47E96F 81EB6EE90700       sub ebx, 0007E96E  ;sub offset of call destination

:47E975 81C300F00700       add ebx, 0007F000  ;add offset of DATA-section

:47E97B 53                 push ebx           ;not necessary

:47E97C 53                 push ebx           ;ebx points to "KERNEL32"



* Reference To: KERNEL32.GetModuleHandleA

                                  |

:47E97D E82AF9FFFF         Call 0047E2AC   ;get handle

:47E982 5B                 pop ebx         ;restores ebx (not necessary)

:47E983 85C0               test eax, eax   ;valid handle?

:47E985 7419               je 0047E9A0     ;no, jump to end of routine

:47E987 83C309             add ebx, 00000009  ;ebx now points to "CopyFileA"

:47E98A 53                 push ebx        ;push it hard, babe

:47E98B 50                 push eax        ;push handle



* Reference To: KERNEL32.GetProcAddress

                                  |

:47E98C E843F8FFFF         Call 0047E1D4   ;get our func. address in eax

:47E991 8D9D14FEFFFF       lea ebx, [ebp-01EC]  ;ebx now points to sourcepath

:47E997 8D4D80             lea ecx, [ebp-80]    ;ecx now points to dest.-path

:47E99A 6A00               push 00000000   ;overwrite existing file

:47E99C 51                 push ecx        ;push it twice, babe

:47E99D 53                 push ebx        ;...

:47E99E FFD0               call eax        ;final call to CopyFileA



* Referenced by Jump at Addresses:47E931(C), :47E947(C), :47E985(C)

|

:47E9A0 8BE5               mov esp, ebp   ;clean up the whole mess

:47E9A2 5D                 pop ebp        ;(stackframe)

:47E9A3 E9FD6AFCFF         jmp 004454A5   ;close bypass (see part 1)



 I know myself that the code isn't very clean or elegant but

 it works transparent for the user and that's enough for me

 for now.

 To get the full pathname of the "w32dsm00.tmp"-file we simply

 copy the way our target does it. After GetTempPath returns

 the length of the path string in eax, we add it to the pointer

 of that path-buffer and append "w32dsm00.tmp" to the string

 using the first of the above methods.

 The rest should become obvious with help of the Win32 API-

 reference.





Last Words



 I hope you enjoyed this essay and as this crack helps improving

 one of the most valuable tools it could even be useful for some,

 although THIS IS MEANT FOR EDUCATIONAL AND ENTERTAINMENT PURPOSES,

 and I am not kidding (it's no fun to follow crack instructions

 and if you use this program so much, consider rewarding the one

 who really deserves it !!!).



This is it!



Keep this great page alive and contribute !!!



Greetings to FOSSTAVOCHT !



PNA

A small addition, by PNA


I didn't do my homework. This crack only works for the

first instance of w32dasm. Please add a note somewhere

if you decide to publish it. Actually it is quite easy to retrieve

the correct filename of the tmp-file. One method is to code

another bypass-routine just before the creation of the file to get its

name and store it in the DATA section (there is still enough space

in that copyright-message.

You can leave it as a practice for others.

Bye...



PNA

  

(c) PNA 1997. All rights reversed