Cracking W32Dasm v8.5 (*NEW protection scheme!*) - by Frog's Print -





Right after downloading this brand new version of W32Dasm ("MMX Compatible"!) I just

thought that I would crack it as usual but wait....what a surprise:

-No more 'DeletefileA'!

-No more 'dec dword ptr[ebx+xxxxxxx]!



I run it, load a file and run the good old PS.COM and...nothing! The W32DSMxx.TMP file

has been deleted!



Another (good) surprise is that now, we can select the fonts. This option was disable in

the previous versions (a lot of people seemed to have problems with the default one).



Anyway, let's have a deeper look and crack it:





1/ The counter



I cracked versions 6, 7 and 8, therefore I know that the counter's setup occurs 

between the following 2 calls:

-OWL50f.TFindReplaceDialog

-KERNEL32.GlobalAlloc



In W32Dasm80 (i.e. previous version 8.0) we had:



* Reference To: OWL50f.TFindReplaceDialog::TData::TData(ulong,int), Ord:0000h

:0044110B E830D70300              Call 0047E840

:00441110 83C40C                  add esp, 0000000C

:00441113 C7837958540001000000    mov dword ptr [ebx+00545879], 00000001

:0044111D C783364C540054010000    mov dword ptr [ebx+00544C36], 00000154   ; < HERE!

:00441127 68F4010000              push 000001F4

:0044112C 6A40                    push 00000040

* Reference To: KERNEL32.GlobalAlloc, Ord:0000h

:0044112E E855D10300              Call 0047E288





So, let's have a look in W32Dasm85 at the OWL50f.TFindReplaceDialog:



* Reference To: OWL50f.TFindReplaceDialog::TData::TData(ulong,int), Ord:0000h

:00438F98 E889E00300              Call 00477026

:00438F9D 83C40C                  add esp, 0000000C

* Possible StringData Ref from Data Obj ->"\W32DEMO8.HLP"

:00438FA0 BE4B474800              mov esi, 0048474B

:00438FA5 8DBBE0605400            lea edi, dword ptr [ebx+60E0]          ; < ???

:00438FAB 8D839E5D5400            lea eax, dword ptr [ebx+5D9E]          ; < ???

:00438FB1 8983584D4900            mov dword ptr [ebx+4D58], eax          ; < ???

:00438FB7 C7831959540001000000    mov dword ptr [ebx+00545919], 00000001

:00438FC1 68F4010000              push 000001F4

:00438FC6 6A40                    push 00000040

* Reference To: KERNEL32.GlobalAlloc, Ord:0000h

:00438FC8 E8D7DA0300              Call 00476AA4





We found 3 new instructions instead of the usual mov dword ptr [ebx+xxxxxxxx],xxxxxxxx.

What's going on? Let's see...



With Soft Ice, load W32Dasm85 and bpx the OWL50f.@TFindReplaceDialog (don't forget to add

it inside your WinIce.dat otherwise you'll get nothing). 

When SoftIce breaks into this function, press F11 and then put 3 Breakpoints on memory

access as per follow:



:BPM ebx+60E0 RW

:BPM ebx+5D9E RW

:BPM ebx+4D58 RW



******

BEFORE pressing CTRL-D to let W32Dasm running DISABLE them (':bd *') otherwise 

you will lock-up your PC.

******



Open a file "to disassemble" inside wdasm and then enable the three breakpoints (':be *').



SoftIce pops out here :



:0043ADF4 55                      push ebp

:0043ADF5 8BEC                    mov ebp, esp

:0043ADF7 8B550C                  mov edx, dword ptr [ebp+0C]

:0043ADFA 8B4508                  mov eax, dword ptr [ebp+08]

:0043ADFD 33C9                    xor ecx, ecx

:0043ADFF 89880B625400            mov dword ptr [eax+620B], ecx

:0043AE05 8B88584D4900            mov ecx, dword ptr [eax+4D58]

:0043AE0B 0FB68900040000          movzx ecx, byte ptr [ecx+00000400] ; < HERE! 

:0043AE12 83C1D3                  add ecx, FFFFFFD3

:0043AE15 81F99B000000            cmp ecx, 0000009B

:0043AE1B 7D0C                    jge 0043AE29

:0043AE1D 6A00                    push 00000000

:0043AE1F 52                      push edx

:0043AE20 8B02                    mov eax, dword ptr [edx]

:0043AE22 FF10                    call dword ptr [eax]

:0043AE24 83C408                  add esp, 00000008

:0043AE27 5D                      pop ebp

:0043AE28 C3                      ret



BPMB #013F:00C7D188 RW



Let's see what means the "movzx ecx, byte ptr [ecx+00000400]" instruction, which 

caused the break:



:d ecx+00000400



And you'll fetch its value in the data window: FF (Hex)

The address is CS:00D2E5CE.

Right below we have a "cmp ecx, 0000009B". If you didn't press any keys under W32DASM yet,

when typing ':? ECX-9B' in SoftIce you'll get : 55 (Dec).

That's it! This version of W32Dasm allows you up to 55 operations. Payload number one :-)



Now clear all breakpoints and BPM at CS:00D2E5CE (Read AND Write):



Each time you'll press CTRL-D SoftIce will pop up again and again. There no way you can

leave it. This means that our target is PERMANENTLY checking how many operations 

left we have.



Let's now disable the Breakpoint (in order to be able to go back to W32Dasm). Then 

press once any key (in the target's ToolBar) to decrement the counter.

Back to SofIce, enable your Breakpoint again:

You'll get another break and at offset CS:00D2E5CE you'll see: FE (Hex). So, here it is!

This is our counter, no doubts about that! FF-1 is FE!



The break occurred here (it may differ in your case, as there are many checking):



:0043E9BE 33D2                    xor edx, edx

:0043E9C0 8A939E615400            mov dl, byte ptr [ebx+0054619E] ; < Read counter 

:0043E9C6 83C2D9                  add edx, FFFFFFD9

:0043E9C9 81FAA1000000            cmp edx, 000000A1               ; < Enough credits left?

:0043E9CF 7D0C                    jge 0043E9DD

:0043E9D1 6A00                    push 00000000

:0043E9D3 57                      push edi

:0043E9D4 8B0F                    mov ecx, dword ptr [edi]

:0043E9D6 FF11                    call dword ptr [ecx]

:0043E9D8 83C408                  add esp, 00000008

:0043E9DB EB7F                    jmp 0043EA5C





Pressing CTRL-D again now we land here:



:004514CD 55                      push ebp

:004514CE 8BEC                    mov ebp, esp

:004514D0 53                      push ebx

:004514D1 56                      push esi

:004514D2 8B750C                  mov esi, dword ptr [ebp+0C]

:004514D5 8B5D08                  mov ebx, dword ptr [ebp+08]

:004514D8 33C0                    xor eax, eax

:004514DA 8A839E615400            mov al, byte ptr [ebx+0054619E]  ; < Read Counter

:004514E0 83C0EE                  add eax, FFFFFFEE

:004514E3 3DB6000000              cmp eax, 000000B6                ; < Enough credits left?

:004514E8 7D0C                    jge 004514F6

:004514EA 6A00                    push 00000000

:004514EC 56                      push esi

:004514ED 8B16                    mov edx, dword ptr [esi]

:004514EF FF12                    call dword ptr [edx]

:004514F1 83C408                  add esp, 00000008

:004514F4 EB37                    jmp 0045152D





And so on and so on....



You'll land in +/- 20 similar pieces of code. Most of them are identical but I found 

out some others that are checked using different 'tips'. In fact, W32dasm will check 

the counter exactly at 32 locations and, as said above, continuously.



But look how the comparison occurs each time, using my last Break:

 

:004514DA 8A839E615400    mov al, byte ptr [ebx+0054619E]  ; < Store Counter in AL

:004514E0 83C0EE          add eax, FFFFFFEE

:004514E3 3DB6000000      cmp eax, 000000B6                ; < Enough credits left?

:004514E8 7D0C            jge 004514F6



Peter Urbanik seems to have learned a lot from our essays!

Remember the followjng (you may find useful to check the cracks for the previous

versions... the HISTORY of a protection scheme is always very useful for our purposes):

With the previous versions of W32Dasm, we had a counter setup using a "mov dword ptr'

instructions (in W32DASM8: mov dword ptr [ebx+00544C36], 00000154) which was subsequently

decremented each time we pressed a key. 

We used to change it to "mov dword ptr [ebx+xxxxxxxx], 0000FFFF" so that we had a total

amount of 65535 operations allowed (a little less in fact).



But here, there's no way for us to do the same, that's Urbanik "counter_measure":



:004514DA 8A839E615400            mov al, byte ptr [ebx+0054619E] 



As you can see, 'al' will contain the counter's value. A low register is only a byte, 

unfortunately, therefore its maximum value cannot be higher than FF (255 Dec)... and 

something more! It has ALREADY been set to FF at the beginning!

So we cannot enlarge our total amount of operations left.

I noticed that this occurs nearly all the time: this value is at times stored in AL, 

sometimes in BL or DL.



Well, well, clever trick!



Anyway...let's crack it:



First of all, let's check again our last break:



:004514CD 55                   push ebp

:004514CE 8BEC                 mov ebp, esp

:004514D0 53                   push ebx

:004514D1 56                   push esi

:004514D2 8B750C               mov esi, dword ptr [ebp+0C]

:004514D5 8B5D08               mov ebx, dword ptr [ebp+08]

:004514D8 33C0                 xor eax, eax

:004514DA 8A839E615400         mov al, byte ptr [ebx+0054619E]  ; < Read Counter

:004514E0 83C0EE               add eax, FFFFFFEE

:004514E3 3DB6000000           cmp eax, 000000B6                ; < Enough credits left?

:004514E8 7D0C                 jge 004514F6

:004514EA 6A00                 push 00000000

:004514EC 56                   push esi

:004514ED 8B16                 mov edx, dword ptr [esi]

:004514EF FF12                 call dword ptr [edx]

:004514F1 83C408               add esp, 00000008

:004514F4 EB37                 jmp 0045152D



In order to see if I'm right, with SoftIce I will modify:



:004514E3 3DB6000000              cmp eax, 000000B6 



and change it to:



:004514E3 3DB6000000              cmp eax, 000000B7



Now, we should only have 54 operations allowed. Disable all Breakpoints and then BPX at

:004514EA (after the JGE). As the program is checking 32 different locations I want to be

sure my crack will work.



Back to W32DASM press the 'Goto Start' boutton 53 times (53 because we have already 

pressed it once:=) and... softIce pops after the 53th time!



So now we can crack:



We had:



:004514DA 8A839E615400         mov al, byte ptr [ebx+0054619E]  ; < Read Counter

:004514E0 83C0EE               add eax, FFFFFFEE

:004514E3 3DB6000000           cmp eax, 000000B6                ; < No more than 55?

:004514E8 7D0C                 jge 004514F6                     ; < Jump if <=55 else...

:004514EA 6A00                 push 00000000                    ; < ...sorry boy...

:004514EC 56                   push esi                         ; < ...

:004514ED 8B16                 mov edx, dword ptr [esi]         ; < ...

:004514EF FF12                 call dword ptr [edx]             ; < ...

:004514F1 83C408               add esp, 00000008                ; < ...

:004514F4 EB37                 jmp 0045152D                     ; < ...bye bye.



We change it to:



:004514DA 8A839E615400        mov al, byte ptr [ebx+0054619E]  ; < Read Counter

:004514E0 83C0EE              add eax, FFFFFFEE

:004514E3 3DB7000000          cmp eax, 000000B7                ; <*No more than 54!!!

:004514E8 7D0C                jge 004514F6                     ; < Jump if <=54 else...

:004514EA 66C7839E615400FF00  mov word ptr[ebx+0054619E],00FF  ; <* ..give us full credits

:004514F3 90                  nop                              ; <* again!

:00050AF4 EB00                jmp 004514F6                     ; <* Go ahead boy...



So, each time we will have only 1 operation left, the counter will be set back to its

maximum value (we could crack anywhere else within the 32 similar comparisons and would

get the same result:=).



******************************************************************

Note about the counter:





1/

If you put a breakpoint on ebx+0054619E (BPM at CS:00D2E5CE *Write ONLY*), go back

to W32Dasm here are the locations where the counter's pointer will be decremented 

each time you press a key:



(offsets show the locations where the breaks occured under SoftIce)



Goto Start	:4515AC

Hex Data	:43CD43

Goto Code	:43B61C

Search	:43D685

Goto PEP	:45169F

Goto Page	:43AFB3

Jump		:43C559

Ret Jmp	none

Call		:43C751

Ret Call	none

Imp.funct.	none		Clicking in the list: 45EA91

Exp.funct.	none		Clicking in the list: 45EA91

Code Hex	:43CA8B

Menu Ref	none		Clicking in the list: 45EA91

Dlg Ref	none		Clicking in the list: 45EA91

Str Ref	none		Clicking in the list: 45EA91



Here is how the code at CS:00D2E5CE is decremented each time the 'Goto 

Start' button is pressed:



* Reference To: USER32.InvalidateRect, Ord:0000h

:0045159E E803560200           Call 00476BA6

:004515A3 80C3B1               add bl, B1

:004515A6 33C9                 xor ecx, ecx

:004515A8 8ACB                 mov cl, bl

:004515AA 890F                 mov dword ptr [edi], ecx

:004515AC 885E63               mov byte ptr [esi+63], bl ;< Store operations left

:004515AF 5F                   pop edi                   ;  in CS:00D2E5CE

:004515B0 5E                   pop esi

:004515B1 5B                   pop ebx

:004515B2 5D                   pop ebp

:004515B3 C3                   ret





2/

I read several times about a flag which is set to '1' when you have reached the 

total of operations allowed.

Yes, there is one. In W32Dasm85 it is 'ebx+0001E441' (it was the same in W32Dasm8):



:0043CAAA 8B8341E40100      mov eax, dword ptr [ebx+E441] ; < HERE

:0043CAB0 85C0              test eax, eax                 ; < Are there any

:0043CAB2 7471              je 0043CB25                   ;   operation left.

:0043CAB4 6AFF              push FFFFFFFF                 ; < No...



* Reference To: USER32.MessageBeep, Ord:0000h             ; < ..so get the message box

:0043CAB6 E839A10300       Call 00476BF4



When set to '1' it will display the message box with: "The Demo limits the total of

operations per session."



But we DO NOT have to crack it as it is ONLY use to display this message. Like the 

counter, it is permanetly checked by W32Dasm.



3/

It seems to me that this crack may not work (??) with W32Dsm85's debugger in some 

rare situations (depending on which key is pressed...) though I didn't get into 

trouble while using it. 

If you meet such a problem, try to change the "cmp eax, 000000B6" to 

"cmp eax, 000000B8" or "cmp eax, 000000B9"... instead of "cmp eax, 000000B7".

Anyway, W32DASM's debugging feature is useless and amazingly slow (who would use it 

to crack??) so I'm not really bothered about that! 

********************************************************************



The counter is cracked and now...





2/ The file deletion



As there's no call to DeleteFileA, let's see how W32DSMxx.TMP is created.



:BPX GetTempPathA



Load any file and SoftIce pops here:





* Reference To: KERNEL32.GetTempPathA, Ord:0000h          ; < Check Temp directory

:0045D63E E855940100           Call 00476A98

:0045D643 0FBE8C05D7FEFFFF     movsx ecx, byte ptr [ebp + eax - 00000129]

:0045D64B 83F95C               cmp ecx, 0000005C

:0045D64E 7508                 jne 0045D658

:0045D650 C68405D7FEFFFF00     mov byte ptr [ebp + eax - 00000129], 00



* Referenced by a Jump at Address:0045D64E(C)

:0045D658 8BC6                 mov eax, esi

:0045D65A 46                   inc esi

:0045D65B 50                   push eax



* Possible StringData Ref from Data Obj ->"\w32dsm%02d.tmp"  ; < W32DSMxx.TMP

:0045D65C 68C6C34800           push 0048C3C6

:0045D661 8D55DC               lea edx, dword ptr [ebp-24]

:0045D664 52                   push edx



* Reference To: USER32.wsprintfA, Ord:0000h

:0045D665 E8A2950100           Call 00476C0C

:0045D66A 83C40C               add esp, 0000000C

:0045D66D 8D4DDC               lea ecx, dword ptr [ebp-24]

:0045D670 51                   push ecx

:0045D671 8D85D8FEFFFF         lea eax, dword ptr [ebp+FED8]

:0045D677 50                   push eax



* Reference To: KERNEL32.lstrcatA, Ord:0000h

:0045D678 E891930100           Call 00476A0E

:0045D67D 8D95D8FEFFFF         lea edx, dword ptr [ebp+FED8]

:0045D683 52                   push edx

:0045D684 8D8B74514900         lea ecx, dword ptr [ebx+5174]

:0045D68A 51                   push ecx



* Reference To: KERNEL32.lstrcpyA, Ord:0000h

:0045D68B E8DE930100           Call 00476A6E

:0045D690 6A00                 push 00000000

:0045D692 57                   push edi                     ; < ??

:0045D693 6A02                 push 00000002                ; < Delete if it exists

:0045D695 8D83F44D4900         lea eax, dword ptr [ebx+4DF4]

:0045D69B 50                   push eax

:0045D69C 6A00                 push 00000000

:0045D69E 68000000C0           push C0000000

:0045D6A3 8D9374514900         lea edx, dword ptr [ebx+5174]

:0045D6A9 52                   push edx



* Reference To: KERNEL32.CreateFileA, Ord:0000h             ; < Create it

:0045D6AA E8F9920100           Call 004769A8

:0045D6AF 83F8FF               cmp eax, FFFFFFFF

:0045D6B2 750B                 jne 0045D6BF

:0045D6B4 83FE19               cmp esi, 00000019

:0045D6B7 0F8675FFFFFF         jbe 0045D632

:0045D6BD 33C0                 xor eax, eax




OK, we see that the "push 00000002" will erase any similar file existing in your 

Temporary directory.

But what could be the "PUSH EDI" right above?



Searching back for it we find it here:



:0045D5EB BF02010004          mov edi, 04000102         ; < HA HA! 



Here it is.

The '04' is (was) our problem. 



Ain't that a "FILE_FLAG_DELETE_ON_CLOSE" (parameter passes to the CreateFileA 

function)which means that the file will be deleted when the handles it uses 

are closed? With this, no more DeleteFileA are needed to erase the file. 

Clever again... a good try, Peter!



Now we can crack.



We had:



:0045D5EB BF02010004              mov edi, 04000102 



We change it to:



:0045D5EB BF80000000              mov edi, 00000080 



With this change, a call to DeleteFileA would be necessary to delete the file. 

Our file will not be hidden anymore either.



As we do not want W32Dasm to erase any W32DSMxx.TMP file if one already exists 

in our temporary directory:



We had



:0045D693 6A02                    push 00000002



We change it to:



:0045D693 6A01                    push 00000001





Having the W32DsmXX.tmp in the same directory of the file I am disassembling would 

be far much better than having it in my C:\windows\temp directory. I did read Wuzat's 

essay, and liked his trick to change the call to GetTempPathA with a call to 

GetCurrentDirectoryA... therefore:



We had:



:0045D63E E855940100              Call KERNEL32.GetTempPathA



We change it to:



:0045D63E E801A1B1BF              Call KERNEL32.GetCurrentDirectoryA



And finally, you can rename "W32DSMxx.TMP" to "W32DSMxx.TXT" or whatever as long 

as you only modify the 6 first characters and the extension.



************************************************************************************





What should we think about this new version of Wdasm's protection?



1/ The 'good' things (from "our" point):

-  I think that this new protection is far more clever than the one used in the 

   previous version of W32Dasm (though, unfortunately, it still doesn't take too 

   much time to crack, c'mon Peter, you can protect better than that :=). 

-  In fact, due to this scheme, I had to delve deeper inside W32Dasm's code in 

   order to solve it, therefore this should indeed alienate the wannaby cracker... 

   on the other side, this allowed me to understand far better how this target 

   works, allowing me to perform a better crack than for the past versions. 

That's good!



2/ The 'bad' things:

- The counter is checked so many times that it is hard NOT to find it... may be it is 

  NOT a good idea to check so oft...

- It seems to me that as long as W32Dasm will use any "ordinary" temporary file to 

  store the listing, we will always be able to crack it quickly... yet there are 

  MANY other possibilities dear Peter (memory files, faked files, leeched files, 

  infected files just to name the most obvious ones :-)





That's all for now.



Frog's Print, 20 June 1997



frog_s_print@thepentagon.com








Go back to Ghiribizzo's Homepage