achi
May 27th, 2003, 18:15
i'd like to know , if there anyone have a source for win32asm keygen with comments 4 newbies.
i think that best way to learn is get some good example.
i think that best way to learn is get some good example.
View Full Version : How to write a keygen ripping the original asm code
;===========================================================================
; KeyGen by etherlord
; Compiled with RadASM/MASM32
;===========================================================================
.386
.model flat, stdcall ;32 bit memory model
option casemap :none ;case sensitive
include REAKEYG1.inc
.code
start:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke InitCommonControls
invoke DialogBoxParam,hInstance,IDD_DIALOG1,NULL,addr DlgProc,NULL
invoke ExitProcess,0
;########################################################################
DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
mov eax,uMsg
.if eax==WM_INITDIALOG
.elseif eax==WM_COMMAND ; user press the generate button
mov eax,wParam
.IF ax==IDC_BTN1
; getting the handle of the Crackme window with FindWindow
invoke FindWindow, addr lpClassName, addr lpWindowName
.if eax!=NULL
; we have found a handle
mov hwndParent,eax
; now we have to get the handle of the subwindow with FindWindowsEx
invoke FindWindowEx,hwndParent,hwndChildAfter, addr ClWindn, NULL
; if we get a handle, time to retrieve the info
.if eax!=NULL
mov hwindfirst,eax
; we are now seeking the second textbox
invoke FindWindowEx,hwndParent,hwind, addr ClWindn, NULL
.if eax!=NULL
mov hwind,eax
invoke SendMessage,hwind,WM_GETTEXT,wParam,addr TexBuf
.if eax!=NULL
;we got some chars in the buffer, placing them back
; to our windows,
invoke SetDlgItemTextA,hWin,IDC_EDT1,addr TexBuf
; Now, we have to build the correct serial from it
pushad
; code removed from here... just serial generation
; then we print out the result
invoke SetDlgItemTextA,hWin,IDC_EDT2,addr HrdCodStr
popad
.endif
.endif
.endif
;invoke MessageBox,NULL,addr MsgBoxText, addr MsgBoxCaption, MB_OK
.endif
.endif
.elseif eax==WM_CLOSE
invoke EndDialog,hWin,0
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
DlgProc endp
end start
So, step by step :
- Find the handle of the application.
- Find the handle of the textbox where the name lie.
- Retrieve the content of the username textbox.
- Compute the correct serial.
- Either show the user the correct serial or inject it directly in the
application.
To find the handle of the application, I use WinSpector, there is
many tools of that kind floating around, any that'll show you the handle,
class, and such info will do the job. What we need to find the handle
of the application is the window name and the class name. Once found we
are ready to start our keygen.
To find the handle of the application windows, we'll use the FindWindow
API. The FindWindow API need the following params:
Syntax
HWND FindWindow(
LPCTSTR lpClassName,
LPCTSTR lpWindowName
);
Parameters
lpClassName
-----------
[in] Pointer to a null-terminated string that specifies the
class name or a class atom created by a previous call to the
RegisterClass or RegisterClassEx function. The atom must be
in the low-order word of lpClassName; the high-order word
must be zero.
If lpClassName points to a string, it specifies the window
class name. The class name can be any name registered with
RegisterClass or RegisterClassEx, or any of the predefined
control-class names.
If lpClassName is NULL, it finds any window whose title matches
the lpWindowName parameter.
lpWindowName
------------
[in] Pointer to a null-terminated string that specifies the
window name (the window's title). If this parameter is NULL,
all window names match.
Return Value
------------
If the function succeeds, the return value is a handle to the
window that has the specified class name and window name.
If the function fails, the return value is NULL. To get extended
error information, call GetLastError.
So, to get the handle, we'll use the function the following way :
includelib user32.lib
FindWindow PROTO lpClassName:HWND,lpWindowName:HWND
.data
lpClassName db "<ClassName>",0
lpWindowName db "<WindowName>",0
hwndParent dd ?
.code
......
.IF ax==IDC_BTN1
; getting the handle of the window with FindWindow
invoke FindWindow, addr lpClassName, addr lpWindowName
.if eax!=NULL
; if we get a result, store the result handle
mov hwndParent,eax
We have now the window handle stored in hwndParent. From there, we must
find the child window, the one wich handle the textbox. In case we have
several textbox, we may need to enumerate them until we got the good one.
Those objects are declared in ressources, kind of static object, once
you got a value about them this value should not change.
To find the handle of the child window, we can use the FindWindowsEx
function.
Syntax
HWND FindWindowEx(
HWND hwndParent,
HWND hwndChildAfter,
LPCTSTR lpszClass,
LPCTSTR lpszWindow
);
Parameters
hwndParent
----------
[in] Handle to the parent window whose child windows are
to be searched. If hwndParent is NULL, the function uses
the desktop window as the parent window. The function searches
among windows that are child windows of the desktop.
hwndChildAfter
--------------
[in] Handle to a child window. The search begins with the
next child window in the Z order. The child window must be
a direct child window of hwndParent, not just a descendant
window. If hwndChildAfter is NULL, the search begins with
the first child window of hwndParent.
Note that if both hwndParent and hwndChildAfter are NULL, the
function searches all top-level and message-only windows.
lpszClass
---------
[in] Pointer to a null-terminated string that specifies the
class name or a class atom created by a previous call to the
RegisterClass or RegisterClassEx function. The atom must be
placed in the low-order word of lpszClass; the high-order word
must be zero.
If lpszClass is a string, it specifies the window class name.
The class name can be any name registered with RegisterClass
or RegisterClassEx, or any of the predefined control-class names,
or it can be MAKEINTATOM(0x800). In this latter case, 0x8000 is
the atom for a menu class. For more information, see the Remarks
section of this topic.
lpszWindow
----------
[in] Pointer to a null-terminated string that specifies the
window name (the window's title). If this parameter is NULL, all
window names match.
Return Value
------------
If the function succeeds, the return value is a handle to the
window that has the specified class and window names.
If the function fails, the return value is NULL. To get extended
error information, call GetLastError.
If we consider a standard username/serial combo, the first subwindow is
usually the username textbox, the one we want to catch. If we wanted to
also grab a second textbox (company, or anything...), then we would have
to call the function a second time. This function is called the followin
way (we are assuming here that we got the hwndParent from previous call):
includelib user32.lib
FindWindowEx PROTO hwndParentWORD, hwndChildAfter
WORD,
lpszClass:HWND, lpszWindow:HWND
.data
ClWindn db "<TextBoxName>",0
hwndChildAfter dd ?
hwindfirst dd ?
.code
......
; now we have to get the handle of the subwindow with FindWindowsEx
invoke FindWindowEx,hwndParent,hwndChildAfter, addr ClWindn, NULL
.if eax!=NULL
; if we get a result, store the handle
mov hwindfirst,eax
Ok, we have now the handle we need to retrieve the info we want. But, how
could we do that ? If we where in the application, a simple WM_GETEXT would
have done the job. But we are seeking the info from an external application.
So we need to use Windows MESSAGES to send the command to the right
application.
Syntax
LRESULT SendMessage(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
);
Parameters
hWnd
----
[in] Handle to the window whose window procedure will
receive the message. If this parameter is HWND_BROADCAST,
the message is sent to all top-level windows in the system,
including disabled or invisible unowned windows, overlapped
windows, and pop-up windows; but the message is not sent
to child windows.
Msg
---
[in] Specifies the message to be sent.
wParam
------
[in] Specifies additional message-specific information.
lParam
------
[in] Specifies additional message-specific information.
Return Value
------------
The return value specifies the result of the message
processing; it depends on the message sent.
To send the WM_GETTEXT command and retrieve the result, we'll use the
following snippet :
includelib user32.lib
.data
TexBuf db "00000000000000000",0
.code
......
; here we are getting the handle of the textbox
.if eax!=NULL
; we save the handle of the textbox
mov hwind,eax
; we send the WM_GETTEXT message to the textbox
; wParam is a parameter passed to/from DlgProc
invoke SendMessage,hwind,WM_GETTEXT,wParam,addr TexBuf
.if eax!=NULL
; here we deal with the result found
And we have now the username stored in TexBuf, ready for any kind of
processing. From them, insert your algo computation and show the result
to the user. We are just showing a textbox here, but we could have as
well send a WM_SETTEXT command to the second textbox to fill the serial
in place of the user. Just a thing to remember, before messing with
register in your function, it's a good thing to save the registers. You
can choose to save only those you play with, I find it easier to user the
PUSHAD/POPAD function (push all 32 bits register in the stack) :
.if eax!=NULL
; here we deal with the result found
pushad
....
your func here
....
popad
Originally posted by FoolFox Hello, Here's one skeleton for, I've removed the serial generation as it was part of the rea course. I've just post the asm, other files are those generted by RadASM, don't think I added something in those.....the basic template is a dialogbox. Anyway, let me know if you need further details: I'm using the Masm8 Hutch's package for win32 and Ketilo RadASM as IDE. Code:
|
Originally posted by Fahr Hmm, interesting; can you let RadASM generate the code for loading the form and handling it automatically? Or do you still have to do it by hand? (If so, I'd rather stick with raw MASM). - Fahr |
Originally posted by ZaiRoN Hi All, thx for the explanation FoolFox :-) To join theory and practice I will add a simple crackme to this thread. This is a simple crackme and, to keygen it, you only need to rip the original code. I decided to attach this type of crackme because I wanted to join this thread with the thread in the newbies forum named "Copying keymaker ASM from Win32Dasm" (http://www.woodmann.net/forum/showthread.php?s=&threadid=4877) (read it, you will find a little hint :-)). In this way the project is complete and it gives you the possibility to: - learn to write a win32asm keygen - learn to rip code from a program I thought it could be an interesting idea, what do you think? Let the discussion begin :-) Good luck, ZaiRoN |
Originally posted by diz First, you are defining buffer which is only 1 byte big: @Buffer db 0 255 bytes will be more than enough: @Buffer db 255 Second, this variable will be used for MessageBox which needs string terminated with 0 so you need to initialize this var with zero's: @Buffer db 255 dup(0) Now, it will work |
The best thing for memory would be then to make it 8, since the serial is always 8 long... |
Originally posted by ZaiRoN Hi Fahr,Ok, the serial is 8 chars long but you have to remember what diz told you about MessageBox function: the serial must be followed by NULL char (00h). When you know the size of a buffer, it's better to terminate it with a 00h byte, like you have done for @Name and @Format: @Buffer db 9 dup(0) ; 9 bytes setted to 00h ZaiRoN |
I'd like to add now is that it generates the serial when you enter something in the box, instead of clicking the 'Generate' button. |
mov eax,uMsg
.IF eax==WM_COMMAND ; wm_command is been received?
mov eax, wParam
.IF ax == IDC_NAME ; IDC_NAME is the name of the edit control
shr eax, 16
.IF ax == EN_CHANGE ; EN_CHANGE is been received?
<the registration name is changed, find the new right serial>
.ENDIF
.ENDIF
.ENDIF
------ EAX (32bit) -----
| |
| -------- -AX(16)- |
| | __ __ | | __ __ | |
| ||__||__|| ||AH||AL|| |
| |________| |________| |
|________________________|
Originally posted by bart achi ty utajony satanisto ![]() |
Originally posted by bart achi ty utajony satanisto ![]() |
Originally posted by squidge Ab ceboyrzf z8, jul qba'g jr whfg gnyx ebg13 vafgrnq - ng yrnfg rirelbar (nyzbfg) haqrefgnaqf vg ![]() |
[Originally Posted by Fahr]heh, fair enough :P Well then, here is a link to my personal server containing further documentation on this project, which covers completely fictional programs and their keygenerators. http://dump.lycantrope.com:5000/keymaker.html Enjoy, - Fahr |