看web看多了,想写写页游的外挂,其实原理是一样的,就是端口不一样协议字段你不知道,而这也提高了点技术门槛,看我们来一点一点突破这些门槛,这次我们来用python发包模拟flash的客户端登陆。
  以热血三国2为例,热血三国2是一款balabalaba自己查去吧的游戏。

step1 : 在sg2.ledu.com注册个账户
    略过...
step2 : 登陆游戏,wireshark抓包分析
     以双线784服为例,游戏页面地址http://s784.sg2.ledu.com/,现在游戏一般都是联运的,就是我的域名下套着游戏给的iframe,当然请求iframe时会有之间的相互签名的。然后就变成这样了

真正的地址是

而这个地址带来的是我们最终想要的

一个flash地址跟它的参数s

<object type="application/x-shockwave-flash" data="http://cdn.ledu.com/rxsg2/1.13.0.9/swf/Rxsg2Runner.swf?r=1916775188" width="100%" height="100%" id="web_game" style="visibility: visible;">
<param name="flashvars" value="g_version=1.13.0.9&amp;g_swf_path=http%3A%2F%2Fcdn.ledu.com%2Frxsg2%2F1.13.0.9&amp;g_res_path=http%3A%2F%2Fcdn.ledu.com%2Frxsg2%2F1.13.0&amp;g_pass_type=ledu&amp;g_pass_port=testfoliet&amp;g_pass_token=2dfdca253759b6986807421362e05e55&amp;g_host=183.60.46.109&amp;g_port=27614&amp;g_pay_url=http%3A%2F%2Fepay.ledu.com%2Findex%2Findex%2Fgid%2F22%2Fsid%2F17614&amp;g_act_url=UNIQUE&amp;g_fcm_url=http%3A%2F%2Fkf.ledu.com%2Ffcm%2F%3Fgameid%3D0%26pid%3Duuyx&amp;g_server_id=17614&amp;">
<param name="allowscriptaccess" value="always">
<param name="wmode" value="Opaque">
<param name="menu" value="false">
<param name="bgcolor" value="#000000">
</object>

而第一个参数flashvars包含了通信的变量,我们把它urldecode一下得到,

#g_version 1.13.0.9
#g_swf_path
#g_res_path
#g_pass_type ledu
#g_pass_port testfoliet
#g_pass_token string(md5) 2DFDCA253759B6986807421362E05E55
#g_host 183.60.46.109
#g_port
#g_pat_url
#g_act_url
#g_fcm_url
#g_server_id

捕获封包

其实就发了俩包,第二个是个持续的连接
第一个

第二个是认证登陆的

从我们能看懂的地方
6c 65 64 75  -> ledu ,
中间是个0a00
下面是74 65 73 74 66 6f 6c 69 65 74 -> testfoliet
2000
38 37 37 35 38 63 33 31 62 65 62 63 35 65  33 65 35 61 38 33 63 6237 35 63 39 36 35 34 66  32 64
这个是我们的32个字符的hash ,
0800 
31 2e 31 33 2e 30 2e 39这个是我们的版本1.13.0.9,
2000
61 63 65 32 30 39 63 65  64 66 30 36 35 34 39 33 34 61 63 62 38 62 35 6338 62 32 35 36 32

这个事32位的hash
此时大致的轮廓出来了,每个字符串前面有2个字节是表示字符串的字节数,比如ledu前面是0400,testfoliet (10位)前面是0a00,hash前面是2000.

然后我们再读下解密后的swf文件as代码(http://www.showmycode.com/)在线反编译swf文件

package Rxsg2.Common {

    import Nireus.Base.Service.Socket.*;

    public class Login {

        private static var _login_func:Function = null;

        private static var _code_transfer_loaded:Boolean = false;

        private static var _mask:String = "";

        public static function login(_arg1:Function):void{

            var succ_func:* = _arg1;

            _login_func = succ_func;

            SocketService.getInstance().registerNotify(ProcDef.USER_NOTIFY_LOGIN, onUserLogin);

            SocketService.getInstance().callProcRaw(ProcDef.SYSTEM_PROC_LOGIN, function (_arg1:NetData):void{

                _arg1.writeInt(GlobalData.server_id);

                _arg1.writeString(GlobalData.pass_type);

                _arg1.writeString(GlobalData.pass_port);

                _arg1.writeString(GlobalData.pass_token);

                _arg1.writeString(GlobalData.version);

                _arg1.writeString(Crypto.hash((((GlobalData.pass_port + GlobalData.version) + "8Ij18Hisl1na0Ous2f") + ProcDef.PROC_SIGN)));

            });

        }

        public static function onUserLogin(_arg1:NetData):void{

            var _local2:int = _arg1.readByte();

            var _local3 = !((_arg1.readByte() == 0));

            var _local4:String = _arg1.readString();

            ((_login_func) && (_login_func((_local2 > 0), _local3)));

            if (_local2 >= 0){

                loadProcTransfer(_local4);

            };

        }

        public static function loadProcTransfer(_arg1:String):void{

            onLoadProcTransfer();

        }

        private static function onLoadProcTransfer():void{

            _code_transfer_loaded = true;

            tryEnterGame();

        }

        public static function tryEnterGame():void{

            if (((((GlobalData.allow_enter) && (GlobalData.main_loaded))) && (_code_transfer_loaded))){

                SocketService.getInstance().callProc(ProcDef.USER_PROC_ENTER_GAME);

                sendMask();

            };

        }

        public static function setMask(_arg1:String):void{

            _mask = _arg1;

            sendMask();

        }

        private static function sendMask():void{

            if (GlobalData.login_mask.length > 0){

                SocketService.getInstance().sendProc(ProcDef.USER_PROC_SEND_LOGIN_MASK, function (_arg1:NetData):void{

                    _arg1.writeString(GlobalData.login_mask);

                });

            };

        }

    }

}//package Rxsg2.Common 

ProcDef.PROC_SIGN 是个常量PROC_SIGN_DEFAULT,其实我们没猜到的就是前面有个serverId

step3 : 用代码模拟封包发包过程 

#!/usr/bin/env python

#-*- encoding: utf-8 -*-
'''
Created on Wed Aug 27 10:13:18 CST 2014
@author lietdai@gmail.com
'''
#flashvar #g_version 1.13.0.9 #g_swf_path #g_res_path #g_pass_type ledu #g_pass_port testfoliet #g_pass_token string(md5) a7e13597be485ec3cd2741335bb81b10 #g_host 183.60.46.109 #g_port 27617 #g_pat_url #g_act_url #g_fcm_url #g_server_id 16431 import os import sys import socket import hashlib import struct import binascii passport = "testfoliet" version = "1.13.0.9" hash = 'b7d6941a8e4fd04ac771f72fad167f10' serverId = 17614 serverIp = '183.60.46.109' serverPort = 27614 #token 加密串的获取 def getToken(passport,version): key = "8Ij18Hisl1na0Ous2f" sign = "PROC_SIGN_DEFAULT" return hashlib.md5(passport+version+key+sign).hexdigest() #第一次socket #sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #server_address = ('183.60.46.107',843) #sock.connect(server_address) #sock.send("<policy-file-request/>.") #print sock.recv(1024) #sck.close #登录socket sock2 = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server_address2 = (serverIp,serverPort) sock2.connect(server_address2) sock2.settimeout(3) # d1 = '' # d2 = '' d2 += '0100c800' d2 += '' d2 += '' d2 += '' d2 += ''+str(hex(serverId)[4:]+hex(serverId)[2:4]) d2 += '' d2 += binascii.hexlify("ledu") d2 += ""+str(hex(len(passport)))[2:]+"" d2 += binascii.hexlify(passport) d2 += '' d2 += binascii.hexlify(hash) d2 += '' d2 += binascii.hexlify(version) d2 += '' d2 += binascii.hexlify(getToken(passport,version)) sock2.send(binascii.unhexlify(d1)) sock2.send(binascii.unhexlify(d2)) res = "" try: while True: buffer = sock2.recv(1460) if not buffer: break res += buffer except: pass print res sock2.close

打印出来的东西
 一个socket连接hash只能被使用一次,所以每次测需要换hash当然你也可以结合我前面的 PYTHON 模拟web登录带着你的leducookie请求  游戏页面,动态解析 HTML获取HASH_TOKEN这样你就不用每次都换hash了。

谈网页游戏外挂之用python模拟游戏(热血三国2)登陆的更多相关文章

  1. Python:游戏:300行代码实现俄罗斯方块

    本文代码基于 python3.6 和 pygame1.9.4. 俄罗斯方块是儿时最经典的游戏之一,刚开始接触 pygame 的时候就想写一个俄罗斯方块.但是想到旋转,停靠,消除等操作,感觉好像很难啊, ...

  2. Python:游戏:五子棋之人机对战

    本文代码基于 python3.6 和 pygame1.9.4. 五子棋比起我之前写的几款游戏来说,难度提高了不少.如果是人与人对战,那么,电脑只需要判断是否赢了就可以.如果是人机对战,那你还得让电脑知 ...

  3. Python:游戏:扫雷(附源码)

    这次我们基于 pygame 来做一个扫雷,上次有园友问我代码的 python 版本,我说明一下,我所有的代码都是基于 python 3.6 的. 先看截图,仿照 XP 上的扫雷做的,感觉 XP 上的样 ...

  4. 用Python制作游戏外挂(上)

    源地址:http://eyehere.net/2012/python-game-bot-autopy-1/ 悲剧成我这样的人,我知道肯定不止我一个,所以我一点都不悲伤:-( 所以我打开了4399小游戏 ...

  5. 一步步用python制作游戏外挂【转】

    转自:http://www.cnblogs.com/xsmhero/archive/2013/01/03/2842973.html 玩过电脑游戏的同学对于外挂肯定不陌生,但是你在用外挂的时候有没有想过 ...

  6. Python论做游戏外挂,Python输过谁?

    玩过电脑游戏的同学对于外挂肯定不陌生,但是你在用外挂的时候有没有想过如何做一个外挂呢? 我打开了4399小游戏网,点开了一个不知名的游戏,唔,做寿司的,有材料在一边,客人过来后说出他们的要求,你按照菜 ...

  7. python模拟鼠标键盘操作 GhostMouse tinytask 调用外部脚本或程序 autopy右键另存为

    0.关键实现:程序窗口前置 python 通过js控制滚动条拉取全文 通过psutil获取pid窗口句柄,通过win32gui使程序窗口前置 通过pyauto实现右键菜单和另存为操作 1.参考 aut ...

  8. C#简单游戏外挂制作(以Warcraft Ⅲ为例)

    网上有很多外挂制作的教程,大多是讲针对大型网络游戏的,主要包含一些抓包.反汇编.C++的知识综合.事实也如此,常见的外挂都是使用VC++写的,从来没有过C#或者其他.NET语言编写的外挂. 作为微软. ...

  9. Python模拟登陆新浪微博

    上篇介绍了新浪微博的登陆过程,这节使用Python编写一个模拟登陆的程序.讲解与程序如下: 1.主函数(WeiboMain.py): import urllib2 import cookielib i ...

随机推荐

  1. mysql表的创建和删除

    在创建数据库表时,最好是在编辑器中写好创建表的代码,然后粘贴到命令行中,这样如果有错修改起来方便. 现在来创建一个user表: -- 打开数据库, --后面必须要有空格, 表示注释 USE mydb3 ...

  2. NDK编译FFMpeg[Linux]

    最近在研究视频直播相关的技术,了解到了FFmpeg,就在网上查看如何将FFmpeg移植到Android中,查了几天,看的东西不少,就是没有一个可以完全移植成功的,最后通过产看各种资料,结合网上的资料, ...

  3. html行内元素和块元素标签分组

    转载 address - 地址blockquote - 块引用center - 举中对齐块dir - 目录列表div - 常用块级容易,也是CSS layout的主要标签dl - 定义列表fields ...

  4. jQuery源码dom ready分析

    一.前言 在平时开发web项目时,我们使用jquery框架时,可能经常这样来使用$(document).ready(fn),$(function(){}),这样使用的原因是在浏览器把DOM树渲染好之前 ...

  5. codeforces 676B B. Pyramid of Glasses(模拟)

    题目链接: B. Pyramid of Glasses time limit per test 1 second memory limit per test 256 megabytes input s ...

  6. 获取IOS bundle中的文件

    在xcode中选择bundle中的文件,右键Show in Finder即可拷贝或删除文件.

  7. 关于inodes占用100%的问题及解决方法

    #df shows no file systems processedPosted by John Quaglieri on 27 July 2012 07:26 AMA df -m command ...

  8. Codevs 1287 矩阵乘法&&Noi.cn 09:矩阵乘法(矩阵乘法练手题)

    1287 矩阵乘法  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Description 小明最近在为线性代数而头疼, ...

  9. js中Frame框架的属性获取(1)

    js中window和document对象及如何操作iframe 一. window对象 . 什么是window对象? Window对象表示浏览器打开的窗口.如果文档包含iframe或者是frame标签 ...

  10. android sqlite操作(1)

    以下只是我个人的浅见,大神请忽略~ android提供了一个轻量级的数据库sqlite,虽然说是轻量级,但是相对移动设备sqlite绝对够用了. 先说一下sqlite的管理工具吧 sqlite3,使用 ...