谈网页游戏外挂之用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代码

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 [email protected]
‘‘‘
#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了。

时间: 2024-10-14 15:09:39

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

python模拟腾讯网页登录

近日,研究Tencent网页模拟登录的过程,过程有些忐忑.先将结果写于此,供大家参考: 其加密过程在c_login_old.js文件中执行,将JS关键代码提取出来如下: function hexchar2bin(str) { var arr = []; for (var i = 0; i < str.length; i = i + 2) { arr.push("\\x" + str.substr(i, 2)) } arr = arr.join(""); eva

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

1.参考 autopy (实践见最后一章节) 用Python制作游戏外挂(上) AutoPy Introduction and Tutorial autopy.mouse.smooth_move(1, 1) 可以实现平滑移动 autopy - API Reference pip install PyUserInput SavinaRoja/PyUserInput [python3.5][PyUserInput]模拟鼠标和键盘模拟 Python-模拟鼠标键盘动作 autoit selenium借助

【转载】游戏外挂的编写原理和思路

原文:游戏外挂的编写原理和思路 游戏外挂的编写原理(一) 一. 前言 所谓游戏外挂,其实是一种游戏外辅程序,它可以协助玩家自动产生游戏动作.修改游戏网络数据包以及修改游戏内存数据等,以实现玩家用最少的时间和金钱去完成功力升级和过关斩将.虽然,现在对游戏外挂程序的“合法”身份众说纷纭,在这里我不想对此发表任何个人意见,让时间去说明一切吧. 不管游戏外挂程序是不是“合法”身份,但是它却是具有一定的技术含量的,在这些小小程序中使用了许多高端技术,如拦截Sock技术.拦截API技术.模拟键盘与鼠标技术.

游戏外挂教程(转)

游戏外挂教程(转) 由于本人是游戏爱好者,又是懒人,所以就有了写外挂的想法. 有同样爱好的人 可以 参考一下 主要是调用API的一些东西. 以下教程来自网上,本人通过一下教程,编写了魔兽争霸3,辅助工具(主用功能显血.改键) 谢谢 O(∩_∩)O~ 游戏外挂的编写原理(一)     一. 前言 所谓游戏外挂,其实是一种游戏外辅程序,它可以协助玩家自动产生游戏动作.修改游戏网络数据包以及修改游 戏内存数据等,以实现玩家用最少的时间和金钱去完成功力升级和过关斩将.虽然,现在对游戏外挂程序的“合法”

关于游戏外挂

这篇文章不是自己所写,但基本上工作中也有接触,看到了就转过来记录 对于一个要上线的游戏,防外挂是必须的,历史上因为外挂而造成大量玩家流失的游戏数不胜数.随着游戏研发技术的发展,对外挂的预防业内其实做的已经越来越好了.下面总结一下防外挂的基础知识,以及我们的移动模块为防外挂做了哪些工作. 1 预防外挂的基础知识 在做外挂预防工作之前,我们要先了解外挂有哪些.根据我的了解,市面上常见的外挂主要有以下几种: 修改客户端的内存信息这类外挂通过分析游戏所使用的内存,找到内存中的变量去分析猜测变量是代表的什

用游戏外挂的方式修复有道云笔记的BUG

由爱到痛 有道云笔记是个好东西,在认识它之前,我一直使用Windows记事本来保存网上摘抄的文档资料和学习心得体会.某天朋友推荐了有道云笔记,我安装后就不可收拾的爱上了它.那种感觉,就好比一夜之间手扶拖拉机换成了奥迪Q7,从此驶上了码字界的康庄大道. 可就在我对它的爱如火如荼的进行中时,一件痛心疾首的事情发生了. 宋体,是我钟爱的字体,而有道云笔记钟爱的字体则是微软雅黑.就是那么一个兴趣爱好的不同,使我们之间产生了矛盾,并不断被激化,最终影响到了工作和生活,以至于之后一度要和它分手. 问题是这样

浅析HTTP中POST和GET区别并用Python模拟其响应和请求

最近在几周在做手游崩溃信息收集和上传,拿到崩溃信息后,使用的是HTTP的POST方法上传到公司共用的服务器的,因此做简单总结.本文首先简单介绍了HTTP协议,主要说明了POST方法和GET方法的区别:然后用Python实现了 对POST方法和GET方法的响应:最后用Python模拟了POST方法和GET方法的请求. HTTP协议简介 HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写,简单来说它是一个应用层的协议,它允许将超文本标记语言(HTML)文档从W

【Python数据分析】Python模拟登录(一) requests.Session应用

最近由于某些原因,需要用到Python模拟登录网站,但是以前对这块并不了解,而且目标网站的登录方法较为复杂, 所以一下卡在这里了,于是我决定从简单的模拟开始,逐渐深入地研究下这块. 注:本文仅为交流学习所用. 登录特点:明文传输,有特殊标志数据 会话对象requests.Session能够跨请求地保持某些参数,比如cookies,即在同一个Session实例发出的所有请求都保持同一个cookies,而requests模块每次会自动处理cookies,这样就很方便地处理登录时的cookies问题.

Python模拟登陆万能法-微博|知乎

Python模拟登陆让不少人伤透脑筋,今天奉上一种万能登陆方法.你无须精通HTML,甚至也无须精通Python,但却能让你成功的进行模拟登陆.本文讲的是登陆所有网站的一种方法,并不局限于微博与知乎,仅用其作为例子来讲解. 用到的库有"selenium"和"requests".通过selenium进行模拟登陆,然后将Cookies传入requests,最终用requests进行网站的抓取.优点就是不但规避了"selenium"其本身抓取速度慢的问题