flash页游seer2折腾日记4-通信协议

in 折腾一下 with 0 comment

游戏中最重要的是什么?通信!那么本次我们就来看一下游戏里面的通信。

s2的通信分成了两部分,登陆时通信和游戏时通信,这两部分都是字节通信,即将数据打包成字节数组的形式再发送。

登陆通信和游戏通信两部分协议规则基本相同,不同的是游戏通信多了一个数据加密的过程。

1567059755983.png

数据通信包含三部分:数据头、数据体和数据加密

数据头

数据头的一个18字节长度的字节数组,包含下面五个部分

类型长度描述
数据长度4需要发送的数据包长度,包括数据头和数据体长度
协议号2游戏定义的协议号,不同协议号代表不同的数据体结构
用户标识4用户的唯一标识,这里为用户账号
消息序码4消息序码,和用户发送数据的顺序有关
校验码4消息的校验码,和消息头、消息体有关

这里说一下消息标识和校验码。

消息标识和协议号、消息长度、上一个消息标识(初始为0)成多元函数关系,具体是如何对应,未知!

校验码是数据头的前14位和消息体字节值之和再模取100000所得到的32位整型int。

数据体

由于数据体是不定长度的,所以不同类型数据体需要用协议号区分。

类型描述长度
字符串字符串为UTF编码,可以包括字符串长度,也可以不包括,由协议号决定。x
字节数组在as3中,其数据结构为ByteArray。x
数组递归分解x
其他写入无符号32位整型int4

数据加密

源码加密混淆过了,我只能根据一部分数据加密前后的值,再通过数学的方式推断出加密方式。

其加密方式就是一个异或和位整合的过程,下面给出的算法是用黑盒法得到的,与源码加密过程可能不同,但二者等价,相同输入时输出也相同。

Java版本代码

private static final int[] EN_KEY = {0xe6, 0x6b, 0xed, 0xcb, 0x6f, 0x84, 0x8e, 0x2e, 0xec, 0xad, 0xad, 0xac, 0xec, 0x6b, 0xae, 0xac, 0x4c, 0x4e};
private static final int EN_KEY_LEN = EN_KEY.length;
private static final int EN_DEFAULT_NUM = 0x68;
public static byte[] MEncrypt(byte[] bytes) {
    byte[] outByts = new byte[bytes.length + 1];
    new ByteArray(outByts).writeUnsignedInt(outByts.length);
    outByts[4]=bytes[4];
    outByts[5]=bytes[5];
    int before = EN_DEFAULT_NUM,now;//b'1101000
    for (int i = NO_ENCRYPT_LEN; i < bytes.length; i++) {
        now = bytes[i] & 0xff;
        outByts[i] = (byte) (((((now << 5) + (before >>> 3)) ^ EN_KEY[i % EN_KEY_LEN]) & 0xf0) +
                             (((before >>> 3) ^ (EN_KEY[i % EN_KEY_LEN])) & 0xf));
        before = now;
    }
    outByts[bytes.length] = (byte) (((before >>> 3) ^ (EN_KEY[bytes.length % EN_KEY_LEN])) & 0xf);
    return outByts;
}

public static byte[] MDecrypt(byte[] bytes) {
    byte[] outByts = new byte[bytes.length - 1];
    new ByteArray(outByts).writeUnsignedInt(outByts.length);
    outByts[4]=bytes[4];
    outByts[5]=bytes[5];
    for (int i = NO_ENCRYPT_LEN; i < outByts.length; i++) {
        int t2_0 = ((bytes[i] ^ EN_KEY[i % EN_KEY_LEN]) & 0xe0) >>> 5; // i [YYYx xxxx] -> [xxxx xxxYYY] i
        int t7 = ((bytes[i + 1] ^ EN_KEY[(i + 1) % EN_KEY_LEN]) & 0x10) << 3;//i+1 [xxxY xxxx] -> [Yxxx xxxx] i
        int t6_3 = ((bytes[i + 1] ^ EN_KEY[(i + 1) % EN_KEY_LEN]) & 0xf) << 3;//i+1 [xxxx YYYY] -> [xYYY Yxxx] i
        outByts[i] = (byte) (t2_0 + t7 + t6_3);
    }
    return outByts;
}

题外话

到这里,狮子(八月)的尾巴也快结束了,折腾日记也暂时告一段落吧!

书读百遍,百遍感觉各有不同,相信之后回顾时亦会有一番收获吧!

Responses