Log in

View Full Version : Copying keymaker ASM from Win32Dasm


Fahr
June 4th, 2003, 10:30
Hello people,

as some of you may know by now, I am trying to learn how to succesfully reverse engineer stuff.

Currently I am practising on a program of a friend of mine, QMacro. I already managed to fish a serial using SoftICE, but now I want to build a keymaker, based on the code I got out of Win32Dasm. I know where the key is generated and what it needs etc., but I can't figure out a few things; for instance; push 0048D50C. That apparently refers to some other address, which immidiately does 2 jumps and then it's all a madhouse.

I looked at some tutorials who rip ASM code to build an own keymaker, but none of them pick very hard programs. This one appears to be quite difficult, at least, to me.

The original encryption used for it is a combination of Base64 and MD5. Knowing that, I could easily produce a keymaker in any non-ASM language, but I want to learn this.

Is there anyone who is willing to offer me some assistance on this one? If possible live (thru MSN or ICQ or IRC or what-not).

Thank you,
- Fahr

naides
June 4th, 2003, 11:51
Do not place links to comercial software in your posts, because web-crawlers, spiders and other minor pests pick them up and point the software companies back to the board. Then they give shit to the host, and the owner of this board.

Fahr
June 4th, 2003, 11:57
Noted and fixed, sorry for the inconvenience

JMI
June 4th, 2003, 12:14
Thanks naides:

If you keep helping out with my Mod duties, I'm going to have to start sharing my salary with you. No wait, I don't get a salary. Maybe you could put in a word with Woodmann about that.

Regards.

Fahr
June 4th, 2003, 13:53
For easier stuff I decided to start with Winzip. Using a tutorial I managed to extract all of the vital code (I think), but it keeps coming up with access violations. Apparently, when I want to messagebox the eax, it's NULL...

I really don't get what I'm doing wrong, I'll link the source here, any help will be highly appreciated

http://dump.lycantrope.com:5000/wzkey.asm

Thanks,
- Fahr

P.S.
it might be handy to note that this is MASM32 work.
and it might also be handy to note that I used THIS: http://www.woodmann.net/krobar/tutlist/tutlist1797.txt tutorial to more or less figure out what is what.
I know he concludes in a C code for the keygen, but I want to rip the ASM... I can do it in C any day...

squidge
June 4th, 2003, 14:53
MessageBoxA requires a pointer to a null terminated string. You are passing it an integer (well, dword). It doesn't know this and so takes it as a memory address, can't read it, and throws up an access violation.

Use a small buffer and convert the values in the EAX and ECX to ascii first, and then pass that to MessageBoxA.

naides
June 4th, 2003, 20:44
Quote:
Originally posted by Fahr
Hello people,

as some of you may know by now, I am trying to learn how to succesfully reverse engineer stuff.

Currently I am practising on a program of a friend of mine, QMacro. I already managed to fish a serial using SoftICE, but now I want to build a keymaker, based on the code I got out of Win32Dasm. I know where the key is generated and what it needs etc., but I can't figure out a few things; for instance; push 0048D50C. That apparently refers to some other address, which immidiately does 2 jumps and then it's all a madhouse.

I looked at some tutorials who rip ASM code to build an own keymaker, but none of them pick very hard programs. This one appears to be quite difficult, at least, to me.

The original encryption used for it is a combination of Base64 and MD5. Knowing that, I could easily produce a keymaker in any non-ASM language, but I want to learn this.

Is there anyone who is willing to offer me some assistance on this one? If possible live (thru MSN or ICQ or IRC or what-not).

Thank you,
- Fahr



There is a reason for those tuts to pick those simple programs to rip the code generating calls: because they were easy.


There is a practical limit for this method: when ripping a key generating code entails more work in finding dependencies, tracking the input and output buffers etc, than writing the code from scratch, you should opt for other options, like: writing the code from scratch.

Also keep in mind that the modularity of structured programming, in which every function and object has unambiguous input parameters, clear methods and defined outputs does not necessarily translate like so into the raw code after compilation, code optimization and linking. Raw code, where crackers do our trade, is not structured and often spaguetti like, with references and depedencies scattered all over the place, as you have seen.

Unless the call or calls that perform the key generation are very well self contained, and the external dependencies are few and explicitly defined, ripping code is a futile or unecessarily arduous endeavor.

By the way, IDA may help you better in those chores.

Fahr
June 5th, 2003, 02:24
I see your point. But as described above; the code generation of this particular program is so endlessly complex that rewriting it in C is not much of an option. I don't intend to do this program directly, that's why I started with Winzip.

On another note; how is it that IDA can offer me better assistance in this? I mean; a disassembler is a disassembler... what is the difference? (I don't know IDA too well... so bear with me here). Does IDA have something to extract a complete call with subcalls or something?

Thanks,
- Fahr

Fahr
June 5th, 2003, 02:26
Quote:
Originally posted by squidge
MessageBoxA requires a pointer to a null terminated string. You are passing it an integer (well, dword). It doesn't know this and so takes it as a memory address, can't read it, and throws up an access violation.

Use a small buffer and convert the values in the EAX and ECX to ascii first, and then pass that to MessageBoxA.


A valid point. Tho I have no idea how to do that (maybe use offset eax?), there is another problem, too. At the point where it actually calls the messageboxes, both EAX and ECX are NULL. So they're neither pointers, nor strings. They're nothing.

- Fahr

naides
June 5th, 2003, 08:38
Quote:
Originally posted by Fahr
I see your point. But as described above; the code generation of this particular program is so endlessly complex that rewriting it in C is not much of an option. I don't intend to do this program directly, that's why I started with Winzip.

On another note; how is it that IDA can offer me better assistance in this? I mean; a disassembler is a disassembler... what is the difference? (I don't know IDA too well... so bear with me here). Does IDA have something to extract a complete call with subcalls or something?

Thanks,
- Fahr


IDA has a feature in which you can reannotate the code and rename the variables from some meningless while technically correct name
to a more intuitive meaningful name

i.e.

push [esp+arg_0]

TO

push My_user_name


or

call 00452367

TO

call _MD5_routine


and IDA will figure out all the instances in which the variable( data segment:memory address) is used
or the subroutine (codesegment: memory address) is called and replace it with your renamed symbol.
After a while, code that looked like a laberinth of meaningless numbers and register names starts to look like human written code.

ZaiRoN
June 5th, 2003, 10:29
Hi All!

Fahr, don't know if you have take a look at the mini project area but, there was a thread named "keygenin!" designed for those whom want to write a win32asm keygen. I thought to join it with this thread but, we can't develop an explicit keygen for a shareware program so, I decided to write a little crackme. The algo I have used in the crackme is very similar to the winzip's name/serial algo (who has said that they are equal? :-).
The thread I am referring to is:How to write a keygen ripping the original asm code (http://www.woodmann.net/forum/showthread.php?threadid=4848).

It's not my intention to stop this thread, I wrote the crackme only because we will speak freely about how to create a complete keygen....

Regards,
ZaiRoN

Fahr
June 5th, 2003, 10:57
Quote:
Originally posted by naides
IDA has a feature in which you can reannotate the code and rename the variables from some meningless while technically correct name
to a more intuitive meaningful name

i.e.

push [esp+arg_0]

TO

push My_user_name


or

call 00452367

TO

call _MD5_routine


and IDA will figure out all the instances in which the variable( data segment:memory address) is used
or the subroutine (codesegment: memory address) is called and replace it with your renamed symbol.
After a while, code that looked like a laberinth of meaningless numbers and register names starts to look like human written code.


That sounds EXACTLY like what I need. Any pointers as to how I can manage that (don't know IDA too well).

Fahr
June 5th, 2003, 10:58
Quote:
Originally posted by ZaiRoN
Hi All!

Fahr, don't know if you have take a look at the mini project area but, there was a thread named "keygenin!" designed for those whom want to write a win32asm keygen. I thought to join it with this thread but, we can't develop an explicit keygen for a shareware program so, I decided to write a little crackme. The algo I have used in the crackme is very similar to the winzip's name/serial algo (who has said that they are equal? :-).
The thread I am referring to is:How to write a keygen ripping the original asm code (http://www.woodmann.net/forum/showthread.php?threadid=4848).

It's not my intention to stop this thread, I wrote the crackme only because we will speak freely about how to create a complete keygen....

Regards,
ZaiRoN


Thanks! I'll be sure to check it out

I already found a link under the 'Some useful places' at the bottom of this board. I guess I will check out both.

- Fahr

Fahr
June 5th, 2003, 14:15
OK, since this has been called out to be one of the keygenning threads, I guess I'll dump all my questions here (of nobody objects, of course).

As suggested I fired up IDA Pro and I'm getting the hang of it, except for 2 things;

1) I can't seem to rename a var that's like this: [ebp+var_4]
I can rename var_4, I can also rename ebp, but I can't seem to rename the combination of the 2...
2) Is it just me, or is it impossible to actually DEBUG with IDA Pro? If it is, it's a function I'm missing dearly. It would be so nice to just be able to name the registers while running thru them and seeing their vars. This way I have to rebreak in SoftICE every time I want to know a new var. (or maybe I can break out of SoftICE without letting the debugged program resume, if so, please enlighten me)

And last, I am trying to get the hang of that piece of code of QMacro. I am gettin thru most of it, but I think my ASM knowledge is still too small
Could someone please explain me what this snippet of code does?

CODE:00403FA4 sub_403FA4 proc near ; CODE XREF: sub_41D144+16p
CODE:00403FA4 ; sub_422934+11p ...
CODE:00403FA4 test eax, eax ; Eax=0?
CODE:00403FA6 jz short EndSub ; If so, go to end sub
CODE:00403FA8 mov edx, [eax-8]
CODE:00403FAB inc edx
CODE:00403FAC jle short EndSub
CODE:00403FAE lock inc dword ptr [eax-8]
CODE:00403FB2
CODE:00403FB2 EndSub: ; CODE XREF: sub_403FA4+2j
CODE:00403FB2 ; sub_403FA4+8j
CODE:00403FB2 retn ; Return
CODE:00403FB2 sub_403FA4 endp

In this case, EAX contains the username (or offset to, whichever). First it checks if eax = 0 (maybe length?), if it's NOT, it does some rather twisted stuff. Starting from the line under 'jz short EndSub', I'm lost...
It goes back 8 chars? And then increases it again? I don't get it

If I'm being too anoying, please tell me and I'll seek my answers elsewhere.

Thanks,
- Fahr

sna
June 7th, 2003, 05:25
The subroutine you pasted is part of a standard DMA (Dynamic Memory Allocation) scheme. It takes a pointer (linear address) to a string, where it's layed out as:

dw[refcount],dw[strlen],string

at [eax-8] you'll find the reference count i believe, and at [eax-4] you'll find the string length.

If you havn't yet, you might want to try debugging with OllyDebug. It let's you debug and name variables at the same time. Don't think there's any olly <-> IDA plugin that will synchronize databases but that's another project completely

regards, sna

squidge
June 7th, 2003, 07:39
There a IDA to Ollydbg converter, but I've never seen anything that'll do the other way around. At least the IDA converter prevents you from accidentally tracing into routines like strcpy etc

naides
June 7th, 2003, 08:06
Quote:
Originally posted by Fahr
OK, since this has been called out to be one of the keygenning threads, I guess I'll dump all my questions here (of nobody objects, of course).

As suggested I fired up IDA Pro and I'm getting the hang of it, except for 2 things;

1) I can't seem to rename a var that's like this: [ebp+var_4]
I can rename var_4, I can also rename ebp, but I can't seem to rename the combination of the 2...



2) Is it just me, or is it impossible to actually DEBUG with IDA Pro? If it is, it's a function I'm missing dearly. It would be so nice to just be able to name the registers while running thru them and seeing their vars. This way I have to rebreak in SoftICE every time I want to know a new var. (or maybe I can break out of SoftICE without letting the debugged program resume, if so, please enlighten me)


IDA 4.5, released this year, includes a live debugger. Previous versions are only disassemblers, so yes, if you need to see the actual contents of variables in real time, you need to have Sice running in the background. I have not seen IDA 4.5 debugger in action, so I cannot comment on its use and quality.




And last, I am trying to get the hang of that piece of code of QMacro. I am gettin thru most of it, but I think my ASM knowledge is still too small
Could someone please explain me what this snippet of code does?

CODE:00403FA4 sub_403FA4 proc near ; CODE XREF: sub_41D144+16 p
CODE:00403FA4 ; sub_422934+11 p ...

Notice that the address 0043FA4 does not advance, so what you are seeing are comments added by IDA. This is a subroutine called from 41D144 and 422934, below.

CODE:00403FA4 test eax, eax ; Eax=0?

Notice that eax is used as a pointer in 403FA8. so in this step it is checking if the pointer is NULL. If so, we simply return by performing the conditional jump to EndSub at instruction 403FA6

CODE:00403FA6 jz short EndSub ; If so, go to end sub
CODE:00403FA8 mov edx, [eax-8]

The dword pointed by eax-8 is loaded into edx

CODE:00403FAB inc edx

Then incremented


CODE:00403FAC jle short EndSub

If the contents of edx was FFFFFFFF, and gets incremented, turns into 00000000 which sets the Zero flag, and the carry flag. In such case, the conditional jump at 403FAC happens, meaning we do nothing else and jump to the end of the suroutine



CODE:00403FAE lock inc dword ptr [eax-8]

Now, the increment we did at 403FAB happened to A COPY of the variable pointed by eax-8, which temporarily stored in edx. Once we make sure the increment will not wrap around and make it zero, we perform the increment operation on the actual variable


CODE:00403FB2
CODE:00403FB2 EndSub: ; CODE XREF: sub_403FA4+2 j
CODE:00403FB2 ; sub_403FA4+8 j
CODE:00403FB2 retn

And we are out of here

; Return
CODE:00403FB2 sub_403FA4 endp

In this case, EAX contains the username (or offset to, whichever). First it checks if eax = 0 (maybe length?)
EAX is a pointer.

, if it's NOT, it does some rather twisted stuff. Starting from the line under 'jz short EndSub', I'm lost...

It is working on a variable 8 bytes below the position pointed by EAX.

Review the significance of brackets, which is the assembly way to work with pointers and references



It goes back 8 chars? And then increases it again? I don't get it

If I'm being too anoying, please tell me and I'll seek my answers elsewhere.

Thanks,
- Fahr

Fahr
June 7th, 2003, 10:48
Ok! Thanks for the explanation

So what it basically does is increase a dword that [eax-8] is the pointer to?

Or to put it in C:

DWORD* MyDWORD = NULL;
*MyDWORD++;

or am I wrong?

Fahr
June 7th, 2003, 15:56
Quote:
Originally posted by naides
IDA 4.5, released this year, includes a live debugger. Previous versions are only disassemblers, so yes, if you need to see the actual contents of variables in real time, you need to have Sice running in the background. I have not seen IDA 4.5 debugger in action, so I cannot comment on its use and quality.


I got IDA 4.5 now, according to help it contains a debugger, but the actual debugger menu is not present

so much for that idea...

- Fahr

JMI
June 7th, 2003, 15:59
That's because, if you've been reading about the copy you found, it is a modified "demo version" and never contained the "debugger" portion of the code.

Regards.

naides
June 7th, 2003, 21:52
Quote:
Originally posted by Fahr
Ok! Thanks for the explanation

So what it basically does is increase a dword that [eax-8] is the pointer to?

Or to put it in C:

DWORD* MyDWORD = NULL;
*MyDWORD++;

or am I wrong?


Not exactly. It only increases the variable pointed by MyDWORD if MyDWORD is not NULL

Fahr
June 8th, 2003, 06:22
Quote:
Originally posted by naides
Not exactly. It only increases the variable pointed by MyDWORD if MyDWORD is not NULL


And what does that mean if the DWORD points to a string? That it goes 1 char further?

Also, I think this code is bogus, cuz it writes in EAX and then modifies it, but after it's done to Name, Email and Serial, it does a xor eax, eax...
Whatever it is, I think it was generated by the compiler for some weird reason, but it doesn't seem to have any actual meaning...

- Fahr

naides
June 8th, 2003, 14:22
Quote:
Originally posted by Fahr
And what does that mean if the DWORD points to a string? That it goes 1 char further?

Also, I think this code is bogus, cuz it writes in EAX and then modifies it, but after it's done to Name, Email and Serial, it does a xor eax, eax...
Whatever it is, I think it was generated by the compiler for some weird reason, but it doesn't seem to have any actual meaning...

- Fahr



I actually downloaded the app we are talking about and traced with softIce around the code you are interested in.

Number One, as far as I can tell this code does not get called during serial validation, but I may be wrong, because I did not dig too much into the serial validation key generation routines.

At start up this subroutine gets call repeatedly from position sub_422934+11

eax points to a structure that contains, at eax, a null terminated string which corresponds to the name of a windows API, like 'CreateMutexA' etc. before it, at position [eax-04] there is a dword containing the length of the string pointed by eax.
at [eax-08] there is a dword flag which at live tracing almost invariably contained 'FFFFFFFF' or -1, which is a rather common flag. every time your little subroutine got called, the 'FFFFFFF' at [eax-08] was moved to edx, edx was incremented and it wrapped around to zero, so the actual flag at [eax-08] was not incremented and left with the value 'FFFFFFFF'

you can see all this action if you type in SoftIce: dd eax-08, while you are tracing through the code. in the data window you will see the structure I am talking about.


Second point, this code, appears to me, has to do with Import symbols, IAT decoding etc, general housekeeping of a Win32 PE app, and not so much into the specifics of key validation; but I may be wrong, because I never saw this subroutine called from the other location at sub_41D144+16.

Third Point:

Your questions are naive, but they are smart. that is why I take some time into digging some answers, but, you need to read 'The Art of Assembly' as you trace trough code, so you learn to get a feel of what it is going on. By definition, computer code may be cryptic, but it is NOT ambiguous. if a CPU can figure outl what it is going on, you certainly can.


Fourth, The code in Qmacro does not seem to me as heavily guarded and full of traps to a cracker, if they at some point echoed the right key in memory.

Fahr
June 8th, 2003, 14:32
Thanks for the info, I'll be sure to look into it.

So far I have been able to create a keymaker for it in Delphi, knowing what I know. Tracing through the code, I was able to grab a serial from memory. Retracing it I found some interesting things;

First it pastes together your Name, Email and some key he hardcoded into it (QM-26092001-1637-MarkvanRenswoude), that's the date, time and name of the author (pretty stupid to hardcode it)
This new 'key' it then generates gets put through some kind of introcate process and produces an output of 32 charachters HEX. With my knowledge of PHP, I was able to define it as an actual MD5 hash of the exact string it created. Comparing this MD5 hash to the actual code, it became clear that he creates the actual serial as follows:

QM- + HASH chars 5 - 15 + - + HASH chars 1 - 3

in Delphi:
Code:

GenerationKey := Name + Email + 'QM-26092001-1637-MarkvanRenswoude';

// MD5
GenerationKey := MD5Print(MD5String(GenerationKey));

// Generate FinalKey
EdtSerial.Text := 'QM-' + Copy(GenerationKey, 5, 10) + '-' + Copy(GenerationKey, 1, 3);


Eventhough this works like a charm, I am still not satisfied. This program uses a very wellknown hash that I was accidentally able to recognize, but other programs don't. So my quest for dumping this keymaker to ASM still continues.

What is this 'The Art of Assembly' you speak of? Sounds good.
I am also digging through the assembly tuts at Krobar. I hope they're good.

Thanks,
- Fahr

naides
June 8th, 2003, 17:26
The Art of Assembly is one of several OnLine, for-free assembly reference E-books, which you may easily find by typing 'the art of assembly' in google. one version is at hxxp://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/toc.html

nothing to it, it is just a handy reference for obscure and not so obscure asm opcodes, variable formats, and so on. you may also find it as .pdf file for local printing, and off-line browsing.

Fahr
June 9th, 2003, 06:14
heh, I am never offline, so I'll stick with this one

Looks like a nice book, I'll read it through, thanks

- Fahr