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 | |||
|