public static int Walk(int x, int y) { /* 行走到大约位于中心的位置: * 00 00 00 3F 31 00 00 08 35 29 75 C9 B0 00 00 03 2E 00 00 00 00 00 00 01 DD 00 00 01 62 00 00 00 1E 09 05 01 0A 23 01 03 78 03 79 05 40 7A E3 33 33 33 33 33 04 82 4A 0A 01 04 83 56 04 82 5E * x坐标是0x1DD, y坐标是0x162. * 不同的坐标,封包的长度居然不一样。 * 不过意外发现只需要修改x, y坐标即可实现行走到相应的位置。 * 其余的数据的含义无需分析出来,哪怕长度并不同,也能正常用。 * 包体的第二个int是x坐标,范围大约是0~0x3c0; * 包体的第三个int是y坐标,范围大约是0~0x280. * 坐标可以超出上限,但是会消失在屏幕范围内。 * 再点一次屏幕,人就回来了。 */ _PacketData PacketData = new _PacketData(); string example = "00 00 00 3F 31 00 00 08 35 29 75 C9 B0 00 00 03 2E 00 00 00 00 00 00 01 DD 00 00 01 62 00 00 00 1E 09 05 01 0A 23 01 03 78 03 79 05 40 7A E3 33 33 33 33 33 04 82 4A 0A 01 04 83 56 04 82 5E "; byte[] plain = Misc.HexString2ByteArray(example); Packet.ParsePacket(plain, ref PacketData); byte[] x_b = Misc.Int2ByteArray(x); byte[] y_b = Misc.Int2ByteArray(y); x_b.CopyTo(PacketData.body, 4); y_b.CopyTo(PacketData.body, 8); plain = Packet.GroupPacket(ref PacketData); string PlainStr = Misc.ByteArray2HexString(plain); return(SendPacketManually(PlainStr)); }
public static void Login(ref _PacketData RecvPacketData) { byte[] b = Misc.ArraySlice(RecvPacketData.body, RecvPacketData.body.Length - 4, RecvPacketData.body.Length); //取LOGIN_IN接收封包的后4个字节 int d = Misc.GetIntParam(b, 0); string s = (d ^ RecvPacketData.userId).ToString(); b = System.Text.Encoding.UTF8.GetBytes(s); s = Misc.GetMD5(b); s = s.Substring(0, 10); //取md5后的前10个字节作为密钥 Algorithm.InitKey(s); }
public static int SendPacketNum = 0; //发送封包序号 #endregion #region 解析一条完整的封包,各项数据放入一个结构体中 public static void ParsePacket(byte[] packet, ref _PacketData PacketData) { if (packet.Length >= 17) { PacketData.length = Misc.GetIntParam(packet, 0); PacketData.version = packet[4]; PacketData.cmdId = Misc.GetIntParam(packet, 5); PacketData.userId = Misc.GetIntParam(packet, 9); PacketData.result = Misc.GetIntParam(packet, 13); PacketData.body = Misc.ArraySlice(packet, 17, PacketData.length); } }
public static byte[] GroupPacket(ref _PacketData PacketData) { byte[] length = Misc.Int2ByteArray(PacketData.length); byte[] cmdId = Misc.Int2ByteArray(PacketData.cmdId); byte[] userId = Misc.Int2ByteArray(PacketData.userId); byte[] result = Misc.Int2ByteArray(PacketData.result); byte[] packet = new byte[PacketData.length]; length.CopyTo(packet, 0); packet[4] = PacketData.version; cmdId.CopyTo(packet, 5); userId.CopyTo(packet, 9); result.CopyTo(packet, 13); PacketData.body.CopyTo(packet, 17); return(packet); }
public static int Chat(string content) { /* 喊话“A” * 00 00 00 1B 31 00 00 08 36 29 75 C9 B0 00 00 02 78 00 00 00 00 00 00 00 02 41 30 * 喊话“aaa” * 00 00 00 1D 31 00 00 08 36 29 75 C9 B0 00 00 02 88 00 00 00 00 00 00 00 04 61 61 61 30 * 喊话“暑期福利放送” * 00 00 00 2C 31 00 00 08 36 29 75 C9 B0 00 00 01 D4 00 00 00 00 00 00 00 13 E6 9A 91 E6 9C 9F E7 A6 8F E5 88 A9 E6 94 BE E9 80 81 30 * 喊话“我*30”,喊话字数上限为30(30个汉字,30个英语字母,等等) * 00 00 00 74 31 00 00 08 36 29 75 C9 B0 00 00 02 A5 00 00 00 00 00 00 00 5B E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 E6 88 91 30 * */ _PacketData PacketData = new _PacketData(); string example = "00 00 00 1B 31 00 00 08 36 29 75 C9 B0 00 00 02 78 00 00 00 00 00 00 00 02 41 30 "; byte[] plain = Misc.HexString2ByteArray(example); Packet.ParsePacket(plain, ref PacketData); //版本号和命令号准备就绪 byte[] a = new byte[7] { 0, 0, 0, 0, 0, 0, 0 }; byte[] c = System.Text.Encoding.UTF8.GetBytes(content); byte[] b = new byte[1] { (byte)(c.Length + 1) }; byte[] d = new byte[1] { 30 }; byte[] body = new byte[9 + c.Length]; a.CopyTo(body, 0); b.CopyTo(body, 7); c.CopyTo(body, 8); d.CopyTo(body, 8 + c.Length); PacketData.body = body; //包体 PacketData.length = 17 + PacketData.body.Length; //长度 //序列号和米米号在调用SendPacketManually()的时候会自动修复 plain = Packet.GroupPacket(ref PacketData); string PlainStr = Misc.ByteArray2HexString(plain); return(SendPacketManually(PlainStr)); }
public void AddList(string type, int num, ref _PacketData PacketData, byte[] plain, byte[] cipher) { ListViewItem li = new ListViewItem(type); li.SubItems.Add(num.ToString()); li.SubItems.Add(PacketData.length.ToString()); li.SubItems.Add(PacketData.version.ToString()); li.SubItems.Add(PacketData.userId.ToString()); li.SubItems.Add(PacketData.cmdId.ToString()); li.SubItems.Add(Command.GetCommandName(PacketData.cmdId)); li.SubItems.Add(PacketData.result.ToString()); li.SubItems.Add(Misc.ByteArray2HexString(PacketData.body)); li.SubItems.Add(Misc.ByteArray2HexString(plain)); li.SubItems.Add(Misc.ByteArray2HexString(cipher)); // 添加到封包log列表中 PacketLogList.Add(li); //Console.WriteLine(PacketLogList.Count); // 这段由PacketFilter内部实现 // 若关键字过滤的文本框中没有字符,则将该条封包log添加到UI的listview框中 //if (String.IsNullOrEmpty(textBox5.Text)) //{ // this.listView1.Items.Add(li); //} PacketFilter(li); if (type == "send") { iSendPacketNum++; } if (type == "recv") { iRecvPacketNum++; } label4.Text = String.Format("本次连接中,发送封包{0}条,接收封包{1}条", iSendPacketNum, iRecvPacketNum); //this.listView1.Items[this.listView1.Items.Count - 1].EnsureVisible(); //列表刷新时自动拉到最后 }
public static void CalculateResult(ref _PacketData PacketData) { int result = 0; if (PacketData.cmdId > 1000) { int v6 = 0, v7 = 0; while (v7 < PacketData.body.Length) { v6 = (v6 ^ PacketData.body[v7]) & 255; v7++; } result = Algorithm.MSerial(Result, PacketData.body.Length, v6, PacketData.cmdId); } else { result = 0; } PacketData.result = result; }
//private static async void RecvLeaveMapPacket(int MapId) private static void RecvLeaveMapPacket(int MapId) { //await Task.Run(() => { // while (!Listen.bLeaveMap) // { // ; // } //}); //MessageBox.Show("ENTER MAP ing"); Thread.Sleep(100); _PacketData PacketData = new _PacketData(); string EntryMap = "00 00 00 21 31 00 00 07 D1 09 C0 B6 F7 00 00 02 55 00 00 00 00 00 00 00 0A 00 00 02 D5 00 00 00 AC "; // 包体是4个int,第一个是0,第二个是地图号,第三第四个分别是x,y坐标 byte[] plain = Misc.HexString2ByteArray(EntryMap); Packet.ParsePacket(plain, ref PacketData); byte[] temp = Misc.Int2ByteArray(0); byte[] mapid = Misc.Int2ByteArray(MapId); //byte[] x = Misc.Int2ByteArray(490); //byte[] y = Misc.Int2ByteArray(280); // 默认传送坐标为(490,280) byte[] x = Misc.Int2ByteArray(0x2d5); byte[] y = Misc.Int2ByteArray(0xac); byte[] body = new byte[16]; temp.CopyTo(body, 0); mapid.CopyTo(body, 4); x.CopyTo(body, 8); y.CopyTo(body, 12); PacketData.body = body; plain = Packet.GroupPacket(ref PacketData); string PlainStr = Misc.ByteArray2HexString(plain); SendPacketManually(PlainStr); }
public static int SendPacketManually(string PlainStr) { if (!Misc.CheckHexString(PlainStr)) { MessageBox.Show("封包数据格式错误,请检查十六进制字符串的格式是否正确"); return(0); } byte[] plain = Misc.HexString2ByteArray(PlainStr); _PacketData SendPacketData = new _PacketData(); Packet.ParsePacket(plain, ref SendPacketData); Packet.CalculateResult(ref SendPacketData); //更新序列号 SendPacketData.userId = Packet.UserId; //修改为当前登录的米米号 plain = Packet.GroupPacket(ref SendPacketData); byte[] cipher = Packet.encrypt(plain); int res = SendPacket.Send(Packet.Socket, cipher); Packet.Result = SendPacketData.result; Packet.SendPacketNum++; Program.UI.AddList("send", Packet.SendPacketNum, ref SendPacketData, plain, cipher); return(res); }
public static void ProcessingRecvPacket(int socket, byte[] buffer, int length) { _PacketData RecvPacketData = new _PacketData(); Array.Copy(buffer, 0, RecvBuf, RecvBufLen, length); //接收封包的数据追加到接收封包缓冲区的尾部,以解决断包的问题 RecvBufLen += length; //更新接收封包缓冲区的长度 if (Socket != socket) { #region 直接过滤的接收封包 if (length > 20) { Console.WriteLine("接收封包-解析过滤 : [ {0}...... ]\n", Misc.ByteArray2HexString(RecvBuf, 20)); } else { Console.WriteLine("接收封包-解析过滤 : [ {0}]\n", Misc.ByteArray2HexString(RecvBuf, length)); } RecvBufIndex += length; //更新接收封包缓冲区的索引 if (RecvBufIndex == RecvBufLen) { //如果接收封包缓冲区索引等于接收封包缓冲区长度 //说明刚好取完所有的包,不存在断包的情况,所以此时将二者的值都设为0 RecvBufLen = 0; RecvBufIndex = 0; } #endregion } else { while (true) //从接收封包缓冲区中不停地取出一条条接收封包,直到取完或遇到断包 { if (RecvBufLen >= 4) { int PacketLen = Misc.GetIntParam(RecvBuf, RecvBufIndex); if (RecvBufIndex + PacketLen <= RecvBufLen) //不是断包 { #region 从缓冲区中取出一条接收封包,解析并发送(同时会监测cmdId为1001和105的封包) byte[] cipher = Misc.ArraySlice(RecvBuf, RecvBufIndex, RecvBufIndex + PacketLen); //取出一条接收封包 byte[] plain; if (NeedDecrypt(cipher)) //解密或者不解密封包 { plain = decrypt(cipher); } else { plain = cipher; } ParsePacket(plain, ref RecvPacketData); //解析封包 RecvPacketNum++; Program.UI.AddList("recv", RecvPacketNum, ref RecvPacketData, plain, cipher); //更新UI界面的列表 #region 登录包(cmdId == 1001) if (RecvPacketData.cmdId == 1001) //登陆LOGIN_IN包 { Login(ref RecvPacketData); //处理登录数据,拿到密钥 Socket = socket; //设置全局socket通信号 Result = RecvPacketData.result; //LOGIN_IN的recv包是含有序列号的 UserId = RecvPacketData.userId; //米米号 HaveLogin = true; //是否登录 } #endregion //Listen.listen(ref RecvPacketData); RecvBufIndex += PacketLen; //更新接收封包缓冲区的索引 #endregion } else //断包,等待下一次接收封包的到来 { break; } } else //断包,等待下一次接收封包的到来 { break; } #region 取完缓冲区内所有的包后重置RecvBufLen和RecvBufIndex if (RecvBufIndex == RecvBufLen) { //如果接收封包缓冲区索引等于接收封包缓冲区长度 //说明刚好取完所有的包,不存在断包的情况,所以此时将二者的值都设为0 RecvBufLen = 0; RecvBufIndex = 0; } #endregion } } }
public static int ProcessingSendPacket(int socket, byte[] cipher, int length) { _PacketData SendPacketData = new _PacketData(); int res = 0; if (cipher.Length < 17 || Misc.ByteArray2HexString(cipher, 2) != "00 00 ") { #region 直接过滤的发送封包(这个包也得发送出去,但是我们的封包解析程序不会解析这一条封包) res = SendPacket.Send(socket, cipher); //直接发送封包 if (cipher.Length > 20) { Console.WriteLine("发送封包-解析过滤 : [ {0}...... ]\n", Misc.ByteArray2HexString(cipher, 20)); } else { Console.WriteLine("发送封包-解析过滤 : [ {0}]\n", Misc.ByteArray2HexString(cipher)); } #endregion } else { #region 需要解析的发送封包 if (!HaveLogin) { Socket = socket; //通信号 } byte[] plain; if (NeedDecrypt(cipher)) { plain = decrypt(cipher); //解密封包 ParsePacket(plain, ref SendPacketData); //解析封包 CalculateResult(ref SendPacketData); //修改序列号 plain = GroupPacket(ref SendPacketData); //组合封包 cipher = encrypt(plain); //加密封包 } else //无需加密只有一种情况,即处于登录界面 { //这种情况下并不需要修改序列号,只解析封包即可 plain = cipher; ParsePacket(plain, ref SendPacketData); //解析封包 #region 登陆前 伪造米米号 // 如果 "伪造米米号" 对应的文本框不为空, // 则登录前的封包,米米号修改为该文本框中的米米号。 // 这个是用于测试赛尔号的伪造登录。正常游戏则置空即可。 if (!HaveLogin && !String.IsNullOrEmpty(Program.UI.textBox11.Text) && !String.IsNullOrEmpty(Program.UI.textBox12.Text) && Program.UI.textBox12.Text.Length == 32 && SendPacketData.cmdId == 103) { int iSubUserId = Int32.Parse(Program.UI.textBox11.Text); byte[] subUserId = Misc.Int2ByteArray(iSubUserId); subUserId.CopyTo(cipher, 9); subUserId.CopyTo(plain, 9); byte[] doubleMD5Pwd; doubleMD5Pwd = System.Text.Encoding.UTF8.GetBytes(Program.UI.textBox12.Text); doubleMD5Pwd.CopyTo(cipher, 17); doubleMD5Pwd.CopyTo(plain, 17); ParsePacket(plain, ref SendPacketData); } #endregion } res = SendPacket.Send(socket, cipher); //发送封包 if (HaveLogin) { Result = SendPacketData.result; //更新全局序列号(登录前的不用更新,也不能更新) } SendPacketNum++; //发送封包的总序号 Program.UI.AddList("send", SendPacketNum, ref SendPacketData, plain, cipher); //UI界面的列表增加这条发送记录 #endregion } return(res); }