• 谈网页游戏外挂之用python模拟游戏(热血三国2)登陆


      看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 27614
    #g_pat_url 
    #g_act_url
    #g_fcm_url
    #g_server_id  17614

    捕获封包

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

    第二个是认证登陆的




    从我们能看懂的地方
    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)
    
    # 23
    
    d1 = '0000000000000000000000000000000000000000000000'
    
    # 114
    
    d2 = ''
    
    d2 += '0100c800'
    
    d2 += '00000100'
    
    d2 += '00000000'
    
    d2 += '00006000'
    
    d2 += '0000'+str(hex(serverId)[4:]+hex(serverId)[2:4])
    
    d2 += '00000400'
    
    d2 +=  binascii.hexlify("ledu")
    
    d2 +=  "0"+str(hex(len(passport)))[2:]+"00"
    
    d2 +=  binascii.hexlify(passport)
    
    d2 += '2000'
    
    d2 +=  binascii.hexlify(hash)
    
    d2 += '0800'
    
    d2 +=  binascii.hexlify(version)
    
    d2 += '2000'
    
    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了。

  • 相关阅读:
    CNI 这么多,怎么选?| 容器网络系列第 1 期
    FabEdge 成为 CNCF 沙箱级项目
    向 Analysis Services 实例授予服务器管理员权限
    Connecting to Integration Services Access is Denied in SQL Server 2016 or 2017
    How To Convert A CER Certificate To PFX Without The Private Key
    Linux Shell脚本经典案例
    MDK5 HC32F460编译生成BIN文件配置
    MDK5 魔术棒中target中的IROM1与IRAM1
    Mongodb副本集切换主从节点调整优先级
    mongodb 创建用户,设置密码
  • 原文地址:https://www.cnblogs.com/l137/p/3938836.html
Copyright © 2020-2023  润新知