W32Dasm Version 8.0 Save re-enabling
(How to get our dialogs and our routines inside our targets)
(31 August 1997)
Courtesy of Fravia's page
of reverse engineering
Well, I'm impressed by this essay... I believe that we are now
leaving the realm of "simple" reverse engineering and finally entering
the "advanced" field of software "reconstruction". It suits us perfectly
that PNA's essay targets wdasm, since this target is an old "friend" that
all old and new hands know perfectly well inside.
PNA explains the patching techniques that are important
for the "crippleware" +HCU's project (project 6). The little "tricks"
he shows (for instance using Borland's copyright strings as location for
"our" strings) are well worth heading. Needless to say, the
techniques you'll learn here can be immediately applied to the many
"crippled" targets that proliferate on the Web.
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 !)
- 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:
- OPENFILENAME (struct)
Please Note: All disassembly listings assume 0x00400000 as the
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
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
: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
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
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
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-
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 !
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.
(c) PNA 1997. All rights reversed
You are deep inside Fravia's page of reverse engineering,
choose your way out:
Back to Project 0 ("Wdasm reversing")
Back to Project 6 ("crippledwarez")
Is reverse engineering legal?