l2j封包研究-Lineage2 packet

l2qq · 2020-03-07 17:01
字数 12090 评论 0 收藏 0 点赞 0

1、一般信息 每个包由包大小(2字节)、包大小(1字节)和参数块(可变长度)组成。除此之外,在服务器包中 授权,在最后添加控制和添加0,使包大小为8字节。控制金额可能 被设计成以下功能:

unsigned long checksum( unsigned char *packet, int count ){   
long chksum = 0L;   
for( int i = 0; i < count; i += 4 ) 
   chksum ^= *((unsigned long *)&raw[i]);
   return chksum;
};

lineage协议使用了6种不同的数据类型:

char的值从-128到127不等。长1字节

short的值从-32768到32767不等。长2字节

int可以从- 214743648到- 214483647。它有四个字节长。

int64的值从- 92233636775808到92233636777807不等。它有8字节长。

float的值从22507e-308到1.79769e+308不等。长8字节

string是UTF8的文本行。每个字母代表两个字节,第一个字节代表字母代码,第二个字母代表

密码表号码字符串末尾的指示器是代码0的符号。

注意:对于那些不熟悉pc内存中的数据存储原则的人来说,字节是反向的。如果我们需要记录

在包中,int类型的10表示,我们应该:

1)把他调到16号计数系统,我们会得到 00 00 00 0a 

2)将字节顺序转换成单词,得到 0a 00 00 00

验证包是通过Blowfish算法加密的。四个编年史上标准默认密钥:

5F 3B 35 2E 5D 39 34 2D 33 31 3D 3D 2D 25 78 54 21 5E 5B 24。在钥匙的末端有一个符号,代码0。Interlude的加密类型被修改为包。

Init包含一个动态的Blowfish键,随机生成给每个客户。这个包最初是通过XOR算法加密的(键生成)。随机放置在包的底部。

然后用静态密钥Blowfish算法加密。默认情况下,静态密钥

6B 60 CB 5B 82 CE 90 B1 CC 2B 6C 55 6C 6C 6C 6C。所有后续的包都将被动态的Blowfish密钥加密。LoginRequest包外

它是通过RSA算法加密的。钥匙由以下部分组成:B = 1024, E = 65537, N =在Init包中传输。

这三个部分加起来就是整个RSA。

钥匙。包中的字节N是用函数加密的:

void scrambleMod( char *n ){      
    typedef unsigned char byte;      
    int i;      
    for( i=0; i<4; i++ ) {
            byte temp = n[0x00 + i];
            n[0x00 + i] = n[0x4d + i];
            n[0x4d + i] = temp;
    };      // step 2 xor first 0x40 bytes with last 0x40 bytes
      for( i=0; i<0x40; i++ ) {
            n[i] = (byte)(n[i] ^ n[0x40 + i]);
      }; 
      // step 3 xor bytes 0x0d-0x10 with bytes 0x34-0x38
      for( i=0; i<4; i++ ) {
            n[0x0d + i] = (byte)(n[0x0d + i] ^ n[0x34 + i]);
      };      // step 4 xor last 0x40 bytes with first 0x40 bytes
      for( i=0; i<0x40; i++ ) {
            n[0x40 + i] = (byte)(n[0x40 + i] ^ n[i]);
      };
};

解码可以使用以下功能:

void unscrambleMod( char *n ){      
    typedef unsigned char byte;      
    int i;      // step 4 xor last 0x40 bytes with first 0x40 bytes
      for( i=0; i<0x40; i++ ) {
            n[0x40 + i] = (byte)(n[0x40 + i] ^ n[i]);
      };      // step 3 xor bytes 0x0d-0x10 with bytes 0x34-0x38
      for( i=0; i<4; i++ ) {
            n[0x0d + i] = (byte)(n[0x0d + i] ^ n[0x34 + i]);
      };      // step 2 xor first 0x40 bytes with last 0x40 bytes
      for( i=0; i<0x40; i++ ) {
            n[i] = (byte)(n[i] ^ n[0x40 + i]);
      };      for( i=0; i<4; i++ ) {
            byte temp = n[0x00 + i];
            n[0x00 + i] = n[0x4d + i];
            n[0x4d + i] = temp;
      };
};

还有使用旧授权协议(785a)的服务器,它不加密Init包,其余的都是Blowfish密码。 21字节长键

然而,LoginRequest包只能通过Blowfish算法加密,没有额外的RSA加密。

XOR算法用于加密服务器包。XOR键是随机生成的,通过CryptInit包传输给客户。函数 下面是加密和解码:

解码数据

void decrypt( unsigned char *data, unsigned int len, unsigned char *Key ){
        int temp = 0;

        for( unsigned int i = 0; i < len; ++i ) {
               int temp2 = data[i] & 0xff;
               data[i] = (temp2 ^ (Key[i & 15] & 0xff) ^ temp);
               temp = temp2;
        };

        

        int old = Key[8] & 0xff;
        old |= (Key[9] << 0x08) & 0xff00;
        old |= (Key[10] << 0x10) & 0xff0000;
        old |= (Key[11] << 0x18) & 0xff000000;

        old += len;

        Key[8] = old &0xff;
        Key[9] = (old >> 0x08) & 0xff;
        Key[10] = (old >> 0x10) & 0xff;
        Key[11] = (old >> 0x18) & 0xff;
};

*编码数据*

void encrypt( unsigned char *data, unsigned int len, unsigned char *Key )
{
        int temp = 0;

        for( unsigned int i = 0; i < len; i++) {
               int temp2 = data[i] & 0xff;
               data[i] = (temp2 ^ (Key[i & 15] & 0xff) ^ temp);
               temp = data[i];
        };

        int old = Key[8] & 0xff;
        old |= (Key[9] << 0x08) & 0xff00;
        old |= (Key[10] << 0x10) & 0xff0000;
        old |= (Key[11] << 0x18) & 0xff000000;

        old += len;

        Key[8] = old &0xff;
        Key[9] = (old >> 0x08) & 0xff;
        Key[10] = (old >> 0x10) & 0xff;
        Key[11] = (old >> 0x18) & 0xff;
};

每一个编码/解码包,钥匙就会改变包的长度。所以我们需要使用两个独立的密钥实例。输出包加密一次,第二个是解码输入。

所有的包从3字节开始加密,也就是说包的大小从来没有被加密过。

服务器登录验证程序

首先,注意到目前正在使用的两项协议修正(可能更多,但我不知道)- c621和785a。不同的是,c621使用了额外的加密和GameGuard授权。Init包和RequestAuthLogin包也不同。版本可以通过Init包的大小来确定,785a修正为11字节,c621 - 170字节。

  1. 一旦连接完成,服务器就会发送一个数据包到客户机。

  2. 作为回应,客户发送了一个RequestGGAuth包(785a协议修正不发送)。

  3. 服务器以GGAuth包回答(785a协议修正中未发送该包)

  4. 如果服务器回答说授权是成功的,客户发送一个包(RequestAuthLogin)含用户名和密码的请求包。

  5. 登录和密码检查,如果失败,服务器发送一个LoginFail包,包含失败的原因,或发送一个LoginOk包 session key 1

  6. 接下来,客户请求请求请求包中的服务器列表(RequestServerList)。

  7. 作为对该包的回应,服务器发送给客户机ServerList,包含服务器列表和带有端口号码的IP地址。

  8. 在选择游戏服务器并点击ok之后,客户发送一个请求服务器包(RequestServerLogin)。

  9. 授权服务器执行最大数量的玩家、服务器可用性等检查。如果所有的测试都通过了,它会发送一个(PlayOk)。包含session key 2,这把钥匙是由目前的系统生成的,在mc中,软件号码等等。之后是客户从服务器登录到游戏服务器。


游戏服务器授权程序

  1. 安装连接后,客户发送一个包含协议版本的ProtocolVersion包。

  2. 服务器发送一个CryptInit包,包含XOR密钥,它将加密所有以下包。

  3. 客户将AuthLogin包发送到选择的服务器,包含session key 1、session key 2和用户名。如果与这些钥匙和登录不匹配,在授权服务器上存储客户将被关闭。

  4. 服务器发送一个CharList包,包含所有账户的列表。

  5. 这是创造/移除和选择角色的过程,在角色被选中并按下开始按钮之后。客户发送一个包到CharacterSelected。

  6. 客户发送两个包——RequestQuestList和requestemanorlist。

  7. 服务器发送一个ExSendManorList包。

  8. 服务器发送一个QuestList包。

  9. 客户发送一个EnterWorld包。

  10. 服务器发送UserInfo包,这也是上传结束的信号。

  11. 游戏中,每60秒发送一个NetPingRequest包,客户必须用NetPing包回答。


包的描述包括ObjectID和ItemID, ItemID是对象类型的标识符,例如:阿巴敦长袍的标识符是2406。

而ObjectID是游戏中物品的唯一标识符。

例如,两个咒语都有化身长袍,它们每个的ItemID长袍都相同-2406,ObjectID将是唯一。

2. 客户端端包(Login服务器)

00 - RequestAuthLogin

02 - RequestServerLogin

05 - RequestServerList

07 - RequestGGAuth


RequestAuthLogin

目的:在登录服务器上请求授权

修订版0x785a的格式:

00

XX XX XX XX 00 //包含登录名的行。 它的长度为14个字节,以ASCII格式存储,而不是UNICODE!

XX XX XX XX 00 //包含密码的行。 它的长度为16个字节,以ASCII格式存储,而不是UNICODE!

08 //结束标记的登录名/密码

00 00 00 00 //不使用

00 00 00 00 //不使用



最新评论 0