Make your own free website on
August  2001
"Grocery Companion v1.2"
Win32 Program
Win32 Code Reversing
by Bengaly
Code Reversing Strainer
Program Details
Program Name:Grocery Companion v1.2
Program Type: Saving Money Utile
Program Location: [ here ]
Program Size: 652 kb


Tools Required:
W32Dasm  - Win'95/98 Dissasembler (optional)
Softice V4.X -  De-Bugger 
Resource Builder v1.0 - resource build
Easy ( X )  Medium (   )  Hard (   )  Pro (   )
"We Are Racing Threw Time In Order To Crack Our Goal"

 Cracking A Win32 Web Utility
('Bad Protection, Good Sniff Out, Easy KeyGen')

Written By Bengaly

Grocery Companion was designed to help you save money on your grocery purchases. The main screen is broken down into aisles, so you can see how much you spend in each section of the store. A single click lets you hide a grocery item in the grocery list and shows you the new total without the hidden grocery item. Another single click lets you attach a coupon to a grocery item. A coupon section shows you the total savings from coupons. After you've finished creating your grocery list, a printed copy is only a couple of clicks away.
In Version 1.1, an option to edit Aisle headings is added. Also, the Help file has been updated. Version 1.2 features new enhancements and expanded compatibility.

Registration costs $12. The unregistered version limits you to 20 grocery items in the grocery list.

                                                About this protection

This program is registered by selecting the 'Help' button, then the 'About' button.
User name:

On successful registration the program will save your User/serial in the registry:
User: Bengaly
Name: 5379333     <-- This is Generated by the program! (It will transform the serial into HEX: 521505 in the registry)

If u want to use this software please Buy it, it's 12$ the program is very good, please support It!

The Essay

Hello and welcome to my 29th Tutorial :=).

Today we are going to Register a small program i have found on the net!
I must say the programmers Implemented a very weak Protection into the main code.
Instead making their program efficient they only make use practice on those protections more and more
Since we are going to Dig the Serial I will explain the algo and where is the Actual serial is generated.
Although there are allot of types of programs every one of them still use this lame way: CMP ->JNZ (JNE)
Enough talking..there is no point to me to keep talk as u all know how to crack such type of easy protection,
But still fun to read and gain knowledge.
Also i will teach you a trick: "how to find the program's code with Hmemcpy", a very good method i found by my self, this will Eliminate the newbies questions about F12 via Hmemcpy.
Also A keygen Explanation Include (My First KeyGen..Was Really Hard to least to me)

We load the program and go straight to the 'ABOUT'
We are welcomed by a Serial/Name input Box, now fill in the info u wish to.

Name: Bengaly
Serial: 12121212 [ Gotta love +ORC ;=) ]
Press OK button, u will greet with a Bad_Boy messageBox saying we entered a bad serial number for our name.
Hm..not too hard, but since API calls are not working with this program [GetWindowTextA,GetDlgItemTextA] for instance
We will use the System Function: HmemCPY [Memory Copy function].
So load WinICE and set the BPX on HmemCPY <enter>
Press either: 'X' / 'F5' / 'Ctrl-D' to exit.
Now that WinICE is waiting to the next Memory copy we press the OK  Button.

Note that the first break is nothing to do with our Program's Code...we are just in a DLL .
We will continue..Press F5 to read the Serial Edit Box WinICE will Drop us here:
0157:9EA3  RETF      0008
0157:9EA6  PUSH      BP
0157:9EA7  MOV       BP,SP
0157:9EA9  PUSH      DS
0157:9EAA  PUSH      EDI
0157:9EAC  PUSH      ESI
0157:9EAE  CLD
0157:9EAF  MOV       ECX,[BP+06]
0157:9EB3  JECXZ     9F2D

Hm..still nothing to do with the program's code [check routine]..keep pressing F12 from now on.
So keep pressing until You see this:
0177:0041FB72  CALL      00420360
0177:0041FB77  RET  <= The Magical Ret
0177:0041FB78  MOV       [EAX+5C],EDX
0177:0041FB7B  TEST      EDX,EDX
0177:0041FB7D  JZ        0041FB85
0177:0041FB7F  XCHG      EAX,EDX
0177:0041FB80  CALL      00412978
0177:0041FB85  RET
0177:0041FB86  MOV       EAX,EAX
0177:0041FB88  PUSH      EBX

Note that:  no metter how many times u pressed F12 if there is no API called from the program so this Method is 100% Working.
Everyone should see this in his WinICE ...that's why this method is 100% working.

This method will Eliminate the lame Questions like:
1. "how do you know how many times you need to press F12 to get to the actual code?"
2. "how can i find the program code with Hmemcpy?"

Now that we landed on the RET command we are 1 step away from the Program's Code Check Routine!
Press F12 1 time and you are inside the Check Routine.
WinICE shows us this:
0177:0046A0C0  CALL      0041FBAC           ; Read Input
0177:0046A0C5  MOV       EAX,[EBP-04]           ; EAX = Fake Serial
0177:0046A0C8  XOR        EDX,EDX                  ; EDX = 0 (Reset EDX)
0177:0046A0CA  CALL      004072B4           ; EAX='12121212' ,D ECX = '12121212'
0177:0046A0CF  MOV       EDX,[0048AE08] ;  0048AE08  =  Memory location of my fake serial
0177:0046A0D5  MOV       [EDX],EAX           ; D *EDX = '12121212'
0177:0046A0D7  MOV       EDX,[0048AD60]      ;  0048AD60 = Our Name: 'Bengaly'
0177:0046A0DD  MOV      EDX,[EDX]                ; EDX= Our Name
0177:0046A0DF  LEA        EAX,[EBP-08]            ; Not Important
0177:0046A0E2  MOV       ECX,0046A158          ;ECX =  0046A158 = 'Bad Message'
0177:0046A0E7  CALL      00403C1C                  ; EAX = Fh (15 Dec) ??
0177:0046A0EC  MOV     EAX,[EBP-08]             ; EAX = 'Bengaly'
0177:0046A0EF  CALL     00469980                    ; Algo!!!!
0177:0046A0F4  MOV      EDX,[0048AE08]        ; EDX =  0048AE08
0177:0046A0FA  CMP      EAX,[EDX]                ; ? EAX='5379333' / ? EDX = '12121212'
0177:0046A0FC  MOV     EAX,[0048ADE4]        ; Not Important
0177:0046A101  SETZ       BYTE PTR [EAX]      ; Possible Patch: SETZ->SETNZ
0177:0046A104  MOV       EAX,[0048ADE4]     ; Not Important
0177:0046A109  CMP       BYTE PTR [EAX],00  ; Flag-City: CMP  BYTE PTR [EAX],01 - PATCH
0177:0046A10C  JNZ        0046A123                  ; Jump Not Equale
0177:0046A10E  PUSH     0A                              ; save Window Handle ?

Now that won't be hard to understand, will it?
The CMP Opcode will Compare EAX and Memory location of [EDX]
D EAX at 0046A0FA Wont show Us anything in therefore Try ? EAX
And We get the number :  5379333 (Dec)
D [EDX] at 0046A0FA Wont show Us anything as well In therefore ? *[EDX] will Dump
Us what [EDX] is, in our case the Fake serial: 12121212

Note: ? *[EDX] , * is to dump the memory location, if we had done ? [EDX] we wouldn't get 12121212 cuz
We must dump the actuall memory location by adding *.

Job Done.
Coding the  keyGen

Now that we know where the real serial is compared with the fake serial, a good look up in the algo will make us
Understand how The serial is being Calculated.
So in D32Dasm goto address 0046A0EF and enter into that call, or you can use Ice-Dump's (/SCREENDUMP)
Be sure to Setup the ScreenDump to mode 1
How we do that??
1.Load proper VxD of Ice-Dump for your WinICE versions we can use his /SCREENDUMP utile /SCREENDUMP until u will see <MODE 1> (a text mode)
This will help us dump the screen seeing at WinICE.

Anyway you Remember the call i marked in YELLOW? ...No?
0046A0EF  CALL     00469980
This is the call that leads to the Algo of the program (where serial is being Calculated).
Let us step into that call...what do we see in WinICE? :
0177:00469980  PUSH      EBP
0177:00469981  MOV       EBP,ESP
0177:00469983  PUSH      ECX
0177:00469984  PUSH      EBX
0177:00469985  PUSH      ESI
0177:00469986  MOV       [EBP-04],EAX            ; EBP-04 = 'Bengaly' <= Name
0177:00469989  XOR       EBX,EBX                    ;  EBX = 0    (counter to 20 ?)
0177:0046998B  MOV       EAX,[EBP-04]           ; EAX = name
0177:0046998E  CALL      00403BD0            ; put "10 commanders"
0177:00469993  MOV       EDX,EAX              ; EDX = 14h (20dec) means 20 grocerys
0177:00469995  TEST      EDX,EDX                   ; is it really 20?
0177:00469997  JLE       004699CE                   ; no? than Jump, Else continue
0177:00469999  MOV       ECX,00000001      ; ECX = 1
0177:0046999E  MOV       EAX,[EBP-04]      ; EAX = 'Bengaly'
0177:004699A1  MOVZX     EAX,BYTE PTR [ECX+EAX-01]   ; mov first char from 'Bengaly' to EAX
0177:004699A6  SHL       EBX,04                ; shift Left 4 in EBX (4<<0 bytes = 0)
0177:004699A9  ADD       EAX,EBX                  ; EAX ('B') + EBX (0) = 'B'
0177:004699AB  JNO       004699B2                 ; Jump Not Overflow <==|
0177:004699AD  CALL      00402DC8                ;                                       |
0177:004699B2  MOV       EBX,EAX                 ; EBX = 'B'            <=====|
0177:004699B4  MOV       EAX,EBX                 ; EAX = 'B'
0177:004699B6  AND       EAX,0F000000          ; B AND 0FFFFFFF = 0
0177:004699BB  TEST      EAX,EAX            ; Eax = 0 ?
0177:004699BD  JZ        004699C6                   ; yes..Jump  <=========|
0177:004699BF  MOV       ESI,EAX                  ; ESI = 0                           |
0177:004699C1  SHR       ESI,18                      ; 0>>18                            |
0177:004699C4  XOR       EBX,ESI                   ; 'B' Xor 0                         |
0177:004699C6  NOT       EAX                         ; 0 NOT = FFFFFFFF <===|
0177:004699C8  AND       EBX,EAX            ; 'B' AND FFFFFFFF = 'B'
0177:004699CA  INC       ECX                          ; Next Char ('e')
0177:004699CB  DEC       EDX                        ; EDX = 13h (19 Dec) Counter 20->0
0177:004699CC  JNZ       0046999E                 ; While not finished Counter: MOV EAX,[EBP-04]
0177:004699CE  MOV       EAX,EBX                ; we are here from jle 004699CE
0177:004699D0  POP       ESI                    ; Restore ESI
0177:004699D1  POP       EBX                        ; Restore EBX
0177:004699D2  POP       ECX                        ; Restore ECX
0177:004699D3  POP       EBP                        ; Restore EBP
0177:004699D4  RET                                      ; Return (out of this call)

What the algo do is pretty Simple in Away:
1.get the name "10 commanders"   (add the string to the name)
3.Get length
4.loop (do while not zero, type of loop) so the loop will get every Char from the name you entered and do the flowing loop
Until it will reach to the last char!
5.EBX will be the pointer where the serial will be generated and it will pass the final serial to EAX

Now we will Delete Unnecessary asm code and Edit it so it will work on our Keygen.
Just remember it's a LOOP so you will need to add a loop statement...(you will see in the finished ripped algo).
Look below and see which code are nunnery!
PUSH EBP                       ; Delete no need to push anything
MOV       EBP,ESP          ; Delete no need to push anything
PUSH      ECX                 ; Delete no need to push anything
PUSH      EBX                 ; Delete no need to push anything
PUSH      ESI                   ; Delete no need to push anything
MOV       [EBP-04],EAX     ; Delete we already got the Name from the input box
XOR       EBX,EBX 
MOV       EAX,[EBP-04]    ; Delete   ne need to move name
CALL      00403BD0           ; Delete we already got what it does "10 commendats" string
MOV       EDX,EAX 
TEST      EDX,EDX           ; Delete no tests
JLE       004699CE             ; Delete no jumps
MOV       ECX,00000001 
MOV       EAX,[EBP-04]   ; Delete, No need to move the name again
MOVZX     EAX,BYTE PTR [ECX+"Put here Enter Buffer"-01] 
SHL       EBX,04 
ADD       EAX,EBX 
JNO       004699B2            ; Delete  No jumps
CALL      00402DC8         ; Delete No need this call anymore
MOV       EBX,EAX 
MOV       EAX,EBX 
AND       EAX,0F000000 
TEST      EAX,EAX          ; Delete we don't need Tests
JZ        004699C6              ; Delete no Jumps
MOV       ESI,EAX 
SHR       ESI,18 
XOR       EBX,ESI 
NOT       EAX 
AND       EBX,EAX 
INC       ECX 
DEC       EDX 
JNZ       0046999E           ; Delete 
MOV       EAX,EBX 
POP       ESI                    ; Delete  no need to pop
POP       EBX                  ; Delete  no need to pop
POP       ECX                  ; Delete  no need to pop
POP       EBP                  ; Delete  no need to pop
RET                                ; Delete  no need to pop

Only thing to left is to Delete Unnecery Code so we can add it properly to the ASM code and to make it
A working algo so it could generate the proper Serial from Our Name.
The Edited Algo is HERE

Now we must code the Interface of our KeyGen, download Resource Builder from: HERE
After you downloaded the program, extract the zip and install the program.
Run the program [we won't need to register it now ;D maybe in another Strainer we will]
Choose 'DIALOG' Right click and press 'ADD'
Now we will get a blank window handle.
something like that:
|_Tools_____________________________________ [x]_|
|                                                 |                               |
|  [<- ] [ok] [A] [ab] [O] [=] [=] [--]  |    V OK ( / ) Cancel  l
|__________________________ _|_________________  |

_________________________         ___________________________
|Dialog______________ [ X_]_|        |Propeties                         [ X ] |
|                                           |        |                                              |
|                                           |        |                                              |
|                                           |        |                                              |
|_______________________ _|        |                                              |
                                                     |_Caption_: |______ _______  __|
                                                     | Control ID:|                             |

Nice pic eh ? :=)
Any way, Our KeyGen need to have 2 edit boxes + 2 button (or 3 if u wish,1 for about button :=) + 2 texts )

So our Dialog should look like this now:
|Dialog______________________ [ X_] _|
|             ___________________            |
|  name  [___________________]           |
|            _ __________________            |
| serial   [___________________]           |
|                                                          |
|          [Generate]  [Exit]  [About]        |
|____________ ___________________ _|

Every Button or Text Edit has a Specific Control ID Number.
Meaning the 'Generate Button' will have: xxx number that we will call it in the ASM code.
It goes the same as the other controls in the Dialog.

Ok after you finished to create your Keygen Interface, we will save it as : Rsrc.rc (i.e.: Resource.rc)
Save it in the dir where you will put your asm file (better in Masm dir: c:\masm6\Rsrc.rc)
Now don't exit 'Resource Builder yet, we need to remember which ID number every item keep it open.

Now we will make the ASM code it self.
We will start by Declaring the Machine/Import instruction, see Below:
;-----------Import Declarations-----------------
.Model flat, StdCall 
option casemap: none 
include \masm32\include\ 
include \masm32\include\ 
include \masm32\include\ 
include \masm32\include\ 
include \masm32\include\ 
includelib \masm32\lib\user32.lib 
includelib \masm32\lib\kernel32.lib 
includelib \masm32\lib\gdi32.lib 
includelib \masm32\lib\advapi32.lib 

We can probably Delete some Lib files but that is not the metter here.
Now we will Declair Variables to our KeyGen's ASM code..Here:
PlzMore  db "1 or more chars needed to create the serial!!",0 
WindowName db "MainWindow",0 
ClassName db "Bengaly",0 
Lengthy dd 00 
Buffy db "10 Commandments",0 
Entered db 40h dup (?) 
AboutT db "This Is My First Keygenerator Crated In Win32ASM",0 
AboutC db "    Grocery Companion KeyGenerator 1.2 ",0 
ToDecimal db "%d",0 
MyS db 15 dup (?) 

Now we will put an Unintialized Data for later use:
;-----UnIntialized Variables--
hInstance HINSTANCE ? 

After we Define the variables to use in our program, we will need a code to create the window it self
Even if made a resource, the resource only put the ID controls and define them while compile.
Window Code (could be copy&paste in any win32asm program) Here:
;--------------------------------------Window Code/Hadlers--------------------------------------------
invoke GetModuleHandle, NULL 
mov hInstance,eax 
WinMain proc hInst:HINSTANCE 
mov wc.lpfnWndProc, OFFSET WndProc 
mov wc.cbClsExtra, NULL 
mov wc.cbWndExtra, DLGWINDOWEXTRA 
push hInst 
pop wc.hInstance 
mov wc.hbrBackground, COLOR_WINDOW 
mov wc.lpszMenuName, NULL 
mov wc.lpszClassName, offset ClassName 
invoke LoadIcon, hInstance, NULL 
mov wc.hIcon, eax 
mov wc.hIconSm, eax 
invoke LoadCursor,NULL,IDC_ARROW 
mov   wc.hCursor,eax 
invoke RegisterClassEx, addr wc 
invoke CreateDialogParam, hInstance, addr WindowName, NULL, NULL, NULL
mov hwnd, eax 
invoke UpdateWindow, hwnd 
invoke GetMessage, ADDR msg,NULL,0,0 
.BREAK .IF (!eax) 
invoke IsDialogMessage, hwnd, ADDR msg 
.if eax==FALSE 
invoke TranslateMessage, ADDR msg 
invoke DispatchMessage, ADDR msg 
mov     eax,msg.wParam 
WinMain endp 
WndProc proc hwnd:HWND ,uMsg:UINT, wParam:WPARAM, lParam:LPARAM 
invoke PostQuitMessage,NULL 

Ok so we have created the window with the button (Rsrc.rc remember?)
Now we need to tell the asm code what each button will do.
Here we fo that:
;---------------------Exit Button-------------------
mov eax, wParam 
push eax 
shr eax, 16 
.If eax==BN_CLICKED 
pop eax 
.If eax==109 
invoke ExitProcess,NULL 

And another Button:
;------------------------About Button--------------------------------
mov eax, wParam 
push eax 
shr eax, 16 
.If eax==BN_CLICKED 
pop eax 
.If eax==112 
invoke MessageBox,NULL,addr AboutT,addr AboutC,MB_OK 

And the last button, the Important one (the Generate button):
;-------------------------Generate Button------------------------------
mov eax, wParam 
push eax 
shr eax, 16 
.If eax==BN_CLICKED 
pop eax 
.If eax==108 
invoke GetDlgItemText,hwnd,106,addr Entered, 40h 
cmp eax,0 
jz bad 
jmp @endlength 
invoke MessageBox,NULL,addr PlzMore,addr AboutC,MB_OK 

Now while we press the Generate button the above code will be Executed :

;----------------Riped&Edited ALGP--------------------

invoke lstrcat, addr Entered, addr Buffy 
invoke lstrlen, addr Entered 
XOR       EBX,EBX 
MOV       EDX,eax 
MOV       ECX,00000001 
MOVZX     EAX,BYTE PTR [ECX+Entered-01] 
SHL       EBX,04 
ADD       EAX,EBX 
MOV       EBX,EAX 
MOV       EAX,EBX 
AND       EAX,0F000000h 
MOV       ESI,EAX 
SHR       ESI,18h 
XOR       EBX,ESI 
NOT       EAX 
AND       EBX,EAX 
INC       ECX 
DEC       EDX 
jnz loop1 
invoke wsprintf, addr MyS, addr ToDecimal, ebx 
invoke SetDlgItemText, hwnd, 107, addr MyS 

And we finish with the last code:
;-------------End windowProc Definition--------
invoke DefWindowProc,hwnd,uMsg,wParam,lParam 
xor eax,eax 
WndProc endp 
end Start 

Compile the program and see the result . (there might be 1 problem if it will ask you about: Resource.h / Rsrc.res)..
But that is not the point, the point is that u would be able to know how to code the KeyGen, finding the files i said above is easy
You can get help in #win32asm at Efnet.

Job Done.
Oh And..

Do I really have to remind you all that by buying and NOT stealing the software you use will ensure that these software houses will continue to produce even *better* software for us to use and more importantly, to continue offering even more challenges to breaking their often weak protection systems.

If your looking for cracks or serial numbers then your wasting your time, try searching elsewhere on the Web under Warez, Cracks and etc.


I would like to say thank you to all who has supported me, and helped me through my cracking days:
For his Great Essays And Skills
For his awesome Tutorials
For Help Me in Cracking & Hosting
For Help Me in Win32Asm
For Help Me in Win32Asm