| WinHex 9.53 | |||
| Intro | |||
|
|
|||
| About the program | |||
|
First released in 1995, last updated August 2000. The following operating systems are supported: Homepage: http://www.winhex.com and http://www.sf-soft.com On feature of the app is that you can load memory of a process into the program. In the help file we can read: RAM Editor Select one of the listed processes. You may access either the so-called
primary memory or the entire Please note the following limitations: Caution: Only keyboard input can be undone! The options relevant for the RAM editor are "Check for virtual memory
alteration" (security options)
|
|||
| The crack | |||
| When
we open the register form in WinHex we can see that 2 registration codes
is used, Code1 and Code2. The first thing to do is to find out where the app gets the codes and any clue of what type of code it is. Press Ctrl+D to break into SIW and put a bpx on
GetDlgItemText and press F5 to resume to Windows. Again enter the codes and press the OK button.
SIW breaks in two times for this bpx, this is nice. We end up here: 004247DB call j_GetDlgItemInt ;Get code 1 To avoid long tracing in
SIW we put a memory breakpoint, bpm, on [ebp-4] and [ebp-8], which is
where our codes goes. 00425F47 loc_425F47:
00425F47 mov al, [ebx+5Ch]
00425F4A cmp al, 24h
00425F4C jnz short loc_425F60
00425F4E mov edx, [ebp+Code1_var_4]
00425F51 mov ds:455208h, edx ; store code 1
00425F57 mov edx, [ebp+Code2_var_8]
00425F5A mov ds:45520Ch, edx ; store code 2
Now we can clear the two previous memory breaks and put two new ones on 455208h and 45520Ch. This is where our codes are moved. Start again with F5 and after a delay (delay timer used) we break in here: 0042BAB0 sub_42BAB0 proc near We can see that 7CBh bytes is moved from 455116Ch, which is before our codes, to the stack. We can also see that 45516Ch+7CBh = 455937h which are after our codes, so our codes is moved. 0040126F C9 leave 0042BAD3 lea eax, [esp+1F2Ch+var_1E4C] If we look at ebx in SIW we see that our Code1 is in ebx. 0042BAE1 cmp dword ptr [ebx], 0D9038h ; 888 888 Now, what can we make out of this then? This is the validation for Code 1. If we read it carefully we can reduce it to this: 15B38h (88 888) < Code1 < D9038h (888 888) If we can find a number that pass all this checks we have a valid number
for Code 1.
KeyGen.asm
.386
.model flat, stdcall
option casemap:none
include e:\masm32\include\windows.inc
include e:\masm32\include\kernel32.inc
include e:\masm32\include\advapi32.inc
include e:\masm32\include\user32.inc
include e:\masm32\include\masm32.inc
includelib e:\masm32\lib\user32.lib
includelib e:\masm32\lib\kernel32.lib
includelib e:\masm32\lib\advapi32.lib
includelib e:\masm32\lib\masm32.lib
.data
Tmp dd 88888
hFile dd 0
pBuffer db 255 dup(0)
pBytesWritten dd 0
pCrLf db 0Dh,0Ah
pEndTxt db "Number of Code1's: %i",0
pFileName db "c:\windows\desktop\cracker\hacks\winhex\Code1.txt",0
.code
xor ebx, ebx ;Match counter
start:
mov eax, Tmp ;Code1 to eax
.if eax > 888888
jmp done
.endif
;======================================== ; Here's the selection algo for Code1 ; See sub_42BAB0 in WinHex ;======================================== ;Idiv with 1000
mov ecx, 3E8h
cdq
idiv ecx
cmp edx, 25Fh
jz inc_Tmp
cmp edx, 315h
jz inc_Tmp
cmp edx, 7Bh
jz inc_Tmp
;Idiv with 100
mov eax, Tmp
mov ecx, 64h
cdq
idiv ecx
cmp edx, 54h
jnz inc_Tmp
;If we get to here we have a valid code in Tmp.
;Save it to file.
convert:
;Convert to ascii string
mov edx,Tmp
invoke dwtoa ,edx,addr pBuffer
;Create the file
.if hFile==0
invoke CreateFileA ,addr pFileName,\
GENERIC_WRITE,\
0,\
0,\
CREATE_ALWAYS,\
FILE_ATTRIBUTE_ARCHIVE,\
NULL
.if eax==INVALID_HANDLE_VALUE
invoke GetLastError ;Get last error in eax
jmp done
.endif
mov hFile, eax
.endif
;Save to file
invoke lstrlenA ,addr pBuffer
invoke WriteFile ,hFile,addr pBuffer,eax,addr pBytesWritten,NULL
invoke WriteFile ,hFile,addr pCrLf,2,addr pBytesWritten,NULL
;Zero out memory (max 6 bytes "888888")
mov dword ptr[pBuffer],0
mov dword ptr[pBuffer+4],0
;Increment match counter
inc ebx
inc_Tmp:
;Next code to try
inc dword ptr [Tmp]
jmp start
done: ;Write number of code1's to the end of the file
invoke wsprintf ,addr pBuffer, addr pEndTxt,ebx
invoke lstrlenA ,addr pBuffer
invoke WriteFile ,hFile,addr pBuffer,eax,addr pBytesWritten,NULL
;Close file
.if hFile!=0
invoke CloseHandle ,hFile
.endif
invoke ExitProcess ,0 end start ------------------------------------------------------------------------------------------------------------
Now we have a file with 8000 valid Code1's. Now what? If we look down a few lines we see this: 0042BB7F loc_42BB7F:We can see here that Code1 is an argument to sub_42F78C and that the return value is compared with Code2. We can assume that Code1 is manipulated in some way to equal Code2. If we trace in to this sub we quickly realize that is it not as easy as with Code1. It is messy, to say the least. Jumps and calls all over the place. Lets try our valid Code1's and see what happens. If we try the first code from our list we can see in SIW that the return value from sub_42F78C is -1 and we jump out at 42BB92. This means that a valid Code1 don't automatically get mangled to a valid Code2. I randomly picked another Code1 from the list (luck?) and this time I was luckier. The return value In eax was code 2 (not my standard 1234567890 :-). Now we got both code1 and code2 so we can register WinHex and the message "Codes OK!" comes up.
At 42BBAC after the call to sub_42F78C we find one of Dettens favorites: 0042BBAA mov al, 0Ah ;string length |
|||
| Final notes | |||
|
As you have noticed I haven't given out any codes :-). Basse Remember, If you like this program, and tested it long enough, buy it! |
|||
| www.biw-reversing.cjb.net | |||
|
|