Saturday, June 17, 2006

Fishing Serials

Generic Method to Fish Serials
(For Learning Purpose Only!!!)



Author: iconizebyte :-)
Audience: newbies
Tools required:
- Debugger: Numega Softice, OllyDbg, TRW anything you are comfortable with.
- Disassembler: Any (Win32Dasm, IDA etc...)
DISCLAIMER: THIS ARTICLE IS MEANT FOR EDUCATIONAL PURPOSES ONLY!!!! THE AUTHOR DOESN'T TAKE ANY RESPONSIBILITY FOR YOUR ILEGAL ACTIONS!!!!

Essay:

Heehehehe..... jika anda sudah terbiasa, skip saja untuk baca hal ini :-D. Proteksi dengan menggunakan UserName/Serial ada metoda yang biasa digunakan untuk memprotek suatu software oleh si pembuat. Artikel ini akan mencoba menjelaskan pada anda metoda generik untuk mecari serila number ini. Mari kita mulai saja ga usah bertele-tele :-)

Dalam proteksi dengan nama/serial, adalah suatu hal dimana kita mengisikan hal yang perlu saja dan akhirnya kita akan mendapatkan manfaat yang "luar biasa" dari program tersebut. Program proteksi ini akan melakukan penghitungan terhadap input yang dimasukkan oleh user dengan algoritma tertentu. Nomer yang kita masukkan akan dibandingkan dan jika sesuai maka progran akan berjalan menjadi legitimate program. Voia....hoba-hoba.... registered :-)) lol.

Struktur umum dari proteksi nama/serial, yang kita perlu lihat adalah saat program (dalam kondisi kita debug dan ini dalam bentuk bahasa asembler) adalah:

call xxxxxxxx (pemanggilan terhadap alamat xxxxxxxx)

test al,al (uji terhadap register)

jne/je yyyyyyy (jump if not equal/jump if equal ke alamat yyyyyyy)

xxxxxxxx adalah lokasi yang dipanggil dan yyyyyyyy adalah lokasi pesan registered atau pesan error akan muncul.

Catatan, al dapat diganti dengan register lain kecuali esp, ebp, eip. Terkadang dalam pemanggilan pada alamat xxxxxxx diganti dengan algoritma dan rela number dengan fake number akan dibandingkan sehingga akan muncul pesan jika input dimasukkan.

jenis algorithm......
cmp real serial, false serial
je registered
jmp error message

Sekarang anggap bahwa registrasi software kita menggunakan rutin masukan berupa username dan serial number. Dalam struktur pemanggilan (call, test, je/jne structur) akan men-generate real serial dengan menggunakan nama, company dan serialnya kemudian dibandingkan dengan nilai yang sebenarnya ke register al.

@ xxxxxxxx
algoritmanya......
cmp real serial,our serial
jne yyyy
mov al,0
@ yyyyyyyy
mov al,1
ret

Maka setelah call, flag akan diset dan berdasarkan set flag tersebut, pesan yang berhubungan akan ditampilkan. Dalam jenis proteksi ini juga terkadang serial berdiri sendiri (independent) terpisah dari username artinya inputan username dan lainnya tidak dianggap oleh algoritmanya. Dalam satu kasus ada juga field yang diset *blacklisted* serial ditampilkan. Hal ini artinya bahwa serial tersebut benar tapi telah masuk daftar hitam program tersebut. Jika mendapatkan serial dalam kategori ini maka yang kita lakukan adalah menghilangkan field black listed number ini, bisa dengan merubah isi ataupun men-skip ke register selanjutnya. Cara yang termudah adalah kita buka file dll/exe dari program tersebut dalam hex editor dan kemudian mencari alamatnya, sehingga algoritma akan mengecek dengan nomor yang berbeda, dan kita akan mendapatkan pesan registered ;).

Mari kita melangkah ke selanjutnya....
Sekarang kita sudah tahu apa yang mesti kita cari. Berikut sedikit penjelasan tetenag apa yang akan kita cari selanjutnya dalam struktur asembler dari program yang kita debug. Yaitu apa yang terjadi setelah kita menekan tombol OK/Check, program akan mengambil nama dan serial kemudian menyimpannya dalam memory, lalu memanggilnya ketika akan di-compare. (Selanjutnya pake bahasa inggris yah.... :-D)

This call maybe be present after the functions or api(s). But not always. They might not even occur during our trace. But we are sure that a call is being used to calculate the serial ,so by directly finding the location of the call (through Win32Dasm), we are saving a lot of time as we know what we are looking for! But how do we find the call, test, je/jne structure. Ok here I will take a few examples and through which I hope to communicate the most.

How do we actually find the serials is that we use the error message and then using this as an error we use the debugger and find the serial. So first we need to know the error message. After that we disassemble the *.exe. Note that ,the algorithm might not always be in the .exe but it could also be in a .dll or any other file, so keep your eyes open ;). But how do you know that it is in an exe or a dll ???? Well for that matter we need to look for the error message, i.e. where it is located (in exe/dll).

After disassembling the .exe or .dll ,click on string data references. In the new window, search for the error message. Once found double click on it and it will take you to its location. Then in order to check if the error message has one or more than one references ,double click it again and if the location changes the error is also at a different location.

Now comes the important part!
Everything i.e. any message is arrived at ; due to some condition or check. For example: If the serial is correct then it will go to the location where the thank you message is displayed else it will go to a location where the error message is displayed. So any message is arrived due to a condition! They are in the form of conditional jumps (je/jne etc.....). In Win32Dasm, above a referenced string, it will tell us the location from where it is referenced or the location from where this error message is reached. Hope you got it. They, in most of the cases will be conditional jumps marked with (C) and sometimes unconditional jumps (U).

Simple analogy to conditional jumps is if statement in C and unconditional jumps is goto. It is from these locations will you find the call test je/jne structure.

Referenced by Conditional or Unconditional Jump:
|1000(c)

The above example tell that the error message is due to the conditional jump at 1000.So we go to that location and then search for the structure.

Referenced by Conditional or Unconditional Jump:
|4000(u)

Here, it is referenced by an unconditional jump. Well how is it possible. This should make it clear :
call ser_gen
test al,al
je registered message
jmp error_message(4000 here)

We now have the location of the call generating the serial. Now we need to access the program in its memory i.e. when it is running because that is when the serial is generated and compared right! So we get into the program's memory via api(s). What the program is doing is ,that it is taking the input from the fields i.e. name/serial, hence we need to use an api which is used to get the data from the fields or edit boxes. They are

GetDlgItemTextA
GetWindowTextA
GetWindowTextW
etc.....

Basic Softice Commands:
Here are the basic SoftIce:

F5:Quit
F11:Return to the location where the fn was called
F12:Return from a call
F10:Trace
F8:Go inside the call
d :Dump the value of register in the memory.
? :Evaluate

I think you know how to set breakpoints right. Good.

Firstly, we set a breakpoint on any of the api(s),the one which will cause sice to break. Then we will return to the location where this api was called(F11 in SoftIce). Then we clear the breakpoints and set a breakpoint on the call which generates (location) the serial, the one we found through Win32Dasm.The debugger should now halt the execution at the said location else ,we are not at the right place. There on we trace into the call and dump the values or evaluate the registers or memory location. It would be advisable to dump after every lea or call instruction. Now I am going to explain few examples.

Inside the call generating the serial:
some algo......
cmp eax,ABCDEF
jne error message

Well here eax might contain the real/fake serial and ABCDEF is a memory location. And since this is cmp instruction we have to check this out. We can either dump the values of eax and the memory location or evaluate it.

some algo.....
cmp eax,[ebp-04]
jne error message

Same as above but being compared with a register which ultimately points to a location. Now sometimes they directly won't give the serial but may point to a location where it might hold the serial. So to find that out we do this:
? *
or
d *

Only difference is the * before the location or register. Now the above example was when the error message was at only one place i.e. not multi referenced. What happens when it is referenced more than once??? Don't bother, follow the above procedure. The only difference is that you have to go to all the locations where it was found and check for the referenced jumps and look for call test jne/je structure. A bit lengthy.

Hope you are with me ;).
The above cases were ,when we had the error message in the string references and we could actually pinpoint the location where the serial was generated (call) and then follow the above method. But what do you do when you don't have the error message in the referenced !Not to worry ,it is quite simple to overcome this. Here we first check the number of fields provided for us. What we want is that ,the program must read all the fields ,because only after the reading all the fields ,will it proceed with the serial generation or comparison.

(FOR SOFTICE) So after setting a breakpoint on the api,we need to press F5 for one time less than the total number of fields and press F11, each time after sice breaks.

Reason:
The first time it breaks ,it means that first field has be read (scanned).So we press F11 and then F5.F5 will cause sice to break again as it will use the same api to read the next field (in most cases). So the 2nd time it breaks it will have scanned the second field as well. Got it. Same case if there are 3 fields. Think about it.

Then we have to trace till we get the error message. Note that address and then back trace. How you ask? Quite simple. It would have arrived due to a conditional jump. If possible ,then retrace in sice only by checking the locations or disassemble the file and then go to that location and check for the nearest referenced conditional or unconditional jumps and then go there and search for the call,test,je/jne structure and you should be find the correct serial.

You can use :
Alt+Up/Down Arrow Key /Alt+PgDn/PgUp, to scroll in the data window, helps sometimes to see the serial.
Ctrl+Up/Down Arrow Key /Ctrl+PgDn/PgUp, to scroll in the data window, helps sometimes to back trace but I would suggest using Win32Dasm for efficient back tracing.

Now some time you have an algorithm like this then the easy method is to reverse the algorithm Here is one eg. to explain it.

Let ecx=name,edx=length of our name.
xor eax,eax
lea ebx,[ecx+02]
xor ebx,edx
xor ebx,1234
cmp ebx,ABCD
jne error_message

Well what do you do when you intercept such an algorithm.It is as simple as a walk in the park,all you need to do is understand what the algorithm is doing.

ecx = name
edx = 2nd char of our name
ebx = 3rd char of our name

Now check the cmp instruction.ebx is being compared with ABCD.This means that if ebx=ABCD ,then serial is correct. This means we have to have the value of ebx=ABCD to get the correct serial(mind well that this is not the location ,but the value). Well how do we calculate the serial.Check the instruction before the cmp.ebx is xored with 1234. What does this mean??? Ok here is the truth table for xor:

x y f
0 0 0
1 0 1
0 1 1
1 1 0

Ok. let us consider a case say x=1, y=0
f=x^y => f=1^0 => f=0

Same way if we know f and any other variable say x we can calculate y.
f=0,x=1 =>0=1^y
The value of y can be found out by
y = f^x => y = 0^1 => y = 1
Got it.

Getting back :
ebx = ABCD (should be)
=> the previous instruction means
ABCD = ebx^1234
=> a(say) = ebx = ABCD^1234

Well 'a' should be the correct serial. What I have proposed is a very simple example but it can get pretty complex with and,or etc.... But the ultimate task is to reverse the algorithm. Then there is a case when the author implements cryptography. Well not many authors actually implement it correctly and they end up making a clown of themselves ;). To fish such serials out we need to know the type of encryption used and how it functions. Then all we have to do is examine the required parameters in the protection routine and put them in the decryption routine of the encryption. But it may be a pain.

Well that almost covers the topic. One more thing ,the entire name/serial protection depends on the author coding it, so if the author his creative ,then you might be in for something different. The author may have a generation as well as a comparison routine that is of his own. But the bottom-line is going for the error message, that always holds the key to the fish out the serial.
Thanks for reading it. Hope this helps you .

Greetz: To everybody I know ,you know who you are ;)
Good Bye

0 Comments:

Post a Comment

<< Home

<BGSOUND src="http://www.geocities.com/merdekayuk/1000kuto.mp3">