EMO Style ForumPro - Hos Geldiniz
Understanding the Knight Online packet structure Uyeols10

Join the forum, it's quick and easy

EMO Style ForumPro - Hos Geldiniz
Understanding the Knight Online packet structure Uyeols10
EMO Style ForumPro - Hos Geldiniz
Would you like to react to this message? Create an account in a few clicks or log in to continue.
Giriş yap

Şifremi unuttum

Istatistikler
Toplam 203 kayıtlı kullanıcımız var
Son kaydolan kullanıcımız: crayzboy76

Kullanıcılarımız toplam 1186 mesaj attılar bunda 862 konu
Tarıyıcı
 Kapı
 Indeks
 Üye Listesi
 Profil
 SSS
 Arama
Arama
 
 

Sonuç :
 


Rechercher çıkıntı araştırma

RSS akısı


Yahoo! 
MSN 
AOL 
Netvibes 
Bloglines 


Anahtar-kelime

pointer  kutu  loot  

Kimler hatta?
Toplam 2 kullanıcı online :: 0 Kayıtlı, 0 Gizli ve 2 Misafir

Yok

[ Bütün listeye bak ]


Sitede bugüne kadar en çok 217 kişi C.tesi Tem. 29, 2017 1:46 am tarihinde online oldu.
En son konular
» İnternetten Para Kazandıran Oyun ! Ödeme Alt Limiti Yok ! DEV KONU
Understanding the Knight Online packet structure I_icon_minitimeCuma Ağus. 29, 2014 8:33 am tarafından Hello EMO

» goldenchase.net maden yaparak para kazanma
Understanding the Knight Online packet structure I_icon_minitimeCuma Ağus. 29, 2014 8:18 am tarafından Hello EMO

» etichal hacker görsel egitim seti
Understanding the Knight Online packet structure I_icon_minitimeÇarş. Ağus. 06, 2014 4:57 am tarafından Hello EMO

» KO TBL Source C#
Understanding the Knight Online packet structure I_icon_minitimePtsi Ara. 09, 2013 6:36 am tarafından Hello EMO

» x86 Registers
Understanding the Knight Online packet structure I_icon_minitimeC.tesi Ağus. 24, 2013 5:02 am tarafından Hello EMO

» [Tutorial] Pegando Address, Pointers de WYD
Understanding the Knight Online packet structure I_icon_minitimeÇarş. Tem. 10, 2013 7:25 am tarafından Hello EMO

» [Tutorial] Pegando Address, Pointers de CS Metodo²
Understanding the Knight Online packet structure I_icon_minitimeÇarş. Tem. 10, 2013 7:23 am tarafından Hello EMO

» [Tutorial] Aprendendo basico deASM OLLYDBG
Understanding the Knight Online packet structure I_icon_minitimeÇarş. Tem. 10, 2013 7:22 am tarafından Hello EMO

» Basic C# DLL injector
Understanding the Knight Online packet structure I_icon_minitimePtsi Tem. 08, 2013 7:48 am tarafından Hello EMO

Reklam

Understanding the Knight Online packet structure

Aşağa gitmek

Understanding the Knight Online packet structure Empty Understanding the Knight Online packet structure

Mesaj tarafından Hello EMO Çarş. Şub. 23, 2011 8:32 am

[quote name='twostars' timestamp='1296413622' post='60']
Knight Online, like most client/server software (but not all; for example, IRC clients all use the same protocol - IRC's!), uses it's own packet structure or protocol.
A (short) Knight Online packet might look like this (hex string form - AA == 0xAA):

Kod:
AA5501000155AA


Lets make it easier to read.
Kod:
AA
55
01
00
01
55
AA

That's better.

The first thing you should make a note of, is that the packet starts with AA 55, and ends with 55 AA. You will find that this is common with all Knight Online packets.
These are, in respective order, our packet header and packet tail. They serve no other purpose than to indicate the start and end of a packet.

Kod:
AA 55 (packet header)
01
00
01
55 AA (packet tail)

This is our example packet so far.

Now, the next byte in the packet (directly after AA55), is 01. 01 in decimal form, is "1". Well, that part was obvious, anyway. I wonder what this part is for? It's hard to tell.. so, let's compare it to another packet:
Kod:
AA 55 (packet header)
15
00
F3
08
00
74
77
6F
73
74
61
72
73
08
00
70
61
73
73
77
6F
72
64
55 AA (packet tail)

That's a much larger packet! 29 whole bytes!

Hmm, this makes little sense. It's all in hex form... maybe we should try converting it to ASCII form, that may just give us a hint.
To do this, (although slow), we can use the Windows calculator! (start->run->calc).
However, by default, we cannot use hexadecimal.. as we are running in "Standard" mode. Easy to change, just click the "View" menu, and select "Scientific".
Make sure "Hex" is selected, then type in the first: 15.
To convert it to decimal, now select "Dec". You'll see that "15" was replaced with... 21! This is our ASCII key code. From there, it's a simple hop, skip and a jump to our ASCII key. If you're unfamiliar with the ASCII key codes, a helpful resource is http://www.zelos.org.uk/Resources/ASCII/. Plain and simple, and to the point. No pictures; you can use your browser's "Find/Search" function to skip straight to your key.

Kod:
AA 55 (packet header)
hex = decimal (ASCII key code) = character
15 = 21 = 1
00 = 0 = <NULL>
F3 = 243 = ò
08 = 8 = <unprintable>
00 = 0 = <NULL>
74 = 116 = t
77 = 119 = w
6F = 111 = o
73 = 115 = s
74 = 116 = t
61 = 097 = a (the 0 is prefixed to align the list so that it's easier to see)
72 = 114 = r
73 = 115 = s
08 = 8 = <unprintable>
00 = 0 = <NULL>
70 = 112 = p
61 = 097 = a (the 0 is prefixed to align the list so that it's easier to see)
73 = 115 = s
73 = 115 = s
77 = 119 = w
6F = 111 = o
72 = 114 = r
64 = 100 = d
55 AA (packet tail)


Now that packet's purpose suddenly becomes a lot clearer! It's the password logger embedded with the USKO client. (Okay, if you believed that for one second, leave this thread please). No, but really, it's the login packet.

What's important to note, is that not all of the bytes were characters. For now, we'll just take a look at the strings.

Kod:
AA 55 (packet header)
15
00
F3

08
00

74 77 6F 73 74 61 72 73
t  w  o  s  t  a  r    s

08
00

70 61 73 73 77 6F 72 64
p  a  s  s  w  o  r  d

55 AA (packet tail)

We've identified where our account ID and password are in that mix, but why is there a
Kod:
08 00

before our account ID and one before our password?

Are you familiar with Pascal? If yes, this should be an easy one.
If no, lets think about how the strings could be identified from the packet.

Well, to start with, the server can only read one byte at a time. It doesn't know what will be ahead of that byte, perhaps it's the end of the packet, or perhaps it's not part of the string? How can it find out? To find out, it must know how many bytes to read.
And this is exactly what happens in KO's case - directly before any string, KO must always send the length of the string (Pascal style! This is also how Pascal's strings work). This way, it knows how many bytes are in the string, so that it knows how many to read.

So, lets look at that part of the packet again:
Kod:
08
00

74 77 6F 73 74 61 72 73
t  w  o  s  t  a  r    s

08
00

70 61 73 73 77 6F 72 64
p  a  s  s  w  o  r  d

Notice how "twostars" is 8 bytes long, therefore "08 00" is prefixed before it. Same with "password". As you can see here, this is exactly what's happening!

But wait... why is "00" straight afterwards? They're separate bytes!
Yes, they are separate bytes. However, a byte is limited to a maximum value of 255.. therefore, the maximum string length would have to be 255.
Of course, for the login packet, this is a generous size.. however, prefixing the string's length in front of the string is a global convention. Knight Online uses a single function to identify strings; it is not packet independant. This means that the maximum string length is spread over two bytes.

In conclusion, our string length is stored in a 2 byte (16 bits - 8 bits to a byte) variable.
The name of this datatype differs per programming language, however a couple are:
Kod:

C++
__int16 (short. In older C implementations, the int datatype represented 16 bits)

VB6
Integer

Pascal

SmallInt


So, lets see our packet structure so far:
Kod:

AA 55 (packet header)
15
00
F3

08 00 - Account ID length (8 bytes long)

74 77 6F 73 74 61 72 73 - Account ID
t  w  o  s  t  a  r    s

08 00 - Password length (8 bytes long)

70 61 73 73 77 6F 72 64 - Password
p  a  s  s  w  o  r  d

55 AA (packet tail)


Excluding the packet header/tail, we've identified 20 out of 23 bytes. Looking good!! Very Happy
That leaves us with 3 unidentified bytes.
Kod:
AA 55 (packet header)
15
00
F3

Hmm, what could they possibly be.

See that 00? Lets see if "15" is really a 16-bit datatype (short/Integer/SmallInt) as well!
That makes: 15 00.
In decimal form: 21.

If that's right, where does 21 fit? Wait... how many bytes have we solved again? 20!
Oh, it's 20, not quite 21. Sad

But wait.. lets go back a step.
How many bytes do we have altogether [excluding header/tail]?
Kod:
15
00
F3

- 3 bytes

08 00 - Account ID length (8 bytes long)

- 2 bytes (keeping a running tally, 2 bytes + 3 bytes = 5 bytes)

74 77 6F 73 74 61 72 73 - Account ID
t  w  o  s  t  a  r    s

- 8 bytes (running tally: 8 bytes + 5 bytes = 13 bytes)

08 00 - Password length (8 bytes long)

- 2 bytes (running tally: 13 bytes + 2 bytes = 15 bytes)

70 61 73 73 77 6F 72 64 - Password
p  a  s  s  w  o  r  d

- 8 bytes (running tally: 15 bytes + 8 bytes = 23 bytes)

We have a total of 23 bytes.

Now, lets, for a moment, exclude the part of the packet that we're dealing with. So, that's the two bytes "15 00".

We're left with:
Kod:

F3

- 1 byte

08 00 - Account ID length (8 bytes long)

- 2 bytes (keeping a running tally, 2 bytes + 1 byte = 3 bytes)

74 77 6F 73 74 61 72 73 - Account ID
t  w  o  s  t  a  r    s

- 8 bytes (running tally: 8 bytes + 3 bytes = 11 bytes)

08 00 - Password length (8 bytes long)

- 2 bytes (running tally: 11 bytes + 2 bytes = 13 bytes)

70 61 73 73 77 6F 72 64 - Password
p  a  s  s  w  o  r  d

- 8 bytes (running tally: 13 bytes + 8 bytes = 21 bytes)

Success! We just got 21.

It seems, if this is right, we have just worked out that the first two bytes are the packet's length. That is, the length of the data in the packet.
This makes sense, as the server needs to know how many bytes there are to read. Just like the strings!

So.. our packet is now nearly completely identified - just one byte left!
Kod:
AA 55 (packet header)
15 00 - Packet content length

F3

08 00 - Account ID length (8 bytes long)

74 77 6F 73 74 61 72 73 - Account ID
t  w  o  s  t  a  r    s

08 00 - Password length (8 bytes long)

70 61 73 73 77 6F 72 64 - Password
p  a  s  s  w  o  r  d

55 AA (packet tail)


Hmm, F3. In decimal form, it is 243! Wow! I don't think that's a length, somehow. We've already identified the rest of the packet. But wait, how does the server know what the packet's for? It knows when the packet starts (packet header: AA 55), it knows how many bytes to read (the length: 15 00), skipping past this unknown byte, it knows how long the following string is by using the prefixed length (08 00), .. the same for the next string .., and where it ends (packet tail: 55 AA).

What's missing? Of course! Something to IDENTIFY the packet. Packet identifiers are typically called opcodes. Thus, F3 is our opcode.

That's it! We've figured out the packet! We now know how F3 (our login packet) works.
Of course, most of the procedure was taking educated guesses by finding patterns. This doesn't mean our definition of the packet is correct (however, in this case it is, because I have double checked. Razz).

How can we double check though?
There are numerous ways we can double check.

With KO, we're lucky - an old version of the server source was released. Though, currently, all of USKO's login server packets are encrypted.. the decrypted packets do match up with the old source. This isn't always the case however, but I guess mgame found that there wasn't too much need to change how it was done; it worked, they're getting income, they're happy.

So, on to double checking!

If we happen to check the released 1.081 login server source, you will see that "Define.h" defines our packet op code:
Kod:
#define LS_LOGIN_REQ                0xF3

Yes! It fits!

Lets confirm the rest of the packet. To do this, we can check "User.cpp".

Scrolling down, you'll notice
Kod:
void CUser::Parsing(int len, char *pData)
{
    int index = 0, send_index = 0, i=0, client_version = 0, usercount = 0;
    char buff[2048];
    memset( buff, 0x00, 2048 );
    BYTE command = GetByte( pData, index );

    switch( command ) {
    case LS_VERSION_REQ:
        SetByte( buff, LS_VERSION_REQ, send_index );
        SetShort( buff, m_pMain->m_nLastVersion, send_index );
        Send( buff, send_index );
        break;
    case LS_SERVERLIST:
        SetByte( buff, LS_SERVERLIST, send_index );
        SetByte( buff, m_pMain->m_nServerCount, send_index );
        for(i=0; i<m_pMain->m_ServerList.size(); i++) {     
            SetShort ( buff, strlen(m_pMain->m_ServerList[i]->strServerIP),      send_index );
            SetString( buff, m_pMain->m_ServerList[i]->strServerIP,              strlen(m_pMain->m_ServerList[i]->strServerIP) ,    send_index );
            SetShort ( buff, strlen(m_pMain->m_ServerList[i]->strServerName), send_index );
            SetString( buff, m_pMain->m_ServerList[i]->strServerName,          strlen( m_pMain->m_ServerList[i]->strServerName ), send_index );         
            SetShort ( buff, (m_pMain->m_ServerList[i]->sUserCount),          send_index); 
        }
        Send( buff, send_index );
        break;
    case LS_DOWNLOADINFO_REQ:
        client_version = GetShort( pData, index );
        SendDownloadInfo( client_version );
        break;
    case LS_LOGIN_REQ:
        LogInReq( pData+index);
        break;

Where I stopped pasting is our stop - at the LS_LOGIN_REQ case:
Kod:

    case LS_LOGIN_REQ:
        LogInReq( pData+index);
        break;

So, if the opcode is LS_LOGIN_REQ (0xF3).. it shall send us to LogInReq, passing the packet buffer with it so that we can handle the packet from there.
Note: Not all login server packets are handled in their own function. Most of them are small and can be handled right away, in it's case - where it's packet is identified.

So, keep scrolling down and you'll see:
Kod:

void CUser::LogInReq(char *pBuf)
{
    int index = 0, idlen=0, pwdlen = 0, send_index = 0, result = 0, serverno = 0;
    BOOL bCurrentuser = FALSE;
    char send_buff[256]; memset( send_buff, 0x00, 256 );
    char serverip[20]; memset( serverip, 0x00, 20 );
    char accountid[MAX_ID_SIZE+1], pwd[13];

    memset( accountid, NULL, MAX_ID_SIZE+1 );
    memset( pwd, NULL, 13 );

    idlen = GetShort( pBuf, index );

    GetString( accountid, pBuf, idlen, index );
    pwdlen = GetShort( pBuf, index );

    if( idlen > MAX_ID_SIZE || idlen <= 0 || pwdlen > 12 || pwdlen < 0)
        goto fail_return;

    GetString( pwd, pBuf, pwdlen, index );

    result = m_pMain->m_DBProcess.AccountLogin( accountid, pwd );
    SetByte( send_buff, LS_LOGIN_REQ, send_index );
    SetByte( send_buff, result, send_index );     
    Send( send_buff, send_index );
    return;
fail_return:
    SetByte( send_buff, LS_LOGIN_REQ, send_index );
    SetByte( send_buff, 0x02, send_index );                // id, pwd ÀÌ»ó...
    Send( send_buff, send_index );
}

As this isn't a C++ guide, we'll just look at the process (everything else I removed, so as to avoid any confusion).

Kod:

int index = 0, idlen=0, pwdlen = 0;

This declares our integer/number variables. These are all 4 byte integers, large enough to contain any value with a size of 1 byte to 4.

Kod:
    string accountid, pwd;

Declares our string variables; account ID and password.

This is where we are in the packet; the login server has already worked out the packet's contents from the length provided.
You will notice that it does not handle 55 AA. That is because the login server has already read the packet using the length provided, and was left with:

Kod:

F3 - Packet identifier (opcode)

08 00 - Account ID length (8 bytes long)

74 77 6F 73 74 61 72 73 - Account ID
t  w  o  s  t  a  r    s

08 00 - Password length (8 bytes long)

70 61 73 73 77 6F 72 64 - Password
p  a  s  s  w  o  r  d


As we know the login server's already identified the packet by it's opcode/packet identifier, it's safe to assume the next thing it should handle is... the length of the account ID, these two bytes:
Kod:

08 00


So, the next line down is:

Kod:

    idlen = GetShort( pBuf, index );

Well look at that - we're right, so far. The first thing it handled.. was the length of the account ID (idlen)! Note that we were right about it being a short/16 bit integer, as well. Smile

So, now that it knows the length of the account ID, the next set of bytes are our account ID - these bytes:
Kod:

74 77 6F 73 74 61 72 73
t  w  o  s  t  a  r    s


The next line in the source, is:
Kod:

    GetString( accountid, pBuf, idlen, index );


Again, we were right. The server was able to retrieve the account ID from the prefixed length (idlen). "index" stores our current location in the packet. So the string is made up of bytes from our current position (index) to current position (index) + idlen (account ID length).

Following our packet structure, the next thing it should do is retrieve our password length, these bytes:
Kod:

08 00


The line:
Kod:

    pwdlen = GetShort( pBuf, index );

Right again!

The final thing left for it to identify, should be our password - as we now know how long the password is.. meaning, we now know how many following bytes in the packet make up the password:
Kod:

70 61 73 73 77 6F 72 64
p  a  s  s  w  o  r  d

Kod:

    GetString( pwd, pBuf, pwdlen, index );


.. and again, we were right!

This means that we have correctly identified all the parameters in the login packet. But wait, that wasn't our original packet!

Our original packet was:
Kod:

AA 55 (packet header)
01
00
01
55 AA (packet tail)

This one's child's play now. I'm not going to spoil all the fun; try figuring it out yourself! Wink
[/quote]
Hello EMO
Hello EMO
EMO Team
EMO Team

Cinsiyet : Erkek
Burçlar : Yay
Yılan
Mesaj Sayısı : 935
Puan : 374943
Rep Puanı : 18
Doğum tarihi : 28/11/89
Kayıt tarihi : 21/07/09
Yaş : 34
Nerden : EMO WorlD
İş/Hobiler : RCE Student / Game Hacking / Learn Beginner C#,C++,Delphi
Lakap : EMO

https://emostyle.yetkinforum.com

Sayfa başına dön Aşağa gitmek

Sayfa başına dön

- Similar topics

 
Bu forumun müsaadesi var:
Bu forumdaki mesajlara cevap veremezsiniz