Log in

View Full Version : How to write a keygen ripping the original asm code


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.

FoolFox
May 28th, 2003, 01:29
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:

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

ZaiRoN
May 29th, 2003, 06:52
Hi achi,
I agree with you about the fact that the best way to learn is to start from some good example but we also need a bit of theory. To learn how to keygen a program, you have only to understand how the name/serial routine works. After that, when you know how the routine works, if you want to write a keygenerator you have to know how to write a simple program, in assembly or c or in the language you like.
The source posted by FoolFox is correct but if you want to learn how to write a program, take a look at Iczelion's site: http://win32asm.cjb.net/
The tutorial section contains interesting tutorials on how to write win32 applications.

Tell us if to write a win32 application is really what you want to learn, we could leave this thread for all those whom want to learn how to write a simple application (or a keygenerator template ;-))

ZaiRoN

FoolFox
June 2nd, 2003, 03:31
Hello,

Yeah, Zairon is right, maybe I was a little bit straightforward on
this one

just in case, here's some details on the keygen I'had made
a while ago for a friend, it's just some notes on why the
sample is done this way :

Code:

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



But the main point, is the one shown by Zairon, that you need
first to understand the algo used in the prog you want to
keygen.

Hope this help to clear it a little bit.

Regards
FoolFox

ZaiRoN
June 5th, 2003, 10:13
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

Fahr
June 5th, 2003, 14:26
Quote:
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:

<--snip-->


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

evaluator
June 5th, 2003, 14:44
hello ZaiRoN & others..

this thread seems to me too iLLegalz!

2 little tech questions I inject here:
I have dlded masm8 & about 2 month fight with it..

Q1: So Masm can't MMX? or can(where to read how?)?
//
Q2: Can't force Masm to Immediate memory R/W..
e.g.
if I wrote:
mov eax, dword ptr[00402000]..

this will anyway:
mov eax, 00402000..

So not supported?

*********
DEPIH is Greyt!

ZaiRoN
June 5th, 2003, 17:04
Hi evaluator!

>Q1: So Masm can't MMX? or can(where to read how?)?
You can but you have to use .MMX directive.

>Q2: Can't force Masm to Immediate memory R/W..
I am not totally sure but I don't think you can work directly with virtual address... Delphi can?

For specific masm questions you can take a look at these two boards:
http://www.masmforum.com/
http://board.win32asmcommunity.net/


ZaiRoN

evaluator
June 6th, 2003, 04:06
ye, Delpih can
mayb, better you switch from masm!?

"I am to old" for inject in other forums
Please, can you describe how put this .MMX
directive or make for me header..
(but no big prob, do DB..)

FoolFox
June 6th, 2003, 06:35
Hello,

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


Yeah, RadASM come with basic templates, such as dialoggbox,
window squeletton, and the code work as is.

Of course, depending on what you want to achieve, you may
have to add some extra functionnality, handling message, and
so on. If you add a button on the ressource, you'll have to
deal accordingly in your source...

But for little projects, RadASM let you quickly do some windows
stuff...

@evaluator:

you can write the .mmx directive just before the .code directive.


Regards
FoolFox

evaluator
June 6th, 2003, 14:10
thanx you very match!
this works, also .XMM works

I searched in HLP files about MMX but nothing found.
judge me..

"RTFM or NOT RTFM <- thiS waS a queStion!" (W.FoolFox)

Fahr
June 8th, 2003, 08:46
Quote:
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


Ok, I did your keygen and it came out nice
Except for one little detail
For some reason, the wsprintfa doesn't produce a nice 8 digit number, instead it produces the correct serial (first 8 digits) and then keeps repeating the last 5 digits of the serial for numerous times. Anyone care to enlighten me as to what is wrong?

Here is my code and exe:
http://dump.lycantrope.com:5000/keymaker.asm
http://dump.lycantrope.com:5000/keymaker.exe

I know the name is still hardcoded, but this is only a tryout for getting the code. Once it works ok, I'll make it into a nice dialog.

- Fahr

squidge
June 8th, 2003, 09:12
Try changing this line:

@Buffer db 0

To this:

@Buffer db 20 dup (0h)

That way you have 20 bytes to store the serial, instead of just one

diz
June 8th, 2003, 09:15
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

Fahr
June 8th, 2003, 09:16
Well, that worked :P

Guess I need some lessons on reservations still.

Tho, why 20?

Fahr
June 8th, 2003, 09:17
Quote:
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


Ah, so the 20 is not significant. The best thing for memory would be then to make it 8, since the serial is always 8 long...

ZaiRoN
June 8th, 2003, 12:15
Hi Fahr,
Quote:
The best thing for memory would be then to make it 8, since the serial is always 8 long...
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

Fahr
June 8th, 2003, 12:40
Quote:
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


Hmm, isn't it so that 8 in fact MEANS 9? I thought the count starts at 0, see some other ppls remarks on how when it's 0, the size is 1. Makes me think that when it's 8, the size is 9 :P

- Fahr

Fahr
June 8th, 2003, 13:03
ok, another small thing; how can I check if the string I have in @Name actually is longer than 0? I assume I could copy it to eax and then test eax, eax, but that doesn't seem to work...

- Fahr

squidge
June 8th, 2003, 14:08
8 will give you 8 bytes, where go from 0 - 7. 9 will give you 9 bytes, 0 - 8.

To make sure the name length is greater than zero bytes, just check the first byte, like so :

mov eax, @name
mov bl, [eax]
cmp bl, 0
je lengthiszero

You may not need the "cmp", but it's best to leave it in there for now.

Fahr
June 8th, 2003, 14:14
I knew it (about the bytes)

also, on

mov eax, @Serial

it gives the following error:

Keymaker.asm(191) : error A2070: invalid instruction operands

I tried it with offset @Serial en addr @Serial, but both don't seem to work... (no errors, but it doesn't work as it's supposed to (always triggers))

- Fahr

diz
June 8th, 2003, 15:00
mov eax, dword ptr @Name
mov bl, [eax]
cmp bl,0
..

or the other way:

mov bl, byte ptr @Name
cmp bl,0
..

Like someone proposed to you, you should read some book, you'r smart, you'll get it fast.

Fahr
June 8th, 2003, 15:08
Thanks that works.

Except for the fact that bl doesn't actually contain the LENGTH of the string (of course). Do I have to loop it till 0 to fetch the length or is there a simpler way (I need to check it against 8)

As for reading books, I'm on it. Reading Krobar's tuts right now, hope it'll provide me with some insight.

- Fahr

diz
June 8th, 2003, 15:29
Yes, you should compare every character against 0h. If you have text in a editbox (like you final keygen will have, I think) the GetDlgItemText function will return number of characters so you can easily check string lenght while retriving it from editbox.

Fahr
June 8th, 2003, 15:34
That's not the problem. I know I can read the length from EAX.

The problem is that after generation when it pushes it through a wsprintfA, any zero's in front get cut off. So I want to know the length of the output, if it's less than 8, I have to paste the missing 0s back in front.

- Fahr

diz
June 8th, 2003, 15:51
Look at wsprintf lpFmt parameter. It will do the job automaticly if you specify right formating.

squidge
June 8th, 2003, 16:47
To get the length of a string does require a loop, but it's quite simple:

MOV EDI, @buffer
XOR ECX, ECX
DEC ECX
XOR AL, AL
REPNE SCAS BYTE PTR [EDI]
NOT ECX
DEC ECX

Most likely not the most optimised piece of code, but it should work

If you just want to pad a hex string with zeroes however, just tell the printf call that you want to do that. Eg:

Instead of %X which will give you (say) 123456
Use %8X which will give you 00123456

Fahr
June 9th, 2003, 06:01
duh, I should have thought of the %8X (eventhough it's %.8X, otherwise it fills with [spaces] instead of 0s :P)

Anyways, I guess my keymaker is ready.

For the sake of others following this thread, I will post it here, with source and all. Enjoy.

And thanks to all those who helped me put it together

- Fahr

squidge
June 9th, 2003, 07:22
doh! I meant %08X, not %8X otherwise it pads with spaces, like you say. Don't know how %.8X works, but hey, who cares as long as it works

Fahr
June 9th, 2003, 07:51
Hmm, I dunno about %08X, but %.8X works for sure :P

The only thing 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.
A friend of mine told me that I would have to subclass the editbox and write its own message handler... seems a bit too much to me. Any simpler ways?

- Fahr

Fahr
June 9th, 2003, 08:29
here's a repost of the, slightly altered, keymaker. Previous one was removed because of certain references that I could not include.

squidge
June 9th, 2003, 09:09
There's a change event from the edit box you should be able to obtain that'll send you a message just like the generate button does when you click it.

ZaiRoN
June 9th, 2003, 09:11
Hi Fahr,
Quote:
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.
You can use EN_CHANGE message, this message is sent when the user has taken an action that may have altered text in an edit control. Take a look at this snippet:
Code:
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

ZaiRoN

Fahr
June 9th, 2003, 09:57
Cool, that worked

I am fully satisfied with the results now :P

Also, does this mean that 'ax' is by default the HIWORD of eax?
And if so, then why shr eax, 16? Why not just read the LOWORD register (al, isn't it?).

Hmm, and I thought it was eax -> ah, al... not ax...

confused yet again :S

diz
June 9th, 2003, 11:28
Code:
------ EAX (32bit) -----
| |
| -------- -AX(16)- |
| | __ __ | | __ __ | |
| ||__||__|| ||AH||AL|| |
| |________| |________| |
|________________________|


well, something like this

there is no direct access to high word of eax, you need to shr it 16 bits (move 16 bits to the right) to move high word to the LOWORD and then read it from ax

Fahr
June 9th, 2003, 11:58
Hmm, I see. Thanks for the little picture, it makes a lot of things more clear :P

Learned another thing again

On learning; I've been digging through some ASM references, books etc. now, but I notice that most of them are AT LEAST 6 years old. On top of that, even more only talk of DOS...

The best I could find so far is:
http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/toc.html

but even that one is 6 years old. Is there nothing more recent?

- Fahr

bart
June 9th, 2003, 12:18
achi ty utajony satanisto

Fahr
June 9th, 2003, 12:35
Quote:
Originally posted by bart
achi ty utajony satanisto


wtf?

diz
June 9th, 2003, 12:58
Quote:
Originally posted by bart
achi ty utajony satanisto


nie mow ze ten gosc to achi.. chyba ze mowisz o mnie, jezeli tak to pudlo

sorry for non english, it's the last time :P

squidge
June 9th, 2003, 13:12
Ab ceboyrzf z8, jul qba'g jr whfg gnyx ebg13 vafgrnq - ng yrnfg rirelbar (nyzbfg) haqrefgnaqf vg

Kayaker
June 9th, 2003, 13:30
Quote:
Originally posted by squidge
Ab ceboyrzf z8, jul qba'g jr whfg gnyx ebg13 vafgrnq - ng yrnfg rirelbar (nyzbfg) haqrefgnaqf vg


V qba\'g. Bu jnvg n zvahgr...

squidge
June 9th, 2003, 14:58

diz
June 9th, 2003, 16:16
BRCRTEUABSTSEOATESXFEAAIE

http://www.randomhouse.com/doubleday/davinci/
pass second riddle to decipher

JMI
June 9th, 2003, 16:44
et tu Brute?

Regards.

Fahr
June 9th, 2003, 17:41
A cesar box, very funny

but what is the rest? Gibberish? Or actual encodings?

Fahr
June 10th, 2003, 16:45
ok, as a going on of this little project, I decided to dig into another program closely related to the original target. I managed to fish out a serial without any problems, I was also able to locate the Keygen call in IDA and name it, etc. etc.

However, putting it to ASM is hell. The entire keygen is full of what seem to be external references (like _strcpy and __isctype, which I can't find in any of the MASM includes (even searched w/o the __)). The most weird things are calls to _malloc and _free. Why on earth would a keygen want to reserve memory? It seems all too weird.

Then there's also calls to things like MulyiByteToWideChar. It seems to me like it's converting from Unicode to Ascii and back...

Anyways, is there any way to include all these functions in MASM, cuz I don't feel like retyping them all when they are probably available in some lib... and is it even NEEDED?

Thanks,
- Fahr

dELTA
June 10th, 2003, 18:05
MultiByteToWideChar is a normal Win32 API function, and you can thus import it easily from MASM (as with any other API/DLL-call), even without knowing at all what the hell it does if you so please. Those string and memory management functions are really easy to emulate, and they should be in every keygenners asm-toolbox anyway, so just start typing (either in your asm editor or in google, both methods will yield complete results quite shortly I'm certain ). Paste their code here then if you write/download them, it would be a nice contribution to this project anyway.


dELTA

Fahr
June 11th, 2003, 11:40
Ok, thanks for the suggestions

So far I've been able to find _strcpy, that MultiByte thing was a typo on my side... sorry.

malloc and free both appear in HLA Library, but that's a whole other assembler it seems... I don't want to let go of MASM... so I guess I'll type them all over.

Results will be posted here, when done.

- Fahr

Fahr
June 11th, 2003, 13:41
I'm now more or less copying the code from IDA ASM output 1 on 1, this works ok, except for the fact that one function wants to jump to a label inside another function...

It doesn't seem like MASM understands this too well... so what to do about that?

- Fahr

Fahr
June 11th, 2003, 15:04
ok, I'm giving up... it's prolly A LOT easier to rewrite this one in a HLL instead of ripping ASM.

I got it running (more or less), but the output is only 000252 (on my name), I traced the problem to some dword var that triggers a jump in the target program, but not in my keymaker. It points to the offset of some __ctype, which is a HUGE var, starting with

unicode 0, < ((((((( H>

and then a buttload of other crap. I don't know where this strange unicode string came from, but it seems totally irrelevant to the actual process. As is 90% of the other crap I ripped, yet it wont run w/o all of it...

So I'm going for HLL, if anyone wants my code so far, just ask and I'll post it.

- Fahr

Fahr
June 11th, 2003, 15:37
Disregard the above 3 posts;

I DID IT! (woohoo, cheer, cheer). Turns out that unicode string was not a unicode string, but more like some kind of encryption key. Playing around with IDA, I found the option to rightclick it and click 'Data', which turned it into a nice, non-unicode array

Pasting that array instead of what I had fixed the problem, just like that it gives out fine serials now

I will spend the next day or 2 cleaning up my code (it's a terrible, terrible mess, all direct rips from IDA output, etc. etc.) and comment it. Expect it here soonish

- Fahr

squidge
June 11th, 2003, 16:27
Well done

dELTA
June 11th, 2003, 16:47
Ok, nice, but I actually meant to write those functions yourself, not shamelessly ripping the asm code. Most of them have really simple functionality, which you can emulate very easily with own functions. You can then use these home-made functions for any keygens having algos referencing them, nice and clean.


dELTA

Fahr
June 12th, 2003, 02:09
I will polish up those functions and comment them, so I don't see what's wrong with copying them from IDA. I mean; how on earth am I supposed to figure out myself what _malloc is? Especially since that one calls upon many others, like __sbh_page_alloc (or something like that).

Anyways, the functions as I have them work, so I'll seperate them in an includable ASM file for everyone here to use.

- Fahr

dELTA
June 12th, 2003, 06:26
If you ever made a single C program, you will most likely know what malloc is, believe me. Otherwise you can easily look it up in any C reference (and the same goes for the other functions you mentioned). And as soon as you know what it is, you don't have to care about their underlying implementation anymore (and whatever internal calls it might make).

In the case of malloc, I'd emulate it with a three line wrapper to GlobalAlloc or VirtualAlloc and be done with it. How many lines of code is your ripped _malloc? I would suspect it's more than three lines anyway.


dELTA

Fahr
June 12th, 2003, 10:46
heh, you're probably right, of course. I might as well mention that I work fulltime as a VC++/PHP programmer, but we mainly do DBase stuff and it's all MFC, so I never actually work with stuff like VirtualAlloc (tho I used it in Delphi in some project a while ago... can't remember what, tho).

Anyways, I'll be sure to figure its works and try to make that wrapper (the calls as IDA ripped them eventually also call VirtualAlloc), as I will with the other calls.

Wish me luck!

- Fahr

ZaiRoN
June 12th, 2003, 11:28
Good luck

Btw, you are doing a great job! Congratulations :-)

ZaiRoN

Fahr
June 12th, 2003, 11:50
Thanks

However, new research shows that that whole _malloc stuff seems totally unneeded. While testing I commented the entire _malloc proc out leaving only this:

_malloc proc
retn
_malloc endp

and it works fine... what to conclude? Am I simply lucky this time? Or is there really actually no need for _malloc (I tried with several names and lengths)?

- Fahr

ZaiRoN
June 12th, 2003, 12:01
Hi Fahr,
what to conclude? Simple, the program does not use malloc in the name/serial algo, nothing more...

ZaiRoN

Fahr
June 12th, 2003, 15:03
OK! I figured it. All the Alloc stuff has to do with support for Unicode. Since I have no desire at all to make a unicode keymaker, I will rip out all the unneeded code now (already made my program 3 times smaller in code, with all the IDA crap I didn't need anymore).

Anyways, still working on it, stay tuned!

- Fahr

Fahr
June 15th, 2003, 13:27
It's finished!

Should I strip it of all references to any actual program before posting it? Or can I post it as-is on my own server and link it here?

- Fahr

dELTA
June 15th, 2003, 13:34
You probably should not post a (link to) working keygen to a specific program here, no.

It's not the end result that matters anyway, it's the journey, and we believe you anyway.


dELTA

Fahr
June 15th, 2003, 13:37
Of course, I get that. But it's more or less part of this thread. Many people helped me build it.

So is it ok if I just kill off all the official names in it? Or can I post it elsewhere and link here to an external server with a page containing it or what not?

Or what?

- Fahr

dELTA
June 15th, 2003, 13:40
I guess you can post a link saying "here is a link to my personal server, where you can find further documentation about this project".

But you are of course welcome to share any technical details of cool and useful stuff that you may have learned and/or discovered during this project here, it's just that a working keygen is not really necessary for anything.

And it is of course up to you what kind of PMs you send to people.


dELTA

Fahr
June 15th, 2003, 13:47
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

aerosmith
January 9th, 2004, 13:37
Quote:
[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



Anyone have Farhr work im interested in looking at it all. but the link no longer works.

monguz
January 12th, 2004, 08:32
The right URL is: hxxp://dump.lycantrope.com/keymaker.html

CU